From 261816b0d4f3d4549a4402b95541b82fc7f10a4b Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Tue, 15 Nov 2016 16:24:39 +0100 Subject: [PATCH 01/20] BGP: Cluster list item should be prepended Commit 3c09af41... changed behavior of int_set_add() from prepend to append, which makes more sense for community list, but prepend must be used for cluster list. Add int_set_prepend() and use it in cluster list handling code. --- nest/a-set.c | 23 +++++++++++++++++++++-- nest/attrs.h | 1 + proto/bgp/attrs.c | 2 +- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/nest/a-set.c b/nest/a-set.c index bd244e2e..a6c07f45 100644 --- a/nest/a-set.c +++ b/nest/a-set.c @@ -231,6 +231,26 @@ lc_set_contains(struct adata *list, lcomm val) return 0; } +struct adata * +int_set_prepend(struct linpool *pool, struct adata *list, u32 val) +{ + struct adata *res; + int len; + + if (int_set_contains(list, val)) + return list; + + len = list ? list->length : 0; + res = lp_alloc(pool, sizeof(struct adata) + len + 4); + res->length = len + 4; + + if (list) + memcpy(res->data + 4, list->data, list->length); + + * (u32 *) res->data = val; + + return res; +} struct adata * int_set_add(struct linpool *pool, struct adata *list, u32 val) @@ -248,8 +268,7 @@ int_set_add(struct linpool *pool, struct adata *list, u32 val) if (list) memcpy(res->data, list->data, list->length); - u32 *c = (u32 *) (res->data + len); - *c = val; + * (u32 *) (res->data + len) = val; return res; } diff --git a/nest/attrs.h b/nest/attrs.h index 548d71a9..a34e64d3 100644 --- a/nest/attrs.h +++ b/nest/attrs.h @@ -132,6 +132,7 @@ int lc_set_format(struct adata *set, int from, byte *buf, uint size); int int_set_contains(struct adata *list, u32 val); int ec_set_contains(struct adata *list, u64 val); int lc_set_contains(struct adata *list, lcomm val); +struct adata *int_set_prepend(struct linpool *pool, struct adata *list, u32 val); struct adata *int_set_add(struct linpool *pool, struct adata *list, u32 val); struct adata *ec_set_add(struct linpool *pool, struct adata *list, u64 val); struct adata *lc_set_add(struct linpool *pool, struct adata *list, lcomm val); diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 0309c1f7..aa2a3b46 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -1077,7 +1077,7 @@ static inline void bgp_cluster_list_prepend(rte *e, ea_list **attrs, struct linpool *pool, u32 cid) { eattr *a = ea_find(e->attrs->eattrs, EA_CODE(EAP_BGP, BA_CLUSTER_LIST)); - bgp_attach_attr(attrs, pool, BA_CLUSTER_LIST, (uintptr_t) int_set_add(pool, a ? a->u.ptr : NULL, cid)); + bgp_attach_attr(attrs, pool, BA_CLUSTER_LIST, (uintptr_t) int_set_prepend(pool, a ? a->u.ptr : NULL, cid)); } static int From ed1a908e535e4333b358d83b472453a2ad6d3f51 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Fri, 25 Nov 2016 11:51:38 +0100 Subject: [PATCH 02/20] BGP: Fix memory leak in graceful restart code Prefix and bucket tables are initialized when entering established state but not explicitly freed when leaving it (that is handled by protocol restart). With graceful restart, BGP may enter and leave established state multiple times without hard protocol restart causing memory leak. --- lib/hash.h | 6 ++++++ proto/bgp/attrs.c | 26 ++++++++++++++++++++++++++ proto/bgp/bgp.c | 3 +++ proto/bgp/bgp.h | 2 ++ 4 files changed, 37 insertions(+) diff --git a/lib/hash.h b/lib/hash.h index 4239b1d8..6995bbc8 100644 --- a/lib/hash.h +++ b/lib/hash.h @@ -25,6 +25,12 @@ (v).data = mb_allocz(pool, HASH_SIZE(v) * sizeof(* (v).data)); \ }) +#define HASH_FREE(v) \ + ({ \ + mb_free((v).data); \ + (v) = (typeof(v)){ }; \ + }) + #define HASH_FIND(v,id,key...) \ ({ \ u32 _h = HASH_FN(v, id, key); \ diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index aa2a3b46..9d23374a 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -934,6 +934,15 @@ bgp_init_prefix_table(struct bgp_proto *p, u32 order) p->prefix_slab = sl_new(p->p.pool, sizeof(struct bgp_prefix)); } +void +bgp_free_prefix_table(struct bgp_proto *p) +{ + HASH_FREE(p->prefix_hash); + + rfree(p->prefix_slab); + p->prefix_slab = NULL; +} + static struct bgp_prefix * bgp_get_prefix(struct bgp_proto *p, ip_addr prefix, int pxlen, u32 path_id) { @@ -1940,6 +1949,23 @@ bgp_init_bucket_table(struct bgp_proto *p) // fib_init(&p->prefix_fib, p->p.pool, sizeof(struct bgp_prefix), 0, bgp_init_prefix); } +void +bgp_free_bucket_table(struct bgp_proto *p) +{ + mb_free(p->bucket_hash); + p->bucket_hash = NULL; + + struct bgp_bucket *b; + WALK_LIST_FIRST(b, p->bucket_queue) + { + rem_node(&b->send_node); + mb_free(b); + } + + mb_free(p->withdraw_bucket); + p->withdraw_bucket = NULL; +} + void bgp_get_route_info(rte *e, byte *buf, ea_list *attrs) { diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index 8ef4b990..0f1c9446 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -416,6 +416,9 @@ bgp_conn_leave_established_state(struct bgp_proto *p) BGP_TRACE(D_EVENTS, "BGP session closed"); p->conn = NULL; + bgp_free_prefix_table(p); + bgp_free_bucket_table(p); + if (p->p.proto_state == PS_UP) bgp_stop(p, 0); } diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index b4067f3a..d028bef4 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -253,8 +253,10 @@ int bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_be void bgp_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old UNUSED, ea_list *attrs); int bgp_import_control(struct proto *, struct rte **, struct ea_list **, struct linpool *); void bgp_init_bucket_table(struct bgp_proto *); +void bgp_free_bucket_table(struct bgp_proto *p); void bgp_free_bucket(struct bgp_proto *p, struct bgp_bucket *buck); void bgp_init_prefix_table(struct bgp_proto *p, u32 order); +void bgp_free_prefix_table(struct bgp_proto *p); void bgp_free_prefix(struct bgp_proto *p, struct bgp_prefix *bp); uint bgp_encode_attrs(struct bgp_proto *p, byte *w, ea_list *attrs, int remains); void bgp_get_route_info(struct rte *, byte *buf, struct ea_list *attrs); From ac3ad139f648184d44707ab145fde3a03ef5cb6e Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Wed, 7 Dec 2016 18:28:07 +0100 Subject: [PATCH 03/20] BGP: Add support for flowspec (RFC 5575) --- lib/flowspec.h | 3 + proto/bgp/attrs.c | 16 +++- proto/bgp/bgp.c | 2 +- proto/bgp/bgp.h | 3 + proto/bgp/config.Y | 4 +- proto/bgp/packets.c | 225 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 247 insertions(+), 6 deletions(-) diff --git a/lib/flowspec.h b/lib/flowspec.h index 57809bec..aa9735f4 100644 --- a/lib/flowspec.h +++ b/lib/flowspec.h @@ -42,6 +42,9 @@ const char *flow_type_str(enum flow_type type, int ipv6); uint flow_write_length(byte *data, u16 len); +static inline u16 flow_hdr_length(const byte *data) +{ return ((*data & 0xf0) == 0xf0) ? 2 : 1; } + static inline u16 flow_read_length(const byte *data) { return ((*data & 0xf0) == 0xf0) ? get_u16(data) & 0x0fff : *data; } diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 52b56efa..227ddadc 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -1221,8 +1221,8 @@ bgp_init_prefix_table(struct bgp_channel *c) { HASH_INIT(c->prefix_hash, c->pool, 8); - c->prefix_slab = sl_new(c->pool, sizeof(struct bgp_prefix) + - net_addr_length[c->c.net_type]); + uint alen = net_addr_length[c->c.net_type]; + c->prefix_slab = alen ? sl_new(c->pool, sizeof(struct bgp_prefix) + alen) : NULL; } static struct bgp_prefix * @@ -1237,7 +1237,11 @@ bgp_get_prefix(struct bgp_channel *c, net_addr *net, u32 path_id) return px; } - px = sl_alloc(c->prefix_slab); + if (c->prefix_slab) + px = sl_alloc(c->prefix_slab); + else + px = mb_alloc(c->pool, sizeof(struct bgp_prefix) + net->length); + px->buck_node.next = NULL; px->buck_node.prev = NULL; px->hash = hash; @@ -1254,7 +1258,11 @@ bgp_free_prefix(struct bgp_channel *c, struct bgp_prefix *px) { rem_node(&px->buck_node); HASH_REMOVE2(c->prefix_hash, PXH, c->pool, px); - sl_free(c->prefix_slab, px); + + if (c->prefix_slab) + sl_free(c->prefix_slab, px); + else + mb_free(px); } diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index 2ca153ab..b7229429 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -1846,7 +1846,7 @@ struct protocol proto_bgp = { .template = "bgp%d", .attr_class = EAP_BGP, .preference = DEF_PREF_BGP, - .channel_mask = NB_IP, + .channel_mask = NB_IP | NB_FLOW4 | NB_FLOW6, .proto_size = sizeof(struct bgp_proto), .config_size = sizeof(struct bgp_config), .postconfig = bgp_postconfig, diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 4ecb86a0..db9ee8ea 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -31,6 +31,7 @@ struct eattr; #define BGP_SAFI_UNICAST 1 #define BGP_SAFI_MULTICAST 2 +#define BGP_SAFI_FLOW 133 /* Internal AF codes */ @@ -42,6 +43,8 @@ struct eattr; #define BGP_AF_IPV6 BGP_AF( BGP_AFI_IPV6, BGP_SAFI_UNICAST ) #define BGP_AF_IPV4_MC BGP_AF( BGP_AFI_IPV4, BGP_SAFI_MULTICAST ) #define BGP_AF_IPV6_MC BGP_AF( BGP_AFI_IPV6, BGP_SAFI_MULTICAST ) +#define BGP_AF_FLOW4 BGP_AF( BGP_AFI_IPV4, BGP_SAFI_FLOW ) +#define BGP_AF_FLOW6 BGP_AF( BGP_AFI_IPV6, BGP_SAFI_FLOW ) struct bgp_write_state; diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y index 10a338d8..2a54db17 100644 --- a/proto/bgp/config.Y +++ b/proto/bgp/config.Y @@ -28,7 +28,7 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, KEEPALIVE, BGP_CLUSTER_LIST, IGP, TABLE, GATEWAY, DIRECT, RECURSIVE, MED, TTL, SECURITY, DETERMINISTIC, SECONDARY, ALLOW, BFD, ADD, PATHS, RX, TX, GRACEFUL, RESTART, AWARE, CHECK, LINK, PORT, EXTENDED, MESSAGES, SETKEY, - STRICT, BIND, CONFEDERATION, MEMBER, MULTICAST) + STRICT, BIND, CONFEDERATION, MEMBER, MULTICAST, FLOW4, FLOW6) %type bgp_afi @@ -139,6 +139,8 @@ bgp_afi: | IPV6 { $$ = BGP_AF_IPV6; } | IPV4 MULTICAST { $$ = BGP_AF_IPV4_MC; } | IPV6 MULTICAST { $$ = BGP_AF_IPV6_MC; } + | FLOW4 { $$ = BGP_AF_FLOW4; } + | FLOW6 { $$ = BGP_AF_FLOW6; } ; bgp_channel_start: bgp_afi diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 66561ee4..1ae75a64 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -20,6 +20,7 @@ #include "nest/mrtdump.h" #include "conf/conf.h" #include "lib/unaligned.h" +#include "lib/flowspec.h" #include "lib/socket.h" #include "nest/cli.h" @@ -793,6 +794,26 @@ bgp_update_next_hop_ip(struct bgp_export_state *s, eattr *a, ea_list **to) WITHDRAW(BAD_NEXT_HOP); } +static uint +bgp_encode_next_hop_none(struct bgp_write_state *s UNUSED, eattr *a UNUSED, byte *buf UNUSED, uint size UNUSED) +{ + // FIXME + return 0; +} + +static void +bgp_decode_next_hop_none(struct bgp_parse_state *s UNUSED, byte *data UNUSED, uint len UNUSED, rta *a UNUSED) +{ + // FIXME + return; +} + +static void +bgp_update_next_hop_none(struct bgp_export_state *s UNUSED, eattr *a UNUSED, ea_list **to UNUSED) +{ + // FIXME +} + /* * UPDATE @@ -1066,6 +1087,190 @@ bgp_decode_next_hop_ip6(struct bgp_parse_state *s, byte *data, uint len, rta *a) } +static uint +bgp_encode_nlri_flow4(struct bgp_write_state *s, struct bgp_bucket *buck, byte *buf, uint size) +{ + byte *pos = buf; + + while (!EMPTY_LIST(buck->prefixes) && (size >= 4)) + { + struct bgp_prefix *px = HEAD(buck->prefixes); + struct net_addr_flow4 *net = (void *) px->net; + uint flen = net->length - sizeof(net_addr_flow4); + + /* Encode path ID */ + if (s->add_path) + { + put_u32(pos, px->path_id); + ADVANCE(pos, size, 4); + } + + if (flen > size) + break; + + /* Copy whole flow data including length */ + memcpy(pos, net->data, flen); + ADVANCE(pos, size, flen); + + bgp_free_prefix(s->channel, px); + } + + return pos - buf; +} + +static void +bgp_decode_nlri_flow4(struct bgp_parse_state *s, byte *pos, uint len, rta *a) +{ + while (len) + { + u32 path_id = 0; + + /* Decode path ID */ + if (s->add_path) + { + if (len < 4) + bgp_parse_error(s, 1); + + path_id = get_u32(pos); + ADVANCE(pos, len, 4); + } + + if (len < 2) + bgp_parse_error(s, 1); + + /* Decode flow length */ + uint hlen = flow_hdr_length(pos); + uint dlen = flow_read_length(pos); + uint flen = hlen + dlen; + byte *data = pos + hlen; + + if (len < flen) + bgp_parse_error(s, 1); + + /* Validate flow data */ + enum flow_validated_state r = flow4_validate(data, dlen); + if (r != FLOW_ST_VALID) + { + log(L_REMOTE "%s: Invalid flow route: %s", s->proto->p.name, flow_validated_state_str(r)); + bgp_parse_error(s, 1); + } + + if (data[0] != FLOW_TYPE_DST_PREFIX) + { + log(L_REMOTE "%s: No dst prefix at first pos", s->proto->p.name); + bgp_parse_error(s, 1); + } + + /* Decode dst prefix */ + ip4_addr px = IP4_NONE; + uint pxlen = data[1]; + + // FIXME: Use some generic function + memcpy(&px, data, BYTES(pxlen)); + px = ip4_and(px, ip4_mkmask(pxlen)); + + /* Prepare the flow */ + net_addr *n = alloca(sizeof(struct net_addr_flow4) + flen); + net_fill_flow4(n, px, pxlen, pos, flen); + ADVANCE(pos, len, flen); + + bgp_rte_update(s, n, path_id, a); + } +} + + +static uint +bgp_encode_nlri_flow6(struct bgp_write_state *s, struct bgp_bucket *buck, byte *buf, uint size) +{ + byte *pos = buf; + + while (!EMPTY_LIST(buck->prefixes) && (size >= 4)) + { + struct bgp_prefix *px = HEAD(buck->prefixes); + struct net_addr_flow6 *net = (void *) px->net; + uint flen = net->length - sizeof(net_addr_flow6); + + /* Encode path ID */ + if (s->add_path) + { + put_u32(pos, px->path_id); + ADVANCE(pos, size, 4); + } + + if (flen > size) + break; + + /* Copy whole flow data including length */ + memcpy(pos, net->data, flen); + ADVANCE(pos, size, flen); + + bgp_free_prefix(s->channel, px); + } + + return pos - buf; +} + +static void +bgp_decode_nlri_flow6(struct bgp_parse_state *s, byte *pos, uint len, rta *a) +{ + while (len) + { + u32 path_id = 0; + + /* Decode path ID */ + if (s->add_path) + { + if (len < 4) + bgp_parse_error(s, 1); + + path_id = get_u32(pos); + ADVANCE(pos, len, 4); + } + + if (len < 2) + bgp_parse_error(s, 1); + + /* Decode flow length */ + uint hlen = flow_hdr_length(pos); + uint dlen = flow_read_length(pos); + uint flen = hlen + dlen; + byte *data = pos + hlen; + + if (len < flen) + bgp_parse_error(s, 1); + + /* Validate flow data */ + enum flow_validated_state r = flow6_validate(data, dlen); + if (r != FLOW_ST_VALID) + { + log(L_REMOTE "%s: Invalid flow route: %s", s->proto->p.name, flow_validated_state_str(r)); + bgp_parse_error(s, 1); + } + + if (data[0] != FLOW_TYPE_DST_PREFIX) + { + log(L_REMOTE "%s: No dst prefix at first pos", s->proto->p.name); + bgp_parse_error(s, 1); + } + + /* Decode dst prefix */ + ip6_addr px = IP6_NONE; + uint pxlen = data[1]; + + // FIXME: Use some generic function + memcpy(&px, data, BYTES(pxlen)); + px = ip6_and(px, ip6_mkmask(pxlen)); + + /* Prepare the flow */ + net_addr *n = alloca(sizeof(struct net_addr_flow6) + flen); + net_fill_flow6(n, px, pxlen, pos, flen); + ADVANCE(pos, len, flen); + + bgp_rte_update(s, n, path_id, a); + } +} + + static const struct bgp_af_desc bgp_af_table[] = { { .afi = BGP_AF_IPV4, @@ -1087,6 +1292,16 @@ static const struct bgp_af_desc bgp_af_table[] = { .decode_next_hop = bgp_decode_next_hop_ip4, .update_next_hop = bgp_update_next_hop_ip, }, + { + .afi = BGP_AF_FLOW4, + .net = NET_FLOW4, + .name = "flow4", + .encode_nlri = bgp_encode_nlri_flow4, + .decode_nlri = bgp_decode_nlri_flow4, + .encode_next_hop = bgp_encode_next_hop_none, + .decode_next_hop = bgp_decode_next_hop_none, + .update_next_hop = bgp_update_next_hop_none, + }, { .afi = BGP_AF_IPV6, .net = NET_IP6, @@ -1107,6 +1322,16 @@ static const struct bgp_af_desc bgp_af_table[] = { .decode_next_hop = bgp_decode_next_hop_ip6, .update_next_hop = bgp_update_next_hop_ip, }, + { + .afi = BGP_AF_FLOW6, + .net = NET_FLOW6, + .name = "flow6", + .encode_nlri = bgp_encode_nlri_flow6, + .decode_nlri = bgp_decode_nlri_flow6, + .encode_next_hop = bgp_encode_next_hop_none, + .decode_next_hop = bgp_decode_next_hop_none, + .update_next_hop = bgp_update_next_hop_none, + }, }; const struct bgp_af_desc * From 66e5dc157af41547f3806a5980183d95ac9bfcd1 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Wed, 7 Dec 2016 19:16:02 +0100 Subject: [PATCH 04/20] Doc: Add MP-BGP example config file --- doc/bird.conf.example | 3 +- doc/bird.conf.example2 | 267 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 269 insertions(+), 1 deletion(-) create mode 100644 doc/bird.conf.example2 diff --git a/doc/bird.conf.example b/doc/bird.conf.example index bbfe0020..62c65ce9 100644 --- a/doc/bird.conf.example +++ b/doc/bird.conf.example @@ -1,5 +1,6 @@ /* - * This is an example configuration file. + * This is an example configuration file + * (for version 1.x.x, obsolete) */ # Yes, even shell-like comments work... diff --git a/doc/bird.conf.example2 b/doc/bird.conf.example2 new file mode 100644 index 00000000..6e8988b9 --- /dev/null +++ b/doc/bird.conf.example2 @@ -0,0 +1,267 @@ +/* + * This is an example configuration file for MB-BGP setting + */ + + +log "bird.log" all; +# debug protocols all; + +router id 192.168.1.1; + +ipv4 table master4; +ipv6 table master6; + +ipv4 table mcast4; +ipv6 table mcast6; + +flow4 table flowtab4; +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; + }; +} + + +protocol static static4 { + ipv4; + + route 10.10.0.0/24 via 192.168.1.2; + route 10.10.1.0/24 via 192.168.1.2 { bgp_large_community.add((10,20,30)); bgp_large_community.add((10,(20*3),10)); }; +} + +protocol static static6 { + ipv6; + + route 2001:db8:10:10::/64 via 2001:db8:1:1::10; + route 2001:db8:10:11::/64 via 2001:db8:1:1::10; + + route 2001:db8:1:1::/64 via fe80::ec9b:67ff:fe60:fd5d % ve1; +} + +# RFC 5575 flow specification +protocol static flowstat4 { + flow4; + + route flow4 { + dst 10.0.0.0/8; + proto = 23; + dport > 24 && < 30 || 40..50,60..70,80; + sport > 24 && < 30 || = 40 || 50,60..70,80; + icmp type 80; + icmp code 90; + tcp flags 0x03/0x0f; + length 2048..65535; + dscp = 63; + fragment dont_fragment, is_fragment || !first_fragment; + } drop; + + route flow4 { + dst 11.0.0.0/8; + proto = 0x12; + sport > 0x5678 && < 0x9abc || 0xdef0 || 0x1234,0x5678,0x9abc..0xdef0; + dport = 50; + tcp flags 0xabcd/0xbbdd; + } drop; + + route flow4 { + dst 12.0.0.0/32; + tcp flags ! 0 / 0x9999; + } drop; + + route flow4 { + dst 220.0.254.0/24; + tcp flags 0x99 / 0x9999; + } drop; + + route flow4 { + dst 220.0.254.192/28; + tcp flags !0xffff / 0xFFFF; + } drop; + + route flow4 { + dst 15.0.0.0/8; + tcp flags !0x9999/0x9999; + } drop; +} + +protocol static flowstat6 { + flow6; + + route flow6 { + dst fec0:1122:3344:5566::1/128; + src 0000:0000:0000:0001:1234:5678:9800:0000/101 offset 63; + next header = 23; + sport 24..30, 42 || 50,60,70..80; + dport = 50; + tcp flags 0x03/0x0f, !0/0xff || 0x33/0x33; + fragment !is_fragment || !first_fragment; + label 0xaaaa/0xaaaa && 0x33/0x33; + } drop; + + route flow6 { + dst fec0:1122:3344:5566::1/128; + src ::1:1234:5678:9800:0/101 offset 63; + next header = 23; + dport = 50; + sport > 24 && < 30 || = 40 || = 50 || = 60 || >= 70 && <= 80; + tcp flags 0x3/0x3 && 0x0/0xc; + } drop; +} + + +protocol pipe { + table master4; + peer table mcast4; + import none; + export where source = RTS_OSPF; +} + +protocol pipe { + table master6; + peer table mcast6; + import none; + export where source = RTS_OSPF; +} + +protocol ospf2 ospf4 { +# ecmp; + + ipv4 { + import all; +# export where source = RTS_STATIC; + }; + + area 0 { + interface "ve0" { stub; }; + interface "ve1" { hello 5; type ptp; }; + interface "ve2" { hello 5; type bcast; ttl security; }; + interface "ve3" { hello 5; type bcast; ttl security; }; + }; +} + + +protocol ospf3 ospf6 { +# ecmp; + + ipv6 { + import all; +# export where source = RTS_STATIC; + }; + + area 0 { + interface "ve0" { stub; }; + interface "ve1" { hello 5; type ptp; }; + interface "ve2" { hello 5; type bcast; }; + }; +} + +protocol bgp { + local 192.168.11.1 as 1000; + neighbor 192.168.11.2 as 2000; +# local 192.168.1.1 as 1000; +# neighbor 192.168.2.1 as 2000; +# multihop; +# rr client; +# strict bind; +# debug all; + + # regular IPv4 unicast (1/1) + ipv4 { + # connects to master4 table by default + import all; + export where source ~ [ RTS_STATIC, RTS_BGP ]; + }; + + # regular IPv6 unicast (2/1) + ipv6 { + # connects to master6 table by default + import all; + export where source ~ [ RTS_STATIC, RTS_BGP ]; +# next hop address 2001:db8:1:1::1; + }; + + # IPv4 multicast topology (1/2) + ipv4 multicast { + # explicit IPv4 table + table mcast4; + import all; + export all; + }; + + # IPv6 multicast topology (2/2) + ipv6 multicast { + # explicit IPv6 table + table mcast6; + import all; + export all; +# next hop address 2001:db8:1:1::1; + }; + + # IPv4 Flowspec (1/133) + flow4 { + # connects to flowtab4 table by default + import all; + export all; + }; + + # IPv6 Flowspec (2/133) + flow6 { + # connects to flowtab6 table by default + import all; + export all; + }; +} + +protocol bgp { + local 192.168.1.1 as 1000; + neighbor 192.168.3.1 as 1000; + multihop; + rr client; + + ipv4 { + import all; + export where source ~ [ RTS_STATIC, RTS_BGP ]; + }; + + ipv6 { + import all; + export where source ~ [ RTS_STATIC, RTS_BGP ]; + next hop address 2001:db8:1:1::1; + }; +} + +protocol bgp { + local 2001:db8:1:1::1 as 1000; + neighbor 2001:db8:4:1::1 as 1000; + multihop; + rr client; + + ipv4 { + import all; + export where source ~ [ RTS_STATIC, RTS_BGP ]; + next hop address 192.168.4.1; + }; + + ipv6 { + import all; + export where source ~ [ RTS_STATIC, RTS_BGP ]; + }; +} + From 5546aad260a3e569e86e2fd2b5f613202ac70be3 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Wed, 7 Dec 2016 19:56:42 +0100 Subject: [PATCH 05/20] NEWS and version update --- NEWS | 16 ++++++++++++++++ misc/bird.spec | 2 +- sysdep/config.h | 2 +- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 26314d82..9669392d 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,19 @@ +Version 2.0.0-pre0 (2016-12-07) + o Integrated IPv4 + IPv6 design + o Major BGP protocol redesign + o BGP multicast support (SAFI 2) + o BGP flowspec support (RFC 5575) + o New RPKI-Router protocol + o New build system + o Unit tests + + Notes: + + Protocols and tables are now connected using explicit channels, most related + protocol options (table, import, export, ...) are now channel options. See + doc/bird.conf.example2 for configuration examples. + + Version 1.6.2 (2016-09-29) o Fixes serious bug introduced in the previous version diff --git a/misc/bird.spec b/misc/bird.spec index ebc0c942..1da0c813 100644 --- a/misc/bird.spec +++ b/misc/bird.spec @@ -1,6 +1,6 @@ Summary: BIRD Internet Routing Daemon Name: bird -Version: 1.6.2 +Version: 2.0.0 Release: 1 Copyright: GPL Group: Networking/Daemons diff --git a/sysdep/config.h b/sysdep/config.h index c7f63e69..eb7356cd 100644 --- a/sysdep/config.h +++ b/sysdep/config.h @@ -7,7 +7,7 @@ #define _BIRD_CONFIG_H_ /* BIRD version */ -#define BIRD_VERSION "1.6.2" +#define BIRD_VERSION "2.0.0-pre0" /* Include parameters determined by configure script */ #include "sysdep/autoconf.h" From 2119ae74c2e3b101bb8c6f5f0413b143d9978c9c Mon Sep 17 00:00:00 2001 From: Ondrej Filip Date: Wed, 7 Dec 2016 20:31:12 +0100 Subject: [PATCH 06/20] Documentation build system fix --- tools/gendist | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/gendist b/tools/gendist index d9b34941..09d5d055 100755 --- a/tools/gendist +++ b/tools/gendist @@ -8,10 +8,10 @@ set -e AC=`if [ -x /usr/bin/autoconf2.50 ] ; then echo autoconf2.50 ; else echo autoconf ; fi` $AC ./configure +make docs make distclean $AC rm -rf autom4te*cache -( cd doc ; make docs ; make clean ) VERSION=`sed $T/$REL/ChangeLog mv $T/$REL/doc/*.ps $T/$DREL/doc +mv $T/$REL/doc/*.pdf $T/$DREL/doc rm -f $T/$REL/bird.conf* rm -rf $T/$REL/.git/ -rm -rf `find $T/$REL -name CVS -o -name tmp` $T/$REL/{misc,rfc,doc/slides} +rm -rf `find $T/$REL -name CVS -o -name tmp` $T/$REL/{misc,rfc,doc/slides,doc/slt2001,doc/old,doc/*.out} ( cd $T ; tar czvvf $REL.tar.gz $REL ) ( cd $T ; tar czvvf $DREL.tar.gz $DREL ) rm -rf $T/$REL $T/$DREL From 5e8df049fbf53220735a2eeb6c751e1758869a18 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Sat, 10 Dec 2016 00:11:26 +0100 Subject: [PATCH 07/20] Babel: Update to integrated branch --- configure.in | 3 +- proto/babel/babel.c | 195 ++++++++++++++++++++---------------------- proto/babel/babel.h | 19 ++-- proto/babel/config.Y | 2 + proto/babel/packets.c | 56 ++++++------ 5 files changed, 131 insertions(+), 144 deletions(-) diff --git a/configure.in b/configure.in index 32344d1f..bb779be7 100644 --- a/configure.in +++ b/configure.in @@ -185,8 +185,7 @@ fi AC_SUBST(iproutedir) -# all_protocols="$proto_bfd babel bgp ospf pipe radv rip $proto_rpki static" -all_protocols="$proto_bfd bgp ospf pipe radv rip $proto_rpki static " +all_protocols="$proto_bfd babel bgp ospf pipe radv rip $proto_rpki static" all_protocols=`echo $all_protocols | sed 's/ /,/g'` diff --git a/proto/babel/babel.c b/proto/babel/babel.c index 38be6909..73cb5c3b 100644 --- a/proto/babel/babel.c +++ b/proto/babel/babel.c @@ -53,8 +53,7 @@ static void babel_dump_route(struct babel_route *r); static void babel_select_route(struct babel_entry *e); static void babel_send_route_request(struct babel_entry *e, struct babel_neighbor *n); static void babel_send_wildcard_request(struct babel_iface *ifa); -static int babel_cache_seqno_request(struct babel_proto *p, ip_addr prefix, u8 plen, - u64 router_id, u16 seqno); +static int babel_cache_seqno_request(struct babel_proto *p, net_addr *n, u64 router_id, u16 seqno); static void babel_trigger_iface_update(struct babel_iface *ifa); static void babel_trigger_update(struct babel_proto *p); static void babel_send_seqno_request(struct babel_entry *e); @@ -67,27 +66,25 @@ static inline void babel_iface_kick_timer(struct babel_iface *ifa); */ static void -babel_init_entry(struct fib_node *n) +babel_init_entry(void *E) { - struct babel_entry *e = (void *) n; - e->proto = NULL; - e->selected_in = NULL; - e->selected_out = NULL; + struct babel_entry *e = E; + e->updated = now; init_list(&e->sources); init_list(&e->routes); } static inline struct babel_entry * -babel_find_entry(struct babel_proto *p, ip_addr prefix, u8 plen) +babel_find_entry(struct babel_proto *p, const net_addr *n) { - return fib_find(&p->rtable, &prefix, plen); + return fib_find(&p->rtable, n); } static struct babel_entry * -babel_get_entry(struct babel_proto *p, ip_addr prefix, u8 plen) +babel_get_entry(struct babel_proto *p, const net_addr *n) { - struct babel_entry *e = fib_get(&p->rtable, &prefix, plen); + struct babel_entry *e = fib_get(&p->rtable, n); e->proto = p; return e; } @@ -180,8 +177,8 @@ babel_flush_route(struct babel_route *r) { struct babel_proto *p = r->e->proto; - DBG("Babel: Flush route %I/%d router_id %lR neigh %I\n", - r->e->n.prefix, r->e->n.pxlen, r->router_id, r->neigh ? r->neigh->addr : IPA_NONE); + DBG("Babel: Flush route %N router_id %lR neigh %I\n", + r->e->n.addr, r->router_id, r->neigh ? r->neigh->addr : IPA_NONE); rem_node(NODE r); @@ -203,8 +200,8 @@ babel_expire_route(struct babel_route *r) struct babel_proto *p = r->e->proto; struct babel_entry *e = r->e; - TRACE(D_EVENTS, "Route expiry timer for %I/%d router-id %lR fired", - e->n.prefix, e->n.pxlen, r->router_id); + TRACE(D_EVENTS, "Route expiry timer for %N router-id %lR fired", + e->n.addr, r->router_id); if (r->metric < BABEL_INFINITY) { @@ -229,16 +226,14 @@ babel_refresh_route(struct babel_route *r) static void babel_expire_routes(struct babel_proto *p) { - struct babel_entry *e; struct babel_route *r, *rx; struct fib_iterator fit; FIB_ITERATE_INIT(&fit, &p->rtable); loop: - FIB_ITERATE_START(&p->rtable, &fit, n) + FIB_ITERATE_START(&p->rtable, &fit, struct babel_entry, e) { - e = (struct babel_entry *) n; int changed = 0; WALK_LIST_DELSAFE(r, rx, e->routes) @@ -261,7 +256,7 @@ loop: * babel_rt_notify() -> p->rtable change, invalidating hidden variables. */ - FIB_ITERATE_PUT(&fit, n); + FIB_ITERATE_PUT(&fit); babel_select_route(e); goto loop; } @@ -271,12 +266,12 @@ loop: /* Remove empty entries */ if (EMPTY_LIST(e->sources) && EMPTY_LIST(e->routes)) { - FIB_ITERATE_PUT(&fit, n); + FIB_ITERATE_PUT(&fit); fib_delete(&p->rtable, e); goto loop; } } - FIB_ITERATE_END(n); + FIB_ITERATE_END; } static struct babel_neighbor * @@ -476,8 +471,7 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e) if (r) { - net *n = net_get(p->p.table, e->n.prefix, e->n.pxlen); - rta A = { + rta a0 = { .src = p->p.main_source, .source = RTS_BABEL, .scope = SCOPE_UNIVERSE, @@ -489,22 +483,20 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e) }; if (r->metric < BABEL_INFINITY) - A.gw = r->next_hop; + a0.gw = r->next_hop; - rta *a = rta_lookup(&A); + rta *a = rta_lookup(&a0); rte *rte = rte_get_temp(a); rte->u.babel.metric = r->metric; rte->u.babel.router_id = r->router_id; - rte->net = n; rte->pflags = 0; - rte_update(&p->p, n, rte); + rte_update(&p->p, e->n.addr, rte); } else { /* Retraction */ - net *n = net_find(p->p.table, e->n.prefix, e->n.pxlen); - rte_update(&p->p, n, NULL); + rte_update(&p->p, e->n.addr, NULL); } } @@ -541,8 +533,8 @@ babel_select_route(struct babel_entry *e) ((!e->selected_in && cur->metric < BABEL_INFINITY) || (e->selected_in && cur->metric < e->selected_in->metric))) { - TRACE(D_EVENTS, "Picked new route for prefix %I/%d: router id %lR metric %d", - e->n.prefix, e->n.pxlen, cur->router_id, cur->metric); + TRACE(D_EVENTS, "Picked new route for prefix %N: router id %lR metric %d", + e->n.addr, cur->router_id, cur->metric); e->selected_in = cur; e->updated = now; @@ -557,8 +549,8 @@ babel_select_route(struct babel_entry *e) babel_build_rte() will set the unreachable flag if the metric is BABEL_INFINITY.*/ if (e->selected_in) { - TRACE(D_EVENTS, "Lost feasible route for prefix %I/%d", - e->n.prefix, e->n.pxlen); + TRACE(D_EVENTS, "Lost feasible route for prefix %N", + e->n.addr); e->selected_in->metric = BABEL_INFINITY; e->updated = now; @@ -576,7 +568,7 @@ babel_select_route(struct babel_entry *e) /* No route currently selected, and no new one selected; this means we don't have a route to this destination anymore (and were probably called from an expiry timer). Remove the route from the nest. */ - TRACE(D_EVENTS, "Flushing route for prefix %I/%d", e->n.prefix, e->n.pxlen); + TRACE(D_EVENTS, "Flushing route for prefix %N", e->n.addr); e->selected_in = NULL; e->updated = now; @@ -663,12 +655,11 @@ babel_send_route_request(struct babel_entry *e, struct babel_neighbor *n) struct babel_iface *ifa = n->ifa; union babel_msg msg = {}; - TRACE(D_PACKETS, "Sending route request for %I/%d to %I", - e->n.prefix, e->n.pxlen, n->addr); + TRACE(D_PACKETS, "Sending route request for %N to %I", + e->n.addr, n->addr); msg.type = BABEL_TLV_ROUTE_REQUEST; - msg.route_request.prefix = e->n.prefix; - msg.route_request.plen = e->n.pxlen; + net_copy(&msg.route_request.net, e->n.addr); babel_send_unicast(&msg, ifa, n->addr); } @@ -698,18 +689,17 @@ babel_send_seqno_request(struct babel_entry *e) union babel_msg msg = {}; s = babel_find_source(e, r->router_id); - if (!s || !babel_cache_seqno_request(p, e->n.prefix, e->n.pxlen, r->router_id, s->seqno + 1)) + if (!s || !babel_cache_seqno_request(p, e->n.addr, r->router_id, s->seqno + 1)) return; - TRACE(D_PACKETS, "Sending seqno request for %I/%d router-id %lR seqno %d", - e->n.prefix, e->n.pxlen, r->router_id, s->seqno + 1); + TRACE(D_PACKETS, "Sending seqno request for %N router-id %lR seqno %d", + e->n.addr, r->router_id, s->seqno + 1); msg.type = BABEL_TLV_SEQNO_REQUEST; - msg.seqno_request.plen = e->n.pxlen; - msg.seqno_request.seqno = s->seqno + 1; msg.seqno_request.hop_count = BABEL_INITIAL_HOP_COUNT; + msg.seqno_request.seqno = s->seqno + 1; msg.seqno_request.router_id = r->router_id; - msg.seqno_request.prefix = e->n.prefix; + net_copy(&msg.seqno_request.net, e->n.addr); WALK_LIST(ifa, p->interfaces) babel_enqueue(&msg, ifa); @@ -725,18 +715,17 @@ babel_unicast_seqno_request(struct babel_route *r) union babel_msg msg = {}; s = babel_find_source(e, r->router_id); - if (!s || !babel_cache_seqno_request(p, e->n.prefix, e->n.pxlen, r->router_id, s->seqno + 1)) + if (!s || !babel_cache_seqno_request(p, e->n.addr, r->router_id, s->seqno + 1)) return; - TRACE(D_PACKETS, "Sending seqno request for %I/%d router-id %lR seqno %d", - e->n.prefix, e->n.pxlen, r->router_id, s->seqno + 1); + TRACE(D_PACKETS, "Sending seqno request for %N router-id %lR seqno %d", + e->n.addr, r->router_id, s->seqno + 1); msg.type = BABEL_TLV_SEQNO_REQUEST; - msg.seqno_request.plen = e->n.pxlen; - msg.seqno_request.seqno = s->seqno + 1; msg.seqno_request.hop_count = BABEL_INITIAL_HOP_COUNT; + msg.seqno_request.seqno = s->seqno + 1; msg.seqno_request.router_id = r->router_id; - msg.seqno_request.prefix = e->n.prefix; + net_copy(&msg.seqno_request.net, e->n.addr); babel_send_unicast(&msg, ifa, r->neigh->addr); } @@ -756,9 +745,8 @@ babel_send_update(struct babel_iface *ifa, bird_clock_t changed) { struct babel_proto *p = ifa->proto; - FIB_WALK(&p->rtable, n) + FIB_WALK(&p->rtable, struct babel_entry, e) { - struct babel_entry *e = (void *) n; struct babel_route *r = e->selected_out; if (!r) @@ -776,17 +764,16 @@ babel_send_update(struct babel_iface *ifa, bird_clock_t changed) if (e->updated < changed) continue; - TRACE(D_PACKETS, "Sending update for %I/%d router-id %lR seqno %d metric %d", - e->n.prefix, e->n.pxlen, r->router_id, r->seqno, r->metric); + TRACE(D_PACKETS, "Sending update for %N router-id %lR seqno %d metric %d", + e->n.addr, r->router_id, r->seqno, r->metric); union babel_msg msg = {}; msg.type = BABEL_TLV_UPDATE; - msg.update.plen = e->n.pxlen; msg.update.interval = ifa->cf->update_interval; msg.update.seqno = r->seqno; msg.update.metric = r->metric; - msg.update.prefix = e->n.prefix; msg.update.router_id = r->router_id; + net_copy(&msg.update.net, e->n.addr); babel_enqueue(&msg, ifa); @@ -839,20 +826,18 @@ babel_trigger_update(struct babel_proto *p) /* A retraction is an update with an infinite metric */ static void -babel_send_retraction(struct babel_iface *ifa, ip_addr prefix, int plen) +babel_send_retraction(struct babel_iface *ifa, net_addr *n) { struct babel_proto *p = ifa->proto; union babel_msg msg = {}; - TRACE(D_PACKETS, "Sending retraction for %I/%d seqno %d", - prefix, plen, p->update_seqno); + TRACE(D_PACKETS, "Sending retraction for %N seqno %d", n, p->update_seqno); msg.type = BABEL_TLV_UPDATE; - msg.update.plen = plen; msg.update.interval = ifa->cf->update_interval; msg.update.seqno = p->update_seqno; msg.update.metric = BABEL_INFINITY; - msg.update.prefix = prefix; + msg.update.net = *n; babel_enqueue(&msg, ifa); } @@ -941,22 +926,20 @@ babel_expire_seqno_requests(struct babel_proto *p) * found. Otherwise, a new entry is stored in the cache. */ static int -babel_cache_seqno_request(struct babel_proto *p, ip_addr prefix, u8 plen, +babel_cache_seqno_request(struct babel_proto *p, net_addr *n, u64 router_id, u16 seqno) { struct babel_seqno_request *r; WALK_LIST(r, p->seqno_cache) { - if (ipa_equal(r->prefix, prefix) && (r->plen == plen) && - (r->router_id == router_id) && (r->seqno == seqno)) + if (net_equal(&r->net, n) && (r->router_id == router_id) && (r->seqno == seqno)) return 0; } /* no entries found */ r = sl_alloc(p->seqno_slab); - r->prefix = prefix; - r->plen = plen; + net_copy(&r->net, n); r->router_id = router_id; r->seqno = seqno; r->updated = now; @@ -973,8 +956,8 @@ babel_forward_seqno_request(struct babel_entry *e, struct babel_proto *p = e->proto; struct babel_route *r; - TRACE(D_PACKETS, "Forwarding seqno request for %I/%d router-id %lR seqno %d", - e->n.prefix, e->n.pxlen, in->router_id, in->seqno); + TRACE(D_PACKETS, "Forwarding seqno request for %N router-id %lR seqno %d", + e->n.addr, in->router_id, in->seqno); WALK_LIST(r, e->routes) { @@ -982,16 +965,15 @@ babel_forward_seqno_request(struct babel_entry *e, !OUR_ROUTE(r) && !ipa_equal(r->neigh->addr, sender)) { - if (!babel_cache_seqno_request(p, e->n.prefix, e->n.pxlen, in->router_id, in->seqno)) + if (!babel_cache_seqno_request(p, e->n.addr, in->router_id, in->seqno)) return; union babel_msg msg = {}; msg.type = BABEL_TLV_SEQNO_REQUEST; - msg.seqno_request.plen = in->plen; - msg.seqno_request.seqno = in->seqno; msg.seqno_request.hop_count = in->hop_count-1; + msg.seqno_request.seqno = in->seqno; msg.seqno_request.router_id = in->router_id; - msg.seqno_request.prefix = e->n.prefix; + net_copy(&msg.seqno_request.net, e->n.addr); babel_send_unicast(&msg, r->neigh->ifa, r->neigh->addr); return; @@ -1073,8 +1055,11 @@ babel_handle_update(union babel_msg *m, struct babel_iface *ifa) node *n; int feasible; - TRACE(D_PACKETS, "Handling update for %I/%d with seqno %d metric %d", - msg->prefix, msg->plen, msg->seqno, msg->metric); + if (msg->wildcard) + TRACE(D_PACKETS, "Handling wildcard retraction", msg->seqno); + else + TRACE(D_PACKETS, "Handling update for %N with seqno %d metric %d", + &msg->net, msg->seqno, msg->metric); nbr = babel_find_neighbor(ifa, msg->sender); if (!nbr) @@ -1140,7 +1125,7 @@ babel_handle_update(union babel_msg *m, struct babel_iface *ifa) } else { - e = babel_find_entry(p, msg->prefix, msg->plen); + e = babel_find_entry(p, &msg->net); if (!e) return; @@ -1159,7 +1144,7 @@ babel_handle_update(union babel_msg *m, struct babel_iface *ifa) return; } - e = babel_get_entry(p, msg->prefix, msg->plen); + e = babel_get_entry(p, &msg->net); r = babel_find_route(e, nbr); /* the route entry indexed by neighbour */ s = babel_find_source(e, msg->router_id); /* for feasibility */ feasible = babel_is_feasible(s, msg->seqno, msg->metric); @@ -1231,14 +1216,14 @@ babel_handle_route_request(union babel_msg *m, struct babel_iface *ifa) return; } - TRACE(D_PACKETS, "Handling route request for %I/%d", msg->prefix, msg->plen); + TRACE(D_PACKETS, "Handling route request for %N", &msg->net); /* Non-wildcard request - see if we have an entry for the route. If not, send a retraction, otherwise send an update. */ - struct babel_entry *e = babel_find_entry(p, msg->prefix, msg->plen); + struct babel_entry *e = babel_find_entry(p, &msg->net); if (!e) { - babel_send_retraction(ifa, msg->prefix, msg->plen); + babel_send_retraction(ifa, &msg->net); } else { @@ -1256,11 +1241,11 @@ babel_handle_seqno_request(union babel_msg *m, struct babel_iface *ifa) /* RFC 6126 3.8.1.2 */ - TRACE(D_PACKETS, "Handling seqno request for %I/%d router-id %lR seqno %d hop count %d", - msg->prefix, msg->plen, msg->router_id, msg->seqno, msg->hop_count); + TRACE(D_PACKETS, "Handling seqno request for %N router-id %lR seqno %d hop count %d", + &msg->net, msg->router_id, msg->seqno, msg->hop_count); /* Ignore if we have no such entry or entry has infinite metric */ - struct babel_entry *e = babel_find_entry(p, msg->prefix, msg->plen); + struct babel_entry *e = babel_find_entry(p, &msg->net); if (!e || !e->selected_out || (e->selected_out->metric == BABEL_INFINITY)) return; @@ -1668,7 +1653,7 @@ babel_dump_entry(struct babel_entry *e) struct babel_source *s; struct babel_route *r; - debug("Babel: Entry %I/%d:\n", e->n.prefix, e->n.pxlen); + debug("Babel: Entry %N:\n", e->n.addr); WALK_LIST(s,e->sources) { debug(" "); babel_dump_source(s); } @@ -1715,9 +1700,9 @@ babel_dump(struct proto *P) WALK_LIST(ifa, p->interfaces) babel_dump_iface(ifa); - FIB_WALK(&p->rtable, n) + FIB_WALK(&p->rtable, struct babel_entry, e) { - babel_dump_entry((struct babel_entry *) n); + babel_dump_entry(e); } FIB_WALK_END; } @@ -1828,11 +1813,9 @@ void babel_show_entries(struct proto *P) { struct babel_proto *p = (void *) P; - struct babel_entry *e = NULL; struct babel_source *s = NULL; struct babel_route *r = NULL; - char ipbuf[STD_ADDRESS_P_LENGTH+5]; char ridbuf[ROUTER_ID_64_LENGTH+1]; if (p->p.proto_state != PS_UP) @@ -1846,17 +1829,14 @@ babel_show_entries(struct proto *P) cli_msg(-1025, "%-29s %-23s %6s %5s %7s %7s", "Prefix", "Router ID", "Metric", "Seqno", "Expires", "Sources"); - FIB_WALK(&p->rtable, n) + FIB_WALK(&p->rtable, struct babel_entry, e) { - e = (struct babel_entry *) n; r = e->selected_in ? e->selected_in : e->selected_out; int srcs = 0; WALK_LIST(s, e->sources) srcs++; - bsprintf(ipbuf, "%I/%u", e->n.prefix, e->n.pxlen); - if (r) { if (r->router_id == p->router_id) @@ -1865,12 +1845,12 @@ babel_show_entries(struct proto *P) bsprintf(ridbuf, "%lR", r->router_id); int time = r->expires ? r->expires - now : 0; - cli_msg(-1025, "%-29s %-23s %6u %5u %7u %7u", - ipbuf, ridbuf, r->metric, r->seqno, MAX(time, 0), srcs); + cli_msg(-1025, "%-29N %-23s %6u %5u %7u %7u", + e->n.addr, ridbuf, r->metric, r->seqno, MAX(time, 0), srcs); } else { - cli_msg(-1025, "%-29s %-44s %7u", ipbuf, "", srcs); + cli_msg(-1025, "%-29N %-44s %7u", e->n.addr, "", srcs); } } FIB_WALK_END; @@ -1964,7 +1944,7 @@ babel_store_tmp_attrs(struct rte *rt, struct ea_list *attrs) * so store it into our data structures. */ static void -babel_rt_notify(struct proto *P, struct rtable *table UNUSED, struct network *net, +babel_rt_notify(struct proto *P, struct channel *c UNUSED, struct network *net, struct rte *new, struct rte *old UNUSED, struct ea_list *attrs UNUSED) { struct babel_proto *p = (void *) P; @@ -1974,7 +1954,7 @@ babel_rt_notify(struct proto *P, struct rtable *table UNUSED, struct network *ne if (new) { /* Update */ - e = babel_get_entry(p, net->n.prefix, net->n.pxlen); + e = babel_get_entry(p, net->n.addr); if (new->attrs->src->proto != P) { @@ -1996,7 +1976,7 @@ babel_rt_notify(struct proto *P, struct rtable *table UNUSED, struct network *ne else { /* Withdraw */ - e = babel_find_entry(p, net->n.prefix, net->n.pxlen); + e = babel_find_entry(p, net->n.addr); if (!e || !e->selected_out) return; @@ -2046,11 +2026,12 @@ babel_rte_same(struct rte *new, struct rte *old) static struct proto * -babel_init(struct proto_config *cfg) +babel_init(struct proto_config *CF) { - struct proto *P = proto_new(cfg, sizeof(struct babel_proto)); + struct proto *P = proto_new(CF); + + P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF)); - P->accept_ra_types = RA_OPTIMAL; P->if_notify = babel_if_notify; P->rt_notify = babel_rt_notify; P->import_control = babel_import_control; @@ -2068,7 +2049,8 @@ babel_start(struct proto *P) struct babel_proto *p = (void *) P; struct babel_config *cf = (void *) P->cf; - fib_init(&p->rtable, P->pool, sizeof(struct babel_entry), 0, babel_init_entry); + fib_init(&p->rtable, P->pool, NET_IP6, sizeof(struct babel_entry), + OFFSETOF(struct babel_entry, n), 0, babel_init_entry); init_list(&p->interfaces); p->timer = tm_new_set(P->pool, babel_timer, p, 0, 1); tm_start(p->timer, 2); @@ -2111,14 +2093,17 @@ babel_shutdown(struct proto *P) } static int -babel_reconfigure(struct proto *P, struct proto_config *c) +babel_reconfigure(struct proto *P, struct proto_config *CF) { struct babel_proto *p = (void *) P; - struct babel_config *new = (void *) c; + struct babel_config *new = (void *) CF; TRACE(D_EVENTS, "Reconfiguring"); - p->p.cf = c; + if (!proto_configure_channel(P, &P->main_channel, proto_cf_main_channel(CF))) + return 0; + + p->p.cf = CF; babel_reconfigure_ifaces(p, new); babel_trigger_update(p); @@ -2133,6 +2118,8 @@ struct protocol proto_babel = { .template = "babel%d", .attr_class = EAP_BABEL, .preference = DEF_PREF_BABEL, + .channel_mask = NB_IP6, + .proto_size = sizeof(struct babel_proto), .config_size = sizeof(struct babel_config), .init = babel_init, .dump = babel_dump, diff --git a/proto/babel/babel.h b/proto/babel/babel.h index e8b6c314..792c9d60 100644 --- a/proto/babel/babel.h +++ b/proto/babel/babel.h @@ -52,7 +52,7 @@ /* Max interval that will not overflow when carried as 16-bit centiseconds */ #define BABEL_MAX_INTERVAL (0xFFFF/BABEL_TIME_UNITS) -#define BABEL_OVERHEAD (SIZE_OF_IP_HEADER+UDP_HEADER_LENGTH) +#define BABEL_OVERHEAD (IP6_HEADER_LENGTH+UDP_HEADER_LENGTH) #define BABEL_MIN_MTU (512 + BABEL_OVERHEAD) @@ -208,7 +208,6 @@ struct babel_route { }; struct babel_entry { - struct fib_node n; struct babel_proto *proto; struct babel_route *selected_in; struct babel_route *selected_out; @@ -217,13 +216,14 @@ struct babel_entry { list sources; /* Source entries for this prefix (struct babel_source). */ list routes; /* Routes for this prefix (struct babel_route) */ + + struct fib_node n; }; /* Stores forwarded seqno requests for duplicate suppression. */ struct babel_seqno_request { node n; - ip_addr prefix; - u8 plen; + net_addr net; u64 router_id; u16 seqno; bird_clock_t updated; @@ -265,12 +265,11 @@ struct babel_msg_ihu { struct babel_msg_update { u8 type; u8 wildcard; - u8 plen; u16 interval; u16 seqno; u16 metric; - ip_addr prefix; u64 router_id; + net_addr net; ip_addr next_hop; ip_addr sender; }; @@ -278,17 +277,15 @@ struct babel_msg_update { struct babel_msg_route_request { u8 type; u8 full; - u8 plen; - ip_addr prefix; + net_addr net; }; struct babel_msg_seqno_request { u8 type; - u8 plen; - u16 seqno; u8 hop_count; + u16 seqno; u64 router_id; - ip_addr prefix; + net_addr net; ip_addr sender; }; diff --git a/proto/babel/config.Y b/proto/babel/config.Y index b6170852..cf8983fa 100644 --- a/proto/babel/config.Y +++ b/proto/babel/config.Y @@ -30,11 +30,13 @@ CF_ADDTO(proto, babel_proto) babel_proto_start: proto_start BABEL { this_proto = proto_config_new(&proto_babel, $1); + this_proto->net_type = NET_IP6; init_list(&BABEL_CFG->iface_list); }; babel_proto_item: proto_item + | proto_channel | INTERFACE babel_iface ; diff --git a/proto/babel/packets.c b/proto/babel/packets.c index 08054832..70cfc196 100644 --- a/proto/babel/packets.c +++ b/proto/babel/packets.c @@ -146,7 +146,8 @@ struct babel_write_state { #define TLV_HDR(tlv,t,l) ({ tlv->type = t; tlv->length = l - sizeof(struct babel_tlv); }) #define TLV_HDR0(tlv,t) TLV_HDR(tlv, t, tlv_data[t].min_length) -#define BYTES(n) ((((uint) n) + 7) / 8) +#define NET_SIZE(n) BYTES(net_pxlen(n)) + static inline u16 get_time16(const void *p) @@ -161,19 +162,19 @@ put_time16(void *p, u16 v) put_u16(p, v * BABEL_TIME_UNITS); } -static inline ip6_addr -get_ip6_px(const void *p, uint plen) +static inline void +read_ip6_px(net_addr *n, const void *p, uint plen) { ip6_addr addr = IPA_NONE; memcpy(&addr, p, BYTES(plen)); - return ip6_ntoh(addr); + net_fill_ip6(n, ip6_ntoh(addr), plen); } static inline void -put_ip6_px(void *p, ip6_addr addr, uint plen) +put_ip6_px(void *p, net_addr *n) { - addr = ip6_hton(addr); - memcpy(p, &addr, BYTES(plen)); + ip6_addr addr = ip6_hton(net6_prefix(n)); + memcpy(p, &addr, NET_SIZE(n)); } static inline ip6_addr @@ -480,6 +481,9 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m, if (tlv->plen > 0) return PARSE_ERROR; + if (msg->metric != 65535) + return PARSE_ERROR; + msg->wildcard = 1; break; @@ -488,7 +492,7 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m, return PARSE_IGNORE; case BABEL_AE_IP6: - if (tlv->plen > MAX_PREFIX_LENGTH) + if (tlv->plen > IP6_MAX_PREFIX_LENGTH) return PARSE_ERROR; /* Cannot omit data if there is no saved prefix */ @@ -499,18 +503,18 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m, memcpy(buf, state->def_ip6_prefix, tlv->omitted); memcpy(buf + tlv->omitted, tlv->addr, len); - msg->plen = tlv->plen; - msg->prefix = ipa_from_ip6(get_ip6(buf)); + ip6_addr prefix = get_ip6(buf); + net_fill_ip6(&msg->net, prefix, tlv->plen); if (tlv->flags & BABEL_FLAG_DEF_PREFIX) { - put_ip6(state->def_ip6_prefix, msg->prefix); + put_ip6(state->def_ip6_prefix, prefix); state->def_ip6_prefix_seen = 1; } if (tlv->flags & BABEL_FLAG_ROUTER_ID) { - state->router_id = ((u64) _I2(msg->prefix)) << 32 | _I3(msg->prefix); + state->router_id = ((u64) _I2(prefix)) << 32 | _I3(prefix); state->router_id_seen = 1; } break; @@ -559,7 +563,7 @@ babel_write_update(struct babel_tlv *hdr, union babel_msg *m, tlv = (struct babel_tlv_update *) NEXT_TLV(tlv); } - uint len = sizeof(struct babel_tlv_update) + BYTES(msg->plen); + uint len = sizeof(struct babel_tlv_update) + NET_SIZE(&msg->net); if (len0 + len > max_len) return 0; @@ -575,8 +579,8 @@ babel_write_update(struct babel_tlv *hdr, union babel_msg *m, else { tlv->ae = BABEL_AE_IP6; - tlv->plen = msg->plen; - put_ip6_px(tlv->addr, msg->prefix, msg->plen); + tlv->plen = net6_pxlen(&msg->net); + put_ip6_px(tlv->addr, &msg->net); } put_time16(&tlv->interval, msg->interval); @@ -610,14 +614,13 @@ babel_read_route_request(struct babel_tlv *hdr, union babel_msg *m, return PARSE_IGNORE; case BABEL_AE_IP6: - if (tlv->plen > MAX_PREFIX_LENGTH) + if (tlv->plen > IP6_MAX_PREFIX_LENGTH) return PARSE_ERROR; if (TLV_OPT_LENGTH(tlv) < BYTES(tlv->plen)) return PARSE_ERROR; - msg->plen = tlv->plen; - msg->prefix = get_ip6_px(tlv->addr, tlv->plen); + read_ip6_px(&msg->net, tlv->addr, tlv->plen); return PARSE_SUCCESS; case BABEL_AE_IP6_LL: @@ -637,7 +640,7 @@ babel_write_route_request(struct babel_tlv *hdr, union babel_msg *m, struct babel_tlv_route_request *tlv = (void *) hdr; struct babel_msg_route_request *msg = &m->route_request; - uint len = sizeof(struct babel_tlv_route_request) + BYTES(msg->plen); + uint len = sizeof(struct babel_tlv_route_request) + NET_SIZE(&msg->net); if (len > max_len) return 0; @@ -652,8 +655,8 @@ babel_write_route_request(struct babel_tlv *hdr, union babel_msg *m, else { tlv->ae = BABEL_AE_IP6; - tlv->plen = msg->plen; - put_ip6_px(tlv->addr, msg->prefix, msg->plen); + tlv->plen = net6_pxlen(&msg->net); + put_ip6_px(tlv->addr, &msg->net); } return len; @@ -685,14 +688,13 @@ babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *m, return PARSE_IGNORE; case BABEL_AE_IP6: - if (tlv->plen > MAX_PREFIX_LENGTH) + if (tlv->plen > IP6_MAX_PREFIX_LENGTH) return PARSE_ERROR; if (TLV_OPT_LENGTH(tlv) < BYTES(tlv->plen)) return PARSE_ERROR; - msg->plen = tlv->plen; - msg->prefix = get_ip6_px(tlv->addr, tlv->plen); + read_ip6_px(&msg->net, tlv->addr, tlv->plen); return PARSE_SUCCESS; case BABEL_AE_IP6_LL: @@ -712,18 +714,18 @@ babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *m, struct babel_tlv_seqno_request *tlv = (void *) hdr; struct babel_msg_seqno_request *msg = &m->seqno_request; - uint len = sizeof(struct babel_tlv_seqno_request) + BYTES(msg->plen); + uint len = sizeof(struct babel_tlv_seqno_request) + NET_SIZE(&msg->net); if (len > max_len) return 0; TLV_HDR(tlv, BABEL_TLV_SEQNO_REQUEST, len); tlv->ae = BABEL_AE_IP6; - tlv->plen = msg->plen; + tlv->plen = net6_pxlen(&msg->net); put_u16(&tlv->seqno, msg->seqno); tlv->hop_count = msg->hop_count; put_u64(&tlv->router_id, msg->router_id); - put_ip6_px(tlv->addr, msg->prefix, msg->plen); + put_ip6_px(tlv->addr, &msg->net); return len; } From 9e7d3a781075b39a7e0f97e63b6f313955daa661 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Tue, 13 Dec 2016 17:34:42 +0100 Subject: [PATCH 08/20] OSPF: Fix net-summary origination combined with stubnet option Stubnet nodes in OSPF FIB were removed during rt_sync(), but the pointer remained in top_hash_entry.nf, so net-summary LSA origination was confused, reported 'LSA ID collision' and net-summary LSAs were not originated properly. Thanks to Naveen Chowdary Yerramneni for bugreport and analysis. --- proto/ospf/rt.c | 17 ++++++++++------- proto/ospf/rt.h | 1 + 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index 19f2d074..21aaf144 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -429,10 +429,9 @@ add_network(struct ospf_area *oa, ip_addr px, int pxlen, int metric, struct top_ if (en == oa->rt) { /* - * Local stub networks does not have proper iface in en->nhi - * (because they all have common top_hash_entry en). - * We have to find iface responsible for that stub network. - * Configured stubnets does not have any iface. They will + * Local stub networks do not have proper iface in en->nhi (because they all + * have common top_hash_entry en). We have to find iface responsible for + * that stub network. Configured stubnets do not have any iface. They will * be removed in rt_sync(). */ @@ -1560,6 +1559,7 @@ ospf_rt_reset(struct ospf_proto *p) { ri = (ort *) nftmp; ri->area_net = 0; + ri->keep = 0; reset_ri(ri); } FIB_WALK_END; @@ -1929,9 +1929,12 @@ again1: } } - /* Remove configured stubnets */ - if (!nf->n.nhs) + /* Remove configured stubnets but keep the entries */ + if (nf->n.type && !nf->n.nhs) + { reset_ri(nf); + nf->keep = 1; + } if (nf->n.type) /* Add the route */ { @@ -1991,7 +1994,7 @@ again1: } /* Remove unused rt entry, some special entries are persistent */ - if (!nf->n.type && !nf->external_rte && !nf->area_net) + if (!nf->n.type && !nf->external_rte && !nf->area_net && !nf->keep) { FIB_ITERATE_PUT(&fit, nftmp); fib_delete(fib, nftmp); diff --git a/proto/ospf/rt.h b/proto/ospf/rt.h index 30332f3b..73b28375 100644 --- a/proto/ospf/rt.h +++ b/proto/ospf/rt.h @@ -84,6 +84,7 @@ typedef struct ort rta *old_rta; u8 external_rte; u8 area_net; + u8 keep; } ort; From eeba61ccd5d1757fd79fcb0cd42b8dee9f941d7e Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Tue, 13 Dec 2016 20:18:11 +0100 Subject: [PATCH 09/20] Minor cleanups --- lib/flowspec.c | 6 +++--- lib/flowspec.h | 4 ++-- lib/flowspec_test.c | 11 +++-------- proto/babel/Makefile | 2 ++ proto/rpki/Makefile | 2 ++ proto/rpki/packets.c | 4 ---- proto/rpki/rpki.c | 11 +++++------ proto/rpki/rpki.h | 1 - test/birdtest.c | 2 +- 9 files changed, 18 insertions(+), 25 deletions(-) diff --git a/lib/flowspec.c b/lib/flowspec.c index b72bc7fc..ea55b736 100644 --- a/lib/flowspec.c +++ b/lib/flowspec.c @@ -957,7 +957,7 @@ fragment_val_str(u8 val) return "???"; } -static int +static uint net_format_flow(char *buf, uint blen, const byte *data, uint dlen, int ipv6) { buffer b = { @@ -1125,7 +1125,7 @@ net_format_flow(char *buf, uint blen, const byte *data, uint dlen, int ipv6) * of written chars. If final string is too large, the string will ends the with * ' ...}' sequence and zero-terminator. */ -int +uint flow4_net_format(char *buf, uint blen, const net_addr_flow4 *f) { return net_format_flow(buf, blen, f->data, f->length - sizeof(net_addr_flow4), 0); @@ -1141,7 +1141,7 @@ flow4_net_format(char *buf, uint blen, const net_addr_flow4 *f) * of written chars. If final string is too large, the string will ends the with * ' ...}' sequence and zero-terminator. */ -int +uint flow6_net_format(char *buf, uint blen, const net_addr_flow6 *f) { return net_format_flow(buf, blen, f->data, f->length - sizeof(net_addr_flow6), 1); diff --git a/lib/flowspec.h b/lib/flowspec.h index aa9735f4..9150ca91 100644 --- a/lib/flowspec.h +++ b/lib/flowspec.h @@ -131,7 +131,7 @@ void flow6_validate_cf(net_addr_flow6 *f); * Net Formatting */ -int flow4_net_format(char *buf, uint blen, const net_addr_flow4 *f); -int flow6_net_format(char *buf, uint blen, const net_addr_flow6 *f); +uint flow4_net_format(char *buf, uint blen, const net_addr_flow4 *f); +uint flow6_net_format(char *buf, uint blen, const net_addr_flow6 *f); #endif /* _BIRD_FLOWSPEC_H_ */ diff --git a/lib/flowspec_test.c b/lib/flowspec_test.c index 93364dfe..36336104 100644 --- a/lib/flowspec_test.c +++ b/lib/flowspec_test.c @@ -30,20 +30,17 @@ t_read_length(void) { byte data[] = { 0xcc, 0xcc, 0xcc }; - u16 get; - u16 expect; - for (uint expect = 0; expect < 0xf0; expect++) { *data = expect; - get = flow_read_length(data); + uint get = flow_read_length(data); bt_assert_msg(get == expect, "Testing get length 0x%02x (get 0x%02x)", expect, get); } for (uint expect = 0; expect <= 0xfff; expect++) { put_u16(data, expect | 0xf000); - get = flow_read_length(data); + uint get = flow_read_length(data); bt_assert_msg(get == expect, "Testing get length 0x%03x (get 0x%03x)", expect, get); } @@ -54,12 +51,10 @@ static int t_write_length(void) { byte data[] = { 0xcc, 0xcc, 0xcc }; - uint offset; - byte *c; for (uint expect = 0; expect <= 0xfff; expect++) { - offset = flow_write_length(data, expect); + uint offset = flow_write_length(data, expect); uint set = (expect < 0xf0) ? *data : (get_u16(data) & 0x0fff); bt_assert_msg(set == expect, "Testing set length 0x%03x (set 0x%03x)", expect, set); diff --git a/proto/babel/Makefile b/proto/babel/Makefile index d7684705..a5b4a13b 100644 --- a/proto/babel/Makefile +++ b/proto/babel/Makefile @@ -2,3 +2,5 @@ src := babel.c packets.c obj := $(src-o-files) $(all-daemon) $(cf-local) + +tests_objs := $(tests_objs) $(src-o-files) \ No newline at end of file diff --git a/proto/rpki/Makefile b/proto/rpki/Makefile index bd76145e..eb09b7df 100644 --- a/proto/rpki/Makefile +++ b/proto/rpki/Makefile @@ -2,3 +2,5 @@ src := rpki.c packets.c tcp_transport.c ssh_transport.c transport.c obj := $(src-o-files) $(all-daemon) $(cf-local) + +tests_objs := $(tests_objs) $(src-o-files) \ No newline at end of file diff --git a/proto/rpki/packets.c b/proto/rpki/packets.c index b9d93106..60ca3936 100644 --- a/proto/rpki/packets.c +++ b/proto/rpki/packets.c @@ -531,8 +531,6 @@ rpki_send_pdu(struct rpki_cache *cache, const void *pdu, const uint len) static int rpki_check_receive_packet(struct rpki_cache *cache, const struct pdu_header *pdu) { - struct rpki_proto *p = cache->p; - int error = RPKI_SUCCESS; u32 pdu_len = ntohl(pdu->len); /* @@ -557,7 +555,6 @@ rpki_check_receive_packet(struct rpki_cache *cache, const struct pdu_header *pdu */ } else if (cache->last_update == 0 - && pdu->ver >= RPKI_MIN_VERSION && pdu->ver <= RPKI_MAX_VERSION && pdu->ver < cache->version) { @@ -608,7 +605,6 @@ rpki_handle_error_pdu(struct rpki_cache *cache, const struct pdu_error *pdu) case UNSUPPORTED_PROTOCOL_VER: CACHE_TRACE(D_PACKETS, cache, "Client uses unsupported protocol version"); if (pdu->ver <= RPKI_MAX_VERSION && - pdu->ver >= RPKI_MIN_VERSION && pdu->ver < cache->version) { CACHE_TRACE(D_EVENTS, cache, "Downgrading from protocol version %d to version %d", cache->version, pdu->ver); diff --git a/proto/rpki/rpki.c b/proto/rpki/rpki.c index 6360dbaf..0d4b1fd3 100644 --- a/proto/rpki/rpki.c +++ b/proto/rpki/rpki.c @@ -358,7 +358,7 @@ rpki_stop_retry_timer_event(struct rpki_cache *cache) tm_stop(cache->retry_timer); } -static void +static void UNUSED rpki_stop_expire_timer_event(struct rpki_cache *cache) { CACHE_DBG(cache, "Stop"); @@ -637,7 +637,7 @@ rpki_shutdown(struct proto *P) */ static int -rpki_try_fast_reconnect(struct rpki_cache *cache, struct rpki_config *new, struct rpki_config *old) +rpki_try_fast_reconnect(struct rpki_cache *cache) { if (cache->state == RPKI_CS_ESTABLISHED) { @@ -661,11 +661,10 @@ rpki_try_fast_reconnect(struct rpki_cache *cache, struct rpki_config *new, struc * protocol. Returns |NEED_TO_RESTART| or |SUCCESSFUL_RECONF|. */ static int -rpki_reconfigure_cache(struct rpki_proto *p, struct rpki_cache *cache, struct rpki_config *new, struct rpki_config *old) +rpki_reconfigure_cache(struct rpki_proto *p UNUSED, struct rpki_cache *cache, struct rpki_config *new, struct rpki_config *old) { u8 try_fast_reconnect = 0; - if (strcmp(old->hostname, new->hostname) != 0) { CACHE_TRACE(D_EVENTS, cache, "Cache server address changed to %s", new->hostname); @@ -710,7 +709,7 @@ rpki_reconfigure_cache(struct rpki_proto *p, struct rpki_cache *cache, struct rp #undef TEST_INTERVAL if (try_fast_reconnect) - return rpki_try_fast_reconnect(cache, new, old); + return rpki_try_fast_reconnect(cache); return SUCCESSFUL_RECONF; } @@ -907,7 +906,7 @@ rpki_postconfig(struct proto_config *CF) static void rpki_copy_config(struct proto_config *dest, struct proto_config *src) { - /* Just a shallow copy */ + /* FIXME: Should copy transport */ } struct protocol proto_rpki = { diff --git a/proto/rpki/rpki.h b/proto/rpki/rpki.h index eaeed858..80ef83df 100644 --- a/proto/rpki/rpki.h +++ b/proto/rpki/rpki.h @@ -29,7 +29,6 @@ #define RPKI_VERSION_0 0 #define RPKI_VERSION_1 1 -#define RPKI_MIN_VERSION RPKI_VERSION_0 #define RPKI_MAX_VERSION RPKI_VERSION_1 diff --git a/test/birdtest.c b/test/birdtest.c index 73cb9901..a4312e9b 100644 --- a/test/birdtest.c +++ b/test/birdtest.c @@ -200,7 +200,7 @@ bt_log_result(int result, const char *fmt, va_list argptr) vsnprintf(pos, sizeof(msg_buf) - (pos - msg_buf), fmt, argptr); int chrs = 0; - for (int i = 0; i < strlen(msg_buf); i += get_num_terminal_cols()) + for (uint i = 0; i < strlen(msg_buf); i += get_num_terminal_cols()) { if (i) printf("\n"); From 7d95c44572d79ef15ec8b0220950b4e4374c6bc6 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Thu, 15 Dec 2016 15:31:25 +0100 Subject: [PATCH 10/20] OSPF: Fix ECMP external merging The variable nfa is not cleaned before each loop iteration and can have a wrong value of nfa.nhs_reuse from the previous step. Thanks to Bernardo Figueiredo for the bugreport and analysis. --- proto/ospf/rt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index 21aaf144..368e3d05 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -1405,7 +1405,6 @@ ospf_ext_spf(struct ospf_proto *p) struct top_hash_entry *en; struct ospf_lsa_ext_local rt; ort *nf1, *nf2; - orta nfa = {}; ip_addr rtid; u32 br_metric; struct ospf_area *atmp; @@ -1414,6 +1413,8 @@ ospf_ext_spf(struct ospf_proto *p) WALK_SLIST(en, p->lsal) { + orta nfa = {}; + /* 16.4. (1) */ if ((en->lsa_type != LSA_T_EXT) && (en->lsa_type != LSA_T_NSSA)) continue; From 256cc8ee0867d7f5314d3a3d7db5429d2bf16b4e Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Tue, 20 Dec 2016 17:39:59 +0100 Subject: [PATCH 11/20] BGP: Report capabilities in show protocols all --- proto/bgp/bgp.c | 125 ++++++++++++++++++++++++++++++++++++++++---- proto/bgp/bgp.h | 4 ++ proto/bgp/packets.c | 3 -- 3 files changed, 118 insertions(+), 14 deletions(-) diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index b7229429..5df2e38d 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -1756,11 +1756,118 @@ bgp_get_status(struct proto *P, byte *buf) bsprintf(buf, "%-14s%s%s", bgp_state_dsc(p), err1, err2); } +static void +bgp_show_afis(int code, char *s, u32 *afis, uint count) +{ + buffer b; + LOG_BUFFER_INIT(b); + + buffer_puts(&b, s); + + for (u32 *af = afis; af < (afis + count); af++) + { + const struct bgp_af_desc *desc = bgp_get_af_desc(*af); + if (desc) + buffer_print(&b, " %s", desc->name); + else + buffer_print(&b, " <%u/%u>", BGP_AFI(*af), BGP_SAFI(*af)); + } + + if (b.pos == b.end) + strcpy(b.end - 32, " ... "); + + cli_msg(code, b.start); +} + +static void +bgp_show_capabilities(struct bgp_proto *p UNUSED, struct bgp_caps *caps) +{ + struct bgp_af_caps *ac; + uint any_mp_bgp = 0; + uint any_gr_able = 0; + uint any_add_path = 0; + u32 *afl1 = alloca(caps->af_count * sizeof(u32)); + u32 *afl2 = alloca(caps->af_count * sizeof(u32)); + uint afn1, afn2; + + WALK_AF_CAPS(caps, ac) + { + any_mp_bgp |= ac->ready; + any_gr_able |= ac->gr_able; + any_add_path |= ac->add_path; + } + + if (any_mp_bgp) + { + cli_msg(-1006, " Multiprotocol"); + + afn1 = 0; + WALK_AF_CAPS(caps, ac) + if (ac->ready) + afl1[afn1++] = ac->afi; + + bgp_show_afis(-1006, " AF announced:", afl1, afn1); + } + + if (caps->route_refresh) + cli_msg(-1006, " Route refresh"); + + if (caps->ext_messages) + cli_msg(-1006, " Extended message"); + + if (caps->gr_aware) + cli_msg(-1006, " Graceful restart"); + + if (any_gr_able) + { + /* Continues from gr_aware */ + cli_msg(-1006, " Restart time: %u", caps->gr_time); + if (caps->gr_flags & BGP_GRF_RESTART) + cli_msg(-1006, " Restart recovery"); + + afn1 = afn2 = 0; + WALK_AF_CAPS(caps, ac) + { + if (ac->gr_able) + afl1[afn1++] = ac->afi; + + if (ac->gr_af_flags & BGP_GRF_FORWARDING) + afl2[afn2++] = ac->afi; + } + + bgp_show_afis(-1006, " AF supported:", afl1, afn1); + bgp_show_afis(-1006, " AF preserved:", afl2, afn2); + } + + if (caps->as4_support) + cli_msg(-1006, " 4-octet AS numbers"); + + if (any_add_path) + { + cli_msg(-1006, " ADD-PATH"); + + afn1 = afn2 = 0; + WALK_AF_CAPS(caps, ac) + { + if (ac->add_path & BGP_ADD_PATH_RX) + afl1[afn1++] = ac->afi; + + if (ac->add_path & BGP_ADD_PATH_TX) + afl2[afn2++] = ac->afi; + } + + bgp_show_afis(-1006, " RX:", afl1, afn1); + bgp_show_afis(-1006, " TX:", afl2, afn2); + } + + if (caps->enhanced_refresh) + cli_msg(-1006, " Enhanced refresh"); +} + static void bgp_show_proto_info(struct proto *P) { struct bgp_proto *p = (struct bgp_proto *) P; - struct bgp_conn *c = p->conn; cli_msg(-1006, " BGP state: %s", bgp_state_dsc(p)); cli_msg(-1006, " Neighbor address: %I%J", p->cf->remote_ip, p->cf->iface); @@ -1789,15 +1896,11 @@ bgp_show_proto_info(struct proto *P) else if (P->proto_state == PS_UP) { cli_msg(-1006, " Neighbor ID: %R", p->remote_id); + cli_msg(-1006, " Local capabilities"); + bgp_show_capabilities(p, p->conn->local_caps); + cli_msg(-1006, " Neighbor capabilities"); + bgp_show_capabilities(p, p->conn->remote_caps); /* XXXX - cli_msg(-1006, " Neighbor caps: %s%s%s%s%s%s%s", - c->peer_refresh_support ? " refresh" : "", - c->peer_enhanced_refresh_support ? " enhanced-refresh" : "", - c->peer_gr_able ? " restart-able" : (c->peer_gr_aware ? " restart-aware" : ""), - c->peer_as4_support ? " AS4" : "", - (c->peer_add_path & ADD_PATH_RX) ? " add-path-rx" : "", - (c->peer_add_path & ADD_PATH_TX) ? " add-path-tx" : "", - c->peer_ext_messages_support ? " ext-messages" : ""); cli_msg(-1006, " Session: %s%s%s%s%s%s%s%s", p->is_internal ? "internal" : "external", p->cf->multihop ? " multihop" : "", @@ -1810,9 +1913,9 @@ bgp_show_proto_info(struct proto *P) */ cli_msg(-1006, " Source address: %I", p->source_addr); cli_msg(-1006, " Hold timer: %d/%d", - tm_remains(c->hold_timer), c->hold_time); + tm_remains(p->conn->hold_timer), p->conn->hold_time); cli_msg(-1006, " Keepalive timer: %d/%d", - tm_remains(c->keepalive_timer), c->keepalive_time); + tm_remains(p->conn->keepalive_timer), p->conn->keepalive_time); } if ((p->last_error_class != BE_NONE) && diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index db9ee8ea..a8a04947 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -174,6 +174,10 @@ struct bgp_caps { struct bgp_af_caps af_data[0]; /* Per-AF capability data */ }; +#define WALK_AF_CAPS(caps,ac) \ + for (ac = caps->af_data; ac < &caps->af_data[caps->af_count]; ac++) + + struct bgp_socket { node n; /* Node in global bgp_sockets */ sock *sk; /* Real listening socket */ diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 1ae75a64..43149a0c 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -185,9 +185,6 @@ bgp_create_notification(struct bgp_conn *conn, byte *buf) /* Capability negotiation as per RFC 5492 */ -#define WALK_AF_CAPS(caps,ac) \ - for (ac = caps->af_data; ac < &caps->af_data[caps->af_count]; ac++) - const struct bgp_af_caps * bgp_find_af_caps(struct bgp_caps *caps, u32 afi) { From 2c33da507046c25d87741fe0ce7947985c8c7a10 Mon Sep 17 00:00:00 2001 From: Jan Moskyto Matejka Date: Tue, 20 Dec 2016 20:13:08 +0100 Subject: [PATCH 12/20] Netlink: fix occasional netlink hangs on busy machines --- sysdep/linux/netlink.c | 1 + sysdep/unix/io.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index 368e0ef9..22313f43 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -1497,6 +1497,7 @@ nl_async_hook(sock *sk, uint size UNUSED) * One day we might react to it by asking for route table * scan in near future. */ + log(L_WARN "Kernel dropped some netlink messages, will resync on next scan."); return 1; /* More data are likely to be ready */ } else if (errno != EWOULDBLOCK) diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index 644a4fcd..8773f4c4 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -2238,7 +2238,8 @@ io_loop(void) if (pfd[s->index].revents & (POLLHUP | POLLERR)) { sk_err(s, pfd[s->index].revents); - goto next2; + if (s != current_sock) + goto next2; } current_sock = sk_next(s); From 017da76b729cc36c4a3416995b06386235660f42 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Wed, 21 Dec 2016 16:46:47 +0100 Subject: [PATCH 13/20] NEWS and version update --- NEWS | 7 +++++++ misc/bird.spec | 2 +- sysdep/config.h | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 26314d82..a9bd6a72 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,10 @@ +Version 1.6.3 (2016-12-21) + o Large BGP communities + o BFD authentication (MD5, SHA1) + o SHA1 and SHA2 authentication for RIP and OSPF + o Improved documentation + o Several bug fixes + Version 1.6.2 (2016-09-29) o Fixes serious bug introduced in the previous version diff --git a/misc/bird.spec b/misc/bird.spec index ebc0c942..bfbfc484 100644 --- a/misc/bird.spec +++ b/misc/bird.spec @@ -1,6 +1,6 @@ Summary: BIRD Internet Routing Daemon Name: bird -Version: 1.6.2 +Version: 1.6.3 Release: 1 Copyright: GPL Group: Networking/Daemons diff --git a/sysdep/config.h b/sysdep/config.h index c7f63e69..84085f9c 100644 --- a/sysdep/config.h +++ b/sysdep/config.h @@ -7,7 +7,7 @@ #define _BIRD_CONFIG_H_ /* BIRD version */ -#define BIRD_VERSION "1.6.2" +#define BIRD_VERSION "1.6.3" /* Include parameters determined by configure script */ #include "sysdep/autoconf.h" From f8aad5d5b7601d0500841e57bafa5796cc3156ab Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Fri, 23 Dec 2016 23:03:26 +0100 Subject: [PATCH 14/20] Minor cleanups --- nest/proto.c | 2 +- nest/route.h | 1 + proto/bgp/bgp.c | 8 +++++--- proto/bgp/bgp.h | 12 ------------ proto/bgp/config.Y | 1 + proto/bgp/packets.c | 8 ++++++-- 6 files changed, 14 insertions(+), 18 deletions(-) diff --git a/nest/proto.c b/nest/proto.c index 815d0652..0a7a32a6 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -490,7 +490,7 @@ int channel_reconfigure(struct channel *c, struct channel_config *cf) { /* FIXME: better handle these changes, also handle in_keep_filtered */ - if ((c->table != cf->table->table) || (c->ra_mode != cf->ra_mode)) + if ((c->table != cf->table->table) || (cf->ra_mode && (c->ra_mode != cf->ra_mode))) return 0; int import_changed = !filter_same(c->in_filter, cf->in_filter); diff --git a/nest/route.h b/nest/route.h index d652ca15..12e67d61 100644 --- a/nest/route.h +++ b/nest/route.h @@ -258,6 +258,7 @@ static inline int rte_is_filtered(rte *r) { return !!(r->flags & REF_FILTERED); /* Types of route announcement, also used as flags */ +#define RA_UNDEF 0 /* Undefined RA type */ #define RA_OPTIMAL 1 /* Announcement of optimal route change */ #define RA_ACCEPTED 2 /* Announcement of first accepted route */ #define RA_ANY 3 /* Announcement of any route change */ diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index 5df2e38d..83c16889 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -524,9 +524,13 @@ bgp_conn_enter_established_state(struct bgp_conn *conn) c->add_path_rx = (loc->add_path & BGP_ADD_PATH_RX) && (rem->add_path & BGP_ADD_PATH_TX); c->add_path_tx = (loc->add_path & BGP_ADD_PATH_TX) && (rem->add_path & BGP_ADD_PATH_RX); - // XXXX reset back to non-ANY? + /* Update RA mode */ if (c->add_path_tx) c->c.ra_mode = RA_ANY; + else if (c->cf->secondary) + c->c.ra_mode = RA_ACCEPTED; + else + c->c.ra_mode = RA_OPTIMAL; } p->afi_map = mb_alloc(p->p.pool, num * sizeof(u32)); @@ -1411,8 +1415,6 @@ bgp_channel_init(struct channel *C, struct channel_config *CF) struct bgp_channel *c = (void *) C; struct bgp_channel_config *cf = (void *) CF; - C->ra_mode = cf->secondary ? RA_ACCEPTED : RA_OPTIMAL; - c->cf = cf; c->afi = cf->afi; c->desc = bgp_get_af_desc(c->afi); diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index a8a04947..7f5be4ea 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -453,18 +453,6 @@ bgp_unset_attr(ea_list **to, struct linpool *pool, uint code) { eattr *e = bgp_set_attr(to, pool, code, 0, 0); e->type = EAF_TYPE_UNDEF; } - - -/* Hack: although BA_NEXT_HOP attribute has type EAF_TYPE_IP_ADDRESS, in IPv6 - * we store two addesses in it - a global address and a link local address. - */ -#ifdef XXX -#define NEXT_HOP_LENGTH (2*sizeof(ip_addr)) -static inline void set_next_hop(byte *b, ip_addr addr) { ((ip_addr *) b)[0] = addr; ((ip_addr *) b)[1] = IPA_NONE; } -#define NEXT_HOP_LENGTH sizeof(ip_addr) -static inline void set_next_hop(byte *b, ip_addr addr) { ((ip_addr *) b)[0] = addr; } -#endif - int bgp_encode_attrs(struct bgp_write_state *s, ea_list *attrs, byte *buf, byte *end); ea_list * bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len); diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y index 2a54db17..7c89fd50 100644 --- a/proto/bgp/config.Y +++ b/proto/bgp/config.Y @@ -152,6 +152,7 @@ bgp_channel_start: bgp_afi this_channel = channel_config_new(&channel_bgp, desc->net, this_proto); BGP_CC->c.name = desc->name; + BGP_CC->c.ra_mode = RA_UNDEF; BGP_CC->afi = $1; BGP_CC->gr_able = 0xff; /* undefined */ }; diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 43149a0c..a7df1c63 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -277,6 +277,12 @@ bgp_write_capabilities(struct bgp_conn *conn, byte *buf) /* Create capability list in buffer */ + /* + * Note that max length is ~ 20+14*af_count. With max 6 channels that is + * 104. Option limit is 253 and buffer size is 4096, so we cannot overflow + * unless we add new capabilities or more AFs. + */ + WALK_AF_CAPS(caps, ac) if (ac->ready) { @@ -350,8 +356,6 @@ bgp_write_capabilities(struct bgp_conn *conn, byte *buf) *buf++ = 0; /* Capability data length */ } - /* FIXME: Should not XXXX 255 */ - return buf; } From f6e6c3b5a5997ffc67d96785bbde76bcec072890 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Tue, 17 Jan 2017 13:21:25 +0100 Subject: [PATCH 15/20] Fix IP_HDRINCL usage on FreeBSD 11 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit FreeBSD 11 changed endianity of ip_len field from host order to network order. Also DragonFly BSD allegedly expects network order here. Thanks to Olivier Cochard-Labbé for the patch. --- sysdep/bsd/sysio.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sysdep/bsd/sysio.h b/sysdep/bsd/sysio.h index 2610a47b..9b10e6e8 100644 --- a/sysdep/bsd/sysio.h +++ b/sysdep/bsd/sysio.h @@ -9,6 +9,7 @@ #include #include // Workaround for some BSDs #include +#include #ifdef __NetBSD__ @@ -179,8 +180,8 @@ sk_prepare_ip_header(sock *s, void *hdr, int dlen) ip->ip_src = ipa_to_in4(s->saddr); ip->ip_dst = ipa_to_in4(s->daddr); -#ifdef __OpenBSD__ - /* OpenBSD expects ip_len in network order, other BSDs expect host order */ +#if (defined __OpenBSD__) || (defined __DragonFly__) || (defined __FreeBSD__ && (__FreeBSD_version >= 1100030)) + /* Different BSDs have different expectations of ip_len endianity */ ip->ip_len = htons(ip->ip_len); #endif } From 5509e17d0c1b4e75d5911864f75ba119769e5725 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Sun, 22 Jan 2017 16:32:42 +0100 Subject: [PATCH 16/20] BGP: Support for AS confederations (RFC 5065) --- doc/bird.sgml | 26 +++- nest/a-path.c | 331 +++++++++++++++++++++++++++------------------ nest/a-path_test.c | 10 +- nest/attrs.h | 7 +- proto/bgp/attrs.c | 88 ++++++------ 5 files changed, 277 insertions(+), 185 deletions(-) diff --git a/doc/bird.sgml b/doc/bird.sgml index 999fa294..ff2c188f 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -1945,12 +1945,11 @@ avoid routing loops.

BIRD supports all requirements of the BGP4 standard as defined in It also supports the community attributes (), -capability negotiation (), MD5 password authentication (), extended communities (), route reflectors (), graceful restart (), multiprotocol extensions -(), 4B AS numbers (), and 4B AS numbers in -extended communities (). - +capability negotiation (), MD5 password authentication +(), extended communities (), route reflectors +(), AS confederations (), graceful restart +(), multiprotocol extensions (), 4B AS numbers +(), and 4B AS numbers in extended communities (). For IPv6, it uses the standard multiprotocol extensions defined in and applied to IPv6 according to . @@ -2134,6 +2133,21 @@ using the following configuration parameters: accepting incoming connections. In passive mode, outgoing connections are not initiated. Default: off. +