diff options
-rw-r--r-- | lib/printf.c | 16 | ||||
-rw-r--r-- | lib/printf_test.c | 37 | ||||
-rw-r--r-- | lib/string.h | 9 | ||||
-rw-r--r-- | nest/bfd.h | 5 | ||||
-rw-r--r-- | nest/config.Y | 5 | ||||
-rw-r--r-- | nest/iface.c | 4 | ||||
-rw-r--r-- | nest/neighbor.c | 11 | ||||
-rw-r--r-- | nest/proto.c | 8 | ||||
-rw-r--r-- | nest/protocol.h | 2 | ||||
-rw-r--r-- | proto/bfd/bfd.c | 21 | ||||
-rw-r--r-- | proto/bfd/config.Y | 4 | ||||
-rw-r--r-- | proto/bfd/packets.c | 2 | ||||
-rw-r--r-- | proto/bgp/bgp.c | 8 | ||||
-rw-r--r-- | proto/ospf/neighbor.c | 7 | ||||
-rw-r--r-- | proto/ospf/ospf.c | 2 | ||||
-rw-r--r-- | proto/rip/rip.c | 3 | ||||
-rw-r--r-- | proto/rpki/rpki.c | 6 | ||||
-rw-r--r-- | proto/static/static.c | 3 | ||||
-rw-r--r-- | sysdep/linux/netlink.c | 68 | ||||
-rw-r--r-- | sysdep/unix/log.c | 3 |
20 files changed, 145 insertions, 79 deletions
diff --git a/lib/printf.c b/lib/printf.c index c2065d9a..8f2cccb3 100644 --- a/lib/printf.c +++ b/lib/printf.c @@ -356,14 +356,14 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args) if (qualifier == 'l') { X = va_arg(args, u64); bsprintf(ipbuf, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", - ((X >> 56) & 0xff), - ((X >> 48) & 0xff), - ((X >> 40) & 0xff), - ((X >> 32) & 0xff), - ((X >> 24) & 0xff), - ((X >> 16) & 0xff), - ((X >> 8) & 0xff), - (X & 0xff)); + (uint) ((X >> 56) & 0xff), + (uint) ((X >> 48) & 0xff), + (uint) ((X >> 40) & 0xff), + (uint) ((X >> 32) & 0xff), + (uint) ((X >> 24) & 0xff), + (uint) ((X >> 16) & 0xff), + (uint) ((X >> 8) & 0xff), + (uint) (X & 0xff)); } else { diff --git a/lib/printf_test.c b/lib/printf_test.c index a2683d93..341fde9c 100644 --- a/lib/printf_test.c +++ b/lib/printf_test.c @@ -56,6 +56,27 @@ t_simple(void) BSPRINTF(2, "-1", buf, "%d", -1); BSPRINTF(11, "-2147483648", buf, "%d", -2147483648); + return 1; +} + +static int +t_router_id(void) +{ + char buf[256]; + + BSPRINTF(7, "1.2.3.4", buf, "%R", (u32) 0x01020304); + BSPRINTF(15, "240.224.208.192", buf, "%R", (u32) 0xF0E0D0C0); + BSPRINTF(23, "01:02:03:04:05:06:07:08", buf, "%lR", (u64) 0x0102030405060708); + BSPRINTF(23, "f0:e0:d0:c0:b0:a0:90:80", buf, "%lR", (u64) 0xF0E0D0C0B0A09080); + + return 1; +} + +static int +t_time(void) +{ + char buf[256]; + BSPRINTF(7, "123.456", buf, "%t", (btime) 123456789); BSPRINTF(7, "123.456", buf, "%2t", (btime) 123456789); BSPRINTF(8, " 123.456", buf, "%8t", (btime) 123456789); @@ -68,12 +89,28 @@ t_simple(void) return 1; } +static int +t_bstrcmp(void) +{ + bt_assert(bstrcmp("aa", "aa") == 0); + bt_assert(bstrcmp("aa", "bb") == -1); + bt_assert(bstrcmp("bb", "aa") == 1); + bt_assert(bstrcmp(NULL, NULL) == 0); + bt_assert(bstrcmp(NULL, "bb") == -1); + bt_assert(bstrcmp("bb", NULL) == 1); + + return 1; +} + int main(int argc, char *argv[]) { bt_init(argc, argv); bt_test_suite(t_simple, "printf without varargs"); + bt_test_suite(t_router_id, "print router id"); + bt_test_suite(t_time, "print time"); + bt_test_suite(t_bstrcmp, "bstrcmp"); return bt_exit_value(); } diff --git a/lib/string.h b/lib/string.h index 6e549cb7..d6ae5ef7 100644 --- a/lib/string.h +++ b/lib/string.h @@ -63,6 +63,15 @@ memset32(void *D, u32 val, uint n) dst[i] = val; } +static inline int +bstrcmp(const char *s1, const char *s2) +{ + if (s1 && s2) + return strcmp(s1, s2); + else + return !s2 - !s1; +} + #define ROUTER_ID_64_LENGTH 23 #endif @@ -19,6 +19,7 @@ struct bfd_request { ip_addr addr; ip_addr local; struct iface *iface; + struct iface *vrf; void (*hook)(struct bfd_request *); void *data; @@ -40,13 +41,13 @@ struct bfd_request { #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); +struct bfd_request * bfd_request_session(pool *p, ip_addr addr, ip_addr local, struct iface *iface, struct iface *vrf, void (*hook)(struct bfd_request *), void *data); static inline void cf_check_bfd(int use UNUSED) { } #else -static inline struct bfd_request * bfd_request_session(pool *p UNUSED, ip_addr addr UNUSED, ip_addr local UNUSED, struct iface *iface UNUSED, void (*hook)(struct bfd_request *) UNUSED, void *data UNUSED) { return NULL; } +static inline struct bfd_request * bfd_request_session(pool *p UNUSED, ip_addr addr UNUSED, ip_addr local UNUSED, struct iface *iface UNUSED, struct iface *vrf UNUSED, void (*hook)(struct bfd_request *) UNUSED, void *data UNUSED) { return NULL; } static inline void cf_check_bfd(int use) { if (use) cf_error("BFD not available"); } diff --git a/nest/config.Y b/nest/config.Y index e97b8fb3..4c4b6c33 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -65,7 +65,7 @@ proto_postconfig(void) CF_DECLS CF_KEYWORDS(ROUTER, ID, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT) -CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, VRF, TABLE, STATES, ROUTES, FILTERS) +CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, VRF, DEFAULT, TABLE, STATES, ROUTES, FILTERS) CF_KEYWORDS(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, SADR, MPLS) CF_KEYWORDS(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED) CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES) @@ -211,7 +211,8 @@ proto_item: | MRTDUMP mrtdump_mask { this_proto->mrtdump = $2; } | ROUTER ID idval { this_proto->router_id = $3; } | DESCRIPTION text { this_proto->dsc = $2; } - | VRF text { this_proto->vrf = if_get_by_name($2); } + | VRF text { this_proto->vrf = if_get_by_name($2); this_proto->vrf_set = 1; } + | VRF DEFAULT { this_proto->vrf = NULL; this_proto->vrf_set = 1; } ; diff --git a/nest/iface.c b/nest/iface.c index c1966ac6..00dfc2ca 100644 --- a/nest/iface.c +++ b/nest/iface.c @@ -147,7 +147,7 @@ ifa_send_notify(struct proto *p, unsigned c, struct ifa *a) { if (p->ifa_notify && (p->proto_state != PS_DOWN) && - (!p->vrf || p->vrf == a->iface->master)) + (!p->vrf_set || p->vrf == a->iface->master)) { if (p->debug & D_IFACES) log(L_TRACE "%s < address %N on interface %s %s", @@ -185,7 +185,7 @@ if_send_notify(struct proto *p, unsigned c, struct iface *i) { if (p->if_notify && (p->proto_state != PS_DOWN) && - (!p->vrf || p->vrf == i->master)) + (!p->vrf_set || p->vrf == i->master)) { if (p->debug & D_IFACES) log(L_TRACE "%s < interface %s %s", p->name, i->name, diff --git a/nest/neighbor.c b/nest/neighbor.c index 87253857..00a8e8a5 100644 --- a/nest/neighbor.c +++ b/nest/neighbor.c @@ -116,7 +116,7 @@ if_connected(ip_addr a, struct iface *i, struct ifa **ap, uint flags) } static inline int -if_connected_any(ip_addr a, struct iface *vrf, struct iface **iface, struct ifa **addr, uint flags) +if_connected_any(ip_addr a, struct iface *vrf, uint vrf_set, struct iface **iface, struct ifa **addr, uint flags) { struct iface *i; struct ifa *b; @@ -127,7 +127,7 @@ if_connected_any(ip_addr a, struct iface *vrf, struct iface **iface, struct ifa /* Get first match, but prefer SCOPE_HOST to other matches */ WALK_LIST(i, iface_list) - if ((!vrf || vrf == i->master) && ((s = if_connected(a, i, &b, flags)) >= 0)) + if ((!vrf_set || vrf == i->master) && ((s = if_connected(a, i, &b, flags)) >= 0)) if ((scope < 0) || ((scope > SCOPE_HOST) && (s == SCOPE_HOST))) { *iface = i; @@ -192,7 +192,7 @@ neigh_find(struct proto *p, ip_addr a, struct iface *iface, uint flags) iface = (scope < 0) ? NULL : iface; } else - scope = if_connected_any(a, p->vrf, &iface, &addr, flags); + scope = if_connected_any(a, p->vrf, p->vrf_set, &iface, &addr, flags); /* scope < 0 means i don't know neighbor */ /* scope >= 0 <=> iface != NULL */ @@ -309,6 +309,7 @@ neigh_free(neighbor *n) void neigh_update(neighbor *n, struct iface *iface) { + struct proto *p = n->proto; struct ifa *ifa = NULL; int scope = -1; @@ -317,14 +318,14 @@ neigh_update(neighbor *n, struct iface *iface) return; /* VRF-bound neighbors ignore changes in other VRFs */ - if (n->proto->vrf && (n->proto->vrf != iface->master)) + if (p->vrf_set && (p->vrf != iface->master)) return; scope = if_connected(n->addr, iface, &ifa, n->flags); /* When neighbor is going down, try to respawn it on other ifaces */ if ((scope < 0) && (n->scope >= 0) && !n->ifreq && (n->flags & NEF_STICKY)) - scope = if_connected_any(n->addr, n->proto->vrf, &iface, &ifa, n->flags); + scope = if_connected_any(n->addr, p->vrf, p->vrf_set, &iface, &ifa, n->flags); /* No change or minor change - ignore or notify */ if ((scope == n->scope) && (iface == n->iface)) diff --git a/nest/proto.c b/nest/proto.c index 9d0990de..2fb4e96f 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -765,6 +765,7 @@ proto_init(struct proto_config *c, node *n) p->proto_state = PS_DOWN; p->last_state_change = current_time(); p->vrf = c->vrf; + p->vrf_set = c->vrf_set; insert_node(&p->n, n); p->event = ev_new_init(proto_pool, proto_event, p); @@ -932,7 +933,8 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config if ((nc->protocol != oc->protocol) || (nc->net_type != oc->net_type) || (nc->disabled != p->disabled) || - (nc->vrf != oc->vrf)) + (nc->vrf != oc->vrf) || + (nc->vrf_set != oc->vrf_set)) return 0; p->name = nc->name; @@ -1838,8 +1840,8 @@ proto_cmd_show(struct proto *p, uintptr_t verbose, int cnt) cli_msg(-1006, " Message: %s", p->message); if (p->cf->router_id) cli_msg(-1006, " Router ID: %R", p->cf->router_id); - if (p->vrf) - cli_msg(-1006, " VRF: %s", p->vrf->name); + if (p->vrf_set) + cli_msg(-1006, " VRF: %s", p->vrf ? p->vrf->name : "default"); if (p->proto->show_proto_info) p->proto->show_proto_info(p); diff --git a/nest/protocol.h b/nest/protocol.h index b6f414f6..da12c771 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -120,6 +120,7 @@ struct proto_config { int class; /* SYM_PROTO or SYM_TEMPLATE */ u8 net_type; /* Protocol network type (NET_*), 0 for undefined */ u8 disabled; /* Protocol enabled/disabled by default */ + u8 vrf_set; /* Related VRF instance (below) is defined */ u32 debug, mrtdump; /* Debugging bitfields, both use D_* constants */ u32 router_id; /* Protocol specific router ID */ @@ -176,6 +177,7 @@ struct proto { uint active_channels; /* Number of active channels */ byte net_type; /* Protocol network type (NET_*), 0 for undefined */ byte disabled; /* Manually disabled */ + byte vrf_set; /* Related VRF instance (above) is defined */ byte proto_state; /* Protocol state machine (PS_*, see below) */ byte active; /* From PS_START to cleanup after PS_STOP */ byte do_start; /* Start actions are scheduled */ diff --git a/proto/bfd/bfd.c b/proto/bfd/bfd.c index fdcd7225..93073070 100644 --- a/proto/bfd/bfd.c +++ b/proto/bfd/bfd.c @@ -624,6 +624,9 @@ bfd_request_notify(struct bfd_request *req, u8 state, u8 diag) static int bfd_add_request(struct bfd_proto *p, struct bfd_request *req) { + if (p->p.vrf_set && (p->p.vrf != req->vrf)) + return 0; + struct bfd_session *s = bfd_find_session_by_addr(p, req->addr); u8 state, diag; @@ -685,7 +688,8 @@ bfd_drop_requests(struct bfd_proto *p) static struct resclass bfd_request_class; struct bfd_request * -bfd_request_session(pool *p, ip_addr addr, ip_addr local, struct iface *iface, +bfd_request_session(pool *p, ip_addr addr, ip_addr local, + struct iface *iface, struct iface *vrf, void (*hook)(struct bfd_request *), void *data) { struct bfd_request *req = ralloc(p, &bfd_request_class); @@ -696,6 +700,7 @@ bfd_request_session(pool *p, ip_addr addr, ip_addr local, struct iface *iface, req->addr = addr; req->local = local; req->iface = iface; + req->vrf = vrf; bfd_submit_request(req); @@ -754,7 +759,7 @@ bfd_neigh_notify(struct neighbor *nb) if ((nb->scope > 0) && !n->req) { ip_addr local = ipa_nonzero(n->local) ? n->local : nb->ifa->ip; - n->req = bfd_request_session(p->p.pool, n->addr, local, nb->iface, NULL, NULL); + n->req = bfd_request_session(p->p.pool, n->addr, local, nb->iface, p->p.vrf, NULL, NULL); } if ((nb->scope <= 0) && n->req) @@ -771,7 +776,7 @@ bfd_start_neighbor(struct bfd_proto *p, struct bfd_neighbor *n) if (n->multihop) { - n->req = bfd_request_session(p->p.pool, n->addr, n->local, NULL, NULL, NULL); + n->req = bfd_request_session(p->p.pool, n->addr, n->local, NULL, p->p.vrf, NULL, NULL); return; } @@ -1051,15 +1056,6 @@ bfd_reconfigure(struct proto *P, struct proto_config *c) return 1; } -/* Ensure one instance */ -struct bfd_config *bfd_cf; - -static void -bfd_preconfig(struct protocol *P UNUSED, struct config *c UNUSED) -{ - bfd_cf = NULL; -} - static void bfd_copy_config(struct proto_config *dest, struct proto_config *src UNUSED) { @@ -1123,6 +1119,5 @@ struct protocol proto_bfd = { .start = bfd_start, .shutdown = bfd_shutdown, .reconfigure = bfd_reconfigure, - .preconfig = bfd_preconfig, .copy_config = bfd_copy_config, }; diff --git a/proto/bfd/config.Y b/proto/bfd/config.Y index 41228e51..ed416f25 100644 --- a/proto/bfd/config.Y +++ b/proto/bfd/config.Y @@ -38,10 +38,6 @@ bfd_proto_start: proto_start BFD this_proto = proto_config_new(&proto_bfd, $1); init_list(&BFD_CFG->patt_list); init_list(&BFD_CFG->neigh_list); - - if (bfd_cf) - cf_error("Only one BFD instance allowed"); - bfd_cf = BFD_CFG; }; bfd_proto_item: diff --git a/proto/bfd/packets.c b/proto/bfd/packets.c index 6d5151ea..703c6e28 100644 --- a/proto/bfd/packets.c +++ b/proto/bfd/packets.c @@ -413,6 +413,7 @@ bfd_open_rx_sk(struct bfd_proto *p, int multihop, int af) sk->type = SK_UDP; sk->subtype = af; sk->sport = !multihop ? BFD_CONTROL_PORT : BFD_MULTI_CTL_PORT; + sk->vrf = p->p.vrf; sk->data = p; sk->rbsize = BFD_MAX_LEN; @@ -444,6 +445,7 @@ bfd_open_tx_sk(struct bfd_proto *p, ip_addr local, struct iface *ifa) sk->saddr = local; sk->dport = ifa ? BFD_CONTROL_PORT : BFD_MULTI_CTL_PORT; sk->iface = ifa; + sk->vrf = p->p.vrf; sk->data = p; sk->tbsize = BFD_MAX_LEN; diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index b68575a5..5a403b40 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -1371,7 +1371,7 @@ bgp_update_bfd(struct bgp_proto *p, int use_bfd) if (use_bfd && !p->bfd_req && !bgp_is_dynamic(p)) p->bfd_req = bfd_request_session(p->p.pool, p->remote_ip, p->local_ip, p->cf->multihop ? NULL : p->neigh->iface, - bgp_bfd_notify, p); + p->p.vrf, bgp_bfd_notify, p); if (!use_bfd && p->bfd_req) { @@ -2011,12 +2011,10 @@ bgp_reconfigure(struct proto *P, struct proto_config *CF) ((byte *) new) + sizeof(struct proto_config), // password item is last and must be checked separately OFFSETOF(struct bgp_config, password) - sizeof(struct proto_config)) - && ((!old->password && !new->password) - || (old->password && new->password && !strcmp(old->password, new->password))) + && !bstrcmp(old->password, new->password) && ((!old->remote_range && !new->remote_range) || (old->remote_range && new->remote_range && net_equal(old->remote_range, new->remote_range))) - && ((!old->dynamic_name && !new->dynamic_name) - || (old->dynamic_name && new->dynamic_name && !strcmp(old->dynamic_name, new->dynamic_name))) + && !bstrcmp(old->dynamic_name, new->dynamic_name) && (old->dynamic_name_digits == new->dynamic_name_digits); /* FIXME: Move channel reconfiguration to generic protocol code ? */ diff --git a/proto/ospf/neighbor.c b/proto/ospf/neighbor.c index 50ef6a49..30e80640 100644 --- a/proto/ospf/neighbor.c +++ b/proto/ospf/neighbor.c @@ -771,8 +771,11 @@ ospf_neigh_bfd_hook(struct bfd_request *req) void ospf_neigh_update_bfd(struct ospf_neighbor *n, int use_bfd) { + struct ospf_proto *p = n->ifa->oa->po; + if (use_bfd && !n->bfd_req) - n->bfd_req = bfd_request_session(n->pool, n->ip, n->ifa->addr->ip, n->ifa->iface, + n->bfd_req = bfd_request_session(n->pool, n->ip, n->ifa->addr->ip, + n->ifa->iface, p->p.vrf, ospf_neigh_bfd_hook, n); if (!use_bfd && n->bfd_req) @@ -854,7 +857,7 @@ ospf_sh_neigh_info(struct ospf_neighbor *n) pos = "Other"; } - cli_msg(-1013, "%-1R\t%3u\t%s/%s\t%7t\t%-10s %-1I", + cli_msg(-1013, "%-12R\t%3u\t%s/%s\t%6t\t%-10s %I", n->rid, n->priority, ospf_ns_names[n->state], pos, tm_remains(n->inactim), ifa->ifname, n->ip); } diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index ef627e20..63ff9e56 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -805,7 +805,7 @@ ospf_sh_neigh(struct proto *P, char *iff) } cli_msg(-1013, "%s:", p->p.name); - cli_msg(-1013, "%-12s\t%3s\t%-15s\t%-5s\t%-10s %-12s", "Router ID", "Pri", + cli_msg(-1013, "%-12s\t%3s\t%-15s\t%-5s\t%-10s %s", "Router ID", "Pri", " State", "DTime", "Interface", "Router IP"); WALK_LIST(ifa, p->iface_list) if ((iff == NULL) || patmatch(iff, ifa->ifname)) diff --git a/proto/rip/rip.c b/proto/rip/rip.c index 91c00588..4559310e 100644 --- a/proto/rip/rip.c +++ b/proto/rip/rip.c @@ -483,7 +483,8 @@ rip_update_bfd(struct rip_proto *p, struct rip_neighbor *n) */ ip_addr saddr = rip_is_v2(p) ? n->ifa->sk->saddr : n->nbr->ifa->ip; n->bfd_req = bfd_request_session(p->p.pool, n->nbr->addr, saddr, - n->nbr->iface, rip_bfd_notify, n); + n->nbr->iface, p->p.vrf, + rip_bfd_notify, n); } if (!use_bfd && n->bfd_req) diff --git a/proto/rpki/rpki.c b/proto/rpki/rpki.c index 36097dc5..70cd0cdd 100644 --- a/proto/rpki/rpki.c +++ b/proto/rpki/rpki.c @@ -687,9 +687,9 @@ rpki_reconfigure_cache(struct rpki_proto *p UNUSED, struct rpki_cache *cache, st { struct rpki_tr_ssh_config *ssh_old = (void *) old->tr_config.spec; struct rpki_tr_ssh_config *ssh_new = (void *) new->tr_config.spec; - if ((strcmp(ssh_old->bird_private_key, ssh_new->bird_private_key) != 0) || - (strcmp(ssh_old->cache_public_key, ssh_new->cache_public_key) != 0) || - (strcmp(ssh_old->user, ssh_new->user) != 0)) + if (bstrcmp(ssh_old->bird_private_key, ssh_new->bird_private_key) || + bstrcmp(ssh_old->cache_public_key, ssh_new->cache_public_key) || + bstrcmp(ssh_old->user, ssh_new->user)) { CACHE_TRACE(D_EVENTS, cache, "Settings of SSH transport configuration changed"); try_fast_reconnect = 1; diff --git a/proto/static/static.c b/proto/static/static.c index 2fa687eb..c899cc87 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -159,7 +159,8 @@ static_update_bfd(struct static_proto *p, struct static_route *r) 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->p.pool, r->via, nb->ifa->ip, nb->iface, + r->bfd_req = bfd_request_session(p->p.pool, r->via, nb->ifa->ip, + nb->iface, p->p.vrf, static_bfd_notify, r); } diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index 95f0481e..10e9a18b 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -69,6 +69,7 @@ #define RTA_ENCAP 22 #endif +#define krt_ipv4(p) ((p)->af == AF_INET) #define krt_ecmp6(p) ((p)->af == AF_INET6) const int rt_default_ecmp = 16; @@ -466,10 +467,21 @@ static inline ip_addr rta_get_via(struct rtattr *a) static u32 rta_mpls_stack[MPLS_MAX_LABEL_STACK]; static inline int rta_get_mpls(struct rtattr *a, u32 *stack) { + if (!a) + return 0; + if (RTA_PAYLOAD(a) % 4) log(L_WARN "KRT: Strange length of received MPLS stack: %u", RTA_PAYLOAD(a)); - return mpls_get(RTA_DATA(a), RTA_PAYLOAD(a) & ~0x3, stack); + int labels = mpls_get(RTA_DATA(a), RTA_PAYLOAD(a) & ~0x3, stack); + + if (labels < 0) + { + log(L_WARN "KRT: Too long MPLS stack received, ignoring"); + labels = 0; + } + + return labels; } #endif @@ -705,7 +717,7 @@ nl_parse_multipath(struct nl_parse_state *s, struct krt_proto *p, struct rtattr rv->gw = IPA_NONE; #ifdef HAVE_MPLS_KERNEL - if (a[RTA_ENCAP_TYPE]) + if (a[RTA_ENCAP] && a[RTA_ENCAP_TYPE]) { if (rta_get_u16(a[RTA_ENCAP_TYPE]) != LWTUNNEL_ENCAP_MPLS) { log(L_WARN "KRT: Unknown encapsulation method %d in multipath", rta_get_u16(a[RTA_ENCAP_TYPE])); @@ -716,7 +728,6 @@ nl_parse_multipath(struct nl_parse_state *s, struct krt_proto *p, struct rtattr nl_attr_len = RTA_PAYLOAD(a[RTA_ENCAP]); nl_parse_attrs(RTA_DATA(a[RTA_ENCAP]), encap_mpls_want, enca, sizeof(enca)); rv->labels = rta_get_mpls(enca[RTA_DST], rv->label); - break; } #endif @@ -1368,27 +1379,43 @@ nl_delete_rte(struct krt_proto *p, rte *e) return err; } +static inline int +nl_replace_rte(struct krt_proto *p, rte *e) +{ + rta *a = e->attrs; + return nl_send_route(p, e, NL_OP_REPLACE, a->dest, &(a->nh)); +} + + void krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old) { int err = 0; /* - * We could use NL_OP_REPLACE, but route replace on Linux has some problems: + * We use NL_OP_REPLACE for IPv4, it has an issue with not checking for + * matching rtm_protocol, but that is OK when dedicated priority is used. * - * 1) Does not check for matching rtm_protocol - * 2) Has broken semantics for IPv6 ECMP - * 3) Crashes some kernel version when used for IPv6 ECMP + * We do not use NL_OP_REPLACE for IPv6, as it has broken semantics for ECMP + * and with some kernel versions ECMP replace crashes kernel. Would need more + * testing and checks for kernel versions. * - * So we use NL_OP_DELETE and then NL_OP_ADD. We also do not trust the old - * route value, so we do not try to optimize IPv6 ECMP reconfigurations. + * For IPv6, we use NL_OP_DELETE and then NL_OP_ADD. We also do not trust the + * old route value, so we do not try to optimize IPv6 ECMP reconfigurations. */ - if (old) - nl_delete_rte(p, old); + if (krt_ipv4(p) && old && new) + { + err = nl_replace_rte(p, new); + } + else + { + if (old) + nl_delete_rte(p, old); - if (new) - err = nl_add_rte(p, new); + if (new) + err = nl_add_rte(p, new); + } if (err < 0) n->n.flags |= KRF_SYNC_ERROR; @@ -1606,7 +1633,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) return; } - ra->nh = *nh; + nexthop_link(ra, nh); break; } @@ -1666,9 +1693,8 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) } #ifdef HAVE_MPLS_KERNEL - int labels = 0; if ((i->rtm_family == AF_MPLS) && a[RTA_NEWDST] && !ra->nh.next) - labels = rta_get_mpls(a[RTA_NEWDST], ra->nh.label); + ra->nh.labels = rta_get_mpls(a[RTA_NEWDST], ra->nh.label); if (a[RTA_ENCAP] && a[RTA_ENCAP_TYPE] && !ra->nh.next) { @@ -1679,7 +1705,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) struct rtattr *enca[BIRD_RTA_MAX]; nl_attr_len = RTA_PAYLOAD(a[RTA_ENCAP]); nl_parse_attrs(RTA_DATA(a[RTA_ENCAP]), encap_mpls_want, enca, sizeof(enca)); - labels = rta_get_mpls(enca[RTA_DST], ra->nh.label); + ra->nh.labels = rta_get_mpls(enca[RTA_DST], ra->nh.label); break; } default: @@ -1687,14 +1713,6 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) break; } } - - if (labels < 0) - { - log(L_WARN "KRT: Too long MPLS stack received, ignoring."); - ra->nh.labels = 0; - } - else - ra->nh.labels = labels; #endif if (i->rtm_scope != def_scope) diff --git a/sysdep/unix/log.c b/sysdep/unix/log.c index 9d107709..45f442e7 100644 --- a/sysdep/unix/log.c +++ b/sysdep/unix/log.c @@ -387,8 +387,7 @@ log_switch(int initial, list *logs, char *new_syslog_name) current_log_list = logs; #ifdef HAVE_SYSLOG_H - if (current_syslog_name && new_syslog_name && - !strcmp(current_syslog_name, new_syslog_name)) + if (!bstrcmp(current_syslog_name, new_syslog_name)) return; if (current_syslog_name) |