From 9fe1d3ca8a6420b4bdaf15a54ab7b13be6cc07eb Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Fri, 22 May 2015 11:12:48 +0200 Subject: [PATCH 01/28] Fixes unnamed protocols from templates --- nest/config.Y | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nest/config.Y b/nest/config.Y index 939bed6a..37551802 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -183,16 +183,18 @@ proto_name: } | FROM SYM { struct symbol *s = cf_default_name(this_proto->protocol->template, &this_proto->protocol->name_counter); + s->class = this_proto->class; + s->def = this_proto; this_proto->name = s->name; + if (($2->class != SYM_TEMPLATE) && ($2->class != SYM_PROTO)) cf_error("Template or protocol name expected"); proto_copy_config(this_proto, $2->def); } | SYM FROM SYM { - if (($3->class != SYM_TEMPLATE) && ($3->class != SYM_PROTO)) cf_error("Template or protocol name expected"); - cf_define_symbol($1, this_proto->class, this_proto); this_proto->name = $1->name; + if (($3->class != SYM_TEMPLATE) && ($3->class != SYM_PROTO)) cf_error("Template or protocol name expected"); proto_copy_config(this_proto, $3->def); } ; From 398f92253186d70eb3f2e910c7f8dd2636ee5fa1 Mon Sep 17 00:00:00 2001 From: Ondrej Filip Date: Mon, 1 Jun 2015 10:41:17 +0200 Subject: [PATCH 02/28] Typo fix by Hans van Kranenburg --- proto/ospf/iface.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c index 656184c6..9b0f7797 100644 --- a/proto/ospf/iface.c +++ b/proto/ospf/iface.c @@ -1344,9 +1344,9 @@ ospf_iface_info(struct ospf_iface *ifa) cli_msg(-1015, "\tRetransmit timer: %u", ifa->rxmtint); if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA)) { - cli_msg(-1015, "\tDesigned router (ID): %R", ifa->drid); - cli_msg(-1015, "\tDesigned router (IP): %I", ifa->drip); - cli_msg(-1015, "\tBackup designed router (ID): %R", ifa->bdrid); - cli_msg(-1015, "\tBackup designed router (IP): %I", ifa->bdrip); + cli_msg(-1015, "\tDesignated router (ID): %R", ifa->drid); + cli_msg(-1015, "\tDesignated router (IP): %I", ifa->drip); + cli_msg(-1015, "\tBackup designated router (ID): %R", ifa->bdrid); + cli_msg(-1015, "\tBackup designated router (IP): %I", ifa->bdrip); } } From e348ef01b433e06888310c1098a05291034a856c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Tvrd=C3=ADk?= Date: Tue, 19 May 2015 08:14:04 +0200 Subject: [PATCH 03/28] unsgined char -> byte --- lib/printf.c | 2 +- nest/route.h | 2 +- proto/ospf/rt.c | 2 +- sysdep/bsd/sysio.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/printf.c b/lib/printf.c index 3eb988fa..a1c36129 100644 --- a/lib/printf.c +++ b/lib/printf.c @@ -215,7 +215,7 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args) if (!(flags & LEFT)) while (--field_width > 0) *str++ = ' '; - *str++ = (unsigned char) va_arg(args, int); + *str++ = (byte) va_arg(args, int); while (--field_width > 0) *str++ = ' '; continue; diff --git a/nest/route.h b/nest/route.h index 87f10ae3..2e6bf741 100644 --- a/nest/route.h +++ b/nest/route.h @@ -320,7 +320,7 @@ struct mpnh { ip_addr gw; /* Next hop */ struct iface *iface; /* Outgoing interface */ struct mpnh *next; - unsigned char weight; + byte weight; }; struct rte_src { diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index 74d10c7b..e74bcae6 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -43,7 +43,7 @@ unresolved_vlink(ort *ort) } static inline struct mpnh * -new_nexthop(struct ospf_proto *p, ip_addr gw, struct iface *iface, unsigned char weight) +new_nexthop(struct ospf_proto *p, ip_addr gw, struct iface *iface, byte weight) { struct mpnh *nh = lp_alloc(p->nhpool, sizeof(struct mpnh)); nh->gw = gw; diff --git a/sysdep/bsd/sysio.h b/sysdep/bsd/sysio.h index df5e0236..c82d7a1e 100644 --- a/sysdep/bsd/sysio.h +++ b/sysdep/bsd/sysio.h @@ -130,7 +130,7 @@ static inline void sk_process_cmsg4_ttl(sock *s, struct cmsghdr *cm) { if (cm->cmsg_type == IP_RECVTTL) - s->rcv_ttl = * (unsigned char *) CMSG_DATA(cm); + s->rcv_ttl = * (byte *) CMSG_DATA(cm); } static inline void From ae80a2de95d3d3c153ce20b90c9d8757d02cb33d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Tvrd=C3=ADk?= Date: Tue, 19 May 2015 08:53:34 +0200 Subject: [PATCH 04/28] unsigned [int] -> uint --- client/commands.c | 2 +- conf/conf.h | 2 +- lib/bitops.c | 2 +- lib/bitops.h | 2 +- lib/checksum.c | 10 +++++----- lib/checksum.h | 4 ++-- lib/ip.h | 4 ++-- lib/mempool.c | 12 ++++++------ lib/printf.c | 2 +- lib/slab.c | 12 ++++++------ lib/socket.h | 14 +++++++------- lib/xmalloc.c | 4 ++-- misc/ips.c | 4 ++-- nest/a-path.c | 2 +- nest/a-set.c | 4 ++-- nest/attrs.h | 6 +++--- nest/cli.c | 10 +++++----- nest/cli.h | 12 ++++++------ nest/neighbor.c | 4 ++-- nest/proto.c | 22 +++++++++++----------- nest/protocol.h | 16 ++++++++-------- nest/route.h | 22 +++++++++++----------- nest/rt-attr.c | 30 +++++++++++++++--------------- nest/rt-fib.c | 10 +++++----- nest/rt-table.c | 10 +++++----- proto/bgp/attrs.c | 14 +++++++------- proto/bgp/bgp.h | 8 ++++---- proto/bgp/packets.c | 8 ++++---- sysdep/bsd/krt-sock.c | 4 ++-- sysdep/linux/netlink.c | 6 +++--- sysdep/unix/main.c | 2 +- sysdep/unix/unix.h | 2 +- 32 files changed, 133 insertions(+), 133 deletions(-) diff --git a/client/commands.c b/client/commands.c index 08e7949a..50fcba40 100644 --- a/client/commands.c +++ b/client/commands.c @@ -38,7 +38,7 @@ static struct cmd_node cmd_root; void cmd_build_tree(void) { - unsigned int i; + uint i; cmd_root.plastson = &cmd_root.son; diff --git a/conf/conf.h b/conf/conf.h index 6ab53e25..515efbb3 100644 --- a/conf/conf.h +++ b/conf/conf.h @@ -100,7 +100,7 @@ void cfg_copy_list(list *dest, list *src, unsigned node_size); /* Lexer */ -extern int (*cf_read_hook)(byte *buf, unsigned int max, int fd); +extern int (*cf_read_hook)(byte *buf, uint max, int fd); struct symbol { struct symbol *next; diff --git a/lib/bitops.c b/lib/bitops.c index b63274b8..81586e87 100644 --- a/lib/bitops.c +++ b/lib/bitops.c @@ -17,7 +17,7 @@ * representation consists of @n ones followed by zeroes. */ u32 -u32_mkmask(unsigned n) +u32_mkmask(uint n) { return n ? ~((1 << (32 - n)) - 1) : 0; } diff --git a/lib/bitops.h b/lib/bitops.h index a12f6b60..c0ad1a70 100644 --- a/lib/bitops.h +++ b/lib/bitops.h @@ -18,7 +18,7 @@ * u32_masklen Inverse operation to u32_mkmask, -1 if not a bitmask. */ -u32 u32_mkmask(unsigned n); +u32 u32_mkmask(uint n); int u32_masklen(u32 x); u32 u32_log2(u32 v); diff --git a/lib/checksum.c b/lib/checksum.c index 18b1f92c..b61306b3 100644 --- a/lib/checksum.c +++ b/lib/checksum.c @@ -28,7 +28,7 @@ add32(u32 sum, u32 x) } static u16 -ipsum_calc_block(u32 *buf, unsigned len, u16 isum) +ipsum_calc_block(u32 *buf, uint len, u16 isum) { /* * A few simple facts about the IP checksum (see RFC 1071 for detailed @@ -57,7 +57,7 @@ ipsum_calc_block(u32 *buf, unsigned len, u16 isum) } static u16 -ipsum_calc(void *frag, unsigned len, va_list args) +ipsum_calc(void *frag, uint len, va_list args) { u16 sum = 0; @@ -67,7 +67,7 @@ ipsum_calc(void *frag, unsigned len, va_list args) frag = va_arg(args, void *); if (!frag) break; - len = va_arg(args, unsigned); + len = va_arg(args, uint); } return sum; } @@ -87,7 +87,7 @@ ipsum_calc(void *frag, unsigned len, va_list args) * Result: 1 if the checksum is correct, 0 else. */ int -ipsum_verify(void *frag, unsigned len, ...) +ipsum_verify(void *frag, uint len, ...) { va_list args; u16 sum; @@ -110,7 +110,7 @@ ipsum_verify(void *frag, unsigned len, ...) * up checksum calculation as much as possible. */ u16 -ipsum_calculate(void *frag, unsigned len, ...) +ipsum_calculate(void *frag, uint len, ...) { va_list args; u16 sum; diff --git a/lib/checksum.h b/lib/checksum.h index 81515543..16cbcce5 100644 --- a/lib/checksum.h +++ b/lib/checksum.h @@ -14,7 +14,7 @@ * fragments finished by NULL pointer. */ -int ipsum_verify(void *frag, unsigned len, ...); -u16 ipsum_calculate(void *frag, unsigned len, ...); +int ipsum_verify(void *frag, uint len, ...); +u16 ipsum_calculate(void *frag, uint len, ...); #endif diff --git a/lib/ip.h b/lib/ip.h index 45e073d9..90bb7f8a 100644 --- a/lib/ip.h +++ b/lib/ip.h @@ -471,11 +471,11 @@ int ip6_pton(char *a, ip6_addr *o); #define ipa_in_net(x,n,p) (ipa_zero(ipa_and(ipa_xor((n),(x)),ipa_mkmask(p)))) #define net_in_net(n1,l1,n2,l2) (((l1) >= (l2)) && (ipa_zero(ipa_and(ipa_xor((n1),(n2)),ipa_mkmask(l2))))) -char *ip_scope_text(unsigned); +char *ip_scope_text(uint); struct prefix { ip_addr addr; - unsigned int len; + uint len; }; diff --git a/lib/mempool.c b/lib/mempool.c index ec9854a9..a8281041 100644 --- a/lib/mempool.c +++ b/lib/mempool.c @@ -27,7 +27,7 @@ struct lp_chunk { struct lp_chunk *next; - unsigned int size; + uint size; uintptr_t data_align[0]; byte data[0]; }; @@ -37,7 +37,7 @@ struct linpool { byte *ptr, *end; struct lp_chunk *first, *current, **plast; /* Normal (reusable) chunks */ struct lp_chunk *first_large; /* Large chunks */ - unsigned chunk_size, threshold, total, total_large; + uint chunk_size, threshold, total, total_large; }; static void lp_free(resource *); @@ -64,7 +64,7 @@ static struct resclass lp_class = { * @blk. */ linpool -*lp_new(pool *p, unsigned blk) +*lp_new(pool *p, uint blk) { linpool *m = ralloc(p, &lp_class); m->plast = &m->first; @@ -88,7 +88,7 @@ linpool * size chunk, an "overflow" chunk is created for it instead. */ void * -lp_alloc(linpool *m, unsigned size) +lp_alloc(linpool *m, uint size) { byte *a = (byte *) BIRD_ALIGN((unsigned long) m->ptr, CPU_STRUCT_ALIGN); byte *e = a + size; @@ -146,7 +146,7 @@ lp_alloc(linpool *m, unsigned size) * how to allocate strings without any space overhead. */ void * -lp_allocu(linpool *m, unsigned size) +lp_allocu(linpool *m, uint size) { byte *a = m->ptr; byte *e = a + size; @@ -168,7 +168,7 @@ lp_allocu(linpool *m, unsigned size) * clears the allocated memory block. */ void * -lp_allocz(linpool *m, unsigned size) +lp_allocz(linpool *m, uint size) { void *z = lp_alloc(m, size); diff --git a/lib/printf.c b/lib/printf.c index a1c36129..e4cc3006 100644 --- a/lib/printf.c +++ b/lib/printf.c @@ -355,7 +355,7 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args) } else if (flags & SIGN) num = va_arg(args, int); else - num = va_arg(args, unsigned int); + num = va_arg(args, uint); str = number(str, num, base, field_width, precision, flags, size); if (!str) return -1; diff --git a/lib/slab.c b/lib/slab.c index 31529c30..5c414f9e 100644 --- a/lib/slab.c +++ b/lib/slab.c @@ -51,7 +51,7 @@ static size_t slab_memsize(resource *r); struct slab { resource r; - unsigned size; + uint size; list objs; }; @@ -71,7 +71,7 @@ struct sl_obj { }; slab * -sl_new(pool *p, unsigned size) +sl_new(pool *p, uint size) { slab *s = ralloc(p, &sl_class); s->size = size; @@ -144,7 +144,7 @@ slab_memsize(resource *r) struct slab { resource r; - unsigned obj_size, head_size, objs_per_slab, num_empty_heads, data_size; + uint obj_size, head_size, objs_per_slab, num_empty_heads, data_size; list empty_heads, partial_heads, full_heads; }; @@ -185,10 +185,10 @@ struct sl_alignment { /* Magic structure for testing of alignment */ * objects of size @size can be allocated. */ slab * -sl_new(pool *p, unsigned size) +sl_new(pool *p, uint size) { slab *s = ralloc(p, &sl_class); - unsigned int align = sizeof(struct sl_alignment); + uint align = sizeof(struct sl_alignment); if (align < sizeof(int)) align = sizeof(int); s->data_size = size; @@ -214,7 +214,7 @@ sl_new_head(slab *s) struct sl_head *h = xmalloc(SLAB_SIZE); struct sl_obj *o = (struct sl_obj *)((byte *)h+s->head_size); struct sl_obj *no; - unsigned int n = s->objs_per_slab; + uint n = s->objs_per_slab; h->first_free = o; h->num_full = 0; diff --git a/lib/socket.h b/lib/socket.h index 683cdde3..fbea92aa 100644 --- a/lib/socket.h +++ b/lib/socket.h @@ -20,7 +20,7 @@ typedef struct birdsock { int type; /* Socket type */ void *data; /* User data */ ip_addr saddr, daddr; /* IPA_NONE = unspecified */ - unsigned sport, dport; /* 0 = unspecified (for IP: protocol type) */ + uint sport, dport; /* 0 = unspecified (for IP: protocol type) */ int tos; /* TOS / traffic class, -1 = default */ int priority; /* Local socket priority, -1 = default */ int ttl; /* Time To Live, -1 = default */ @@ -28,20 +28,20 @@ typedef struct birdsock { struct iface *iface; /* Interface; specify this for broad/multicast sockets */ byte *rbuf, *rpos; /* NULL=allocate automatically */ - unsigned rbsize; + uint rbsize; int (*rx_hook)(struct birdsock *, int size); /* NULL=receiving turned off, returns 1 to clear rx buffer */ byte *tbuf, *tpos; /* NULL=allocate automatically */ byte *ttx; /* Internal */ - unsigned tbsize; + uint tbsize; void (*tx_hook)(struct birdsock *); void (*err_hook)(struct birdsock *, int); /* errno or zero if EOF */ /* Information about received datagrams (UDP, RAW), valid in rx_hook */ ip_addr faddr, laddr; /* src (From) and dst (Local) address of the datagram */ - unsigned fport; /* src port of the datagram */ - unsigned lifindex; /* local interface that received the datagram */ + uint fport; /* src port of the datagram */ + uint lifindex; /* local interface that received the datagram */ /* laddr and lifindex are valid only if SKF_LADDR_RX flag is set to request it */ int af; /* Address family (AF_INET, AF_INET6 or 0 for non-IP) of fd */ @@ -59,8 +59,8 @@ sock *sock_new(pool *); /* Allocate new socket */ int sk_open(sock *); /* Open socket */ int sk_rx_ready(sock *s); -int sk_send(sock *, unsigned len); /* Send data, <0=err, >0=ok, 0=sleep */ -int sk_send_to(sock *, unsigned len, ip_addr to, unsigned port); /* sk_send to given destination */ +int sk_send(sock *, uint len); /* Send data, <0=err, >0=ok, 0=sleep */ +int sk_send_to(sock *, uint len, ip_addr to, uint port); /* sk_send to given destination */ void sk_reallocate(sock *); /* Free and allocate tbuf & rbuf */ void sk_set_rbsize(sock *s, uint val); /* Resize RX buffer */ void sk_set_tbsize(sock *s, uint val); /* Resize TX buffer, keeping content */ diff --git a/lib/xmalloc.c b/lib/xmalloc.c index da2f0941..10bf28cf 100644 --- a/lib/xmalloc.c +++ b/lib/xmalloc.c @@ -24,7 +24,7 @@ * Wherever possible, please use the memory resources instead. */ void * -xmalloc(unsigned size) +xmalloc(uint size) { void *p = malloc(size); if (p) @@ -44,7 +44,7 @@ xmalloc(unsigned size) * Wherever possible, please use the memory resources instead. */ void * -xrealloc(void *ptr, unsigned size) +xrealloc(void *ptr, uint size) { void *p = realloc(ptr, size); if (p) diff --git a/misc/ips.c b/misc/ips.c index 7ea6c71b..467cc25d 100644 --- a/misc/ips.c +++ b/misc/ips.c @@ -23,7 +23,7 @@ int h[65536]; * = ((1-1/k)^k)^a which we can approximate by e^-a. */ -unsigned int hf(unsigned int n) +uint hf(uint n) { #if 0 n = (n ^ (n >> 16)) & 0xffff; @@ -58,7 +58,7 @@ main(int argc, char **argv) while (max--) { - unsigned int i, e; + uint i, e; if (scanf("%x/%d", &i, &e) != 2) if (feof(stdin)) break; diff --git a/nest/a-path.c b/nest/a-path.c index dc36e653..c9c5aefb 100644 --- a/nest/a-path.c +++ b/nest/a-path.c @@ -124,7 +124,7 @@ as_path_convert_to_new(struct adata *path, byte *dst, int req_as) } void -as_path_format(struct adata *path, byte *buf, unsigned int size) +as_path_format(struct adata *path, byte *buf, uint size) { byte *p = path->data; byte *e = p + path->length; diff --git a/nest/a-set.c b/nest/a-set.c index 42ef9b06..a6116022 100644 --- a/nest/a-set.c +++ b/nest/a-set.c @@ -32,7 +32,7 @@ * the buffer to indicate truncation. */ int -int_set_format(struct adata *set, int way, int from, byte *buf, unsigned int size) +int_set_format(struct adata *set, int way, int from, byte *buf, uint size) { u32 *z = (u32 *) set->data; byte *end = buf + size - 24; @@ -113,7 +113,7 @@ ec_format(byte *buf, u64 ec) } int -ec_set_format(struct adata *set, int from, byte *buf, unsigned int size) +ec_set_format(struct adata *set, int from, byte *buf, uint size) { u32 *z = int_set_get_data(set); byte *end = buf + size - 24; diff --git a/nest/attrs.h b/nest/attrs.h index b6e067cb..1d005a6a 100644 --- a/nest/attrs.h +++ b/nest/attrs.h @@ -30,7 +30,7 @@ struct f_tree; struct adata *as_path_prepend(struct linpool *pool, struct adata *olda, u32 as); int as_path_convert_to_old(struct adata *path, byte *dst, int *new_used); int as_path_convert_to_new(struct adata *path, byte *dst, int req_as); -void as_path_format(struct adata *path, byte *buf, unsigned int size); +void as_path_format(struct adata *path, byte *buf, uint size); int as_path_getlen(struct adata *path); int as_path_getlen_int(struct adata *path, int bs); int as_path_get_first(struct adata *path, u32 *orig_as); @@ -95,9 +95,9 @@ static inline u64 ec_ip4(u64 kind, u64 key, u64 val) static inline u64 ec_generic(u64 key, u64 val) { return (key << 32) | val; } -int int_set_format(struct adata *set, int way, int from, byte *buf, unsigned int size); +int int_set_format(struct adata *set, int way, int from, byte *buf, uint size); int ec_format(byte *buf, u64 ec); -int ec_set_format(struct adata *set, int from, byte *buf, unsigned int size); +int ec_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); struct adata *int_set_add(struct linpool *pool, struct adata *list, u32 val); diff --git a/nest/cli.c b/nest/cli.c index 11f98794..83e79616 100644 --- a/nest/cli.c +++ b/nest/cli.c @@ -163,7 +163,7 @@ static void cli_copy_message(cli *c) { byte *p, *q; - unsigned int cnt = 2; + uint cnt = 2; if (c->ring_overflow) { @@ -230,12 +230,12 @@ cli_written(cli *c) static byte *cli_rh_pos; -static unsigned int cli_rh_len; +static uint cli_rh_len; static int cli_rh_trick_flag; struct cli *this_cli; static int -cli_cmd_read_hook(byte *buf, unsigned int max, UNUSED int fd) +cli_cmd_read_hook(byte *buf, uint max, UNUSED int fd) { if (!cli_rh_trick_flag) { @@ -330,7 +330,7 @@ static list cli_log_hooks; static int cli_log_inited; void -cli_set_log_echo(cli *c, unsigned int mask, unsigned int size) +cli_set_log_echo(cli *c, uint mask, uint size) { if (c->ring_buf) { @@ -351,7 +351,7 @@ cli_set_log_echo(cli *c, unsigned int mask, unsigned int size) } void -cli_echo(unsigned int class, byte *msg) +cli_echo(uint class, byte *msg) { unsigned len, free, i, l; cli *c; diff --git a/nest/cli.h b/nest/cli.h index 396656e8..92f3c3d7 100644 --- a/nest/cli.h +++ b/nest/cli.h @@ -40,10 +40,10 @@ typedef struct cli { struct linpool *parser_pool; /* Pool used during parsing */ byte *ring_buf; /* Ring buffer for asynchronous messages */ byte *ring_end, *ring_read, *ring_write; /* Pointers to the ring buffer */ - unsigned int ring_overflow; /* Counter of ring overflows */ - unsigned int log_mask; /* Mask of allowed message levels */ - unsigned int log_threshold; /* When free < log_threshold, store only important messages */ - unsigned int async_msg_size; /* Total size of async messages queued in tx_buf */ + uint ring_overflow; /* Counter of ring overflows */ + uint log_mask; /* Mask of allowed message levels */ + uint log_threshold; /* When free < log_threshold, store only important messages */ + uint async_msg_size; /* Total size of async messages queued in tx_buf */ } cli; extern pool *cli_pool; @@ -55,7 +55,7 @@ extern struct cli *this_cli; /* Used during parsing */ void cli_printf(cli *, int, char *, ...); #define cli_msg(x...) cli_printf(this_cli, x) -void cli_set_log_echo(cli *, unsigned int mask, unsigned int size); +void cli_set_log_echo(cli *, uint mask, uint size); /* Functions provided to sysdep layer */ @@ -64,7 +64,7 @@ void cli_init(void); void cli_free(cli *); void cli_kick(cli *); void cli_written(cli *); -void cli_echo(unsigned int class, byte *msg); +void cli_echo(uint class, byte *msg); static inline int cli_access_restricted(void) { diff --git a/nest/neighbor.c b/nest/neighbor.c index 48b6b6ac..1685d67e 100644 --- a/nest/neighbor.c +++ b/nest/neighbor.c @@ -49,7 +49,7 @@ static slab *neigh_slab; static list sticky_neigh_list, neigh_hash_table[NEIGH_HASH_SIZE]; -static inline unsigned int +static inline uint neigh_hash(struct proto *p, ip_addr *a) { return (p->hash_key ^ ipa_hash(*a)) & (NEIGH_HASH_SIZE-1); @@ -126,7 +126,7 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags) { neighbor *n; int class, scope = -1; - unsigned int h = neigh_hash(p, a); + uint h = neigh_hash(p, a); struct iface *i; struct ifa *addr; diff --git a/nest/proto.c b/nest/proto.c index 44cfb637..6531083c 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -1488,7 +1488,7 @@ proto_show_basic_info(struct proto *p) } void -proto_cmd_show(struct proto *p, unsigned int verbose, int cnt) +proto_cmd_show(struct proto *p, uint verbose, int cnt) { byte buf[256], tbuf[TM_DATETIME_BUFFER_SIZE]; @@ -1524,7 +1524,7 @@ proto_cmd_show(struct proto *p, unsigned int verbose, int cnt) } void -proto_cmd_disable(struct proto *p, unsigned int arg UNUSED, int cnt UNUSED) +proto_cmd_disable(struct proto *p, uint arg UNUSED, int cnt UNUSED) { if (p->disabled) { @@ -1540,7 +1540,7 @@ proto_cmd_disable(struct proto *p, unsigned int arg UNUSED, int cnt UNUSED) } void -proto_cmd_enable(struct proto *p, unsigned int arg UNUSED, int cnt UNUSED) +proto_cmd_enable(struct proto *p, uint arg UNUSED, int cnt UNUSED) { if (!p->disabled) { @@ -1555,7 +1555,7 @@ proto_cmd_enable(struct proto *p, unsigned int arg UNUSED, int cnt UNUSED) } void -proto_cmd_restart(struct proto *p, unsigned int arg UNUSED, int cnt UNUSED) +proto_cmd_restart(struct proto *p, uint arg UNUSED, int cnt UNUSED) { if (p->disabled) { @@ -1573,7 +1573,7 @@ proto_cmd_restart(struct proto *p, unsigned int arg UNUSED, int cnt UNUSED) } void -proto_cmd_reload(struct proto *p, unsigned int dir, int cnt UNUSED) +proto_cmd_reload(struct proto *p, uint dir, int cnt UNUSED) { if (p->disabled) { @@ -1615,19 +1615,19 @@ proto_cmd_reload(struct proto *p, unsigned int dir, int cnt UNUSED) } void -proto_cmd_debug(struct proto *p, unsigned int mask, int cnt UNUSED) +proto_cmd_debug(struct proto *p, uint mask, int cnt UNUSED) { p->debug = mask; } void -proto_cmd_mrtdump(struct proto *p, unsigned int mask, int cnt UNUSED) +proto_cmd_mrtdump(struct proto *p, uint mask, int cnt UNUSED) { p->mrtdump = mask; } static void -proto_apply_cmd_symbol(struct symbol *s, void (* cmd)(struct proto *, unsigned int, int), unsigned int arg) +proto_apply_cmd_symbol(struct symbol *s, void (* cmd)(struct proto *, uint, int), uint arg) { if (s->class != SYM_PROTO) { @@ -1640,7 +1640,7 @@ proto_apply_cmd_symbol(struct symbol *s, void (* cmd)(struct proto *, unsigned i } static void -proto_apply_cmd_patt(char *patt, void (* cmd)(struct proto *, unsigned int, int), unsigned int arg) +proto_apply_cmd_patt(char *patt, void (* cmd)(struct proto *, uint, int), uint arg) { int cnt = 0; @@ -1660,8 +1660,8 @@ proto_apply_cmd_patt(char *patt, void (* cmd)(struct proto *, unsigned int, int) } void -proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, unsigned int, int), - int restricted, unsigned int arg) +proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, uint, int), + int restricted, uint arg) { if (restricted && cli_access_restricted()) return; diff --git a/nest/protocol.h b/nest/protocol.h index 8660cc2c..a51e9afd 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -261,15 +261,15 @@ void proto_graceful_restart_unlock(struct proto *p); void proto_show_limit(struct proto_limit *l, const char *dsc); void proto_show_basic_info(struct proto *p); -void proto_cmd_show(struct proto *, unsigned int, int); -void proto_cmd_disable(struct proto *, unsigned int, int); -void proto_cmd_enable(struct proto *, unsigned int, int); -void proto_cmd_restart(struct proto *, unsigned int, int); -void proto_cmd_reload(struct proto *, unsigned int, int); -void proto_cmd_debug(struct proto *, unsigned int, int); -void proto_cmd_mrtdump(struct proto *, unsigned int, int); +void proto_cmd_show(struct proto *, uint, int); +void proto_cmd_disable(struct proto *, uint, int); +void proto_cmd_enable(struct proto *, uint, int); +void proto_cmd_restart(struct proto *, uint, int); +void proto_cmd_reload(struct proto *, uint, int); +void proto_cmd_debug(struct proto *, uint, int); +void proto_cmd_mrtdump(struct proto *, uint, int); -void proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, unsigned int, int), int restricted, unsigned int arg); +void proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, uint, int), int restricted, uint arg); struct proto *proto_get_named(struct symbol *, struct protocol *); #define CMD_RELOAD 0 diff --git a/nest/route.h b/nest/route.h index 2e6bf741..8f3c7c9a 100644 --- a/nest/route.h +++ b/nest/route.h @@ -47,7 +47,7 @@ struct fib_iterator { /* See lib/slists.h for an explanation */ byte efef; /* 0xff to distinguish between iterator and node */ byte pad[3]; struct fib_node *node; /* Or NULL if freshly merged */ - unsigned int hash; + uint hash; }; typedef void (*fib_init_func)(struct fib_node *); @@ -56,11 +56,11 @@ struct fib { pool *fib_pool; /* Pool holding all our data */ slab *fib_slab; /* Slab holding all fib nodes */ struct fib_node **hash_table; /* Node hash table */ - unsigned int hash_size; /* Number of hash table entries (a power of two) */ - unsigned int hash_order; /* Binary logarithm of hash_size */ - unsigned int hash_shift; /* 16 - hash_log */ - unsigned int entries; /* Number of entries */ - unsigned int entries_min, entries_max;/* Entry count limits (else start rehashing) */ + uint hash_size; /* Number of hash table entries (a power of two) */ + uint hash_order; /* Binary logarithm of hash_size */ + uint hash_shift; /* 16 - hash_log */ + uint entries; /* Number of entries */ + uint entries_min, entries_max; /* Entry count limits (else start rehashing) */ fib_init_func init; /* Constructor */ }; @@ -78,7 +78,7 @@ void fit_put(struct fib_iterator *, struct fib_node *); #define FIB_WALK(fib, z) do { \ struct fib_node *z, **ff = (fib)->hash_table; \ - unsigned int count = (fib)->hash_size; \ + uint count = (fib)->hash_size; \ while (count--) \ for(z = *ff++; z; z=z->next) @@ -88,8 +88,8 @@ void fit_put(struct fib_iterator *, struct fib_node *); #define FIB_ITERATE_START(fib, it, z) do { \ struct fib_node *z = fit_get(fib, it); \ - unsigned int count = (fib)->hash_size; \ - unsigned int hpos = (it)->hash; \ + uint count = (fib)->hash_size; \ + uint hpos = (it)->hash; \ for(;;) { \ if (!z) \ { \ @@ -435,7 +435,7 @@ typedef struct eattr { #define EAF_TEMP 0x80 /* A temporary attribute (the one stored in the tmp attr list) */ struct adata { - unsigned int length; /* Length of data */ + uint length; /* Length of data */ byte data[0]; }; @@ -475,7 +475,7 @@ void ea_sort(ea_list *); /* Sort entries in all sub-lists */ unsigned ea_scan(ea_list *); /* How many bytes do we need for merged ea_list */ void ea_merge(ea_list *from, ea_list *to); /* Merge sub-lists to allocated buffer */ int ea_same(ea_list *x, ea_list *y); /* Test whether two ea_lists are identical */ -unsigned int ea_hash(ea_list *e); /* Calculate 16-bit hash value */ +uint ea_hash(ea_list *e); /* Calculate 16-bit hash value */ ea_list *ea_append(ea_list *to, ea_list *what); void ea_format_bitfield(struct eattr *a, byte *buf, int bufsize, const char **names, int min, int max); diff --git a/nest/rt-attr.c b/nest/rt-attr.c index c5537208..85a192c8 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -98,7 +98,7 @@ rte_src_init(void) HASH_INIT(src_hash, rta_pool, RSH_INIT_ORDER); } -static inline int u32_cto(unsigned int x) { return ffs(~x) - 1; } +static inline int u32_cto(uint x) { return ffs(~x) - 1; } static inline u32 rte_src_alloc_id(void) @@ -195,10 +195,10 @@ rt_prune_sources(void) * Multipath Next Hop */ -static inline unsigned int +static inline uint mpnh_hash(struct mpnh *x) { - unsigned int h = 0; + uint h = 0; for (; x; x = x->next) h ^= ipa_hash(x->gw); @@ -666,7 +666,7 @@ ea_format_bitfield(struct eattr *a, byte *buf, int bufsize, const char **names, } static inline void -opaque_format(struct adata *ad, byte *buf, unsigned int size) +opaque_format(struct adata *ad, byte *buf, uint size) { byte *bound = buf + size - 10; int i; @@ -838,7 +838,7 @@ ea_dump(ea_list *e) * ea_hash() takes an extended attribute list and calculated a hopefully * uniformly distributed hash value from its contents. */ -inline unsigned int +inline uint ea_hash(ea_list *e) { u32 h = 0; @@ -900,10 +900,10 @@ ea_append(ea_list *to, ea_list *what) * rta's */ -static unsigned int rta_cache_count; -static unsigned int rta_cache_size = 32; -static unsigned int rta_cache_limit; -static unsigned int rta_cache_mask; +static uint rta_cache_count; +static uint rta_cache_size = 32; +static uint rta_cache_limit; +static uint rta_cache_mask; static rta **rta_hash_table; static void @@ -917,7 +917,7 @@ rta_alloc_hash(void) rta_cache_mask = rta_cache_size - 1; } -static inline unsigned int +static inline uint rta_hash(rta *a) { return (((uint) (uintptr_t) a->src) ^ ipa_hash(a->gw) ^ @@ -957,7 +957,7 @@ rta_copy(rta *o) static inline void rta_insert(rta *r) { - unsigned int h = r->hash_key & rta_cache_mask; + uint h = r->hash_key & rta_cache_mask; r->next = rta_hash_table[h]; if (r->next) r->next->pprev = &r->next; @@ -968,8 +968,8 @@ rta_insert(rta *r) static void rta_rehash(void) { - unsigned int ohs = rta_cache_size; - unsigned int h; + uint ohs = rta_cache_size; + uint h; rta *r, *n; rta **oht = rta_hash_table; @@ -1002,7 +1002,7 @@ rta * rta_lookup(rta *o) { rta *r; - unsigned int h; + uint h; ASSERT(!(o->aflags & RTAF_CACHED)); if (o->eattrs) @@ -1093,7 +1093,7 @@ void rta_dump_all(void) { rta *a; - unsigned int h; + uint h; debug("Route attribute cache (%d entries, rehash at %d):\n", rta_cache_count, rta_cache_limit); for(h=0; hhash_table + (h >> f->hash_shift); struct fib_node *g, *e = *ee; u32 uid = h << 16; @@ -321,7 +321,7 @@ void fib_delete(struct fib *f, void *E) { struct fib_node *e = E; - unsigned int h = fib_hash(f, &e->prefix); + uint h = fib_hash(f, &e->prefix); struct fib_node **ee = f->hash_table + h; struct fib_iterator *it; @@ -442,7 +442,7 @@ fit_put(struct fib_iterator *i, struct fib_node *n) void fib_check(struct fib *f) { - unsigned int i, ec, lo, nulls; + uint i, ec, lo, nulls; ec = 0; for(i=0; ihash_size; i++) @@ -452,7 +452,7 @@ fib_check(struct fib *f) for(n=f->hash_table[i]; n; n=n->next) { struct fib_iterator *j, *j0; - unsigned int h0 = ipa_hash(n->prefix); + uint h0 = ipa_hash(n->prefix); if (h0 < lo) bug("fib_check: discord in hash chains"); lo = h0; @@ -489,7 +489,7 @@ struct fib f; void dump(char *m) { - unsigned int i; + uint i; debug("%s ... order=%d, size=%d, entries=%d\n", m, f.hash_order, f.hash_size, f.hash_size); for(i=0; idebug & flag) rte_trace(p, e, '>', msg); } static inline void -rte_trace_out(unsigned int flag, struct proto *p, rte *e, char *msg) +rte_trace_out(uint flag, struct proto *p, rte *e, char *msg) { if (p->debug & flag) rte_trace(p, e, '<', msg); @@ -1880,7 +1880,7 @@ hc_hash(ip_addr a, rtable *dep) static inline void hc_insert(struct hostcache *hc, struct hostentry *he) { - unsigned int k = he->hash_key >> hc->hash_shift; + uint k = he->hash_key >> hc->hash_shift; he->next = hc->hash_table[k]; hc->hash_table[k] = he; } @@ -1889,7 +1889,7 @@ static inline void hc_remove(struct hostcache *hc, struct hostentry *he) { struct hostentry **hep; - unsigned int k = he->hash_key >> hc->hash_shift; + uint k = he->hash_key >> hc->hash_shift; for (hep = &hc->hash_table[k]; *hep != he; hep = &(*hep)->next); *hep = he->next; @@ -2154,7 +2154,7 @@ rt_get_hostentry(rtable *tab, ip_addr a, ip_addr ll, rtable *dep) if (!tab->hostcache) rt_init_hostcache(tab); - unsigned int k = hc_hash(a, dep); + uint k = hc_hash(a, dep); struct hostcache *hc = tab->hostcache; for (he = hc->hash_table[k >> hc->hash_shift]; he != NULL; he = he->next) if (ipa_equal(he->addr, a) && (he->tab == dep)) diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 72b45d47..d56c017d 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -114,7 +114,7 @@ path_segment_contains(byte *p, int bs, u32 asn) /* Validates path attribute, removes AS_CONFED_* segments, and also returns path length */ static int -validate_path(struct bgp_proto *p, int as_path, int bs, byte *idata, unsigned int *ilength) +validate_path(struct bgp_proto *p, int as_path, int bs, byte *idata, uint *ilength) { int res = 0; u8 *a, *dst; @@ -381,7 +381,7 @@ bgp_attach_attr_wa(ea_list **to, struct linpool *pool, unsigned attr, unsigned l } static int -bgp_encode_attr_hdr(byte *dst, unsigned int flags, unsigned code, int len) +bgp_encode_attr_hdr(byte *dst, uint flags, unsigned code, int len) { int wlen; @@ -473,10 +473,10 @@ bgp_get_attr_len(eattr *a) * * Result: Length of the attribute block generated or -1 if not enough space. */ -unsigned int +uint bgp_encode_attrs(struct bgp_proto *p, byte *w, ea_list *attrs, int remains) { - unsigned int i, code, type, flags; + uint i, code, type, flags; byte *start = w; int len, rv; @@ -1593,11 +1593,11 @@ bgp_remove_as4_attrs(struct bgp_proto *p, rta *a) * by a &rta. */ struct rta * -bgp_decode_attrs(struct bgp_conn *conn, byte *attr, unsigned int len, struct linpool *pool, int mandatory) +bgp_decode_attrs(struct bgp_conn *conn, byte *attr, uint len, struct linpool *pool, int mandatory) { struct bgp_proto *bgp = conn->bgp; rta *a = lp_alloc(pool, sizeof(struct rta)); - unsigned int flags, code, l, i, type; + uint flags, code, l, i, type; int errcode; byte *z, *attr_start; byte seen[256/8]; @@ -1791,7 +1791,7 @@ err: int bgp_get_attr(eattr *a, byte *buf, int buflen) { - unsigned int i = EA_ID(a->id); + uint i = EA_ID(a->id); struct attr_desc *d; int len; diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index f4f21226..446fc857 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -90,7 +90,7 @@ struct bgp_config { struct bgp_conn { struct bgp_proto *bgp; struct birdsock *sk; - unsigned int state; /* State of connection state machine */ + uint state; /* State of connection state machine */ struct timer *connect_retry_timer; struct timer *hold_timer; struct timer *keepalive_timer; @@ -142,7 +142,7 @@ struct bgp_proto { struct timer *startup_timer; /* Timer used to delay protocol startup due to previous errors (startup_delay) */ struct timer *gr_timer; /* Timer waiting for reestablishment after graceful restart */ struct bgp_bucket **bucket_hash; /* Hash table of attribute buckets */ - unsigned int hash_size, hash_count, hash_limit; + uint hash_size, hash_count, hash_limit; HASH(struct bgp_prefix) prefix_hash; /* Prefixes to be sent */ slab *prefix_slab; /* Slab holding prefix nodes */ list bucket_queue; /* Queue of buckets to send */ @@ -235,7 +235,7 @@ static inline void set_next_hop(byte *b, ip_addr addr) { ((ip_addr *) b)[0] = ad void bgp_attach_attr(struct ea_list **to, struct linpool *pool, unsigned attr, uintptr_t val); byte *bgp_attach_attr_wa(struct ea_list **to, struct linpool *pool, unsigned attr, unsigned len); -struct rta *bgp_decode_attrs(struct bgp_conn *conn, byte *a, unsigned int len, struct linpool *pool, int mandatory); +struct rta *bgp_decode_attrs(struct bgp_conn *conn, byte *a, uint len, struct linpool *pool, int mandatory); int bgp_get_attr(struct eattr *e, byte *buf, int buflen); int bgp_rte_better(struct rte *, struct rte *); int bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best); @@ -245,7 +245,7 @@ void bgp_init_bucket_table(struct bgp_proto *); 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(struct bgp_proto *p, struct bgp_prefix *bp); -unsigned int bgp_encode_attrs(struct bgp_proto *p, byte *w, ea_list *attrs, int remains); +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); inline static void bgp_attach_attr_ip(struct ea_list **to, struct linpool *pool, unsigned attr, ip_addr a) diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 4bd68f52..378f5ab1 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -289,8 +289,8 @@ bgp_create_open(struct bgp_conn *conn, byte *buf) } } -static unsigned int -bgp_encode_prefixes(struct bgp_proto *p, byte *w, struct bgp_bucket *buck, unsigned int remains) +static uint +bgp_encode_prefixes(struct bgp_proto *p, byte *w, struct bgp_bucket *buck, uint remains) { byte *start = w; ip_addr a; @@ -648,7 +648,7 @@ bgp_create_end_refresh(struct bgp_conn *conn, byte *buf) static void -bgp_create_header(byte *buf, unsigned int len, unsigned int type) +bgp_create_header(byte *buf, uint len, uint type) { memset(buf, 0xff, 16); /* Marker */ put_u16(buf+16, len); @@ -669,7 +669,7 @@ static int bgp_fire_tx(struct bgp_conn *conn) { struct bgp_proto *p = conn->bgp; - unsigned int s = conn->packets_to_send; + uint s = conn->packets_to_send; sock *sk = conn->sk; byte *buf, *pkt, *end; int type; diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c index aaf3b23c..064bae18 100644 --- a/sysdep/bsd/krt-sock.c +++ b/sysdep/bsd/krt-sock.c @@ -181,7 +181,7 @@ struct ks_msg #define GETADDR(p, F) \ bzero(p, sizeof(*p));\ if ((addrs & (F)) && ((struct sockaddr *)body)->sa_len) {\ - unsigned int l = ROUNDUP(((struct sockaddr *)body)->sa_len);\ + uint l = ROUNDUP(((struct sockaddr *)body)->sa_len);\ memcpy(p, body, (l > sizeof(*p) ? sizeof(*p) : l));\ body += l;} @@ -537,7 +537,7 @@ krt_read_ifinfo(struct ks_msg *msg, int scan) struct if_msghdr *ifm = (struct if_msghdr *)&msg->rtm; void *body = (void *)(ifm + 1); struct sockaddr_dl *dl = NULL; - unsigned int i; + uint i; struct iface *iface = NULL, f = {}; int fl = ifm->ifm_flags; int nlen = 0; diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index 71f58554..c4d52255 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -50,7 +50,7 @@ struct nl_sock u32 seq; byte *rx_buffer; /* Receive buffer */ struct nlmsghdr *last_hdr; /* Recently received packet */ - unsigned int last_size; + uint last_size; }; #define NL_RX_SIZE 8192 @@ -443,7 +443,7 @@ nl_parse_link(struct nlmsghdr *h, int scan) struct iface *ifi; char *name; u32 mtu; - unsigned int fl; + uint fl; if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(IFLA_RTA(i), a, sizeof(a))) return; @@ -1088,7 +1088,7 @@ nl_async_hook(sock *sk, int size UNUSED) struct msghdr m = { (struct sockaddr *) &sa, sizeof(sa), &iov, 1, NULL, 0, 0 }; struct nlmsghdr *h; int x; - unsigned int len; + uint len; x = recvmsg(sk->fd, &m, 0); if (x < 0) diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c index 05f7560d..e31471da 100644 --- a/sysdep/unix/main.c +++ b/sysdep/unix/main.c @@ -155,7 +155,7 @@ read_iproute_table(char *file, char *prefix, int max) static char *config_name = PATH_CONFIG_FILE; static int -cf_read(byte *dest, unsigned int len, int fd) +cf_read(byte *dest, uint len, int fd) { int l = read(fd, dest, len); if (l < 0) diff --git a/sysdep/unix/unix.h b/sysdep/unix/unix.h index 593978cc..4e0ff841 100644 --- a/sysdep/unix/unix.h +++ b/sysdep/unix/unix.h @@ -119,7 +119,7 @@ void log_switch(int debug, list *l, char *); /* Use l=NULL for initial switch */ struct log_config { node n; - unsigned int mask; /* Classes to log */ + uint mask; /* Classes to log */ void *fh; /* FILE to log to, NULL=syslog */ int terminal_flag; }; From ca34698ca62d979c281ed517f040619e31c3ada3 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sun, 31 May 2015 11:29:53 +0200 Subject: [PATCH 05/28] Fixes bug in pipe feeding when filtered routes are kept in table --- nest/rt-table.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/nest/rt-table.c b/nest/rt-table.c index d5af41c7..27c6cb76 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -1816,15 +1816,20 @@ again: { if (p->export_state != ES_FEEDING) return 1; /* In the meantime, the protocol fell down. */ + do_feed_baby(p, p->accept_ra_types, h, n, e); max_feed--; } if (p->accept_ra_types == RA_ANY) - for(e = n->routes; rte_is_valid(e); e = e->next) + for(e = n->routes; e; e = e->next) { if (p->export_state != ES_FEEDING) return 1; /* In the meantime, the protocol fell down. */ + + if (!rte_is_valid(e)) + continue; + do_feed_baby(p, RA_ANY, h, n, e); max_feed--; } From d217ba5111a80a629e408961b902d7759c4b46f5 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sun, 31 May 2015 23:25:33 +0200 Subject: [PATCH 06/28] Moving of mulipath merging code from OSPF to nest --- nest/route.h | 1 + nest/rt-attr.c | 94 ++++++++++++++++++++++++++++++++++++-- proto/ospf/rt.c | 104 ++++++------------------------------------ proto/ospf/rt.h | 3 +- proto/ospf/topology.h | 2 +- 5 files changed, 110 insertions(+), 94 deletions(-) diff --git a/nest/route.h b/nest/route.h index 8f3c7c9a..e22f950b 100644 --- a/nest/route.h +++ b/nest/route.h @@ -482,6 +482,7 @@ void ea_format_bitfield(struct eattr *a, byte *buf, int bufsize, const char **na int mpnh__same(struct mpnh *x, struct mpnh *y); /* Compare multipath nexthops */ static inline int mpnh_same(struct mpnh *x, struct mpnh *y) { return (x == y) || mpnh__same(x, y); } +struct mpnh *mpnh_merge(struct mpnh *x, struct mpnh *y, int rx, int ry, int max, linpool *lp); void rta_init(void); rta *rta_lookup(rta *); /* Get rta equivalent to this one, uc++ */ diff --git a/nest/rt-attr.c b/nest/rt-attr.c index 85a192c8..32090b52 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -167,7 +167,7 @@ rt_get_source(struct proto *p, u32 id) src->private_id = id; src->global_id = rte_src_alloc_id(); src->uc = 0; - + HASH_INSERT2(src_hash, RSH, rta_pool, src); return src; @@ -215,6 +215,94 @@ mpnh__same(struct mpnh *x, struct mpnh *y) return x == y; } +static int +mpnh_compare_node(struct mpnh *x, struct mpnh *y) +{ + int r; + + if (!x) + return 1; + + if (!y) + return -1; + + r = ((int) y->weight) - ((int) x->weight); + if (r) + return r; + + r = ipa_compare(x->gw, y->gw); + if (r) + return r; + + return ((int) x->iface->index) - ((int) y->iface->index); +} + +static inline struct mpnh * +mpnh_copy_node(const struct mpnh *src, linpool *lp) +{ + struct mpnh *n = lp_alloc(lp, sizeof(struct mpnh)); + n->gw = src->gw; + n->iface = src->iface; + n->next = NULL; + n->weight = src->weight; + return n; +} + +/** + * mpnh_merge - merge nexthop lists + * @x: list 1 + * @y: list 2 + * @rx: reusability of list @x + * @ry: reusability of list @y + * @max: max number of nexthops + * @lp: linpool for allocating nexthops + * + * The mpnh_merge() function takes two nexthop lists @x and @y and merges them, + * eliminating possible duplicates. The input lists must be sorted and the + * result is sorted too. The number of nexthops in result is limited by @max. + * New nodes are allocated from linpool @lp. + * + * The arguments @rx and @ry specify whether corresponding input lists may be + * consumed by the function (i.e. their nodes reused in the resulting list), in + * that case the caller should not access these lists after that. To eliminate + * issues with deallocation of these lists, the caller should use some form of + * bulk deallocation (e.g. stack or linpool) to free these nodes when the + * resulting list is no longer needed. When reusability is not set, the + * corresponding lists are not modified nor linked from the resulting list. + */ +struct mpnh * +mpnh_merge(struct mpnh *x, struct mpnh *y, int rx, int ry, int max, linpool *lp) +{ + struct mpnh *root = NULL; + struct mpnh **n = &root; + + while ((x || y) && max--) + { + int cmp = mpnh_compare_node(x, y); + if (cmp < 0) + { + *n = rx ? x : mpnh_copy_node(x, lp); + x = x->next; + } + else if (cmp > 0) + { + *n = ry ? y : mpnh_copy_node(y, lp); + y = y->next; + } + else + { + *n = rx ? x : (ry ? y : mpnh_copy_node(x, lp)); + x = x->next; + y = y->next; + } + n = &((*n)->next); + } + *n = NULL; + + return root; +} + + static struct mpnh * mpnh_copy(struct mpnh *o) { @@ -635,7 +723,7 @@ get_generic_attr(eattr *a, byte **buf, int buflen UNUSED) *buf += bsprintf(*buf, "igp_metric"); return GA_NAME; } - + return GA_UNKNOWN; } @@ -741,7 +829,7 @@ ea_show(struct cli *c, eattr *e) } else if (EA_PROTO(e->id)) pos += bsprintf(pos, "%02x.", EA_PROTO(e->id)); - else + else status = get_generic_attr(e, &pos, end - pos); if (status < GA_NAME) diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index e74bcae6..cdf8012a 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -53,88 +53,6 @@ new_nexthop(struct ospf_proto *p, ip_addr gw, struct iface *iface, byte weight) return nh; } -static inline struct mpnh * -copy_nexthop(struct ospf_proto *p, const struct mpnh *src) -{ - struct mpnh *nh = lp_alloc(p->nhpool, sizeof(struct mpnh)); - nh->gw = src->gw; - nh->iface = src->iface; - nh->next = NULL; - nh->weight = src->weight; - return nh; -} - -/* Compare nexthops during merge. - We need to maintain nhs sorted to eliminate duplicities */ -static int -cmp_nhs(struct mpnh *s1, struct mpnh *s2) -{ - int r; - - if (!s1) - return 1; - - if (!s2) - return -1; - - r = ((int) s2->weight) - ((int) s1->weight); - if (r) - return r; - - r = ipa_compare(s1->gw, s2->gw); - if (r) - return r; - - return ((int) s1->iface->index) - ((int) s2->iface->index); -} - -static struct mpnh * -merge_nexthops(struct ospf_proto *p, struct mpnh *s1, struct mpnh *s2, int r1, int r2) -{ - struct mpnh *root = NULL; - struct mpnh **n = &root; - int count = p->ecmp; - - ASSERT(p->ecmp); - - /* - * r1, r2 signalize whether we can reuse nexthops from s1, s2. - * New nexthops (s2, new) can be reused if they are not inherited - * from the parent (i.e. it is allocated in calc_next_hop()). - * Current nexthops (s1, en->nhs) can be reused if they weren't - * inherited in previous steps (that is stored in nhs_reuse, - * i.e. created by merging or allocalted in calc_next_hop()). - * - * Generally, a node first inherits shared nexthops from its - * parent and later possibly gets reusable copy during merging. - */ - - while ((s1 || s2) && count--) - { - int cmp = cmp_nhs(s1, s2); - if (cmp < 0) - { - *n = r1 ? s1 : copy_nexthop(p, s1); - s1 = s1->next; - } - else if (cmp > 0) - { - *n = r2 ? s2 : copy_nexthop(p, s2); - s2 = s2->next; - } - else - { - *n = r1 ? s1 : (r2 ? s2 : copy_nexthop(p, s1)); - s1 = s1->next; - s2 = s2->next; - } - n = &((*n)->next); - } - *n = NULL; - - return root; -} - /* Returns true if there are device nexthops in n */ static inline int has_device_nexthops(const struct mpnh *n) @@ -178,7 +96,7 @@ fix_device_nexthops(struct ospf_proto *p, const struct mpnh *n, ip_addr gw) } } - return merge_nexthops(p, root1, root2, 1, 1); + return mpnh_merge(root1, root2, 1, 1, p->ecmp, p->nhpool); } @@ -374,7 +292,8 @@ ort_merge(struct ospf_proto *p, ort *o, const orta *new) if (old->nhs != new->nhs) { - old->nhs = merge_nexthops(p, old->nhs, new->nhs, old->nhs_reuse, new->nhs_reuse); + old->nhs = mpnh_merge(old->nhs, new->nhs, old->nhs_reuse, new->nhs_reuse, + p->ecmp, p->nhpool); old->nhs_reuse = 1; } @@ -389,7 +308,8 @@ ort_merge_ext(struct ospf_proto *p, ort *o, const orta *new) if (old->nhs != new->nhs) { - old->nhs = merge_nexthops(p, old->nhs, new->nhs, old->nhs_reuse, new->nhs_reuse); + old->nhs = mpnh_merge(old->nhs, new->nhs, old->nhs_reuse, new->nhs_reuse, + p->ecmp, p->nhpool); old->nhs_reuse = 1; } @@ -1885,8 +1805,7 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par, return; } - /* We know that en->color == CANDIDATE and en->nhs is defined. */ - + /* If en->dist > 0, we know that en->color == CANDIDATE and en->nhs is defined. */ if ((dist == en->dist) && !nh_is_vlink(en->nhs)) { /* @@ -1900,7 +1819,14 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par, * allocated in calc_next_hop()). * * Generally, a node first inherits shared nexthops from its parent and - * later possibly gets reusable copy during merging. + * later possibly gets reusable (private) copy during merging. This is more + * or less same for both top_hash_entry nodes and orta nodes. + * + * Note that when a child inherits a private nexthop from its parent, it + * should make the nexthop shared for both parent and child, while we only + * update nhs_reuse for the child node. This makes nhs_reuse field for the + * parent technically incorrect, but it is not a problem as parent's nhs + * will not be modified (and nhs_reuse examined) afterwards. */ /* Keep old ones */ @@ -1909,7 +1835,7 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par, /* Merge old and new */ int new_reuse = (par->nhs != nhs); - en->nhs = merge_nexthops(p, en->nhs, nhs, en->nhs_reuse, new_reuse); + en->nhs = mpnh_merge(en->nhs, nhs, en->nhs_reuse, new_reuse, p->ecmp, p->nhpool); en->nhs_reuse = 1; return; } diff --git a/proto/ospf/rt.h b/proto/ospf/rt.h index 61936f3c..30332f3b 100644 --- a/proto/ospf/rt.h +++ b/proto/ospf/rt.h @@ -18,7 +18,8 @@ typedef struct orta { u8 type; /* RTS_OSPF_* */ - u8 nhs_reuse; /* Whether nhs nodes can be reused during merging */ + u8 nhs_reuse; /* Whether nhs nodes can be reused during merging. + See a note in rt.c:add_cand() */ u32 options; /* * For ORT_ROUTER routes, options field are router-LSA style diff --git a/proto/ospf/topology.h b/proto/ospf/topology.h index e2d6c773..5652ced0 100644 --- a/proto/ospf/topology.h +++ b/proto/ospf/topology.h @@ -39,7 +39,7 @@ struct top_hash_entry #define INSPF 2 u8 mode; /* LSA generated during RT calculation (LSA_RTCALC or LSA_STALE)*/ u8 nhs_reuse; /* Whether nhs nodes can be reused during merging. - See a note in rt.c:merge_nexthops() */ + See a note in rt.c:add_cand() */ }; From 78a2cc289fbe11d5b5783220e2cc61d119a78ec3 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Wed, 3 Jun 2015 11:58:46 +0200 Subject: [PATCH 07/28] KRT: Fixes some minor bugs in kernel protocol --- sysdep/linux/netlink.c | 5 ++ sysdep/unix/krt.c | 107 +++++++++++++++++++++++++---------------- 2 files changed, 71 insertions(+), 41 deletions(-) diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index c4d52255..9f206e1c 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -703,6 +703,11 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int new) r.r.rtm_scope = RT_SCOPE_UNIVERSE; nl_add_attr_ipa(&r.h, sizeof(r), RTA_DST, net->n.prefix); + /* For route delete, we do not specify route attributes */ + if (!new) + return nl_exchange(&r.h); + + if (ea = ea_find(eattrs, EA_KRT_METRIC)) nl_add_attr_u32(&r.h, sizeof(r), RTA_PRIORITY, ea->u.data); diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index cfb623ce..d8d28c7c 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -592,6 +592,44 @@ krt_flush_routes(struct krt_proto *p) FIB_WALK_END; } +static struct rte * +krt_export_net(struct krt_proto *p, net *net, rte **rt_free, ea_list **tmpa) +{ + struct filter *filter = p->p.main_ahook->out_filter; + rte *rt; + + rt = net->routes; + *rt_free = NULL; + + if (!rte_is_valid(rt)) + return NULL; + + if (filter == FILTER_REJECT) + return NULL; + + struct proto *src = rt->attrs->src->proto; + *tmpa = src->make_tmp_attrs ? src->make_tmp_attrs(rt, krt_filter_lp) : NULL; + + /* We could run krt_import_control() here, but it is already handled by KRF_INSTALLED */ + + if (filter == FILTER_ACCEPT) + goto accept; + + if (f_run(filter, &rt, tmpa, krt_filter_lp, FF_FORCE_TMPATTR) > F_ACCEPT) + goto reject; + + +accept: + if (rt != net->routes) + *rt_free = rt; + return rt; + +reject: + if (rt != net->routes) + rte_free(rt); + return NULL; +} + static int krt_same_dest(rte *k, rte *e) { @@ -620,7 +658,6 @@ krt_same_dest(rte *k, rte *e) void krt_got_route(struct krt_proto *p, rte *e) { - rte *old; net *net = e->net; int verdict; @@ -663,15 +700,26 @@ krt_got_route(struct krt_proto *p, rte *e) goto sentenced; } - old = net->routes; - if ((net->n.flags & KRF_INSTALLED) && rte_is_valid(old)) + if (net->n.flags & KRF_INSTALLED) { - /* There may be changes in route attributes, we ignore that. - Also, this does not work well if gw is changed in export filter */ - if ((net->n.flags & KRF_SYNC_ERROR) || ! krt_same_dest(e, old)) + rte *new, *rt_free; + ea_list *tmpa; + + new = krt_export_net(p, net, &rt_free, &tmpa); + + /* TODO: There also may be changes in route eattrs, we ignore that for now. */ + + if (!new) + verdict = KRF_DELETE; + else if ((net->n.flags & KRF_SYNC_ERROR) || !krt_same_dest(e, new)) verdict = KRF_UPDATE; else verdict = KRF_SEEN; + + if (rt_free) + rte_free(rt_free); + + lp_flush(krt_filter_lp); } else verdict = KRF_DELETE; @@ -692,25 +740,6 @@ krt_got_route(struct krt_proto *p, rte *e) rte_free(e); } -static inline int -krt_export_rte(struct krt_proto *p, rte **new, ea_list **tmpa) -{ - struct filter *filter = p->p.main_ahook->out_filter; - - if (! *new) - return 0; - - if (filter == FILTER_REJECT) - return 0; - - if (filter == FILTER_ACCEPT) - return 1; - - struct proto *src = (*new)->attrs->src->proto; - *tmpa = src->make_tmp_attrs ? src->make_tmp_attrs(*new, krt_filter_lp) : NULL; - return f_run(filter, new, tmpa, krt_filter_lp, FF_FORCE_TMPATTR) <= F_ACCEPT; -} - static void krt_prune(struct krt_proto *p) { @@ -721,7 +750,7 @@ krt_prune(struct krt_proto *p) { net *n = (net *) f; int verdict = f->flags & KRF_VERDICT_MASK; - rte *new, *new0, *old; + rte *new, *old, *rt_free = NULL; ea_list *tmpa = NULL; if (verdict == KRF_UPDATE || verdict == KRF_DELETE) @@ -733,23 +762,18 @@ krt_prune(struct krt_proto *p) else old = NULL; - new = new0 = n->routes; if (verdict == KRF_CREATE || verdict == KRF_UPDATE) { /* We have to run export filter to get proper 'new' route */ - if (! krt_export_rte(p, &new, &tmpa)) - { - /* Route rejected, should not happen (KRF_INSTALLED) but to be sure .. */ - verdict = (verdict == KRF_CREATE) ? KRF_IGNORE : KRF_DELETE; - } + new = krt_export_net(p, n, &rt_free, &tmpa); + + if (!new) + verdict = (verdict == KRF_CREATE) ? KRF_IGNORE : KRF_DELETE; else - { - ea_list **x = &tmpa; - while (*x) - x = &((*x)->next); - *x = new ? new->attrs->eattrs : NULL; - } + tmpa = ea_append(tmpa, new->attrs->eattrs); } + else + new = NULL; switch (verdict) { @@ -778,8 +802,8 @@ krt_prune(struct krt_proto *p) if (old) rte_free(old); - if (new != new0) - rte_free(new); + if (rt_free) + rte_free(rt_free); lp_flush(krt_filter_lp); f->flags &= ~KRF_VERDICT_MASK; } @@ -974,7 +998,8 @@ krt_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool * * We will remove KRT_INSTALLED flag, which stops such withdraw to be * processed in krt_rt_notify() and krt_replace_rte(). */ - e->net->n.flags &= ~KRF_INSTALLED; + if (e == e->net->routes) + e->net->n.flags &= ~KRF_INSTALLED; #endif return -1; } From db027a41d47b8fc52b65067ccabe2024554e53ca Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Thu, 4 Jun 2015 11:35:26 +0200 Subject: [PATCH 08/28] Fixes subtle bug in temporary attribute handling In some cases, export filter accessed attributes of a different route. --- nest/rt-table.c | 49 ++++++++++++++++++++----------------------------- 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/nest/rt-table.c b/nest/rt-table.c index 27c6cb76..22e1c489 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -208,12 +208,10 @@ export_filter(struct announce_hook *ah, rte *rt0, rte **rt_free, ea_list **tmpa, rt = rt0; *rt_free = NULL; - /* If called does not care for eattrs, we prepare one internally */ if (!tmpa) - { - tmpb = make_tmp_attrs(rt, rte_update_pool); - tmpa = &tmpb; - } + tmpa = &tmpb; + + *tmpa = make_tmp_attrs(rt, rte_update_pool); v = p->import_control ? p->import_control(p, &rt, tmpa, rte_update_pool) : 0; if (v < 0) @@ -347,7 +345,7 @@ do_rt_notify(struct announce_hook *ah, net *net, rte *new, rte *old, ea_list *tm } static void -rt_notify_basic(struct announce_hook *ah, net *net, rte *new0, rte *old0, ea_list *tmpa, int refeed) +rt_notify_basic(struct announce_hook *ah, net *net, rte *new0, rte *old0, int refeed) { struct proto *p = ah->proto; struct proto_stats *stats = ah->stats; @@ -356,6 +354,7 @@ rt_notify_basic(struct announce_hook *ah, net *net, rte *new0, rte *old0, ea_lis rte *old = old0; rte *new_free = NULL; rte *old_free = NULL; + ea_list *tmpa = NULL; if (new) stats->exp_updates_received++; @@ -419,17 +418,17 @@ rt_notify_basic(struct announce_hook *ah, net *net, rte *new0, rte *old0, ea_lis } static void -rt_notify_accepted(struct announce_hook *ah, net *net, rte *new_changed, rte *old_changed, rte *before_old, - ea_list *tmpa, int feed) +rt_notify_accepted(struct announce_hook *ah, net *net, rte *new_changed, rte *old_changed, rte *before_old, int feed) { // struct proto *p = ah->proto; struct proto_stats *stats = ah->stats; + rte *r; rte *new_best = NULL; rte *old_best = NULL; rte *new_free = NULL; rte *old_free = NULL; - rte *r; + ea_list *tmpa = NULL; /* Used to track whether we met old_changed position. If before_old is NULL old_changed was the first and we met it implicitly before current best route. */ @@ -543,7 +542,6 @@ rt_notify_accepted(struct announce_hook *ah, net *net, rte *new_changed, rte *ol * @net: network in question * @new: the new route to be announced * @old: the previous route for the same network - * @tmpa: a list of temporary attributes belonging to the new route * * This function gets a routing table update and announces it * to all protocols that acccepts given type of route announcement @@ -566,7 +564,7 @@ rt_notify_accepted(struct announce_hook *ah, net *net, rte *new_changed, rte *ol * the protocol gets called. */ static void -rte_announce(rtable *tab, unsigned type, net *net, rte *new, rte *old, rte *before_old, ea_list *tmpa) +rte_announce(rtable *tab, unsigned type, net *net, rte *new, rte *old, rte *before_old) { if (!rte_is_valid(old)) old = before_old = NULL; @@ -594,9 +592,9 @@ rte_announce(rtable *tab, unsigned type, net *net, rte *new, rte *old, rte *befo ASSERT(a->proto->export_state != ES_DOWN); if (a->proto->accept_ra_types == type) if (type == RA_ACCEPTED) - rt_notify_accepted(a, net, new, old, before_old, tmpa, 0); + rt_notify_accepted(a, net, new, old, before_old, 0); else - rt_notify_basic(a, net, new, old, tmpa, 0); + rt_notify_basic(a, net, new, old, 0); } } @@ -659,7 +657,7 @@ rte_same(rte *x, rte *y) static inline int rte_is_ok(rte *e) { return e && !rte_is_filtered(e); } static void -rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, struct rte_src *src) +rte_recalculate(struct announce_hook *ah, net *net, rte *new, struct rte_src *src) { struct proto *p = ah->proto; struct rtable *table = ah->table; @@ -900,11 +898,11 @@ rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, str } /* Propagate the route change */ - rte_announce(table, RA_ANY, net, new, old, NULL, tmpa); + rte_announce(table, RA_ANY, net, new, old, NULL); if (net->routes != old_best) - rte_announce(table, RA_OPTIMAL, net, net->routes, old_best, NULL, tmpa); + rte_announce(table, RA_OPTIMAL, net, net->routes, old_best, NULL); if (table->config->sorted) - rte_announce(table, RA_ACCEPTED, net, new, old, before_old, tmpa); + rte_announce(table, RA_ACCEPTED, net, new, old, before_old); if (!net->routes && (table->gc_counter++ >= table->config->gc_max_ops) && @@ -1069,7 +1067,7 @@ rte_update2(struct announce_hook *ah, net *net, rte *new, struct rte_src *src) recalc: rte_hide_dummy_routes(net, &dummy); - rte_recalculate(ah, net, new, tmpa, src); + rte_recalculate(ah, net, new, src); rte_unhide_dummy_routes(net, &dummy); rte_update_unlock(); return; @@ -1077,7 +1075,6 @@ rte_update2(struct announce_hook *ah, net *net, rte *new, struct rte_src *src) drop: rte_free(new); new = NULL; - tmpa = NULL; goto recalc; } @@ -1086,11 +1083,8 @@ rte_update2(struct announce_hook *ah, net *net, rte *new, struct rte_src *src) static inline void rte_announce_i(rtable *tab, unsigned type, net *n, rte *new, rte *old) { - ea_list *tmpa; - rte_update_lock(); - tmpa = make_tmp_attrs(new, rte_update_pool); - rte_announce(tab, type, n, new, old, NULL, tmpa); + rte_announce(tab, type, n, new, old, NULL); rte_update_unlock(); } @@ -1098,7 +1092,7 @@ void rte_discard(rtable *t, rte *old) /* Non-filtered route deletion, used during garbage collection */ { rte_update_lock(); - rte_recalculate(old->sender, old->net, NULL, NULL, old->attrs->src); + rte_recalculate(old->sender, old->net, NULL, old->attrs->src); rte_update_unlock(); } @@ -1758,14 +1752,11 @@ rt_commit(struct config *new, struct config *old) static inline void do_feed_baby(struct proto *p, int type, struct announce_hook *h, net *n, rte *e) { - ea_list *tmpa; - rte_update_lock(); - tmpa = make_tmp_attrs(e, rte_update_pool); if (type == RA_ACCEPTED) - rt_notify_accepted(h, n, e, NULL, NULL, tmpa, p->refeeding ? 2 : 1); + rt_notify_accepted(h, n, e, NULL, NULL, p->refeeding ? 2 : 1); else - rt_notify_basic(h, n, e, p->refeeding ? e : NULL, tmpa, p->refeeding); + rt_notify_basic(h, n, e, p->refeeding ? e : NULL, p->refeeding); rte_update_unlock(); } From 8d9eef17713a9b38cd42bd59c4ce76c3ef6c2fc2 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Mon, 8 Jun 2015 02:20:43 +0200 Subject: [PATCH 09/28] BGP multipath support Kernel option 'merge paths' allows to merge routes exported to kernel protocol (currently BGP and static routes) to multipath routes. --- doc/bird.sgml | 12 +++ filter/filter.c | 30 +++--- lib/birdlib.h | 1 + nest/protocol.h | 3 + nest/route.h | 11 ++ nest/rt-attr.c | 10 ++ nest/rt-table.c | 228 +++++++++++++++++++++++++++++++++++++++--- proto/bgp/attrs.c | 76 ++++++++++++++ proto/bgp/bgp.c | 1 + proto/bgp/bgp.h | 1 + proto/static/static.c | 7 ++ sysdep/unix/krt.Y | 4 +- sysdep/unix/krt.c | 17 +++- sysdep/unix/krt.h | 3 + 14 files changed, 368 insertions(+), 36 deletions(-) diff --git a/doc/bird.sgml b/doc/bird.sgml index 1c2dda4b..752465b9 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -2227,6 +2227,18 @@ limitations can be overcome using another routing table and the pipe protocol. a graceful restart recovery is active, the Kernel protocol will defer synchronization of routing tables until the end of the recovery. Note that import of kernel routes to BIRD is not affected. + + merge paths switch [limit number] + Usually, only best routes are exported to the kernel protocol. With path + merging enabled, both best routes and equivalent non-best routes are + merged during export to generate one ECMP (equal-cost multipath) route + for each network. This is useful e.g. for BGP multipath. Note that best + routes are still pivotal for route export (responsible for most + properties of resulting ECMP routes), while exported non-best routes are + responsible just for additional multipath next hops. This option also + allows to specify a limit on maximal number of nexthops in one route. By + default, multipath merging is disabled. If enabled, default value of the + limit is 16. Attributes diff --git a/filter/filter.c b/filter/filter.c index 3b14fc0c..3f8968aa 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -471,26 +471,22 @@ static inline void f_rte_cow(void) static void f_rta_cow(void) { - if ((*f_rte)->attrs->aflags & RTAF_CACHED) { + if (!rta_is_cached((*f_rte)->attrs)) + return; - /* Prepare to modify rte */ - f_rte_cow(); + /* Prepare to modify rte */ + f_rte_cow(); - /* Store old rta to free it later */ - f_old_rta = (*f_rte)->attrs; + /* Store old rta to free it later, it stores reference from rte_cow() */ + f_old_rta = (*f_rte)->attrs; - /* - * Alloc new rta, do shallow copy and update rte. Fields eattrs - * and nexthops of rta are shared with f_old_rta (they will be - * copied when the cached rta will be obtained at the end of - * f_run()), also the lock of hostentry is inherited (we suppose - * hostentry is not changed by filters). - */ - rta *ra = lp_alloc(f_pool, sizeof(rta)); - memcpy(ra, f_old_rta, sizeof(rta)); - ra->aflags = 0; - (*f_rte)->attrs = ra; - } + /* + * Get shallow copy of rta. Fields eattrs and nexthops of rta are shared + * with f_old_rta (they will be copied when the cached rta will be obtained + * at the end of f_run()), also the lock of hostentry is inherited (we + * suppose hostentry is not changed by filters). + */ + (*f_rte)->attrs = rta_do_cow((*f_rte)->attrs, f_pool); } static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS; diff --git a/lib/birdlib.h b/lib/birdlib.h index 94054769..ad41dca3 100644 --- a/lib/birdlib.h +++ b/lib/birdlib.h @@ -31,6 +31,7 @@ #endif #define ABS(a) ((a)>=0 ? (a) : -(a)) +#define DELTA(a,b) (((a)>=(b))?(a)-(b):(b)-(a)) #define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a))) diff --git a/nest/protocol.h b/nest/protocol.h index a51e9afd..8c49154f 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -158,6 +158,7 @@ struct proto { byte gr_wait; /* Route export to protocol is postponed until graceful restart */ byte down_sched; /* Shutdown is scheduled for later (PDS_*) */ byte down_code; /* Reason for shutdown (PDC_* codes) */ + byte merge_limit; /* Maximal number of nexthops for RA_MERGED */ u32 hash_key; /* Random key used for hashing of neighbors */ bird_clock_t last_state_change; /* Time of last state transition */ char *last_state_name_announced; /* Last state name we've announced to the user */ @@ -200,6 +201,7 @@ struct proto { * rte_recalculate Called at the beginning of the best route selection * rte_better Compare two rte's and decide which one is better (1=first, 0=second). * rte_same Compare two rte's and decide whether they are identical (1=yes, 0=no). + * rte_mergable Compare two rte's and decide whether they could be merged (1=yes, 0=no). * rte_insert Called whenever a rte is inserted to a routing table. * rte_remove Called whenever a rte is removed from the routing table. */ @@ -207,6 +209,7 @@ struct proto { int (*rte_recalculate)(struct rtable *, struct network *, struct rte *, struct rte *, struct rte *); int (*rte_better)(struct rte *, struct rte *); int (*rte_same)(struct rte *, struct rte *); + int (*rte_mergable)(struct rte *, struct rte *); void (*rte_insert)(struct network *, struct rte *); void (*rte_remove)(struct network *, struct rte *); diff --git a/nest/route.h b/nest/route.h index e22f950b..6067526d 100644 --- a/nest/route.h +++ b/nest/route.h @@ -240,6 +240,7 @@ static inline int rte_is_filtered(rte *r) { return !!(r->flags & REF_FILTERED); #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 */ +#define RA_MERGED 4 /* Announcement of optimal route merged with next ones */ /* Return value of import_control() callback */ #define RIC_ACCEPT 1 /* Accepted by protocol */ @@ -263,12 +264,14 @@ void rte_update2(struct announce_hook *ah, net *net, rte *new, struct rte_src *s static inline void rte_update(struct proto *p, net *net, rte *new) { rte_update2(p->main_ahook, net, new, p->main_source); } void rte_discard(rtable *tab, rte *old); int rt_examine(rtable *t, ip_addr prefix, int pxlen, struct proto *p, struct filter *filter); +rte *rt_export_merged(struct announce_hook *ah, net *net, rte **rt_free, struct ea_list **tmpa, int silent); void rt_refresh_begin(rtable *t, struct announce_hook *ah); void rt_refresh_end(rtable *t, struct announce_hook *ah); void rte_dump(rte *); void rte_free(rte *); rte *rte_do_cow(rte *); static inline rte * rte_cow(rte *r) { return (r->flags & REF_COW) ? rte_do_cow(r) : r; } +rte *rte_cow_rta(rte *r, linpool *lp); void rt_dump(rtable *); void rt_dump_all(void); int rt_feed_baby(struct proto *p); @@ -388,6 +391,12 @@ typedef struct rta { #define IGP_METRIC_UNKNOWN 0x80000000 /* Default igp_metric used when no other protocol-specific metric is availabe */ + +/* Route has regular, reachable nexthop (i.e. not RTD_UNREACHABLE and like) */ +static inline int rte_is_reachable(rte *r) +{ uint d = r->attrs->dest; return (d == RTD_ROUTER) || (d == RTD_DEVICE) || (d == RTD_MULTIPATH); } + + /* * Extended Route Attributes */ @@ -490,6 +499,8 @@ static inline int rta_is_cached(rta *r) { return r->aflags & RTAF_CACHED; } static inline rta *rta_clone(rta *r) { r->uc++; return r; } void rta__free(rta *r); static inline void rta_free(rta *r) { if (r && !--r->uc) rta__free(r); } +rta *rta_do_cow(rta *o, linpool *lp); +static inline rta * rta_cow(rta *r, linpool *lp) { return rta_is_cached(r) ? rta_do_cow(r, lp) : r; } void rta_dump(rta *); void rta_dump_all(void); void rta_show(struct cli *, rta *, ea_list *); diff --git a/nest/rt-attr.c b/nest/rt-attr.c index 32090b52..7fa05d6d 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -1138,6 +1138,16 @@ rta__free(rta *a) sl_free(rta_slab, a); } +rta * +rta_do_cow(rta *o, linpool *lp) +{ + rta *r = lp_alloc(lp, sizeof(rta)); + memcpy(r, o, sizeof(rta)); + r->aflags = 0; + r->uc = 0; + return r; +} + /** * rta_dump - dump route attributes * @a: attribute structure to dump diff --git a/nest/rt-table.c b/nest/rt-table.c index 22e1c489..9e2c4e0d 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -144,6 +144,38 @@ rte_do_cow(rte *r) return e; } +/** + * rte_cow_rta - get a private writable copy of &rte with writable &rta + * @r: a route entry to be copied + * @lp: a linpool from which to allocate &rta + * + * rte_cow_rta() takes a &rte and prepares it and associated &rta for + * modification. There are three possibilities: First, both &rte and &rta are + * private copies, in that case they are returned unchanged. Second, &rte is + * private copy, but &rta is cached, in that case &rta is duplicated using + * rta_do_cow(). Third, both &rte is shared and &rta is cached, in that case + * both structures are duplicated by rte_do_cow() and rta_do_cow(). + * + * Note that in the second case, cached &rta loses one reference, while private + * copy created by rta_do_cow() is a shallow copy sharing indirect data (eattrs, + * nexthops, ...) with it. To work properly, original shared &rta should have + * another reference during the life of created private copy. + * + * Result: a pointer to the new writable &rte with writable &rta. + */ +rte * +rte_cow_rta(rte *r, linpool *lp) +{ + if (!rta_is_cached(r->attrs)) + return r; + + rte *e = rte_cow(r); + rta *a = rta_do_cow(r->attrs, lp); + rta_free(e->attrs); + e->attrs = a; + return e; +} + static int /* Actually better or at least as good as */ rte_better(rte *new, rte *old) { @@ -172,6 +204,26 @@ rte_better(rte *new, rte *old) return 0; } +static int +rte_mergable(rte *pri, rte *sec) +{ + int (*mergable)(rte *, rte *); + + if (!rte_is_valid(pri) || !rte_is_valid(sec)) + return 0; + + if (pri->pref != sec->pref) + return 0; + + if (pri->attrs->src->proto->proto != sec->attrs->src->proto->proto) + return 0; + + if (mergable = pri->attrs->src->proto->rte_mergable) + return mergable(pri, sec); + + return 0; +} + static void rte_trace(struct proto *p, rte *e, int dir, char *msg) { @@ -535,6 +587,129 @@ rt_notify_accepted(struct announce_hook *ah, net *net, rte *new_changed, rte *ol rte_free(old_free); } + +static struct mpnh * +mpnh_merge_rta(struct mpnh *nhs, rta *a, int max) +{ + struct mpnh nh = { .gw = a->gw, .iface = a->iface }; + struct mpnh *nh2 = (a->dest == RTD_MULTIPATH) ? a->nexthops : &nh; + return mpnh_merge(nhs, nh2, 1, 0, max, rte_update_pool); +} + +rte * +rt_export_merged(struct announce_hook *ah, net *net, rte **rt_free, ea_list **tmpa, int silent) +{ + // struct proto *p = ah->proto; + struct mpnh *nhs = NULL; + rte *best0, *best, *rt0, *rt, *tmp; + + best0 = net->routes; + *rt_free = NULL; + + if (!rte_is_valid(best0)) + return NULL; + + best = export_filter(ah, best0, rt_free, tmpa, silent); + + if (!best || !rte_is_reachable(best)) + return best; + + for (rt0 = best0->next; rt0; rt0 = rt0->next) + { + if (!rte_mergable(best0, rt0)) + continue; + + rt = export_filter(ah, rt0, &tmp, NULL, 1); + + if (!rt) + continue; + + if (rte_is_reachable(rt)) + nhs = mpnh_merge_rta(nhs, rt->attrs, ah->proto->merge_limit); + + if (tmp) + rte_free(tmp); + } + + if (nhs) + { + nhs = mpnh_merge_rta(nhs, best->attrs, ah->proto->merge_limit); + + if (nhs->next) + { + best = rte_cow_rta(best, rte_update_pool); + best->attrs->dest = RTD_MULTIPATH; + best->attrs->nexthops = nhs; + } + } + + if (best != best0) + *rt_free = best; + + return best; +} + + +static void +rt_notify_merged(struct announce_hook *ah, net *net, rte *new_changed, rte *old_changed, + rte *new_best, rte*old_best, int refeed) +{ + // struct proto *p = ah->proto; + + rte *new_best_free = NULL; + rte *old_best_free = NULL; + rte *new_changed_free = NULL; + rte *old_changed_free = NULL; + ea_list *tmpa = NULL; + + /* We assume that all rte arguments are either NULL or rte_is_valid() */ + + /* This check should be done by the caller */ + if (!new_best && !old_best) + return; + + /* Check whether the change is relevant to the merged route */ + if ((new_best == old_best) && !refeed) + { + new_changed = rte_mergable(new_best, new_changed) ? + export_filter(ah, new_changed, &new_changed_free, NULL, 1) : NULL; + + old_changed = rte_mergable(old_best, old_changed) ? + export_filter(ah, old_changed, &old_changed_free, NULL, 1) : NULL; + + if (!new_changed && !old_changed) + return; + } + + if (new_best) + ah->stats->exp_updates_received++; + else + ah->stats->exp_withdraws_received++; + + /* Prepare new merged route */ + if (new_best) + new_best = rt_export_merged(ah, net, &new_best_free, &tmpa, 0); + + /* Prepare old merged route (without proper merged next hops) */ + /* There are some issues with running filter on old route - see rt_notify_basic() */ + if (old_best && !refeed) + old_best = export_filter(ah, old_best, &old_best_free, NULL, 1); + + if (new_best || old_best) + do_rt_notify(ah, net, new_best, old_best, tmpa, refeed); + + /* Discard temporary rte's */ + if (new_best_free) + rte_free(new_best_free); + if (old_best_free) + rte_free(old_best_free); + if (new_changed_free) + rte_free(new_changed_free); + if (old_changed_free) + rte_free(old_changed_free); +} + + /** * rte_announce - announce a routing table change * @tab: table the route has been added to @@ -564,13 +739,20 @@ rt_notify_accepted(struct announce_hook *ah, net *net, rte *new_changed, rte *ol * the protocol gets called. */ static void -rte_announce(rtable *tab, unsigned type, net *net, rte *new, rte *old, rte *before_old) +rte_announce(rtable *tab, unsigned type, net *net, rte *new, rte *old, + rte *new_best, rte *old_best, rte *before_old) { + if (!rte_is_valid(new)) + new = NULL; + if (!rte_is_valid(old)) old = before_old = NULL; - if (!rte_is_valid(new)) - new = NULL; + if (!rte_is_valid(new_best)) + new_best = NULL; + + if (!rte_is_valid(old_best)) + old_best = NULL; if (!old && !new) return; @@ -593,6 +775,8 @@ rte_announce(rtable *tab, unsigned type, net *net, rte *new, rte *old, rte *befo if (a->proto->accept_ra_types == type) if (type == RA_ACCEPTED) rt_notify_accepted(a, net, new, old, before_old, 0); + else if (type == RA_MERGED) + rt_notify_merged(a, net, new, old, new_best, old_best, 0); else rt_notify_basic(a, net, new, old, 0); } @@ -898,11 +1082,12 @@ rte_recalculate(struct announce_hook *ah, net *net, rte *new, struct rte_src *sr } /* Propagate the route change */ - rte_announce(table, RA_ANY, net, new, old, NULL); + rte_announce(table, RA_ANY, net, new, old, NULL, NULL, NULL); if (net->routes != old_best) - rte_announce(table, RA_OPTIMAL, net, net->routes, old_best, NULL); + rte_announce(table, RA_OPTIMAL, net, net->routes, old_best, NULL, NULL, NULL); if (table->config->sorted) - rte_announce(table, RA_ACCEPTED, net, new, old, before_old); + rte_announce(table, RA_ACCEPTED, net, new, old, NULL, NULL, before_old); + rte_announce(table, RA_MERGED, net, new, old, net->routes, old_best, NULL); if (!net->routes && (table->gc_counter++ >= table->config->gc_max_ops) && @@ -1081,10 +1266,11 @@ rte_update2(struct announce_hook *ah, net *net, 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 -rte_announce_i(rtable *tab, unsigned type, net *n, rte *new, rte *old) +rte_announce_i(rtable *tab, unsigned type, net *net, rte *new, rte *old, + rte *new_best, rte *old_best) { rte_update_lock(); - rte_announce(tab, type, n, new, old, NULL); + rte_announce(tab, type, net, new, old, new_best, old_best, NULL); rte_update_unlock(); } @@ -1548,7 +1734,7 @@ rt_next_hop_update_net(rtable *tab, net *n) new = rt_next_hop_update_rte(tab, e); *k = new; - rte_announce_i(tab, RA_ANY, n, new, e); + rte_announce_i(tab, RA_ANY, n, new, e, NULL, NULL); rte_trace_in(D_ROUTES, new->sender->proto, new, "updated"); /* Call a pre-comparison hook */ @@ -1588,10 +1774,13 @@ rt_next_hop_update_net(rtable *tab, net *n) /* Announce the new best route */ if (new != old_best) { - rte_announce_i(tab, RA_OPTIMAL, n, new, old_best); + rte_announce_i(tab, RA_OPTIMAL, n, new, old_best, NULL, NULL); rte_trace_in(D_ROUTES, new->sender->proto, new, "updated [best]"); } + /* FIXME: Better announcement of merged routes */ + rte_announce_i(tab, RA_MERGED, n, new, old_best, new, old_best); + if (free_old_best) rte_free_quick(old_best); @@ -1755,6 +1944,8 @@ do_feed_baby(struct proto *p, int type, struct announce_hook *h, net *n, rte *e) rte_update_lock(); if (type == RA_ACCEPTED) rt_notify_accepted(h, n, e, NULL, NULL, p->refeeding ? 2 : 1); + else if (type == RA_MERGED) + rt_notify_merged(h, n, NULL, NULL, e, p->refeeding ? e : NULL, p->refeeding); else rt_notify_basic(h, n, e, p->refeeding ? e : NULL, p->refeeding); rte_update_unlock(); @@ -1802,7 +1993,8 @@ again: /* XXXX perhaps we should change feed for RA_ACCEPTED to not use 'new' */ if ((p->accept_ra_types == RA_OPTIMAL) || - (p->accept_ra_types == RA_ACCEPTED)) + (p->accept_ra_types == RA_ACCEPTED) || + (p->accept_ra_types == RA_MERGED)) if (rte_is_valid(e)) { if (p->export_state != ES_FEEDING) @@ -2267,12 +2459,22 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d) rte_update_lock(); /* We use the update buffer for filtering */ tmpa = make_tmp_attrs(e, rte_update_pool); - if (d->export_mode) + /* Special case for merged export */ + if ((d->export_mode == RSEM_EXPORT) && (d->export_protocol->accept_ra_types == RA_MERGED)) + { + rte *rt_free; + e = rt_export_merged(a, n, &rt_free, &tmpa, 1); + pass = 1; + + if (!e) + { e = ee; goto skip; } + } + else if (d->export_mode) { struct proto *ep = d->export_protocol; int ic = ep->import_control ? ep->import_control(ep, &e, &tmpa, rte_update_pool) : 0; - if (ep->accept_ra_types == RA_OPTIMAL) + if (ep->accept_ra_types == RA_OPTIMAL || ep->accept_ra_types == RA_MERGED) pass = 1; if (ic < 0) diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index d56c017d..d85afa8f 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -1312,6 +1312,82 @@ bgp_rte_better(rte *new, rte *old) } +int +bgp_rte_mergable(rte *pri, rte *sec) +{ + struct bgp_proto *pri_bgp = (struct bgp_proto *) pri->attrs->src->proto; + struct bgp_proto *sec_bgp = (struct bgp_proto *) sec->attrs->src->proto; + eattr *x, *y; + u32 p, s; + + /* Skip suppressed routes (see bgp_rte_recalculate()) */ + if (pri->u.bgp.suppressed != sec->u.bgp.suppressed) + return 0; + + /* RFC 4271 9.1.2.1. Route resolvability test */ + if (!rte_resolvable(sec)) + return 0; + + /* Start with local preferences */ + x = ea_find(pri->attrs->eattrs, EA_CODE(EAP_BGP, BA_LOCAL_PREF)); + y = ea_find(sec->attrs->eattrs, EA_CODE(EAP_BGP, BA_LOCAL_PREF)); + p = x ? x->u.data : pri_bgp->cf->default_local_pref; + s = y ? y->u.data : sec_bgp->cf->default_local_pref; + if (p != s) + return 0; + + /* RFC 4271 9.1.2.2. a) Use AS path lengths */ + if (pri_bgp->cf->compare_path_lengths || sec_bgp->cf->compare_path_lengths) + { + x = ea_find(pri->attrs->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH)); + y = ea_find(sec->attrs->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH)); + p = x ? as_path_getlen(x->u.ptr) : AS_PATH_MAXLEN; + s = y ? as_path_getlen(y->u.ptr) : AS_PATH_MAXLEN; + + if (p != s) + return 0; + +// if (DELTA(p, s) > pri_bgp->cf->relax_multipath) +// return 0; + } + + /* RFC 4271 9.1.2.2. b) Use origins */ + x = ea_find(pri->attrs->eattrs, EA_CODE(EAP_BGP, BA_ORIGIN)); + y = ea_find(sec->attrs->eattrs, EA_CODE(EAP_BGP, BA_ORIGIN)); + p = x ? x->u.data : ORIGIN_INCOMPLETE; + s = y ? y->u.data : ORIGIN_INCOMPLETE; + if (p != s) + return 0; + + /* RFC 4271 9.1.2.2. c) Compare MED's */ + if (pri_bgp->cf->med_metric || sec_bgp->cf->med_metric || + (bgp_get_neighbor(pri) == bgp_get_neighbor(sec))) + { + x = ea_find(pri->attrs->eattrs, EA_CODE(EAP_BGP, BA_MULTI_EXIT_DISC)); + y = ea_find(sec->attrs->eattrs, EA_CODE(EAP_BGP, BA_MULTI_EXIT_DISC)); + p = x ? x->u.data : pri_bgp->cf->default_med; + s = y ? y->u.data : sec_bgp->cf->default_med; + if (p != s) + return 0; + } + + /* RFC 4271 9.1.2.2. d) Prefer external peers */ + if (pri_bgp->is_internal != sec_bgp->is_internal) + return 0; + + /* RFC 4271 9.1.2.2. e) Compare IGP metrics */ + p = pri_bgp->cf->igp_metric ? pri->attrs->igp_metric : 0; + s = sec_bgp->cf->igp_metric ? sec->attrs->igp_metric : 0; + if (p != s) + return 0; + + /* Remaining criteria are ignored */ + + return 1; +} + + + static inline int same_group(rte *r, u32 lpref, u32 lasn) { diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index e48b643b..9e28b278 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -1243,6 +1243,7 @@ bgp_init(struct proto_config *C) P->feed_begin = bgp_feed_begin; P->feed_end = bgp_feed_end; P->rte_better = bgp_rte_better; + P->rte_mergable = bgp_rte_mergable; P->rte_recalculate = c->deterministic_med ? bgp_rte_recalculate : NULL; p->cf = c; diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 446fc857..b6e80fe5 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -238,6 +238,7 @@ byte *bgp_attach_attr_wa(struct ea_list **to, struct linpool *pool, unsigned att struct rta *bgp_decode_attrs(struct bgp_conn *conn, byte *a, uint len, struct linpool *pool, int mandatory); int bgp_get_attr(struct eattr *e, byte *buf, int buflen); int bgp_rte_better(struct rte *, struct rte *); +int bgp_rte_mergable(rte *pri, rte *sec); int bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best); 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 *); diff --git a/proto/static/static.c b/proto/static/static.c index 4b72fa9d..e7e7ab15 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -352,6 +352,12 @@ static_if_notify(struct proto *p, unsigned flags, struct iface *i) } } +int +static_rte_mergable(rte *pri, rte *sec) +{ + return 1; +} + void static_init_config(struct static_config *c) { @@ -366,6 +372,7 @@ static_init(struct proto_config *c) p->neigh_notify = static_neigh_notify; p->if_notify = static_if_notify; + p->rte_mergable = static_rte_mergable; return p; } diff --git a/sysdep/unix/krt.Y b/sysdep/unix/krt.Y index 630cda38..e036081d 100644 --- a/sysdep/unix/krt.Y +++ b/sysdep/unix/krt.Y @@ -17,7 +17,7 @@ CF_DEFINES CF_DECLS -CF_KEYWORDS(KERNEL, PERSIST, SCAN, TIME, LEARN, DEVICE, ROUTES, GRACEFUL, RESTART, KRT_SOURCE, KRT_METRIC) +CF_KEYWORDS(KERNEL, PERSIST, SCAN, TIME, LEARN, DEVICE, ROUTES, GRACEFUL, RESTART, KRT_SOURCE, KRT_METRIC, MERGE, PATHS) CF_GRAMMAR @@ -47,6 +47,8 @@ kern_item: } | DEVICE ROUTES bool { THIS_KRT->devroutes = $3; } | GRACEFUL RESTART bool { THIS_KRT->graceful_restart = $3; } + | MERGE PATHS bool { THIS_KRT->merge_paths = $3 ? KRT_DEFAULT_ECMP_LIMIT : 0; } + | MERGE PATHS bool LIMIT expr { THIS_KRT->merge_paths = $3 ? $5 : 0; if (($5 <= 0) || ($5 > 255)) cf_error("Merge paths limit must be in range 1-255"); } ; /* Kernel interface protocol */ diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index d8d28c7c..2eab5cb2 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -595,9 +595,13 @@ krt_flush_routes(struct krt_proto *p) static struct rte * krt_export_net(struct krt_proto *p, net *net, rte **rt_free, ea_list **tmpa) { - struct filter *filter = p->p.main_ahook->out_filter; + struct announce_hook *ah = p->p.main_ahook; + struct filter *filter = ah->out_filter; rte *rt; + if (p->p.accept_ra_types == RA_MERGED) + return rt_export_merged(ah, net, rt_free, tmpa, 1); + rt = net->routes; *rt_free = NULL; @@ -1091,11 +1095,13 @@ krt_rte_same(rte *a, rte *b) struct krt_config *krt_cf; static struct proto * -krt_init(struct proto_config *c) +krt_init(struct proto_config *C) { - struct krt_proto *p = proto_new(c, sizeof(struct krt_proto)); + struct krt_proto *p = proto_new(C, sizeof(struct krt_proto)); + struct krt_config *c = (struct krt_config *) C; - p->p.accept_ra_types = RA_OPTIMAL; + p->p.accept_ra_types = c->merge_paths ? RA_MERGED : RA_OPTIMAL; + p->p.merge_limit = c->merge_paths; p->p.import_control = krt_import_control; p->p.rt_notify = krt_rt_notify; p->p.if_notify = krt_if_notify; @@ -1161,7 +1167,8 @@ krt_reconfigure(struct proto *p, struct proto_config *new) 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 && + o->devroutes == n->devroutes && o->merge_paths == n->merge_paths; } static void diff --git a/sysdep/unix/krt.h b/sysdep/unix/krt.h index 1940cbcd..9d5d4e8c 100644 --- a/sysdep/unix/krt.h +++ b/sysdep/unix/krt.h @@ -26,6 +26,8 @@ struct kif_proto; #define KRF_DELETE 3 /* Should be deleted */ #define KRF_IGNORE 4 /* To be ignored */ +#define KRT_DEFAULT_ECMP_LIMIT 16 + #define EA_KRT_SOURCE EA_CODE(EAP_KRT, 0) #define EA_KRT_METRIC EA_CODE(EAP_KRT, 1) @@ -47,6 +49,7 @@ struct krt_config { int learn; /* Learn routes from other sources */ int devroutes; /* Allow export of device routes */ int graceful_restart; /* Regard graceful restart recovery */ + int merge_paths; /* Exported routes are merged for ECMP */ }; struct krt_proto { From ab4da3423d89fb6c60a4137f19c189a8716ecab6 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sat, 18 Jul 2015 13:05:05 +0200 Subject: [PATCH 10/28] Direct: Fixes behavior for the same routes on different interfaces Thanks to Andrew (seti.kr.ua) for the bug report. --- nest/rt-dev.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/nest/rt-dev.c b/nest/rt-dev.c index 87ffc5ec..f6bc1432 100644 --- a/nest/rt-dev.c +++ b/nest/rt-dev.c @@ -51,7 +51,10 @@ dev_ifa_notify(struct proto *p, unsigned c, struct ifa *ad) DBG("dev_if_notify: device shutdown: prefix not found\n"); return; } - rte_update(p, n, NULL); + + /* Use iface ID as local source ID */ + struct rte_src *src = rt_get_source(p, ad->iface->index); + rte_update2(p->main_ahook, n, NULL, src); } else if (c & IF_CHANGE_UP) { @@ -61,8 +64,11 @@ dev_ifa_notify(struct proto *p, unsigned c, struct ifa *ad) DBG("dev_if_notify: %s:%I going up\n", ad->iface->name, ad->ip); + /* Use iface ID as local source ID */ + struct rte_src *src = rt_get_source(p, ad->iface->index); + rta a0 = { - .src = p->main_source, + .src = src, .source = RTS_DEVICE, .scope = SCOPE_UNIVERSE, .cast = RTC_UNICAST, @@ -75,7 +81,7 @@ dev_ifa_notify(struct proto *p, unsigned c, struct ifa *ad) e = rte_get_temp(a); e->net = n; e->pflags = 0; - rte_update(p, n, e); + rte_update2(p->main_ahook, n, e, src); } } From 06e0d1b692d8a190c3f1d073c5c557d8efe78b17 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sat, 18 Jul 2015 13:38:21 +0200 Subject: [PATCH 11/28] BGP: Extended messages support Implements draft-ietf-idr-bgp-extended-messages-10, for now undocumented and with temporary private capability number. --- doc/bird.sgml | 2 +- proto/bgp/bgp.c | 22 ++++++++++++++++------ proto/bgp/bgp.h | 13 +++++++++++-- proto/bgp/config.Y | 3 ++- proto/bgp/packets.c | 29 ++++++++++++++++++++++++----- 5 files changed, 54 insertions(+), 15 deletions(-) diff --git a/doc/bird.sgml b/doc/bird.sgml index 752465b9..2ae9f649 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -1571,7 +1571,7 @@ RFC 4271 It also supports the community attributes (RFC 1997), capability negotiation -(RFC 3392), +(RFC 5492), MD5 password authentication (RFC 2385), extended communities diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index 9e28b278..f549b0ed 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -569,6 +569,7 @@ bgp_send_open(struct bgp_conn *conn) conn->peer_gr_time = 0; conn->peer_gr_flags = 0; conn->peer_gr_aflags = 0; + conn->peer_ext_messages_support = 0; DBG("BGP: Sending open\n"); conn->sk->rx_hook = bgp_rx; @@ -733,8 +734,8 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c s->dport = p->cf->remote_port; s->iface = p->neigh ? p->neigh->iface : NULL; s->ttl = p->cf->ttl_security ? 255 : hops; - s->rbsize = BGP_RX_BUFFER_SIZE; - s->tbsize = BGP_TX_BUFFER_SIZE; + s->rbsize = p->cf->enable_extended_messages ? BGP_RX_BUFFER_EXT_SIZE : BGP_RX_BUFFER_SIZE; + s->tbsize = p->cf->enable_extended_messages ? BGP_TX_BUFFER_EXT_SIZE : BGP_TX_BUFFER_SIZE; s->tos = IP_PREC_INTERNET_CONTROL; s->password = p->cf->password; s->tx_hook = bgp_connected; @@ -843,6 +844,13 @@ bgp_incoming_connection(sock *sk, int dummy UNUSED) if (sk_set_min_ttl(sk, 256 - hops) < 0) goto err; + if (p->cf->enable_extended_messages) + { + sk->rbsize = BGP_RX_BUFFER_EXT_SIZE; + sk->tbsize = BGP_TX_BUFFER_EXT_SIZE; + sk_reallocate(sk); + } + bgp_setup_conn(p, &p->incoming_conn); bgp_setup_sk(&p->incoming_conn, sk); bgp_send_open(&p->incoming_conn); @@ -1518,21 +1526,23 @@ 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, " Neighbor caps: %s%s%s%s%s%s", + 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" : ""); - cli_msg(-1006, " Session: %s%s%s%s%s%s%s", + (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" : "", p->rr_client ? " route-reflector" : "", p->rs_client ? " route-server" : "", p->as4_session ? " AS4" : "", p->add_path_rx ? " add-path-rx" : "", - p->add_path_tx ? " add-path-tx" : ""); + p->add_path_tx ? " add-path-tx" : "", + p->ext_messages ? " ext-messages" : ""); cli_msg(-1006, " Source address: %I", p->source_addr); if (P->cf->in_limit) cli_msg(-1006, " Route limit: %d/%d", diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index b6e80fe5..274794f1 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -40,6 +40,7 @@ struct bgp_config { int capabilities; /* Enable capability handshake [RFC3392] */ int enable_refresh; /* Enable local support for route refresh [RFC2918] */ int enable_as4; /* Enable local support for 4B AS numbers [RFC4893] */ + int enable_extended_messages; /* Enable local support for extended messages [draft] */ u32 rr_cluster_id; /* Route reflector cluster ID, if different from local ID */ int rr_client; /* Whether neighbor is RR client of me */ int rs_client; /* Whether neighbor is RS client of me */ @@ -109,6 +110,7 @@ struct bgp_conn { u16 peer_gr_time; u8 peer_gr_flags; u8 peer_gr_aflags; + u8 peer_ext_messages_support; /* Peer supports extended message length [draft] */ unsigned hold_time, keepalive_time; /* Times calculated from my and neighbor's requirements */ }; @@ -121,6 +123,7 @@ struct bgp_proto { u8 as4_session; /* Session uses 4B AS numbers in AS_PATH (both sides support it) */ u8 add_path_rx; /* Session expects receive of ADD-PATH extended NLRI */ u8 add_path_tx; /* Session expects transmit of ADD-PATH extended NLRI */ + u8 ext_messages; /* Session allows to use extended messages (both sides support it) */ u32 local_id; /* BGP identifier of this router */ u32 remote_id; /* BGP identifier of the neighbor */ u32 rr_cluster_id; /* Route reflector cluster ID */ @@ -180,9 +183,15 @@ struct bgp_bucket { #define BGP_PORT 179 #define BGP_VERSION 4 #define BGP_HEADER_LENGTH 19 -#define BGP_MAX_PACKET_LENGTH 4096 +#define BGP_MAX_MESSAGE_LENGTH 4096 +#define BGP_MAX_EXT_MSG_LENGTH 65535 #define BGP_RX_BUFFER_SIZE 4096 -#define BGP_TX_BUFFER_SIZE BGP_MAX_PACKET_LENGTH +#define BGP_TX_BUFFER_SIZE 4096 +#define BGP_RX_BUFFER_EXT_SIZE 65535 +#define BGP_TX_BUFFER_EXT_SIZE 65535 + +static inline int bgp_max_packet_length(struct bgp_proto *p) +{ return p->ext_messages ? BGP_MAX_EXT_MSG_LENGTH : BGP_MAX_MESSAGE_LENGTH; } extern struct linpool *bgp_linpool; diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y index 49afe5ae..85b93a6b 100644 --- a/proto/bgp/config.Y +++ b/proto/bgp/config.Y @@ -27,7 +27,7 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, INTERPRET, COMMUNITIES, BGP_ORIGINATOR_ID, 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) + CHECK, LINK, PORT, EXTENDED, MESSAGES) CF_GRAMMAR @@ -108,6 +108,7 @@ bgp_proto: | bgp_proto DISABLE AFTER ERROR bool ';' { BGP_CFG->disable_after_error = $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; } | bgp_proto CAPABILITIES bool ';' { BGP_CFG->capabilities = $3; } | bgp_proto ADVERTISE IPV4 bool ';' { BGP_CFG->advertise_ipv4 = $4; } | bgp_proto PASSWORD text ';' { BGP_CFG->password = $3; } diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 378f5ab1..ed99f623 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -84,7 +84,7 @@ mrt_put_bgp4_hdr(byte *buf, struct bgp_conn *conn, int as4) static void mrt_dump_bgp_packet(struct bgp_conn *conn, byte *pkt, unsigned len) { - byte buf[BGP_MAX_PACKET_LENGTH + 128]; + byte *buf = alloca(128+len); /* 128 is enough for MRT headers */ byte *bp = buf + MRTDUMP_HDR_LENGTH; int as4 = conn->bgp->as4_session; @@ -223,6 +223,14 @@ bgp_put_cap_err(struct bgp_proto *p UNUSED, byte *buf) return buf; } +static byte * +bgp_put_cap_ext_msg(struct bgp_proto *p UNUSED, byte *buf) +{ + *buf++ = 230; /* Capability TBD: Support for extended messages */ + *buf++ = 0; /* Capability data length */ + return buf; +} + static byte * bgp_create_open(struct bgp_conn *conn, byte *buf) @@ -274,6 +282,9 @@ bgp_create_open(struct bgp_conn *conn, byte *buf) if (p->cf->enable_refresh) cap = bgp_put_cap_err(p, cap); + if (p->cf->enable_extended_messages) + cap = bgp_put_cap_ext_msg(p, cap); + cap_len = cap - buf - 12; if (cap_len > 0) { @@ -342,7 +353,7 @@ bgp_create_update(struct bgp_conn *conn, byte *buf) { struct bgp_proto *p = conn->bgp; struct bgp_bucket *buck; - int remains = BGP_MAX_PACKET_LENGTH - BGP_HEADER_LENGTH - 4; + int remains = bgp_max_packet_length(p) - BGP_HEADER_LENGTH - 4; byte *w; int wd_size = 0; int r_size = 0; @@ -428,7 +439,7 @@ bgp_create_update(struct bgp_conn *conn, byte *buf) struct bgp_proto *p = conn->bgp; struct bgp_bucket *buck; int size, second, rem_stored; - int remains = BGP_MAX_PACKET_LENGTH - BGP_HEADER_LENGTH - 4; + int remains = bgp_max_packet_length(p) - BGP_HEADER_LENGTH - 4; byte *w, *w_stored, *tmp, *tstart; ip_addr *ipp, ip, ip_ll; ea_list *ea; @@ -856,6 +867,12 @@ bgp_parse_capabilities(struct bgp_conn *conn, byte *opt, int len) conn->peer_enhanced_refresh_support = 1; break; + case 230: /* Extended message length capability, draft, cap number TBD */ + if (cl != 0) + goto err; + conn->peer_ext_messages_support = 1; + break; + /* We can safely ignore all other capabilities */ } len -= 2 + cl; @@ -1019,6 +1036,7 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, int len) p->add_path_rx = (p->cf->add_path & ADD_PATH_RX) && (conn->peer_add_path & ADD_PATH_TX); p->add_path_tx = (p->cf->add_path & ADD_PATH_TX) && (conn->peer_add_path & ADD_PATH_RX); p->gr_ready = p->cf->gr_mode && conn->peer_gr_able; + p->ext_messages = p->cf->enable_extended_messages && conn->peer_ext_messages_support; if (p->add_path_tx) p->p.accept_ra_types = RA_ANY; @@ -1418,7 +1436,7 @@ static struct { { 2, 4, "Unsupported optional parameter" }, { 2, 5, "Authentication failure" }, { 2, 6, "Unacceptable hold time" }, - { 2, 7, "Required capability missing" }, /* [RFC3392] */ + { 2, 7, "Required capability missing" }, /* [RFC5492] */ { 2, 8, "No supported AFI/SAFI" }, /* This error msg is nonstandard */ { 3, 0, "Invalid UPDATE message" }, { 3, 1, "Malformed attribute list" }, @@ -1666,6 +1684,7 @@ int bgp_rx(sock *sk, int size) { struct bgp_conn *conn = sk->data; + struct bgp_proto *p = conn->bgp; byte *pkt_start = sk->rbuf; byte *end = pkt_start + size; unsigned i, len; @@ -1682,7 +1701,7 @@ bgp_rx(sock *sk, int size) break; } len = get_u16(pkt_start+16); - if (len < BGP_HEADER_LENGTH || len > BGP_MAX_PACKET_LENGTH) + if (len < BGP_HEADER_LENGTH || len > bgp_max_packet_length(p)) { bgp_error(conn, 1, 2, pkt_start+16, 2); break; From 6683d42d5b560c8805b977736b2a769ea2d9aa8b Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sat, 18 Jul 2015 19:05:11 +0200 Subject: [PATCH 12/28] Documentation update --- doc/bird.sgml | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/doc/bird.sgml b/doc/bird.sgml index 2ae9f649..df83aacd 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -1707,7 +1707,11 @@ using the following configuration parameters: scan time - Time in seconds between two scans of the network interface list. On systems where we are notified about interface status changes asynchronously (such as newer versions of Linux), we need to scan the @@ -2266,6 +2269,20 @@ these attributes: The realm of the route. Can be used for traffic classification. +

In Linux, there is also a plenty of obscure route attributes mostly focused +on tuning TCP performance of local connections. BIRD supports most of these +attributes, see Linux or iproute2 documentation for their meaning. Attributes +Example

A simple configuration can look this way: @@ -3394,7 +3411,9 @@ of the protocol contains mainly a list of static routes: route - Static route through a neighboring router. + Static route through a neighboring router. For link-local next hops, + interface can be specified as a part of the address (e.g., + route Static multipath route. Contains several nexthops (gateways), possibly From 17661ff934a80d517284c96756357d4ed5af9a64 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sat, 18 Jul 2015 19:30:35 +0200 Subject: [PATCH 13/28] Nest: Fixes symbols in router id Thanks to Peter Hudec for noticing the problem. --- nest/config.Y | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/nest/config.Y b/nest/config.Y index 37551802..7ad6c712 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -94,6 +94,7 @@ rtrid: idval: NUM { $$ = $1; } + | '(' term ')' { $$ = f_eval_int($2); } | RTRID | IPA { #ifndef IPV6 @@ -102,6 +103,16 @@ idval: cf_error("Router IDs must be entered as hexadecimal numbers or IPv4 addresses in IPv6 version"); #endif } + | SYM { + if ($1->class == (SYM_CONSTANT | T_INT) || $1->class == (SYM_CONSTANT | T_QUAD)) + $$ = SYM_VAL($1).i; +#ifndef IPV6 + else if ($1->class == (SYM_CONSTANT | T_IP)) + $$ = SYM_VAL($1).px.ip; +#endif + else + cf_error("Number of IPv4 address constant expected"); + } ; From a8ad8fd6491d04620fe4fdebc50f0da2927f9b21 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sat, 18 Jul 2015 23:15:04 +0200 Subject: [PATCH 14/28] Simplify build messages Thanks to Christian Tacke for the original patch. --- tools/Makefile.in | 9 ++++++--- tools/Rules.in | 6 ++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/tools/Makefile.in b/tools/Makefile.in index 062ba916..01bb7a7c 100644 --- a/tools/Makefile.in +++ b/tools/Makefile.in @@ -37,13 +37,16 @@ subdir: sysdep/paths.h .dir-stamp .dep-stamp set -e ; for a in $(static-dirs) $(client-dirs) ; do $(MAKE) -C $$a -f $(srcdir_abs)/$$a/Makefile $@ ; done $(exedir)/bird: $(bird-dep) - $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + @echo LD $(LDFLAGS) -o $@ $^ $(LIBS) + @$(CC) $(LDFLAGS) -o $@ $^ $(LIBS) $(exedir)/birdc: $(birdc-dep) - $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) $(CLIENT_LIBS) + @echo LD $(LDFLAGS) -o $@ $^ $(LIBS) $(CLIENT_LIBS) + @$(CC) $(LDFLAGS) -o $@ $^ $(LIBS) $(CLIENT_LIBS) $(exedir)/birdcl: $(birdcl-dep) - $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + @echo LD $(LDFLAGS) -o $@ $^ $(LIBS) + @$(CC) $(LDFLAGS) -o $@ $^ $(LIBS) .dir-stamp: sysdep/paths.h mkdir -p $(static-dirs) $(client-dirs) $(doc-dirs) diff --git a/tools/Rules.in b/tools/Rules.in index ca930ec8..f00c85d1 100644 --- a/tools/Rules.in +++ b/tools/Rules.in @@ -68,12 +68,14 @@ subdir: all.o all.o: $(objs) # $(LD) -r -o $@ $^ # Changed to $(CC) because $(LD) has problems with crosscompiling - $(CC) -nostdlib -r -o $@ $^ + @echo LD -r -o $@ $^ + @$(CC) -nostdlib -r -o $@ $^ endif %.o: $(src-path)%.c - $(CC) $(CFLAGS) -o $@ -c $< + @echo CC -o $@ -c $< + @$(CC) $(CFLAGS) -o $@ -c $< ifndef source-dep source-dep := $(source) From ffa398b8d8bac4cf6368fe700466cad4ff12fee8 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sun, 19 Jul 2015 11:39:24 +0200 Subject: [PATCH 15/28] BFD: Fixes crash after socket error Thanks to Thomas King for the bugreport. --- proto/bfd/bfd.c | 28 ++++++++++++++++------------ proto/bfd/packets.c | 8 ++++++-- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/proto/bfd/bfd.c b/proto/bfd/bfd.c index 5f089846..7a085791 100644 --- a/proto/bfd/bfd.c +++ b/proto/bfd/bfd.c @@ -43,7 +43,7 @@ * the needs of BFD sessions. When a new session is created, it requests a * proper BFD interface by function bfd_get_iface(), which either finds an * existing one in &iface_list (from &bfd_proto) or allocates a new one. When a - * session is removed, an associated iface is dicharged by bfd_free_iface(). + * session is removed, an associated iface is discharged by bfd_free_iface(). * * BFD requests are the external API for the other protocols. When a protocol * wants a BFD session, it calls bfd_request_session(), which creates a @@ -62,7 +62,7 @@ * configuration (like static routes in the static protocol). BFD neighbors are * handled by BFD protocol like it is a BFD client -- when a BFD neighbor is * ready, the protocol just creates a BFD request like any other protocol. - * + * * The protocol uses a new generic event loop (structure &birdloop) from |io.c|, * which supports sockets, timers and events like the main loop. Timers * (structure &timer2) are new microsecond based timers, while sockets and @@ -129,11 +129,11 @@ static inline void bfd_notify_kick(struct bfd_proto *p); * BFD sessions */ -static void +static void bfd_session_update_state(struct bfd_session *s, uint state, uint diag) { struct bfd_proto *p = s->ifa->bfd; - uint old_state = s->loc_state; + uint old_state = s->loc_state; int notify; if (state == old_state) @@ -201,8 +201,8 @@ bfd_session_control_tx_timer(struct bfd_session *s, int reset) if (s->passive && (s->rem_id == 0)) goto stop; - if (s->rem_demand_mode && - !s->poll_active && + if (s->rem_demand_mode && + !s->poll_active && (s->loc_state == BFD_STATE_UP) && (s->rem_state == BFD_STATE_UP)) goto stop; @@ -303,7 +303,7 @@ bfd_session_process_ctl(struct bfd_session *s, u8 flags, u32 old_tx_int, u32 old bfd_send_ctl(s->ifa->bfd, s, 1); } -static void +static void bfd_session_timeout(struct bfd_session *s) { struct bfd_proto *p = s->ifa->bfd; @@ -353,7 +353,7 @@ bfd_session_set_min_rx(struct bfd_session *s, u32 val) if (val == s->req_min_rx_new) return; - s->req_min_rx_new = val; + s->req_min_rx_new = val; /* Postpone timer update if req_min_rx_int decreases and the session is up */ if ((s->loc_state != BFD_STATE_UP) || (val > s->req_min_rx_int)) @@ -575,9 +575,13 @@ bfd_free_iface(struct bfd_iface *ifa) if (!ifa || --ifa->uc) return; + if (ifa->sk) + { + sk_stop(ifa->sk); + rfree(ifa->sk); + } + rem_node(&ifa->n); - sk_stop(ifa->sk); - rfree(ifa->sk); mb_free(ifa); } @@ -873,7 +877,7 @@ bfd_notify_hook(sock *sk, int len) diag = s->loc_diag; bfd_unlock_sessions(p); - /* FIXME: convert to btime and move to bfd_session_update_state() */ + /* FIXME: convert to btime and move to bfd_session_update_state() */ s->last_state_change = now; s->notify_running = 1; @@ -1092,7 +1096,7 @@ bfd_show_sessions(struct proto *P) /* FIXME: this is thread-unsafe, but perhaps harmless */ state = s->loc_state; diag = s->loc_diag; - ifname = (s->ifa && s->ifa->sk->iface) ? s->ifa->sk->iface->name : "---"; + ifname = (s->ifa && s->ifa->iface) ? s->ifa->iface->name : "---"; tx_int = s->last_tx ? (MAX(s->des_min_tx_int, s->rem_min_rx_int) TO_MS) : 0; timeout = (MAX(s->req_min_rx_int, s->rem_min_tx_int) TO_MS) * s->rem_detect_mult; diff --git a/proto/bfd/packets.c b/proto/bfd/packets.c index b5fd6782..cb40bcda 100644 --- a/proto/bfd/packets.c +++ b/proto/bfd/packets.c @@ -63,9 +63,13 @@ void bfd_send_ctl(struct bfd_proto *p, struct bfd_session *s, int final) { sock *sk = s->ifa->sk; - struct bfd_ctl_packet *pkt = (struct bfd_ctl_packet *) sk->tbuf; + struct bfd_ctl_packet *pkt; char fb[8]; + if (!sk) + return; + + pkt = (struct bfd_ctl_packet *) sk->tbuf; pkt->vdiag = bfd_pack_vdiag(1, s->loc_diag); pkt->flags = bfd_pack_flags(s->loc_state, 0); pkt->detect_mult = s->detect_mult; @@ -139,7 +143,7 @@ bfd_rx_hook(sock *sk, int len) u8 ps = bfd_pkt_get_state(pkt); if (ps > BFD_STATE_DOWN) DROP("invalid init state", ps); - + s = bfd_find_session_by_addr(p, sk->faddr); /* FIXME: better session matching and message */ From 1321e12ac460bd542d3946a0c4a4dacd71157cfa Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Mon, 20 Jul 2015 11:12:02 +0200 Subject: [PATCH 16/28] Static: Allows to specify attributes for static routes The patch adds suport for specifying route attributes together with static routes, e.g.: route 10.1.1.0/24 via 10.0.0.1 { krt_advmss = 1200; ospf_metric1 = 100; }; --- filter/filter.c | 24 ++++++++++++++++++++++++ filter/filter.h | 1 + proto/ospf/ospf.c | 17 ++++++++++++++--- proto/static/config.Y | 19 ++++++++++++++++++- proto/static/static.c | 30 +++++++++++++++++++++++++----- proto/static/static.h | 1 + 6 files changed, 83 insertions(+), 9 deletions(-) diff --git a/filter/filter.c b/filter/filter.c index 3f8968aa..55062aca 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -1527,6 +1527,30 @@ f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struc return res.val.i; } +/* TODO: perhaps we could integrate f_eval(), f_eval_rte() and f_run() */ + +struct f_val +f_eval_rte(struct f_inst *expr, struct rte **rte, struct linpool *tmp_pool) +{ + struct ea_list *tmp_attrs = NULL; + + f_rte = rte; + f_old_rta = NULL; + f_tmp_attrs = &tmp_attrs; + f_pool = tmp_pool; + f_flags = 0; + + LOG_BUFFER_INIT(f_buf); + + /* Note that in this function we assume that rte->attrs is private / uncached */ + struct f_val res = interpret(expr); + + /* Hack to include EAF_TEMP attributes to the main list */ + (*rte)->attrs->eattrs = ea_append(tmp_attrs, (*rte)->attrs->eattrs); + + return res; +} + struct f_val f_eval(struct f_inst *expr, struct linpool *tmp_pool) { diff --git a/filter/filter.h b/filter/filter.h index 2b2d23c2..e59c8226 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -107,6 +107,7 @@ struct ea_list; struct rte; int f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool, int flags); +struct f_val f_eval_rte(struct f_inst *expr, struct rte **rte, struct linpool *tmp_pool); struct f_val f_eval(struct f_inst *expr, struct linpool *tmp_pool); uint f_eval_int(struct f_inst *expr); u32 f_eval_asn(struct f_inst *expr); diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index 1bc4e077..d5d5d354 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -450,10 +450,21 @@ ospf_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool if (oa_is_stub(oa)) return -1; /* Do not export routes to stub areas */ - eattr *ea = ea_find(e->attrs->eattrs, EA_GEN_IGP_METRIC); - u32 m1 = (ea && (ea->u.data < LSINFINITY)) ? ea->u.data : LSINFINITY; + ea_list *ea = e->attrs->eattrs; + u32 m0 = ea_get_int(ea, EA_GEN_IGP_METRIC, LSINFINITY); + u32 m1 = MIN(m0, LSINFINITY); + u32 m2 = 10000; + u32 tag = 0; - *attrs = ospf_build_attrs(*attrs, pool, m1, 10000, 0, 0); + /* Hack for setting attributes directly in static protocol */ + if (e->attrs->source == RTS_STATIC) + { + m1 = ea_get_int(ea, EA_OSPF_METRIC1, m1); + m2 = ea_get_int(ea, EA_OSPF_METRIC2, 10000); + tag = ea_get_int(ea, EA_OSPF_TAG, 0); + } + + *attrs = ospf_build_attrs(*attrs, pool, m1, m2, tag, 0); return 0; /* Leave decision to the filters */ } diff --git a/proto/static/config.Y b/proto/static/config.Y index a8bfa36f..d1b62af9 100644 --- a/proto/static/config.Y +++ b/proto/static/config.Y @@ -14,6 +14,7 @@ CF_DEFINES #define STATIC_CFG ((struct static_config *) this_proto) static struct static_route *this_srt, *this_srt_nh, *last_srt_nh; +static struct f_inst **this_srt_last_cmd; CF_DECLS @@ -36,7 +37,7 @@ static_proto: | static_proto proto_item ';' | static_proto CHECK LINK bool ';' { STATIC_CFG->check_link = $4; } | static_proto IGP TABLE rtable ';' { STATIC_CFG->igp_table = $4; } - | static_proto stat_route ';' + | static_proto stat_route stat_route_opt_list ';' ; stat_route0: ROUTE prefix { @@ -44,6 +45,7 @@ stat_route0: ROUTE prefix { add_tail(&STATIC_CFG->other_routes, &this_srt->n); this_srt->net = $2.addr; this_srt->masklen = $2.len; + this_srt_last_cmd = &(this_srt->cmds); } ; @@ -94,6 +96,21 @@ stat_route: | stat_route0 PROHIBIT { this_srt->dest = RTD_PROHIBIT; } ; +stat_route_item: + cmd { *this_srt_last_cmd = $1; this_srt_last_cmd = &($1->next); } + ; + +stat_route_opts: + /* empty */ + | stat_route_opts stat_route_item + ; + +stat_route_opt_list: + /* empty */ + | '{' stat_route_opts '}' + ; + + CF_CLI(SHOW STATIC, optsym, [], [[Show details of static protocol]]) { static_show(proto_get_named($3, &proto_static)); } ; diff --git a/proto/static/static.c b/proto/static/static.c index e7e7ab15..57c44885 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -42,11 +42,14 @@ #include "nest/route.h" #include "nest/cli.h" #include "conf/conf.h" +#include "filter/filter.h" #include "lib/string.h" #include "lib/alloca.h" #include "static.h" +static linpool *static_lp; + static inline rtable * p_igp_table(struct proto *p) { @@ -54,12 +57,11 @@ p_igp_table(struct proto *p) return cf->igp_table ? cf->igp_table->table : p->table; } - static void static_install(struct proto *p, struct static_route *r, struct iface *ifa) { net *n; - rta a, *aa; + rta a; rte *e; if (r->installed > 0) @@ -108,13 +110,21 @@ static_install(struct proto *p, struct static_route *r, struct iface *ifa) if (r->dest == RTDX_RECURSIVE) rta_set_recursive_next_hop(p->table, &a, p_igp_table(p), &r->via, &r->via); - aa = rta_lookup(&a); + /* We skip rta_lookup() here */ + n = net_get(p->table, r->net, r->masklen); - e = rte_get_temp(aa); + e = rte_get_temp(&a); e->net = n; e->pflags = 0; + + if (r->cmds) + f_eval_rte(r->cmds, &e, static_lp); + rte_update(p, n, e); r->installed = 1; + + if (r->cmds) + lp_flush(static_lp); } static void @@ -220,6 +230,9 @@ static_start(struct proto *p) DBG("Static: take off!\n"); + if (!static_lp) + static_lp = lp_new(&root_pool, 1008); + if (cf->igp_table) rt_lock_table(cf->igp_table->table); @@ -413,6 +426,13 @@ static_same_dest(struct static_route *x, struct static_route *y) } } +static inline int +static_same_rte(struct static_route *x, struct static_route *y) +{ + return static_same_dest(x, y) && i_same(x->cmds, y->cmds); +} + + static void static_match(struct proto *p, struct static_route *r, struct static_config *n) { @@ -441,7 +461,7 @@ static_match(struct proto *p, struct static_route *r, struct static_config *n) found: /* If destination is different, force reinstall */ - if ((r->installed > 0) && !static_same_dest(r, t)) + if ((r->installed > 0) && !static_same_rte(r, t)) t->installed = -1; else t->installed = r->installed; diff --git a/proto/static/static.h b/proto/static/static.h index 99a0e68b..f197d352 100644 --- a/proto/static/static.h +++ b/proto/static/static.h @@ -31,6 +31,7 @@ struct static_route { struct neighbor *neigh; byte *if_name; /* Name for RTD_DEVICE routes */ struct static_route *mp_next; /* Nexthops for RTD_MULTIPATH routes */ + struct f_inst *cmds; /* List of commands for setting attributes */ int installed; /* Installed in rt table, -1 for reinstall */ }; From 538264cf1a7690d90b2953aebff21958c2b55c44 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Fri, 24 Jul 2015 18:02:07 +0200 Subject: [PATCH 17/28] Static: Support for BFD controlled static routes --- nest/bfd.h | 6 ++ proto/static/config.Y | 21 +++++- proto/static/static.c | 146 ++++++++++++++++++++++++++++++++---------- proto/static/static.h | 5 ++ 4 files changed, 141 insertions(+), 37 deletions(-) diff --git a/nest/bfd.h b/nest/bfd.h index 79c3c921..f1e95cb2 100644 --- a/nest/bfd.h +++ b/nest/bfd.h @@ -32,6 +32,12 @@ struct bfd_request { }; +#define BFD_STATE_ADMIN_DOWN 0 +#define BFD_STATE_DOWN 1 +#define BFD_STATE_INIT 2 +#define BFD_STATE_UP 3 + + #ifdef CONFIG_BFD struct bfd_request * bfd_request_session(pool *p, ip_addr addr, ip_addr local, struct iface *iface, void (*hook)(struct bfd_request *), void *data); diff --git a/proto/static/config.Y b/proto/static/config.Y index d1b62af9..182721b3 100644 --- a/proto/static/config.Y +++ b/proto/static/config.Y @@ -16,10 +16,22 @@ CF_DEFINES static struct static_route *this_srt, *this_srt_nh, *last_srt_nh; static struct f_inst **this_srt_last_cmd; +static void +static_route_finish(void) +{ + struct static_route *r; + + /* Update undefined use_bfd entries in multipath nexthops */ + if (this_srt->dest == RTD_MULTIPATH) + for (r = this_srt->mp_next; r; r = r->mp_next) + if (r->use_bfd < 0) + r->use_bfd = this_srt->use_bfd; +} + CF_DECLS CF_KEYWORDS(STATIC, ROUTE, VIA, DROP, REJECT, PROHIBIT, PREFERENCE, CHECK, LINK) -CF_KEYWORDS(MULTIPATH, WEIGHT, RECURSIVE, IGP, TABLE, BLACKHOLE, UNREACHABLE) +CF_KEYWORDS(MULTIPATH, WEIGHT, RECURSIVE, IGP, TABLE, BLACKHOLE, UNREACHABLE, BFD) CF_GRAMMAR @@ -37,7 +49,7 @@ static_proto: | static_proto proto_item ';' | static_proto CHECK LINK bool ';' { STATIC_CFG->check_link = $4; } | static_proto IGP TABLE rtable ';' { STATIC_CFG->igp_table = $4; } - | static_proto stat_route stat_route_opt_list ';' + | static_proto stat_route stat_route_opt_list ';' { static_route_finish(); } ; stat_route0: ROUTE prefix { @@ -57,11 +69,15 @@ stat_multipath1: this_srt_nh->via = $2; this_srt_nh->via_if = $3; this_srt_nh->if_name = (void *) this_srt; /* really */ + this_srt_nh->use_bfd = -1; /* undefined */ } | stat_multipath1 WEIGHT expr { this_srt_nh->masklen = $3 - 1; /* really */ if (($3<1) || ($3>256)) cf_error("Weight must be in range 1-256"); } + | stat_multipath1 BFD bool { + this_srt_nh->use_bfd = $3; cf_check_bfd($3); + } ; stat_multipath: @@ -98,6 +114,7 @@ stat_route: stat_route_item: cmd { *this_srt_last_cmd = $1; this_srt_last_cmd = &($1->next); } + | BFD bool ';' { this_srt->use_bfd = $2; cf_check_bfd($2); } ; stat_route_opts: diff --git a/proto/static/static.c b/proto/static/static.c index 57c44885..be808593 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -141,6 +141,29 @@ static_remove(struct proto *p, struct static_route *r) r->installed = 0; } +static void +static_bfd_notify(struct bfd_request *req); + +static void +static_update_bfd(struct proto *p, struct static_route *r) +{ + struct neighbor *nb = r->neigh; + int bfd_up = (nb->scope > 0) && r->use_bfd; + + if (bfd_up && !r->bfd_req) + { + // ip_addr local = ipa_nonzero(r->local) ? r->local : nb->ifa->ip; + r->bfd_req = bfd_request_session(p->pool, r->via, nb->ifa->ip, nb->iface, + static_bfd_notify, r); + } + + if (!bfd_up && r->bfd_req) + { + rfree(r->bfd_req); + r->bfd_req = NULL; + } +} + static int static_decide(struct static_config *cf, struct static_route *r) { @@ -153,6 +176,9 @@ static_decide(struct static_config *cf, struct static_route *r) if (cf->check_link && !(r->neigh->iface->flags & IF_LINK_UP)) return 0; + if (r->bfd_req && r->bfd_req->state != BFD_STATE_UP) + return 0; + return 1; } @@ -171,6 +197,8 @@ static_add(struct proto *p, struct static_config *cf, struct static_route *r) r->chain = n->data; n->data = r; r->neigh = n; + + static_update_bfd(p, r); if (static_decide(cf, r)) static_install(p, r, n->iface); else @@ -200,6 +228,8 @@ static_add(struct proto *p, struct static_config *cf, struct static_route *r) r2->chain = n->data; n->data = r2; r2->neigh = n; + + static_update_bfd(p, r2); r2->installed = static_decide(cf, r2); count += r2->installed; } @@ -222,6 +252,26 @@ static_add(struct proto *p, struct static_config *cf, struct static_route *r) } } +static void +static_rte_cleanup(struct proto *p, struct static_route *r) +{ + struct static_route *r2; + + if (r->bfd_req) + { + rfree(r->bfd_req); + r->bfd_req = NULL; + } + + if (r->dest == RTD_MULTIPATH) + for (r2 = r->mp_next; r2; r2 = r2->mp_next) + if (r2->bfd_req) + { + rfree(r2->bfd_req); + r2->bfd_req = NULL; + } +} + static int static_start(struct proto *p) { @@ -254,7 +304,10 @@ static_shutdown(struct proto *p) WALK_LIST(r, cf->iface_routes) r->installed = 0; WALK_LIST(r, cf->other_routes) + { + static_rte_cleanup(p, r); r->installed = 0; + } return PS_DOWN; } @@ -268,6 +321,44 @@ static_cleanup(struct proto *p) rt_unlock_table(cf->igp_table->table); } +static void +static_update_rte(struct proto *p, struct static_route *r) +{ + switch (r->dest) + { + case RTD_ROUTER: + if (static_decide((struct static_config *) p->cf, r)) + static_install(p, r, r->neigh->iface); + else + static_remove(p, r); + break; + + case RTD_NONE: /* a part of multipath route */ + { + int decision = static_decide((struct static_config *) p->cf, r); + if (decision == r->installed) + break; /* no change */ + r->installed = decision; + + struct static_route *r1, *r2; + int count = 0; + r1 = (void *) r->if_name; /* really */ + for (r2 = r1->mp_next; r2; r2 = r2->mp_next) + count += r2->installed; + + if (count) + { + /* Set of nexthops changed - force reinstall */ + r1->installed = 0; + static_install(p, r1, NULL); + } + else + static_remove(p, r1); + + break; + } + } +} static void static_neigh_notify(struct neighbor *n) @@ -277,40 +368,21 @@ static_neigh_notify(struct neighbor *n) DBG("Static: neighbor notify for %I: iface %p\n", n->addr, n->iface); for(r=n->data; r; r=r->chain) - switch (r->dest) - { - case RTD_ROUTER: - if (static_decide((struct static_config *) p->cf, r)) - static_install(p, r, n->iface); - else - static_remove(p, r); - break; + { + static_update_bfd(p, r); + static_update_rte(p, r); + } +} - case RTD_NONE: /* a part of multipath route */ - { - int decision = static_decide((struct static_config *) p->cf, r); - if (decision == r->installed) - break; /* no change */ - r->installed = decision; +static void +static_bfd_notify(struct bfd_request *req) +{ + struct static_route *r = req->data; + struct proto *p = r->neigh->proto; - struct static_route *r1, *r2; - int count = 0; - r1 = (void *) r->if_name; /* really */ - for (r2 = r1->mp_next; r2; r2 = r2->mp_next) - count += r2->installed; + // if (req->down) TRACE(D_EVENTS, "BFD session down for nbr %I on %s", XXXX); - if (count) - { - /* Set of nexthops changed - force reinstall */ - r1->installed = 0; - static_install(p, r1, NULL); - } - else - static_remove(p, r1); - - break; - } - } + static_update_rte(p, r); } static void @@ -414,7 +486,7 @@ static_same_dest(struct static_route *x, struct static_route *y) for (x = x->mp_next, y = y->mp_next; x && y; x = x->mp_next, y = y->mp_next) - if (!ipa_equal(x->via, y->via) || (x->via_if != y->via_if)) + if (!ipa_equal(x->via, y->via) || (x->via_if != y->via_if) || (x->use_bfd != y->use_bfd)) return 0; return !x && !y; @@ -499,6 +571,9 @@ static_reconfigure(struct proto *p, struct proto_config *new) WALK_LIST(r, n->other_routes) static_add(p, n, r); + WALK_LIST(r, o->other_routes) + static_rte_cleanup(p, r); + return 1; } @@ -584,13 +659,14 @@ static_show_rt(struct static_route *r) case RTDX_RECURSIVE: bsprintf(via, "recursive %I", r->via); break; default: bsprintf(via, "???"); } - cli_msg(-1009, "%I/%d %s%s", r->net, r->masklen, via, r->installed ? "" : " (dormant)"); + cli_msg(-1009, "%I/%d %s%s%s", r->net, r->masklen, via, + r->bfd_req ? " (bfd)" : "", r->installed ? "" : " (dormant)"); struct static_route *r2; if (r->dest == RTD_MULTIPATH) for (r2 = r->mp_next; r2; r2 = r2->mp_next) - cli_msg(-1009, "\tvia %I%J weight %d%s", r2->via, r2->via_if, r2->masklen + 1, /* really */ - r2->installed ? "" : " (dormant)"); + cli_msg(-1009, "\tvia %I%J weight %d%s%s", r2->via, r2->via_if, r2->masklen + 1, /* really */ + r2->bfd_req ? " (bfd)" : "", r2->installed ? "" : " (dormant)"); } void diff --git a/proto/static/static.h b/proto/static/static.h index f197d352..6b047234 100644 --- a/proto/static/static.h +++ b/proto/static/static.h @@ -9,6 +9,9 @@ #ifndef _BIRD_STATIC_H_ #define _BIRD_STATIC_H_ +#include "nest/route.h" +#include "nest/bfd.h" + struct static_config { struct proto_config c; list iface_routes; /* Routes to search on interface events */ @@ -33,6 +36,8 @@ struct static_route { struct static_route *mp_next; /* Nexthops for RTD_MULTIPATH routes */ struct f_inst *cmds; /* List of commands for setting attributes */ int installed; /* Installed in rt table, -1 for reinstall */ + int use_bfd; /* Configured to use BFD */ + struct bfd_request *bfd_req; /* BFD request, if BFD is used */ }; /* Dummy nodes (parts of multipath route) abuses masklen field for weight From 641172c6e5e4e291029084074f94f448d6bc69dd Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Tue, 28 Jul 2015 12:35:12 +0200 Subject: [PATCH 18/28] Netlink: Fixes uninitialized variable Thanks to Pavel Tvrdik for the bugfix --- sysdep/linux/netlink.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index 9f206e1c..9c9449e2 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -100,11 +100,12 @@ nl_request_dump(int af, int cmd) struct { struct nlmsghdr nh; struct rtgenmsg g; - } req; - req.nh.nlmsg_type = cmd; - req.nh.nlmsg_len = sizeof(req); - req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; - req.g.rtgen_family = af; + } req = { + .nh.nlmsg_type = cmd, + .nh.nlmsg_len = sizeof(req), + .nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP, + .g.rtgen_family = af + }; nl_send(&nl_scan, &req.nh); } From dbf4c0cb258bd92efb54f95194f664f95ba98fd9 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Tue, 28 Jul 2015 12:56:51 +0200 Subject: [PATCH 19/28] Minor update to test commits --- README | 1 + 1 file changed, 1 insertion(+) diff --git a/README b/README index daeb18bd..5d4bd9b2 100644 --- a/README +++ b/README @@ -64,6 +64,7 @@ What do we support: o Static routes o Inter-table protocol o IPv6 router advertisements + o Bidirectional Forwarding Detection (BFD) o Command-line interface (using the `birdc' client; to get some help, just press `?') o Soft reconfiguration -- no online commands for changing the From c7b99a932cab1873042e356143ab71755920157a Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Tue, 28 Jul 2015 15:08:21 +0200 Subject: [PATCH 20/28] Nest: Fixes one of previous commit --- nest/config.Y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nest/config.Y b/nest/config.Y index 7ad6c712..799a09f9 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -108,7 +108,7 @@ idval: $$ = SYM_VAL($1).i; #ifndef IPV6 else if ($1->class == (SYM_CONSTANT | T_IP)) - $$ = SYM_VAL($1).px.ip; + $$ = ipa_to_u32(SYM_VAL($1).px.ip); #endif else cf_error("Number of IPv4 address constant expected"); From b5e76398de1d4468b4061d9ef57dd3154b2f745e Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Wed, 19 Aug 2015 11:16:23 +0200 Subject: [PATCH 21/28] OSPF: Fixes some issues with link detection Thanks to Bernardo Figueiredo and Israel G. Lugo for the bugreport. --- proto/ospf/iface.c | 7 +++++-- proto/ospf/packet.c | 4 ++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c index 9b0f7797..77ce839a 100644 --- a/proto/ospf/iface.c +++ b/proto/ospf/iface.c @@ -493,8 +493,11 @@ ospf_iface_add(struct object_lock *lock) ifa->flood_queue = mb_allocz(ifa->pool, ifa->flood_queue_size * sizeof(void *)); } - /* Do iface UP, unless there is no link and we use link detection */ - ospf_iface_sm(ifa, (ifa->check_link && !(ifa->iface->flags & IF_LINK_UP)) ? ISM_LOOP : ISM_UP); + /* Do iface UP, unless there is no link (then wait in LOOP state) */ + if (!ifa->check_link || (ifa->iface->flags & IF_LINK_UP)) + ospf_iface_sm(ifa, ISM_UP); + else + ospf_iface_chstate(ifa, OSPF_IS_LOOP); } static inline void diff --git a/proto/ospf/packet.c b/proto/ospf/packet.c index fb63e61c..6b8fd7b5 100644 --- a/proto/ospf/packet.c +++ b/proto/ospf/packet.c @@ -231,6 +231,10 @@ ospf_rx_hook(sock *sk, int len) const char *err_dsc = NULL; uint err_val = 0; + /* Should not happen */ + if (ifa->state <= OSPF_IS_LOOP) + return 1; + int src_local, dst_local, dst_mcast; src_local = ipa_in_net(sk->faddr, ifa->addr->prefix, ifa->addr->pxlen); dst_local = ipa_equal(sk->laddr, ifa->addr->ip); From acb04cfdc550697a7171a86ca559fd8c52841acb Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Sat, 17 Oct 2015 14:36:53 +0200 Subject: [PATCH 22/28] Minor changes --- nest/route.h | 34 ++++++++++++++++++++-------------- sysdep/linux/netlink.c | 23 ++++++++++++++++------- 2 files changed, 36 insertions(+), 21 deletions(-) diff --git a/nest/route.h b/nest/route.h index 6067526d..d0f8c688 100644 --- a/nest/route.h +++ b/nest/route.h @@ -174,7 +174,7 @@ struct hostentry { ip_addr addr; /* IP address of host, part of key */ ip_addr link; /* (link-local) IP address of host, used as gw if host is directly attached */ - struct rtable *tab; /* Dependent table, part of key*/ + struct rtable *tab; /* Dependent table, part of key */ struct hostentry *next; /* Next in hash chain */ unsigned hash_key; /* Hash key */ unsigned uc; /* Use count */ @@ -507,19 +507,25 @@ void rta_show(struct cli *, rta *, ea_list *); void rta_set_recursive_next_hop(rtable *dep, rta *a, rtable *tab, ip_addr *gw, ip_addr *ll); /* - * rta_set_recursive_next_hop() acquires hostentry from hostcache and - * fills rta->hostentry field. New hostentry has zero use - * count. Cached rta locks its hostentry (increases its use count), - * uncached rta does not lock it. Hostentry with zero use count is - * removed asynchronously during host cache update, therefore it is - * safe to hold such hostentry temorarily. Hostentry holds a lock for - * a 'source' rta, mainly to share multipath nexthops. There is no - * need to hold a lock for hostentry->dep table, because that table - * contains routes responsible for that hostentry, and therefore is - * non-empty if given hostentry has non-zero use count. The protocol - * responsible for routes with recursive next hops should also hold a - * lock for a table governing that routes (argument tab to - * rta_set_recursive_next_hop()). + * rta_set_recursive_next_hop() acquires hostentry from hostcache and fills + * rta->hostentry field. New hostentry has zero use count. Cached rta locks its + * hostentry (increases its use count), uncached rta does not lock it. Hostentry + * with zero use count is removed asynchronously during host cache update, + * therefore it is safe to hold such hostentry temorarily. Hostentry holds a + * lock for a 'source' rta, mainly to share multipath nexthops. + * + * There is no need to hold a lock for hostentry->dep table, because that table + * contains routes responsible for that hostentry, and therefore is non-empty if + * given hostentry has non-zero use count. If the hostentry has zero use count, + * the entry is removed before dep is referenced. + * + * The protocol responsible for routes with recursive next hops should hold a + * lock for a 'source' table governing that routes (argument tab to + * rta_set_recursive_next_hop()), because its routes reference hostentries + * (through rta) related to the governing table. When all such routes are + * removed, rtas are immediately removed achieving zero uc. Then the 'source' + * table lock could be immediately released, although hostentries may still + * exist - they will be freed together with the 'source' table. */ static inline void rt_lock_hostentry(struct hostentry *he) { if (he) he->uc++; } diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index 9c9449e2..674d338b 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -239,6 +239,16 @@ nl_parse_attrs(struct rtattr *a, struct rtattr **k, int ksize) return 1; } +static inline ip4_addr rta_get_u32(struct rtattr *a) +{ return *(u32 *) RTA_DATA(a); } + +static inline ip4_addr rta_get_ip4(struct rtattr *a) +{ return ip4_ntoh(*(ip4_addr *) RTA_DATA(a)); } + +static inline ip6_addr rta_get_ip6(struct rtattr *a) +{ return ip6_ntoh(*(ip6_addr *) RTA_DATA(a)); } + + struct rtattr * nl_add_attr(struct nlmsghdr *h, uint bufsize, uint code, const void *data, uint dlen) { @@ -420,7 +430,7 @@ nl_parse_metrics(struct rtattr *hdr, u32 *metrics, int max) return -1; metrics[0] |= 1 << a->rta_type; - metrics[a->rta_type] = *(u32 *)RTA_DATA(a); + metrics[a->rta_type] = rta_get_u32(a); } if (len > 0) @@ -456,7 +466,7 @@ nl_parse_link(struct nlmsghdr *h, int scan) return; } name = RTA_DATA(a[IFLA_IFNAME]); - memcpy(&mtu, RTA_DATA(a[IFLA_MTU]), sizeof(u32)); + mtu = rta_get_u32(a[IFLA_MTU]); ifi = if_find_by_index(i->ifi_index); if (!new) @@ -831,7 +841,7 @@ nl_parse_route(struct nlmsghdr *h, int scan) } if (a[RTA_OIF]) - memcpy(&oif, RTA_DATA(a[RTA_OIF]), sizeof(oif)); + oif = rta_get_u32(a[RTA_OIF]); p = nl_table_map[i->rtm_table]; /* Do we know this table? */ DBG("KRT: Got %I/%d, type=%d, oif=%d, table=%d, prid=%d, proto=%s\n", dst, i->rtm_dst_len, i->rtm_type, oif, i->rtm_table, i->rtm_protocol, p ? p->p.name : "(none)"); @@ -965,11 +975,10 @@ nl_parse_route(struct nlmsghdr *h, int scan) e->u.krt.src = src; e->u.krt.proto = i->rtm_protocol; e->u.krt.type = i->rtm_type; + e->u.krt.metric = 0; if (a[RTA_PRIORITY]) - memcpy(&e->u.krt.metric, RTA_DATA(a[RTA_PRIORITY]), sizeof(e->u.krt.metric)); - else - e->u.krt.metric = 0; + e->u.krt.metric = rta_get_u32(a[RTA_PRIORITY]); if (a[RTA_PREFSRC]) { @@ -1000,7 +1009,7 @@ nl_parse_route(struct nlmsghdr *h, int scan) ea->attrs[0].id = EA_KRT_REALM; ea->attrs[0].flags = 0; ea->attrs[0].type = EAF_TYPE_INT; - memcpy(&ea->attrs[0].u.data, RTA_DATA(a[RTA_FLOW]), 4); + ea->attrs[0].u.data = rta_get_u32(a[RTA_FLOW]); } if (a[RTA_METRICS]) From 338f85ca7721fac16394ccabd561ddb5ccaacb36 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Tue, 3 Nov 2015 11:08:57 +0100 Subject: [PATCH 23/28] IO: Handle fd values too big for select() If the number of sockets is too much for select(), we should at least handle it with proper error messages and reject new sockets instead of breaking the event loop. Thanks to Alexander V. Chernikov for the patch. --- sysdep/unix/io.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index 0724667d..726f1e49 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -1309,6 +1309,16 @@ sk_passive_connected(sock *s, int type) return 0; } + if (fd >= FD_SETSIZE) + { + /* FIXME: Call err_hook instead ? */ + log(L_ERR "SOCK: Incoming connection from %I%J (port %d) %s", + t->daddr, ipa_is_link_local(t->daddr) ? t->iface : NULL, + t->dport, "rejected due to FD_SETSIZE limit"); + close(fd); + return 1; + } + sock *t = sk_new(s->pool); t->type = type; t->fd = fd; @@ -1404,6 +1414,9 @@ sk_open(sock *s) if (fd < 0) ERR("socket"); + if (fd >= FD_SETSIZE) + ERR2("FD_SETSIZE limit reached"); + s->af = af; s->fd = fd; From 3aed0a6ff7b2b811a535202fd787281d2ac33409 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Tue, 3 Nov 2015 11:27:27 +0100 Subject: [PATCH 24/28] IO: Fix the previous bugfix I should check it after making some trivial changes. The original patch from Alexander has it right. --- sysdep/unix/io.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index 726f1e49..b636e799 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -1309,16 +1309,6 @@ sk_passive_connected(sock *s, int type) return 0; } - if (fd >= FD_SETSIZE) - { - /* FIXME: Call err_hook instead ? */ - log(L_ERR "SOCK: Incoming connection from %I%J (port %d) %s", - t->daddr, ipa_is_link_local(t->daddr) ? t->iface : NULL, - t->dport, "rejected due to FD_SETSIZE limit"); - close(fd); - return 1; - } - sock *t = sk_new(s->pool); t->type = type; t->fd = fd; @@ -1338,6 +1328,18 @@ sk_passive_connected(sock *s, int type) log(L_WARN "SOCK: Cannot get remote IP address for TCP<"); } + if (fd >= FD_SETSIZE) + { + /* FIXME: Call err_hook instead ? */ + log(L_ERR "SOCK: Incoming connection from %I%J (port %d) %s", + t->daddr, ipa_is_link_local(t->daddr) ? t->iface : NULL, + t->dport, "rejected due to FD_SETSIZE limit"); + close(fd); + t->fd = -1; + rfree(t); + return 1; + } + if (sk_setup(t) < 0) { /* FIXME: Call err_hook instead ? */ From 9b9a7143c43d01f0459d40363d56e9c7690c596f Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Mon, 9 Nov 2015 00:42:02 +0100 Subject: [PATCH 25/28] Conf: Fixes bug in symbol lookup during reconfiguration Symbol lookup by cf_find_symbol() not only did the lookup but also added new void symbols allocated from cfg_mem linpool, which gets broken when lookups are done outside of config parsing, which may lead to crashes during reconfiguration. The patch separates lookup-only cf_find_symbol() and config-modifying cf_get_symbol(), while the later is called only during parsing. Also new_config and cfg_mem global variables are NULLed outside of parsing. --- conf/cf-lex.l | 64 ++++++++++++++++++++++++++++++--------------- conf/conf.c | 65 +++++++++++++++++++++++++++------------------- conf/conf.h | 4 ++- nest/proto.c | 2 +- nest/rt-roa.c | 2 +- nest/rt-table.c | 4 +-- sysdep/unix/main.c | 2 +- 7 files changed, 90 insertions(+), 53 deletions(-) diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 61e04075..5a2a4d6b 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -70,7 +70,7 @@ struct sym_scope { static struct sym_scope *conf_this_scope; static int cf_hash(byte *c); -static struct symbol *cf_find_sym(byte *c, unsigned int h0); +static inline struct symbol * cf_get_sym(byte *c, uint h0); linpool *cfg_mem; @@ -194,7 +194,7 @@ else: { } k=k->next; } - cf_lval.s = cf_find_sym(yytext, h); + cf_lval.s = cf_get_sym(yytext, h); return SYM; } @@ -426,8 +426,9 @@ check_eof(void) } static struct symbol * -cf_new_sym(byte *c, unsigned int h) +cf_new_sym(byte *c, uint h0) { + uint h = h0 & (SYM_HASH_SIZE-1); struct symbol *s, **ht; int l; @@ -449,56 +450,77 @@ cf_new_sym(byte *c, unsigned int h) } static struct symbol * -cf_find_sym(byte *c, unsigned int h0) +cf_find_sym(struct config *cfg, byte *c, uint h0) { - unsigned int h = h0 & (SYM_HASH_SIZE-1); + uint h = h0 & (SYM_HASH_SIZE-1); struct symbol *s, **ht; - if (ht = new_config->sym_hash) + if (ht = cfg->sym_hash) { for(s = ht[h]; s; s=s->next) if (!strcmp(s->name, c) && s->scope->active) return s; } - if (new_config->sym_fallback) + if (ht = cfg->sym_fallback) { /* We know only top-level scope is active */ - for(s = new_config->sym_fallback[h]; s; s=s->next) + for(s = ht[h]; s; s=s->next) if (!strcmp(s->name, c) && s->scope->active) return s; } - return cf_new_sym(c, h); + + return NULL; +} + +static inline struct symbol * +cf_get_sym(byte *c, uint h0) +{ + return cf_find_sym(new_config, c, h0) ?: cf_new_sym(c, h0); } /** * cf_find_symbol - find a symbol by name + * @cfg: specificed config * @c: symbol name * - * This functions searches the symbol table for a symbol of given - * name. First it examines the current scope, then the second recent - * one and so on until it either finds the symbol and returns a pointer - * to its &symbol structure or reaches the end of the scope chain - * and returns %NULL to signify no match. + * This functions searches the symbol table in the config @cfg for a symbol of + * given name. First it examines the current scope, then the second recent one + * and so on until it either finds the symbol and returns a pointer to its + * &symbol structure or reaches the end of the scope chain and returns %NULL to + * signify no match. */ struct symbol * -cf_find_symbol(byte *c) +cf_find_symbol(struct config *cfg, byte *c) { - return cf_find_sym(c, cf_hash(c)); + return cf_find_sym(cfg, c, cf_hash(c)); +} + +/** + * cf_get_symbol - get a symbol by name + * @c: symbol name + * + * This functions searches the symbol table of the currently parsed config + * (@new_config) for a symbol of given name. It returns either the already + * existing symbol or a newly allocated undefined (%SYM_VOID) symbol if no + * existing symbol is found. + */ +struct symbol * +cf_get_symbol(byte *c) +{ + return cf_get_sym(c, cf_hash(c)); } struct symbol * cf_default_name(char *template, int *counter) { - char buf[32]; + char buf[SYM_MAX_LEN]; struct symbol *s; char *perc = strchr(template, '%'); for(;;) { bsprintf(buf, template, ++(*counter)); - s = cf_find_sym(buf, cf_hash(buf)); - if (!s) - break; + s = cf_get_sym(buf, cf_hash(buf)); if (s->class == SYM_VOID) return s; if (!perc) @@ -529,7 +551,7 @@ cf_define_symbol(struct symbol *sym, int type, void *def) { if (sym->scope == conf_this_scope) cf_error("Symbol already defined"); - sym = cf_new_sym(sym->name, cf_hash(sym->name) & (SYM_HASH_SIZE-1)); + sym = cf_new_sym(sym->name, cf_hash(sym->name)); } sym->class = type; sym->def = def; diff --git a/conf/conf.c b/conf/conf.c index a907402d..825a8e9f 100644 --- a/conf/conf.c +++ b/conf/conf.c @@ -20,19 +20,19 @@ * * There can exist up to four different configurations at one time: an active * one (pointed to by @config), configuration we are just switching from - * (@old_config), one queued for the next reconfiguration (@future_config; - * if there is one and the user wants to reconfigure once again, we just - * free the previous queued config and replace it with the new one) and - * finally a config being parsed (@new_config). The stored @old_config - * is also used for undo reconfiguration, which works in a similar way. - * Reconfiguration could also have timeout (using @config_timer) and undo - * is automatically called if the new configuration is not confirmed later. + * (@old_config), one queued for the next reconfiguration (@future_config; if + * there is one and the user wants to reconfigure once again, we just free the + * previous queued config and replace it with the new one) and finally a config + * being parsed (@new_config). The stored @old_config is also used for undo + * reconfiguration, which works in a similar way. Reconfiguration could also + * have timeout (using @config_timer) and undo is automatically called if the + * new configuration is not confirmed later. The new config (@new_config) and + * associated linear pool (@cfg_mem) is non-NULL only during parsing. * - * Loading of new configuration is very simple: just call config_alloc() - * to get a new &config structure, then use config_parse() to parse a - * configuration file and fill all fields of the structure - * and finally ask the config manager to switch to the new - * config by calling config_commit(). + * Loading of new configuration is very simple: just call config_alloc() to get + * a new &config structure, then use config_parse() to parse a configuration + * file and fill all fields of the structure and finally ask the config manager + * to switch to the new config by calling config_commit(). * * CLI commands are parsed in a very similar way -- there is also a stripped-down * &config structure associated with them and they are lex-ed and parsed by the @@ -91,10 +91,15 @@ config_alloc(byte *name) linpool *l = lp_new(p, 4080); struct config *c = lp_allocz(l, sizeof(struct config)); + /* Duplication of name string in local linear pool */ + uint nlen = strlen(name) + 1; + char *ndup = lp_allocu(l, nlen); + memcpy(ndup, name, nlen); + c->mrtdump_file = -1; /* Hack, this should be sysdep-specific */ c->pool = p; - cfg_mem = c->mem = l; - c->file_name = cfg_strdup(name); + c->mem = l; + c->file_name = ndup; c->load_time = now; c->tf_route = c->tf_proto = (struct timeformat){"%T", "%F", 20*3600}; c->tf_base = c->tf_log = (struct timeformat){"%F %T", NULL, 0}; @@ -119,11 +124,13 @@ config_alloc(byte *name) int config_parse(struct config *c) { + int done = 0; DBG("Parsing configuration file `%s'\n", c->file_name); new_config = c; cfg_mem = c->mem; if (setjmp(conf_jmpbuf)) - return 0; + goto cleanup; + cf_lex_init(0, c); sysdep_preconfig(c); protos_preconfig(c); @@ -137,7 +144,12 @@ config_parse(struct config *c) if (!c->router_id) cf_error("Router ID must be configured manually on IPv6 routers"); #endif - return 1; + done = 1; + +cleanup: + new_config = NULL; + cfg_mem = NULL; + return done; } /** @@ -150,14 +162,22 @@ config_parse(struct config *c) int cli_parse(struct config *c) { - new_config = c; + int done = 0; c->sym_fallback = config->sym_hash; + new_config = c; cfg_mem = c->mem; if (setjmp(conf_jmpbuf)) - return 0; + goto cleanup; + cf_lex_init(1, c); cf_parse(); - return 1; + done = 1; + +cleanup: + c->sym_fallback = NULL; + new_config = NULL; + cfg_mem = NULL; + return done; } /** @@ -237,10 +257,6 @@ config_do_commit(struct config *c, int type) if (old_config && !config->shutdown) log(L_INFO "Reconfiguring"); - /* This should not be necessary, but it seems there are some - functions that access new_config instead of config */ - new_config = config; - if (old_config) old_config->obstacle_count++; @@ -254,9 +270,6 @@ config_do_commit(struct config *c, int type) DBG("protos_commit\n"); protos_commit(c, old_config, force_restart, type); - /* Just to be sure nobody uses that now */ - new_config = NULL; - int obs = 0; if (old_config) obs = --old_config->obstacle_count; diff --git a/conf/conf.h b/conf/conf.h index 515efbb3..89a2c5b7 100644 --- a/conf/conf.h +++ b/conf/conf.h @@ -147,7 +147,9 @@ int cf_lex(void); void cf_lex_init(int is_cli, struct config *c); void cf_lex_unwind(void); -struct symbol *cf_find_symbol(byte *c); +struct symbol *cf_find_symbol(struct config *cfg, byte *c); + +struct symbol *cf_get_symbol(byte *c); struct symbol *cf_default_name(char *template, int *counter); struct symbol *cf_define_symbol(struct symbol *symbol, int type, void *def); void cf_push_scope(struct symbol *); diff --git a/nest/proto.c b/nest/proto.c index 6531083c..d04da333 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -521,7 +521,7 @@ protos_commit(struct config *new, struct config *old, int force_reconfig, int ty WALK_LIST(oc, old->protos) { p = oc->proto; - sym = cf_find_symbol(oc->name); + sym = cf_find_symbol(new, oc->name); if (sym && sym->class == SYM_PROTO && !new->shutdown) { /* Found match, let's check if we can smoothly switch to new configuration */ diff --git a/nest/rt-roa.c b/nest/rt-roa.c index aa453f16..0fd89667 100644 --- a/nest/rt-roa.c +++ b/nest/rt-roa.c @@ -311,7 +311,7 @@ roa_commit(struct config *new, struct config *old) if (old) WALK_LIST(t, roa_table_list) { - struct symbol *sym = cf_find_symbol(t->name); + struct symbol *sym = cf_find_symbol(new, t->name); if (sym && sym->class == SYM_ROA) { /* Found old table in new config */ diff --git a/nest/rt-table.c b/nest/rt-table.c index 9e2c4e0d..2ddff12e 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -1663,7 +1663,7 @@ rt_prune_loop(void) void rt_preconfig(struct config *c) { - struct symbol *s = cf_find_symbol("master"); + struct symbol *s = cf_get_symbol("master"); init_list(&c->tables); c->master_rtc = rt_new_table(s); @@ -1903,7 +1903,7 @@ rt_commit(struct config *new, struct config *old) rtable *ot = o->table; if (!ot->deleted) { - struct symbol *sym = cf_find_symbol(o->name); + struct symbol *sym = cf_find_symbol(new, o->name); if (sym && sym->class == SYM_TABLE && !new->shutdown) { DBG("\t%s: same\n", o->name); diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c index e31471da..24d34f60 100644 --- a/sysdep/unix/main.c +++ b/sysdep/unix/main.c @@ -96,7 +96,7 @@ drop_gid(gid_t gid) static inline void add_num_const(char *name, int val) { - struct symbol *s = cf_find_symbol(name); + struct symbol *s = cf_get_symbol(name); s->class = SYM_CONSTANT | T_INT; s->def = cfg_allocz(sizeof(struct f_val)); SYM_TYPE(s) = T_INT; From 86b4e17001fe4cca6dde7ff523346121c0ae68fe Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Mon, 9 Nov 2015 01:01:12 +0100 Subject: [PATCH 26/28] Nest: Fixes bug in missing cleanup during table removal When a table is removed during reconfiguration, a reference was not cleared in the old configuration, which breaks undo. --- nest/rt-table.c | 1 + 1 file changed, 1 insertion(+) diff --git a/nest/rt-table.c b/nest/rt-table.c index 2ddff12e..10ce400a 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -1868,6 +1868,7 @@ rt_unlock_table(rtable *r) { struct config *conf = r->deleted; DBG("Deleting routing table %s\n", r->name); + r->config->table = NULL; if (r->hostcache) rt_free_hostcache(r); rem_node(&r->n); From 9ddbfbddf87462bbf50437bdc1d44499a5c223e7 Mon Sep 17 00:00:00 2001 From: Jan Moskyto Matejka Date: Tue, 3 Nov 2015 14:42:41 +0100 Subject: [PATCH 27/28] Netlink: Allow more than 256 routing tables. Since 2.6.19, the netlink API defines RTA_TABLE routing attribute to allow 32-bit routing table IDs. Using this attribute to index routing tables at Linux, instead of 8-bit rtm_table field. --- sysdep/bsd/krt-sock.c | 7 +++- sysdep/bsd/krt-sys.h | 1 + sysdep/linux/krt-sys.h | 8 ++-- sysdep/linux/netlink.Y | 2 - sysdep/linux/netlink.c | 90 ++++++++++++++++++++++++++++-------------- sysdep/unix/krt.c | 11 +++++- sysdep/unix/krt.h | 3 +- 7 files changed, 82 insertions(+), 40 deletions(-) diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c index 064bae18..29203d1b 100644 --- a/sysdep/bsd/krt-sock.c +++ b/sysdep/bsd/krt-sock.c @@ -970,13 +970,15 @@ krt_sock_close_shared(void) } } -void +int krt_sys_start(struct krt_proto *p) { krt_table_map[KRT_CF->sys.table_id] = p; krt_sock_open_shared(); p->sys.sk = krt_sock; + + return 1; } void @@ -992,10 +994,11 @@ krt_sys_shutdown(struct krt_proto *p) #else -void +int krt_sys_start(struct krt_proto *p) { p->sys.sk = krt_sock_open(p->p.pool, p, KRT_CF->sys.table_id); + return 1; } void diff --git a/sysdep/bsd/krt-sys.h b/sysdep/bsd/krt-sys.h index 2c6e35c5..a63f8caf 100644 --- a/sysdep/bsd/krt-sys.h +++ b/sysdep/bsd/krt-sys.h @@ -42,6 +42,7 @@ struct krt_state { }; +static inline void krt_sys_io_init(void) { } static inline void krt_sys_init(struct krt_proto *p UNUSED) { } static inline int krt_sys_get_attr(eattr *a UNUSED, byte *buf UNUSED, int buflen UNUSED) { } diff --git a/sysdep/linux/krt-sys.h b/sysdep/linux/krt-sys.h index e32e4fe1..7fd5f139 100644 --- a/sysdep/linux/krt-sys.h +++ b/sysdep/linux/krt-sys.h @@ -84,18 +84,18 @@ static inline struct ifa * kif_get_primary_ip(struct iface *i) { return NULL; } #define EA_KRT_FEATURE_ALLFRAG EA_KRT_FEATURES | EA_BIT(0x3) - -#define NL_NUM_TABLES 256 - struct krt_params { - int table_id; /* Kernel table ID we sync with */ + u32 table_id; /* Kernel table ID we sync with */ }; struct krt_state { + struct krt_proto *hash_next; }; static inline void krt_sys_init(struct krt_proto *p UNUSED) { } +static inline void krt_sys_preconfig(struct config *c UNUSED) { } +static inline void krt_sys_postconfig(struct krt_config *x UNUSED) { } #endif diff --git a/sysdep/linux/netlink.Y b/sysdep/linux/netlink.Y index f8137e23..e9c225a2 100644 --- a/sysdep/linux/netlink.Y +++ b/sysdep/linux/netlink.Y @@ -23,8 +23,6 @@ CF_ADDTO(kern_proto, kern_proto kern_sys_item ';') kern_sys_item: KERNEL TABLE expr { - if ($3 <= 0 || $3 >= NL_NUM_TABLES) - cf_error("Kernel routing table number out of range"); THIS_KRT->sys.table_id = $3; } ; diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index 674d338b..db998926 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -25,6 +25,7 @@ #include "lib/krt.h" #include "lib/socket.h" #include "lib/string.h" +#include "lib/hash.h" #include "conf/conf.h" #include @@ -32,6 +33,7 @@ #include #include + #ifndef MSG_TRUNC /* Hack: Several versions of glibc miss this one :( */ #define MSG_TRUNC 0x20 #endif @@ -40,6 +42,11 @@ #define IFF_LOWER_UP 0x10000 #endif +#ifndef RTA_TABLE +#define RTA_TABLE 15 +#endif + + /* * Synchronous Netlink interface */ @@ -650,7 +657,23 @@ kif_do_scan(struct kif_proto *p UNUSED) * Routes */ -static struct krt_proto *nl_table_map[NL_NUM_TABLES]; +static inline u32 +krt_table_id(struct krt_proto *p) +{ + return KRT_CF->sys.table_id; +} + +static HASH(struct krt_proto) nl_table_map; + +#define RTH_FN(k) u32_hash(k) +#define RTH_EQ(k1,k2) k1 == k2 +#define RTH_KEY(p) krt_table_id(p) +#define RTH_NEXT(p) p->sys.hash_next + +#define RTH_REHASH rth_rehash +#define RTH_PARAMS /8, *2, 2, 2, 6, 20 + +HASH_DEFINE_REHASH_FN(RTH, struct krt_proto) int krt_capable(rte *e) @@ -708,12 +731,15 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int new) r.r.rtm_family = BIRD_AF; r.r.rtm_dst_len = net->n.pxlen; - r.r.rtm_tos = 0; - r.r.rtm_table = KRT_CF->sys.table_id; r.r.rtm_protocol = RTPROT_BIRD; r.r.rtm_scope = RT_SCOPE_UNIVERSE; nl_add_attr_ipa(&r.h, sizeof(r), RTA_DST, net->n.prefix); + if (krt_table_id(p) < 256) + r.r.rtm_table = krt_table_id(p); + else + nl_add_attr_u32(&r.h, sizeof(r), RTA_TABLE, krt_table_id(p)); + /* For route delete, we do not specify route attributes */ if (!new) return nl_exchange(&r.h); @@ -809,11 +835,12 @@ nl_parse_route(struct nlmsghdr *h, int scan) { struct krt_proto *p; struct rtmsg *i; - struct rtattr *a[RTA_CACHEINFO+1]; + struct rtattr *a[RTA_TABLE+1]; int new = h->nlmsg_type == RTM_NEWROUTE; ip_addr dst = IPA_NONE; u32 oif = ~0; + u32 table; int src; if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(RTM_RTA(i), a, sizeof(a))) @@ -825,6 +852,7 @@ nl_parse_route(struct nlmsghdr *h, int scan) (a[RTA_IIF] && RTA_PAYLOAD(a[RTA_IIF]) != 4) || #endif (a[RTA_OIF] && RTA_PAYLOAD(a[RTA_OIF]) != 4) || + (a[RTA_TABLE] && RTA_PAYLOAD(a[RTA_TABLE]) != 4) || (a[RTA_GATEWAY] && RTA_PAYLOAD(a[RTA_GATEWAY]) != sizeof(ip_addr)) || (a[RTA_PRIORITY] && RTA_PAYLOAD(a[RTA_PRIORITY]) != 4) || (a[RTA_PREFSRC] && RTA_PAYLOAD(a[RTA_PREFSRC]) != sizeof(ip_addr)) || @@ -843,10 +871,15 @@ nl_parse_route(struct nlmsghdr *h, int scan) if (a[RTA_OIF]) oif = rta_get_u32(a[RTA_OIF]); - p = nl_table_map[i->rtm_table]; /* Do we know this table? */ - DBG("KRT: Got %I/%d, type=%d, oif=%d, table=%d, prid=%d, proto=%s\n", dst, i->rtm_dst_len, i->rtm_type, oif, i->rtm_table, i->rtm_protocol, p ? p->p.name : "(none)"); + if (a[RTA_TABLE]) + table = rta_get_u32(a[RTA_TABLE]); + else + table = i->rtm_table; + + p = HASH_FIND(nl_table_map, RTH, table); /* Do we know this table? */ + DBG("KRT: Got %I/%d, type=%d, oif=%d, table=%d, prid=%d, proto=%s\n", dst, i->rtm_dst_len, i->rtm_type, oif, table, i->rtm_protocol, p ? p->p.name : "(none)"); if (!p) - SKIP("unknown table %d\n", i->rtm_table); + SKIP("unknown table %d\n", table); #ifdef IPV6 @@ -1186,25 +1219,41 @@ nl_open_async(void) bug("Netlink: sk_open failed"); } + /* * Interface to the UNIX krt module */ -static u8 nl_cf_table[(NL_NUM_TABLES+7) / 8]; - void +krt_sys_io_init(void) +{ + HASH_INIT(nl_table_map, krt_pool, 6); +} + +int krt_sys_start(struct krt_proto *p) { - nl_table_map[KRT_CF->sys.table_id] = p; + struct krt_proto *old = HASH_FIND(nl_table_map, RTH, krt_table_id(p)); + + if (old) + { + log(L_ERR "%s: Kernel table %u already registered by %s", + p->p.name, krt_table_id(p), old->p.name); + return 0; + } + + HASH_INSERT2(nl_table_map, RTH, krt_pool, p); nl_open(); nl_open_async(); + + return 1; } void -krt_sys_shutdown(struct krt_proto *p UNUSED) +krt_sys_shutdown(struct krt_proto *p) { - nl_table_map[KRT_CF->sys.table_id] = NULL; + HASH_REMOVE2(nl_table_map, RTH, krt_pool, p); } int @@ -1213,23 +1262,6 @@ krt_sys_reconfigure(struct krt_proto *p UNUSED, struct krt_config *n, struct krt return n->sys.table_id == o->sys.table_id; } - -void -krt_sys_preconfig(struct config *c UNUSED) -{ - bzero(&nl_cf_table, sizeof(nl_cf_table)); -} - -void -krt_sys_postconfig(struct krt_config *x) -{ - int id = x->sys.table_id; - - if (nl_cf_table[id/8] & (1 << (id%8))) - cf_error("Multiple kernel syncers defined for table #%d", id); - nl_cf_table[id/8] |= (1 << (id%8)); -} - void krt_sys_init_config(struct krt_config *cf) { diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index 2eab5cb2..49bf9519 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -77,6 +77,7 @@ krt_io_init(void) krt_pool = rp_new(&root_pool, "Kernel Syncer"); krt_filter_lp = lp_new(krt_pool, 4080); init_list(&krt_proto_list); + krt_sys_io_init(); } /* @@ -1126,7 +1127,11 @@ krt_start(struct proto *P) krt_learn_init(p); #endif - krt_sys_start(p); + if (!krt_sys_start(p)) + { + rem_node(&p->krt_node); + return PS_START; + } krt_scan_timer_start(p); @@ -1150,8 +1155,10 @@ krt_shutdown(struct proto *P) p->ready = 0; p->initialized = 0; - krt_sys_shutdown(p); + if (p->p.proto_state == PS_START) + return PS_DOWN; + krt_sys_shutdown(p); rem_node(&p->krt_node); return PS_DOWN; diff --git a/sysdep/unix/krt.h b/sysdep/unix/krt.h index 9d5d4e8c..aea20102 100644 --- a/sysdep/unix/krt.h +++ b/sysdep/unix/krt.h @@ -119,8 +119,9 @@ struct proto_config * krt_init_config(int class); /* krt sysdep */ +void krt_sys_io_init(void); void krt_sys_init(struct krt_proto *); -void krt_sys_start(struct krt_proto *); +int krt_sys_start(struct krt_proto *); void krt_sys_shutdown(struct krt_proto *); int krt_sys_reconfigure(struct krt_proto *p UNUSED, struct krt_config *n, struct krt_config *o); From fce764f90e8331d1adb6a85ec00136dfeae1a398 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Tvrd=C3=ADk?= Date: Mon, 9 Nov 2015 09:14:26 +0100 Subject: [PATCH 28/28] Fix compiling with --enable-debug option --- sysdep/linux/netlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index db998926..f2f60100 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -246,7 +246,7 @@ nl_parse_attrs(struct rtattr *a, struct rtattr **k, int ksize) return 1; } -static inline ip4_addr rta_get_u32(struct rtattr *a) +static inline u32 rta_get_u32(struct rtattr *a) { return *(u32 *) RTA_DATA(a); } static inline ip4_addr rta_get_ip4(struct rtattr *a)