diff --git a/lib/ip.h b/lib/ip.h index 5cfce1f1..ec2d6966 100644 --- a/lib/ip.h +++ b/lib/ip.h @@ -238,6 +238,12 @@ static inline int ip6_is_link_local(ip6_addr a) static inline int ip6_is_v4mapped(ip6_addr a) { return _I0(a) == 0 && _I1(a) == 0 && _I2(a) == 0xffff; } +static inline int ip4_is_multicast(ip4_addr a) +{ return (_I(a) & 0xf0000000) == 0xe0000000; } + +static inline int ip6_is_multicast(ip6_addr a) +{ return (_I0(a) & 0xff000000) == 0xff000000; } + #define ipa_classify(x) ip6_classify(&(x)) #define ipa_is_link_local(x) ip6_is_link_local(x) diff --git a/lib/net.c b/lib/net.c index 9335b78f..01af3a4d 100644 --- a/lib/net.c +++ b/lib/net.c @@ -12,8 +12,12 @@ const char * const net_label[] = { [NET_VPN6] = "vpn6", [NET_ROA4] = "roa4", [NET_ROA6] = "roa6", - [NET_FLOW4] = "flow4", - [NET_FLOW6] = "flow6", + [NET_FLOW4] = "flow4", + [NET_FLOW6] = "flow6", + [NET_MREQ4] = "mreq4", + [NET_MREQ6] = "mreq6", + [NET_MGRP4] = "mgrp4", + [NET_MGRP6] = "mgrp6", [NET_MPLS] = "mpls", }; @@ -24,8 +28,12 @@ const u16 net_addr_length[] = { [NET_VPN6] = sizeof(net_addr_vpn6), [NET_ROA4] = sizeof(net_addr_roa4), [NET_ROA6] = sizeof(net_addr_roa6), - [NET_FLOW4] = 0, - [NET_FLOW6] = 0, + [NET_FLOW4] = 0, + [NET_FLOW6] = 0, + [NET_MREQ4] = sizeof(net_addr_mreq4), + [NET_MREQ6] = sizeof(net_addr_mreq6), + [NET_MGRP4] = sizeof(net_addr_mgrp4), + [NET_MGRP6] = sizeof(net_addr_mgrp6), [NET_MPLS] = sizeof(net_addr_mpls), }; @@ -36,8 +44,12 @@ const u8 net_max_prefix_length[] = { [NET_VPN6] = IP6_MAX_PREFIX_LENGTH, [NET_ROA4] = IP4_MAX_PREFIX_LENGTH, [NET_ROA6] = IP6_MAX_PREFIX_LENGTH, - [NET_FLOW4] = IP4_MAX_PREFIX_LENGTH, - [NET_FLOW6] = IP6_MAX_PREFIX_LENGTH, + [NET_FLOW4] = IP4_MAX_PREFIX_LENGTH, + [NET_FLOW6] = 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, [NET_MPLS] = 0, }; @@ -48,8 +60,12 @@ 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_FLOW4] = 0, /* "flow4 { ... }" */ - [NET_FLOW6] = 0, /* "flow6 { ... }" */ + [NET_FLOW4] = 0, /* "flow4 { ... }" */ + [NET_FLOW6] = 0, /* "flow6 { ... }" */ + [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" */ [NET_MPLS] = 7, /* "1048575" */ }; @@ -102,6 +118,14 @@ net_format(const net_addr *N, char *buf, int buflen) return flow4_net_format(buf, buflen, &n->flow4); case NET_FLOW6: return flow6_net_format(buf, buflen, &n->flow6); + case NET_MREQ4: + return bsnprintf(buf, buflen, "%I4", n->mreq4.grp); + case NET_MREQ6: + return bsnprintf(buf, buflen, "%I6", n->mreq6.grp); + case NET_MGRP4: + return bsnprintf(buf, buflen, "%I4", n->mgrp4.grp); + case NET_MGRP6: + return bsnprintf(buf, buflen, "%I6", n->mgrp6.grp); case NET_MPLS: return bsnprintf(buf, buflen, "%u", n->mpls.label); } @@ -118,12 +142,16 @@ net_pxmask(const net_addr *a) case NET_VPN4: case NET_ROA4: case NET_FLOW4: + 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_FLOW6: + case NET_MREQ6: + case NET_MGRP6: return ipa_from_ip6(ip6_mkmask(net6_pxlen(a))); case NET_MPLS: @@ -156,6 +184,14 @@ net_compare(const net_addr *a, const net_addr *b) return net_compare_flow4((const net_addr_flow4 *) a, (const net_addr_flow4 *) b); case NET_FLOW6: return net_compare_flow6((const net_addr_flow6 *) a, (const net_addr_flow6 *) b); + case NET_MREQ4: + return net_compare_mreq4((const net_addr_mreq4 *) a, (const net_addr_mreq4 *) b); + case NET_MREQ6: + return net_compare_mreq6((const net_addr_mreq6 *) a, (const net_addr_mreq6 *) b); + case NET_MGRP4: + return net_compare_mgrp4((const net_addr_mgrp4 *) a, (const net_addr_mgrp4 *) b); + case NET_MGRP6: + return net_compare_mgrp6((const net_addr_mgrp6 *) a, (const net_addr_mgrp6 *) b); case NET_MPLS: return net_compare_mpls((const net_addr_mpls *) a, (const net_addr_mpls *) b); } @@ -177,6 +213,10 @@ net_hash(const net_addr *n) case NET_ROA6: return NET_HASH(n, roa6); case NET_FLOW4: return NET_HASH(n, flow4); case NET_FLOW6: return NET_HASH(n, flow6); + case NET_MREQ4: return NET_HASH(n, mreq4); + case NET_MREQ6: return NET_HASH(n, mreq6); + case NET_MGRP4: return NET_HASH(n, mgrp4); + case NET_MGRP6: return NET_HASH(n, mgrp6); case NET_MPLS: return NET_HASH(n, mpls); default: bug("invalid type"); } @@ -198,6 +238,10 @@ net_validate(const net_addr *n) case NET_ROA6: return NET_VALIDATE(n, roa6); case NET_FLOW4: return NET_VALIDATE(n, flow4); case NET_FLOW6: return NET_VALIDATE(n, flow6); + case NET_MREQ4: return NET_VALIDATE(n, mreq4); + case NET_MREQ6: return NET_VALIDATE(n, mreq6); + case NET_MGRP4: return NET_VALIDATE(n, mgrp4); + case NET_MGRP6: return NET_VALIDATE(n, mgrp6); case NET_MPLS: return NET_VALIDATE(n, mpls); default: return 0; } @@ -222,6 +266,10 @@ net_normalize(net_addr *N) case NET_FLOW6: return net_normalize_ip6(&n->ip6); + case NET_MREQ4: + case NET_MREQ6: + case NET_MGRP4: + case NET_MGRP6: case NET_MPLS: return; } @@ -238,12 +286,16 @@ net_classify(const net_addr *N) case NET_VPN4: case NET_ROA4: case NET_FLOW4: + case NET_MREQ4: + case NET_MGRP4: return ip4_zero(n->ip4.prefix) ? (IADDR_HOST | SCOPE_UNIVERSE) : ip4_classify(n->ip4.prefix); case NET_IP6: case NET_VPN6: case NET_ROA6: case NET_FLOW6: + case NET_MREQ6: + case NET_MGRP6: return ip6_zero(n->ip6.prefix) ? (IADDR_HOST | SCOPE_UNIVERSE) : ip6_classify(&n->ip6.prefix); case NET_MPLS: @@ -274,6 +326,16 @@ 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), net4_prefix(n)); + + case NET_MREQ6: + case NET_MGRP6: + if (ipa_is_ip4(a)) return 0; + return ip6_equal(ipa_to_ip6(a), net6_prefix(n)); + case NET_MPLS: default: return 0; @@ -304,5 +366,9 @@ net_init(void) CHECK_NET(net_addr_roa6, 28); CHECK_NET(net_addr_flow4, 8); CHECK_NET(net_addr_flow6, 20); + CHECK_NET(net_addr_mreq4, 12); + CHECK_NET(net_addr_mreq6, 24); + CHECK_NET(net_addr_mgrp4, 8); + CHECK_NET(net_addr_mgrp6, 20); CHECK_NET(net_addr_mpls, 8); } diff --git a/lib/net.h b/lib/net.h index 69f00641..de25ad6d 100644 --- a/lib/net.h +++ b/lib/net.h @@ -21,8 +21,12 @@ #define NET_ROA6 6 #define NET_FLOW4 7 #define NET_FLOW6 8 -#define NET_MPLS 9 -#define NET_MAX 10 +#define NET_MREQ4 9 +#define NET_MREQ6 10 +#define NET_MGRP4 11 +#define NET_MGRP6 12 +#define NET_MPLS 13 +#define NET_MAX 14 #define NB_IP4 (1 << NET_IP4) #define NB_IP6 (1 << NET_IP6) @@ -32,11 +36,20 @@ #define NB_ROA6 (1 << NET_ROA6) #define NB_FLOW4 (1 << NET_FLOW4) #define NB_FLOW6 (1 << NET_FLOW6) +#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_MPLS (1 << NET_MPLS) #define NB_IP (NB_IP4 | NB_IP6) #define NB_VPN (NB_VPN4 | NB_VPN6) +#define NB_ROA (NB_ROA4 | NB_ROA6) #define NB_FLOW (NB_FLOW4 | NB_FLOW6) +#define NB_MREQ (NB_MREQ4 | NB_MREQ6) +#define NB_MGRP (NB_MGRP4 | NB_MGRP6) + +#define NB_HOST (NB_IP | NB_VPN | NB_ROA) #define NB_DEST (NB_IP | NB_VPN | NB_MPLS) #define NB_ANY 0xffffffff @@ -114,6 +127,36 @@ typedef struct net_addr_flow6 { byte data[0]; } net_addr_flow6; +typedef struct net_addr_mreq4 { + u8 type; + u8 pxlen; + u16 length; + ip4_addr grp; + uint ifindex; +} net_addr_mreq4; + +typedef struct net_addr_mreq6 { + u8 type; + u8 pxlen; + u16 length; + ip6_addr grp; + uint ifindex; +} net_addr_mreq6; + +typedef struct net_addr_mgrp4 { + u8 type; + u8 pxlen; + u16 length; + ip4_addr grp; +} net_addr_mgrp4; + +typedef struct net_addr_mgrp6 { + u8 type; + u8 pxlen; + u16 length; + ip6_addr grp; +} net_addr_mgrp6; + typedef struct net_addr_mpls { u8 type; u8 pxlen; @@ -131,6 +174,10 @@ typedef union net_addr_union { net_addr_roa6 roa6; net_addr_flow4 flow4; net_addr_flow6 flow6; + net_addr_mreq4 mreq4; + net_addr_mreq6 mreq6; + net_addr_mgrp4 mgrp4; + net_addr_mgrp6 mgrp6; net_addr_mpls mpls; } net_addr_union; @@ -167,6 +214,18 @@ extern const u16 net_max_text_length[]; #define NET_ADDR_FLOW6(prefix,pxlen,dlen) \ ((net_addr_flow6) { NET_FLOW6, pxlen, sizeof(net_addr_ip6) + dlen, prefix }) +#define NET_ADDR_MREQ4(grp, ifindex) \ + ((net_addr_mreq4) { NET_MREQ4, IP4_MAX_PREFIX_LENGTH, sizeof(net_addr_mreq4), grp, ifindex }) + +#define NET_ADDR_MREQ6(grp, ifindex) \ + ((net_addr_mreq6) { NET_MREQ6, IP6_MAX_PREFIX_LENGTH, sizeof(net_addr_mreq6), grp, ifindex }) + +#define NET_ADDR_MGRP4(grp) \ + ((net_addr_mgrp4) { NET_MGRP4, IP4_MAX_PREFIX_LENGTH, sizeof(net_addr_mgrp4), grp }) + +#define NET_ADDR_MGRP6(grp) \ + ((net_addr_mgrp6) { NET_MGRP6, IP6_MAX_PREFIX_LENGTH, sizeof(net_addr_mgrp6), grp }) + #define NET_ADDR_MPLS(label) \ ((net_addr_mpls) { NET_MPLS, 20, sizeof(net_addr_mpls), label }) @@ -189,6 +248,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 grp, uint ifindex) +{ *(net_addr_mreq4 *)a = NET_ADDR_MREQ4(grp, ifindex); } + +static inline void net_fill_mreq6(net_addr *a, ip6_addr grp, uint ifindex) +{ *(net_addr_mreq6 *)a = NET_ADDR_MREQ6(grp, ifindex); } + +static inline void net_fill_mgrp4(net_addr *a, ip4_addr grp) +{ *(net_addr_mgrp4 *)a = NET_ADDR_MGRP4(grp); } + +static inline void net_fill_mgrp6(net_addr *a, ip6_addr grp) +{ *(net_addr_mgrp6 *)a = NET_ADDR_MGRP6(grp); } + static inline void net_fill_mpls(net_addr *a, u32 label) { *(net_addr_mpls *)a = NET_ADDR_MPLS(label); } @@ -208,6 +279,22 @@ 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 grp, unsigned ifindex) +{ + if (ipa_is_ip4(grp)) + net_fill_mreq4(a, ipa_to_ip4(grp), ifindex); + else + net_fill_mreq6(a, ipa_to_ip6(grp), ifindex); +} + +static inline void net_fill_mgrp(net_addr *a, ip_addr grp) +{ + if (ipa_is_ip4(grp)) + net_fill_mgrp4(a, ipa_to_ip4(grp)); + else + net_fill_mgrp6(a, ipa_to_ip6(grp)); +} + static inline void net_fill_flow4(net_addr *a, ip4_addr prefix, uint pxlen, byte *data, uint dlen) { net_addr_flow4 *f = (void *) a; @@ -240,6 +327,12 @@ static inline int net_is_roa(const net_addr *a) static inline int net_is_flow(const net_addr *a) { return (a->type == NET_FLOW4) || (a->type == NET_FLOW6); } +static inline int net_is_mreq(const net_addr *a) +{ return (a->type == NET_MREQ4) || (a->type == NET_MREQ6); } + +static inline int net_is_mgrp(const net_addr *a) +{ return (a->type == NET_MGRP4) || (a->type == NET_MGRP6); } + static inline ip4_addr net4_prefix(const net_addr *a) { return ((net_addr_ip4 *) a)->prefix; } @@ -255,12 +348,16 @@ static inline ip_addr net_prefix(const net_addr *a) case NET_VPN4: case NET_ROA4: case NET_FLOW4: + case NET_MREQ4: + case NET_MGRP4: return ipa_from_ip4(net4_prefix(a)); case NET_IP6: case NET_VPN6: case NET_ROA6: case NET_FLOW6: + case NET_MREQ6: + case NET_MGRP6: return ipa_from_ip6(net6_prefix(a)); case NET_MPLS: @@ -293,11 +390,25 @@ static inline u64 net_rd(const net_addr *a) switch (a->type) { case NET_VPN4: - return ((net_addr_vpn4 *)a)->rd; + return ((net_addr_vpn4 *) a)->rd; case NET_VPN6: - return ((net_addr_vpn6 *)a)->rd; + return ((net_addr_vpn6 *) a)->rd; + default: + return 0; + } +} + +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; } - return 0; } @@ -338,6 +449,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); } @@ -363,6 +486,18 @@ static inline int net_zero_flow4(const net_addr_flow4 *a) static inline int net_zero_flow6(const net_addr_flow6 *a) { return !a->pxlen && ip6_zero(a->prefix) && (a->length == sizeof(net_addr_flow6)); } +static inline int net_zero_mreq4(const net_addr_mreq4 *a) +{ return ip4_zero(a->grp) && !a->ifindex; } + +static inline int net_zero_mreq6(const net_addr_mreq6 *a) +{ return ip6_zero(a->grp) && !a->ifindex; } + +static inline int net_zero_mgrp4(const net_addr_mgrp4 *a) +{ return ip4_zero(a->grp); } + +static inline int net_zero_mgrp6(const net_addr_mgrp6 *a) +{ return ip6_zero(a->grp); } + static inline int net_zero_mpls(const net_addr_mpls *a) { return !a->label; } @@ -391,6 +526,18 @@ static inline int net_compare_flow4(const net_addr_flow4 *a, const net_addr_flow static inline int net_compare_flow6(const net_addr_flow6 *a, const net_addr_flow6 *b) { return ip6_compare(a->prefix, b->prefix) ?: uint_cmp(a->pxlen, b->pxlen) ?: uint_cmp(a->length, b->length) ?: memcmp(a->data, b->data, a->length - sizeof(net_addr_flow6)); } +static inline int net_compare_mreq4(const net_addr_mreq4 *a, const net_addr_mreq4 *b) +{ return ip4_compare(a->grp, b->grp) ?: 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->grp, b->grp) ?: 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->grp, b->grp); } + +static inline int net_compare_mgrp6(const net_addr_mgrp6 *a, const net_addr_mgrp6 *b) +{ return ip6_compare(a->grp, b->grp); } + static inline int net_compare_mpls(const net_addr_mpls *a, const net_addr_mpls *b) { return uint_cmp(a->label, b->label); } @@ -424,6 +571,18 @@ static inline void net_copy_flow4(net_addr_flow4 *dst, const net_addr_flow4 *src static inline void net_copy_flow6(net_addr_flow6 *dst, const net_addr_flow6 *src) { memcpy(dst, src, src->length); } +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 void net_copy_mpls(net_addr_mpls *dst, const net_addr_mpls *src) { memcpy(dst, src, sizeof(net_addr_mpls)); } @@ -456,6 +615,18 @@ static inline u32 net_hash_flow4(const net_addr_flow4 *n) static inline u32 net_hash_flow6(const net_addr_flow6 *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->grp) ^ u32_hash(n->ifindex); } + +static inline u32 net_hash_mreq6(const net_addr_mreq6 *n) +{ return ip6_hash(n->grp) ^ u32_hash(n->ifindex); } + +static inline u32 net_hash_mgrp4(const net_addr_mgrp4 *n) +{ return ip4_hash(n->grp); } + +static inline u32 net_hash_mgrp6(const net_addr_mgrp6 *n) +{ return ip6_hash(n->grp); } + static inline u32 net_hash_mpls(const net_addr_mpls *n) { return n->label; } @@ -505,6 +676,18 @@ static inline int net_validate_flow4(const net_addr_flow4 *n) static inline int net_validate_flow6(const net_addr_flow6 *n) { return net_validate_px6(n->prefix, n->pxlen); } +static inline int net_validate_mreq4(const net_addr_mreq4 *n) +{ return ip4_is_multicast(n->grp); } + +static inline int net_validate_mreq6(const net_addr_mreq6 *n) +{ return ip6_is_multicast(n->grp); } + +static inline int net_validate_mgrp4(const net_addr_mgrp4 *n) +{ return ip4_is_multicast(n->grp); } + +static inline int net_validate_mgrp6(const net_addr_mgrp6 *n) +{ return ip6_is_multicast(n->grp); } + static inline int net_validate_mpls(const net_addr_mpls *n) { return n->label < (1 << 20); } diff --git a/lib/printf.c b/lib/printf.c index 533a1300..9226debe 100644 --- a/lib/printf.c +++ b/lib/printf.c @@ -410,6 +410,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 e53ec5ba..11bcff71 100644 --- a/lib/socket.h +++ b/lib/socket.h @@ -103,6 +103,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 044aba2b..6093b586 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -66,7 +66,7 @@ CF_DECLS CF_KEYWORDS(ROUTER, ID, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT) CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, VRF, TABLE, STATES, ROUTES, FILTERS) -CF_KEYWORDS(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6) +CF_KEYWORDS(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, 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(ALGORITHM, KEYED, HMAC, MD5, SHA1, SHA256, SHA384, SHA512) @@ -138,8 +138,12 @@ net_type: | VPN6 { $$ = NET_VPN6; } | ROA4 { $$ = NET_ROA4; } | ROA6 { $$ = NET_ROA6; } - | FLOW4{ $$ = NET_FLOW4; } - | FLOW6{ $$ = NET_FLOW6; } + | FLOW4 { $$ = NET_FLOW4; } + | FLOW6 { $$ = NET_FLOW6; } + | MREQ4 { $$ = NET_MREQ4; } + | MREQ6 { $$ = NET_MREQ6; } + | MGRP4 { $$ = NET_MGRP4; } + | MGRP6 { $$ = NET_MGRP6; } | MPLS { $$ = NET_MPLS; } ; diff --git a/nest/route.h b/nest/route.h index 43d7d696..7a4b1672 100644 --- a/nest/route.h +++ b/nest/route.h @@ -204,6 +204,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 */ @@ -247,6 +249,9 @@ typedef struct rte { u8 best; /* Best route in network, propagated to core */ u32 metric; /* Kernel metric */ } krt; + struct { + u32 iifs, oifs; /* Bitmaps for iifs and oifs. Use RTE_MGRP_* macros to manipulate. */ + } mkrt; } u; } rte; @@ -275,6 +280,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 << if_get_vifi((iface)))) +#define RTE_MGRP_CLR(iface,m) ((m) &= ~(1 << if_get_vifi((iface)))) +#define RTE_MGRP_ISSET(iface,m) ((m) & (1 << if_get_vifi((iface)))) +#define RTE_MGRP_ZERO(m) ((m) = 0) +#define RTE_MGRP_COPY(src,dst) ((dst) = (src)) +#define RTE_MGRP_SAME(m1,m2) ((m1) == (m2)) + struct config; void rt_init(void); @@ -430,7 +442,8 @@ typedef struct rta { #define RTD_BLACKHOLE 2 /* Silently drop packets */ #define RTD_UNREACHABLE 3 /* Reject as unreachable */ #define RTD_PROHIBIT 4 /* Administratively prohibited */ -#define RTD_MAX 5 +#define RTD_MULTICAST 5 /* Multicast route */ +#define RTD_MAX 6 /* Flags for net->n.flags, used by kernel syncer */ #define KRF_INSTALLED 0x80 /* This route should be installed in the kernel */ diff --git a/nest/rt-attr.c b/nest/rt-attr.c index 761ba9fe..a7b4a749 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -64,6 +64,7 @@ const char * rta_dest_names[RTD_MAX] = { [RTD_BLACKHOLE] = "blackhole", [RTD_UNREACHABLE] = "unreachable", [RTD_PROHIBIT] = "prohibited", + [RTD_MULTICAST] = "multicast", }; pool *rta_pool; diff --git a/nest/rt-fib.c b/nest/rt-fib.c index 24a7facc..cf755efe 100644 --- a/nest/rt-fib.c +++ b/nest/rt-fib.c @@ -213,6 +213,10 @@ fib_hash(struct fib *f, const net_addr *a) case NET_ROA6: return FIB_HASH(f, a, roa6); case NET_FLOW4: return FIB_HASH(f, a, flow4); case NET_FLOW6: return FIB_HASH(f, a, flow6); + 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); case NET_MPLS: return FIB_HASH(f, a, mpls); default: bug("invalid type"); } @@ -250,6 +254,10 @@ fib_find(struct fib *f, const net_addr *a) case NET_ROA6: return FIB_FIND(f, a, roa6); case NET_FLOW4: return FIB_FIND(f, a, flow4); case NET_FLOW6: return FIB_FIND(f, a, flow6); + 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); case NET_MPLS: return FIB_FIND(f, a, mpls); default: bug("invalid type"); } @@ -270,6 +278,10 @@ fib_insert(struct fib *f, const net_addr *a, struct fib_node *e) case NET_ROA6: FIB_INSERT(f, a, e, roa6); return; case NET_FLOW4: FIB_INSERT(f, a, e, flow4); return; case NET_FLOW6: FIB_INSERT(f, a, e, flow6); 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; case NET_MPLS: FIB_INSERT(f, a, e, mpls); return; default: bug("invalid type"); } diff --git a/nest/rt-table.c b/nest/rt-table.c index b0dd6d3f..3e15a17d 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -898,9 +898,10 @@ rte_validate(rte *e) } /* FIXME: better handling different nettypes */ - c = !net_is_flow(n->n.addr) ? - net_classify(n->n.addr): (IADDR_HOST | SCOPE_UNIVERSE); - if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK)) + /* FIXME: should be check mcast addresses here or in net_validate()? */ + if (net_type_match(n->n.addr, NB_HOST) && + (c = net_classify(n->n.addr)) && + ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))) { log(L_WARN "Ignoring bogus route %N received via %s", n->n.addr, e->sender->proto->name); @@ -1430,6 +1431,33 @@ rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter) return v > 0; } +#if 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); + } +} +#endif + /** * rt_refresh_begin - start a refresh cycle @@ -2358,7 +2386,7 @@ if_local_addr(ip_addr a, struct iface *i) return 0; } -static u32 +static u32 rt_get_igp_metric(rte *rt) { eattr *ea = ea_find(rt->attrs->eattrs, EA_GEN_IGP_METRIC); diff --git a/sysdep/linux/sysio.h b/sysdep/linux/sysio.h index b1cc25dc..7b39c0f7 100644 --- a/sysdep/linux/sysio.h +++ b/sysdep/linux/sysio.h @@ -226,6 +226,24 @@ 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 cd2558b2..13b5e639 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -630,6 +630,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