diff options
39 files changed, 649 insertions, 211 deletions
@@ -12,3 +12,4 @@ /configure /sysdep/autoconf.h.in /sysdep/autoconf.h.in~ +/cscope.* diff --git a/Makefile.in b/Makefile.in index fdd5e6c7..c8168bbe 100644 --- a/Makefile.in +++ b/Makefile.in @@ -58,7 +58,7 @@ endif docgoals := docs userdocs progdocs testgoals := check test tests tests_run cleangoals := clean distclean testsclean -.PHONY: all daemon cli $(docgoals) $(testgoals) $(cleangoals) tags +.PHONY: all daemon cli $(docgoals) $(testgoals) $(cleangoals) tags cscope all: daemon cli daemon: $(daemon) @@ -162,6 +162,9 @@ endif tags: cd $(srcdir) ; etags -lc `find $(dirs) -name *.[chY]` +cscope: + cd $(srcdir) ; find $(dirs) -name *.[chY] > cscope.files ; cscope -b + # Install install: all @@ -22,13 +22,14 @@ protocol direct { # Feed routes to kernel FIB protocol kernel { - ipv4 { export all; }; -# learn; # Learn all routes from the kernel + ipv4 { export all; import all; }; + learn; # Learn all routes from the kernel # scan time 10; # Scan kernel tables every 10 seconds } protocol kernel { - ipv6; + ipv6 { import all; }; + learn; } # Static route feed diff --git a/conf/confbase.Y b/conf/confbase.Y index 7e0537c5..c2d647eb 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -83,7 +83,7 @@ CF_DECLS %type <time> expr_us time %type <a> ipa %type <net> net_ip4_ net_ip6_ net_ip6 net_ip_ net_ip net_or_ipa -%type <net_ptr> net_ net_any net_vpn4_ net_vpn6_ net_vpn_ net_roa4_ net_roa6_ net_roa_ net_mpls_ +%type <net_ptr> net_ net_any net_vpn4_ net_vpn6_ net_vpn_ net_roa4_ net_roa6_ net_roa_ net_ip6_sadr_ net_mpls_ %type <mls> label_stack_start label_stack %type <t> text opttext @@ -96,7 +96,7 @@ CF_DECLS %left '!' %nonassoc '.' -CF_KEYWORDS(DEFINE, ON, OFF, YES, NO, S, MS, US, PORT, VPN, MPLS) +CF_KEYWORDS(DEFINE, ON, OFF, YES, NO, S, MS, US, PORT, VPN, MPLS, FROM) CF_GRAMMAR @@ -206,6 +206,25 @@ net_ip6_: IP6 '/' NUM n->prefix, n->pxlen, ip6_and(n->prefix, ip6_mkmask(n->pxlen)), n->pxlen); }; +net_ip6_sadr_: IP6 '/' NUM FROM IP6 '/' NUM +{ + if ($3 > IP6_MAX_PREFIX_LENGTH) + cf_error("Invalid prefix length %u", $3); + + if ($7 > IP6_MAX_PREFIX_LENGTH) + cf_error("Invalid prefix length %u", $7); + + $$ = cfg_alloc(sizeof(net_addr_ip6_sadr)); + net_fill_ip6_sadr($$, $1, $3, $5, $7); + + net_addr_ip6_sadr *n = (void *) $$; + if (!net_validate_ip6_sadr(n)) + cf_error("Invalid SADR IPv6 prefix %I6/%d from %I6/%d, maybe you wanted %I6/%d from %I6/%d", + n->dst_prefix, n->dst_pxlen, n->src_prefix, n->src_pxlen, + ip6_and(n->dst_prefix, ip6_mkmask(n->dst_pxlen)), n->dst_pxlen, + ip6_and(n->src_prefix, ip6_mkmask(n->src_pxlen)), n->src_pxlen); +}; + net_vpn4_: VPN_RD net_ip4_ { $$ = cfg_alloc(sizeof(net_addr_vpn4)); @@ -249,6 +268,7 @@ net_: | net_vpn_ | net_roa_ | net_flow_ + | net_ip6_sadr_ | net_mpls_ ; diff --git a/doc/bird.conf.example2 b/doc/bird.conf.example2 index d7048b64..815651c7 100644 --- a/doc/bird.conf.example2 +++ b/doc/bird.conf.example2 @@ -28,20 +28,15 @@ flow6 table flowtab6; protocol device { - scan time 10; } protocol kernel kernel4 { - scan time 20; - ipv4 { export all; }; } protocol kernel kernel6 { - scan time 20; - ipv6 { export all; }; @@ -169,8 +164,6 @@ protocol pipe { } protocol ospf v2 ospf4 { -# ecmp; - ipv4 { import all; # export where source = RTS_STATIC; @@ -186,8 +179,6 @@ protocol ospf v2 ospf4 { protocol ospf v3 ospf6 { -# ecmp; - ipv6 { import all; # export where source = RTS_STATIC; @@ -251,7 +242,7 @@ protocol bgp { }; # IPv6 with MPLS labels (2/4) - ipv6 multicast { + ipv6 mpls { # explicit IPv6 table table mtab6; import all; diff --git a/filter/f-util.c b/filter/f-util.c index 661941ec..52c13223 100644 --- a/filter/f-util.c +++ b/filter/f-util.c @@ -24,11 +24,11 @@ f_new_inst(void) } struct f_inst * -f_new_dynamic_attr(int type, int f_type UNUSED, int code) +f_new_dynamic_attr(int type, int f_type, int code) { /* FIXME: Remove the f_type parameter? */ struct f_inst *f = f_new_inst(); - f->aux = type; + f->aux = (f_type << 8) | type; f->a2.i = code; return f; } diff --git a/filter/filter.c b/filter/filter.c index 4e17f974..8cf90b53 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -587,7 +587,8 @@ val_format_str(struct f_val v) { static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS; #define runtime(fmt, ...) do { \ - log_rl(&rl_runtime_err, L_ERR "filters, line %d: " fmt, what->lineno, ##__VA_ARGS__); \ + if (!(f_flags & FF_SILENT)) \ + log_rl(&rl_runtime_err, L_ERR "filters, line %d: " fmt, what->lineno, ##__VA_ARGS__); \ res.type = T_RETURN; \ res.val.i = F_ERROR; \ return res; \ @@ -903,7 +904,8 @@ interpret(struct f_inst *what) break; case P('p',','): ONEARG; - if (what->a2.i == F_NOP || (what->a2.i != F_NONL && what->a1.p)) + if ((what->a2.i == F_NOP || (what->a2.i != F_NONL && what->a1.p)) && + !(f_flags & FF_SILENT)) log_commit(*L_INFO, &f_buf); switch (what->a2.i) { @@ -1003,6 +1005,7 @@ interpret(struct f_inst *what) { eattr *e = NULL; u16 code = what->a2.i; + int f_type = what->aux >> 8; if (!(f_flags & FF_FORCE_TMPATTR)) e = ea_find((*f_rte)->attrs->eattrs, code); @@ -1047,7 +1050,7 @@ interpret(struct f_inst *what) switch (what->aux & EAF_TYPE_MASK) { case EAF_TYPE_INT: - res.type = T_INT; + res.type = f_type; res.val.i = e->u.data; break; case EAF_TYPE_ROUTER_ID: @@ -1097,18 +1100,18 @@ interpret(struct f_inst *what) { struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr)); u16 code = what->a2.i; + int f_type = what->aux >> 8; l->next = NULL; l->flags = EALF_SORTED; l->count = 1; l->attrs[0].id = code; l->attrs[0].flags = 0; - l->attrs[0].type = what->aux | EAF_ORIGINATED | EAF_FRESH; + l->attrs[0].type = (what->aux & 0xff) | EAF_ORIGINATED | EAF_FRESH; switch (what->aux & EAF_TYPE_MASK) { case EAF_TYPE_INT: - // Enums are also ints, so allow them in. - if (v1.type != T_INT && (v1.type < T_ENUM_LO || v1.type > T_ENUM_HI)) + if (v1.type != f_type) runtime( "Setting int attribute to non-int value" ); l->attrs[0].u.data = v1.val.i; break; @@ -1793,7 +1796,8 @@ f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struc if (res.type != T_RETURN) { - log_rl(&rl_runtime_err, L_ERR "Filter %s did not return accept nor reject. Make up your mind", filter->name); + if (!(f_flags & FF_SILENT)) + log_rl(&rl_runtime_err, L_ERR "Filter %s did not return accept nor reject. Make up your mind", filter->name); return F_ERROR; } DBG( "done (%u)\n", res.val.i ); diff --git a/filter/filter.h b/filter/filter.h index 89cd80e6..49004c33 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -208,6 +208,7 @@ struct f_trie #define NEW_F_VAL struct f_val * val; val = cfg_alloc(sizeof(struct f_val)); #define FF_FORCE_TMPATTR 1 /* Force all attributes to be temporary */ +#define FF_SILENT 2 /* Silent filter execution */ /* Bird Tests */ struct f_bt_test_suite { @@ -6,50 +6,54 @@ const char * const net_label[] = { - [NET_IP4] = "ipv4", - [NET_IP6] = "ipv6", - [NET_VPN4] = "vpn4", - [NET_VPN6] = "vpn6", - [NET_ROA4] = "roa4", - [NET_ROA6] = "roa6", - [NET_FLOW4] = "flow4", - [NET_FLOW6] = "flow6", + [NET_IP4] = "ipv4", + [NET_IP6] = "ipv6", + [NET_VPN4] = "vpn4", + [NET_VPN6] = "vpn6", + [NET_ROA4] = "roa4", + [NET_ROA6] = "roa6", + [NET_FLOW4] = "flow4", + [NET_FLOW6] = "flow6", + [NET_IP6_SADR]= "ipv6-sadr", [NET_MPLS] = "mpls", }; const u16 net_addr_length[] = { - [NET_IP4] = sizeof(net_addr_ip4), - [NET_IP6] = sizeof(net_addr_ip6), - [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_FLOW4] = 0, - [NET_FLOW6] = 0, + [NET_IP4] = sizeof(net_addr_ip4), + [NET_IP6] = sizeof(net_addr_ip6), + [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_FLOW4] = 0, + [NET_FLOW6] = 0, + [NET_IP6_SADR]= sizeof(net_addr_ip6_sadr), [NET_MPLS] = sizeof(net_addr_mpls), }; const u8 net_max_prefix_length[] = { - [NET_IP4] = IP4_MAX_PREFIX_LENGTH, - [NET_IP6] = IP6_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_FLOW4] = IP4_MAX_PREFIX_LENGTH, - [NET_FLOW6] = IP6_MAX_PREFIX_LENGTH, + [NET_IP4] = IP4_MAX_PREFIX_LENGTH, + [NET_IP6] = IP6_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_FLOW4] = IP4_MAX_PREFIX_LENGTH, + [NET_FLOW6] = IP6_MAX_PREFIX_LENGTH, + [NET_IP6_SADR]= IP6_MAX_PREFIX_LENGTH, [NET_MPLS] = 0, }; const u16 net_max_text_length[] = { - [NET_IP4] = 18, /* "255.255.255.255/32" */ - [NET_IP6] = 43, /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128" */ - [NET_VPN4] = 40, /* "4294967296:4294967296 255.255.255.255/32" */ - [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_IP4] = 18, /* "255.255.255.255/32" */ + [NET_IP6] = 43, /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128" */ + [NET_VPN4] = 40, /* "4294967296:4294967296 255.255.255.255/32" */ + [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_IP6_SADR]= 92, /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128 from ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128" */ [NET_MPLS] = 7, /* "1048575" */ }; @@ -102,6 +106,8 @@ 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_IP6_SADR: + return bsnprintf(buf, buflen, "%I6/%d from %I6/%d", n->ip6_sadr.dst_prefix, n->ip6_sadr.dst_pxlen, n->ip6_sadr.src_prefix, n->ip6_sadr.src_pxlen); case NET_MPLS: return bsnprintf(buf, buflen, "%u", n->mpls.label); } @@ -124,6 +130,7 @@ net_pxmask(const net_addr *a) case NET_VPN6: case NET_ROA6: case NET_FLOW6: + case NET_IP6_SADR: return ipa_from_ip6(ip6_mkmask(net6_pxlen(a))); case NET_MPLS: @@ -156,6 +163,8 @@ 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_IP6_SADR: + return net_compare_ip6_sadr((const net_addr_ip6_sadr *) a, (const net_addr_ip6_sadr *) b); case NET_MPLS: return net_compare_mpls((const net_addr_mpls *) a, (const net_addr_mpls *) b); } @@ -177,6 +186,7 @@ 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_IP6_SADR: return NET_HASH(n, ip6_sadr); case NET_MPLS: return NET_HASH(n, mpls); default: bug("invalid type"); } @@ -198,6 +208,7 @@ 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_IP6_SADR: return NET_VALIDATE(n, ip6_sadr); case NET_MPLS: return NET_VALIDATE(n, mpls); default: return 0; } @@ -222,6 +233,9 @@ net_normalize(net_addr *N) case NET_FLOW6: return net_normalize_ip6(&n->ip6); + case NET_IP6_SADR: + return net_normalize_ip6_sadr(&n->ip6_sadr); + case NET_MPLS: return; } @@ -246,6 +260,9 @@ net_classify(const net_addr *N) case NET_FLOW6: return ip6_zero(n->ip6.prefix) ? (IADDR_HOST | SCOPE_UNIVERSE) : ip6_classify(&n->ip6.prefix); + case NET_IP6_SADR: + return ip6_zero(n->ip6_sadr.dst_prefix) ? (IADDR_HOST | SCOPE_UNIVERSE) : ip6_classify(&n->ip6_sadr.dst_prefix); + case NET_MPLS: return IADDR_HOST | SCOPE_UNIVERSE; } @@ -274,6 +291,11 @@ 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_IP6_SADR: + if (ipa_is_ip4(a)) return 0; + return ip6_zero(ip6_and(ip6_xor(ipa_to_ip6(a), net6_prefix(n)), + ip6_mkmask(net6_pxlen(n)))); + case NET_MPLS: default: return 0; @@ -304,5 +326,6 @@ 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_ip6_sadr, 40); CHECK_NET(net_addr_mpls, 8); } @@ -21,8 +21,9 @@ #define NET_ROA6 6 #define NET_FLOW4 7 #define NET_FLOW6 8 -#define NET_MPLS 9 -#define NET_MAX 10 +#define NET_IP6_SADR 9 +#define NET_MPLS 10 +#define NET_MAX 11 #define NB_IP4 (1 << NET_IP4) #define NB_IP6 (1 << NET_IP6) @@ -32,12 +33,13 @@ #define NB_ROA6 (1 << NET_ROA6) #define NB_FLOW4 (1 << NET_FLOW4) #define NB_FLOW6 (1 << NET_FLOW6) +#define NB_IP6_SADR (1 << NET_IP6_SADR) #define NB_MPLS (1 << NET_MPLS) #define NB_IP (NB_IP4 | NB_IP6) #define NB_VPN (NB_VPN4 | NB_VPN6) #define NB_FLOW (NB_FLOW4 | NB_FLOW6) -#define NB_DEST (NB_IP | NB_VPN | NB_MPLS) +#define NB_DEST (NB_IP | NB_IP6_SADR | NB_VPN | NB_MPLS) #define NB_ANY 0xffffffff @@ -121,6 +123,15 @@ typedef struct net_addr_mpls { u32 label; } net_addr_mpls; +typedef struct net_addr_ip6_sadr { + u8 type; + u8 dst_pxlen; + u16 length; + ip6_addr dst_prefix; + s32 src_pxlen; /* s32 to avoid padding */ + ip6_addr src_prefix; +} net_addr_ip6_sadr; + typedef union net_addr_union { net_addr n; net_addr_ip4 ip4; @@ -131,6 +142,7 @@ typedef union net_addr_union { net_addr_roa6 roa6; net_addr_flow4 flow4; net_addr_flow6 flow6; + net_addr_ip6_sadr ip6_sadr; net_addr_mpls mpls; } net_addr_union; @@ -167,6 +179,9 @@ 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_IP6_SADR(dst_prefix,dst_pxlen,src_prefix,src_pxlen) \ + ((net_addr_ip6_sadr) { NET_IP6_SADR, dst_pxlen, sizeof(net_addr_ip6_sadr), dst_prefix, src_pxlen, src_prefix }) + #define NET_ADDR_MPLS(label) \ ((net_addr_mpls) { NET_MPLS, 20, sizeof(net_addr_mpls), label }) @@ -189,6 +204,9 @@ 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_ip6_sadr(net_addr *a, ip6_addr dst_prefix, uint dst_pxlen, ip6_addr src_prefix, uint src_pxlen) +{ *(net_addr_ip6_sadr *)a = NET_ADDR_IP6_SADR(dst_prefix, dst_pxlen, src_prefix, src_pxlen); } + static inline void net_fill_mpls(net_addr *a, u32 label) { *(net_addr_mpls *)a = NET_ADDR_MPLS(label); } @@ -222,6 +240,16 @@ static inline void net_fill_flow6(net_addr *a, ip6_addr prefix, uint pxlen, byte memcpy(f->data, data, dlen); } +/* Make NET_IP6_SADR from NET_IP6, assuming there is enough space */ +static inline void net_make_ip6_sadr(net_addr *a) +{ + net_addr_ip6_sadr *n = (void *) a; + n->type = NET_IP6_SADR; + n->length = sizeof(net_addr_ip6_sadr); + n->src_pxlen = 0; + n->src_prefix = IP6_NONE; +} + static inline int net_val_match(u8 type, u32 mask) { return !!((1 << type) & mask); } @@ -261,6 +289,7 @@ static inline ip_addr net_prefix(const net_addr *a) case NET_VPN6: case NET_ROA6: case NET_FLOW6: + case NET_IP6_SADR: return ipa_from_ip6(net6_prefix(a)); case NET_MPLS: @@ -328,6 +357,9 @@ static inline int net_equal_flow4(const net_addr_flow4 *a, const net_addr_flow4 static inline int net_equal_flow6(const net_addr_flow6 *a, const net_addr_flow6 *b) { return net_equal((const net_addr *) a, (const net_addr *) b); } +static inline int net_equal_ip6_sadr(const net_addr_ip6_sadr *a, const net_addr_ip6_sadr *b) +{ return !memcmp(a, b, sizeof(net_addr_ip6_sadr)); } + static inline int net_equal_mpls(const net_addr_mpls *a, const net_addr_mpls *b) { return !memcmp(a, b, sizeof(net_addr_mpls)); } @@ -338,6 +370,12 @@ 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_dst_ip6_sadr(const net_addr_ip6_sadr *a, const net_addr_ip6_sadr *b) +{ return ip6_equal(a->dst_prefix, b->dst_prefix) && (a->dst_pxlen == b->dst_pxlen); } + +static inline int net_equal_src_ip6_sadr(const net_addr_ip6_sadr *a, const net_addr_ip6_sadr *b) +{ return ip6_equal(a->src_prefix, b->src_prefix) && (a->src_pxlen == b->src_pxlen); } + static inline int net_zero_ip4(const net_addr_ip4 *a) { return !a->pxlen && ip4_zero(a->prefix); } @@ -391,6 +429,13 @@ 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_ip6_sadr(const net_addr_ip6_sadr *a, const net_addr_ip6_sadr *b) +{ + return + ip6_compare(a->dst_prefix, b->dst_prefix) ?: uint_cmp(a->dst_pxlen, b->dst_pxlen) ?: + ip6_compare(a->src_prefix, b->src_prefix) ?: uint_cmp(a->src_pxlen, b->src_pxlen); +} + 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 +469,9 @@ 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_ip6_sadr(net_addr_ip6_sadr *dst, const net_addr_ip6_sadr *src) +{ memcpy(dst, src, sizeof(net_addr_ip6_sadr)); } + static inline void net_copy_mpls(net_addr_mpls *dst, const net_addr_mpls *src) { memcpy(dst, src, sizeof(net_addr_mpls)); } @@ -456,6 +504,9 @@ 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_ip6_sadr(const net_addr_ip6_sadr *n) +{ return net_hash_ip6((net_addr_ip6 *) n); } + static inline u32 net_hash_mpls(const net_addr_mpls *n) { return n->label; } @@ -508,6 +559,9 @@ static inline int net_validate_flow6(const net_addr_flow6 *n) static inline int net_validate_mpls(const net_addr_mpls *n) { return n->label < (1 << 20); } +static inline int net_validate_ip6_sadr(const net_addr_ip6_sadr *n) +{ return net_validate_px6(n->dst_prefix, n->dst_pxlen) && net_validate_px6(n->src_prefix, n->src_pxlen); } + int net_validate(const net_addr *N); @@ -523,6 +577,12 @@ static inline void net_normalize_vpn4(net_addr_vpn4 *n) static inline void net_normalize_vpn6(net_addr_vpn6 *n) { net_normalize_ip6((net_addr_ip6 *) n); } +static inline void net_normalize_ip6_sadr(net_addr_ip6_sadr *n) +{ + n->dst_prefix = ip6_and(n->dst_prefix, ip6_mkmask(n->dst_pxlen)); + n->src_prefix = ip6_and(n->src_prefix, ip6_mkmask(n->src_pxlen)); +} + void net_normalize(net_addr *N); @@ -530,17 +590,29 @@ int net_classify(const net_addr *N); int net_format(const net_addr *N, char *buf, int buflen); int rd_format(const u64 rd, char *buf, int buflen); -static inline int ipa_in_net_ip4(ip4_addr a, const net_addr_ip4 *n) -{ return ip4_zero(ip4_and(ip4_xor(a, n->prefix), ip4_mkmask(n->pxlen))); } +static inline int ipa_in_px4(ip4_addr a, ip4_addr prefix, uint pxlen) +{ return ip4_zero(ip4_and(ip4_xor(a, prefix), ip4_mkmask(pxlen))); } -static inline int net_in_net_ip4(const net_addr_ip4 *a, const net_addr_ip4 *b) -{ return (a->pxlen >= b->pxlen) && ipa_in_net_ip4(a->prefix, b); } +static inline int ipa_in_px6(ip6_addr a, ip6_addr prefix, uint pxlen) +{ return ip6_zero(ip6_and(ip6_xor(a, prefix), ip6_mkmask(pxlen))); } + +static inline int ipa_in_net_ip4(ip4_addr a, const net_addr_ip4 *n) +{ return ipa_in_px4(a, n->prefix, n->pxlen); } static inline int ipa_in_net_ip6(ip6_addr a, const net_addr_ip6 *n) -{ return ip6_zero(ip6_and(ip6_xor(a, n->prefix), ip6_mkmask(n->pxlen))); } +{ return ipa_in_px6(a, n->prefix, n->pxlen); } + +static inline int net_in_net_ip4(const net_addr_ip4 *a, const net_addr_ip4 *b) +{ return (a->pxlen >= b->pxlen) && ipa_in_px4(a->prefix, b->prefix, b->pxlen); } static inline int net_in_net_ip6(const net_addr_ip6 *a, const net_addr_ip6 *b) -{ return (a->pxlen >= b->pxlen) && ipa_in_net_ip6(a->prefix, b); } +{ return (a->pxlen >= b->pxlen) && ipa_in_px6(a->prefix, b->prefix, b->pxlen); } + +static inline int net_in_net_dst_ip6_sadr(const net_addr_ip6_sadr *a, const net_addr_ip6_sadr *b) +{ return (a->dst_pxlen >= b->dst_pxlen) && ipa_in_px6(a->dst_prefix, b->dst_prefix, b->dst_pxlen); } + +static inline int net_in_net_src_ip6_sadr(const net_addr_ip6_sadr *a, const net_addr_ip6_sadr *b) +{ return (a->src_pxlen >= b->src_pxlen) && ipa_in_px6(a->src_prefix, b->src_prefix, b->src_pxlen); } int ipa_in_netX(const ip_addr A, const net_addr *N); int net_in_netX(const net_addr *A, const net_addr *N); diff --git a/nest/a-path.c b/nest/a-path.c index 32ffc72c..c0d16c30 100644 --- a/nest/a-path.c +++ b/nest/a-path.c @@ -810,7 +810,7 @@ as_path_match(const struct adata *path, struct f_path_mask *mask) case PM_ASN_RANGE: val = mask->val; val2 = mask->val2; - goto step; + goto step; case PM_QUESTION: step: nh = nl = -1; diff --git a/nest/a-path_test.c b/nest/a-path_test.c index 5e122396..a71b48ba 100644 --- a/nest/a-path_test.c +++ b/nest/a-path_test.c @@ -43,14 +43,14 @@ t_as_path_match(void) bt_debug("Prepending ASN: %10u \n", val); if (i == 0) - first_prepended = val; + first_prepended = val; if (i == AS_PATH_LENGTH-1) - last_prepended = val; + last_prepended = val; mask[i].kind = PM_ASN; mask[i].val = val; if (i) - mask[i].next = &mask[i-1]; + mask[i].next = &mask[i-1]; } bt_assert_msg(as_path_match(as_path, &mask[AS_PATH_LENGTH-1]), "Mask should match with AS path"); @@ -60,7 +60,7 @@ * the new one. When the consumer processes everything in the buffer * queue, it calls cli_written(), tha frees all buffers (except the * first one) and schedules cli.event . - * + * */ #include "nest/bird.h" @@ -136,7 +136,7 @@ cli_printf(cli *c, int code, char *msg, ...) } else if (cd == CLI_ASYNC_CODE) { - size = 1; buf[0] = '+'; + size = 1; buf[0] = '+'; errcode = cd; } else diff --git a/nest/config.Y b/nest/config.Y index 044aba2b..ab09a10c 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, SADR, MPLS) 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) @@ -77,7 +77,7 @@ CF_KEYWORDS(TIMEFORMAT, ISO, SHORT, LONG, ROUTE, PROTOCOL, BASE, LOG, S, MS, US) CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS) /* For r_args_channel */ -CF_KEYWORDS(IPV4, IPV4_MC, IPV4_MPLS, IPV6, IPV6_MC, IPV6_MPLS, VPN4, VPN4_MC, VPN4_MPLS, VPN6, VPN6_MC, VPN6_MPLS, ROA4, ROA6, FLOW4, FLOW6, MPLS, PRI, SEC) +CF_KEYWORDS(IPV4, IPV4_MC, IPV4_MPLS, IPV6, IPV6_MC, IPV6_MPLS, IPV6_SADR, VPN4, VPN4_MC, VPN4_MPLS, VPN6, VPN6_MC, VPN6_MPLS, ROA4, ROA6, FLOW4, FLOW6, MPLS, PRI, SEC) CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT, RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE, BABEL) @@ -134,6 +134,7 @@ gr_opts: GRACEFUL RESTART WAIT expr ';' { new_config->gr_wait = $4; } ; net_type: IPV4 { $$ = NET_IP4; } | IPV6 { $$ = NET_IP6; } + | IPV6 SADR { $$ = NET_IP6_SADR; } | VPN4 { $$ = NET_VPN4; } | VPN6 { $$ = NET_VPN6; } | ROA4 { $$ = NET_ROA4; } @@ -143,7 +144,7 @@ net_type: | MPLS { $$ = NET_MPLS; } ; -CF_ENUM(T_ENUM_NETTYPE, NET_, IP4, IP6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6) +CF_ENUM(T_ENUM_NETTYPE, NET_, IP4, IP6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, IP6_SADR) /* Creation of routing tables */ @@ -151,7 +152,7 @@ CF_ENUM(T_ENUM_NETTYPE, NET_, IP4, IP6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6) CF_ADDTO(conf, table) table_sorted: - { $$ = 0; } + { $$ = 0; } | SORTED { $$ = 1; } ; @@ -454,9 +455,9 @@ password_item: password_item_begin: PASSWORD text { if (!this_p_list) { - this_p_list = cfg_alloc(sizeof(list)); - init_list(this_p_list); - password_id = 1; + this_p_list = cfg_alloc(sizeof(list)); + init_list(this_p_list); + password_id = 1; } this_p_item = cfg_alloc(sizeof (struct password_item)); this_p_item->password = $2; @@ -625,6 +626,7 @@ r_args_for: } | net_vpn4_ | net_vpn6_ + | net_ip6_sadr_ | VPN_RD IP4 { $$ = cfg_alloc(sizeof(net_addr_vpn4)); net_fill_vpn4($$, $2, IP4_MAX_PREFIX_LENGTH, $1); @@ -633,6 +635,10 @@ r_args_for: $$ = cfg_alloc(sizeof(net_addr_vpn6)); net_fill_vpn6($$, $2, IP6_MAX_PREFIX_LENGTH, $1); } + | IP6 FROM IP6 { + $$ = cfg_alloc(sizeof(net_addr_ip6_sadr)); + net_fill_ip6_sadr($$, $1, IP6_MAX_PREFIX_LENGTH, $3, IP6_MAX_PREFIX_LENGTH); + } | SYM { if ($1->class == (SYM_CONSTANT | T_IP)) { @@ -666,6 +672,7 @@ r_args_channel: | IPV6 { $$ = "ipv6"; } | IPV6_MC { $$ = "ipv6-mc"; } | IPV6_MPLS { $$ = "ipv6-mpls"; } + | IPV6_SADR { $$ = "ipv6-sadr"; } | VPN4 { $$ = "vpn4"; } | VPN4_MC { $$ = "vpn4-mc"; } | VPN4_MPLS { $$ = "vpn4-mpls"; } diff --git a/nest/iface.c b/nest/iface.c index 54c16c58..a633f748 100644 --- a/nest/iface.c +++ b/nest/iface.c @@ -317,7 +317,7 @@ if_update(struct iface *new) new->sysdep = i->sysdep; memcpy(&new->addrs, &i->addrs, sizeof(i->addrs)); memcpy(i, new, sizeof(*i)); - i->flags &= ~IF_UP; /* IF_TMP_DOWN will be added later */ + i->flags &= ~IF_UP; /* IF_TMP_DOWN will be added later */ goto newif; } diff --git a/nest/mrtdump.h b/nest/mrtdump.h index 73932553..28b3bdfd 100644 --- a/nest/mrtdump.h +++ b/nest/mrtdump.h @@ -28,4 +28,3 @@ void mrt_dump_message(struct proto *p, u16 type, u16 subtype, byte *buf, u32 len); #endif - diff --git a/nest/neighbor.c b/nest/neighbor.c index fb05d96c..4f93e29e 100644 --- a/nest/neighbor.c +++ b/nest/neighbor.c @@ -156,7 +156,7 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags) WALK_LIST(i, iface_list) if ((!p->vrf || p->vrf == i->master) && ((scope = if_connected(a, i, &addr)) >= 0)) - { + { ifa = i; break; } diff --git a/nest/proto-hooks.c b/nest/proto-hooks.c index 92863f8e..71cddd64 100644 --- a/nest/proto-hooks.c +++ b/nest/proto-hooks.c @@ -281,7 +281,7 @@ int import_control(struct proto *p, rte **e, ea_list **attrs, struct linpool *po /** * rte_recalculate - prepare routes for comparison - * @table: a routing table + * @table: a routing table * @net: a network entry * @new: new route for the network * @old: old route for the network diff --git a/nest/protocol.h b/nest/protocol.h index 9afd3a0a..8a22d76b 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -337,7 +337,7 @@ void proto_notify_state(struct proto *p, unsigned state); * * HUNGRY ----> FEEDING * ^ | - * | V + * | V * FLUSHING <---- HAPPY * * States: HUNGRY Protocol either administratively down (i.e., diff --git a/nest/route.h b/nest/route.h index 43d7d696..79127519 100644 --- a/nest/route.h +++ b/nest/route.h @@ -74,7 +74,7 @@ static inline struct fib_node * fib_user_to_node(struct fib *f, void *e) void fib_init(struct fib *f, pool *p, uint addr_type, uint node_size, uint node_offset, uint hash_order, fib_init_fn init); void *fib_find(struct fib *, const net_addr *); /* Find or return NULL if doesn't exist */ void *fib_get_chain(struct fib *f, const net_addr *a); /* Find first node in linked list from hash table */ -void *fib_get(struct fib *, const net_addr *); /* Find or create new if nonexistent */ +void *fib_get(struct fib *, const net_addr *); /* Find or create new if nonexistent */ void *fib_route(struct fib *, const net_addr *); /* Longest-match routing lookup */ void fib_delete(struct fib *, void *); /* Remove fib entry */ void fib_free(struct fib *); /* Destroy the fib */ @@ -104,7 +104,7 @@ void fit_put_next(struct fib *f, struct fib_iterator *i, struct fib_node *n, uin type *z; \ for(;;) { \ if (!fn_) \ - { \ + { \ if (++hpos_ >= count_) \ break; \ fn_ = (fib)->hash_table[hpos_]; \ @@ -282,7 +282,7 @@ void rt_preconfig(struct config *); void rt_commit(struct config *new, struct config *old); void rt_lock_table(rtable *); void rt_unlock_table(rtable *); -void rt_setup(pool *, rtable *, char *, struct rtable_config *); +void rt_setup(pool *, rtable *, struct rtable_config *); static inline net *net_find(rtable *tab, const net_addr *addr) { return (net *) fib_find(&tab->fib, addr); } static inline net *net_find_valid(rtable *tab, const net_addr *addr) { net *n = net_find(tab, addr); return (n && rte_is_valid(n->routes)) ? n : NULL; } @@ -663,7 +663,7 @@ extern struct protocol *attr_class_to_protocol[EAP_MAX]; * Default protocol preferences */ -#define DEF_PREF_DIRECT 240 /* Directly connected */ +#define DEF_PREF_DIRECT 240 /* Directly connected */ #define DEF_PREF_STATIC 200 /* Static route */ #define DEF_PREF_OSPF 150 /* OSPF intra-area, inter-area and type 1 external routes */ #define DEF_PREF_BABEL 130 /* Babel */ diff --git a/nest/rt-attr.c b/nest/rt-attr.c index 761ba9fe..881687de 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -1204,7 +1204,7 @@ rta_dump(rta *a) static char *rts[] = { "RTS_DUMMY", "RTS_STATIC", "RTS_INHERIT", "RTS_DEVICE", "RTS_STAT_DEV", "RTS_REDIR", "RTS_RIP", "RTS_OSPF", "RTS_OSPF_IA", "RTS_OSPF_EXT1", - "RTS_OSPF_EXT2", "RTS_BGP", "RTS_PIPE", "RTS_BABEL" }; + "RTS_OSPF_EXT2", "RTS_BGP", "RTS_PIPE", "RTS_BABEL" }; static char *rtd[] = { "", " DEV", " HOLE", " UNREACH", " PROHIBIT" }; debug("p=%s uc=%d %s %s%s h=%04x", diff --git a/nest/rt-dev.c b/nest/rt-dev.c index b3d5bf97..718c4578 100644 --- a/nest/rt-dev.c +++ b/nest/rt-dev.c @@ -159,13 +159,13 @@ dev_copy_config(struct proto_config *dest, struct proto_config *src) } struct protocol proto_device = { - .name = "Direct", - .template = "direct%d", + .name = "Direct", + .template = "direct%d", .preference = DEF_PREF_DIRECT, .channel_mask = NB_IP, .proto_size = sizeof(struct rt_dev_proto), .config_size = sizeof(struct rt_dev_config), - .init = dev_init, - .reconfigure = dev_reconfigure, - .copy_config = dev_copy_config + .init = dev_init, + .reconfigure = dev_reconfigure, + .copy_config = dev_copy_config }; diff --git a/nest/rt-fib.c b/nest/rt-fib.c index 24a7facc..18ccbfc3 100644 --- a/nest/rt-fib.c +++ b/nest/rt-fib.c @@ -92,8 +92,7 @@ fib_ht_free(struct fib_node **h) } -static u32 -fib_hash(struct fib *f, const net_addr *a); +static inline u32 fib_hash(struct fib *f, const net_addr *a); /** * fib_init - initialize a new FIB @@ -198,24 +197,11 @@ fib_rehash(struct fib *f, int step) }) -static u32 +static inline u32 fib_hash(struct fib *f, const net_addr *a) { - ASSERT(f->addr_type == a->type); - - switch (f->addr_type) - { - case NET_IP4: return FIB_HASH(f, a, ip4); - case NET_IP6: return FIB_HASH(f, a, ip6); - case NET_VPN4: return FIB_HASH(f, a, vpn4); - 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_FLOW4: return FIB_HASH(f, a, flow4); - case NET_FLOW6: return FIB_HASH(f, a, flow6); - case NET_MPLS: return FIB_HASH(f, a, mpls); - default: bug("invalid type"); - } + /* Same as FIB_HASH() */ + return net_hash(a) >> f->hash_shift; } void * @@ -250,6 +236,7 @@ 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_IP6_SADR: return FIB_FIND(f, a, ip6_sadr); case NET_MPLS: return FIB_FIND(f, a, mpls); default: bug("invalid type"); } @@ -270,6 +257,7 @@ 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_IP6_SADR: FIB_INSERT(f, a, e, ip6_sadr); return; case NET_MPLS: FIB_INSERT(f, a, e, mpls); return; default: bug("invalid type"); } @@ -617,7 +605,7 @@ fib_histogram(struct fib *f) for (e = f->hash_table[i]; e != NULL; e = e->next) j++; if (j > 0) - log(L_WARN "Histogram line %d: %d", i, j); + log(L_WARN "Histogram line %d: %d", i, j); } log(L_WARN "Histogram dump end"); diff --git a/nest/rt-show.c b/nest/rt-show.c index 41a141a2..1f1b73d2 100644 --- a/nest/rt-show.c +++ b/nest/rt-show.c @@ -74,7 +74,7 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm char weight[16] = ""; if (nh->labels) - { + { lsp += bsprintf(lsp, " mpls %d", nh->label[0]); for (int i=1;i<nh->labels; i++) lsp += bsprintf(lsp, "/%d", nh->label[i]); @@ -129,7 +129,7 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d) /* Special case for merged export */ if ((d->export_mode == RSEM_EXPORT) && (ec->ra_mode == RA_MERGED)) - { + { rte *rt_free; e = rt_export_merged(ec, n, &rt_free, &tmpa, c->show_pool, 1); pass = 1; @@ -156,7 +156,8 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d) * command may change the export filter and do not update routes. */ int do_export = (ic > 0) || - (f_run(ec->out_filter, &e, &tmpa, c->show_pool, FF_FORCE_TMPATTR) <= F_ACCEPT); + (f_run(ec->out_filter, &e, &tmpa, c->show_pool, + FF_FORCE_TMPATTR | FF_SILENT) <= F_ACCEPT); if (do_export != (d->export_mode == RSEM_EXPORT)) goto skip; @@ -418,4 +419,3 @@ rt_show(struct rt_show_data *d) cli_msg(8001, "Network not found"); } } - diff --git a/nest/rt-table.c b/nest/rt-table.c index b0dd6d3f..686d0e84 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -85,6 +85,45 @@ net_route_ip6(rtable *t, net_addr_ip6 *n) return r; } +static inline void * +net_route_ip6_sadr(rtable *t, net_addr_ip6_sadr *n) +{ + struct fib_node *fn; + + while (1) + { + net *best = NULL; + int best_pxlen = 0; + + /* We need to do dst first matching. Since sadr addresses are hashed on dst + prefix only, find the hash table chain and go through it to find the + match with the smallest matching src prefix. */ + for (fn = fib_get_chain(&t->fib, (net_addr *) n); fn; fn = fn->next) + { + net_addr_ip6_sadr *a = (void *) fn->addr; + + if (net_equal_dst_ip6_sadr(n, a) && + net_in_net_src_ip6_sadr(n, a) && + (a->src_pxlen >= best_pxlen)) + { + best = fib_node_to_user(&t->fib, fn); + best_pxlen = a->src_pxlen; + } + } + + if (best) + return best; + + if (!n->dst_pxlen) + break; + + n->dst_pxlen--; + ip6_clrbit(&n->dst_prefix, n->dst_pxlen); + } + + return NULL; +} + void * net_route(rtable *tab, const net_addr *n) { @@ -105,6 +144,9 @@ net_route(rtable *tab, const net_addr *n) case NET_ROA6: return net_route_ip6(tab, (net_addr_ip6 *) n0); + case NET_IP6_SADR: + return net_route_ip6_sadr(tab, (net_addr_ip6_sadr *) n0); + default: return NULL; } @@ -387,7 +429,8 @@ export_filter_(struct channel *c, rte *rt0, rte **rt_free, ea_list **tmpa, linpo } v = filter && ((filter == FILTER_REJECT) || - (f_run(filter, &rt, tmpa, pool, FF_FORCE_TMPATTR) > F_ACCEPT)); + (f_run(filter, &rt, tmpa, pool, + FF_FORCE_TMPATTR | (silent ? FF_SILENT : 0)) > F_ACCEPT)); if (v) { if (silent) @@ -613,9 +656,9 @@ rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_chang old_meet = 1; } - /* + /* * Second, handle the feed case. That means we do not care for - * old_best. It is NULL for feed, and the new_best for refeed. + * old_best. It is NULL for feed, and the new_best for refeed. * For refeed, there is a hack similar to one in rt_notify_basic() * to ensure withdraws in case of changed filters */ @@ -824,7 +867,7 @@ rt_notify_merged(struct channel *c, net *net, rte *new_changed, rte *old_changed * @new_best: the new best route for the same network * @old_best: the previous best route for the same network * @before_old: The previous route before @old for the same network. - * If @before_old is NULL @old was the first. + * If @before_old is NULL @old was the first. * * This function gets a routing table update and announces it * to all protocols that acccepts given type of route announcement @@ -1386,7 +1429,7 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src) /* Independent call to rte_announce(), used from next hop recalculation, outside of rte_update(). new must be non-NULL */ -static inline void +static inline void rte_announce_i(rtable *tab, unsigned type, net *net, rte *new, rte *old, rte *new_best, rte *old_best) { @@ -1419,7 +1462,8 @@ rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter) ea_list *tmpa = rte_make_tmp_attrs(rt, rte_update_pool); int v = p->import_control ? p->import_control(p, &rt, &tmpa, rte_update_pool) : 0; if (v == RIC_PROCESS) - v = (f_run(filter, &rt, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) <= F_ACCEPT); + v = (f_run(filter, &rt, &tmpa, rte_update_pool, + FF_FORCE_TMPATTR | FF_SILENT) <= F_ACCEPT); /* Discard temporary rte */ if (rt != n->routes) @@ -1597,22 +1641,19 @@ rt_event(void *ptr) } void -rt_setup(pool *p, rtable *t, char *name, struct rtable_config *cf) +rt_setup(pool *p, rtable *t, struct rtable_config *cf) { bzero(t, sizeof(*t)); - t->name = name; + t->name = cf->name; t->config = cf; - t->addr_type = cf ? cf->addr_type : NET_IP4; + t->addr_type = cf->addr_type; fib_init(&t->fib, p, t->addr_type, sizeof(net), OFFSETOF(net, n), 0, NULL); init_list(&t->channels); - if (cf) - { - t->rt_event = ev_new(p); - t->rt_event->hook = rt_event; - t->rt_event->data = t; - t->gc_time = current_time(); - } + t->rt_event = ev_new(p); + t->rt_event->hook = rt_event; + t->rt_event->data = t; + t->gc_time = current_time(); } /** @@ -2088,7 +2129,7 @@ rt_commit(struct config *new, struct config *old) { rtable *t = mb_alloc(rt_table_pool, sizeof(struct rtable)); DBG("\t%s: created\n", r->name); - rt_setup(rt_table_pool, t, r->name, r); + rt_setup(rt_table_pool, t, r); add_tail(&routing_tables, &t->n); r->table = t; } @@ -2358,7 +2399,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); @@ -2390,12 +2431,13 @@ static int rt_update_hostentry(rtable *tab, struct hostentry *he) { rta *old_src = he->src; + int direct = 0; int pxlen = 0; /* Reset the hostentry */ he->src = NULL; - he->nexthop_linkable = 0; he->dest = RTD_UNREACHABLE; + he->nexthop_linkable = 0; he->igp_metric = 0; net_addr he_addr; @@ -2415,9 +2457,7 @@ rt_update_hostentry(rtable *tab, struct hostentry *he) goto done; } - he->dest = a->dest; - he->nexthop_linkable = 1; - if (he->dest == RTD_UNICAST) + if (a->dest == RTD_UNICAST) { for (struct nexthop *nh = &(a->nh); nh; nh = nh->next) if (ipa_zero(nh->gw)) @@ -2430,12 +2470,13 @@ rt_update_hostentry(rtable *tab, struct hostentry *he) goto done; } - he->nexthop_linkable = 0; - break; + direct++; } } he->src = rta_clone(a); + he->dest = a->dest; + he->nexthop_linkable = !direct; he->igp_metric = rt_get_igp_metric(e); } diff --git a/proto/babel/babel.c b/proto/babel/babel.c index aa7e8b68..88c4711e 100644 --- a/proto/babel/babel.c +++ b/proto/babel/babel.c @@ -1935,8 +1935,10 @@ babel_show_neighbors(struct proto *P, char *iff) } static void -babel_show_entries_(struct babel_proto *p UNUSED, struct fib *rtable) +babel_show_entries_(struct babel_proto *p, struct fib *rtable) { + int width = babel_sadr_enabled(p) ? -54 : -24; + FIB_WALK(rtable, struct babel_entry, e) { struct babel_route *r = NULL; @@ -1950,13 +1952,13 @@ babel_show_entries_(struct babel_proto *p UNUSED, struct fib *rtable) srcs++; if (e->valid) - cli_msg(-1025, "%-24N %-23lR %6u %5u %7u %7u", + cli_msg(-1025, "%-*N %-23lR %6u %5u %7u %7u", width, e->n.addr, e->router_id, e->metric, e->seqno, rts, srcs); else if (r = e->selected) - cli_msg(-1025, "%-24N %-23lR %6u %5u %7u %7u", + cli_msg(-1025, "%-*N %-23lR %6u %5u %7u %7u", width, e->n.addr, r->router_id, r->metric, r->seqno, rts, srcs); else - cli_msg(-1025, "%-24N %-23s %6s %5s %7u %7u", + cli_msg(-1025, "%-*N %-23s %6s %5s %7u %7u", width, e->n.addr, "<none>", "-", "-", rts, srcs); } FIB_WALK_END; @@ -1966,6 +1968,7 @@ void babel_show_entries(struct proto *P) { struct babel_proto *p = (void *) P; + int width = babel_sadr_enabled(p) ? -54 : -24; if (p->p.proto_state != PS_UP) { @@ -1975,7 +1978,7 @@ babel_show_entries(struct proto *P) } cli_msg(-1025, "%s:", p->p.name); - cli_msg(-1025, "%-24s %-23s %6s %5s %7s %7s", + cli_msg(-1025, "%-*s %-23s %6s %5s %7s %7s", width, "Prefix", "Router ID", "Metric", "Seqno", "Routes", "Sources"); babel_show_entries_(p, &p->ip4_rtable); @@ -1985,8 +1988,10 @@ babel_show_entries(struct proto *P) } static void -babel_show_routes_(struct babel_proto *p UNUSED, struct fib *rtable) +babel_show_routes_(struct babel_proto *p, struct fib *rtable) { + int width = babel_sadr_enabled(p) ? -54 : -24; + FIB_WALK(rtable, struct babel_entry, e) { struct babel_route *r; @@ -1994,7 +1999,7 @@ babel_show_routes_(struct babel_proto *p UNUSED, struct fib *rtable) { char c = (r == e->selected) ? '*' : (r->feasible ? '+' : ' '); btime time = r->expires ? r->expires - current_time() : 0; - cli_msg(-1025, "%-24N %-25I %-10s %5u %c %5u %7t", + cli_msg(-1025, "%-*N %-25I %-10s %5u %c %5u %7t", width, e->n.addr, r->next_hop, r->neigh->ifa->ifname, r->metric, c, r->seqno, MAX(time, 0)); } @@ -2006,6 +2011,7 @@ void babel_show_routes(struct proto *P) { struct babel_proto *p = (void *) P; + int width = babel_sadr_enabled(p) ? -54 : -24; if (p->p.proto_state != PS_UP) { @@ -2015,7 +2021,7 @@ babel_show_routes(struct proto *P) } cli_msg(-1025, "%s:", p->p.name); - cli_msg(-1025, "%-24s %-25s %-9s %6s F %5s %7s", + cli_msg(-1025, "%-*s %-25s %-9s %6s F %5s %7s", width, "Prefix", "Nexthop", "Interface", "Metric", "Seqno", "Expires"); babel_show_routes_(p, &p->ip4_rtable); @@ -2139,7 +2145,7 @@ babel_rt_notify(struct proto *P, struct channel *c UNUSED, struct network *net, e = babel_get_entry(p, net->n.addr); /* Activate triggered updates */ - if ((e->valid |= BABEL_ENTRY_VALID) || + if ((e->valid != BABEL_ENTRY_VALID) || (e->router_id != rt_router_id)) { babel_trigger_update(p); @@ -2182,14 +2188,32 @@ babel_rte_same(struct rte *new, struct rte *old) } +static void +babel_postconfig(struct proto_config *CF) +{ + struct babel_config *cf = (void *) CF; + struct channel_config *ip4, *ip6, *ip6_sadr; + + ip4 = proto_cf_find_channel(CF, NET_IP4); + ip6 = proto_cf_find_channel(CF, NET_IP6); + ip6_sadr = proto_cf_find_channel(CF, NET_IP6_SADR); + + if (ip6 && ip6_sadr) + cf_error("Both ipv6 and ipv6-sadr channels"); + + cf->ip4_channel = ip4; + cf->ip6_channel = ip6 ?: ip6_sadr; +} + static struct proto * babel_init(struct proto_config *CF) { struct proto *P = proto_new(CF); struct babel_proto *p = (void *) P; + struct babel_config *cf = (void *) CF; - proto_configure_channel(P, &p->ip4_channel, proto_cf_find_channel(CF, NET_IP4)); - proto_configure_channel(P, &p->ip6_channel, proto_cf_find_channel(CF, NET_IP6)); + proto_configure_channel(P, &p->ip4_channel, cf->ip4_channel); + proto_configure_channel(P, &p->ip6_channel, cf->ip6_channel); P->if_notify = babel_if_notify; P->rt_notify = babel_rt_notify; @@ -2207,10 +2231,11 @@ babel_start(struct proto *P) { struct babel_proto *p = (void *) P; struct babel_config *cf = (void *) P->cf; + u8 ip6_type = cf->ip6_channel ? cf->ip6_channel->net_type : NET_IP6; fib_init(&p->ip4_rtable, P->pool, NET_IP4, sizeof(struct babel_entry), OFFSETOF(struct babel_entry, n), 0, babel_init_entry); - fib_init(&p->ip6_rtable, P->pool, NET_IP6, sizeof(struct babel_entry), + fib_init(&p->ip6_rtable, P->pool, ip6_type, sizeof(struct babel_entry), OFFSETOF(struct babel_entry, n), 0, babel_init_entry); init_list(&p->interfaces); @@ -2258,11 +2283,15 @@ babel_reconfigure(struct proto *P, struct proto_config *CF) { struct babel_proto *p = (void *) P; struct babel_config *new = (void *) CF; + u8 ip6_type = new->ip6_channel ? new->ip6_channel->net_type : NET_IP6; TRACE(D_EVENTS, "Reconfiguring"); - if (!proto_configure_channel(P, &p->ip4_channel, proto_cf_find_channel(CF, NET_IP4)) || - !proto_configure_channel(P, &p->ip6_channel, proto_cf_find_channel(CF, NET_IP6))) + if (p->ip6_rtable.addr_type != ip6_type) + return 0; + + if (!proto_configure_channel(P, &p->ip4_channel, new->ip4_channel) || + !proto_configure_channel(P, &p->ip6_channel, new->ip6_channel)) return 0; p->p.cf = CF; @@ -2280,9 +2309,10 @@ struct protocol proto_babel = { .template = "babel%d", .attr_class = EAP_BABEL, .preference = DEF_PREF_BABEL, - .channel_mask = NB_IP, + .channel_mask = NB_IP | NB_IP6_SADR, .proto_size = sizeof(struct babel_proto), .config_size = sizeof(struct babel_config), + .postconfig = babel_postconfig, .init = babel_init, .dump = babel_dump, .start = babel_start, diff --git a/proto/babel/babel.h b/proto/babel/babel.h index 1128d261..b194ce30 100644 --- a/proto/babel/babel.h +++ b/proto/babel/babel.h @@ -85,7 +85,10 @@ enum babel_tlv_type { enum babel_subtlv_type { BABEL_SUBTLV_PAD1 = 0, - BABEL_SUBTLV_PADN = 1 + BABEL_SUBTLV_PADN = 1, + + /* Mandatory subtlvs */ + BABEL_SUBTLV_SOURCE_PREFIX = 128, }; enum babel_iface_type { @@ -109,6 +112,9 @@ struct babel_config { struct proto_config c; list iface_list; /* List of iface configs (struct babel_iface_config) */ uint hold_time; /* Time to hold stale entries and unreachable routes */ + + struct channel_config *ip4_channel; + struct channel_config *ip6_channel; }; struct babel_iface_config { @@ -303,7 +309,10 @@ struct babel_msg_update { u16 seqno; u16 metric; u64 router_id; - net_addr net; + union { + net_addr net; + net_addr_ip6_sadr net_sadr; + }; ip_addr next_hop; ip_addr sender; }; @@ -311,7 +320,10 @@ struct babel_msg_update { struct babel_msg_route_request { u8 type; u8 full; - net_addr net; + union { + net_addr net; + net_addr_ip6_sadr net_sadr; + }; }; struct babel_msg_seqno_request { @@ -319,7 +331,10 @@ struct babel_msg_seqno_request { u8 hop_count; u16 seqno; u64 router_id; - net_addr net; + union { + net_addr net; + net_addr_ip6_sadr net_sadr; + }; ip_addr sender; }; @@ -339,6 +354,8 @@ struct babel_msg_node { union babel_msg msg; }; +static inline int babel_sadr_enabled(struct babel_proto *p) +{ return p->ip6_rtable.addr_type == NET_IP6_SADR; } /* babel.c */ void babel_handle_ack_req(union babel_msg *msg, struct babel_iface *ifa); diff --git a/proto/babel/packets.c b/proto/babel/packets.c index dd86222a..59678678 100644 --- a/proto/babel/packets.c +++ b/proto/babel/packets.c @@ -105,6 +105,13 @@ struct babel_tlv_seqno_request { u8 addr[0]; } PACKED; +struct babel_subtlv_source_prefix { + u8 type; + u8 length; + u8 plen; + u8 addr[0]; +} PACKED; + /* Hello flags */ #define BABEL_HF_UNICAST 0x8000 @@ -127,6 +134,7 @@ struct babel_parse_state { u8 def_ip6_prefix_seen; /* def_ip6_prefix is valid */ u8 def_ip4_prefix_seen; /* def_ip4_prefix is valid */ u8 current_tlv_endpos; /* End of self-terminating TLVs (offset from start) */ + u8 sadr_enabled; }; enum parse_result { @@ -237,6 +245,7 @@ static int babel_read_next_hop(struct babel_tlv *hdr, union babel_msg *msg, stru static int babel_read_update(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state); static int babel_read_route_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state); static int babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state); +static int babel_read_source_prefix(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state); static uint babel_write_ack(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len); static uint babel_write_hello(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len); @@ -244,6 +253,7 @@ static uint babel_write_ihu(struct babel_tlv *hdr, union babel_msg *msg, struct static uint babel_write_update(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len); static uint babel_write_route_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len); static uint babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len); +static int babel_write_source_prefix(struct babel_tlv *hdr, net_addr *net, uint max_len); struct babel_tlv_data { u8 min_length; @@ -640,6 +650,9 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m, ip6_addr prefix6 = get_ip6(buf); net_fill_ip6(&msg->net, prefix6, tlv->plen); + if (state->sadr_enabled) + net_make_ip6_sadr(&msg->net); + if (tlv->flags & BABEL_UF_DEF_PREFIX) { put_ip6(state->def_ip6_prefix, prefix6); @@ -770,12 +783,21 @@ babel_write_update(struct babel_tlv *hdr, union babel_msg *m, put_u16(&tlv->seqno, msg->seqno); put_u16(&tlv->metric, msg->metric); + if (msg->net.type == NET_IP6_SADR) + { + int l = babel_write_source_prefix(hdr, &msg->net, max_len - (len0 + len)); + if (l < 0) + return 0; + + len += l; + } + return len0 + len; } static int babel_read_route_request(struct babel_tlv *hdr, union babel_msg *m, - struct babel_parse_state *state UNUSED) + struct babel_parse_state *state) { struct babel_tlv_route_request *tlv = (void *) hdr; struct babel_msg_route_request *msg = &m->route_request; @@ -812,6 +834,10 @@ babel_read_route_request(struct babel_tlv *hdr, union babel_msg *m, read_ip6_px(&msg->net, tlv->addr, tlv->plen); state->current_tlv_endpos += BYTES(tlv->plen); + + if (state->sadr_enabled) + net_make_ip6_sadr(&msg->net); + return PARSE_SUCCESS; case BABEL_AE_IP6_LL: @@ -856,6 +882,15 @@ babel_write_route_request(struct babel_tlv *hdr, union babel_msg *m, put_ip6_px(tlv->addr, &msg->net); } + if (msg->net.type == NET_IP6_SADR) + { + int l = babel_write_source_prefix(hdr, &msg->net, max_len - len); + if (l < 0) + return 0; + + len += l; + } + return len; } @@ -900,6 +935,10 @@ babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *m, read_ip6_px(&msg->net, tlv->addr, tlv->plen); state->current_tlv_endpos += BYTES(tlv->plen); + + if (state->sadr_enabled) + net_make_ip6_sadr(&msg->net); + return PARSE_SUCCESS; case BABEL_AE_IP6_LL: @@ -943,38 +982,147 @@ babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *m, tlv->hop_count = msg->hop_count; put_u64(&tlv->router_id, msg->router_id); + if (msg->net.type == NET_IP6_SADR) + { + int l = babel_write_source_prefix(hdr, &msg->net, max_len - len); + if (l < 0) + return 0; + + len += l; + } + return len; } +static int +babel_read_source_prefix(struct babel_tlv *hdr, union babel_msg *msg, + struct babel_parse_state *state UNUSED) +{ + struct babel_subtlv_source_prefix *tlv = (void *) hdr; + net_addr_ip6_sadr *net; + + /* + * We would like to skip the sub-TLV if SADR is not enabled, but we do not + * know AF of the enclosing TLV yet. We will do that later. + */ + + /* Check internal consistency */ + if ((tlv->length < 1) || + (tlv->plen > IP6_MAX_PREFIX_LENGTH) || + (tlv->length < (1 + BYTES(tlv->plen)))) + return PARSE_ERROR; + + /* Plen MUST NOT be 0 */ + if (tlv->plen == 0) + return PARSE_ERROR; + + switch(msg->type) + { + case BABEL_TLV_UPDATE: + /* Wildcard updates with source prefix MUST be silently ignored */ + if (msg->update.wildcard) + return PARSE_IGNORE; + + net = (void *) &msg->update.net; + break; + + case BABEL_TLV_ROUTE_REQUEST: + /* Wildcard requests with source addresses MUST be silently ignored */ + if (msg->route_request.full) + return PARSE_IGNORE; + + net = (void *) &msg->route_request.net; + break; + + case BABEL_TLV_SEQNO_REQUEST: + net = (void *) &msg->seqno_request.net; + break; + + default: + return PARSE_ERROR; + } + + /* If SADR is active, the net has appropriate type */ + if (net->type != NET_IP6_SADR) + return PARSE_IGNORE; + + /* Duplicate Source Prefix sub-TLV; SHOULD ignore whole TLV */ + if (net->src_pxlen > 0) + return PARSE_IGNORE; + + net_addr_ip6 src; + read_ip6_px((void *) &src, tlv->addr, tlv->plen); + net->src_prefix = src.prefix; + net->src_pxlen = src.pxlen; + + return PARSE_SUCCESS; +} + +static int +babel_write_source_prefix(struct babel_tlv *hdr, net_addr *n, uint max_len) +{ + struct babel_subtlv_source_prefix *tlv = (void *) NEXT_TLV(hdr); + net_addr_ip6_sadr *net = (void *) n; + + /* Do not use this sub-TLV for default prefix */ + if (net->src_pxlen == 0) + return 0; + + uint len = sizeof(*tlv) + BYTES(net->src_pxlen); + + if (len > max_len) + return -1; + + TLV_HDR(tlv, BABEL_SUBTLV_SOURCE_PREFIX, len); + hdr->length += len; + + net_addr_ip6 src = NET_ADDR_IP6(net->src_prefix, net->src_pxlen); + tlv->plen = src.pxlen; + put_ip6_px(tlv->addr, (void *) &src); + + return len; +} + + static inline int babel_read_subtlvs(struct babel_tlv *hdr, - union babel_msg *msg UNUSED, + union babel_msg *msg, struct babel_parse_state *state) { struct babel_tlv *tlv; + byte *pos, *end = (byte *) hdr + TLV_LENGTH(hdr); + int res; for (tlv = (void *) hdr + state->current_tlv_endpos; - (void *) tlv < (void *) hdr + TLV_LENGTH(hdr); + (byte *) tlv < end; tlv = NEXT_TLV(tlv)) { + /* Ugly special case */ + if (tlv->type == BABEL_TLV_PAD1) + continue; + + /* The end of the common TLV header */ + pos = (byte *)tlv + sizeof(struct babel_tlv); + if ((pos > end) || (pos + tlv->length > end)) + return PARSE_ERROR; + /* * The subtlv type space is non-contiguous (due to the mandatory bit), so * use a switch for dispatch instead of the mapping array we use for TLVs */ switch (tlv->type) { - case BABEL_SUBTLV_PAD1: - case BABEL_SUBTLV_PADN: - /* FIXME: Framing errors in PADN are silently ignored, see babel_process_packet() */ + case BABEL_SUBTLV_SOURCE_PREFIX: + res = babel_read_source_prefix(tlv, msg, state); + if (res != PARSE_SUCCESS) + return res; break; + case BABEL_SUBTLV_PADN: default: /* Unknown mandatory subtlv; PARSE_IGNORE ignores the whole TLV */ - if (tlv->type > 128) - { - DBG("Babel: Mandatory subtlv %d found; skipping TLV\n", tlv->type); + if (tlv->type >= 128) return PARSE_IGNORE; - } break; } } @@ -1197,6 +1345,7 @@ babel_process_packet(struct babel_pkt_header *pkt, int len, .ifa = ifa, .saddr = saddr, .next_hop_ip6 = saddr, + .sadr_enabled = babel_sadr_enabled(p), }; if ((pkt->magic != BABEL_MAGIC) || (pkt->version != BABEL_VERSION)) diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 1310582b..30424abb 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -118,6 +118,7 @@ struct bgp_config { unsigned error_delay_time_min; /* Time to wait after an error is detected */ unsigned error_delay_time_max; unsigned disable_after_error; /* Disable the protocol when error is detected */ + u32 disable_after_cease; /* Disable it when cease is received, bitfield */ char *password; /* Password used for MD5 authentication */ int check_link; /* Use iface link state for liveness detection */ diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y index 04e6d666..41eaa729 100644 --- a/proto/bgp/config.Y +++ b/proto/bgp/config.Y @@ -32,6 +32,12 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, KEEPALIVE, %type <i32> bgp_afi +CF_KEYWORDS(CEASE, PREFIX, LIMIT, HIT, ADMINISTRATIVE, SHUTDOWN, RESET, PEER, + CONFIGURATION, CHANGE, DECONFIGURED, CONNECTION, REJECTED, COLLISION, + OUT, OF, RESOURCES) + +%type<i> bgp_cease_mask bgp_cease_list bgp_cease_flag + CF_GRAMMAR CF_ADDTO(proto, bgp_proto '}' ) @@ -74,6 +80,29 @@ bgp_nbr_opts: | bgp_nbr_opts AS expr { BGP_CFG->remote_as = $3; } ; +bgp_cease_mask: + /* true -> all except connection collision */ + bool { $$ = $1 ? ~(1 << 7) : 0; } + | '{' bgp_cease_list '}' { $$ = $2; } + ; + +bgp_cease_list: + bgp_cease_flag + | bgp_cease_list ',' bgp_cease_flag { $$ = $1 | $3; } + ; + +bgp_cease_flag: + CEASE { $$ = 1 << 0; } + | PREFIX LIMIT HIT { $$ = 1 << 1; } + | ADMINISTRATIVE SHUTDOWN { $$ = 1 << 2; } + | PEER DECONFIGURED { $$ = 1 << 3; } + | ADMINISTRATIVE RESET { $$ = 1 << 4; } + | CONNECTION REJECTED { $$ = 1 << 5; } + | CONFIGURATION CHANGE { $$ = 1 << 6; } + | CONNECTION COLLISION { $$ = 1 << 7; } + | OUT OF RESOURCES { $$ = 1 << 8; } + ; + bgp_proto: bgp_proto_start proto_name '{' | bgp_proto proto_item ';' @@ -117,6 +146,7 @@ bgp_proto: | bgp_proto ERROR FORGET TIME expr ';' { BGP_CFG->error_amnesia_time = $5; } | bgp_proto ERROR WAIT TIME expr ',' expr ';' { BGP_CFG->error_delay_time_min = $5; BGP_CFG->error_delay_time_max = $7; } | bgp_proto DISABLE AFTER ERROR bool ';' { BGP_CFG->disable_after_error = $5; } + | bgp_proto DISABLE AFTER CEASE bgp_cease_mask ';' { BGP_CFG->disable_after_cease = $5; } | bgp_proto ENABLE ROUTE REFRESH bool ';' { BGP_CFG->enable_refresh = $5; } | bgp_proto ENABLE AS4 bool ';' { BGP_CFG->enable_as4 = $4; } | bgp_proto ENABLE EXTENDED MESSAGES bool ';' { BGP_CFG->enable_extended_messages = $5; } diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 95a974eb..aa08732d 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -2772,6 +2772,16 @@ bgp_rx_notification(struct bgp_conn *conn, byte *pkt, uint len) bgp_update_startup_delay(p); bgp_stop(p, 0, NULL, 0); } + else + { + uint subcode_bit = 1 << ((subcode <= 8) ? subcode : 0); + if (p->cf->disable_after_cease & subcode_bit) + { + log(L_INFO "%s: Disabled after Cease notification", p->p.name); + p->startup_delay = 0; + p->p.disabled = 1; + } + } } static void diff --git a/proto/pipe/config.Y b/proto/pipe/config.Y index 4f96fdcb..b3c332be 100644 --- a/proto/pipe/config.Y +++ b/proto/pipe/config.Y @@ -25,13 +25,19 @@ CF_ADDTO(proto, pipe_proto '}' { this_channel = NULL; } ) pipe_proto_start: proto_start PIPE { this_proto = proto_config_new(&proto_pipe, $1); - this_channel = channel_config_new(NULL, NULL, 0, this_proto); - this_channel->in_filter = FILTER_ACCEPT; - this_channel->out_filter = FILTER_ACCEPT; +} +proto_name +{ + this_channel = proto_cf_main_channel(this_proto); + if (!this_channel) { + this_channel = channel_config_new(NULL, NULL, 0, this_proto); + this_channel->in_filter = FILTER_ACCEPT; + this_channel->out_filter = FILTER_ACCEPT; + } }; pipe_proto: - pipe_proto_start proto_name '{' + pipe_proto_start '{' | pipe_proto proto_item ';' | pipe_proto channel_item ';' | pipe_proto PEER TABLE rtable ';' { PIPE_CFG->peer = $4; } diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c index 310f3c01..49ff52e2 100644 --- a/proto/pipe/pipe.c +++ b/proto/pipe/pipe.c @@ -249,6 +249,8 @@ pipe_show_stats(struct pipe_proto *p) s2->imp_withdraws_ignored, s2->imp_withdraws_accepted); } +static const char *pipe_feed_state[] = { [ES_DOWN] = "down", [ES_FEEDING] = "feed", [ES_READY] = "up" }; + static void pipe_show_proto_info(struct proto *P) { @@ -257,6 +259,8 @@ pipe_show_proto_info(struct proto *P) cli_msg(-1006, " Channel %s", "main"); cli_msg(-1006, " Table: %s", p->pri->table->name); cli_msg(-1006, " Peer table: %s", p->sec->table->name); + cli_msg(-1006, " Import state: %s", pipe_feed_state[p->sec->export_state]); + cli_msg(-1006, " Export state: %s", pipe_feed_state[p->pri->export_state]); cli_msg(-1006, " Import filter: %s", filter_name(p->sec->out_filter)); cli_msg(-1006, " Export filter: %s", filter_name(p->pri->out_filter)); diff --git a/sysdep/cf/linux.h b/sysdep/cf/linux.h index 3a3a15da..047d3764 100644 --- a/sysdep/cf/linux.h +++ b/sysdep/cf/linux.h @@ -10,6 +10,7 @@ #define CONFIG_SELF_CONSCIOUS #define CONFIG_MULTIPLE_TABLES #define CONFIG_ALL_TABLES_AT_ONCE +#define CONFIG_IP6_SADR_KERNEL #define CONFIG_MC_PROPER_SRC #define CONFIG_UNIX_DONTROUTE diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index 4cb51519..84591eb2 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -374,6 +374,7 @@ static struct nl_want_attrs rtm_attr_want4[BIRD_RTA_MAX] = { static struct nl_want_attrs rtm_attr_want6[BIRD_RTA_MAX] = { [RTA_DST] = { 1, 1, sizeof(ip6_addr) }, + [RTA_SRC] = { 1, 1, sizeof(ip6_addr) }, [RTA_IIF] = { 1, 1, sizeof(u32) }, [RTA_OIF] = { 1, 1, sizeof(u32) }, [RTA_GATEWAY] = { 1, 1, sizeof(ip6_addr) }, @@ -1221,8 +1222,18 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int op, int d } else #endif + { nl_add_attr_ipa(&r->h, rsize, RTA_DST, net_prefix(net->n.addr)); + /* Add source address for IPv6 SADR routes */ + if (net->n.addr->type == NET_IP6_SADR) + { + net_addr_ip6_sadr *a = (void *) &net->n.addr; + nl_add_attr_ip6(&r->h, rsize, RTA_SRC, a->src_prefix); + r->r.rtm_src_len = a->src_pxlen; + } + } + /* * Strange behavior for RTM_DELROUTE: * 1) rtm_family is ignored in IPv6, works for IPv4 @@ -1447,12 +1458,12 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) struct rtattr *a[BIRD_RTA_MAX]; int new = h->nlmsg_type == RTM_NEWROUTE; - net_addr dst; + net_addr dst, src = {}; u32 oif = ~0; u32 table_id; u32 priority = 0; u32 def_scope = RT_SCOPE_UNIVERSE; - int src; + int krt_src; if (!(i = nl_checkin(h, sizeof(*i)))) return; @@ -1477,6 +1488,11 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) net_fill_ip6(&dst, rta_get_ip6(a[RTA_DST]), i->rtm_dst_len); else net_fill_ip6(&dst, IP6_NONE, 0); + + if (a[RTA_SRC]) + net_fill_ip6(&src, rta_get_ip6(a[RTA_SRC]), i->rtm_src_len); + else + net_fill_ip6(&src, IP6_NONE, 0); break; #ifdef HAVE_MPLS_KERNEL @@ -1511,6 +1527,9 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) if (!p) SKIP("unknown table %d\n", table); + if (a[RTA_SRC] && (p->p.net_type != NET_IP6_SADR)) + SKIP("src prefix for non-SADR channel\n"); + if (a[RTA_IIF]) SKIP("IIF set\n"); @@ -1533,25 +1552,33 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) SKIP("proto unspec\n"); case RTPROT_REDIRECT: - src = KRT_SRC_REDIRECT; + krt_src = KRT_SRC_REDIRECT; break; case RTPROT_KERNEL: - src = KRT_SRC_KERNEL; + krt_src = KRT_SRC_KERNEL; return; case RTPROT_BIRD: if (!s->scan) SKIP("echo\n"); - src = KRT_SRC_BIRD; + krt_src = KRT_SRC_BIRD; break; case RTPROT_BOOT: default: - src = KRT_SRC_ALIEN; + krt_src = KRT_SRC_ALIEN; } - net *net = net_get(p->p.main_channel->table, &dst); + net_addr *n = &dst; + if (p->p.net_type == NET_IP6_SADR) + { + n = alloca(sizeof(net_addr_ip6_sadr)); + net_fill_ip6_sadr(n, net6_prefix(&dst), net6_pxlen(&dst), + net6_prefix(&src), net6_pxlen(&src)); + } + + net *net = net_get(p->p.main_channel->table, n); if (s->net && !nl_mergable_route(s, net, p, priority, i->rtm_type)) nl_announce_route(s); @@ -1755,7 +1782,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) s->attrs = ra; s->proto = p; s->new = new; - s->krt_src = src; + s->krt_src = krt_src; s->krt_type = i->rtm_type; s->krt_proto = i->rtm_protocol; s->krt_metric = priority; diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index cd2558b2..012deaf0 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -958,10 +958,6 @@ sk_setup(sock *s) #endif } - if (s->priority >= 0) - if (sk_set_priority(s, s->priority) < 0) - return -1; - if (sk_is_ipv4(s)) { if (s->flags & SKF_LADDR_RX) @@ -1012,6 +1008,11 @@ sk_setup(sock *s) return -1; } + /* Must be after sk_set_tos4() as setting ToS on Linux also mangles priority */ + if (s->priority >= 0) + if (sk_set_priority(s, s->priority) < 0) + return -1; + return 0; } diff --git a/sysdep/unix/krt.Y b/sysdep/unix/krt.Y index 1cb28389..9aac8668 100644 --- a/sysdep/unix/krt.Y +++ b/sysdep/unix/krt.Y @@ -17,16 +17,6 @@ CF_DEFINES #define KIF_IFACE ((struct kif_iface_config *) this_ipatt) static void -krt_set_merge_paths(struct channel_config *cc, uint merge, uint limit) -{ - if ((limit <= 0) || (limit > 255)) - cf_error("Merge paths limit must be in range 1-255"); - - cc->ra_mode = merge ? RA_MERGED : RA_OPTIMAL; - cc->merge_limit = limit; -} - -static void kif_set_preferred(ip_addr ip) { if (ipa_is_ip4(ip)) @@ -78,10 +68,9 @@ kern_item: cf_error("Learning of kernel routes not supported on this platform"); #endif } - | DEVICE ROUTES bool { THIS_KRT->devroutes = $3; } | GRACEFUL RESTART bool { THIS_KRT->graceful_restart = $3; } | MERGE PATHS bool kern_mp_limit { - krt_set_merge_paths(this_channel, $3, $4); + THIS_KRT->merge_paths = $3 ? $4 : 0; #ifndef KRT_ALLOW_MERGE_PATHS if ($3) cf_error("Path merging not supported on this platform"); diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index 29d2d01e..b4fb1967 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -506,7 +506,13 @@ static void krt_learn_init(struct krt_proto *p) { if (KRT_CF->learn) - rt_setup(p->p.pool, &p->krt_table, "Inherited", NULL); + { + struct rtable_config *cf = mb_allocz(p->p.pool, sizeof(struct rtable_config)); + cf->name = "Inherited"; + cf->addr_type = p->p.net_type; + + rt_setup(p->p.pool, &p->krt_table, cf); + } } static void @@ -578,7 +584,7 @@ krt_export_net(struct krt_proto *p, net *net, rte **rt_free, ea_list **tmpa) if (filter == FILTER_ACCEPT) goto accept; - if (f_run(filter, &rt, tmpa, krt_filter_lp, FF_FORCE_TMPATTR) > F_ACCEPT) + if (f_run(filter, &rt, tmpa, krt_filter_lp, FF_FORCE_TMPATTR | FF_SILENT) > F_ACCEPT) goto reject; @@ -1059,11 +1065,18 @@ krt_postconfig(struct proto_config *CF) cf_error("All kernel syncers must use the same table scan interval"); #endif - struct rtable_config *tab = proto_cf_main_channel(CF)->table; + struct channel_config *cc = proto_cf_main_channel(CF); + struct rtable_config *tab = cc->table; if (tab->krt_attached) cf_error("Kernel syncer (%s) already attached to table %s", tab->krt_attached->name, tab->name); tab->krt_attached = CF; + if (cf->merge_paths) + { + cc->ra_mode = RA_MERGED; + cc->merge_limit = cf->merge_paths; + } + krt_sys_postconfig(cf); } @@ -1095,10 +1108,11 @@ krt_start(struct proto *P) switch (p->p.net_type) { - case NET_IP4: p->af = AF_INET; break; - case NET_IP6: p->af = AF_INET6; break; + case NET_IP4: p->af = AF_INET; break; + case NET_IP6: p->af = AF_INET6; break; + case NET_IP6_SADR: p->af = AF_INET6; break; #ifdef AF_MPLS - case NET_MPLS: p->af = AF_MPLS; break; + case NET_MPLS: p->af = AF_MPLS; break; #endif default: log(L_ERR "KRT: Tried to start with strange net type: %d", p->p.net_type); return PS_START; break; } @@ -1159,7 +1173,7 @@ krt_reconfigure(struct proto *p, struct proto_config *CF) return 0; /* persist, graceful restart need not be the same */ - return o->scan_time == n->scan_time && o->learn == n->learn && o->devroutes == n->devroutes; + return o->scan_time == n->scan_time && o->learn == n->learn; } struct proto_config * @@ -1206,16 +1220,24 @@ krt_get_attr(eattr *a, byte *buf, int buflen) } +#ifdef CONFIG_IP6_SADR_KERNEL +#define MAYBE_IP6_SADR NB_IP6_SADR +#else +#define MAYBE_IP6_SADR 0 +#endif + +#ifdef HAVE_MPLS_KERNEL +#define MAYBE_MPLS NB_MPLS +#else +#define MAYBE_MPLS 0 +#endif + struct protocol proto_unix_kernel = { .name = "Kernel", .template = "kernel%d", .attr_class = EAP_KRT, .preference = DEF_PREF_INHERITED, -#ifdef HAVE_MPLS_KERNEL - .channel_mask = NB_IP | NB_MPLS, -#else - .channel_mask = NB_IP, -#endif + .channel_mask = NB_IP | MAYBE_IP6_SADR | MAYBE_MPLS, .proto_size = sizeof(struct krt_proto), .config_size = sizeof(struct krt_config), .preconfig = krt_preconfig, diff --git a/sysdep/unix/krt.h b/sysdep/unix/krt.h index 3bfccfc2..b627882d 100644 --- a/sysdep/unix/krt.h +++ b/sysdep/unix/krt.h @@ -49,8 +49,8 @@ struct krt_config { btime scan_time; /* How often we re-scan routes */ int persist; /* Keep routes when we exit */ int learn; /* Learn routes from other sources */ - int devroutes; /* XXX: remove */ int graceful_restart; /* Regard graceful restart recovery */ + int merge_paths; /* Exported routes are merged for ECMP */ }; struct krt_proto { |