diff options
86 files changed, 1656 insertions, 590 deletions
diff --git a/bfdd/bfd.c b/bfdd/bfd.c index e9645824f2..a2e84e928d 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -128,15 +128,8 @@ int bfd_session_enable(struct bfd_session *bs) * If the interface or VRF doesn't exist, then we must register * the session but delay its start. */ - if (bs->key.ifname[0]) { - ifp = if_lookup_by_name_all_vrf(bs->key.ifname); - if (ifp == NULL) { - log_error( - "session-enable: specified interface doesn't exists."); - return 0; - } - - vrf = vrf_lookup_by_id(ifp->vrf_id); + if (bs->key.vrfname[0]) { + vrf = vrf_lookup_by_name(bs->key.vrfname); if (vrf == NULL) { log_error( "session-enable: specified VRF doesn't exists."); @@ -144,13 +137,24 @@ int bfd_session_enable(struct bfd_session *bs) } } - if (bs->key.vrfname[0]) { - vrf = vrf_lookup_by_name(bs->key.vrfname); - if (vrf == NULL) { + if (bs->key.ifname[0]) { + if (vrf) + ifp = if_lookup_by_name(bs->key.ifname, vrf->vrf_id); + else + ifp = if_lookup_by_name_all_vrf(bs->key.ifname); + if (ifp == NULL) { log_error( - "session-enable: specified VRF doesn't exists."); + "session-enable: specified interface doesn't exists."); return 0; } + if (bs->key.ifname[0] && !vrf) { + vrf = vrf_lookup_by_id(ifp->vrf_id); + if (vrf == NULL) { + log_error( + "session-enable: specified VRF doesn't exists."); + return 0; + } + } } /* Assign interface/VRF pointers. */ @@ -164,7 +168,7 @@ int bfd_session_enable(struct bfd_session *bs) /* Sanity check: don't leak open sockets. */ if (bs->sock != -1) { - zlog_debug("session-enable: previous socket open"); + log_debug("session-enable: previous socket open"); close(bs->sock); bs->sock = -1; } @@ -291,7 +295,7 @@ void ptm_bfd_echo_start(struct bfd_session *bfd) ptm_bfd_echo_xmt_TO(bfd); } -void ptm_bfd_ses_up(struct bfd_session *bfd) +void ptm_bfd_sess_up(struct bfd_session *bfd) { int old_state = bfd->ses_state; @@ -315,7 +319,7 @@ void ptm_bfd_ses_up(struct bfd_session *bfd) } } -void ptm_bfd_ses_dn(struct bfd_session *bfd, uint8_t diag) +void ptm_bfd_sess_dn(struct bfd_session *bfd, uint8_t diag) { int old_state = bfd->ses_state; @@ -432,7 +436,7 @@ int bfd_recvtimer_cb(struct thread *t) switch (bs->ses_state) { case PTM_BFD_INIT: case PTM_BFD_UP: - ptm_bfd_ses_dn(bs, BD_CONTROL_EXPIRED); + ptm_bfd_sess_dn(bs, BD_CONTROL_EXPIRED); bfd_recvtimer_update(bs); break; @@ -455,7 +459,7 @@ int bfd_echo_recvtimer_cb(struct thread *t) switch (bs->ses_state) { case PTM_BFD_INIT: case PTM_BFD_UP: - ptm_bfd_ses_dn(bs, BD_ECHO_FAILED); + ptm_bfd_sess_dn(bs, BD_ECHO_FAILED); break; } @@ -725,7 +729,7 @@ struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc) return bfd; } -int ptm_bfd_ses_del(struct bfd_peer_cfg *bpc) +int ptm_bfd_sess_del(struct bfd_peer_cfg *bpc) { struct bfd_session *bs; @@ -805,7 +809,7 @@ static void bs_down_handler(struct bfd_session *bs, int nstate) * Remote peer told us his path is up, lets turn * activate the session. */ - ptm_bfd_ses_up(bs); + ptm_bfd_sess_up(bs); break; default: @@ -832,7 +836,7 @@ static void bs_init_handler(struct bfd_session *bs, int nstate) case PTM_BFD_INIT: case PTM_BFD_UP: /* We agreed on the settings and the path is up. */ - ptm_bfd_ses_up(bs); + ptm_bfd_sess_up(bs); break; default: @@ -847,7 +851,7 @@ static void bs_up_handler(struct bfd_session *bs, int nstate) case PTM_BFD_ADM_DOWN: case PTM_BFD_DOWN: /* Peer lost or asked to shutdown connection. */ - ptm_bfd_ses_dn(bs, BD_NEIGHBOR_DOWN); + ptm_bfd_sess_dn(bs, BD_NEIGHBOR_DOWN); break; case PTM_BFD_INIT: @@ -1197,10 +1201,6 @@ int bs_observer_add(struct bfd_session *bs) if (bso->bso_isinterface) strlcpy(bso->bso_entryname, bs->key.ifname, sizeof(bso->bso_entryname)); - else - strlcpy(bso->bso_entryname, bs->key.vrfname, - sizeof(bso->bso_entryname)); - /* Handle socket binding failures caused by missing local addresses. */ if (bs->sock == -1) { bso->bso_isaddress = true; @@ -1322,32 +1322,105 @@ struct bfd_session *bfd_id_lookup(uint32_t id) return hash_lookup(bfd_id_hash, &bs); } +struct bfd_key_walk_partial_lookup { + struct bfd_session *given; + struct bfd_session *result; +}; + +/* ignore some parameters */ +static int bfd_key_lookup_ignore_partial_walker(struct hash_bucket *b, void *data) +{ + struct bfd_key_walk_partial_lookup *ctx = + (struct bfd_key_walk_partial_lookup *)data; + struct bfd_session *given = ctx->given; + struct bfd_session *parsed = b->data; + + if (given->key.family != parsed->key.family) + return HASHWALK_CONTINUE; + if (given->key.mhop != parsed->key.mhop) + return HASHWALK_CONTINUE; + if (memcmp(&given->key.peer, &parsed->key.peer, sizeof(struct in6_addr))) + return HASHWALK_CONTINUE; + if (memcmp(given->key.vrfname, parsed->key.vrfname, MAXNAMELEN)) + return HASHWALK_CONTINUE; + ctx->result = parsed; + /* ignore localaddr or interface */ + return HASHWALK_ABORT; +} + struct bfd_session *bfd_key_lookup(struct bfd_key key) { struct bfd_session bs, *bsp; + struct bfd_key_walk_partial_lookup ctx; + char peer_buf[INET6_ADDRSTRLEN]; bs.key = key; bsp = hash_lookup(bfd_key_hash, &bs); + if (bsp) + return bsp; + inet_ntop(bs.key.family, &bs.key.peer, peer_buf, + sizeof(peer_buf)); /* Handle cases where local-address is optional. */ - if (bsp == NULL && bs.key.family == AF_INET) { + if (bs.key.family == AF_INET) { memset(&bs.key.local, 0, sizeof(bs.key.local)); bsp = hash_lookup(bfd_key_hash, &bs); + if (bsp) { + char addr_buf[INET6_ADDRSTRLEN]; + + inet_ntop(bs.key.family, &key.local, addr_buf, + sizeof(addr_buf)); + log_debug(" peer %s found, but loc-addr %s ignored", + peer_buf, addr_buf); + return bsp; + } } - /* Handle cases where ifname is optional. */ bs.key = key; - if (bsp == NULL && bs.key.ifname[0]) { + /* Handle cases where ifname is optional. */ + if (bs.key.ifname[0]) { memset(bs.key.ifname, 0, sizeof(bs.key.ifname)); bsp = hash_lookup(bfd_key_hash, &bs); + if (bsp) { + log_debug(" peer %s found, but ifp %s ignored", + peer_buf, key.ifname); + return bsp; + } + } - /* Handle cases where local-address and ifname are optional. */ - if (bsp == NULL && bs.key.family == AF_INET) { - memset(&bs.key.local, 0, sizeof(bs.key.local)); - bsp = hash_lookup(bfd_key_hash, &bs); + /* Handle cases where local-address and ifname are optional. */ + if (bs.key.family == AF_INET) { + memset(&bs.key.local, 0, sizeof(bs.key.local)); + bsp = hash_lookup(bfd_key_hash, &bs); + if (bsp) { + char addr_buf[INET6_ADDRSTRLEN]; + + inet_ntop(bs.key.family, &bs.key.local, addr_buf, + sizeof(addr_buf)); + log_debug(" peer %s found, but ifp %s" + " and loc-addr %s ignored", + peer_buf, key.ifname, + addr_buf); + return bsp; } } + bs.key = key; + /* Handle case where a context more complex ctx is present. + * input has no iface nor local-address, but a context may + * exist + */ + ctx.result = NULL; + ctx.given = &bs; + hash_walk(bfd_key_hash, + &bfd_key_lookup_ignore_partial_walker, + &ctx); + /* change key */ + if (ctx.result) { + bsp = ctx.result; + log_debug(" peer %s found, but ifp" + " and/or loc-addr params ignored"); + } return bsp; } @@ -1443,3 +1516,125 @@ void bfd_shutdown(void) hash_free(bfd_id_hash); hash_free(bfd_key_hash); } + +static int bfd_vrf_new(struct vrf *vrf) +{ + log_debug("VRF Created: %s(%u)", vrf->name, vrf->vrf_id); + return 0; +} + +static int bfd_vrf_delete(struct vrf *vrf) +{ + log_debug("VRF Deletion: %s(%u)", vrf->name, vrf->vrf_id); + return 0; +} + +static int bfd_vrf_enable(struct vrf *vrf) +{ + struct bfd_vrf_global *bvrf; + + /* a different name */ + if (!vrf->info) { + bvrf = XCALLOC(MTYPE_BFDD_VRF, sizeof(struct bfd_vrf_global)); + bvrf->vrf = vrf; + vrf->info = (void *)bvrf; + } else + bvrf = vrf->info; + log_debug("VRF enable add %s id %u", vrf->name, vrf->vrf_id); + + /* create sockets if needed */ + if (!bvrf->bg_shop) + bvrf->bg_shop = bp_udp_shop(vrf->vrf_id); + if (!bvrf->bg_mhop) + bvrf->bg_mhop = bp_udp_mhop(vrf->vrf_id); + if (!bvrf->bg_shop6) + bvrf->bg_shop6 = bp_udp6_shop(vrf->vrf_id); + if (!bvrf->bg_mhop6) + bvrf->bg_mhop6 = bp_udp6_mhop(vrf->vrf_id); + if (!bvrf->bg_echo) + bvrf->bg_echo = bp_echo_socket(vrf->vrf_id); + if (!bvrf->bg_echov6) + bvrf->bg_echov6 = bp_echov6_socket(vrf->vrf_id); + + /* Add descriptors to the event loop. */ + if (!bvrf->bg_ev[0]) + thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_shop, + &bvrf->bg_ev[0]); + if (!bvrf->bg_ev[1]) + thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_mhop, + &bvrf->bg_ev[1]); + if (!bvrf->bg_ev[2]) + thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_shop6, + &bvrf->bg_ev[2]); + if (!bvrf->bg_ev[3]) + thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_mhop6, + &bvrf->bg_ev[3]); + if (!bvrf->bg_ev[4]) + thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_echo, + &bvrf->bg_ev[4]); + if (!bvrf->bg_ev[5]) + thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_echov6, + &bvrf->bg_ev[5]); + + if (vrf->vrf_id != VRF_DEFAULT) { + bfdd_zclient_register(vrf->vrf_id); + bfdd_sessions_enable_vrf(vrf); + } + return 0; +} + +static int bfd_vrf_disable(struct vrf *vrf) +{ + struct bfd_vrf_global *bvrf; + + if (!vrf->info) + return 0; + bvrf = vrf->info; + + if (vrf->vrf_id != VRF_DEFAULT) { + bfdd_sessions_disable_vrf(vrf); + bfdd_zclient_unregister(vrf->vrf_id); + } + + log_debug("VRF disable %s id %d", vrf->name, vrf->vrf_id); + /* Close all descriptors. */ + socket_close(&bvrf->bg_echo); + socket_close(&bvrf->bg_shop); + socket_close(&bvrf->bg_mhop); + socket_close(&bvrf->bg_shop6); + socket_close(&bvrf->bg_mhop6); + + /* free context */ + XFREE(MTYPE_BFDD_VRF, bvrf); + vrf->info = NULL; + + return 0; +} + +void bfd_vrf_init(void) +{ + vrf_init(bfd_vrf_new, bfd_vrf_enable, bfd_vrf_disable, + bfd_vrf_delete, NULL); +} + +void bfd_vrf_terminate(void) +{ + vrf_terminate(); +} + +struct bfd_vrf_global *bfd_vrf_look_by_session(struct bfd_session *bfd) +{ + struct vrf *vrf; + + if (!vrf_is_backend_netns()) { + vrf = vrf_lookup_by_id(VRF_DEFAULT); + if (vrf) + return (struct bfd_vrf_global *)vrf->info; + return NULL; + } + if (!bfd) + return NULL; + if (!bfd->vrf) + return NULL; + return bfd->vrf->info; +} diff --git a/bfdd/bfd.h b/bfdd/bfd.h index e08a1ff724..3f3d603832 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -48,6 +48,7 @@ DECLARE_MTYPE(BFDD_LABEL); DECLARE_MTYPE(BFDD_CONTROL); DECLARE_MTYPE(BFDD_SESSION_OBSERVER); DECLARE_MTYPE(BFDD_NOTIFICATION); +DECLARE_MTYPE(BFDD_VRF); struct bfd_timers { uint32_t desired_min_tx; @@ -379,15 +380,19 @@ int control_accept(struct thread *t); * * Daemon specific code. */ -struct bfd_global { +struct bfd_vrf_global { int bg_shop; int bg_mhop; int bg_shop6; int bg_mhop6; int bg_echo; int bg_echov6; + struct vrf *vrf; + struct thread *bg_ev[6]; +}; +struct bfd_global { int bg_csock; struct thread *bg_csockev; struct bcslist bg_bcslist; @@ -395,6 +400,8 @@ struct bfd_global { struct pllist bg_pllist; struct obslist bg_obslist; + + struct zebra_privs_t bfdd_privs; }; extern struct bfd_global bglobal; extern struct bfd_diag_str_list diag_list[]; @@ -459,14 +466,14 @@ int bp_set_tosv6(int sd, uint8_t value); int bp_set_tos(int sd, uint8_t value); int bp_bind_dev(int sd, const char *dev); -int bp_udp_shop(void); -int bp_udp_mhop(void); -int bp_udp6_shop(void); -int bp_udp6_mhop(void); +int bp_udp_shop(vrf_id_t vrf_id); +int bp_udp_mhop(vrf_id_t vrf_id); +int bp_udp6_shop(vrf_id_t vrf_id); +int bp_udp6_mhop(vrf_id_t vrf_id); int bp_peer_socket(const struct bfd_session *bs); int bp_peer_socketv6(const struct bfd_session *bs); -int bp_echo_socket(void); -int bp_echov6_socket(void); +int bp_echo_socket(vrf_id_t vrf_id); +int bp_echov6_socket(vrf_id_t vrf_id); void ptm_bfd_snd(struct bfd_session *bfd, int fbit); void ptm_bfd_echo_snd(struct bfd_session *bfd); @@ -505,9 +512,9 @@ void bfd_echo_xmttimer_assign(struct bfd_session *bs, bfd_ev_cb cb); int bfd_session_enable(struct bfd_session *bs); void bfd_session_disable(struct bfd_session *bs); struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc); -int ptm_bfd_ses_del(struct bfd_peer_cfg *bpc); -void ptm_bfd_ses_dn(struct bfd_session *bfd, uint8_t diag); -void ptm_bfd_ses_up(struct bfd_session *bfd); +int ptm_bfd_sess_del(struct bfd_peer_cfg *bpc); +void ptm_bfd_sess_dn(struct bfd_session *bfd, uint8_t diag); +void ptm_bfd_sess_up(struct bfd_session *bfd); void ptm_bfd_echo_stop(struct bfd_session *bfd); void ptm_bfd_echo_start(struct bfd_session *bfd); void ptm_bfd_xmt_TO(struct bfd_session *bfd, int fbit); @@ -539,6 +546,9 @@ void bs_to_bpc(struct bfd_session *bs, struct bfd_peer_cfg *bpc); /* BFD hash data structures interface */ void bfd_initialize(void); void bfd_shutdown(void); +void bfd_vrf_init(void); +void bfd_vrf_terminate(void); +struct bfd_vrf_global *bfd_vrf_look_by_session(struct bfd_session *bfd); struct bfd_session *bfd_id_lookup(uint32_t id); struct bfd_session *bfd_key_lookup(struct bfd_key key); @@ -576,6 +586,10 @@ void bfdd_vty_init(void); */ void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv); void bfdd_zclient_stop(void); +void bfdd_zclient_unregister(vrf_id_t vrf_id); +void bfdd_zclient_register(vrf_id_t vrf_id); +void bfdd_sessions_enable_vrf(struct vrf *vrf); +void bfdd_sessions_disable_vrf(struct vrf *vrf); int ptm_bfd_notify(struct bfd_session *bs); diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c index 93677ec85a..8edba05d12 100644 --- a/bfdd/bfd_packet.c +++ b/bfdd/bfd_packet.c @@ -37,15 +37,14 @@ #include "bfd.h" - /* * Prototypes */ -static int ptm_bfd_process_echo_pkt(int s); +static int ptm_bfd_process_echo_pkt(struct bfd_vrf_global *bvrf, int s); int _ptm_bfd_send(struct bfd_session *bs, uint16_t *port, const void *data, size_t datalen); -static void bfd_sd_reschedule(int sd); +static void bfd_sd_reschedule(struct bfd_vrf_global *bvrf, int sd); ssize_t bfd_recv_ipv4(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl, ifindex_t *ifindex, struct sockaddr_any *local, struct sockaddr_any *peer); @@ -54,7 +53,8 @@ ssize_t bfd_recv_ipv6(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl, struct sockaddr_any *peer); int bp_udp_send(int sd, uint8_t ttl, uint8_t *data, size_t datalen, struct sockaddr *to, socklen_t tolen); -int bp_bfd_echo_in(int sd, uint8_t *ttl, uint32_t *my_discr); +int bp_bfd_echo_in(struct bfd_vrf_global *bvrf, int sd, + uint8_t *ttl, uint32_t *my_discr); /* socket related prototypes */ static void bp_set_ipopts(int sd); @@ -129,7 +129,10 @@ void ptm_bfd_echo_snd(struct bfd_session *bfd) struct bfd_echo_pkt bep; struct sockaddr_in sin; struct sockaddr_in6 sin6; + struct bfd_vrf_global *bvrf = bfd_vrf_look_by_session(bfd); + if (!bvrf) + return; if (!BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE)) BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE); @@ -139,7 +142,7 @@ void ptm_bfd_echo_snd(struct bfd_session *bfd) bep.my_discr = htonl(bfd->discrs.my_discr); if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6)) { - sd = bglobal.bg_echov6; + sd = bvrf->bg_echov6; memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; memcpy(&sin6.sin6_addr, &bfd->key.peer, sizeof(sin6.sin6_addr)); @@ -154,7 +157,7 @@ void ptm_bfd_echo_snd(struct bfd_session *bfd) sa = (struct sockaddr *)&sin6; salen = sizeof(sin6); } else { - sd = bglobal.bg_echo; + sd = bvrf->bg_echo; memset(&sin6, 0, sizeof(sin6)); sin.sin_family = AF_INET; memcpy(&sin.sin_addr, &bfd->key.peer, sizeof(sin.sin_addr)); @@ -174,14 +177,14 @@ void ptm_bfd_echo_snd(struct bfd_session *bfd) bfd->stats.tx_echo_pkt++; } -static int ptm_bfd_process_echo_pkt(int s) +static int ptm_bfd_process_echo_pkt(struct bfd_vrf_global *bvrf, int s) { struct bfd_session *bfd; uint32_t my_discr = 0; uint8_t ttl = 0; /* Receive and parse echo packet. */ - if (bp_bfd_echo_in(s, &ttl, &my_discr) == -1) + if (bp_bfd_echo_in(bvrf, s, &ttl, &my_discr) == -1) return 0; /* Your discriminator not zero - use it to find session */ @@ -441,32 +444,32 @@ ssize_t bfd_recv_ipv6(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl, return mlen; } -static void bfd_sd_reschedule(int sd) +static void bfd_sd_reschedule(struct bfd_vrf_global *bvrf, int sd) { - if (sd == bglobal.bg_shop) { - THREAD_OFF(bglobal.bg_ev[0]); - thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_shop, - &bglobal.bg_ev[0]); - } else if (sd == bglobal.bg_mhop) { - THREAD_OFF(bglobal.bg_ev[1]); - thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_mhop, - &bglobal.bg_ev[1]); - } else if (sd == bglobal.bg_shop6) { - THREAD_OFF(bglobal.bg_ev[2]); - thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_shop6, - &bglobal.bg_ev[2]); - } else if (sd == bglobal.bg_mhop6) { - THREAD_OFF(bglobal.bg_ev[3]); - thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_mhop6, - &bglobal.bg_ev[3]); - } else if (sd == bglobal.bg_echo) { - THREAD_OFF(bglobal.bg_ev[4]); - thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_echo, - &bglobal.bg_ev[4]); - } else if (sd == bglobal.bg_echov6) { - THREAD_OFF(bglobal.bg_ev[5]); - thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_echov6, - &bglobal.bg_ev[5]); + if (sd == bvrf->bg_shop) { + THREAD_OFF(bvrf->bg_ev[0]); + thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_shop, + &bvrf->bg_ev[0]); + } else if (sd == bvrf->bg_mhop) { + THREAD_OFF(bvrf->bg_ev[1]); + thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_mhop, + &bvrf->bg_ev[1]); + } else if (sd == bvrf->bg_shop6) { + THREAD_OFF(bvrf->bg_ev[2]); + thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_shop6, + &bvrf->bg_ev[2]); + } else if (sd == bvrf->bg_mhop6) { + THREAD_OFF(bvrf->bg_ev[3]); + thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_mhop6, + &bvrf->bg_ev[3]); + } else if (sd == bvrf->bg_echo) { + THREAD_OFF(bvrf->bg_ev[4]); + thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_echo, + &bvrf->bg_ev[4]); + } else if (sd == bvrf->bg_echov6) { + THREAD_OFF(bvrf->bg_ev[5]); + thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_echov6, + &bvrf->bg_ev[5]); } } @@ -518,13 +521,16 @@ int bfd_recv_cb(struct thread *t) ifindex_t ifindex = IFINDEX_INTERNAL; struct sockaddr_any local, peer; uint8_t msgbuf[1516]; + struct bfd_vrf_global *bvrf = THREAD_ARG(t); + if (bvrf) + vrfid = bvrf->vrf->vrf_id; /* Schedule next read. */ - bfd_sd_reschedule(sd); + bfd_sd_reschedule(bvrf, sd); /* Handle echo packets. */ - if (sd == bglobal.bg_echo || sd == bglobal.bg_echov6) { - ptm_bfd_process_echo_pkt(sd); + if (sd == bvrf->bg_echo || sd == bvrf->bg_echov6) { + ptm_bfd_process_echo_pkt(bvrf, sd); return 0; } @@ -534,12 +540,12 @@ int bfd_recv_cb(struct thread *t) /* Handle control packets. */ is_mhop = false; - if (sd == bglobal.bg_shop || sd == bglobal.bg_mhop) { - is_mhop = sd == bglobal.bg_mhop; + if (sd == bvrf->bg_shop || sd == bvrf->bg_mhop) { + is_mhop = sd == bvrf->bg_mhop; mlen = bfd_recv_ipv4(sd, msgbuf, sizeof(msgbuf), &ttl, &ifindex, &local, &peer); - } else if (sd == bglobal.bg_shop6 || sd == bglobal.bg_mhop6) { - is_mhop = sd == bglobal.bg_mhop6; + } else if (sd == bvrf->bg_shop6 || sd == bvrf->bg_mhop6) { + is_mhop = sd == bvrf->bg_mhop6; mlen = bfd_recv_ipv6(sd, msgbuf, sizeof(msgbuf), &ttl, &ifindex, &local, &peer); } @@ -682,7 +688,8 @@ int bfd_recv_cb(struct thread *t) * * Returns -1 on error or loopback or 0 on success. */ -int bp_bfd_echo_in(int sd, uint8_t *ttl, uint32_t *my_discr) +int bp_bfd_echo_in(struct bfd_vrf_global *bvrf, int sd, + uint8_t *ttl, uint32_t *my_discr) { struct bfd_echo_pkt *bep; ssize_t rlen; @@ -691,7 +698,7 @@ int bp_bfd_echo_in(int sd, uint8_t *ttl, uint32_t *my_discr) vrf_id_t vrfid = VRF_DEFAULT; uint8_t msgbuf[1516]; - if (sd == bglobal.bg_echo) + if (sd == bvrf->bg_echo) rlen = bfd_recv_ipv4(sd, msgbuf, sizeof(msgbuf), ttl, &ifindex, &local, &peer); else @@ -709,7 +716,7 @@ int bp_bfd_echo_in(int sd, uint8_t *ttl, uint32_t *my_discr) if (*ttl == BFD_TTL_VAL) { bp_udp_send(sd, *ttl - 1, msgbuf, rlen, (struct sockaddr *)&peer, - (sd == bglobal.bg_echo) ? sizeof(peer.sa_sin) + (sd == bvrf->bg_echo) ? sizeof(peer.sa_sin) : sizeof(peer.sa_sin6)); return -1; } @@ -872,25 +879,28 @@ static void bp_bind_ip(int sd, uint16_t port) log_fatal("bind-ip: bind: %s", strerror(errno)); } -int bp_udp_shop(void) +int bp_udp_shop(vrf_id_t vrf_id) { int sd; - sd = socket(AF_INET, SOCK_DGRAM, PF_UNSPEC); + frr_elevate_privs(&bglobal.bfdd_privs) { + sd = vrf_socket(AF_INET, SOCK_DGRAM, PF_UNSPEC, vrf_id, NULL); + } if (sd == -1) log_fatal("udp-shop: socket: %s", strerror(errno)); bp_set_ipopts(sd); bp_bind_ip(sd, BFD_DEFDESTPORT); - return sd; } -int bp_udp_mhop(void) +int bp_udp_mhop(vrf_id_t vrf_id) { int sd; - sd = socket(AF_INET, SOCK_DGRAM, PF_UNSPEC); + frr_elevate_privs(&bglobal.bfdd_privs) { + sd = vrf_socket(AF_INET, SOCK_DGRAM, PF_UNSPEC, vrf_id, NULL); + } if (sd == -1) log_fatal("udp-mhop: socket: %s", strerror(errno)); @@ -905,8 +915,18 @@ int bp_peer_socket(const struct bfd_session *bs) int sd, pcount; struct sockaddr_in sin; static int srcPort = BFD_SRCPORTINIT; + const char *device_to_bind = NULL; + + if (bs->key.ifname[0]) + device_to_bind = (const char *)bs->key.ifname; + else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) + && bs->key.vrfname[0]) + device_to_bind = (const char *)bs->key.vrfname; - sd = socket(AF_INET, SOCK_DGRAM, PF_UNSPEC); + frr_elevate_privs(&bglobal.bfdd_privs) { + sd = vrf_socket(AF_INET, SOCK_DGRAM, PF_UNSPEC, + bs->vrf->vrf_id, device_to_bind); + } if (sd == -1) { log_error("ipv4-new: failed to create socket: %s", strerror(errno)); @@ -925,19 +945,6 @@ int bp_peer_socket(const struct bfd_session *bs) return -1; } - if (bs->key.ifname[0]) { - if (bp_bind_dev(sd, bs->key.ifname) != 0) { - close(sd); - return -1; - } - } else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) - && bs->key.vrfname[0]) { - if (bp_bind_dev(sd, bs->key.vrfname) != 0) { - close(sd); - return -1; - } - } - /* Find an available source port in the proper range */ memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; @@ -975,8 +982,18 @@ int bp_peer_socketv6(const struct bfd_session *bs) int sd, pcount; struct sockaddr_in6 sin6; static int srcPort = BFD_SRCPORTINIT; + const char *device_to_bind = NULL; - sd = socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC); + if (bs->key.ifname[0]) + device_to_bind = (const char *)bs->key.ifname; + else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) + && bs->key.vrfname[0]) + device_to_bind = (const char *)bs->key.vrfname; + + frr_elevate_privs(&bglobal.bfdd_privs) { + sd = vrf_socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC, + bs->vrf->vrf_id, device_to_bind); + } if (sd == -1) { log_error("ipv6-new: failed to create socket: %s", strerror(errno)); @@ -1005,19 +1022,6 @@ int bp_peer_socketv6(const struct bfd_session *bs) if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr)) sin6.sin6_scope_id = bs->ifp->ifindex; - if (bs->key.ifname[0]) { - if (bp_bind_dev(sd, bs->key.ifname) != 0) { - close(sd); - return -1; - } - } else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) - && bs->key.vrfname[0]) { - if (bp_bind_dev(sd, bs->key.vrfname) != 0) { - close(sd); - return -1; - } - } - pcount = 0; do { if ((++pcount) > (BFD_SRCPORTMAX - BFD_SRCPORTINIT)) { @@ -1102,11 +1106,13 @@ static void bp_bind_ipv6(int sd, uint16_t port) log_fatal("bind-ipv6: bind: %s", strerror(errno)); } -int bp_udp6_shop(void) +int bp_udp6_shop(vrf_id_t vrf_id) { int sd; - sd = socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC); + frr_elevate_privs(&bglobal.bfdd_privs) { + sd = vrf_socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC, vrf_id, NULL); + } if (sd == -1) log_fatal("udp6-shop: socket: %s", strerror(errno)); @@ -1116,11 +1122,13 @@ int bp_udp6_shop(void) return sd; } -int bp_udp6_mhop(void) +int bp_udp6_mhop(vrf_id_t vrf_id) { int sd; - sd = socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC); + frr_elevate_privs(&bglobal.bfdd_privs) { + sd = vrf_socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC, vrf_id, NULL); + } if (sd == -1) log_fatal("udp6-mhop: socket: %s", strerror(errno)); @@ -1130,11 +1138,13 @@ int bp_udp6_mhop(void) return sd; } -int bp_echo_socket(void) +int bp_echo_socket(vrf_id_t vrf_id) { int s; - s = socket(AF_INET, SOCK_DGRAM, 0); + frr_elevate_privs(&bglobal.bfdd_privs) { + s = vrf_socket(AF_INET, SOCK_DGRAM, 0, vrf_id, NULL); + } if (s == -1) log_fatal("echo-socket: socket: %s", strerror(errno)); @@ -1144,11 +1154,13 @@ int bp_echo_socket(void) return s; } -int bp_echov6_socket(void) +int bp_echov6_socket(vrf_id_t vrf_id) { int s; - s = socket(AF_INET6, SOCK_DGRAM, 0); + frr_elevate_privs(&bglobal.bfdd_privs) { + s = vrf_socket(AF_INET6, SOCK_DGRAM, 0, vrf_id, NULL); + } if (s == -1) log_fatal("echov6-socket: socket: %s", strerror(errno)); diff --git a/bfdd/bfdd.c b/bfdd/bfdd.c index 6023b5e4f0..218f0883c5 100644 --- a/bfdd/bfdd.c +++ b/bfdd/bfdd.c @@ -34,25 +34,13 @@ DEFINE_MTYPE(BFDD, BFDD_LABEL, "long-lived label memory"); DEFINE_MTYPE(BFDD, BFDD_CONTROL, "long-lived control socket memory"); DEFINE_MTYPE(BFDD, BFDD_SESSION_OBSERVER, "Session observer"); DEFINE_MTYPE(BFDD, BFDD_NOTIFICATION, "short-lived control notification data"); +DEFINE_MTYPE(BFDD, BFDD_VRF, "BFD VRF"); /* Master of threads. */ struct thread_master *master; /* BFDd privileges */ -static zebra_capabilities_t _caps_p[] = {ZCAP_BIND}; - -struct zebra_privs_t bfdd_privs = { -#if defined(FRR_USER) && defined(FRR_GROUP) - .user = FRR_USER, - .group = FRR_GROUP, -#endif -#if defined(VTY_GROUP) - .vty_group = VTY_GROUP, -#endif - .caps_p = _caps_p, - .cap_num_p = array_size(_caps_p), - .cap_num_i = 0, -}; +static zebra_capabilities_t _caps_p[] = {ZCAP_BIND, ZCAP_SYS_ADMIN, ZCAP_NET_RAW}; void socket_close(int *s) { @@ -85,12 +73,7 @@ static void sigterm_handler(void) /* Shutdown and free all protocol related memory. */ bfd_shutdown(); - /* Close all descriptors. */ - socket_close(&bglobal.bg_echo); - socket_close(&bglobal.bg_shop); - socket_close(&bglobal.bg_mhop); - socket_close(&bglobal.bg_shop6); - socket_close(&bglobal.bg_mhop6); + bfd_vrf_terminate(); /* Terminate and free() FRR related memory. */ frr_fini(); @@ -116,7 +99,7 @@ static struct quagga_signal_t bfd_signals[] = { FRR_DAEMON_INFO(bfdd, BFD, .vty_port = 2617, .proghelp = "Implementation of the BFD protocol.", .signals = bfd_signals, .n_signals = array_size(bfd_signals), - .privs = &bfdd_privs) + .privs = &bglobal.bfdd_privs) #define OPTION_CTLSOCK 1001 static struct option longopts[] = { @@ -153,15 +136,24 @@ struct bfd_state_str_list state_list[] = { static void bg_init(void) { + struct zebra_privs_t bfdd_privs = { +#if defined(FRR_USER) && defined(FRR_GROUP) + .user = FRR_USER, + .group = FRR_GROUP, +#endif +#if defined(VTY_GROUP) + .vty_group = VTY_GROUP, +#endif + .caps_p = _caps_p, + .cap_num_p = array_size(_caps_p), + .cap_num_i = 0, + }; + TAILQ_INIT(&bglobal.bg_bcslist); TAILQ_INIT(&bglobal.bg_obslist); - bglobal.bg_shop = bp_udp_shop(); - bglobal.bg_mhop = bp_udp_mhop(); - bglobal.bg_shop6 = bp_udp6_shop(); - bglobal.bg_mhop6 = bp_udp6_mhop(); - bglobal.bg_echo = bp_echo_socket(); - bglobal.bg_echov6 = bp_echov6_socket(); + memcpy(&bglobal.bfdd_privs, &bfdd_privs, + sizeof(bfdd_privs)); } int main(int argc, char *argv[]) @@ -169,6 +161,9 @@ int main(int argc, char *argv[]) const char *ctl_path = BFDD_CONTROL_SOCKET; int opt; + /* Initialize system sockets. */ + bg_init(); + frr_preinit(&bfdd_di, argc, argv); frr_opt_add("", longopts, " --bfdctl Specify bfdd control socket\n"); @@ -196,9 +191,6 @@ int main(int argc, char *argv[]) /* Initialize logging API. */ log_init(1, BLOG_DEBUG, &bfdd_di); - /* Initialize system sockets. */ - bg_init(); - /* Initialize control socket. */ control_init(ctl_path); @@ -208,22 +200,11 @@ int main(int argc, char *argv[]) /* Initialize BFD data structures. */ bfd_initialize(); + bfd_vrf_init(); + /* Initialize zebra connection. */ - bfdd_zclient_init(&bfdd_privs); - - /* Add descriptors to the event loop. */ - thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_shop, - &bglobal.bg_ev[0]); - thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_mhop, - &bglobal.bg_ev[1]); - thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_shop6, - &bglobal.bg_ev[2]); - thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_mhop6, - &bglobal.bg_ev[3]); - thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_echo, - &bglobal.bg_ev[4]); - thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_echov6, - &bglobal.bg_ev[5]); + bfdd_zclient_init(&bglobal.bfdd_privs); + thread_add_read(master, control_accept, NULL, bglobal.bg_csock, &bglobal.bg_csockev); diff --git a/bfdd/bfdd_vty.c b/bfdd/bfdd_vty.c index 4efdd817c1..75f6632db0 100644 --- a/bfdd/bfdd_vty.c +++ b/bfdd/bfdd_vty.c @@ -64,7 +64,7 @@ static struct json_object *__display_peer_json(struct bfd_session *bs); static struct json_object *_peer_json_header(struct bfd_session *bs); static void _display_peer_json(struct vty *vty, struct bfd_session *bs); static void _display_peer(struct vty *vty, struct bfd_session *bs); -static void _display_all_peers(struct vty *vty, bool use_json); +static void _display_all_peers(struct vty *vty, char *vrfname, bool use_json); static void _display_peer_iter(struct hash_bucket *hb, void *arg); static void _display_peer_json_iter(struct hash_bucket *hb, void *arg); static void _display_peer_counter(struct vty *vty, struct bfd_session *bs); @@ -72,7 +72,7 @@ static struct json_object *__display_peer_counters_json(struct bfd_session *bs); static void _display_peer_counters_json(struct vty *vty, struct bfd_session *bs); static void _display_peer_counter_iter(struct hash_bucket *hb, void *arg); static void _display_peer_counter_json_iter(struct hash_bucket *hb, void *arg); -static void _display_peers_counter(struct vty *vty, bool use_json); +static void _display_peers_counter(struct vty *vty, char *vrfname, bool use_json); static struct bfd_session * _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv, const char *label, const char *peer_str, @@ -90,7 +90,7 @@ DEFUN_NOSH(bfd_enter, bfd_enter_cmd, "bfd", "Configure BFD peers\n") DEFUN_NOSH( bfd_peer_enter, bfd_peer_enter_cmd, - "peer <A.B.C.D|X:X::X:X> [{[multihop] local-address <A.B.C.D|X:X::X:X>|interface IFNAME|vrf NAME}]", + "peer <A.B.C.D|X:X::X:X> [{multihop|local-address <A.B.C.D|X:X::X:X>|interface IFNAME|vrf NAME}]", PEER_STR PEER_IPV4_STR PEER_IPV6_STR MHOP_STR LOCAL_STR LOCAL_IPV4_STR LOCAL_IPV6_STR @@ -126,15 +126,6 @@ DEFUN_NOSH( if (argv_find(argv, argc, "vrf", &idx)) vrfname = argv[idx + 1]->arg; - if (vrfname && ifname) { - vty_out(vty, "%% VRF is not mixable with interface\n"); - return CMD_WARNING_CONFIG_FAILED; - } - if (vrfname && !mhop) { - vty_out(vty, "%% VRF only applies with multihop.\n"); - return CMD_WARNING_CONFIG_FAILED; - } - strtosa(peer, &psa); if (local) { strtosa(local, &lsa); @@ -360,7 +351,7 @@ DEFPY(bfd_no_peer, bfd_no_peer_cmd, return CMD_WARNING_CONFIG_FAILED; } - if (ptm_bfd_ses_del(&bpc) != 0) { + if (ptm_bfd_sess_del(&bpc) != 0) { vty_out(vty, "%% Failed to remove peer.\n"); return CMD_WARNING_CONFIG_FAILED; } @@ -549,19 +540,46 @@ static void _display_peer_json(struct vty *vty, struct bfd_session *bs) json_object_free(jo); } +struct bfd_vrf_tuple { + char *vrfname; + struct vty *vty; + struct json_object *jo; +}; + static void _display_peer_iter(struct hash_bucket *hb, void *arg) { - struct vty *vty = arg; + struct bfd_vrf_tuple *bvt = (struct bfd_vrf_tuple *)arg; + struct vty *vty; struct bfd_session *bs = hb->data; + if (!bvt) + return; + vty = bvt->vty; + + if (bvt->vrfname) { + if (!bs->key.vrfname[0] || + !strmatch(bs->key.vrfname, bvt->vrfname)) + return; + } _display_peer(vty, bs); } static void _display_peer_json_iter(struct hash_bucket *hb, void *arg) { - struct json_object *jo = arg, *jon = NULL; + struct bfd_vrf_tuple *bvt = (struct bfd_vrf_tuple *)arg; + struct json_object *jo, *jon = NULL; struct bfd_session *bs = hb->data; + if (!bvt) + return; + jo = bvt->jo; + + if (bvt->vrfname) { + if (!bs->key.vrfname[0] || + !strmatch(bs->key.vrfname, bvt->vrfname)) + return; + } + jon = __display_peer_json(bs); if (jon == NULL) { log_warning("%s: not enough memory", __func__); @@ -571,18 +589,24 @@ static void _display_peer_json_iter(struct hash_bucket *hb, void *arg) json_object_array_add(jo, jon); } -static void _display_all_peers(struct vty *vty, bool use_json) +static void _display_all_peers(struct vty *vty, char *vrfname, bool use_json) { struct json_object *jo; + struct bfd_vrf_tuple bvt; + + memset(&bvt, 0, sizeof(bvt)); + bvt.vrfname = vrfname; if (!use_json) { + bvt.vty = vty; vty_out(vty, "BFD Peers:\n"); - bfd_id_iterate(_display_peer_iter, vty); + bfd_id_iterate(_display_peer_iter, &bvt); return; } jo = json_object_new_array(); - bfd_id_iterate(_display_peer_json_iter, jo); + bvt.jo = jo; + bfd_id_iterate(_display_peer_json_iter, &bvt); vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0)); json_object_free(jo); @@ -634,16 +658,38 @@ static void _display_peer_counters_json(struct vty *vty, struct bfd_session *bs) static void _display_peer_counter_iter(struct hash_bucket *hb, void *arg) { - struct vty *vty = arg; + struct bfd_vrf_tuple *bvt = arg; + struct vty *vty; struct bfd_session *bs = hb->data; + if (!bvt) + return; + vty = bvt->vty; + + if (bvt->vrfname) { + if (!bs->key.vrfname[0] || + !strmatch(bs->key.vrfname, bvt->vrfname)) + return; + } + _display_peer_counter(vty, bs); } static void _display_peer_counter_json_iter(struct hash_bucket *hb, void *arg) { - struct json_object *jo = arg, *jon = NULL; + struct json_object *jo, *jon = NULL; struct bfd_session *bs = hb->data; + struct bfd_vrf_tuple *bvt = arg; + + if (!bvt) + return; + jo = bvt->jo; + + if (bvt->vrfname) { + if (!bs->key.vrfname[0] || + !strmatch(bs->key.vrfname, bvt->vrfname)) + return; + } jon = __display_peer_counters_json(bs); if (jon == NULL) { @@ -654,17 +700,22 @@ static void _display_peer_counter_json_iter(struct hash_bucket *hb, void *arg) json_object_array_add(jo, jon); } -static void _display_peers_counter(struct vty *vty, bool use_json) +static void _display_peers_counter(struct vty *vty, char *vrfname, bool use_json) { struct json_object *jo; + struct bfd_vrf_tuple bvt; + memset(&bvt, 0, sizeof(struct bfd_vrf_tuple)); + bvt.vrfname = vrfname; if (!use_json) { + bvt.vty = vty; vty_out(vty, "BFD Peers:\n"); - bfd_id_iterate(_display_peer_counter_iter, vty); + bfd_id_iterate(_display_peer_counter_iter, &bvt); return; } jo = json_object_new_array(); + bvt.jo = jo; bfd_id_iterate(_display_peer_counter_json_iter, jo); vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0)); @@ -734,24 +785,31 @@ _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv, /* * Show commands. */ -DEFPY(bfd_show_peers, bfd_show_peers_cmd, "show bfd peers [json]", +DEFPY(bfd_show_peers, bfd_show_peers_cmd, "show bfd [vrf <NAME>] peers [json]", SHOW_STR "Bidirection Forwarding Detection\n" + VRF_CMD_HELP_STR "BFD peers status\n" JSON_STR) { - _display_all_peers(vty, use_json(argc, argv)); + char *vrf_name = NULL; + int idx_vrf = 0; + + if (argv_find(argv, argc, "vrf", &idx_vrf)) + vrf_name = argv[idx_vrf + 1]->arg; + + _display_all_peers(vty, vrf_name, use_json(argc, argv)); return CMD_SUCCESS; } DEFPY(bfd_show_peer, bfd_show_peer_cmd, - "show bfd peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrfname}]> [json]", + "show bfd [vrf <NAME$vrfname>] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json]", SHOW_STR "Bidirection Forwarding Detection\n" + VRF_CMD_HELP_STR "BFD peers status\n" "Peer label\n" PEER_IPV4_STR PEER_IPV6_STR MHOP_STR LOCAL_STR - LOCAL_IPV4_STR LOCAL_IPV6_STR INTERFACE_STR LOCAL_INTF_STR VRF_STR - VRF_NAME_STR JSON_STR) + LOCAL_IPV4_STR LOCAL_IPV6_STR INTERFACE_STR LOCAL_INTF_STR JSON_STR) { struct bfd_session *bs; @@ -772,9 +830,10 @@ DEFPY(bfd_show_peer, bfd_show_peer_cmd, } DEFPY(bfd_show_peer_counters, bfd_show_peer_counters_cmd, - "show bfd peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrfname}]> counters [json]", + "show bfd [vrf <NAME$vrfname>] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> counters [json]", SHOW_STR "Bidirection Forwarding Detection\n" + VRF_CMD_HELP_STR "BFD peers status\n" "Peer label\n" PEER_IPV4_STR @@ -785,8 +844,6 @@ DEFPY(bfd_show_peer_counters, bfd_show_peer_counters_cmd, LOCAL_IPV6_STR INTERFACE_STR LOCAL_INTF_STR - VRF_STR - VRF_NAME_STR "Show BFD peer counters information\n" JSON_STR) { @@ -807,14 +864,21 @@ DEFPY(bfd_show_peer_counters, bfd_show_peer_counters_cmd, } DEFPY(bfd_show_peers_counters, bfd_show_peers_counters_cmd, - "show bfd peers counters [json]", + "show bfd [vrf <NAME>] peers counters [json]", SHOW_STR "Bidirection Forwarding Detection\n" + VRF_CMD_HELP_STR "BFD peers status\n" "Show BFD peer counters information\n" JSON_STR) { - _display_peers_counter(vty, use_json(argc, argv)); + char *vrf_name = NULL; + int idx_vrf = 0; + + if (argv_find(argv, argc, "vrf", &idx_vrf)) + vrf_name = argv[idx_vrf + 1]->arg; + + _display_peers_counter(vty, vrf_name, use_json(argc, argv)); return CMD_SUCCESS; } diff --git a/bfdd/bsd.c b/bfdd/bsd.c deleted file mode 100644 index 923fbd909e..0000000000 --- a/bfdd/bsd.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * *BSD specific code - * - * Copyright (C) 2018 Network Device Education Foundation, Inc. ("NetDEF") - * - * FRR is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * FRR is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with FRR; see the file COPYING. If not, write to the Free - * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include <zebra.h> - -#ifdef BFD_BSD - -#include <net/if.h> -#include <net/if_types.h> -#include <sys/types.h> -#include <sys/socket.h> - -#include <ifaddrs.h> - -#include "bfd.h" - -/* - * Definitions. - */ -int bp_bind_dev(int sd, const char *dev) -{ - /* - * *BSDs don't support `SO_BINDTODEVICE`, instead you must - * manually specify the main address of the interface or use - * BPF on the socket descriptor. - */ - return 0; -} - -#endif /* BFD_BSD */ diff --git a/bfdd/config.c b/bfdd/config.c index cd57ea9fe3..74e7d63d0c 100644 --- a/bfdd/config.c +++ b/bfdd/config.c @@ -68,7 +68,7 @@ static int config_add(struct bfd_peer_cfg *bpc, static int config_del(struct bfd_peer_cfg *bpc, void *arg __attribute__((unused))) { - return ptm_bfd_ses_del(bpc) != 0; + return ptm_bfd_sess_del(bpc) != 0; } static int parse_config_json(struct json_object *jo, bpc_handle h, void *arg) diff --git a/bfdd/linux.c b/bfdd/linux.c deleted file mode 100644 index 3a76b459d7..0000000000 --- a/bfdd/linux.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Linux specific code - * - * Copyright (C) 2018 Network Device Education Foundation, Inc. ("NetDEF") - * - * FRR is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * FRR is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with FRR; see the file COPYING. If not, write to the Free - * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include <zebra.h> - -#ifdef BFD_LINUX - -#include "bfd.h" - - -/* - * Definitions. - */ -int bp_bind_dev(int sd __attribute__((__unused__)), - const char *dev __attribute__((__unused__))) -{ - /* - * TODO: implement this differently. It is not possible to - * SO_BINDTODEVICE after the daemon has dropped its privileges. - */ -#if 0 - size_t devlen = strlen(dev) + 1; - - if (setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, dev, devlen) == -1) { - log_warning("%s: setsockopt(SO_BINDTODEVICE, \"%s\"): %s", - __func__, dev, strerror(errno)); - return -1; - } -#endif - - return 0; -} - -#endif /* BFD_LINUX */ diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c index 6f76a15a57..a12a3c196b 100644 --- a/bfdd/ptm_adapter.c +++ b/bfdd/ptm_adapter.c @@ -58,7 +58,7 @@ static struct zclient *zclient; static int _ptm_msg_address(struct stream *msg, int family, const void *addr); static void _ptm_msg_read_address(struct stream *msg, struct sockaddr_any *sa); -static int _ptm_msg_read(struct stream *msg, int command, +static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id, struct bfd_peer_cfg *bpc, struct ptm_client **pc); static struct ptm_client *pc_lookup(uint32_t pid); @@ -72,8 +72,8 @@ static struct ptm_client_notification *pcn_lookup(struct ptm_client *pc, static void pcn_free(struct ptm_client_notification *pcn); -static void bfdd_dest_register(struct stream *msg); -static void bfdd_dest_deregister(struct stream *msg); +static void bfdd_dest_register(struct stream *msg, vrf_id_t vrf_id); +static void bfdd_dest_deregister(struct stream *msg, vrf_id_t vrf_id); static void bfdd_client_register(struct stream *msg); static void bfdd_client_deregister(struct stream *msg); @@ -182,7 +182,10 @@ int ptm_bfd_notify(struct bfd_session *bs) stream_reset(msg); /* TODO: VRF handling */ - zclient_create_header(msg, ZEBRA_BFD_DEST_REPLAY, VRF_DEFAULT); + if (bs->vrf) + zclient_create_header(msg, ZEBRA_BFD_DEST_REPLAY, bs->vrf->vrf_id); + else + zclient_create_header(msg, ZEBRA_BFD_DEST_REPLAY, VRF_DEFAULT); /* This header will be handled by `zebra_ptm.c`. */ stream_putl(msg, ZEBRA_INTERFACE_BFD_DEST_UPDATE); @@ -256,7 +259,7 @@ stream_failure: memset(sa, 0, sizeof(*sa)); } -static int _ptm_msg_read(struct stream *msg, int command, +static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id, struct bfd_peer_cfg *bpc, struct ptm_client **pc) { uint32_t pid; @@ -355,6 +358,18 @@ static int _ptm_msg_read(struct stream *msg, int command, bpc->bpc_localif[ifnamelen] = 0; } } + if (vrf_id != VRF_DEFAULT) { + struct vrf *vrf; + + vrf = vrf_lookup_by_id(vrf_id); + if (vrf) { + bpc->bpc_has_vrfname = true; + strlcpy(bpc->bpc_vrfname, vrf->name, sizeof(bpc->bpc_vrfname)); + } else { + log_error("ptm-read: vrf id %u could not be identified", vrf_id); + return -1; + } + } /* Sanity check: peer and local address must match IP types. */ if (bpc->bpc_local.sa_sin.sin_family != 0 @@ -370,7 +385,7 @@ stream_failure: return -1; } -static void bfdd_dest_register(struct stream *msg) +static void bfdd_dest_register(struct stream *msg, vrf_id_t vrf_id) { struct ptm_client *pc; struct ptm_client_notification *pcn; @@ -378,7 +393,7 @@ static void bfdd_dest_register(struct stream *msg) struct bfd_peer_cfg bpc; /* Read the client context and peer data. */ - if (_ptm_msg_read(msg, ZEBRA_BFD_DEST_REGISTER, &bpc, &pc) == -1) + if (_ptm_msg_read(msg, ZEBRA_BFD_DEST_REGISTER, vrf_id, &bpc, &pc) == -1) return; DEBUG_PRINTBPC(&bpc); @@ -408,7 +423,7 @@ static void bfdd_dest_register(struct stream *msg) ptm_bfd_notify(bs); } -static void bfdd_dest_deregister(struct stream *msg) +static void bfdd_dest_deregister(struct stream *msg, vrf_id_t vrf_id) { struct ptm_client *pc; struct ptm_client_notification *pcn; @@ -416,7 +431,7 @@ static void bfdd_dest_deregister(struct stream *msg) struct bfd_peer_cfg bpc; /* Read the client context and peer data. */ - if (_ptm_msg_read(msg, ZEBRA_BFD_DEST_DEREGISTER, &bpc, &pc) == -1) + if (_ptm_msg_read(msg, ZEBRA_BFD_DEST_DEREGISTER, vrf_id, &bpc, &pc) == -1) return; DEBUG_PRINTBPC(&bpc); @@ -434,7 +449,7 @@ static void bfdd_dest_deregister(struct stream *msg) if (bs->refcount || BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG)) return; - ptm_bfd_ses_del(&bpc); + ptm_bfd_sess_del(&bpc); } /* @@ -497,10 +512,10 @@ static int bfdd_replay(ZAPI_CALLBACK_ARGS) switch (rcmd) { case ZEBRA_BFD_DEST_REGISTER: case ZEBRA_BFD_DEST_UPDATE: - bfdd_dest_register(msg); + bfdd_dest_register(msg, vrf_id); break; case ZEBRA_BFD_DEST_DEREGISTER: - bfdd_dest_deregister(msg); + bfdd_dest_deregister(msg, vrf_id); break; case ZEBRA_BFD_CLIENT_REGISTER: bfdd_client_register(msg); @@ -548,15 +563,21 @@ static void bfdd_sessions_enable_interface(struct interface *ifp) { struct bfd_session_observer *bso; struct bfd_session *bs; + struct vrf *vrf; TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) { + bs = bso->bso_bs; if (bso->bso_isinterface == false) continue; - /* Interface name mismatch. */ - bs = bso->bso_bs; if (strcmp(ifp->name, bs->key.ifname)) continue; + vrf = vrf_lookup_by_id(ifp->vrf_id); + if (!vrf) + continue; + if (bs->key.vrfname[0] && + strcmp(vrf->name, bs->key.vrfname)) + continue; /* Skip enabled sessions. */ if (bs->sock != -1) continue; @@ -586,7 +607,52 @@ static void bfdd_sessions_disable_interface(struct interface *ifp) /* Try to enable it. */ bfd_session_disable(bs); - TAILQ_INSERT_HEAD(&bglobal.bg_obslist, bso, bso_entry); + } +} + +void bfdd_sessions_enable_vrf(struct vrf *vrf) +{ + struct bfd_session_observer *bso; + struct bfd_session *bs; + + /* it may affect configs without interfaces */ + TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) { + bs = bso->bso_bs; + if (bs->vrf) + continue; + if (bs->key.vrfname[0] && + strcmp(vrf->name, bs->key.vrfname)) + continue; + /* need to update the vrf information on + * bs so that callbacks are handled + */ + bs->vrf = vrf; + /* Skip enabled sessions. */ + if (bs->sock != -1) + continue; + /* Try to enable it. */ + bfd_session_enable(bs); + } +} + +void bfdd_sessions_disable_vrf(struct vrf *vrf) +{ + struct bfd_session_observer *bso; + struct bfd_session *bs; + + TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) { + if (bso->bso_isinterface) + continue; + bs = bso->bso_bs; + if (bs->key.vrfname[0] && + strcmp(vrf->name, bs->key.vrfname)) + continue; + /* Skip disabled sessions. */ + if (bs->sock == -1) + continue; + + /* Try to enable it. */ + bfd_session_disable(bs); } } @@ -701,6 +767,20 @@ void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv) zclient->interface_address_delete = bfdd_interface_address_update; } +void bfdd_zclient_register(vrf_id_t vrf_id) +{ + if (!zclient || zclient->sock < 0) + return; + zclient_send_reg_requests(zclient, vrf_id); +} + +void bfdd_zclient_unregister(vrf_id_t vrf_id) +{ + if (!zclient || zclient->sock < 0) + return; + zclient_send_dereg_requests(zclient, vrf_id); +} + void bfdd_zclient_stop(void) { zclient_stop(zclient); diff --git a/bfdd/subdir.am b/bfdd/subdir.am index 334e974b04..e88b982ec3 100644 --- a/bfdd/subdir.am +++ b/bfdd/subdir.am @@ -14,11 +14,9 @@ bfdd_libbfd_a_SOURCES = \ bfdd/bfd.c \ bfdd/bfdd_vty.c \ bfdd/bfd_packet.c \ - bfdd/bsd.c \ bfdd/config.c \ bfdd/control.c \ bfdd/event.c \ - bfdd/linux.c \ bfdd/log.c \ bfdd/ptm_adapter.c \ # end diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 0699c8adfa..0e9d387153 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1255,6 +1255,32 @@ static int bgp_attr_as4_path(struct bgp_attr_parser_args *args, return BGP_ATTR_PARSE_PROCEED; } +/* + * Check that the nexthop attribute is valid. + */ +bgp_attr_parse_ret_t +bgp_attr_nexthop_valid(struct peer *peer, struct attr *attr) +{ + in_addr_t nexthop_h; + + nexthop_h = ntohl(attr->nexthop.s_addr); + if ((IPV4_NET0(nexthop_h) || IPV4_NET127(nexthop_h) + || IPV4_CLASS_DE(nexthop_h)) + && !BGP_DEBUG(allow_martians, ALLOW_MARTIANS)) { + char buf[INET_ADDRSTRLEN]; + + inet_ntop(AF_INET, &attr->nexthop.s_addr, buf, + INET_ADDRSTRLEN); + flog_err(EC_BGP_ATTR_MARTIAN_NH, "Martian nexthop %s", + buf); + bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP); + return BGP_ATTR_PARSE_ERROR; + } + + return BGP_ATTR_PARSE_PROCEED; +} + /* Nexthop attribute. */ static bgp_attr_parse_ret_t bgp_attr_nexthop(struct bgp_attr_parser_args *args) { @@ -1262,8 +1288,6 @@ static bgp_attr_parse_ret_t bgp_attr_nexthop(struct bgp_attr_parser_args *args) struct attr *const attr = args->attr; const bgp_size_t length = args->length; - in_addr_t nexthop_h, nexthop_n; - /* Check nexthop attribute length. */ if (length != 4) { flog_err(EC_BGP_ATTR_LEN, @@ -1273,30 +1297,7 @@ static bgp_attr_parse_ret_t bgp_attr_nexthop(struct bgp_attr_parser_args *args) args->total); } - /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP - attribute must result in a NOTIFICATION message (this is implemented - below). - At the same time, semantically incorrect NEXT_HOP is more likely to - be just - logged locally (this is implemented somewhere else). The UPDATE - message - gets ignored in any of these cases. */ - nexthop_n = stream_get_ipv4(peer->curr); - nexthop_h = ntohl(nexthop_n); - if ((IPV4_NET0(nexthop_h) || IPV4_NET127(nexthop_h) - || IPV4_CLASS_DE(nexthop_h)) - && !BGP_DEBUG( - allow_martians, - ALLOW_MARTIANS)) /* loopbacks may be used in testing */ - { - char buf[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, &nexthop_n, buf, INET_ADDRSTRLEN); - flog_err(EC_BGP_ATTR_MARTIAN_NH, "Martian nexthop %s", buf); - return bgp_attr_malformed( - args, BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP, args->total); - } - - attr->nexthop.s_addr = nexthop_n; + attr->nexthop.s_addr = stream_get_ipv4(peer->curr); attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); return BGP_ATTR_PARSE_PROCEED; @@ -2684,6 +2685,26 @@ bgp_attr_parse_ret_t bgp_attr_parse(struct peer *peer, struct attr *attr, return BGP_ATTR_PARSE_ERROR; } + /* + * RFC4271: If the NEXT_HOP attribute field is syntactically incorrect, + * then the Error Subcode MUST be set to Invalid NEXT_HOP Attribute. + * This is implemented below and will result in a NOTIFICATION. If the + * NEXT_HOP attribute is semantically incorrect, the error SHOULD be + * logged, and the route SHOULD be ignored. In this case, a NOTIFICATION + * message SHOULD NOT be sent. This is implemented elsewhere. + * + * RFC4760: An UPDATE message that carries no NLRI, other than the one + * encoded in the MP_REACH_NLRI attribute, SHOULD NOT carry the NEXT_HOP + * attribute. If such a message contains the NEXT_HOP attribute, the BGP + * speaker that receives the message SHOULD ignore this attribute. + */ + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) + && !CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI))) { + if (bgp_attr_nexthop_valid(peer, attr) < 0) { + return BGP_ATTR_PARSE_ERROR; + } + } + /* Check all mandatory well-known attributes are present */ if ((ret = bgp_attr_check(peer, attr)) < 0) { if (as4_path) diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 3518f1accb..a6fdac9ebf 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -348,6 +348,9 @@ extern void bgp_packet_mpunreach_prefix(struct stream *s, struct prefix *p, uint32_t, int, uint32_t, struct attr *); extern void bgp_packet_mpunreach_end(struct stream *s, size_t attrlen_pnt); +extern bgp_attr_parse_ret_t bgp_attr_nexthop_valid(struct peer *peer, + struct attr *attr); + static inline int bgp_rmap_nhop_changed(uint32_t out_rmap_flags, uint32_t in_rmap_flags) { diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c index 45e45977a4..a9c30acafb 100644 --- a/bgpd/bgp_bfd.c +++ b/bgpd/bgp_bfd.c @@ -96,13 +96,12 @@ int bgp_bfd_is_peer_multihop(struct peer *peer) static void bgp_bfd_peer_sendmsg(struct peer *peer, int command) { struct bfd_info *bfd_info; - vrf_id_t vrf_id = VRF_DEFAULT; int multihop; + vrf_id_t vrf_id; bfd_info = (struct bfd_info *)peer->bfd_info; - if (peer->bgp->inst_type == BGP_INSTANCE_TYPE_VRF) - vrf_id = peer->bgp->vrf_id; + vrf_id = peer->bgp->vrf_id; if (command == ZEBRA_BFD_DEST_DEREGISTER) { multihop = @@ -244,7 +243,7 @@ static int bgp_bfd_dest_replay(ZAPI_CALLBACK_ARGS) zlog_debug("Zebra: BFD Dest replay request"); /* Send the client registration */ - bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER); + bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id); /* Replay the peer, if BFD is enabled in BGP */ diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 1bd153639b..4296604c4a 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -1048,7 +1048,20 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd, rd_header = 1; tbl_ver = table->version; - for (rm = bgp_table_top(table); rm; rm = bgp_route_next(rm)) + for (rm = bgp_table_top(table); rm; rm = bgp_route_next(rm)) { + if (use_json) { + json_array = json_object_new_array(); + json_prefix_info = json_object_new_object(); + + json_object_string_add(json_prefix_info, + "prefix", bgp_evpn_route2str( + (struct prefix_evpn *)&rm->p, buf, + BUFSIZ)); + + json_object_int_add(json_prefix_info, + "prefixLen", rm->p.prefixlen); + } + for (pi = bgp_node_get_bgp_path_info(rm); pi; pi = pi->next) { total_count++; @@ -1121,10 +1134,6 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd, if (use_json) { json_nroute = json_object_new_object(); - json_prefix_info = - json_object_new_object(); - json_array = - json_object_new_array(); if (type == RD_TYPE_AS || type == RD_TYPE_AS4) sprintf(rd_str, "%u:%d", @@ -1140,18 +1149,6 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd, "rd", rd_str); - json_object_string_add( - json_prefix_info, - "prefix", - bgp_evpn_route2str( - (struct prefix_evpn *) - &rm->p, buf, BUFSIZ)); - - json_object_int_add( - json_prefix_info, - "prefixLen", - rm->p.prefixlen); - } else { vty_out(vty, "Route Distinguisher: "); @@ -1174,6 +1171,7 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd, } rd_header = 0; } + if (option == SHOW_DISPLAY_TAGS) route_vty_out_tag(vty, &rm->p, pi, 0, SAFI_EVPN, @@ -1186,14 +1184,16 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd, SAFI_EVPN, json_array); output_count++; } + if (use_json) { + json_object_object_add(json_prefix_info, + "paths", json_array); + json_object_object_add(json_nroute, buf, + json_prefix_info); + } + } - if (use_json) { - json_object_object_add(json_prefix_info, "paths", - json_array); - json_object_object_add(json_nroute, buf, - json_prefix_info); + if (use_json) json_object_object_add(json, rd_str, json_nroute); - } } if (use_json) { diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 130e06a6cf..b5934fb56e 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1533,6 +1533,17 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size) nlris[NLRI_UPDATE].nlri = stream_pnt(s); nlris[NLRI_UPDATE].length = update_len; stream_forward_getp(s, update_len); + + if (CHECK_FLAG(attr.flag, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI))) { + /* + * We skipped nexthop attribute validation earlier so + * validate the nexthop now. + */ + if (bgp_attr_nexthop_valid(peer, &attr) < 0) { + bgp_attr_unintern_sub(&attr); + return BGP_Stop; + } + } } if (BGP_DEBUG(update, UPDATE_IN)) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 0da9a84b56..9ff4196dae 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -3447,7 +3447,7 @@ static void bgp_route_map_delete(const char *rmap_name) route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_DELETED); } -static void bgp_route_map_event(route_map_event_t event, const char *rmap_name) +static void bgp_route_map_event(const char *rmap_name) { if (route_map_mark_updated(rmap_name) == 0) bgp_route_map_mark_update(rmap_name); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index d47c1f9638..a45480fdc2 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -2441,7 +2441,7 @@ static void bgp_zebra_connected(struct zclient *zclient) bgp_zebra_instance_register(bgp); /* Send the client registration */ - bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER); + bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, bgp->vrf_id); /* tell label pool that zebra is connected */ bgp_lp_event_zebra_up(); diff --git a/bgpd/rfapi/bgp_rfapi_cfg.c b/bgpd/rfapi/bgp_rfapi_cfg.c index 2220f0ed9a..cad33404fa 100644 --- a/bgpd/rfapi/bgp_rfapi_cfg.c +++ b/bgpd/rfapi/bgp_rfapi_cfg.c @@ -2208,24 +2208,6 @@ void vnc_routemap_update(struct bgp *bgp, const char *unused) vnc_zlog_debug_verbose("%s done", __func__); } -#if 0 /* superseded */ -static void vnc_routemap_event(route_map_event_t type, /* ignored */ - const char *rmap_name) /* ignored */ -{ - struct listnode *mnode, *mnnode; - struct bgp *bgp; - - vnc_zlog_debug_verbose("%s(event type=%d)", __func__, type); - if (bm->bgp == NULL) /* may be called during cleanup */ - return; - - for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) - vnc_routemap_update(bgp, rmap_name); - - vnc_zlog_debug_verbose("%s: done", __func__); -} -#endif - /*------------------------------------------------------------------------- * nve-group *-----------------------------------------------------------------------*/ @@ -3699,10 +3681,6 @@ bgp_rfapi_get_ecommunity_by_lni_label(struct bgp *bgp, uint32_t is_import, void bgp_rfapi_cfg_init(void) { - /* main bgpd code does not use this hook, but vnc does */ - /* superseded by bgp_route_map_process_update_cb() */ - /* bgp_route_map_event_hook_add(vnc_routemap_event); */ - install_node(&bgp_vnc_defaults_node, NULL); install_node(&bgp_vnc_nve_group_node, NULL); install_node(&bgp_vrf_policy_node, NULL); diff --git a/doc/developer/building-frr-for-ubuntu1804.rst b/doc/developer/building-frr-for-ubuntu1804.rst index 1320bda577..8bdc2b9c76 100644 --- a/doc/developer/building-frr-for-ubuntu1804.rst +++ b/doc/developer/building-frr-for-ubuntu1804.rst @@ -104,6 +104,10 @@ And load the kernel modules on the running system: sudo modprobe mpls-router mpls-iptunnel +If the above command returns an error, you may need to install the appropriate +or latest linux-modules-extra-<kernel-version>-generic package. For example +``apt-get install linux-modules-extra-`uname -r`-generic`` + Enable MPLS Forwarding """""""""""""""""""""" diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst index 605b9c9a0c..1e165a2444 100644 --- a/doc/developer/topotests.rst +++ b/doc/developer/topotests.rst @@ -105,6 +105,8 @@ Execute all tests with output to console py.test -s -v --tb=no +The above command must be executed from inside the topotests directory. + All test\_\* scripts in subdirectories are detected and executed (unless disabled in ``pytest.ini`` file). @@ -119,6 +121,13 @@ Execute single test cd test_to_be_run ./test_to_be_run.py +For example, and assuming you are inside the frr directory: + +.. code:: shell + + cd tests/topotests/bgp_l3vpn_to_bgp_vrf + ./test_bgp_l3vpn_to_bgp_vrf.py + For further options, refer to pytest documentation. Test will set exit code which can be used with ``git bisect``. diff --git a/doc/user/bfd.rst b/doc/user/bfd.rst index 986d1494a5..a7c5cf28bc 100644 --- a/doc/user/bfd.rst +++ b/doc/user/bfd.rst @@ -72,8 +72,7 @@ BFDd Commands peer listener to and the address we should use to send the packets. This option is mandatory for IPv6. - `interface` selects which interface we should use. This option - conflicts with `vrf`. + `interface` selects which interface we should use. `vrf` selects which domain we want to use. @@ -82,13 +81,13 @@ BFDd Commands Stops and removes the selected peer. -.. index:: show bfd peers [json] -.. clicmd:: show bfd peers [json] +.. index:: show bfd [vrf NAME] peers [json] +.. clicmd:: show bfd [vrf NAME] peers [json] Show all configured BFD peers information and current status. -.. index:: show bfd peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrfname}]> [json] -.. clicmd:: show bfd peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrfname}]> [json] +.. index:: show bfd [vrf NAME$vrfname] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json] +.. clicmd:: show bfd [vrf NAME$vrfname] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json] Show status for a specific BFD peer. @@ -296,6 +295,11 @@ Here are the available peer configurations: shutdown ! + ! configure a peer on an interface from a separate vrf + peer 192.168.0.5 interface eth1 vrf vrf2 + no shutdown + ! + ! remove a peer no peer 192.168.0.3 vrf foo diff --git a/doc/user/ospf6d.rst b/doc/user/ospf6d.rst index 71bc047720..6413c62995 100644 --- a/doc/user/ospf6d.rst +++ b/doc/user/ospf6d.rst @@ -15,8 +15,8 @@ OSPF6 router .. index:: router ospf6 .. clicmd:: router ospf6 -.. index:: router-id A.B.C.D -.. clicmd:: router-id A.B.C.D +.. index:: ospf6 router-id A.B.C.D +.. clicmd:: ospf6 router-id A.B.C.D Set router's Router-ID. diff --git a/isisd/isis_bfd.c b/isisd/isis_bfd.c index a98c44eeb0..fccef0169e 100644 --- a/isisd/isis_bfd.c +++ b/isisd/isis_bfd.c @@ -139,7 +139,7 @@ static int isis_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS) static int isis_bfd_nbr_replay(ZAPI_CALLBACK_ARGS) { - bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER); + bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id); struct listnode *anode; struct isis_area *area; @@ -167,7 +167,7 @@ static void isis_bfd_zebra_connected(struct zclient *zclient) if (orig_zebra_connected) orig_zebra_connected(zclient); - bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER); + bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT); } static void bfd_debug(struct in_addr *dst, struct in_addr *src, @@ -433,7 +433,8 @@ void bfd_show_info(struct vty *vty, struct bfd_info *bfd_info, int multihop, * bfd_client_sendmsg - Format and send a client register * command to Zebra to be forwarded to BFD */ -void bfd_client_sendmsg(struct zclient *zclient, int command) +void bfd_client_sendmsg(struct zclient *zclient, int command, + vrf_id_t vrf_id) { struct stream *s; int ret; @@ -450,7 +451,7 @@ void bfd_client_sendmsg(struct zclient *zclient, int command) s = zclient->obuf; stream_reset(s); - zclient_create_header(s, command, VRF_DEFAULT); + zclient_create_header(s, command, vrf_id); stream_putl(s, getpid()); @@ -102,7 +102,8 @@ extern void bfd_show_info(struct vty *vty, struct bfd_info *bfd_info, int multihop, int extra_space, bool use_json, json_object *json_obj); -extern void bfd_client_sendmsg(struct zclient *zclient, int command); +extern void bfd_client_sendmsg(struct zclient *zclient, int command, + vrf_id_t vrf_id); extern void bfd_gbl_init(void); diff --git a/lib/grammar_sandbox_main.c b/lib/grammar_sandbox_main.c index c9c942f9bf..38494fb007 100644 --- a/lib/grammar_sandbox_main.c +++ b/lib/grammar_sandbox_main.c @@ -58,6 +58,8 @@ int main(int argc, char **argv) vty_init(master); memory_init(); + yang_init(); + nb_init(master, NULL, 0); vty_stdio(vty_do_exit); diff --git a/lib/openbsd-tree.c b/lib/openbsd-tree.c index eadef9902b..ddcc59fa8f 100644 --- a/lib/openbsd-tree.c +++ b/lib/openbsd-tree.c @@ -435,7 +435,8 @@ void *_rb_insert(const struct rb_type *t, struct rbt_tree *rbt, void *elm) } /* Finds the node with the same key as elm */ -void *_rb_find(const struct rb_type *t, struct rbt_tree *rbt, const void *key) +void *_rb_find(const struct rb_type *t, const struct rbt_tree *rbt, + const void *key) { struct rb_entry *tmp = RBH_ROOT(rbt); void *node; @@ -456,7 +457,8 @@ void *_rb_find(const struct rb_type *t, struct rbt_tree *rbt, const void *key) } /* Finds the first node greater than or equal to the search key */ -void *_rb_nfind(const struct rb_type *t, struct rbt_tree *rbt, const void *key) +void *_rb_nfind(const struct rb_type *t, const struct rbt_tree *rbt, + const void *key) { struct rb_entry *tmp = RBH_ROOT(rbt); void *node; @@ -522,14 +524,14 @@ void *_rb_prev(const struct rb_type *t, void *elm) return (rbe == NULL ? NULL : rb_e2n(t, rbe)); } -void *_rb_root(const struct rb_type *t, struct rbt_tree *rbt) +void *_rb_root(const struct rb_type *t, const struct rbt_tree *rbt) { struct rb_entry *rbe = RBH_ROOT(rbt); return (rbe == NULL ? rbe : rb_e2n(t, rbe)); } -void *_rb_min(const struct rb_type *t, struct rbt_tree *rbt) +void *_rb_min(const struct rb_type *t, const struct rbt_tree *rbt) { struct rb_entry *rbe = RBH_ROOT(rbt); struct rb_entry *parent = NULL; @@ -542,7 +544,7 @@ void *_rb_min(const struct rb_type *t, struct rbt_tree *rbt) return (parent == NULL ? NULL : rb_e2n(t, parent)); } -void *_rb_max(const struct rb_type *t, struct rbt_tree *rbt) +void *_rb_max(const struct rb_type *t, const struct rbt_tree *rbt) { struct rb_entry *rbe = RBH_ROOT(rbt); struct rb_entry *parent = NULL; diff --git a/lib/openbsd-tree.h b/lib/openbsd-tree.h index d2f0781333..832a10141e 100644 --- a/lib/openbsd-tree.h +++ b/lib/openbsd-tree.h @@ -364,18 +364,18 @@ static inline void _rb_init(struct rbt_tree *rbt) rbt->rbt_root = NULL; } -static inline int _rb_empty(struct rbt_tree *rbt) +static inline int _rb_empty(const struct rbt_tree *rbt) { return (rbt->rbt_root == NULL); } void *_rb_insert(const struct rb_type *, struct rbt_tree *, void *); void *_rb_remove(const struct rb_type *, struct rbt_tree *, void *); -void *_rb_find(const struct rb_type *, struct rbt_tree *, const void *); -void *_rb_nfind(const struct rb_type *, struct rbt_tree *, const void *); -void *_rb_root(const struct rb_type *, struct rbt_tree *); -void *_rb_min(const struct rb_type *, struct rbt_tree *); -void *_rb_max(const struct rb_type *, struct rbt_tree *); +void *_rb_find(const struct rb_type *, const struct rbt_tree *, const void *); +void *_rb_nfind(const struct rb_type *, const struct rbt_tree *, const void *); +void *_rb_root(const struct rb_type *, const struct rbt_tree *); +void *_rb_min(const struct rb_type *, const struct rbt_tree *); +void *_rb_max(const struct rb_type *, const struct rbt_tree *); void *_rb_next(const struct rb_type *, void *); void *_rb_prev(const struct rb_type *, void *); void *_rb_left(const struct rb_type *, void *); @@ -401,56 +401,58 @@ int _rb_check(const struct rb_type *, void *, unsigned long); __attribute__((__unused__)) static inline struct _type \ *_name##_RB_INSERT(struct _name *head, struct _type *elm) \ { \ - return (struct _type *)_rb_insert( \ - _name##_RB_TYPE, &head->rbh_root, elm); \ + return (struct _type *)_rb_insert(_name##_RB_TYPE, \ + &head->rbh_root, elm); \ } \ \ __attribute__((__unused__)) static inline struct _type \ *_name##_RB_REMOVE(struct _name *head, struct _type *elm) \ { \ - return (struct _type *)_rb_remove( \ - _name##_RB_TYPE, &head->rbh_root, elm); \ + return (struct _type *)_rb_remove(_name##_RB_TYPE, \ + &head->rbh_root, elm); \ } \ \ __attribute__((__unused__)) static inline struct _type \ - *_name##_RB_FIND(struct _name *head, const struct _type *key) \ + *_name##_RB_FIND(const struct _name *head, \ + const struct _type *key) \ { \ - return (struct _type *)_rb_find( \ - _name##_RB_TYPE, &head->rbh_root, key); \ + return (struct _type *)_rb_find(_name##_RB_TYPE, \ + &head->rbh_root, key); \ } \ \ __attribute__((__unused__)) static inline struct _type \ - *_name##_RB_NFIND(struct _name *head, const struct _type *key) \ + *_name##_RB_NFIND(const struct _name *head, \ + const struct _type *key) \ { \ - return (struct _type *)_rb_nfind( \ - _name##_RB_TYPE, &head->rbh_root, key); \ + return (struct _type *)_rb_nfind(_name##_RB_TYPE, \ + &head->rbh_root, key); \ } \ \ __attribute__((__unused__)) static inline struct _type \ - *_name##_RB_ROOT(struct _name *head) \ + *_name##_RB_ROOT(const struct _name *head) \ { \ - return (struct _type *)_rb_root( \ - _name##_RB_TYPE, &head->rbh_root); \ + return (struct _type *)_rb_root(_name##_RB_TYPE, \ + &head->rbh_root); \ } \ \ __attribute__((__unused__)) static inline int _name##_RB_EMPTY( \ - struct _name *head) \ + const struct _name *head) \ { \ return _rb_empty(&head->rbh_root); \ } \ \ __attribute__((__unused__)) static inline struct _type \ - *_name##_RB_MIN(struct _name *head) \ + *_name##_RB_MIN(const struct _name *head) \ { \ - return (struct _type *)_rb_min( \ - _name##_RB_TYPE, &head->rbh_root); \ + return (struct _type *)_rb_min(_name##_RB_TYPE, \ + &head->rbh_root); \ } \ \ __attribute__((__unused__)) static inline struct _type \ - *_name##_RB_MAX(struct _name *head) \ + *_name##_RB_MAX(const struct _name *head) \ { \ - return (struct _type *)_rb_max( \ - _name##_RB_TYPE, &head->rbh_root); \ + return (struct _type *)_rb_max(_name##_RB_TYPE, \ + &head->rbh_root); \ } \ \ __attribute__((__unused__)) static inline struct _type \ diff --git a/lib/routemap.c b/lib/routemap.c index e8bdaa68fb..0c75be3323 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -616,7 +616,7 @@ struct route_map_list { void (*add_hook)(const char *); void (*delete_hook)(const char *); - void (*event_hook)(route_map_event_t, const char *); + void (*event_hook)(const char *); }; /* Master list of route map. */ @@ -902,7 +902,7 @@ static const char *route_map_type_str(enum route_map_type type) case RMAP_DENY: return "deny"; break; - default: + case RMAP_ANY: return ""; break; } @@ -1077,8 +1077,7 @@ static void route_map_index_delete(struct route_map_index *index, int notify) /* Execute event hook. */ if (route_map_master.event_hook && notify) { - (*route_map_master.event_hook)(RMAP_EVENT_INDEX_DELETED, - index->map->name); + (*route_map_master.event_hook)(index->map->name); route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED); } @@ -1137,8 +1136,7 @@ route_map_index_add(struct route_map *map, enum route_map_type type, int pref) /* Execute event hook. */ if (route_map_master.event_hook) { - (*route_map_master.event_hook)(RMAP_EVENT_INDEX_ADDED, - map->name); + (*route_map_master.event_hook)(map->name); route_map_notify_dependencies(map->name, RMAP_EVENT_CALL_ADDED); } return index; @@ -1337,10 +1335,7 @@ int route_map_add_match(struct route_map_index *index, const char *match_name, /* Execute event hook. */ if (route_map_master.event_hook) { - (*route_map_master.event_hook)( - replaced ? RMAP_EVENT_MATCH_REPLACED - : RMAP_EVENT_MATCH_ADDED, - index->map->name); + (*route_map_master.event_hook)(index->map->name); route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED); } @@ -1365,9 +1360,7 @@ int route_map_delete_match(struct route_map_index *index, route_map_rule_delete(&index->match_list, rule); /* Execute event hook. */ if (route_map_master.event_hook) { - (*route_map_master.event_hook)( - RMAP_EVENT_MATCH_DELETED, - index->map->name); + (*route_map_master.event_hook)(index->map->name); route_map_notify_dependencies( index->map->name, RMAP_EVENT_CALL_ADDED); @@ -1425,10 +1418,7 @@ int route_map_add_set(struct route_map_index *index, const char *set_name, /* Execute event hook. */ if (route_map_master.event_hook) { - (*route_map_master.event_hook)(replaced - ? RMAP_EVENT_SET_REPLACED - : RMAP_EVENT_SET_ADDED, - index->map->name); + (*route_map_master.event_hook)(index->map->name); route_map_notify_dependencies(index->map->name, RMAP_EVENT_CALL_ADDED); } @@ -1452,9 +1442,7 @@ int route_map_delete_set(struct route_map_index *index, const char *set_name, route_map_rule_delete(&index->set_list, rule); /* Execute event hook. */ if (route_map_master.event_hook) { - (*route_map_master.event_hook)( - RMAP_EVENT_SET_DELETED, - index->map->name); + (*route_map_master.event_hook)(index->map->name); route_map_notify_dependencies( index->map->name, RMAP_EVENT_CALL_ADDED); @@ -1651,7 +1639,7 @@ void route_map_delete_hook(void (*func)(const char *)) route_map_master.delete_hook = func; } -void route_map_event_hook(void (*func)(route_map_event_t, const char *)) +void route_map_event_hook(void (*func)(const char *name)) { route_map_master.event_hook = func; } @@ -1795,7 +1783,14 @@ static int route_map_dep_update(struct hash *dephash, const char *dep_name, dep = NULL; } break; - default: + case RMAP_EVENT_SET_ADDED: + case RMAP_EVENT_SET_DELETED: + case RMAP_EVENT_SET_REPLACED: + case RMAP_EVENT_MATCH_ADDED: + case RMAP_EVENT_MATCH_DELETED: + case RMAP_EVENT_MATCH_REPLACED: + case RMAP_EVENT_INDEX_ADDED: + case RMAP_EVENT_INDEX_DELETED: break; } @@ -1846,7 +1841,18 @@ static struct hash *route_map_get_dep_hash(route_map_event_t event) case RMAP_EVENT_FILTER_DELETED: upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_FILTER]; break; - default: + /* + * Should we actually be ignoring these? + * I am not sure but at this point in time, let + * us get them into this switch and we can peel + * them into the appropriate place in the future + */ + case RMAP_EVENT_SET_ADDED: + case RMAP_EVENT_SET_DELETED: + case RMAP_EVENT_SET_REPLACED: + case RMAP_EVENT_MATCH_REPLACED: + case RMAP_EVENT_INDEX_ADDED: + case RMAP_EVENT_INDEX_DELETED: upd8_hash = NULL; break; } @@ -1856,13 +1862,12 @@ static struct hash *route_map_get_dep_hash(route_map_event_t event) static void route_map_process_dependency(struct hash_bucket *bucket, void *data) { char *rmap_name = (char *)bucket->data; - route_map_event_t type = (route_map_event_t)(ptrdiff_t)data; if (rmap_debug) zlog_debug("%s: Notifying %s of dependency", __FUNCTION__, rmap_name); if (route_map_master.event_hook) - (*route_map_master.event_hook)(type, rmap_name); + (*route_map_master.event_hook)(rmap_name); } void route_map_upd8_dependency(route_map_event_t type, const char *arg, diff --git a/lib/routemap.h b/lib/routemap.h index e43e74a633..9969936a6b 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -238,7 +238,15 @@ extern route_map_result_t route_map_apply(struct route_map *map, extern void route_map_add_hook(void (*func)(const char *)); extern void route_map_delete_hook(void (*func)(const char *)); -extern void route_map_event_hook(void (*func)(route_map_event_t, const char *)); + +/* + * This is the callback for when something has changed about a + * route-map. The interested parties can register to receive + * this data. + * + * name - Is the name of the changed route-map + */ +extern void route_map_event_hook(void (*func)(const char *name)); extern int route_map_mark_updated(const char *name); extern void route_map_walk_update_list(void (*update_fn)(char *name)); extern void route_map_upd8_dependency(route_map_event_t type, const char *arg, @@ -904,10 +904,16 @@ vrf_id_t vrf_get_default_id(void) int vrf_bind(vrf_id_t vrf_id, int fd, const char *name) { int ret = 0; + struct interface *ifp; if (fd < 0 || name == NULL) return fd; - if (vrf_is_backend_netns()) + /* the device should exist + * otherwise we should return + * case ifname = vrf in netns mode => return + */ + ifp = if_lookup_by_name(name, vrf_id); + if (!ifp) return fd; #ifdef SO_BINDTODEVICE ret = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, name, strlen(name)+1); diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 2795bb9abd..946bbf8cc9 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -956,7 +956,7 @@ static void ospf6_asbr_routemap_update(const char *mapname) } } -static void ospf6_asbr_routemap_event(route_map_event_t event, const char *name) +static void ospf6_asbr_routemap_event(const char *name) { int type; diff --git a/ospf6d/ospf6_bfd.c b/ospf6d/ospf6_bfd.c index 3394bd75db..7a26af1f09 100644 --- a/ospf6d/ospf6_bfd.c +++ b/ospf6d/ospf6_bfd.c @@ -151,7 +151,7 @@ static int ospf6_bfd_nbr_replay(ZAPI_CALLBACK_ARGS) zlog_debug("Zebra: BFD Dest replay request"); /* Send the client registration */ - bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER); + bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id); /* Replay the neighbor, if BFD is enabled on the interface*/ FOR_ALL_INTERFACES (vrf, ifp) { diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index 8db4ffef18..af16c5aa7c 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -571,7 +571,7 @@ uint8_t ospf6_distance_apply(struct prefix_ipv6 *p, struct ospf6_route * or) static void ospf6_zebra_connected(struct zclient *zclient) { /* Send the client registration */ - bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER); + bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT); zclient_send_reg_requests(zclient, VRF_DEFAULT); } diff --git a/ospfd/ospf_bfd.c b/ospfd/ospf_bfd.c index 6bff5b8ddb..c8ad6d04f4 100644 --- a/ospfd/ospf_bfd.c +++ b/ospfd/ospf_bfd.c @@ -156,7 +156,7 @@ static int ospf_bfd_nbr_replay(ZAPI_CALLBACK_ARGS) } /* Send the client registration */ - bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER); + bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id); /* Replay the neighbor, if BFD is enabled in OSPF */ for (ALL_LIST_ELEMENTS(om->ospf, node, onode, ospf)) { diff --git a/ospfd/ospf_routemap.c b/ospfd/ospf_routemap.c index 30b2a50bb3..ab2d5ae584 100644 --- a/ospfd/ospf_routemap.c +++ b/ospfd/ospf_routemap.c @@ -97,7 +97,7 @@ static void ospf_route_map_update(const char *name) } } -static void ospf_route_map_event(route_map_event_t event, const char *name) +static void ospf_route_map_event(const char *name) { struct ospf *ospf; int type; diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index 16796e68fb..c178e367d3 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -1565,7 +1565,7 @@ void ospf_zebra_vrf_deregister(struct ospf *ospf) static void ospf_zebra_connected(struct zclient *zclient) { /* Send the client registration */ - bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER); + bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT); zclient_send_reg_requests(zclient, VRF_DEFAULT); } diff --git a/pimd/pim_bfd.c b/pimd/pim_bfd.c index 82087c4c56..300261e5a9 100644 --- a/pimd/pim_bfd.c +++ b/pimd/pim_bfd.c @@ -297,7 +297,7 @@ static int pim_bfd_nbr_replay(ZAPI_CALLBACK_ARGS) struct vrf *vrf = NULL; /* Send the client registration */ - bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER); + bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id); RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { FOR_ALL_INTERFACES (vrf, ifp) { diff --git a/pimd/pim_routemap.c b/pimd/pim_routemap.c index 4230c127ad..2de94e9031 100644 --- a/pimd/pim_routemap.c +++ b/pimd/pim_routemap.c @@ -36,7 +36,7 @@ static void pim_route_map_delete(const char *rmap_name) route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_DELETED); } -static void pim_route_map_event(route_map_event_t event, const char *rmap_name) +static void pim_route_map_event(const char *rmap_name) { route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED); } diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index b27d2e0581..25ac307ac4 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -780,7 +780,7 @@ void sched_rpf_cache_refresh(struct pim_instance *pim) static void pim_zebra_connected(struct zclient *zclient) { /* Send the client registration */ - bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER); + bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, router->vrf_id); zclient_send_reg_requests(zclient, router->vrf_id); } diff --git a/tests/topotests/bfd-vrf-topo1/__init__.py b/tests/topotests/bfd-vrf-topo1/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bfd-vrf-topo1/__init__.py diff --git a/tests/topotests/bfd-vrf-topo1/r1/bfdd.conf b/tests/topotests/bfd-vrf-topo1/r1/bfdd.conf new file mode 100644 index 0000000000..3466e6a3ca --- /dev/null +++ b/tests/topotests/bfd-vrf-topo1/r1/bfdd.conf @@ -0,0 +1,6 @@ +bfd + peer 192.168.0.2 vrf r1-cust1 + echo-mode + no shutdown + ! +! diff --git a/tests/topotests/bfd-vrf-topo1/r1/bgp_prefixes.json b/tests/topotests/bfd-vrf-topo1/r1/bgp_prefixes.json new file mode 100644 index 0000000000..4b2cc1ad62 --- /dev/null +++ b/tests/topotests/bfd-vrf-topo1/r1/bgp_prefixes.json @@ -0,0 +1,52 @@ +{ + "routes": { + "10.254.254.2/32": [ + { + "aspath": "102", + "prefix": "10.254.254.2", + "valid": true, + "peerId": "192.168.0.2", + "prefixLen": 32, + "nexthops": [ + { + "ip": "192.168.0.2", + "used": true, + "afi": "ipv4" + } + ] + } + ], + "10.254.254.3/32": [ + { + "aspath": "102 103", + "prefix": "10.254.254.3", + "valid": true, + "peerId": "192.168.0.2", + "prefixLen": 32, + "nexthops": [ + { + "ip": "192.168.0.2", + "used": true, + "afi": "ipv4" + } + ] + } + ], + "10.254.254.4/32": [ + { + "aspath": "102 104", + "prefix": "10.254.254.4", + "valid": true, + "peerId": "192.168.0.2", + "prefixLen": 32, + "nexthops": [ + { + "ip": "192.168.0.2", + "used": true, + "afi": "ipv4" + } + ] + } + ] + } +} diff --git a/tests/topotests/bfd-vrf-topo1/r1/bgp_summary.json b/tests/topotests/bfd-vrf-topo1/r1/bgp_summary.json new file mode 100644 index 0000000000..fa07d60df9 --- /dev/null +++ b/tests/topotests/bfd-vrf-topo1/r1/bgp_summary.json @@ -0,0 +1,11 @@ +{ + "ipv4Unicast": { + "as": 101, + "peers": { + "192.168.0.2": { + "remoteAs": 102, + "state": "Established" + } + } + } +} diff --git a/tests/topotests/bfd-vrf-topo1/r1/bgpd.conf b/tests/topotests/bfd-vrf-topo1/r1/bgpd.conf new file mode 100644 index 0000000000..7ad4e2bd74 --- /dev/null +++ b/tests/topotests/bfd-vrf-topo1/r1/bgpd.conf @@ -0,0 +1,8 @@ +router bgp 101 vrf r1-cust1 + neighbor 192.168.0.2 remote-as 102 +! neighbor 192.168.0.2 ebgp-multihop 10 + neighbor 192.168.0.2 bfd + address-family ipv4 unicast + network 10.254.254.1/32 + exit-address-family +! diff --git a/tests/topotests/bfd-vrf-topo1/r1/peers.json b/tests/topotests/bfd-vrf-topo1/r1/peers.json new file mode 100644 index 0000000000..f49768ff75 --- /dev/null +++ b/tests/topotests/bfd-vrf-topo1/r1/peers.json @@ -0,0 +1,8 @@ +[ + { + "remote-receive-interval": 1000, + "remote-transmit-interval": 500, + "peer": "192.168.0.2", + "status": "up" + } +] diff --git a/tests/topotests/bfd-vrf-topo1/r1/zebra.conf b/tests/topotests/bfd-vrf-topo1/r1/zebra.conf new file mode 100644 index 0000000000..fcd1e7db17 --- /dev/null +++ b/tests/topotests/bfd-vrf-topo1/r1/zebra.conf @@ -0,0 +1,3 @@ +interface r1-eth0 vrf r1-cust1 + ip address 192.168.0.1/24 +! diff --git a/tests/topotests/bfd-vrf-topo1/r2/bfdd.conf b/tests/topotests/bfd-vrf-topo1/r2/bfdd.conf new file mode 100644 index 0000000000..3481ea8c87 --- /dev/null +++ b/tests/topotests/bfd-vrf-topo1/r2/bfdd.conf @@ -0,0 +1,12 @@ +bfd + peer 192.168.0.1 vrf r2-cust1 + receive-interval 1000 + transmit-interval 500 + echo-mode + no shutdown + ! + peer 192.168.1.1 vrf r2-cust1 + echo-mode + no shutdown + ! +! diff --git a/tests/topotests/bfd-vrf-topo1/r2/bgp_prefixes.json b/tests/topotests/bfd-vrf-topo1/r2/bgp_prefixes.json new file mode 100644 index 0000000000..39f3c0a835 --- /dev/null +++ b/tests/topotests/bfd-vrf-topo1/r2/bgp_prefixes.json @@ -0,0 +1,52 @@ +{ + "routes": { + "10.254.254.1/32": [ + { + "aspath": "101", + "prefix": "10.254.254.1", + "valid": true, + "peerId": "192.168.0.1", + "prefixLen": 32, + "nexthops": [ + { + "ip": "192.168.0.1", + "used": true, + "afi": "ipv4" + } + ] + } + ], + "10.254.254.3/32": [ + { + "aspath": "103", + "prefix": "10.254.254.3", + "valid": true, + "peerId": "192.168.1.1", + "prefixLen": 32, + "nexthops": [ + { + "ip": "192.168.1.1", + "used": true, + "afi": "ipv4" + } + ] + } + ], + "10.254.254.4/32": [ + { + "aspath": "104", + "prefix": "10.254.254.4", + "valid": true, + "peerId": "192.168.2.1", + "prefixLen": 32, + "nexthops": [ + { + "ip": "192.168.2.1", + "used": true, + "afi": "ipv4" + } + ] + } + ] + } +} diff --git a/tests/topotests/bfd-vrf-topo1/r2/bgp_summary.json b/tests/topotests/bfd-vrf-topo1/r2/bgp_summary.json new file mode 100644 index 0000000000..c0ef11ac5f --- /dev/null +++ b/tests/topotests/bfd-vrf-topo1/r2/bgp_summary.json @@ -0,0 +1,19 @@ +{ + "ipv4Unicast": { + "as": 102, + "peers": { + "192.168.0.1": { + "remoteAs": 101, + "state": "Established" + }, + "192.168.1.1": { + "remoteAs": 103, + "state": "Established" + }, + "192.168.2.1": { + "remoteAs": 104, + "state": "Established" + } + } + } +} diff --git a/tests/topotests/bfd-vrf-topo1/r2/bgpd.conf b/tests/topotests/bfd-vrf-topo1/r2/bgpd.conf new file mode 100644 index 0000000000..0715ea32a5 --- /dev/null +++ b/tests/topotests/bfd-vrf-topo1/r2/bgpd.conf @@ -0,0 +1,11 @@ +router bgp 102 vrf r2-cust1 + neighbor 192.168.0.1 remote-as 101 + neighbor 192.168.0.1 bfd + neighbor 192.168.1.1 remote-as 103 + neighbor 192.168.1.1 bfd + neighbor 192.168.2.1 remote-as 104 + neighbor 192.168.2.1 bfd + address-family ipv4 unicast + network 10.254.254.2/32 + exit-address-family +! diff --git a/tests/topotests/bfd-vrf-topo1/r2/peers.json b/tests/topotests/bfd-vrf-topo1/r2/peers.json new file mode 100644 index 0000000000..5035d643c5 --- /dev/null +++ b/tests/topotests/bfd-vrf-topo1/r2/peers.json @@ -0,0 +1,17 @@ +[ + { + "peer": "192.168.0.1", + "status": "up" + }, + { + "remote-echo-interval": 100, + "peer": "192.168.1.1", + "status": "up" + }, + { + "remote-transmit-interval": 2000, + "remote-receive-interval": 2000, + "peer": "192.168.2.1", + "status": "up" + } +] diff --git a/tests/topotests/bfd-vrf-topo1/r2/zebra.conf b/tests/topotests/bfd-vrf-topo1/r2/zebra.conf new file mode 100644 index 0000000000..daffd1912e --- /dev/null +++ b/tests/topotests/bfd-vrf-topo1/r2/zebra.conf @@ -0,0 +1,9 @@ +interface r2-eth0 vrf r2-cust1 + ip address 192.168.0.2/24 +! +interface r2-eth1 vrf r2-cust1 + ip address 192.168.1.2/24 +! +interface r2-eth2 vrf r2-cust1 + ip address 192.168.2.2/24 +! diff --git a/tests/topotests/bfd-vrf-topo1/r3/bfdd.conf b/tests/topotests/bfd-vrf-topo1/r3/bfdd.conf new file mode 100644 index 0000000000..f6921b7818 --- /dev/null +++ b/tests/topotests/bfd-vrf-topo1/r3/bfdd.conf @@ -0,0 +1,7 @@ +bfd + peer 192.168.1.2 vrf r3-cust1 + echo-interval 100 + echo-mode + no shutdown + ! +! diff --git a/tests/topotests/bfd-vrf-topo1/r3/bgp_prefixes.json b/tests/topotests/bfd-vrf-topo1/r3/bgp_prefixes.json new file mode 100644 index 0000000000..c92d4e052a --- /dev/null +++ b/tests/topotests/bfd-vrf-topo1/r3/bgp_prefixes.json @@ -0,0 +1,52 @@ +{ + "routes": { + "10.254.254.1/32": [ + { + "aspath": "102 101", + "prefix": "10.254.254.1", + "valid": true, + "peerId": "192.168.1.2", + "prefixLen": 32, + "nexthops": [ + { + "ip": "192.168.1.2", + "used": true, + "afi": "ipv4" + } + ] + } + ], + "10.254.254.2/32": [ + { + "aspath": "102", + "prefix": "10.254.254.2", + "valid": true, + "peerId": "192.168.1.2", + "prefixLen": 32, + "nexthops": [ + { + "ip": "192.168.1.2", + "used": true, + "afi": "ipv4" + } + ] + } + ], + "10.254.254.4/32": [ + { + "aspath": "102 104", + "prefix": "10.254.254.4", + "valid": true, + "peerId": "192.168.1.2", + "prefixLen": 32, + "nexthops": [ + { + "ip": "192.168.1.2", + "used": true, + "afi": "ipv4" + } + ] + } + ] + } +} diff --git a/tests/topotests/bfd-vrf-topo1/r3/bgp_summary.json b/tests/topotests/bfd-vrf-topo1/r3/bgp_summary.json new file mode 100644 index 0000000000..d47833377b --- /dev/null +++ b/tests/topotests/bfd-vrf-topo1/r3/bgp_summary.json @@ -0,0 +1,11 @@ +{ + "ipv4Unicast": { + "as": 103, + "peers": { + "192.168.1.2": { + "remoteAs": 102, + "state": "Established" + } + } + } +} diff --git a/tests/topotests/bfd-vrf-topo1/r3/bgpd.conf b/tests/topotests/bfd-vrf-topo1/r3/bgpd.conf new file mode 100644 index 0000000000..277f027d5b --- /dev/null +++ b/tests/topotests/bfd-vrf-topo1/r3/bgpd.conf @@ -0,0 +1,7 @@ +router bgp 103 vrf r3-cust1 + neighbor 192.168.1.2 remote-as 102 + neighbor 192.168.1.2 bfd + address-family ipv4 unicast + network 10.254.254.3/32 + exit-address-family +! diff --git a/tests/topotests/bfd-vrf-topo1/r3/peers.json b/tests/topotests/bfd-vrf-topo1/r3/peers.json new file mode 100644 index 0000000000..ef38008643 --- /dev/null +++ b/tests/topotests/bfd-vrf-topo1/r3/peers.json @@ -0,0 +1,6 @@ +[ + { + "peer": "192.168.1.2", + "status": "up" + } +] diff --git a/tests/topotests/bfd-vrf-topo1/r3/zebra.conf b/tests/topotests/bfd-vrf-topo1/r3/zebra.conf new file mode 100644 index 0000000000..f727c2d633 --- /dev/null +++ b/tests/topotests/bfd-vrf-topo1/r3/zebra.conf @@ -0,0 +1,3 @@ +interface r3-eth0 vrf r3-cust1 + ip address 192.168.1.1/24 +! diff --git a/tests/topotests/bfd-vrf-topo1/r4/bfdd.conf b/tests/topotests/bfd-vrf-topo1/r4/bfdd.conf new file mode 100644 index 0000000000..a56a3a0d37 --- /dev/null +++ b/tests/topotests/bfd-vrf-topo1/r4/bfdd.conf @@ -0,0 +1,7 @@ +bfd + peer 192.168.2.2 vrf r4-cust1 + transmit-interval 2000 + receive-interval 2000 + no shutdown + ! +! diff --git a/tests/topotests/bfd-vrf-topo1/r4/bgp_prefixes.json b/tests/topotests/bfd-vrf-topo1/r4/bgp_prefixes.json new file mode 100644 index 0000000000..cc8510dd61 --- /dev/null +++ b/tests/topotests/bfd-vrf-topo1/r4/bgp_prefixes.json @@ -0,0 +1,52 @@ +{ + "routes": { + "10.254.254.1/32": [ + { + "aspath": "102 101", + "prefix": "10.254.254.1", + "valid": true, + "peerId": "192.168.2.2", + "prefixLen": 32, + "nexthops": [ + { + "ip": "192.168.2.2", + "used": true, + "afi": "ipv4" + } + ] + } + ], + "10.254.254.2/32": [ + { + "aspath": "102", + "prefix": "10.254.254.2", + "valid": true, + "peerId": "192.168.2.2", + "prefixLen": 32, + "nexthops": [ + { + "ip": "192.168.2.2", + "used": true, + "afi": "ipv4" + } + ] + } + ], + "10.254.254.3/32": [ + { + "aspath": "102 103", + "prefix": "10.254.254.3", + "valid": true, + "peerId": "192.168.2.2", + "prefixLen": 32, + "nexthops": [ + { + "ip": "192.168.2.2", + "used": true, + "afi": "ipv4" + } + ] + } + ] + } +} diff --git a/tests/topotests/bfd-vrf-topo1/r4/bgp_summary.json b/tests/topotests/bfd-vrf-topo1/r4/bgp_summary.json new file mode 100644 index 0000000000..7d81784b56 --- /dev/null +++ b/tests/topotests/bfd-vrf-topo1/r4/bgp_summary.json @@ -0,0 +1,11 @@ +{ + "ipv4Unicast": { + "as": 104, + "peers": { + "192.168.2.2": { + "remoteAs": 102, + "state": "Established" + } + } + } +} diff --git a/tests/topotests/bfd-vrf-topo1/r4/bgpd.conf b/tests/topotests/bfd-vrf-topo1/r4/bgpd.conf new file mode 100644 index 0000000000..66bf28587d --- /dev/null +++ b/tests/topotests/bfd-vrf-topo1/r4/bgpd.conf @@ -0,0 +1,7 @@ +router bgp 104 vrf r4-cust1 + neighbor 192.168.2.2 remote-as 102 + neighbor 192.168.2.2 bfd + address-family ipv4 unicast + network 10.254.254.4/32 + exit-address-family +! diff --git a/tests/topotests/bfd-vrf-topo1/r4/peers.json b/tests/topotests/bfd-vrf-topo1/r4/peers.json new file mode 100644 index 0000000000..37140089e1 --- /dev/null +++ b/tests/topotests/bfd-vrf-topo1/r4/peers.json @@ -0,0 +1,6 @@ +[ + { + "peer": "192.168.2.2", + "status": "up" + } +] diff --git a/tests/topotests/bfd-vrf-topo1/r4/zebra.conf b/tests/topotests/bfd-vrf-topo1/r4/zebra.conf new file mode 100644 index 0000000000..69770dd2bf --- /dev/null +++ b/tests/topotests/bfd-vrf-topo1/r4/zebra.conf @@ -0,0 +1,3 @@ +interface r4-eth0 vrf r4-cust1 + ip address 192.168.2.1/24 +! diff --git a/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.dot b/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.dot new file mode 100644 index 0000000000..c84ace2780 --- /dev/null +++ b/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.dot @@ -0,0 +1,73 @@ +## Color coding: +######################### +## Main FRR: #f08080 red +## Switches: #d0e0d0 gray +## RIP: #19e3d9 Cyan +## RIPng: #fcb314 dark yellow +## OSPFv2: #32b835 Green +## OSPFv3: #19e3d9 Cyan +## ISIS IPv4 #fcb314 dark yellow +## ISIS IPv6 #9a81ec purple +## BGP IPv4 #eee3d3 beige +## BGP IPv6 #fdff00 yellow +##### Colors (see http://www.color-hex.com/) + +graph template { + label="bfd-topo1"; + + # Routers + r1 [ + shape=doubleoctagon, + label="r1", + fillcolor="#f08080", + style=filled, + ]; + r2 [ + shape=doubleoctagon + label="r2", + fillcolor="#f08080", + style=filled, + ]; + r3 [ + shape=doubleoctagon + label="r3", + fillcolor="#f08080", + style=filled, + ]; + r4 [ + shape=doubleoctagon + label="r4", + fillcolor="#f08080", + style=filled, + ]; + + # Switches + sw1 [ + shape=oval, + label="sw1\n192.168.0.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + sw2 [ + shape=oval, + label="sw2\n192.168.1.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + sw3 [ + shape=oval, + label="sw3\n192.168.2.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + + # Connections + r1 -- sw1 [label="eth0\n.1"]; + r2 -- sw1 [label="eth0\n.2"]; + + r3 -- sw2 [label="eth0\n.1"]; + r2 -- sw2 [label="eth1\n.2"]; + + r4 -- sw3 [label="eth0\n.1"]; + r2 -- sw3 [label="eth2\n.2"]; +} diff --git a/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.jpg b/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.jpg Binary files differnew file mode 100644 index 0000000000..4d6d56e072 --- /dev/null +++ b/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.jpg diff --git a/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py b/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py new file mode 100755 index 0000000000..e2933820bd --- /dev/null +++ b/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py @@ -0,0 +1,292 @@ +#!/usr/bin/env python + +# +# test_bfd_vrf_topo1.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2018 by +# Network Device Education Foundation, Inc. ("NetDEF") +# Copyright (c) 2019 by 6WIND +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_bfd_vrf_topo1.py: Test the FRR/Quagga BFD daemon. +""" + +import os +import sys +import json +from functools import partial +import pytest + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, '../')) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. +from mininet.topo import Topo + +class BFDTopo(Topo): + "Test topology builder" + def build(self, *_args, **_opts): + "Build function" + tgen = get_topogen(self) + + # Create 4 routers + for routern in range(1, 5): + tgen.add_router('r{}'.format(routern)) + + switch = tgen.add_switch('s1') + switch.add_link(tgen.gears['r1']) + switch.add_link(tgen.gears['r2']) + + switch = tgen.add_switch('s2') + switch.add_link(tgen.gears['r2']) + switch.add_link(tgen.gears['r3']) + + switch = tgen.add_switch('s3') + switch.add_link(tgen.gears['r2']) + switch.add_link(tgen.gears['r4']) + + +def setup_module(mod): + "Sets up the pytest environment" + tgen = Topogen(BFDTopo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + # check for zebra capability + for rname, router in router_list.iteritems(): + if router.check_capability( + TopoRouter.RD_ZEBRA, + '--vrfwnetns' + ) == False: + return pytest.skip('Skipping BFD Topo1 VRF NETNS feature. VRF NETNS backend not available on FRR') + + if os.system('ip netns list') != 0: + return pytest.skip('Skipping BFD Topo1 VRF NETNS Test. NETNS not available on System') + + logger.info('Testing with VRF Namespace support') + + cmds = ['if [ -e /var/run/netns/{0}-cust1 ] ; then ip netns del {0}-cust1 ; fi', + 'ip netns add {0}-cust1', + 'ip link set dev {0}-eth0 netns {0}-cust1', + 'ip netns exec {0}-cust1 ifconfig {0}-eth0 up'] + cmds2 = ['ip link set dev {0}-eth1 netns {0}-cust1', + 'ip netns exec {0}-cust1 ifconfig {0}-eth1 up', + 'ip link set dev {0}-eth2 netns {0}-cust1', + 'ip netns exec {0}-cust1 ifconfig {0}-eth2 up'] + + for rname, router in router_list.iteritems(): + # create VRF rx-cust1 and link rx-eth0 to rx-cust1 + for cmd in cmds: + output = tgen.net[rname].cmd(cmd.format(rname)) + if rname == 'r2': + for cmd in cmds2: + output = tgen.net[rname].cmd(cmd.format(rname)) + + for rname, router in router_list.iteritems(): + router.load_config( + TopoRouter.RD_ZEBRA, + os.path.join(CWD, '{}/zebra.conf'.format(rname)), + '--vrfwnetns' + ) + router.load_config( + TopoRouter.RD_BFD, + os.path.join(CWD, '{}/bfdd.conf'.format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, + os.path.join(CWD, '{}/bgpd.conf'.format(rname)) + ) + + # Initialize all routers. + tgen.start_router() + + # Verify that we are using the proper version and that the BFD + # daemon exists. + for router in router_list.values(): + # Check for Version + if router.has_version('<', '5.1'): + tgen.set_error('Unsupported FRR version') + break + +def teardown_module(_mod): + "Teardown the pytest environment" + tgen = get_topogen() + # move back rx-eth0 to default VRF + # delete rx-vrf + cmds = ['ip netns exec {0}-cust1 ip link set {0}-eth0 netns 1', + 'ip netns delete {0}-cust1'] + cmds2 = ['ip netns exec {0}-cust1 ip link set {0}-eth1 netns 1', + 'ip netns exec {0}-cust2 ip link set {0}-eth1 netns 1'] + + router_list = tgen.routers() + for rname, router in router_list.iteritems(): + if rname == 'r2': + for cmd in cmds2: + tgen.net[rname].cmd(cmd.format(rname)) + for cmd in cmds: + tgen.net[rname].cmd(cmd.format(rname)) + tgen.stop_topology() + +def test_bfd_connection(): + "Assert that the BFD peers can find themselves." + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info('waiting for bfd peers to go up') + for router in tgen.routers().values(): + json_file = '{}/{}/peers.json'.format(CWD, router.name) + expected = json.loads(open(json_file).read()) + + test_func = partial(topotest.router_json_cmp, + router, 'show bfd peers json', expected) + _, result = topotest.run_and_expect(test_func, None, count=8, wait=0.5) + assertmsg = '"{}" JSON output mismatches'.format(router.name) + assert result is None, assertmsg + + +def test_bgp_convergence(): + "Assert that BGP is converging." + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info('waiting for bgp peers to go up') + + for router in tgen.routers().values(): + ref_file = '{}/{}/bgp_summary.json'.format(CWD, router.name) + expected = json.loads(open(ref_file).read()) + test_func = partial(topotest.router_json_cmp, + router, 'show ip bgp vrf {}-cust1 summary json'.format(router.name), expected) + _, res = topotest.run_and_expect(test_func, None, count=125, wait=1.0) + assertmsg = '{}: bgp did not converge'.format(router.name) + assert res is None, assertmsg + + +def test_bgp_fast_convergence(): + "Assert that BGP is converging before setting a link down." + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info('waiting for bgp peers converge') + + for router in tgen.routers().values(): + ref_file = '{}/{}/bgp_prefixes.json'.format(CWD, router.name) + expected = json.loads(open(ref_file).read()) + test_func = partial(topotest.router_json_cmp, + router, 'show ip bgp vrf {}-cust1 json'.format(router.name), expected) + _, res = topotest.run_and_expect(test_func, None, count=40, wait=0.5) + assertmsg = '{}: bgp did not converge'.format(router.name) + assert res is None, assertmsg + + +def test_bfd_fast_convergence(): + """ + Assert that BFD notices the link down after simulating network + failure. + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Disable r2-eth0 link + router2 = tgen.gears['r2'] + topotest.interface_set_status(router2, 'r2-eth0', ifaceaction=False, vrf_name='r2-cust1') + + # Wait the minimum time we can before checking that BGP/BFD + # converged. + logger.info('waiting for BFD converge') + + # Check that BGP converged quickly. + for router in tgen.routers().values(): + json_file = '{}/{}/peers.json'.format(CWD, router.name) + expected = json.loads(open(json_file).read()) + + # Load the same file as previous test, but expect R1 to be down. + if router.name == 'r1': + for peer in expected: + if peer['peer'] == '192.168.0.2': + peer['status'] = 'down' + else: + for peer in expected: + if peer['peer'] == '192.168.0.1': + peer['status'] = 'down' + + test_func = partial(topotest.router_json_cmp, + router, 'show bfd peers json', expected) + _, res = topotest.run_and_expect(test_func, None, count=20, wait=0.5) + assertmsg = '"{}" JSON output mismatches'.format(router.name) + assert res is None, assertmsg + + +def test_bgp_fast_reconvergence(): + "Assert that BGP is converging after setting a link down." + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info('waiting for BGP re convergence') + + # Check that BGP converged quickly. + for router in tgen.routers().values(): + ref_file = '{}/{}/bgp_prefixes.json'.format(CWD, router.name) + expected = json.loads(open(ref_file).read()) + + # Load the same file as previous test, but set networks to None + # to test absence. + if router.name == 'r1': + expected['routes']['10.254.254.2/32'] = None + expected['routes']['10.254.254.3/32'] = None + expected['routes']['10.254.254.4/32'] = None + else: + expected['routes']['10.254.254.1/32'] = None + + test_func = partial(topotest.router_json_cmp, + router, 'show ip bgp vrf {}-cust1 json'.format(router.name), expected) + _, res = topotest.run_and_expect( + test_func, + None, + count=3, + wait=1 + ) + assertmsg = '{}: bgp did not converge'.format(router.name) + assert res is None, assertmsg + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip('Memory leak test/report is disabled') + + tgen.report_memory_leaks() + + +if __name__ == '__main__': + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 0071e001c6..fe064f847a 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -614,7 +614,7 @@ int zebra_add_import_table_entry(struct route_node *rn, struct route_entry *re, newre->mtu = re->mtu; newre->table = 0; newre->nexthop_num = 0; - newre->uptime = time(NULL); + newre->uptime = monotime(NULL); newre->instance = re->table; route_entry_copy_nexthops(newre, re->ng.nexthop); diff --git a/zebra/rib.h b/zebra/rib.h index 8a59cea6d0..c39abaffcc 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -148,6 +148,10 @@ struct route_entry { uint32_t dplane_sequence; }; +#define RIB_SYSTEM_ROUTE(R) RSYSTEM_ROUTE((R)->type) + +#define RIB_KERNEL_ROUTE(R) RKERNEL_ROUTE((R)->type) + /* meta-queue structure: * sub-queue 0: connected, kernel * sub-queue 1: static diff --git a/zebra/rt.h b/zebra/rt.h index 08b51fcc0b..04576671fe 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -35,8 +35,10 @@ extern "C" { #endif -#define RSYSTEM_ROUTE(type) \ - ((type) == ZEBRA_ROUTE_KERNEL || (type) == ZEBRA_ROUTE_CONNECT) +#define RKERNEL_ROUTE(type) ((type) == ZEBRA_ROUTE_KERNEL) + +#define RSYSTEM_ROUTE(type) \ + ((RKERNEL_ROUTE(type)) || (type) == ZEBRA_ROUTE_CONNECT) /* * Update or delete a route, LSP, or pseudowire from the kernel, diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 289ed5a15b..def5bf7d88 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -583,7 +583,7 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, re->vrf_id = vrf_id; re->table = table; re->nexthop_num = 0; - re->uptime = time(NULL); + re->uptime = monotime(NULL); re->tag = tag; for (;;) { diff --git a/zebra/rtadv.c b/zebra/rtadv.c index 5088e2e8e1..817c65bf28 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -42,7 +42,6 @@ #include "zebra/debug.h" #include "zebra/rib.h" #include "zebra/zapi_msg.h" -#include "zebra/zebra_ns.h" #include "zebra/zebra_vrf.h" #include "zebra/zebra_errors.h" #include "zebra/zebra_router.h" @@ -81,18 +80,25 @@ enum rtadv_event { RTADV_READ }; -static void rtadv_event(struct zebra_ns *, enum rtadv_event, int); +static void rtadv_event(struct zebra_vrf *, enum rtadv_event, int); static int if_join_all_router(int, struct interface *); static int if_leave_all_router(int, struct interface *); -static int rtadv_increment_received(struct zebra_ns *zns, ifindex_t *ifindex) +static int rtadv_get_socket(struct zebra_vrf *zvrf) +{ + if (zvrf->rtadv.sock >= 0) + return zvrf->rtadv.sock; + return zrouter.rtadv_sock; +} + +static int rtadv_increment_received(struct zebra_vrf *zvrf, ifindex_t *ifindex) { int ret = -1; struct interface *iface; struct zebra_if *zif; - iface = if_lookup_by_index_per_ns(zns, *ifindex); + iface = if_lookup_by_index(*ifindex, zvrf->vrf->vrf_id); if (iface && iface->info) { zif = iface->info; zif->ra_rcvd++; @@ -101,7 +107,7 @@ static int rtadv_increment_received(struct zebra_ns *zns, ifindex_t *ifindex) return ret; } -static int rtadv_recv_packet(struct zebra_ns *zns, int sock, uint8_t *buf, +static int rtadv_recv_packet(struct zebra_vrf *zvrf, int sock, uint8_t *buf, int buflen, struct sockaddr_in6 *from, ifindex_t *ifindex, int *hoplimit) { @@ -149,7 +155,7 @@ static int rtadv_recv_packet(struct zebra_ns *zns, int sock, uint8_t *buf, } } - rtadv_increment_received(zns, ifindex); + rtadv_increment_received(zvrf, ifindex); return ret; } @@ -461,19 +467,19 @@ no_more_opts: static int rtadv_timer(struct thread *thread) { - struct zebra_ns *zns = THREAD_ARG(thread); + struct zebra_vrf *zvrf = THREAD_ARG(thread); struct vrf *vrf; struct interface *ifp; struct zebra_if *zif; int period; - zrouter.rtadv.ra_timer = NULL; - if (zrouter.rtadv.adv_msec_if_count == 0) { + zvrf->rtadv.ra_timer = NULL; + if (zvrf->rtadv.adv_msec_if_count == 0) { period = 1000; /* 1 s */ - rtadv_event(zns, RTADV_TIMER, 1 /* 1 s */); + rtadv_event(zvrf, RTADV_TIMER, 1 /* 1 s */); } else { period = 10; /* 10 ms */ - rtadv_event(zns, RTADV_TIMER_MSEC, 10 /* 10 ms */); + rtadv_event(zvrf, RTADV_TIMER_MSEC, 10 /* 10 ms */); } RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) @@ -500,7 +506,7 @@ static int rtadv_timer(struct thread *thread) "Fast RA Rexmit on interface %s", ifp->name); - rtadv_send_packet(zrouter.rtadv.sock, + rtadv_send_packet(rtadv_get_socket(zvrf), ifp); } else { zif->rtadv.AdvIntervalTimer -= period; @@ -514,8 +520,8 @@ static int rtadv_timer(struct thread *thread) zif->rtadv .MaxRtrAdvInterval; rtadv_send_packet( - zrouter.rtadv.sock, - ifp); + rtadv_get_socket(zvrf), + ifp); } } } @@ -527,10 +533,9 @@ static int rtadv_timer(struct thread *thread) static void rtadv_process_solicit(struct interface *ifp) { struct zebra_vrf *zvrf = vrf_info_lookup(ifp->vrf_id); - struct zebra_ns *zns = zvrf->zns; - assert(zns); - rtadv_send_packet(zrouter.rtadv.sock, ifp); + assert(zvrf); + rtadv_send_packet(rtadv_get_socket(zvrf), ifp); } /* @@ -652,7 +657,7 @@ static void rtadv_process_advert(uint8_t *msg, unsigned int len, static void rtadv_process_packet(uint8_t *buf, unsigned int len, ifindex_t ifindex, int hoplimit, struct sockaddr_in6 *from, - struct zebra_ns *zns) + struct zebra_vrf *zvrf) { struct icmp6_hdr *icmph; struct interface *ifp; @@ -662,7 +667,7 @@ static void rtadv_process_packet(uint8_t *buf, unsigned int len, inet_ntop(AF_INET6, &from->sin6_addr, addr_str, INET6_ADDRSTRLEN); /* Interface search. */ - ifp = if_lookup_by_index_per_ns(zns, ifindex); + ifp = if_lookup_by_index(ifindex, zvrf->vrf->vrf_id); if (ifp == NULL) { flog_warn(EC_ZEBRA_UNKNOWN_INTERFACE, "RA/RS received on unknown IF %u from %s", ifindex, @@ -724,15 +729,15 @@ static int rtadv_read(struct thread *thread) struct sockaddr_in6 from; ifindex_t ifindex = 0; int hoplimit = -1; - struct zebra_ns *zns = THREAD_ARG(thread); + struct zebra_vrf *zvrf = THREAD_ARG(thread); sock = THREAD_FD(thread); - zrouter.rtadv.ra_read = NULL; + zvrf->rtadv.ra_read = NULL; /* Register myself. */ - rtadv_event(zns, RTADV_READ, sock); + rtadv_event(zvrf, RTADV_READ, sock); - len = rtadv_recv_packet(zns, sock, buf, sizeof(buf), &from, &ifindex, + len = rtadv_recv_packet(zvrf, sock, buf, sizeof(buf), &from, &ifindex, &hoplimit); if (len < 0) { @@ -742,7 +747,7 @@ static int rtadv_read(struct thread *thread) return len; } - rtadv_process_packet(buf, (unsigned)len, ifindex, hoplimit, &from, zns); + rtadv_process_packet(buf, (unsigned)len, ifindex, hoplimit, &from, zvrf); return 0; } @@ -875,29 +880,27 @@ static void ipv6_nd_suppress_ra_set(struct interface *ifp, { struct zebra_if *zif; struct zebra_vrf *zvrf; - struct zebra_ns *zns; zif = ifp->info; zvrf = vrf_info_lookup(ifp->vrf_id); - zns = zvrf->zns; if (status == RA_SUPPRESS) { /* RA is currently enabled */ if (zif->rtadv.AdvSendAdvertisements) { zif->rtadv.AdvSendAdvertisements = 0; zif->rtadv.AdvIntervalTimer = 0; - zrouter.rtadv.adv_if_count--; + zvrf->rtadv.adv_if_count--; - if_leave_all_router(zrouter.rtadv.sock, ifp); + if_leave_all_router(rtadv_get_socket(zvrf), ifp); - if (zrouter.rtadv.adv_if_count == 0) - rtadv_event(zns, RTADV_STOP, 0); + if (zvrf->rtadv.adv_if_count == 0) + rtadv_event(zvrf, RTADV_STOP, 0); } } else { if (!zif->rtadv.AdvSendAdvertisements) { zif->rtadv.AdvSendAdvertisements = 1; zif->rtadv.AdvIntervalTimer = 0; - zrouter.rtadv.adv_if_count++; + zvrf->rtadv.adv_if_count++; if (zif->rtadv.MaxRtrAdvInterval >= 1000) { /* Enable Fast RA only when RA interval is in @@ -907,11 +910,11 @@ static void ipv6_nd_suppress_ra_set(struct interface *ifp, RTADV_NUM_FAST_REXMITS; } - if_join_all_router(zrouter.rtadv.sock, ifp); + if_join_all_router(rtadv_get_socket(zvrf), ifp); - if (zrouter.rtadv.adv_if_count == 1) - rtadv_event(zns, RTADV_START, - zrouter.rtadv.sock); + if (zvrf->rtadv.adv_if_count == 1) + rtadv_event(zvrf, RTADV_START, + rtadv_get_socket(zvrf)); } } } @@ -944,7 +947,7 @@ static void zebra_interface_radv_set(ZAPI_HANDLER_ARGS, int enable) zebra_route_string(client->proto), ra_interval); /* Locate interface and check VRF match. */ - ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT), ifindex); + ifp = if_lookup_by_index(ifindex, zvrf->vrf->vrf_id); if (!ifp) { flog_warn(EC_ZEBRA_UNKNOWN_INTERFACE, "%u: IF %u RA %s client %s - interface unknown", @@ -1051,6 +1054,9 @@ DEFUN (ipv6_nd_ra_interval_msec, VTY_DECLVAR_CONTEXT(interface, ifp); unsigned interval; struct zebra_if *zif = ifp->info; + struct zebra_vrf *zvrf; + + zvrf = vrf_info_lookup(ifp->vrf_id); interval = strtoul(argv[idx_number]->arg, NULL, 10); if ((zif->rtadv.AdvDefaultLifetime != -1 @@ -1061,10 +1067,10 @@ DEFUN (ipv6_nd_ra_interval_msec, } if (zif->rtadv.MaxRtrAdvInterval % 1000) - zrouter.rtadv.adv_msec_if_count--; + zvrf->rtadv.adv_msec_if_count--; if (interval % 1000) - zrouter.rtadv.adv_msec_if_count++; + zvrf->rtadv.adv_msec_if_count++; SET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED); zif->rtadv.MaxRtrAdvInterval = interval; @@ -1086,6 +1092,9 @@ DEFUN (ipv6_nd_ra_interval, VTY_DECLVAR_CONTEXT(interface, ifp); unsigned interval; struct zebra_if *zif = ifp->info; + struct zebra_vrf *zvrf; + + zvrf = vrf_info_lookup(ifp->vrf_id); interval = strtoul(argv[idx_number]->arg, NULL, 10); if ((zif->rtadv.AdvDefaultLifetime != -1 @@ -1096,7 +1105,7 @@ DEFUN (ipv6_nd_ra_interval, } if (zif->rtadv.MaxRtrAdvInterval % 1000) - zrouter.rtadv.adv_msec_if_count--; + zvrf->rtadv.adv_msec_if_count--; /* convert to milliseconds */ interval = interval * 1000; @@ -1122,9 +1131,12 @@ DEFUN (no_ipv6_nd_ra_interval, { VTY_DECLVAR_CONTEXT(interface, ifp); struct zebra_if *zif = ifp->info; + struct zebra_vrf *zvrf = NULL; + + zvrf = vrf_info_lookup(ifp->vrf_id); if (zif->rtadv.MaxRtrAdvInterval % 1000) - zrouter.rtadv.adv_msec_if_count--; + zvrf->rtadv.adv_msec_if_count--; UNSET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED); @@ -2094,15 +2106,15 @@ static int rtadv_config_write(struct vty *vty, struct interface *ifp) } -static void rtadv_event(struct zebra_ns *zns, enum rtadv_event event, int val) +static void rtadv_event(struct zebra_vrf *zvrf, enum rtadv_event event, int val) { - struct rtadv *rtadv = &zrouter.rtadv; + struct rtadv *rtadv = &zvrf->rtadv; switch (event) { case RTADV_START: - thread_add_read(zrouter.master, rtadv_read, zns, val, + thread_add_read(zrouter.master, rtadv_read, zvrf, val, &rtadv->ra_read); - thread_add_event(zrouter.master, rtadv_timer, zns, 0, + thread_add_event(zrouter.master, rtadv_timer, zvrf, 0, &rtadv->ra_timer); break; case RTADV_STOP: @@ -2116,15 +2128,15 @@ static void rtadv_event(struct zebra_ns *zns, enum rtadv_event event, int val) } break; case RTADV_TIMER: - thread_add_timer(zrouter.master, rtadv_timer, zns, val, + thread_add_timer(zrouter.master, rtadv_timer, zvrf, val, &rtadv->ra_timer); break; case RTADV_TIMER_MSEC: - thread_add_timer_msec(zrouter.master, rtadv_timer, zns, val, + thread_add_timer_msec(zrouter.master, rtadv_timer, zvrf, val, &rtadv->ra_timer); break; case RTADV_READ: - thread_add_read(zrouter.master, rtadv_read, zns, val, + thread_add_read(zrouter.master, rtadv_read, zvrf, val, &rtadv->ra_read); break; default: @@ -2133,21 +2145,29 @@ static void rtadv_event(struct zebra_ns *zns, enum rtadv_event event, int val) return; } -void rtadv_init(struct zebra_ns *zns) +void rtadv_init(struct zebra_vrf *zvrf) { - zrouter.rtadv.sock = rtadv_make_socket(zns->ns_id); + if (vrf_is_backend_netns()) { + zvrf->rtadv.sock = rtadv_make_socket(zvrf->zns->ns_id); + zrouter.rtadv_sock = -1; + } else if (!zrouter.rtadv_sock) { + zvrf->rtadv.sock = -1; + zrouter.rtadv_sock = rtadv_make_socket(zvrf->zns->ns_id); + } } -void rtadv_terminate(struct zebra_ns *zns) +void rtadv_terminate(struct zebra_vrf *zvrf) { - rtadv_event(zns, RTADV_STOP, 0); - if (zrouter.rtadv.sock >= 0) { - close(zrouter.rtadv.sock); - zrouter.rtadv.sock = -1; + rtadv_event(zvrf, RTADV_STOP, 0); + if (zvrf->rtadv.sock >= 0) { + close(zvrf->rtadv.sock); + zvrf->rtadv.sock = -1; + } else if (zrouter.rtadv_sock >= 0) { + close(zrouter.rtadv_sock); + zrouter.rtadv_sock = -1; } - - zrouter.rtadv.adv_if_count = 0; - zrouter.rtadv.adv_msec_if_count = 0; + zvrf->rtadv.adv_if_count = 0; + zvrf->rtadv.adv_msec_if_count = 0; } void rtadv_cmd_init(void) @@ -2243,11 +2263,11 @@ static int if_leave_all_router(int sock, struct interface *ifp) } #else -void rtadv_init(struct zebra_ns *zns) +void rtadv_init(struct zebra_vrf *zvrf) { /* Empty.*/; } -void rtadv_terminate(struct zebra_ns *zns) +void rtadv_terminate(struct zebra_vrf *zvrf) { /* Empty.*/; } diff --git a/zebra/rtadv.h b/zebra/rtadv.h index 53c497fc09..8ad3de7f17 100644 --- a/zebra/rtadv.h +++ b/zebra/rtadv.h @@ -135,8 +135,8 @@ typedef enum { RA_SUPPRESS, } ipv6_nd_suppress_ra_status; -extern void rtadv_init(struct zebra_ns *); -extern void rtadv_terminate(struct zebra_ns *); +extern void rtadv_init(struct zebra_vrf *); +extern void rtadv_terminate(struct zebra_vrf *); extern void rtadv_cmd_init(void); extern void zebra_interface_radv_disable(ZAPI_HANDLER_ARGS); extern void zebra_interface_radv_enable(ZAPI_HANDLER_ARGS); diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 7f6af82018..974cc9de30 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -1388,7 +1388,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) re->type = api.type; re->instance = api.instance; re->flags = api.flags; - re->uptime = time(NULL); + re->uptime = monotime(NULL); re->vrf_id = vrf_id; if (api.tableid && vrf_id == VRF_DEFAULT) re->table = api.tableid; diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index ae52762c5a..6fc62147c8 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -1574,8 +1574,7 @@ done: else { atomic_fetch_add_explicit(&zdplane_info.dg_lsp_errors, 1, memory_order_relaxed); - if (ctx) - dplane_ctx_free(&ctx); + dplane_ctx_free(&ctx); } return result; @@ -1609,8 +1608,7 @@ done: else { atomic_fetch_add_explicit(&zdplane_info.dg_pw_errors, 1, memory_order_relaxed); - if (ctx) - dplane_ctx_free(&ctx); + dplane_ctx_free(&ctx); } return result; @@ -1737,8 +1735,7 @@ static enum zebra_dplane_result intf_addr_update_internal( /* Error counter */ atomic_fetch_add_explicit(&zdplane_info.dg_intf_addr_errors, 1, memory_order_relaxed); - if (ctx) - dplane_ctx_free(&ctx); + dplane_ctx_free(&ctx); } return result; diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c index bdc1dcdff3..16459b606a 100644 --- a/zebra/zebra_fpm_netlink.c +++ b/zebra/zebra_fpm_netlink.c @@ -270,7 +270,6 @@ static int netlink_route_info_fill(netlink_route_info_t *ri, int cmd, ri->rtm_type = RTN_BLACKHOLE; break; } - return 1; } if ((cmd == RTM_NEWROUTE diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c index 0c743d8678..db4f9d0015 100644 --- a/zebra/zebra_ns.c +++ b/zebra/zebra_ns.c @@ -27,7 +27,6 @@ #include "lib/prefix.h" #include "lib/memory.h" -#include "rtadv.h" #include "zebra_ns.h" #include "zebra_vrf.h" #include "zebra_memory.h" @@ -122,10 +121,6 @@ int zebra_ns_enable(ns_id_t ns_id, void **info) zns->ns_id = ns_id; -#if defined(HAVE_RTADV) - rtadv_init(zns); -#endif - kernel_init(zns); interface_list(zns); route_read(zns); @@ -142,9 +137,6 @@ int zebra_ns_enable(ns_id_t ns_id, void **info) static int zebra_ns_disable_internal(struct zebra_ns *zns, bool complete) { route_table_finish(zns->if_table); -#if defined(HAVE_RTADV) - rtadv_terminate(zns); -#endif kernel_terminate(zns, complete); diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c index bb352dc2ff..d3ecd3695a 100644 --- a/zebra/zebra_ptm.c +++ b/zebra/zebra_ptm.c @@ -1188,8 +1188,8 @@ static void pp_free_all(void); static void zebra_ptm_send_bfdd(struct stream *msg); static void zebra_ptm_send_clients(struct stream *msg); static int _zebra_ptm_bfd_client_deregister(struct zserv *zs); -static void _zebra_ptm_reroute(struct zserv *zs, struct stream *msg, - uint32_t command); +static void _zebra_ptm_reroute(struct zserv *zs, struct zebra_vrf *zvrf, + struct stream *msg, uint32_t command); /* @@ -1392,8 +1392,8 @@ void zebra_ptm_finish(void) /* * Message handling. */ -static void _zebra_ptm_reroute(struct zserv *zs, struct stream *msg, - uint32_t command) +static void _zebra_ptm_reroute(struct zserv *zs, struct zebra_vrf *zvrf, + struct stream *msg, uint32_t command) { struct stream *msgc; size_t zmsglen, zhdrlen; @@ -1420,7 +1420,7 @@ static void _zebra_ptm_reroute(struct zserv *zs, struct stream *msg, * one callback at the `bfdd` side, however the real command * number will be included right after the zebra header. */ - zclient_create_header(msgc, ZEBRA_BFD_DEST_REPLAY, 0); + zclient_create_header(msgc, ZEBRA_BFD_DEST_REPLAY, zvrf->vrf->vrf_id); stream_putl(msgc, command); /* Update the data pointers. */ @@ -1446,7 +1446,7 @@ void zebra_ptm_bfd_dst_register(ZAPI_HANDLER_ARGS) zlog_debug("bfd_dst_register msg from client %s: length=%d", zebra_route_string(client->proto), hdr->length); - _zebra_ptm_reroute(client, msg, ZEBRA_BFD_DEST_REGISTER); + _zebra_ptm_reroute(client, zvrf, msg, ZEBRA_BFD_DEST_REGISTER); } void zebra_ptm_bfd_dst_deregister(ZAPI_HANDLER_ARGS) @@ -1455,7 +1455,7 @@ void zebra_ptm_bfd_dst_deregister(ZAPI_HANDLER_ARGS) zlog_debug("bfd_dst_deregister msg from client %s: length=%d", zebra_route_string(client->proto), hdr->length); - _zebra_ptm_reroute(client, msg, ZEBRA_BFD_DEST_DEREGISTER); + _zebra_ptm_reroute(client, zvrf, msg, ZEBRA_BFD_DEST_DEREGISTER); } void zebra_ptm_bfd_client_register(ZAPI_HANDLER_ARGS) @@ -1464,7 +1464,7 @@ void zebra_ptm_bfd_client_register(ZAPI_HANDLER_ARGS) zlog_debug("bfd_client_register msg from client %s: length=%d", zebra_route_string(client->proto), hdr->length); - _zebra_ptm_reroute(client, msg, ZEBRA_BFD_CLIENT_REGISTER); + _zebra_ptm_reroute(client, zvrf, msg, ZEBRA_BFD_CLIENT_REGISTER); } void zebra_ptm_bfd_dst_replay(ZAPI_HANDLER_ARGS) @@ -1488,7 +1488,7 @@ void zebra_ptm_bfd_dst_replay(ZAPI_HANDLER_ARGS) * special treatment. */ if (client->proto != ZEBRA_ROUTE_BFD) { - _zebra_ptm_reroute(client, msg, ZEBRA_BFD_DEST_REPLAY); + _zebra_ptm_reroute(client, zvrf, msg, ZEBRA_BFD_DEST_REPLAY); return; } diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 3623852afd..eddf6c8158 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -797,12 +797,6 @@ struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, vrf_id_t vrf_id) return NULL; } -#define RIB_SYSTEM_ROUTE(R) \ - ((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT) - -#define RIB_KERNEL_ROUTE(R) \ - ((R)->type == ZEBRA_ROUTE_KERNEL) - /* This function verifies reachability of one given nexthop, which can be * numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored * in nexthop->flags field. The nexthop->ifindex will be updated @@ -3003,7 +2997,7 @@ int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, re->table = table_id; re->vrf_id = vrf_id; re->nexthop_num = 0; - re->uptime = time(NULL); + re->uptime = monotime(NULL); re->tag = tag; /* Add nexthop. */ diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index 5d1cbbe781..5355fa062e 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -1798,8 +1798,7 @@ static void zebra_route_map_delete(const char *rmap_name) route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_DELETED); } -static void zebra_route_map_event(route_map_event_t event, - const char *rmap_name) +static void zebra_route_map_event(const char *rmap_name) { if (route_map_mark_updated(rmap_name) == 0) zebra_route_map_mark_update(rmap_name); diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h index b316b91d0d..c1f07397d0 100644 --- a/zebra/zebra_router.h +++ b/zebra/zebra_router.h @@ -82,9 +82,8 @@ struct zebra_router { struct hash *iptable_hash; -#if defined(HAVE_RTADV) - struct rtadv rtadv; -#endif /* HAVE_RTADV */ + /* used if vrf backend is not network namespace */ + int rtadv_sock; /* A sequence number used for tracking routes */ _Atomic uint32_t sequence_num; diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index 5a18534ac4..1f2ff63286 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -29,6 +29,7 @@ #include "vty.h" #include "zebra/zebra_router.h" +#include "zebra/rtadv.h" #include "zebra/debug.h" #include "zebra/zapi_msg.h" #include "zebra/rib.h" @@ -114,6 +115,10 @@ static int zebra_vrf_enable(struct vrf *vrf) zvrf->zns = zebra_ns_lookup((ns_id_t)vrf->vrf_id); else zvrf->zns = zebra_ns_lookup(NS_DEFAULT); +#if defined(HAVE_RTADV) + rtadv_init(zvrf); +#endif + /* Inform clients that the VRF is now active. This is an * add for the clients. */ @@ -156,6 +161,10 @@ static int zebra_vrf_disable(struct vrf *vrf) /* Stop any VxLAN-EVPN processing. */ zebra_vxlan_vrf_disable(zvrf); +#if defined(HAVE_RTADV) + rtadv_terminate(zvrf); +#endif + /* Inform clients that the VRF is now inactive. This is a * delete for the clients. */ diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h index c7a64d300a..2dd47b5561 100644 --- a/zebra/zebra_vrf.h +++ b/zebra/zebra_vrf.h @@ -155,6 +155,10 @@ struct zebra_vrf { uint64_t lsp_removals_queued; uint64_t lsp_installs; uint64_t lsp_removals; + +#if defined(HAVE_RTADV) + struct rtadv rtadv; +#endif /* HAVE_RTADV */ }; #define PROTO_RM_NAME(zvrf, afi, rtype) zvrf->proto_rm[afi][rtype].name #define NHT_RM_NAME(zvrf, afi, rtype) zvrf->nht_rm[afi][rtype].name diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 77795c6152..c4249b6366 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -230,7 +230,7 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, time_t uptime; struct tm *tm; - uptime = time(NULL); + uptime = monotime(NULL); uptime -= re->uptime; tm = gmtime(&uptime); @@ -385,7 +385,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, struct tm *tm; rib_dest_t *dest = rib_dest_from_rnode(rn); - uptime = time(NULL); + uptime = monotime(NULL); uptime -= re->uptime; tm = gmtime(&uptime); diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index baa050c9b9..605e9eae66 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -7505,9 +7505,9 @@ int zebra_vxlan_check_del_local_mac(struct interface *ifp, if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "Add/update remote MAC %s intf %s(%u) VNI %u - del local", + "Add/update remote MAC %s intf %s(%u) VNI %u flags 0x%x - del local", prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name, - ifp->ifindex, vni); + ifp->ifindex, vni, mac->flags); /* Remove MAC from BGP. */ zvni_mac_send_del_to_client(zvni->vni, macaddr); @@ -7520,6 +7520,7 @@ int zebra_vxlan_check_del_local_mac(struct interface *ifp, zvni_mac_del(zvni, mac); } else { UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); + UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY); SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); } @@ -7603,11 +7604,6 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if, return -1; } - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("DEL MAC %s intf %s(%u) VID %u -> VNI %u", - prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name, - ifp->ifindex, vid, zvni->vni); - /* If entry doesn't exist, nothing to do. */ mac = zvni_mac_lookup(zvni, macaddr); if (!mac) @@ -7617,6 +7613,11 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if, if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) return 0; + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("DEL MAC %s intf %s(%u) VID %u -> VNI %u flags 0x%x", + prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name, + ifp->ifindex, vid, zvni->vni, mac->flags); + /* Update all the neigh entries associated with this mac */ zvni_process_neigh_on_local_mac_del(zvni, mac); @@ -7631,6 +7632,7 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if, zvni_mac_del(zvni, mac); } else { UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); + UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY); SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); } |
