From 76baa8b38ad411e871793ab30bb94e17e1cd2397 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hlavat=C3=BD?= Date: Fri, 27 May 2016 02:40:17 +0200 Subject: [PATCH] Core: Prepare for multicast --- lib/birdlib.h | 18 ----- lib/hash.h | 4 +- lib/net.c | 59 +++++++++++++- lib/net.h | 181 ++++++++++++++++++++++++++++++++++++++++++- lib/printf.c | 3 + lib/socket.h | 1 + nest/config.Y | 6 +- nest/iface.c | 11 +++ nest/iface.h | 1 + nest/route.h | 19 ++++- nest/rt-fib.c | 12 +++ nest/rt-table.c | 53 ++++++++++++- sysdep/linux/sysio.h | 19 +++++ sysdep/unix/io.c | 102 +++++++++++++++--------- sysdep/unix/timer.h | 57 ++++++++++++-- 15 files changed, 478 insertions(+), 68 deletions(-) diff --git a/lib/birdlib.h b/lib/birdlib.h index 188e59b2..7b5500b7 100644 --- a/lib/birdlib.h +++ b/lib/birdlib.h @@ -64,24 +64,6 @@ static inline int u64_cmp(u64 i1, u64 i2) #define PACKED __attribute__((packed)) -/* Microsecond time */ - -typedef s64 btime; - -#define S_ *1000000 -#define MS_ *1000 -#define US_ *1 -#define TO_S /1000000 -#define TO_MS /1000 -#define TO_US /1 - -#ifndef PARSER -#define S S_ -#define MS MS_ -#define US US_ -#endif - - /* Rate limiting */ struct tbf { diff --git a/lib/hash.h b/lib/hash.h index c2fd8bca..b67efeb2 100644 --- a/lib/hash.h +++ b/lib/hash.h @@ -1,4 +1,5 @@ - +#ifndef BIRD_HASH_H +#define BIRD_HASH_H #define HASH(type) struct { type **data; uint count, order; } #define HASH_TYPE(v) typeof(** (v).data) @@ -212,3 +213,4 @@ mem_hash(void *p, int s) return mem_hash_value(&h); } +#endif diff --git a/lib/net.c b/lib/net.c index 55eec4b5..0e7262b2 100644 --- a/lib/net.c +++ b/lib/net.c @@ -11,6 +11,10 @@ const char * const net_label[] = { [NET_VPN6] = "vpn6", [NET_ROA4] = "roa4", [NET_ROA6] = "roa6", + [NET_MREQ4] = "mreq4", + [NET_MREQ6] = "mreq6", + [NET_MGRP4] = "mgrp4", + [NET_MGRP6] = "mgrp6", }; const u16 net_addr_length[] = { @@ -19,7 +23,11 @@ const u16 net_addr_length[] = { [NET_VPN4] = sizeof(net_addr_vpn4), [NET_VPN6] = sizeof(net_addr_vpn6), [NET_ROA4] = sizeof(net_addr_roa4), - [NET_ROA6] = sizeof(net_addr_roa6) + [NET_ROA6] = sizeof(net_addr_roa6), + [NET_MREQ4] = sizeof(net_addr_mreq4), + [NET_MREQ6] = sizeof(net_addr_mreq6), + [NET_MGRP4] = sizeof(net_addr_mgrp4), + [NET_MGRP6] = sizeof(net_addr_mgrp6), }; const u8 net_max_prefix_length[] = { @@ -28,7 +36,11 @@ const u8 net_max_prefix_length[] = { [NET_VPN4] = IP4_MAX_PREFIX_LENGTH, [NET_VPN6] = IP6_MAX_PREFIX_LENGTH, [NET_ROA4] = IP4_MAX_PREFIX_LENGTH, - [NET_ROA6] = IP6_MAX_PREFIX_LENGTH + [NET_ROA6] = IP6_MAX_PREFIX_LENGTH, + [NET_MREQ4] = IP4_MAX_PREFIX_LENGTH, + [NET_MREQ6] = IP6_MAX_PREFIX_LENGTH, + [NET_MGRP4] = IP4_MAX_PREFIX_LENGTH, + [NET_MGRP6] = IP6_MAX_PREFIX_LENGTH, }; const u16 net_max_text_length[] = { @@ -38,6 +50,10 @@ const u16 net_max_text_length[] = { [NET_VPN6] = 65, /* "4294967296:4294967296 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128" */ [NET_ROA4] = 34, /* "255.255.255.255/32-32 AS4294967295" */ [NET_ROA6] = 60, /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128-128 AS4294967295" */ + [NET_MREQ4] = 15, /* "255.255.255.255" */ + [NET_MREQ6] = 39, /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" */ + [NET_MGRP4] = 15, /* "255.255.255.255" */ + [NET_MGRP6] = 39, /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" */ }; @@ -60,6 +76,12 @@ net_format(const net_addr *N, char *buf, int buflen) return bsnprintf(buf, buflen, "%I4/%u-%u AS%u", n->roa4.prefix, n->roa4.pxlen, n->roa4.max_pxlen, n->roa4.asn); case NET_ROA6: return bsnprintf(buf, buflen, "%I6/%u-%u AS%u", n->roa6.prefix, n->roa6.pxlen, n->roa6.max_pxlen, n->roa6.asn); + case NET_MREQ4: + case NET_MGRP4: + return bsnprintf(buf, buflen, "%I4", n->mgrp4.ga); + case NET_MREQ6: + case NET_MGRP6: + return bsnprintf(buf, buflen, "%I6", n->mgrp6.ga); } return 0; @@ -73,11 +95,15 @@ net_pxmask(const net_addr *a) case NET_IP4: case NET_VPN4: case NET_ROA4: + case NET_MREQ4: + case NET_MGRP4: return ipa_from_ip4(ip4_mkmask(net4_pxlen(a))); case NET_IP6: case NET_VPN6: case NET_ROA6: + case NET_MREQ6: + case NET_MGRP6: return ipa_from_ip6(ip6_mkmask(net6_pxlen(a))); default: @@ -105,6 +131,12 @@ net_compare(const net_addr *a, const net_addr *b) return net_compare_roa4((const net_addr_roa4 *) a, (const net_addr_roa4 *) b); case NET_ROA6: return net_compare_roa6((const net_addr_roa6 *) a, (const net_addr_roa6 *) b); + case NET_MREQ4: + case NET_MGRP4: + return net_compare_mgrp4((const net_addr_mgrp4 *) a, (const net_addr_mgrp4 *) b); + case NET_MREQ6: + case NET_MGRP6: + return net_compare_mgrp6((const net_addr_mgrp6 *) a, (const net_addr_mgrp6 *) b); } return 0; } @@ -124,6 +156,13 @@ net_validate(const net_addr *N) case NET_ROA6: return net_validate_ip6((net_addr_ip6 *) N); + case NET_MREQ4: + case NET_MGRP4: + return ip4_classify(((net_addr_mgrp4 *) N)->ga) & IADDR_MULTICAST; + case NET_MREQ6: + case NET_MGRP6: + return ip6_classify(&((net_addr_mgrp6 *) N)->ga) & IADDR_MULTICAST; + default: return 0; } @@ -164,6 +203,13 @@ net_classify(const net_addr *N) case NET_VPN6: case NET_ROA6: return ip6_zero(n->ip6.prefix) ? (IADDR_HOST | SCOPE_UNIVERSE) : ip6_classify(&n->ip6.prefix); + + case NET_MREQ4: + case NET_MGRP4: + return ip4_classify(n->mgrp4.ga); + case NET_MREQ6: + case NET_MGRP6: + return ip6_classify(&n->mgrp6.ga); } return IADDR_INVALID; @@ -188,6 +234,15 @@ ipa_in_netX(const ip_addr a, const net_addr *n) return ip6_zero(ip6_and(ip6_xor(ipa_to_ip6(a), net6_prefix(n)), ip6_mkmask(net6_pxlen(n)))); + case NET_MREQ4: + case NET_MGRP4: + if (!ipa_is_ip4(a)) return 0; + return ip4_equal(ipa_to_ip4(a), ((net_addr_mgrp4 *) n)->ga); + case NET_MREQ6: + case NET_MGRP6: + if (ipa_is_ip4(a)) return 0; + return ip6_equal(ipa_to_ip6(a), ((net_addr_mgrp6 *) n)->ga); + default: return 0; } diff --git a/lib/net.h b/lib/net.h index d9137c4a..6f28f875 100644 --- a/lib/net.h +++ b/lib/net.h @@ -19,7 +19,11 @@ #define NET_VPN6 4 #define NET_ROA4 5 #define NET_ROA6 6 -#define NET_MAX 7 +#define NET_MREQ4 7 +#define NET_MREQ6 8 +#define NET_MGRP4 9 +#define NET_MGRP6 10 +#define NET_MAX 11 #define NB_IP4 (1 << NET_IP4) #define NB_IP6 (1 << NET_IP6) @@ -27,8 +31,16 @@ #define NB_VPN6 (1 << NET_VPN6) #define NB_ROA4 (1 << NET_ROA4) #define NB_ROA6 (1 << NET_ROA6) +#define NB_MREQ4 (1 << NET_MREQ4) +#define NB_MREQ6 (1 << NET_MREQ6) +#define NB_MGRP4 (1 << NET_MGRP4) +#define NB_MGRP6 (1 << NET_MGRP6) #define NB_IP (NB_IP4 | NB_IP6) +#define NB_MREQ (NB_MREQ4 | NB_MREQ6) +#define NB_MGRP (NB_MGRP4 | NB_MGRP6) +#define NB_MCAST (NB_MREQ | NB_MGRP) +#define NB_6 (NB_IP6 | NB_VPN6 | NB_MREQ6 | NB_MGRP6) #define NB_ANY 0xffffffff @@ -88,6 +100,36 @@ typedef struct net_addr_roa6 { u32 asn; } net_addr_roa6; +typedef struct net_addr_mreq4 { + u8 type; + u8 pxlen; + u16 length; + ip4_addr ga; + unsigned ifindex; +} net_addr_mreq4; + +typedef struct net_addr_mreq6 { + u8 type; + u8 pxlen; + u16 length; + ip6_addr ga; + unsigned ifindex; +} net_addr_mreq6; + +typedef struct net_addr_mgrp4 { + u8 type; + u8 pxlen; + u16 length; + ip4_addr ga; +} net_addr_mgrp4; + +typedef struct net_addr_mgrp6 { + u8 type; + u8 pxlen; + u16 length; + ip6_addr ga; +} net_addr_mgrp6; + typedef union net_addr_union { net_addr n; net_addr_ip4 ip4; @@ -96,6 +138,10 @@ typedef union net_addr_union { net_addr_vpn6 vpn6; net_addr_roa4 roa4; net_addr_roa6 roa6; + net_addr_mreq4 mreq4; + net_addr_mreq6 mreq6; + net_addr_mgrp4 mgrp4; + net_addr_mgrp6 mgrp6; } net_addr_union; @@ -125,6 +171,17 @@ extern const u16 net_max_text_length[]; #define NET_ADDR_ROA6(prefix,pxlen,max_pxlen,asn) \ ((net_addr_roa6) { NET_ROA6, pxlen, sizeof(net_addr_roa6), prefix, max_pxlen, asn }) +#define NET_ADDR_MREQ4(ga, ifindex) \ + ((net_addr_mreq4) { NET_MREQ4, IP4_MAX_PREFIX_LENGTH, sizeof(net_addr_mreq4), ga, ifindex }) + +#define NET_ADDR_MREQ6(ga, ifindex) \ + ((net_addr_mreq6) { NET_MREQ6, IP6_MAX_PREFIX_LENGTH, sizeof(net_addr_mreq6), ga, ifindex }) + +#define NET_ADDR_MGRP4(ga) \ + ((net_addr_mgrp4) { NET_MGRP4, IP4_MAX_PREFIX_LENGTH, sizeof(net_addr_mgrp4), ga }) + +#define NET_ADDR_MGRP6(ga) \ + ((net_addr_mgrp6) { NET_MGRP6, IP6_MAX_PREFIX_LENGTH, sizeof(net_addr_mgrp6), ga }) static inline void net_fill_ip4(net_addr *a, ip4_addr prefix, uint pxlen) @@ -145,6 +202,18 @@ static inline void net_fill_roa4(net_addr *a, ip4_addr prefix, uint pxlen, uint static inline void net_fill_roa6(net_addr *a, ip6_addr prefix, uint pxlen, uint max_pxlen, u32 asn) { *(net_addr_roa6 *)a = NET_ADDR_ROA6(prefix, pxlen, max_pxlen, asn); } +static inline void net_fill_mreq4(net_addr *a, ip4_addr ga, unsigned ifindex) +{ *(net_addr_mreq4 *)a = NET_ADDR_MREQ4(ga, ifindex); } + +static inline void net_fill_mreq6(net_addr *a, ip6_addr ga, unsigned ifindex) +{ *(net_addr_mreq6 *)a = NET_ADDR_MREQ6(ga, ifindex); } + +static inline void net_fill_mgrp4(net_addr *a, ip4_addr ga) +{ *(net_addr_mgrp4 *)a = NET_ADDR_MGRP4(ga); } + +static inline void net_fill_mgrp6(net_addr *a, ip6_addr ga) +{ *(net_addr_mgrp6 *)a = NET_ADDR_MGRP6(ga); } + static inline void net_fill_ipa(net_addr *a, ip_addr prefix, uint pxlen) { if (ipa_is_ip4(prefix)) @@ -161,6 +230,21 @@ static inline void net_fill_ip_host(net_addr *a, ip_addr prefix) net_fill_ip6(a, ipa_to_ip6(prefix), IP6_MAX_PREFIX_LENGTH); } +static inline void net_fill_mreq(net_addr *a, ip_addr ga, unsigned ifindex) +{ + if (ipa_is_ip4(ga)) + net_fill_mreq4(a, ipa_to_ip4(ga), ifindex); + else + net_fill_mreq6(a, ipa_to_ip6(ga), ifindex); +} + +static inline void net_fill_mgrp(net_addr *a, ip_addr ga) +{ + if (ipa_is_ip4(ga)) + net_fill_mgrp4(a, ipa_to_ip4(ga)); + else + net_fill_mgrp6(a, ipa_to_ip6(ga)); +} static inline int net_val_match(u8 type, u32 mask) { return !!((1 << type) & mask); } @@ -185,11 +269,15 @@ static inline ip_addr net_prefix(const net_addr *a) case NET_IP4: case NET_VPN4: case NET_ROA4: + case NET_MREQ4: + case NET_MGRP4: return ipa_from_ip4(net4_prefix(a)); case NET_IP6: case NET_VPN6: case NET_ROA6: + case NET_MREQ6: + case NET_MGRP6: return ipa_from_ip6(net6_prefix(a)); default: @@ -208,6 +296,39 @@ static inline uint net_pxlen(const net_addr *a) ip_addr net_pxmask(const net_addr *a); +static inline int net_is_host(const net_addr *a) +{ + switch (a->type) + { + case NET_IP4: + case NET_VPN4: return net4_pxlen(a) == IP4_MAX_PREFIX_LENGTH; + case NET_IP6: + case NET_VPN6: return net6_pxlen(a) == IP6_MAX_PREFIX_LENGTH; + case NET_MREQ4: + case NET_MREQ6: + case NET_MGRP4: + case NET_MGRP6: return 1; + default: return 0; + } +} + +static inline int net_is_v6(net_addr *a) +{ + return net_type_match(a, NB_6); +} + +static inline int net_ifindex(net_addr *a) +{ + switch (a->type) + { + case NET_MREQ4: + return ((net_addr_mreq4 *) a)->ifindex; + case NET_MREQ6: + return ((net_addr_mreq6 *) a)->ifindex; + default: return 0; + } + +} static inline int net_equal(const net_addr *a, const net_addr *b) { return (a->length == b->length) && !memcmp(a, b, a->length); } @@ -236,6 +357,18 @@ static inline int net_equal_prefix_roa4(const net_addr_roa4 *a, const net_addr_r static inline int net_equal_prefix_roa6(const net_addr_roa6 *a, const net_addr_roa6 *b) { return ip6_equal(a->prefix, b->prefix) && (a->pxlen == b->pxlen); } +static inline int net_equal_mreq4(const net_addr_mreq4 *a, const net_addr_mreq4 *b) +{ return !memcmp(a, b, sizeof(net_addr_mreq4)); } + +static inline int net_equal_mreq6(const net_addr_mreq6 *a, const net_addr_mreq6 *b) +{ return !memcmp(a, b, sizeof(net_addr_mreq6)); } + +static inline int net_equal_mgrp4(const net_addr_mgrp4 *a, const net_addr_mgrp4 *b) +{ return !memcmp(a, b, sizeof(net_addr_mgrp4)); } + +static inline int net_equal_mgrp6(const net_addr_mgrp6 *a, const net_addr_mgrp6 *b) +{ return !memcmp(a, b, sizeof(net_addr_mgrp6)); } + static inline int net_zero_ip4(const net_addr_ip4 *a) { return !a->pxlen && ip4_zero(a->prefix); } @@ -255,6 +388,18 @@ static inline int net_zero_roa4(const net_addr_roa4 *a) static inline int net_zero_roa6(const net_addr_roa6 *a) { return !a->pxlen && ip6_zero(a->prefix) && !a->max_pxlen && !a->asn; } +static inline int net_zero_mreq4(const net_addr_mreq4 *a) +{ return ip4_zero(a->ga) && !a->ifindex; } + +static inline int net_zero_mreq6(const net_addr_mreq6 *a) +{ return ip6_zero(a->ga) && !a->ifindex; } + +static inline int net_zero_mgrp4(const net_addr_mgrp4 *a) +{ return ip4_zero(a->ga); } + +static inline int net_zero_mgrp6(const net_addr_mgrp6 *a) +{ return ip6_zero(a->ga); } + static inline int net_compare_ip4(const net_addr_ip4 *a, const net_addr_ip4 *b) { return ip4_compare(a->prefix, b->prefix) ?: uint_cmp(a->pxlen, b->pxlen); } @@ -274,6 +419,18 @@ static inline int net_compare_roa4(const net_addr_roa4 *a, const net_addr_roa4 * static inline int net_compare_roa6(const net_addr_roa6 *a, const net_addr_roa6 *b) { return ip6_compare(a->prefix, b->prefix) ?: uint_cmp(a->pxlen, b->pxlen) ?: uint_cmp(a->max_pxlen, b->max_pxlen) ?: uint_cmp(a->asn, b->asn); } +static inline int net_compare_mreq4(const net_addr_mreq4 *a, const net_addr_mreq4 *b) +{ return ip4_compare(a->ga, b->ga) ?: uint_cmp(a->ifindex, b->ifindex); } + +static inline int net_compare_mreq6(const net_addr_mreq6 *a, const net_addr_mreq6 *b) +{ return ip6_compare(a->ga, b->ga) ?: uint_cmp(a->ifindex, b->ifindex); } + +static inline int net_compare_mgrp4(const net_addr_mgrp4 *a, const net_addr_mgrp4 *b) +{ return ip4_compare(a->ga, b->ga); } + +static inline int net_compare_mgrp6(const net_addr_mgrp6 *a, const net_addr_mgrp6 *b) +{ return ip6_compare(a->ga, b->ga); } + int net_compare(const net_addr *a, const net_addr *b); @@ -298,6 +455,17 @@ static inline void net_copy_roa4(net_addr_roa4 *dst, const net_addr_roa4 *src) static inline void net_copy_roa6(net_addr_roa6 *dst, const net_addr_roa6 *src) { memcpy(dst, src, sizeof(net_addr_roa6)); } +static inline void net_copy_mreq4(net_addr_mreq4 *dst, const net_addr_mreq4 *src) +{ memcpy(dst, src, sizeof(net_addr_mreq4)); } + +static inline void net_copy_mreq6(net_addr_mreq6 *dst, const net_addr_mreq6 *src) +{ memcpy(dst, src, sizeof(net_addr_mreq6)); } + +static inline void net_copy_mgrp4(net_addr_mgrp4 *dst, const net_addr_mgrp4 *src) +{ memcpy(dst, src, sizeof(net_addr_mgrp4)); } + +static inline void net_copy_mgrp6(net_addr_mgrp6 *dst, const net_addr_mgrp6 *src) +{ memcpy(dst, src, sizeof(net_addr_mgrp6)); } static inline u32 net_hash_ip4(const net_addr_ip4 *n) { return ip4_hash(n->prefix) ^ ((u32) n->pxlen << 26); } @@ -321,6 +489,17 @@ static inline u32 net_hash_roa4(const net_addr_roa4 *n) static inline u32 net_hash_roa6(const net_addr_roa6 *n) { return ip6_hash(n->prefix) ^ ((u32) n->pxlen << 26); } +static inline u32 net_hash_mreq4(const net_addr_mreq4 *n) +{ return ip4_hash(n->ga) ^ u64_hash(n->ifindex); } + +static inline u32 net_hash_mreq6(const net_addr_mreq6 *n) +{ return ip6_hash(n->ga) ^ u64_hash(n->ifindex); } + +static inline u32 net_hash_mgrp4(const net_addr_mgrp4 *n) +{ return ip4_hash(n->ga); } + +static inline u32 net_hash_mgrp6(const net_addr_mgrp6 *n) +{ return ip6_hash(n->ga); } static inline int net_validate_ip4(const net_addr_ip4 *n) { diff --git a/lib/printf.c b/lib/printf.c index 844f5969..3c2c245e 100644 --- a/lib/printf.c +++ b/lib/printf.c @@ -364,6 +364,9 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args) case 'o': base = 8; break; + case 'b': + base = 2; + break; case 'X': flags |= LARGE; diff --git a/lib/socket.h b/lib/socket.h index 7d1aa7ef..5b8f0dd3 100644 --- a/lib/socket.h +++ b/lib/socket.h @@ -77,6 +77,7 @@ static inline int sk_send_buffer_empty(sock *sk) int sk_setup_multicast(sock *s); /* Prepare UDP or IP socket for multicasting */ int sk_join_group(sock *s, ip_addr maddr); /* Join multicast group on sk iface */ int sk_leave_group(sock *s, ip_addr maddr); /* Leave multicast group on sk iface */ +int sk_set_router_alert(sock *s, int ra); int sk_setup_broadcast(sock *s); int sk_set_ttl(sock *s, int ttl); /* Set transmit TTL for given socket */ int sk_set_min_ttl(sock *s, int ttl); /* Set minimal accepted TTL for given socket */ diff --git a/nest/config.Y b/nest/config.Y index 2961dafb..9bc80054 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -65,7 +65,7 @@ CF_DECLS CF_KEYWORDS(ROUTER, ID, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT) CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE, STATES, ROUTES, FILTERS) -CF_KEYWORDS(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6) +CF_KEYWORDS(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6, MREQ4, MREQ6, MGRP4, MGRP6) CF_KEYWORDS(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED) CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES) CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, NOEXPORT, GENERATE) /* ,ROA */ @@ -148,6 +148,10 @@ net_type: | VPN6 { $$ = NET_VPN6; } | ROA4 { $$ = NET_ROA4; } | ROA6 { $$ = NET_ROA6; } + | MREQ4 { $$ = NET_MREQ4; } + | MREQ6 { $$ = NET_MREQ6; } + | MGRP4 { $$ = NET_MGRP4; } + | MGRP6 { $$ = NET_MGRP6; } ; diff --git a/nest/iface.c b/nest/iface.c index 00af5052..d031d4cc 100644 --- a/nest/iface.c +++ b/nest/iface.c @@ -502,6 +502,17 @@ ifa_same(struct ifa *a, struct ifa *b) return ipa_equal(a->ip, b->ip) && net_equal(&a->prefix, &b->prefix); } +struct ifa * +ifa_find_match(struct iface *i, u32 mask) +{ + struct ifa *a; + + WALK_LIST(a, i->addrs) + if (net_type_match(&a->prefix, mask)) + return a; + + return NULL; +} /** * ifa_update - update interface address diff --git a/nest/iface.h b/nest/iface.h index c4f414ec..a0411f0a 100644 --- a/nest/iface.h +++ b/nest/iface.h @@ -88,6 +88,7 @@ void if_show(void); void if_show_summary(void); struct iface *if_update(struct iface *); void if_delete(struct iface *old); +struct ifa *ifa_find_match(struct iface *i, u32 mask); struct ifa *ifa_update(struct ifa *); void ifa_delete(struct ifa *); void if_start_update(void); diff --git a/nest/route.h b/nest/route.h index b5885ee3..0a3e5cda 100644 --- a/nest/route.h +++ b/nest/route.h @@ -200,6 +200,8 @@ struct hostentry { u32 igp_metric; /* Chosen route IGP metric */ }; +#define RTE_MGRP_MAXVIFS 32 + typedef struct rte { struct rte *next; net *net; /* Network this RTE belongs to */ @@ -235,6 +237,9 @@ typedef struct rte { u64 router_id; /* Babel router id */ } babel; #endif + struct { + u32 oifs, iifs; /* Bitmaps for iifs and oifs. Use RTE_MGRP_* macros to manipulate. */ + } mkrt; struct { /* Routes generated by krt sync (both temporary and inherited ones) */ s8 src; /* Alleged route source (see krt.h) */ u8 proto; /* Kernel source protocol ID */ @@ -269,6 +274,13 @@ static inline int rte_is_filtered(rte *r) { return !!(r->flags & REF_FILTERED); #define RIC_REJECT -1 /* Rejected by protocol */ #define RIC_DROP -2 /* Silently dropped by protocol */ +#define RTE_MGRP_SET(iface,m) ((m)|=(1<n.flags, used by kernel syncer */ #define KRF_INSTALLED 0x80 /* This route should be installed in the kernel */ diff --git a/nest/rt-fib.c b/nest/rt-fib.c index 8021ea24..cb1f07f4 100644 --- a/nest/rt-fib.c +++ b/nest/rt-fib.c @@ -193,6 +193,10 @@ fib_hash(struct fib *f, const net_addr *a) case NET_VPN6: return FIB_HASH(f, a, vpn6); case NET_ROA4: return FIB_HASH(f, a, roa4); case NET_ROA6: return FIB_HASH(f, a, roa6); + case NET_MREQ4: return FIB_HASH(f, a, mreq4); + case NET_MREQ6: return FIB_HASH(f, a, mreq6); + case NET_MGRP4: return FIB_HASH(f, a, mgrp4); + case NET_MGRP6: return FIB_HASH(f, a, mgrp6); default: bug("invalid type"); } } @@ -227,6 +231,10 @@ fib_find(struct fib *f, const net_addr *a) case NET_VPN6: return FIB_FIND(f, a, vpn6); case NET_ROA4: return FIB_FIND(f, a, roa4); case NET_ROA6: return FIB_FIND(f, a, roa6); + case NET_MREQ4: return FIB_FIND(f, a, mreq4); + case NET_MREQ6: return FIB_FIND(f, a, mreq6); + case NET_MGRP4: return FIB_FIND(f, a, mgrp4); + case NET_MGRP6: return FIB_FIND(f, a, mgrp6); default: bug("invalid type"); } } @@ -244,6 +252,10 @@ fib_insert(struct fib *f, const net_addr *a, struct fib_node *e) case NET_VPN6: FIB_INSERT(f, a, e, vpn6); return; case NET_ROA4: FIB_INSERT(f, a, e, roa4); return; case NET_ROA6: FIB_INSERT(f, a, e, roa6); return; + case NET_MREQ4: FIB_INSERT(f, a, e, mreq4); return; + case NET_MREQ6: FIB_INSERT(f, a, e, mreq6); return; + case NET_MGRP4: FIB_INSERT(f, a, e, mgrp4); return; + case NET_MGRP6: FIB_INSERT(f, a, e, mgrp6); return; default: bug("invalid type"); } } diff --git a/nest/rt-table.c b/nest/rt-table.c index 9e9d4c7a..464107c3 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -900,7 +900,7 @@ rte_announce(rtable *tab, unsigned type, net *net, rte *new, rte *old, static inline int rte_validate(rte *e) { - int c; + int c, mask; net *n = e->net; // (n->n.pxlen > BITS_PER_IP_ADDRESS) || !ip_is_prefix(n->n.prefix,n->n.pxlen)) @@ -911,8 +911,10 @@ rte_validate(rte *e) return 0; } + mask = net_val_match(n->n.addr->type, NB_MCAST) ? IADDR_MULTICAST : IADDR_HOST; + c = net_classify(n->n.addr); - if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK)) + if ((c < 0) || !(c & mask) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK)) { log(L_WARN "Ignoring bogus route %N received via %s", n->n.addr, e->sender->proto->name); @@ -1406,8 +1408,15 @@ int rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter) { net *n = net_find(t, a); - rte *rt = n ? n->routes : NULL; + return rt_examine2(n, p, filter, NULL, NULL); +} +/* If rte would be exported to p, call the callback */ +int +rt_examine2(net *n, struct proto *p, struct filter *filter, void (*callback)(struct proto *, void *, rte *), void *data) +{ + rte *rt = n ? n->routes : NULL; + if (!rte_is_valid(rt)) return 0; @@ -1419,6 +1428,9 @@ rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter) if (v == RIC_PROCESS) v = (f_run(filter, &rt, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) <= F_ACCEPT); + if (callback && v > 0) + callback(p, data, rt); + /* Discard temporary rte */ if (rt != n->routes) rte_free(rt); @@ -1426,6 +1438,32 @@ rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter) rte_update_unlock(); return v > 0; + +} + +/* Sometimes protocols need to find one route in table without keeping their own copy. + * rt_route finds the best route after applying filter. + * As the routes may be temporary, successful find is announced by the callback. + * Returns 1 if the callback was called. + */ +int +rt_route(struct channel *c, net_addr *n, void (*callback)(struct proto *, void *, rte *), void *data) +{ + net *r; + + net_addr *n0 = alloca(n->length); + net_copy(n0, n); + + while (1) + { + r = net_find(c->table, n0); + if (r && rte_is_valid(r->routes) && rt_examine2(r, c->proto, c->out_filter, callback, data)) + return 1; + if (n0->pxlen == 0) + return 0; + n0->pxlen--; + net_normalize(n0); + } } @@ -1734,6 +1772,11 @@ rt_preconfig(struct config *c) rt_new_table(cf_get_symbol("master4"), NET_IP4); rt_new_table(cf_get_symbol("master6"), NET_IP6); + + rt_new_table(cf_get_symbol("mreq4"), NET_MREQ4); + rt_new_table(cf_get_symbol("mreq6"), NET_MREQ6); + rt_new_table(cf_get_symbol("mroute4"), NET_MGRP4); + rt_new_table(cf_get_symbol("mroute6"), NET_MGRP6); } @@ -2278,7 +2321,7 @@ if_local_addr(ip_addr a, struct iface *i) return 0; } -static u32 +u32 rt_get_igp_metric(rte *rt) { eattr *ea = ea_find(rt->attrs->eattrs, EA_GEN_IGP_METRIC); @@ -2439,6 +2482,8 @@ rt_format_via(rte *e, byte *via) case RTD_UNREACHABLE: bsprintf(via, "unreachable"); break; case RTD_PROHIBIT: bsprintf(via, "prohibited"); break; case RTD_MULTIPATH: bsprintf(via, "multipath"); break; + case RTD_MREQUEST: bsprintf(via, "for %s", a->iface->name); break; + case RTD_MULTICAST: bsprintf(via, "iifs: %b, oifs: %b", e->u.mkrt.iifs, e->u.mkrt.oifs); break; default: bsprintf(via, "???"); } } diff --git a/sysdep/linux/sysio.h b/sysdep/linux/sysio.h index 58644417..a90d6ed0 100644 --- a/sysdep/linux/sysio.h +++ b/sysdep/linux/sysio.h @@ -236,6 +236,25 @@ sk_set_min_ttl6(sock *s, int ttl) return 0; } + +static inline int +sk_set_router_alert4(sock *s, int ra) +{ + if (setsockopt(s->fd, SOL_IP, IP_ROUTER_ALERT, &ra, sizeof(ra)) < 0) + ERR("IP_ROUTER_ALER"); + + return 0; +} + +static inline int +sk_set_router_alert6(sock *s, int ra) +{ + if (setsockopt(s->fd, SOL_IPV6, IPV6_ROUTER_ALERT, &ra, sizeof(ra)) < 0) + ERR("IPV6_ROUTER_ALER"); + + return 0; +} + static inline int sk_disable_mtu_disc4(sock *s) { diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index 5ec728af..bd5f3d06 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -122,10 +122,11 @@ tracked_fopen(pool *p, char *name, char *mode) #define NEAR_TIMER_LIMIT 4 static list near_timers, far_timers; -static bird_clock_t first_far_timer = TIME_INFINITY; +static btime first_far_timer = BTIME_INFINITY; /* now must be different from 0, because 0 is a special value in timer->expires */ bird_clock_t now = 1, now_real, boot_time; +btime now_btime = 1; static void update_times_plain(void) @@ -134,10 +135,11 @@ update_times_plain(void) int delta = new_time - now_real; if ((delta >= 0) && (delta < 60)) - now += delta; + now_btime += delta S; else if (now_real != 0) log(L_WARN "Time jump, delta %d s", delta); + now = now_btime TO_S; now_real = new_time; } @@ -151,11 +153,14 @@ update_times_gettime(void) if (rv != 0) die("clock_gettime: %m"); - if (ts.tv_sec != now) { - if (ts.tv_sec < now) + btime bt = (ts.tv_sec S) + (ts.tv_nsec NS); + + if (bt != now_btime) { + if (bt < now_btime) log(L_ERR "Monotonic timer is broken"); - now = ts.tv_sec; + now_btime = bt; + now = now_btime TO_S; now_real = time(NULL); } } @@ -234,7 +239,7 @@ tm_insert_near(timer *t) { node *n = HEAD(near_timers); - while (n->next && (SKIP_BACK(timer, n, n)->expires < t->expires)) + while (n->next && (SKIP_BACK(timer, n, n)->expires_btime < t->expires_btime)) n = n->next; insert_node(&t->n, n->prev); } @@ -259,17 +264,25 @@ tm_insert_near(timer *t) void tm_start(timer *t, unsigned after) { - bird_clock_t when; - if (t->randomize) after += random() % (t->randomize + 1); - when = now + after; - if (t->expires == when) + + tm_start_btime(t, after S); +} + +void +tm_start_btime(timer *t, btime after) +{ + btime when; + + when = now_btime + after; + if (t->expires_btime == when) return; - if (t->expires) + if (t->expires_btime) rem_node(&t->n); - t->expires = when; - if (after <= NEAR_TIMER_LIMIT) + t->expires_btime = when; + t->expires = when TO_S; + if (after TO_S <= NEAR_TIMER_LIMIT) tm_insert_near(t); else { @@ -289,10 +302,10 @@ tm_start(timer *t, unsigned after) void tm_stop(timer *t) { - if (t->expires) + if (t->expires_btime) { rem_node(&t->n); - t->expires = 0; + t->expires = t->expires_btime = 0; } } @@ -319,16 +332,16 @@ tm_dump_all(void) tm_dump_them("Far", &far_timers); } -static inline time_t +static inline btime tm_first_shot(void) { - time_t x = first_far_timer; + btime x = first_far_timer; if (!EMPTY_LIST(near_timers)) { timer *t = SKIP_BACK(timer, n, HEAD(near_timers)); - if (t->expires < x) - x = t->expires; + if (t->expires_btime < x) + x = t->expires_btime; } return x; } @@ -341,21 +354,21 @@ tm_shot(void) timer *t; node *n, *m; - if (first_far_timer <= now) + if (first_far_timer <= now_btime) { - bird_clock_t limit = now + NEAR_TIMER_LIMIT; - first_far_timer = TIME_INFINITY; + btime limit = now_btime + NEAR_TIMER_LIMIT S; + first_far_timer = BTIME_INFINITY; n = HEAD(far_timers); while (m = n->next) { t = SKIP_BACK(timer, n, n); - if (t->expires <= limit) + if (t->expires_btime <= limit) { rem_node(n); tm_insert_near(t); } - else if (t->expires < first_far_timer) - first_far_timer = t->expires; + else if (t->expires_btime < first_far_timer) + first_far_timer = t->expires_btime; n = m; } } @@ -363,17 +376,17 @@ tm_shot(void) { int delay; t = SKIP_BACK(timer, n, n); - if (t->expires > now) + if (t->expires_btime > now_btime) break; rem_node(n); - delay = t->expires - now; - t->expires = 0; + delay = t->expires_btime - now_btime; + t->expires = t->expires_btime = 0; if (t->recurrent) { - int i = t->recurrent - delay; + int i = t->recurrent S - delay; if (i < 0) i = 0; - tm_start(t, i); + tm_start_btime(t, i); } io_log_event(t->hook, t->data); t->hook(t); @@ -812,7 +825,7 @@ sk_skip_ip_header(byte *pkt, int *len) byte * sk_rx_buffer(sock *s, int *len) { - if (sk_is_ipv4(s) && (s->type == SK_IP)) + if (sk_is_ipv4(s) && s->type == SK_IP) return sk_skip_ip_header(s->rbuf, len); else return s->rbuf; @@ -948,6 +961,24 @@ sk_set_min_ttl(sock *s, int ttl) return sk_set_min_ttl6(s, ttl); } +/** + * sk_set_router_alert - set router alert option + * @s: socket + * @ra: packets with this router alert option value will be passed to the + * socket. Negative integer disables. + * + * Result: 0 for success, -1 for an error. + */ + +int +sk_set_router_alert(sock *s, int ra) +{ + if (sk_is_ipv4(s)) + return sk_set_router_alert4(s, ra); + else + return sk_set_router_alert6(s, ra); +} + #if 0 /** * sk_set_md5_auth - add / remove MD5 security association for given socket @@ -1087,7 +1118,8 @@ sk_free(resource *r) current_sock = sk_next(s); if (s == stored_sock) stored_sock = sk_next(s); - rem_node(&s->n); + if (NODE_VALID(&s->n)) + rem_node(&s->n); } } @@ -2093,7 +2125,7 @@ void io_loop(void) { int poll_tout; - time_t tout; + btime tout; int nfds, events, pout; sock *s; node *n; @@ -2107,12 +2139,12 @@ io_loop(void) timers: update_times(); tout = tm_first_shot(); - if (tout <= now) + if (tout <= now_btime) { tm_shot(); goto timers; } - poll_tout = (events ? 0 : MIN(tout - now, 3)) * 1000; /* Time in milliseconds */ + poll_tout = (events ? 0 : MIN(tout - now_btime, 3)) TO_MS; /* Time in milliseconds */ io_close_event(); diff --git a/sysdep/unix/timer.h b/sysdep/unix/timer.h index 99d43932..81da1ef6 100644 --- a/sysdep/unix/timer.h +++ b/sysdep/unix/timer.h @@ -13,6 +13,27 @@ #include "lib/resource.h" +/* Microsecond time */ + +typedef s64 btime; + +#define S_ *1000000 +#define MS_ *1000 +#define US_ *1 +#define NS_ /1000 + +#define TO_S /1000000 +#define TO_MS /1000 +#define TO_US /1 +#define TO_NS *1000 + +#ifndef PARSER +#define S S_ +#define MS MS_ +#define US US_ +#define NS NS_ +#endif + typedef time_t bird_clock_t; /* Use instead of time_t */ typedef struct timer { @@ -22,35 +43,59 @@ typedef struct timer { unsigned randomize; /* Amount of randomization */ unsigned recurrent; /* Timer recurrence */ node n; /* Internal link */ - bird_clock_t expires; /* 0=inactive */ + btime expires_btime; /* 0=inactive */ + bird_clock_t expires; /* == expires_btime TO_S */ } timer; timer *tm_new(pool *); void tm_start(timer *, unsigned after); +void tm_start_btime(timer *, btime after); void tm_stop(timer *); void tm_dump_all(void); extern bird_clock_t now; /* Relative, monotonic time in seconds */ +extern btime now_btime; /* dtto in microseconds */ extern bird_clock_t now_real; /* Time in seconds since fixed known epoch */ extern bird_clock_t boot_time; + static inline int tm_active(timer *t) { - return t->expires != 0; + return t->expires_btime != 0; +} + +static inline btime +tm_remains_btime(timer *t) +{ + return t->expires_btime ? t->expires_btime - now_btime : 0; } static inline bird_clock_t tm_remains(timer *t) { - return t->expires ? t->expires - now : 0; + return tm_remains_btime(t) TO_S; +} + +static inline void +tm_start_max_btime(timer *t, btime after) +{ + btime rem = tm_remains_btime(t); + tm_start(t, (rem > after) ? rem : after); +} + +static inline void +tm_start_min_btime(timer *t, btime after) +{ + btime rem = tm_remains_btime(t); + if (!rem || after < rem) + tm_start(t, after); } static inline void tm_start_max(timer *t, unsigned after) { - bird_clock_t rem = tm_remains(t); - tm_start(t, (rem > after) ? rem : after); + tm_start_max_btime(t, after S_); } static inline timer * @@ -87,4 +132,6 @@ tm_format_datetime(char *x, struct timeformat *fmt_spec, bird_clock_t t); #endif #endif +#define BTIME_INFINITY 0x7fffffffffffffff + #endif