diff options
557 files changed, 13461 insertions, 5919 deletions
diff --git a/.gitignore b/.gitignore index 05fcd6ce4b..bf6df9ad60 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ /aclocal.m4 /libtool /libtool.orig +/changelog-auto /Makefile /Makefile.in diff --git a/Makefile.am b/Makefile.am index 9e6c53d87c..2618029a4b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -124,7 +124,6 @@ include watchfrr/subdir.am include qpb/subdir.am include fpm/subdir.am include tools/subdir.am -include debianpkg/subdir.am include solaris/subdir.am include bgpd/subdir.am @@ -170,17 +169,15 @@ EXTRA_DIST += \ m4/README.txt \ m4/libtool-whole-archive.patch \ config.version \ + changelog-auto \ + changelog-auto.in \ \ python/clidef.py \ python/clippy/__init__.py \ \ - redhat/frr.init \ - redhat/frr.service \ - redhat/daemons \ redhat/frr.logrotate \ redhat/frr.pam \ redhat/frr.spec \ - redhat/README.rpm_build.md \ \ snapcraft/snapcraft.yaml \ snapcraft/README.snap_build.md \ @@ -18,6 +18,8 @@ FRR currently supports the following protocols: * LDP * BFD * Babel +* PBR +* OpenFabric * EIGRP (alpha) * NHRP (alpha) diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index 79242f5b85..0ff89abc49 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -1414,12 +1414,7 @@ static babel_interface_nfo * babel_interface_allocate (void) { babel_interface_nfo *babel_ifp; - babel_ifp = XMALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo)); - if(babel_ifp == NULL) - return NULL; - - /* Here are set the default values for an interface. */ - memset(babel_ifp, 0, sizeof(babel_interface_nfo)); + babel_ifp = XCALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo)); /* All flags are unset */ babel_ifp->bucket_time = babel_now.tv_sec; babel_ifp->bucket = BUCKET_TOKENS_MAX; diff --git a/bfdd/Makefile b/bfdd/Makefile new file mode 100644 index 0000000000..dfe78232c4 --- /dev/null +++ b/bfdd/Makefile @@ -0,0 +1,10 @@ +all: ALWAYS + @$(MAKE) -s -C .. bfdd/bfdd +%: ALWAYS + @$(MAKE) -s -C .. bfdd/$@ + +Makefile: + #nothing +ALWAYS: +.PHONY: ALWAYS makefiles +.SUFFIXES: diff --git a/bfdd/bfd.c b/bfdd/bfd.c index df263a91c9..3575ba7a00 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -36,25 +36,65 @@ DEFINE_QOBJ_TYPE(bfd_session); /* * Prototypes */ +void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer, + struct sockaddr_any *local, bool mhop, const char *ifname, + const char *vrfname); + static uint32_t ptm_bfd_gen_ID(void); static void ptm_bfd_echo_xmt_TO(struct bfd_session *bfd); static void bfd_session_free(struct bfd_session *bs); -static struct bfd_session *bfd_session_new(int sd); +static struct bfd_session *bfd_session_new(void); static struct bfd_session *bfd_find_disc(struct sockaddr_any *sa, uint32_t ldisc); static int bfd_session_update(struct bfd_session *bs, struct bfd_peer_cfg *bpc); static const char *get_diag_str(int diag); +static void bs_admin_down_handler(struct bfd_session *bs, int nstate); +static void bs_down_handler(struct bfd_session *bs, int nstate); +static void bs_init_handler(struct bfd_session *bs, int nstate); +static void bs_up_handler(struct bfd_session *bs, int nstate); + +/* Zeroed array with the size of an IPv6 address. */ +struct in6_addr zero_addr; /* * Functions */ +void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer, + struct sockaddr_any *local, bool mhop, const char *ifname, + const char *vrfname) +{ + memset(key, 0, sizeof(*key)); + + switch (peer->sa_sin.sin_family) { + case AF_INET: + key->family = AF_INET; + memcpy(&key->peer, &peer->sa_sin.sin_addr, + sizeof(peer->sa_sin.sin_addr)); + memcpy(&key->local, &local->sa_sin.sin_addr, + sizeof(local->sa_sin.sin_addr)); + break; + case AF_INET6: + key->family = AF_INET6; + memcpy(&key->peer, &peer->sa_sin6.sin6_addr, + sizeof(peer->sa_sin6.sin6_addr)); + memcpy(&key->local, &local->sa_sin6.sin6_addr, + sizeof(local->sa_sin6.sin6_addr)); + break; + } + + key->mhop = mhop; + if (ifname && ifname[0]) + strlcpy(key->ifname, ifname, sizeof(key->ifname)); + if (vrfname && vrfname[0]) + strlcpy(key->vrfname, vrfname, sizeof(key->vrfname)); +} + struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc) { struct bfd_session *bs; struct peer_label *pl; - struct bfd_mhop_key mhop; - struct bfd_shop_key shop; + struct bfd_key key; /* Try to find label first. */ if (bpc->bpc_has_label) { @@ -66,33 +106,130 @@ struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc) } /* Otherwise fallback to peer/local hash lookup. */ - if (bpc->bpc_mhop) { - memset(&mhop, 0, sizeof(mhop)); - mhop.peer = bpc->bpc_peer; - mhop.local = bpc->bpc_local; - if (bpc->bpc_has_vrfname) - strlcpy(mhop.vrf_name, bpc->bpc_vrfname, - sizeof(mhop.vrf_name)); - - bs = bfd_mhop_lookup(mhop); + gen_bfd_key(&key, &bpc->bpc_peer, &bpc->bpc_local, bpc->bpc_mhop, + bpc->bpc_localif, bpc->bpc_vrfname); + + return bfd_key_lookup(key); +} + +/* + * Starts a disabled BFD session. + * + * A session is disabled when the specified interface/VRF doesn't exist + * yet. It might happen on FRR boot or with virtual interfaces. + */ +int bfd_session_enable(struct bfd_session *bs) +{ + struct interface *ifp = NULL; + struct vrf *vrf = NULL; + int psock; + + /* + * 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 (vrf == NULL) { + log_error( + "session-enable: specified VRF doesn't exists."); + return 0; + } + } + + 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."); + return 0; + } + } + + /* Assign interface/VRF pointers. */ + bs->vrf = vrf; + if (bs->vrf == NULL) + bs->vrf = vrf_lookup_by_id(VRF_DEFAULT); + + if (bs->key.ifname[0] + && BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0) + bs->ifp = ifp; + + /* Sanity check: don't leak open sockets. */ + if (bs->sock != -1) { + zlog_debug("session-enable: previous socket open"); + close(bs->sock); + bs->sock = -1; + } + + /* + * Get socket for transmitting control packets. Note that if we + * could use the destination port (3784) for the source + * port we wouldn't need a socket per session. + */ + if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6) == 0) { + psock = bp_peer_socket(bs); + if (psock == -1) + return 0; } else { - memset(&shop, 0, sizeof(shop)); - shop.peer = bpc->bpc_peer; - if (bpc->bpc_has_localif) - strlcpy(shop.port_name, bpc->bpc_localif, - sizeof(shop.port_name)); + psock = bp_peer_socketv6(bs); + if (psock == -1) + return 0; + } + + /* + * We've got a valid socket, lets start the timers and the + * protocol. + */ + bs->sock = psock; + bfd_recvtimer_update(bs); + ptm_bfd_start_xmt_timer(bs, false); + + return 0; +} - bs = bfd_shop_lookup(shop); +/* + * Disabled a running BFD session. + * + * A session is disabled when the specified interface/VRF gets removed + * (e.g. virtual interfaces). + */ +void bfd_session_disable(struct bfd_session *bs) +{ + /* Free up socket resources. */ + if (bs->sock != -1) { + close(bs->sock); + bs->sock = -1; } - return bs; + /* Disable all timers. */ + bfd_recvtimer_delete(bs); + bfd_echo_recvtimer_delete(bs); + bfd_xmttimer_delete(bs); + bfd_echo_xmttimer_delete(bs); } static uint32_t ptm_bfd_gen_ID(void) { - static uint32_t sessionID = 1; + uint32_t session_id; - return (sessionID++); + /* + * RFC 5880, Section 6.8.1. recommends that we should generate + * random session identification numbers. + */ + do { + session_id = ((random() << 16) & 0xFFFF0000) + | (random() & 0x0000FFFF); + } while (session_id == 0 || bfd_id_lookup(session_id) != NULL); + + return session_id; } void ptm_bfd_start_xmt_timer(struct bfd_session *bfd, bool is_echo) @@ -137,7 +274,7 @@ void ptm_bfd_xmt_TO(struct bfd_session *bfd, int fbit) ptm_bfd_start_xmt_timer(bfd, false); } -void ptm_bfd_echo_stop(struct bfd_session *bfd, int polling) +void ptm_bfd_echo_stop(struct bfd_session *bfd) { bfd->echo_xmt_TO = 0; bfd->echo_detect_TO = 0; @@ -145,13 +282,6 @@ void ptm_bfd_echo_stop(struct bfd_session *bfd, int polling) bfd_echo_xmttimer_delete(bfd); bfd_echo_recvtimer_delete(bfd); - - if (polling) { - bfd->polling = polling; - bfd->new_timers.desired_min_tx = bfd->up_min_tx; - bfd->new_timers.required_min_rx = bfd->timers.required_min_rx; - ptm_bfd_snd(bfd, 0); - } } void ptm_bfd_echo_start(struct bfd_session *bfd) @@ -159,11 +289,6 @@ void ptm_bfd_echo_start(struct bfd_session *bfd) bfd->echo_detect_TO = (bfd->remote_detect_mult * bfd->echo_xmt_TO); if (bfd->echo_detect_TO > 0) ptm_bfd_echo_xmt_TO(bfd); - - bfd->polling = 1; - bfd->new_timers.desired_min_tx = bfd->up_min_tx; - bfd->new_timers.required_min_rx = bfd->timers.required_min_rx; - ptm_bfd_snd(bfd, 0); } void ptm_bfd_ses_up(struct bfd_session *bfd) @@ -172,17 +297,13 @@ void ptm_bfd_ses_up(struct bfd_session *bfd) bfd->local_diag = 0; bfd->ses_state = PTM_BFD_UP; - bfd->polling = 1; monotime(&bfd->uptime); - /* If the peer is capable to receiving Echo pkts */ - if (bfd->echo_xmt_TO && !BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_MH)) { - ptm_bfd_echo_start(bfd); - } else { - bfd->new_timers.desired_min_tx = bfd->up_min_tx; - bfd->new_timers.required_min_rx = bfd->timers.required_min_rx; - ptm_bfd_snd(bfd, 0); - } + /* Connection is up, lets negotiate timers. */ + bfd_set_polling(bfd); + + /* Start sending control packets with poll bit immediately. */ + ptm_bfd_snd(bfd, 0); control_notify(bfd); @@ -207,13 +328,16 @@ void ptm_bfd_ses_dn(struct bfd_session *bfd, uint8_t diag) ptm_bfd_snd(bfd, 0); + /* Slow down the control packets, the connection is down. */ + bs_set_slow_timers(bfd); + /* only signal clients when going from up->down state */ if (old_state == PTM_BFD_UP) control_notify(bfd); /* Stop echo packet transmission if they are active */ if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE)) - ptm_bfd_echo_stop(bfd, 0); + ptm_bfd_echo_stop(bfd); if (old_state != bfd->ses_state) { bfd->stats.session_down++; @@ -224,25 +348,6 @@ void ptm_bfd_ses_dn(struct bfd_session *bfd, uint8_t diag) } } -static int ptm_bfd_get_vrf_name(char *port_name, char *vrf_name) -{ - struct bfd_iface *iface; - struct bfd_vrf *vrf; - - if ((port_name == NULL) || (vrf_name == NULL)) - return -1; - - iface = bfd_iface_lookup(port_name); - if (iface) { - vrf = bfd_vrf_lookup(iface->vrf_id); - if (vrf) { - strlcpy(vrf_name, vrf->name, sizeof(vrf->name)); - return 0; - } - } - return -1; -} - static struct bfd_session *bfd_find_disc(struct sockaddr_any *sa, uint32_t ldisc) { @@ -252,64 +357,52 @@ static struct bfd_session *bfd_find_disc(struct sockaddr_any *sa, if (bs == NULL) return NULL; - /* Remove unused fields. */ - switch (sa->sa_sin.sin_family) { + switch (bs->key.family) { case AF_INET: - sa->sa_sin.sin_port = 0; - if (memcmp(sa, &bs->shop.peer, sizeof(sa->sa_sin)) == 0) - return bs; + if (memcmp(&sa->sa_sin.sin_addr, &bs->key.peer, + sizeof(sa->sa_sin.sin_addr))) + return NULL; break; case AF_INET6: - sa->sa_sin6.sin6_port = 0; - if (memcmp(sa, &bs->shop.peer, sizeof(sa->sa_sin6)) == 0) - return bs; + if (memcmp(&sa->sa_sin6.sin6_addr, &bs->key.peer, + sizeof(sa->sa_sin6.sin6_addr))) + return NULL; break; } - return NULL; + return bs; } -struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp, char *port_name, +struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp, struct sockaddr_any *peer, struct sockaddr_any *local, - char *vrf_name, bool is_mhop) + ifindex_t ifindex, vrf_id_t vrfid, + bool is_mhop) { - struct bfd_session *l_bfd = NULL; - struct bfd_mhop_key mhop; - struct bfd_shop_key shop; - char vrf_buf[MAXNAMELEN]; + struct interface *ifp; + struct vrf *vrf; + struct bfd_key key; /* Find our session using the ID signaled by the remote end. */ if (cp->discrs.remote_discr) return bfd_find_disc(peer, ntohl(cp->discrs.remote_discr)); /* Search for session without using discriminator. */ - if (is_mhop) { - memset(&mhop, 0, sizeof(mhop)); - mhop.peer = *peer; - mhop.local = *local; - if (vrf_name && vrf_name[0]) { - strlcpy(mhop.vrf_name, vrf_name, sizeof(mhop.vrf_name)); - } else if (port_name && port_name[0]) { - memset(vrf_buf, 0, sizeof(vrf_buf)); - if (ptm_bfd_get_vrf_name(port_name, vrf_buf) != -1) - strlcpy(mhop.vrf_name, vrf_buf, - sizeof(mhop.vrf_name)); - } + ifp = if_lookup_by_index(ifindex, vrfid); + if (vrfid == VRF_DEFAULT) { + /* + * Don't use the default vrf, otherwise we won't find + * sessions that doesn't specify it. + */ + vrf = NULL; + } else + vrf = vrf_lookup_by_id(vrfid); - l_bfd = bfd_mhop_lookup(mhop); - } else { - memset(&shop, 0, sizeof(shop)); - shop.peer = *peer; - if (port_name && port_name[0]) - strlcpy(shop.port_name, port_name, - sizeof(shop.port_name)); - - l_bfd = bfd_shop_lookup(shop); - } + gen_bfd_key(&key, peer, local, is_mhop, ifp ? ifp->name : NULL, + vrf ? vrf->name : NULL); /* XXX maybe remoteDiscr should be checked for remoteHeard cases. */ - return l_bfd; + return bfd_key_lookup(key); } int bfd_xmt_cb(struct thread *t) @@ -369,23 +462,29 @@ int bfd_echo_recvtimer_cb(struct thread *t) return 0; } -static struct bfd_session *bfd_session_new(int sd) +static struct bfd_session *bfd_session_new(void) { struct bfd_session *bs; bs = XCALLOC(MTYPE_BFDD_CONFIG, sizeof(*bs)); - if (bs == NULL) - return NULL; QOBJ_REG(bs, bfd_session); - bs->up_min_tx = BFD_DEFDESIREDMINTX; + bs->timers.desired_min_tx = BFD_DEFDESIREDMINTX; bs->timers.required_min_rx = BFD_DEFREQUIREDMINRX; bs->timers.required_min_echo = BFD_DEF_REQ_MIN_ECHO; bs->detect_mult = BFD_DEFDETECTMULT; bs->mh_ttl = BFD_DEF_MHOP_TTL; + bs->ses_state = PTM_BFD_DOWN; - bs->sock = sd; + /* Initiate connection with slow timers. */ + bs_set_slow_timers(bs); + + /* Initiate remote settings as well. */ + bs->remote_timers = bs->cur_timers; + bs->remote_detect_mult = BFD_DEFDETECTMULT; + + bs->sock = -1; monotime(&bs->uptime); bs->downtime = bs->uptime; @@ -434,22 +533,21 @@ static void _bfd_session_update(struct bfd_session *bs, goto skip_echo; BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO); - ptm_bfd_echo_start(bs); /* Activate/update echo receive timeout timer. */ - bfd_echo_recvtimer_update(bs); + bs_echo_timer_handler(bs); } else { /* Check if echo mode is already disabled. */ if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO)) goto skip_echo; BFD_UNSET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO); - ptm_bfd_echo_stop(bs, 0); + ptm_bfd_echo_stop(bs); } skip_echo: if (bpc->bpc_has_txinterval) - bs->up_min_tx = bpc->bpc_txinterval * 1000; + bs->timers.desired_min_tx = bpc->bpc_txinterval * 1000; if (bpc->bpc_has_recvinterval) bs->timers.required_min_rx = bpc->bpc_recvinterval * 1000; @@ -480,7 +578,9 @@ skip_echo: bs->ses_state = PTM_BFD_ADM_DOWN; control_notify(bs); - ptm_bfd_snd(bs, 0); + /* Don't try to send packets with a disabled session. */ + if (bs->sock != -1) + ptm_bfd_snd(bs, 0); } else { /* Check if already working. */ if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN)) @@ -495,10 +595,6 @@ skip_echo: /* Enable all timers. */ bfd_recvtimer_update(bs); bfd_xmttimer_update(bs, bs->xmt_TO); - if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO)) { - bfd_echo_recvtimer_update(bs); - bfd_echo_xmttimer_update(bs, bs->echo_xmt_TO); - } } } @@ -517,19 +613,22 @@ static int bfd_session_update(struct bfd_session *bs, struct bfd_peer_cfg *bpc) static void bfd_session_free(struct bfd_session *bs) { - if (bs->sock != -1) - close(bs->sock); + struct bfd_session_observer *bso; - bfd_recvtimer_delete(bs); - bfd_echo_recvtimer_delete(bs); - bfd_xmttimer_delete(bs); - bfd_echo_xmttimer_delete(bs); + bfd_session_disable(bs); + bfd_key_delete(bs->key); bfd_id_delete(bs->discrs.my_discr); - if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) - bfd_mhop_delete(bs->mhop); - else - bfd_shop_delete(bs->shop); + + /* Remove observer if any. */ + TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) { + if (bso->bso_bs != bs) + continue; + + break; + } + if (bso != NULL) + bs_observer_del(bso); pl_free(bs->pl); @@ -540,8 +639,6 @@ static void bfd_session_free(struct bfd_session *bs) struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc) { struct bfd_session *bfd, *l_bfd; - struct interface *ifp = NULL; - int psock; /* check to see if this needs a new session */ l_bfd = bs_peer_find(bpc); @@ -553,105 +650,73 @@ struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc) return NULL; } - /* - * No session found, we have to allocate a new one. - * - * First a few critical checks: - * - * * Check that the specified interface exists. - * * Attempt to create the UDP socket (might fail if we exceed - * our limits). - */ - if (bpc->bpc_has_localif) { - ifp = if_lookup_by_name(bpc->bpc_localif, VRF_DEFAULT); - if (ifp == NULL) { - log_error( - "session-new: specified interface doesn't exists."); - return NULL; - } - } - - /* - * Get socket for transmitting control packets. Note that if we - * could use the destination port (3784) for the source - * port we wouldn't need a socket per session. - */ - if (bpc->bpc_ipv4) { - psock = bp_peer_socket(bpc); - if (psock == -1) - return NULL; - } else { - psock = bp_peer_socketv6(bpc); - if (psock == -1) - return NULL; - } - - /* Get memory */ - bfd = bfd_session_new(psock); + /* Get BFD session storage with its defaults. */ + bfd = bfd_session_new(); if (bfd == NULL) { log_error("session-new: allocation failed"); return NULL; } - if (bpc->bpc_has_localif && !bpc->bpc_mhop) - bfd->ifp = ifp; + /* + * Store interface/VRF name in case we need to delay session + * start. See `bfd_session_enable` for more information. + */ + if (bpc->bpc_has_localif) + strlcpy(bfd->key.ifname, bpc->bpc_localif, + sizeof(bfd->key.ifname)); - if (bpc->bpc_ipv4 == false) { - BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6); + if (bpc->bpc_has_vrfname) + strlcpy(bfd->key.vrfname, bpc->bpc_vrfname, + sizeof(bfd->key.vrfname)); - /* Set the IPv6 scope id for link-local addresses. */ - if (IN6_IS_ADDR_LINKLOCAL(&bpc->bpc_local.sa_sin6.sin6_addr)) - bpc->bpc_local.sa_sin6.sin6_scope_id = - bfd->ifp != NULL ? bfd->ifp->ifindex - : IFINDEX_INTERNAL; - if (IN6_IS_ADDR_LINKLOCAL(&bpc->bpc_peer.sa_sin6.sin6_addr)) - bpc->bpc_peer.sa_sin6.sin6_scope_id = - bfd->ifp != NULL ? bfd->ifp->ifindex - : IFINDEX_INTERNAL; - } + /* Copy remaining data. */ + if (bpc->bpc_ipv4 == false) + BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6); - /* Initialize the session */ - bfd->ses_state = PTM_BFD_DOWN; - bfd->discrs.my_discr = ptm_bfd_gen_ID(); - bfd->discrs.remote_discr = 0; - bfd->local_ip = bpc->bpc_local; - bfd->local_address = bpc->bpc_local; - bfd->timers.desired_min_tx = bfd->up_min_tx; - bfd->detect_TO = (bfd->detect_mult * BFD_DEF_SLOWTX); + bfd->key.family = (bpc->bpc_ipv4) ? AF_INET : AF_INET6; + switch (bfd->key.family) { + case AF_INET: + memcpy(&bfd->key.peer, &bpc->bpc_peer.sa_sin.sin_addr, + sizeof(bpc->bpc_peer.sa_sin.sin_addr)); + memcpy(&bfd->key.local, &bpc->bpc_local.sa_sin.sin_addr, + sizeof(bpc->bpc_local.sa_sin.sin_addr)); + break; - /* Use detect_TO first for slow detection, then use recvtimer_update. */ - bfd_recvtimer_update(bfd); + case AF_INET6: + memcpy(&bfd->key.peer, &bpc->bpc_peer.sa_sin6.sin6_addr, + sizeof(bpc->bpc_peer.sa_sin6.sin6_addr)); + memcpy(&bfd->key.local, &bpc->bpc_local.sa_sin6.sin6_addr, + sizeof(bpc->bpc_local.sa_sin6.sin6_addr)); + break; - bfd_id_insert(bfd); + default: + assert(1); + break; + } - if (bpc->bpc_mhop) { + if (bpc->bpc_mhop) BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_MH); - bfd->mhop.peer = bpc->bpc_peer; - bfd->mhop.local = bpc->bpc_local; - if (bpc->bpc_has_vrfname) - strlcpy(bfd->mhop.vrf_name, bpc->bpc_vrfname, - sizeof(bfd->mhop.vrf_name)); - bfd_mhop_insert(bfd); - } else { - bfd->shop.peer = bpc->bpc_peer; - if (bpc->bpc_has_localif) - strlcpy(bfd->shop.port_name, bpc->bpc_localif, - sizeof(bfd->shop.port_name)); + bfd->key.mhop = bpc->bpc_mhop; - bfd_shop_insert(bfd); - } + /* Registrate session into data structures. */ + bfd_key_insert(bfd); + bfd->discrs.my_discr = ptm_bfd_gen_ID(); + bfd_id_insert(bfd); - /* - * XXX: session update triggers echo start, so we must have our - * discriminator ID set first. - */ - _bfd_session_update(bfd, bpc); + /* Try to enable session and schedule for packet receive/send. */ + if (bfd_session_enable(bfd) == -1) { + /* Unrecoverable failure, remove the session/peer. */ + bfd_session_free(bfd); + return NULL; + } - /* Start transmitting with slow interval until peer responds */ - bfd->xmt_TO = BFD_DEF_SLOWTX; + /* Add observer if we have moving parts. */ + if (bfd->key.ifname[0] || bfd->key.vrfname[0] || bfd->sock == -1) + bs_observer_add(bfd); - ptm_bfd_xmt_TO(bfd, 0); + /* Apply other configurations. */ + _bfd_session_update(bfd, bpc); log_info("session-new: %s", bs_to_string(bfd)); @@ -688,12 +753,268 @@ int ptm_bfd_ses_del(struct bfd_peer_cfg *bpc) void bfd_set_polling(struct bfd_session *bs) { - bs->new_timers.desired_min_tx = bs->up_min_tx; - bs->new_timers.required_min_rx = bs->timers.required_min_rx; - bs->new_timers.required_min_echo = bs->timers.required_min_echo; + /* + * Start polling procedure: the only timers that require polling + * to change value without losing connection are: + * + * - Desired minimum transmission interval; + * - Required minimum receive interval; + * + * RFC 5880, Section 6.8.3. + */ bs->polling = 1; } +/* + * bs_<state>_handler() functions implement the BFD state machine + * transition mechanism. `<state>` is the current session state and + * the parameter `nstate` is the peer new state. + */ +static void bs_admin_down_handler(struct bfd_session *bs + __attribute__((__unused__)), + int nstate __attribute__((__unused__))) +{ + /* + * We are administratively down, there is no state machine + * handling. + */ +} + +static void bs_down_handler(struct bfd_session *bs, int nstate) +{ + switch (nstate) { + case PTM_BFD_ADM_DOWN: + /* + * Remote peer doesn't want to talk, so lets keep the + * connection down. + */ + case PTM_BFD_UP: + /* Peer can't be up yet, wait it go to 'init' or 'down'. */ + break; + + case PTM_BFD_DOWN: + /* + * Remote peer agreed that the path is down, lets try to + * bring it up. + */ + bs->ses_state = PTM_BFD_INIT; + break; + + case PTM_BFD_INIT: + /* + * Remote peer told us his path is up, lets turn + * activate the session. + */ + ptm_bfd_ses_up(bs); + break; + + default: + log_debug("state-change: unhandled neighbor state: %d", nstate); + break; + } +} + +static void bs_init_handler(struct bfd_session *bs, int nstate) +{ + switch (nstate) { + case PTM_BFD_ADM_DOWN: + /* + * Remote peer doesn't want to talk, so lets make the + * connection down. + */ + bs->ses_state = PTM_BFD_DOWN; + break; + + case PTM_BFD_DOWN: + /* Remote peer hasn't moved to first stage yet. */ + break; + + case PTM_BFD_INIT: + case PTM_BFD_UP: + /* We agreed on the settings and the path is up. */ + ptm_bfd_ses_up(bs); + break; + + default: + log_debug("state-change: unhandled neighbor state: %d", nstate); + break; + } +} + +static void bs_up_handler(struct bfd_session *bs, int nstate) +{ + switch (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); + break; + + case PTM_BFD_INIT: + case PTM_BFD_UP: + /* Path is up and working. */ + break; + + default: + log_debug("state-change: unhandled neighbor state: %d", nstate); + break; + } +} + +void bs_state_handler(struct bfd_session *bs, int nstate) +{ + switch (bs->ses_state) { + case PTM_BFD_ADM_DOWN: + bs_admin_down_handler(bs, nstate); + break; + case PTM_BFD_DOWN: + bs_down_handler(bs, nstate); + break; + case PTM_BFD_INIT: + bs_init_handler(bs, nstate); + break; + case PTM_BFD_UP: + bs_up_handler(bs, nstate); + break; + + default: + log_debug("state-change: [%s] is in invalid state: %d", + bs_to_string(bs), nstate); + break; + } +} + +/* + * Handles echo timer manipulation after updating timer. + */ +void bs_echo_timer_handler(struct bfd_session *bs) +{ + uint32_t old_timer; + + /* + * Before doing any echo handling, check if it is possible to + * use it. + * + * - Check for `echo-mode` configuration. + * - Check that we are not using multi hop (RFC 5883, + * Section 3). + * - Check that we are already at the up state. + */ + if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO) == 0 + || BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) + || bs->ses_state != PTM_BFD_UP) + return; + + /* Remote peer asked to stop echo. */ + if (bs->remote_timers.required_min_echo == 0) { + if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO_ACTIVE)) + ptm_bfd_echo_stop(bs); + + return; + } + + /* + * Calculate the echo transmission timer: we must not send + * echo packets faster than the minimum required time + * announced by the remote system. + * + * RFC 5880, Section 6.8.9. + */ + old_timer = bs->echo_xmt_TO; + if (bs->remote_timers.required_min_echo > bs->timers.required_min_echo) + bs->echo_xmt_TO = bs->remote_timers.required_min_echo; + else + bs->echo_xmt_TO = bs->timers.required_min_echo; + + if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO_ACTIVE) == 0 + || old_timer != bs->echo_xmt_TO) + ptm_bfd_echo_start(bs); +} + +/* + * RFC 5880 Section 6.5. + * + * When a BFD control packet with the final bit is received, we must + * update the session parameters. + */ +void bs_final_handler(struct bfd_session *bs) +{ + /* Start using our new timers. */ + bs->cur_timers.desired_min_tx = bs->timers.desired_min_tx; + bs->cur_timers.required_min_rx = bs->timers.required_min_rx; + + /* + * TODO: demand mode. See RFC 5880 Section 6.1. + * + * When using demand mode we must disable the detection timer + * for lost control packets. + */ + if (bs->demand_mode) { + /* Notify watchers about changed timers. */ + control_notify_config(BCM_NOTIFY_CONFIG_UPDATE, bs); + return; + } + + /* + * Calculate detection time based on new timers. + * + * Transmission calculation: + * We must respect the RequiredMinRxInterval from the remote + * system: if our desired transmission timer is more than the + * minimum receive rate, then we must lower it to at least the + * minimum receive interval. + * + * RFC 5880, Section 6.8.3. + */ + if (bs->timers.desired_min_tx > bs->remote_timers.required_min_rx) + bs->xmt_TO = bs->remote_timers.required_min_rx; + else + bs->xmt_TO = bs->timers.desired_min_tx; + + /* Apply new transmission timer immediately. */ + ptm_bfd_start_xmt_timer(bs, false); + + /* + * Detection timeout calculation: + * The minimum detection timeout is the remote detection + * multipler (number of packets to be missed) times the agreed + * transmission interval. + * + * RFC 5880, Section 6.8.4. + * + * TODO: support sending/counting more packets inside detection + * timeout. + */ + if (bs->remote_timers.required_min_rx > bs->timers.desired_min_tx) + bs->detect_TO = bs->remote_detect_mult + * bs->remote_timers.required_min_rx; + else + bs->detect_TO = bs->remote_detect_mult + * bs->timers.desired_min_tx; + + /* Apply new receive timer immediately. */ + bfd_recvtimer_update(bs); + + /* Notify watchers about changed timers. */ + control_notify_config(BCM_NOTIFY_CONFIG_UPDATE, bs); +} + +void bs_set_slow_timers(struct bfd_session *bs) +{ + /* + * BFD connection must use slow timers before going up or after + * losing connectivity to avoid wasting bandwidth. + * + * RFC 5880, Section 6.8.3. + */ + bs->cur_timers.desired_min_tx = BFD_DEF_SLOWTX; + bs->cur_timers.required_min_rx = BFD_DEF_SLOWTX; + bs->cur_timers.required_min_echo = 0; + + /* Set the appropriated timeouts for slow connection. */ + bs->detect_TO = (BFD_DEFDETECTMULT * BFD_DEF_SLOWTX); + bs->xmt_TO = BFD_DEF_SLOWTX; +} /* * Helper functions. @@ -839,36 +1160,105 @@ void integer2timestr(uint64_t time, char *buf, size_t buflen) snprintf(buf, buflen, "%u second(s)", second); } -const char *bs_to_string(struct bfd_session *bs) +const char *bs_to_string(const struct bfd_session *bs) { static char buf[256]; + char addr_buf[INET6_ADDRSTRLEN]; int pos; bool is_mhop = BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH); pos = snprintf(buf, sizeof(buf), "mhop:%s", is_mhop ? "yes" : "no"); - if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) { - pos += snprintf(buf + pos, sizeof(buf) - pos, - " peer:%s local:%s", satostr(&bs->mhop.peer), - satostr(&bs->mhop.local)); - - if (bs->mhop.vrf_name[0]) - snprintf(buf + pos, sizeof(buf) - pos, " vrf:%s", - bs->mhop.vrf_name); - } else { - pos += snprintf(buf + pos, sizeof(buf) - pos, " peer:%s", - satostr(&bs->shop.peer)); + pos += snprintf(buf + pos, sizeof(buf) - pos, " peer:%s", + inet_ntop(bs->key.family, &bs->key.peer, addr_buf, + sizeof(addr_buf))); + pos += snprintf(buf + pos, sizeof(buf) - pos, " local:%s", + inet_ntop(bs->key.family, &bs->key.local, addr_buf, + sizeof(addr_buf))); + if (bs->key.vrfname[0]) + pos += snprintf(buf + pos, sizeof(buf) - pos, " vrf:%s", + bs->key.vrfname); + if (bs->key.ifname[0]) + pos += snprintf(buf + pos, sizeof(buf) - pos, " ifname:%s", + bs->key.ifname); + return buf; +} - if (bs->local_address.sa_sin.sin_family) - pos += snprintf(buf + pos, sizeof(buf) - pos, - " local:%s", - satostr(&bs->local_address)); +int bs_observer_add(struct bfd_session *bs) +{ + struct bfd_session_observer *bso; - if (bs->shop.port_name[0]) - snprintf(buf + pos, sizeof(buf) - pos, " interface:%s", - bs->shop.port_name); + bso = XCALLOC(MTYPE_BFDD_SESSION_OBSERVER, sizeof(*bso)); + bso->bso_isaddress = false; + bso->bso_bs = bs; + bso->bso_isinterface = !BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH); + 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; + bso->bso_addr.family = bs->key.family; + memcpy(&bso->bso_addr.u.prefix, &bs->key.local, + sizeof(bs->key.local)); } - return buf; + TAILQ_INSERT_TAIL(&bglobal.bg_obslist, bso, bso_entry); + + return 0; +} + +void bs_observer_del(struct bfd_session_observer *bso) +{ + TAILQ_REMOVE(&bglobal.bg_obslist, bso, bso_entry); + XFREE(MTYPE_BFDD_SESSION_OBSERVER, bso); +} + +void bs_to_bpc(struct bfd_session *bs, struct bfd_peer_cfg *bpc) +{ + memset(bpc, 0, sizeof(*bpc)); + + bpc->bpc_ipv4 = (bs->key.family == AF_INET); + bpc->bpc_mhop = bs->key.mhop; + + switch (bs->key.family) { + case AF_INET: + bpc->bpc_peer.sa_sin.sin_family = AF_INET; + memcpy(&bpc->bpc_peer.sa_sin.sin_addr, &bs->key.peer, + sizeof(bpc->bpc_peer.sa_sin.sin_addr)); + + if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local))) { + bpc->bpc_local.sa_sin.sin_family = AF_INET6; + memcpy(&bpc->bpc_local.sa_sin.sin_addr, &bs->key.local, + sizeof(bpc->bpc_local.sa_sin.sin_addr)); + } + break; + + case AF_INET6: + bpc->bpc_peer.sa_sin.sin_family = AF_INET6; + memcpy(&bpc->bpc_peer.sa_sin6.sin6_addr, &bs->key.peer, + sizeof(bpc->bpc_peer.sa_sin6.sin6_addr)); + + bpc->bpc_local.sa_sin6.sin6_family = AF_INET6; + memcpy(&bpc->bpc_local.sa_sin6.sin6_addr, &bs->key.local, + sizeof(bpc->bpc_local.sa_sin6.sin6_addr)); + break; + } + + if (bs->key.ifname[0]) { + bpc->bpc_has_localif = true; + strlcpy(bpc->bpc_localif, bs->key.ifname, + sizeof(bpc->bpc_localif)); + } + + if (bs->key.vrfname[0]) { + bpc->bpc_has_vrfname = true; + strlcpy(bpc->bpc_vrfname, bs->key.vrfname, + sizeof(bpc->bpc_vrfname)); + } } @@ -876,26 +1266,13 @@ const char *bs_to_string(struct bfd_session *bs) * BFD hash data structures to find sessions. */ static struct hash *bfd_id_hash; -static struct hash *bfd_shop_hash; -static struct hash *bfd_mhop_hash; -static struct hash *bfd_vrf_hash; -static struct hash *bfd_iface_hash; +static struct hash *bfd_key_hash; static unsigned int bfd_id_hash_do(void *p); -static unsigned int bfd_shop_hash_do(void *p); -static unsigned int bfd_mhop_hash_do(void *p); -static unsigned int bfd_vrf_hash_do(void *p); -static unsigned int bfd_iface_hash_do(void *p); +static unsigned int bfd_key_hash_do(void *p); -static void _shop_key(struct bfd_session *bs, const struct bfd_shop_key *shop); -static void _shop_key2(struct bfd_session *bs, const struct bfd_shop_key *shop); -static void _mhop_key(struct bfd_session *bs, const struct bfd_mhop_key *mhop); -static int _iface_key(struct bfd_iface *iface, const char *ifname); - -static void _bfd_free(struct hash_backet *hb, +static void _bfd_free(struct hash_bucket *hb, void *arg __attribute__((__unused__))); -static void _vrf_free(void *arg); -static void _iface_free(void *arg); /* BFD hash for our discriminator. */ static unsigned int bfd_id_hash_do(void *p) @@ -913,114 +1290,20 @@ static bool bfd_id_hash_cmp(const void *n1, const void *n2) } /* BFD hash for single hop. */ -static unsigned int bfd_shop_hash_do(void *p) -{ - struct bfd_session *bs = p; - - return jhash(&bs->shop, sizeof(bs->shop), 0); -} - -static bool bfd_shop_hash_cmp(const void *n1, const void *n2) -{ - const struct bfd_session *bs1 = n1, *bs2 = n2; - - return memcmp(&bs1->shop, &bs2->shop, sizeof(bs1->shop)) == 0; -} - -/* BFD hash for multi hop. */ -static unsigned int bfd_mhop_hash_do(void *p) +static unsigned int bfd_key_hash_do(void *p) { struct bfd_session *bs = p; - return jhash(&bs->mhop, sizeof(bs->mhop), 0); + return jhash(&bs->key, sizeof(bs->key), 0); } -static bool bfd_mhop_hash_cmp(const void *n1, const void *n2) +static bool bfd_key_hash_cmp(const void *n1, const void *n2) { const struct bfd_session *bs1 = n1, *bs2 = n2; - return memcmp(&bs1->mhop, &bs2->mhop, sizeof(bs1->mhop)) == 0; + return memcmp(&bs1->key, &bs2->key, sizeof(bs1->key)) == 0; } -/* BFD hash for VRFs. */ -static unsigned int bfd_vrf_hash_do(void *p) -{ - struct bfd_vrf *vrf = p; - - return jhash_1word(vrf->vrf_id, 0); -} - -static bool bfd_vrf_hash_cmp(const void *n1, const void *n2) -{ - const struct bfd_vrf *v1 = n1, *v2 = n2; - - return v1->vrf_id == v2->vrf_id; -} - -/* BFD hash for interfaces. */ -static unsigned int bfd_iface_hash_do(void *p) -{ - struct bfd_iface *iface = p; - - return string_hash_make(iface->ifname); -} - -static bool bfd_iface_hash_cmp(const void *n1, const void *n2) -{ - const struct bfd_iface *i1 = n1, *i2 = n2; - - return strcmp(i1->ifname, i2->ifname) == 0; -} - -/* Helper functions */ -static void _shop_key(struct bfd_session *bs, const struct bfd_shop_key *shop) -{ - bs->shop = *shop; - - /* Remove unused fields. */ - switch (bs->shop.peer.sa_sin.sin_family) { - case AF_INET: - bs->shop.peer.sa_sin.sin_port = 0; - break; - case AF_INET6: - bs->shop.peer.sa_sin6.sin6_port = 0; - break; - } -} - -static void _shop_key2(struct bfd_session *bs, const struct bfd_shop_key *shop) -{ - _shop_key(bs, shop); - memset(bs->shop.port_name, 0, sizeof(bs->shop.port_name)); -} - -static void _mhop_key(struct bfd_session *bs, const struct bfd_mhop_key *mhop) -{ - bs->mhop = *mhop; - - /* Remove unused fields. */ - switch (bs->mhop.peer.sa_sin.sin_family) { - case AF_INET: - bs->mhop.peer.sa_sin.sin_port = 0; - bs->mhop.local.sa_sin.sin_port = 0; - break; - case AF_INET6: - bs->mhop.peer.sa_sin6.sin6_port = 0; - bs->mhop.local.sa_sin6.sin6_port = 0; - break; - } -} - -static int _iface_key(struct bfd_iface *iface, const char *ifname) -{ - size_t slen = sizeof(iface->ifname); - - memset(iface->ifname, 0, slen); - if (strlcpy(iface->ifname, ifname, slen) >= slen) - return -1; - - return 0; -} /* * Hash public interface / exported functions. @@ -1036,51 +1319,33 @@ struct bfd_session *bfd_id_lookup(uint32_t id) return hash_lookup(bfd_id_hash, &bs); } -struct bfd_session *bfd_shop_lookup(struct bfd_shop_key shop) +struct bfd_session *bfd_key_lookup(struct bfd_key key) { struct bfd_session bs, *bsp; - _shop_key(&bs, &shop); + bs.key = key; + bsp = hash_lookup(bfd_key_hash, &bs); - bsp = hash_lookup(bfd_shop_hash, &bs); - if (bsp == NULL && bs.shop.port_name[0] != 0) { - /* - * Since the local interface spec is optional, try - * searching the key without it as well. - */ - _shop_key2(&bs, &shop); - bsp = hash_lookup(bfd_shop_hash, &bs); + /* Handle cases where local-address is 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); } - return bsp; -} - -struct bfd_session *bfd_mhop_lookup(struct bfd_mhop_key mhop) -{ - struct bfd_session bs; - - _mhop_key(&bs, &mhop); - - return hash_lookup(bfd_mhop_hash, &bs); -} - -struct bfd_vrf *bfd_vrf_lookup(int vrf_id) -{ - struct bfd_vrf vrf; - - vrf.vrf_id = vrf_id; + /* Handle cases where ifname is optional. */ + bs.key = key; + if (bsp == NULL && bs.key.ifname[0]) { + memset(bs.key.ifname, 0, sizeof(bs.key.ifname)); + bsp = hash_lookup(bfd_key_hash, &bs); - return hash_lookup(bfd_vrf_hash, &vrf); -} - -struct bfd_iface *bfd_iface_lookup(const char *ifname) -{ - struct bfd_iface iface; - - if (_iface_key(&iface, ifname) != 0) - return NULL; + /* 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); + } + } - return hash_lookup(bfd_iface_hash, &iface); + return bsp; } /* @@ -1102,50 +1367,18 @@ struct bfd_session *bfd_id_delete(uint32_t id) return hash_release(bfd_id_hash, &bs); } -struct bfd_session *bfd_shop_delete(struct bfd_shop_key shop) +struct bfd_session *bfd_key_delete(struct bfd_key key) { struct bfd_session bs, *bsp; - _shop_key(&bs, &shop); - bsp = hash_release(bfd_shop_hash, &bs); - if (bsp == NULL && shop.port_name[0] != 0) { - /* - * Since the local interface spec is optional, try - * searching the key without it as well. - */ - _shop_key2(&bs, &shop); - bsp = hash_release(bfd_shop_hash, &bs); + bs.key = key; + bsp = hash_lookup(bfd_key_hash, &bs); + if (bsp == NULL && key.ifname[0]) { + memset(bs.key.ifname, 0, sizeof(bs.key.ifname)); + bsp = hash_lookup(bfd_key_hash, &bs); } - return bsp; -} - -struct bfd_session *bfd_mhop_delete(struct bfd_mhop_key mhop) -{ - struct bfd_session bs; - - _mhop_key(&bs, &mhop); - - return hash_release(bfd_mhop_hash, &bs); -} - -struct bfd_vrf *bfd_vrf_delete(int vrf_id) -{ - struct bfd_vrf vrf; - - vrf.vrf_id = vrf_id; - - return hash_release(bfd_vrf_hash, &vrf); -} - -struct bfd_iface *bfd_iface_delete(const char *ifname) -{ - struct bfd_iface iface; - - if (_iface_key(&iface, ifname) != 0) - return NULL; - - return hash_release(bfd_iface_hash, &iface); + return hash_release(bfd_key_hash, bsp); } /* Iteration functions. */ @@ -1154,24 +1387,9 @@ void bfd_id_iterate(hash_iter_func hif, void *arg) hash_iterate(bfd_id_hash, hif, arg); } -void bfd_shop_iterate(hash_iter_func hif, void *arg) +void bfd_key_iterate(hash_iter_func hif, void *arg) { - hash_iterate(bfd_shop_hash, hif, arg); -} - -void bfd_mhop_iterate(hash_iter_func hif, void *arg) -{ - hash_iterate(bfd_mhop_hash, hif, arg); -} - -void bfd_vrf_iterate(hash_iter_func hif, void *arg) -{ - hash_iterate(bfd_vrf_hash, hif, arg); -} - -void bfd_iface_iterate(hash_iter_func hif, void *arg) -{ - hash_iterate(bfd_iface_hash, hif, arg); + hash_iterate(bfd_key_hash, hif, arg); } /* @@ -1185,41 +1403,20 @@ bool bfd_id_insert(struct bfd_session *bs) return (hash_get(bfd_id_hash, bs, hash_alloc_intern) == bs); } -bool bfd_shop_insert(struct bfd_session *bs) +bool bfd_key_insert(struct bfd_session *bs) { - return (hash_get(bfd_shop_hash, bs, hash_alloc_intern) == bs); -} - -bool bfd_mhop_insert(struct bfd_session *bs) -{ - return (hash_get(bfd_mhop_hash, bs, hash_alloc_intern) == bs); -} - -bool bfd_vrf_insert(struct bfd_vrf *vrf) -{ - return (hash_get(bfd_vrf_hash, vrf, hash_alloc_intern) == vrf); -} - -bool bfd_iface_insert(struct bfd_iface *iface) -{ - return (hash_get(bfd_iface_hash, iface, hash_alloc_intern) == iface); + return (hash_get(bfd_key_hash, bs, hash_alloc_intern) == bs); } void bfd_initialize(void) { bfd_id_hash = hash_create(bfd_id_hash_do, bfd_id_hash_cmp, - "BFD discriminator hash"); - bfd_shop_hash = hash_create(bfd_shop_hash_do, bfd_shop_hash_cmp, - "BFD single hop hash"); - bfd_mhop_hash = hash_create(bfd_mhop_hash_do, bfd_mhop_hash_cmp, - "BFD multihop hop hash"); - bfd_vrf_hash = - hash_create(bfd_vrf_hash_do, bfd_vrf_hash_cmp, "BFD VRF hash"); - bfd_iface_hash = hash_create(bfd_iface_hash_do, bfd_iface_hash_cmp, - "BFD interface hash"); + "BFD session discriminator hash"); + bfd_key_hash = hash_create(bfd_key_hash_do, bfd_key_hash_cmp, + "BFD session hash"); } -static void _bfd_free(struct hash_backet *hb, +static void _bfd_free(struct hash_bucket *hb, void *arg __attribute__((__unused__))) { struct bfd_session *bs = hb->data; @@ -1227,20 +1424,6 @@ static void _bfd_free(struct hash_backet *hb, bfd_session_free(bs); } -static void _vrf_free(void *arg) -{ - struct bfd_vrf *vrf = arg; - - XFREE(MTYPE_BFDD_CONFIG, vrf); -} - -static void _iface_free(void *arg) -{ - struct bfd_iface *iface = arg; - - XFREE(MTYPE_BFDD_CONFIG, iface); -} - void bfd_shutdown(void) { /* @@ -1251,17 +1434,9 @@ void bfd_shutdown(void) * assert() here to make sure it really happened. */ bfd_id_iterate(_bfd_free, NULL); - assert(bfd_shop_hash->count == 0); - assert(bfd_mhop_hash->count == 0); - - /* Clean the VRF and interface hashes. */ - hash_clean(bfd_vrf_hash, _vrf_free); - hash_clean(bfd_iface_hash, _iface_free); + assert(bfd_key_hash->count == 0); /* Now free the hashes themselves. */ hash_free(bfd_id_hash); - hash_free(bfd_shop_hash); - hash_free(bfd_mhop_hash); - hash_free(bfd_vrf_hash); - hash_free(bfd_iface_hash); + hash_free(bfd_key_hash); } diff --git a/bfdd/bfd.h b/bfdd/bfd.h index a3e5ad1447..a69ff9a1a7 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -35,8 +35,6 @@ #include "bfdctl.h" -#define ETHERNET_ADDRESS_LENGTH 6 - #ifdef BFD_DEBUG #define BFDD_JSON_CONV_OPTIONS (JSON_C_TO_STRING_PRETTY) #else @@ -48,6 +46,7 @@ DECLARE_MTYPE(BFDD_TMP); DECLARE_MTYPE(BFDD_CONFIG); DECLARE_MTYPE(BFDD_LABEL); DECLARE_MTYPE(BFDD_CONTROL); +DECLARE_MTYPE(BFDD_SESSION_OBSERVER); DECLARE_MTYPE(BFDD_NOTIFICATION); struct bfd_timers { @@ -174,15 +173,13 @@ enum bfd_session_flags { #define BFD_CHECK_FLAG(field, flag) (field & flag) /* BFD session hash keys */ -struct bfd_shop_key { - struct sockaddr_any peer; - char port_name[MAXNAMELEN + 1]; -}; - -struct bfd_mhop_key { - struct sockaddr_any peer; - struct sockaddr_any local; - char vrf_name[MAXNAMELEN + 1]; +struct bfd_key { + uint16_t family; + uint8_t mhop; + struct in6_addr peer; + struct in6_addr local; + char ifname[MAXNAMELEN]; + char vrfname[MAXNAMELEN]; }; struct bfd_session_stats { @@ -214,8 +211,7 @@ struct bfd_session { /* Timers */ struct bfd_timers timers; - struct bfd_timers new_timers; - uint32_t up_min_tx; + struct bfd_timers cur_timers; uint64_t detect_TO; struct thread *echo_recvtimer_ev; struct thread *recvtimer_ev; @@ -229,18 +225,14 @@ struct bfd_session { uint8_t polling; /* This and the localDiscr are the keys to state info */ + struct bfd_key key; struct peer_label *pl; - union { - struct bfd_shop_key shop; - struct bfd_mhop_key mhop; - }; - int sock; struct sockaddr_any local_address; - struct sockaddr_any local_ip; struct interface *ifp; - uint8_t local_mac[ETHERNET_ADDRESS_LENGTH]; - uint8_t peer_mac[ETHERNET_ADDRESS_LENGTH]; + struct vrf *vrf; + + int sock; /* BFD session flags */ enum bfd_session_flags flags; @@ -279,15 +271,18 @@ struct bfd_state_str_list { int type; }; -struct bfd_vrf { - int vrf_id; - char name[MAXNAMELEN + 1]; -} bfd_vrf; +struct bfd_session_observer { + struct bfd_session *bso_bs; + bool bso_isinterface; + bool bso_isaddress; + union { + char bso_entryname[MAXNAMELEN]; + struct prefix bso_addr; + }; -struct bfd_iface { - int vrf_id; - char ifname[MAXNAMELEN + 1]; -} bfd_iface; + TAILQ_ENTRY(bfd_session_observer) bso_entry; +}; +TAILQ_HEAD(obslist, bfd_session_observer); /* States defined per 4.1 */ @@ -299,15 +294,12 @@ struct bfd_iface { /* Various constants */ /* Retrieved from ptm_timer.h from Cumulus PTM sources. */ -#define MSEC_PER_SEC 1000L -#define NSEC_PER_MSEC 1000000L - #define BFD_DEF_DEMAND 0 #define BFD_DEFDETECTMULT 3 -#define BFD_DEFDESIREDMINTX (300 * MSEC_PER_SEC) -#define BFD_DEFREQUIREDMINRX (300 * MSEC_PER_SEC) -#define BFD_DEF_REQ_MIN_ECHO (50 * MSEC_PER_SEC) -#define BFD_DEF_SLOWTX (2000 * MSEC_PER_SEC) +#define BFD_DEFDESIREDMINTX (300 * 1000) /* microseconds. */ +#define BFD_DEFREQUIREDMINRX (300 * 1000) /* microseconds. */ +#define BFD_DEF_REQ_MIN_ECHO (50 * 1000) /* microseconds. */ +#define BFD_DEF_SLOWTX (1000 * 1000) /* microseconds. */ #define BFD_DEF_MHOP_TTL 5 #define BFD_PKT_LEN 24 /* Length of control packet */ #define BFD_TTL_VAL 255 @@ -321,8 +313,6 @@ struct bfd_iface { #define BFD_DEFDESTPORT 3784 #define BFD_DEF_ECHO_PORT 3785 #define BFD_DEF_MHOP_DEST_PORT 4784 -#define BFD_CMD_STRING_LEN (MAXNAMELEN + 50) -#define BFD_BUFFER_LEN (BFD_CMD_STRING_LEN + MAXNAMELEN + 1) /* * control.c @@ -402,6 +392,8 @@ struct bfd_global { struct bcslist bg_bcslist; struct pllist bg_pllist; + + struct obslist bg_obslist; }; extern struct bfd_global bglobal; extern struct bfd_diag_str_list diag_list[]; @@ -470,8 +462,8 @@ int bp_udp_shop(void); int bp_udp_mhop(void); int bp_udp6_shop(void); int bp_udp6_mhop(void); -int bp_peer_socket(struct bfd_peer_cfg *bpc); -int bp_peer_socketv6(struct bfd_peer_cfg *bpc); +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); @@ -509,55 +501,55 @@ void bfd_echo_xmttimer_assign(struct bfd_session *bs, bfd_ev_cb cb); * * BFD protocol specific code. */ +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); -void ptm_bfd_echo_stop(struct bfd_session *bfd, int polling); +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); void ptm_bfd_start_xmt_timer(struct bfd_session *bfd, bool is_echo); -struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp, char *port_name, +struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp, struct sockaddr_any *peer, struct sockaddr_any *local, - char *vrf_name, bool is_mhop); + ifindex_t ifindex, vrf_id_t vrfid, + bool is_mhop); struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc); int bfd_session_update_label(struct bfd_session *bs, const char *nlabel); void bfd_set_polling(struct bfd_session *bs); +void bs_state_handler(struct bfd_session *bs, int nstate); +void bs_echo_timer_handler(struct bfd_session *bs); +void bs_final_handler(struct bfd_session *bs); +void bs_set_slow_timers(struct bfd_session *bs); const char *satostr(struct sockaddr_any *sa); const char *diag2str(uint8_t diag); int strtosa(const char *addr, struct sockaddr_any *sa); void integer2timestr(uint64_t time, char *buf, size_t buflen); -const char *bs_to_string(struct bfd_session *bs); +const char *bs_to_string(const struct bfd_session *bs); + +int bs_observer_add(struct bfd_session *bs); +void bs_observer_del(struct bfd_session_observer *bso); + +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); struct bfd_session *bfd_id_lookup(uint32_t id); -struct bfd_session *bfd_shop_lookup(struct bfd_shop_key shop); -struct bfd_session *bfd_mhop_lookup(struct bfd_mhop_key mhop); -struct bfd_vrf *bfd_vrf_lookup(int vrf_id); -struct bfd_iface *bfd_iface_lookup(const char *ifname); +struct bfd_session *bfd_key_lookup(struct bfd_key key); struct bfd_session *bfd_id_delete(uint32_t id); -struct bfd_session *bfd_shop_delete(struct bfd_shop_key shop); -struct bfd_session *bfd_mhop_delete(struct bfd_mhop_key mhop); -struct bfd_vrf *bfd_vrf_delete(int vrf_id); -struct bfd_iface *bfd_iface_delete(const char *ifname); +struct bfd_session *bfd_key_delete(struct bfd_key key); bool bfd_id_insert(struct bfd_session *bs); -bool bfd_shop_insert(struct bfd_session *bs); -bool bfd_mhop_insert(struct bfd_session *bs); -bool bfd_vrf_insert(struct bfd_vrf *vrf); -bool bfd_iface_insert(struct bfd_iface *iface); +bool bfd_key_insert(struct bfd_session *bs); -typedef void (*hash_iter_func)(struct hash_backet *hb, void *arg); +typedef void (*hash_iter_func)(struct hash_bucket *hb, void *arg); void bfd_id_iterate(hash_iter_func hif, void *arg); -void bfd_shop_iterate(hash_iter_func hif, void *arg); -void bfd_mhop_iterate(hash_iter_func hif, void *arg); -void bfd_vrf_iterate(hash_iter_func hif, void *arg); -void bfd_iface_iterate(hash_iter_func hif, void *arg); +void bfd_key_iterate(hash_iter_func hif, void *arg); /* Export callback functions for `event.c`. */ extern struct thread_master *master; @@ -567,6 +559,8 @@ int bfd_echo_recvtimer_cb(struct thread *t); int bfd_xmt_cb(struct thread *t); int bfd_echo_xmt_cb(struct thread *t); +extern struct in6_addr zero_addr; + /* * bfdd_vty.c diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c index 9cfd7e866f..93677ec85a 100644 --- a/bfdd/bfd_packet.c +++ b/bfdd/bfd_packet.c @@ -47,12 +47,10 @@ int _ptm_bfd_send(struct bfd_session *bs, uint16_t *port, const void *data, static void bfd_sd_reschedule(int sd); ssize_t bfd_recv_ipv4(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl, - char *port, size_t portlen, char *vrfname, - size_t vrfnamelen, struct sockaddr_any *local, + ifindex_t *ifindex, struct sockaddr_any *local, struct sockaddr_any *peer); ssize_t bfd_recv_ipv6(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl, - char *port, size_t portlen, char *vrfname, - size_t vrfnamelen, struct sockaddr_any *local, + ifindex_t *ifindex, struct sockaddr_any *local, 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); @@ -81,7 +79,10 @@ int _ptm_bfd_send(struct bfd_session *bs, uint16_t *port, const void *data, if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6)) { memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; - sin6.sin6_addr = bs->shop.peer.sa_sin6.sin6_addr; + memcpy(&sin6.sin6_addr, &bs->key.peer, sizeof(sin6.sin6_addr)); + if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr)) + sin6.sin6_scope_id = bs->ifp->ifindex; + sin6.sin6_port = (port) ? *port : (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) @@ -94,7 +95,7 @@ int _ptm_bfd_send(struct bfd_session *bs, uint16_t *port, const void *data, } else { memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; - sin.sin_addr = bs->shop.peer.sa_sin.sin_addr; + memcpy(&sin.sin_addr, &bs->key.peer, sizeof(sin.sin_addr)); sin.sin_port = (port) ? *port : (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) @@ -122,7 +123,7 @@ int _ptm_bfd_send(struct bfd_session *bs, uint16_t *port, const void *data, void ptm_bfd_echo_snd(struct bfd_session *bfd) { - struct sockaddr_any *sa; + struct sockaddr *sa; socklen_t salen; int sd; struct bfd_echo_pkt bep; @@ -137,31 +138,36 @@ void ptm_bfd_echo_snd(struct bfd_session *bfd) bep.len = BFD_ECHO_PKT_LEN; bep.my_discr = htonl(bfd->discrs.my_discr); - sa = BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_MH) ? &bfd->mhop.peer - : &bfd->shop.peer; if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6)) { sd = bglobal.bg_echov6; - sin6 = sa->sa_sin6; + memset(&sin6, 0, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + memcpy(&sin6.sin6_addr, &bfd->key.peer, sizeof(sin6.sin6_addr)); + if (bfd->ifp && IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr)) + sin6.sin6_scope_id = bfd->ifp->ifindex; + sin6.sin6_port = htons(BFD_DEF_ECHO_PORT); #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN sin6.sin6_len = sizeof(sin6); #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ - sa = (struct sockaddr_any *)&sin6; + sa = (struct sockaddr *)&sin6; salen = sizeof(sin6); } else { sd = bglobal.bg_echo; - sin = sa->sa_sin; + memset(&sin6, 0, sizeof(sin6)); + sin.sin_family = AF_INET; + memcpy(&sin.sin_addr, &bfd->key.peer, sizeof(sin.sin_addr)); sin.sin_port = htons(BFD_DEF_ECHO_PORT); #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN sin.sin_len = sizeof(sin); #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ - sa = (struct sockaddr_any *)&sin; + sa = (struct sockaddr *)&sin; salen = sizeof(sin); } - if (bp_udp_send(sd, BFD_TTL_VAL, (uint8_t *)&bep, sizeof(bep), - (struct sockaddr *)sa, salen) + if (bp_udp_send(sd, BFD_TTL_VAL, (uint8_t *)&bep, sizeof(bep), sa, + salen) == -1) return; @@ -213,20 +219,36 @@ void ptm_bfd_snd(struct bfd_session *bfd, int fbit) cp.flags = 0; BFD_SETSTATE(cp.flags, bfd->ses_state); BFD_SETDEMANDBIT(cp.flags, BFD_DEF_DEMAND); - BFD_SETPBIT(cp.flags, bfd->polling); + + /* + * Polling and Final can't be set at the same time. + * + * RFC 5880, Section 6.5. + */ BFD_SETFBIT(cp.flags, fbit); + if (fbit == 0) + BFD_SETPBIT(cp.flags, bfd->polling); + cp.detect_mult = bfd->detect_mult; cp.len = BFD_PKT_LEN; cp.discrs.my_discr = htonl(bfd->discrs.my_discr); cp.discrs.remote_discr = htonl(bfd->discrs.remote_discr); if (bfd->polling) { cp.timers.desired_min_tx = - htonl(bfd->new_timers.desired_min_tx); + htonl(bfd->timers.desired_min_tx); cp.timers.required_min_rx = - htonl(bfd->new_timers.required_min_rx); + htonl(bfd->timers.required_min_rx); } else { - cp.timers.desired_min_tx = htonl(bfd->timers.desired_min_tx); - cp.timers.required_min_rx = htonl(bfd->timers.required_min_rx); + /* + * We can only announce current setting on poll, this + * avoids timing mismatch with our peer and give it + * the oportunity to learn. See `bs_final_handler` for + * more information. + */ + cp.timers.desired_min_tx = + htonl(bfd->cur_timers.desired_min_tx); + cp.timers.required_min_rx = + htonl(bfd->cur_timers.required_min_rx); } cp.timers.required_min_echo = htonl(bfd->timers.required_min_echo); @@ -237,21 +259,16 @@ void ptm_bfd_snd(struct bfd_session *bfd, int fbit) } ssize_t bfd_recv_ipv4(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl, - char *port, size_t portlen, char *vrfname, - size_t vrfnamelen, struct sockaddr_any *local, + ifindex_t *ifindex, struct sockaddr_any *local, struct sockaddr_any *peer) { - struct interface *ifp; struct cmsghdr *cm; - int ifindex; ssize_t mlen; struct sockaddr_in msgaddr; struct msghdr msghdr; struct iovec iov[1]; uint8_t cmsgbuf[255]; - port[0] = '\0'; - /* Prepare the recvmsg params. */ iov[0].iov_base = msgbuf; iov[0].iov_len = msgbuflen; @@ -309,13 +326,7 @@ ssize_t bfd_recv_ipv4(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl, local->sa_sin.sin_len = sizeof(local->sa_sin); #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ - ifp = if_lookup_by_index(pi->ipi_ifindex, VRF_DEFAULT); - if (ifp == NULL) - break; - - if (strlcpy(port, ifp->name, portlen) >= portlen) - log_debug( - "ipv4-recv: interface name truncated"); + *ifindex = pi->ipi_ifindex; break; } #endif /* BFD_LINUX */ @@ -350,31 +361,18 @@ ssize_t bfd_recv_ipv4(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl, } /* OS agnostic way of getting interface name. */ - if (port[0] == 0) { - ifindex = getsockopt_ifindex(AF_INET, &msghdr); - if (ifindex <= 0) - return mlen; - - ifp = if_lookup_by_index(ifindex, VRF_DEFAULT); - if (ifp == NULL) - return mlen; - - if (strlcpy(port, ifp->name, portlen) >= portlen) - log_debug("ipv4-recv: interface name truncated"); - } + if (*ifindex == IFINDEX_INTERNAL) + *ifindex = getsockopt_ifindex(AF_INET, &msghdr); return mlen; } ssize_t bfd_recv_ipv6(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl, - char *port, size_t portlen, char *vrfname, - size_t vrfnamelen, struct sockaddr_any *local, + ifindex_t *ifindex, struct sockaddr_any *local, struct sockaddr_any *peer) { - struct interface *ifp; struct cmsghdr *cm; struct in6_pktinfo *pi6 = NULL; - int ifindex = 0; ssize_t mlen; uint32_t ttlval; struct sockaddr_in6 msgaddr6; @@ -429,24 +427,16 @@ ssize_t bfd_recv_ipv6(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl, local->sa_sin6.sin6_len = sizeof(local->sa_sin6); #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ - ifindex = pi6->ipi6_ifindex; - ifp = if_lookup_by_index(ifindex, VRF_DEFAULT); - if (ifp == NULL) - break; - - if (strlcpy(port, ifp->name, portlen) - >= portlen) - log_debug( - "ipv6-recv: interface name truncated"); + *ifindex = pi6->ipi6_ifindex; } } } /* Set scope ID for link local addresses. */ if (IN6_IS_ADDR_LINKLOCAL(&peer->sa_sin6.sin6_addr)) - peer->sa_sin6.sin6_scope_id = ifindex; + peer->sa_sin6.sin6_scope_id = *ifindex; if (IN6_IS_ADDR_LINKLOCAL(&local->sa_sin6.sin6_addr)) - local->sa_sin6.sin6_scope_id = ifindex; + local->sa_sin6.sin6_scope_id = *ifindex; return mlen; } @@ -481,8 +471,8 @@ static void bfd_sd_reschedule(int sd) } static void cp_debug(bool mhop, struct sockaddr_any *peer, - struct sockaddr_any *local, const char *port, - const char *vrf, const char *fmt, ...) + struct sockaddr_any *local, ifindex_t ifindex, + vrf_id_t vrfid, const char *fmt, ...) { char buf[512], peerstr[128], localstr[128], portstr[64], vrfstr[64]; va_list vl; @@ -498,13 +488,13 @@ static void cp_debug(bool mhop, struct sockaddr_any *peer, else localstr[0] = 0; - if (port[0]) - snprintf(portstr, sizeof(portstr), " port:%s", port); + if (ifindex != IFINDEX_INTERNAL) + snprintf(portstr, sizeof(portstr), " port:%u", ifindex); else portstr[0] = 0; - if (vrf[0]) - snprintf(vrfstr, sizeof(vrfstr), " vrf:%s", port); + if (vrfid != VRF_DEFAULT) + snprintf(vrfstr, sizeof(vrfstr), " vrf:%u", vrfid); else vrfstr[0] = 0; @@ -523,10 +513,10 @@ int bfd_recv_cb(struct thread *t) struct bfd_pkt *cp; bool is_mhop; ssize_t mlen = 0; - uint32_t oldEchoXmt_TO, oldXmtTime; - uint8_t ttl; + uint8_t ttl = 0; + vrf_id_t vrfid = VRF_DEFAULT; + ifindex_t ifindex = IFINDEX_INTERNAL; struct sockaddr_any local, peer; - char port[MAXNAMELEN + 1], vrfname[MAXNAMELEN + 1]; uint8_t msgbuf[1516]; /* Schedule next read. */ @@ -539,8 +529,6 @@ int bfd_recv_cb(struct thread *t) } /* Sanitize input/output. */ - memset(port, 0, sizeof(port)); - memset(vrfname, 0, sizeof(vrfname)); memset(&local, 0, sizeof(local)); memset(&peer, 0, sizeof(peer)); @@ -548,26 +536,24 @@ int bfd_recv_cb(struct thread *t) is_mhop = false; if (sd == bglobal.bg_shop || sd == bglobal.bg_mhop) { is_mhop = sd == bglobal.bg_mhop; - mlen = bfd_recv_ipv4(sd, msgbuf, sizeof(msgbuf), &ttl, port, - sizeof(port), vrfname, sizeof(vrfname), + 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; - mlen = bfd_recv_ipv6(sd, msgbuf, sizeof(msgbuf), &ttl, port, - sizeof(port), vrfname, sizeof(vrfname), + mlen = bfd_recv_ipv6(sd, msgbuf, sizeof(msgbuf), &ttl, &ifindex, &local, &peer); } /* Implement RFC 5880 6.8.6 */ if (mlen < BFD_PKT_LEN) { - cp_debug(is_mhop, &peer, &local, port, vrfname, + cp_debug(is_mhop, &peer, &local, ifindex, vrfid, "too small (%ld bytes)", mlen); return 0; } /* Validate packet TTL. */ - if ((is_mhop == false) && (ttl != BFD_TTL_VAL)) { - cp_debug(is_mhop, &peer, &local, port, vrfname, + if ((!is_mhop) && (ttl != BFD_TTL_VAL)) { + cp_debug(is_mhop, &peer, &local, ifindex, vrfid, "invalid TTL: %d expected %d", ttl, BFD_TTL_VAL); return 0; } @@ -581,32 +567,32 @@ int bfd_recv_cb(struct thread *t) */ cp = (struct bfd_pkt *)(msgbuf); if (BFD_GETVER(cp->diag) != BFD_VERSION) { - cp_debug(is_mhop, &peer, &local, port, vrfname, + cp_debug(is_mhop, &peer, &local, ifindex, vrfid, "bad version %d", BFD_GETVER(cp->diag)); return 0; } if (cp->detect_mult == 0) { - cp_debug(is_mhop, &peer, &local, port, vrfname, + cp_debug(is_mhop, &peer, &local, ifindex, vrfid, "detect multiplier set to zero"); return 0; } if ((cp->len < BFD_PKT_LEN) || (cp->len > mlen)) { - cp_debug(is_mhop, &peer, &local, port, vrfname, "too small"); + cp_debug(is_mhop, &peer, &local, ifindex, vrfid, "too small"); return 0; } if (cp->discrs.my_discr == 0) { - cp_debug(is_mhop, &peer, &local, port, vrfname, + cp_debug(is_mhop, &peer, &local, ifindex, vrfid, "'my discriminator' is zero"); return 0; } /* Find the session that this packet belongs. */ - bfd = ptm_bfd_sess_find(cp, port, &peer, &local, vrfname, is_mhop); + bfd = ptm_bfd_sess_find(cp, &peer, &local, ifindex, vrfid, is_mhop); if (bfd == NULL) { - cp_debug(is_mhop, &peer, &local, port, vrfname, + cp_debug(is_mhop, &peer, &local, ifindex, vrfid, "no session found"); return 0; } @@ -619,13 +605,13 @@ int bfd_recv_cb(struct thread *t) */ if (is_mhop) { if ((BFD_TTL_VAL - bfd->mh_ttl) > BFD_TTL_VAL) { - cp_debug(is_mhop, &peer, &local, port, vrfname, + cp_debug(is_mhop, &peer, &local, ifindex, vrfid, "exceeded max hop count (expected %d, got %d)", bfd->mh_ttl, BFD_TTL_VAL); return 0; } - } else if (bfd->local_ip.sa_sin.sin_family == AF_UNSPEC) { - bfd->local_ip = local; + } else if (bfd->local_address.sa_sin.sin_family == AF_UNSPEC) { + bfd->local_address = local; } /* @@ -633,137 +619,57 @@ int bfd_recv_cb(struct thread *t) * packet came in. */ if (bfd->ifp == NULL) - bfd->ifp = if_lookup_by_name(port, VRF_DEFAULT); + bfd->ifp = if_lookup_by_index(ifindex, vrfid); /* Log remote discriminator changes. */ if ((bfd->discrs.remote_discr != 0) && (bfd->discrs.remote_discr != ntohl(cp->discrs.my_discr))) - cp_debug(is_mhop, &peer, &local, port, vrfname, - "remote discriminator mismatch (expected %d, got %d)", + cp_debug(is_mhop, &peer, &local, ifindex, vrfid, + "remote discriminator mismatch (expected %u, got %u)", bfd->discrs.remote_discr, ntohl(cp->discrs.my_discr)); bfd->discrs.remote_discr = ntohl(cp->discrs.my_discr); - /* If received the Final bit, the new values should take effect */ - if (bfd->polling && BFD_GETFBIT(cp->flags)) { - bfd->timers.desired_min_tx = bfd->new_timers.desired_min_tx; - bfd->timers.required_min_rx = bfd->new_timers.required_min_rx; - bfd->new_timers.desired_min_tx = 0; - bfd->new_timers.required_min_rx = 0; - bfd->polling = 0; - } - - if (!bfd->demand_mode) { - /* Compute detect time */ - bfd->detect_TO = cp->detect_mult - * ((bfd->timers.required_min_rx - > ntohl(cp->timers.desired_min_tx)) - ? bfd->timers.required_min_rx - : ntohl(cp->timers.desired_min_tx)); - bfd->remote_detect_mult = cp->detect_mult; - } else - cp_debug(is_mhop, &peer, &local, port, vrfname, - "unsupported demand mode"); - /* Save remote diagnostics before state switch. */ bfd->remote_diag = cp->diag & BFD_DIAGMASK; - /* State switch from section 6.8.6 */ - if (BFD_GETSTATE(cp->flags) == PTM_BFD_ADM_DOWN) { - if (bfd->ses_state != PTM_BFD_DOWN) - ptm_bfd_ses_dn(bfd, BD_NEIGHBOR_DOWN); - } else { - switch (bfd->ses_state) { - case (PTM_BFD_DOWN): - if (BFD_GETSTATE(cp->flags) == PTM_BFD_INIT) - ptm_bfd_ses_up(bfd); - else if (BFD_GETSTATE(cp->flags) == PTM_BFD_DOWN) - bfd->ses_state = PTM_BFD_INIT; - break; - case (PTM_BFD_INIT): - if (BFD_GETSTATE(cp->flags) == PTM_BFD_INIT - || BFD_GETSTATE(cp->flags) == PTM_BFD_UP) - ptm_bfd_ses_up(bfd); - break; - case (PTM_BFD_UP): - if (BFD_GETSTATE(cp->flags) == PTM_BFD_DOWN) - ptm_bfd_ses_dn(bfd, BD_NEIGHBOR_DOWN); - break; - } - } - - /* - * Handle echo packet status: - * - Start echo packets if configured and permitted - * (required_min_echo > 0); - * - Stop echo packets if not allowed (required_min_echo == 0); - * - Recalculate echo packet interval; - */ - if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO)) { - if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE)) { - if (!ntohl(cp->timers.required_min_echo)) { - ptm_bfd_echo_stop(bfd, 1); - } else { - oldEchoXmt_TO = bfd->echo_xmt_TO; - bfd->echo_xmt_TO = - bfd->timers.required_min_echo; - if (ntohl(cp->timers.required_min_echo) - > bfd->echo_xmt_TO) - bfd->echo_xmt_TO = ntohl( - cp->timers.required_min_echo); - if (oldEchoXmt_TO != bfd->echo_xmt_TO) - ptm_bfd_echo_start(bfd); - } - } else if (ntohl(cp->timers.required_min_echo)) { - bfd->echo_xmt_TO = bfd->timers.required_min_echo; - if (ntohl(cp->timers.required_min_echo) - > bfd->echo_xmt_TO) - bfd->echo_xmt_TO = - ntohl(cp->timers.required_min_echo); - ptm_bfd_echo_start(bfd); - } - } + /* Update remote timers settings. */ + bfd->remote_timers.desired_min_tx = ntohl(cp->timers.desired_min_tx); + bfd->remote_timers.required_min_rx = ntohl(cp->timers.required_min_rx); + bfd->remote_timers.required_min_echo = + ntohl(cp->timers.required_min_echo); + bfd->remote_detect_mult = cp->detect_mult; - if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE)) { - bfd->echo_xmt_TO = bfd->timers.required_min_echo; - if (ntohl(cp->timers.required_min_echo) > bfd->echo_xmt_TO) - bfd->echo_xmt_TO = ntohl(cp->timers.required_min_echo); - } + /* State switch from section 6.2. */ + bs_state_handler(bfd, BFD_GETSTATE(cp->flags)); - /* Calculate new transmit time */ - oldXmtTime = bfd->xmt_TO; - bfd->xmt_TO = - (bfd->timers.desired_min_tx > ntohl(cp->timers.required_min_rx)) - ? bfd->timers.desired_min_tx - : ntohl(cp->timers.required_min_rx); + /* RFC 5880, Section 6.5: handle POLL/FINAL negotiation sequence. */ + if (bfd->polling && BFD_GETFBIT(cp->flags)) { + /* Disable pooling. */ + bfd->polling = 0; - /* If transmit time has changed, and too much time until next xmt, - * restart - */ - if (BFD_GETPBIT(cp->flags)) { - ptm_bfd_xmt_TO(bfd, 1); - } else if (oldXmtTime != bfd->xmt_TO) { - /* XXX add some skid to this as well */ - ptm_bfd_start_xmt_timer(bfd, false); + /* Handle poll finalization. */ + bs_final_handler(bfd); + } else { + /* Received a packet, lets update the receive timer. */ + bfd_recvtimer_update(bfd); } - /* Restart detection timer (packet received) */ - if (!bfd->demand_mode) - bfd_recvtimer_update(bfd); + /* Handle echo timers changes. */ + bs_echo_timer_handler(bfd); /* - * Save the timers and state sent by the remote end - * for debugging and statistics. + * We've received a packet with the POLL bit set, we must send + * a control packet back with the FINAL bit set. + * + * RFC 5880, Section 6.5. */ - if (BFD_GETFBIT(cp->flags)) { - bfd->remote_timers.desired_min_tx = - ntohl(cp->timers.desired_min_tx); - bfd->remote_timers.required_min_rx = - ntohl(cp->timers.required_min_rx); - bfd->remote_timers.required_min_echo = - ntohl(cp->timers.required_min_echo); - - control_notify_config(BCM_NOTIFY_CONFIG_UPDATE, bfd); + if (BFD_GETPBIT(cp->flags)) { + /* We are finalizing a poll negotiation. */ + bs_final_handler(bfd); + + /* Send the control packet with the final bit immediately. */ + ptm_bfd_snd(bfd, 1); } return 0; @@ -781,21 +687,20 @@ int bp_bfd_echo_in(int sd, uint8_t *ttl, uint32_t *my_discr) struct bfd_echo_pkt *bep; ssize_t rlen; struct sockaddr_any local, peer; - char port[MAXNAMELEN + 1], vrfname[MAXNAMELEN + 1]; + ifindex_t ifindex = IFINDEX_INTERNAL; + vrf_id_t vrfid = VRF_DEFAULT; uint8_t msgbuf[1516]; if (sd == bglobal.bg_echo) - rlen = bfd_recv_ipv4(sd, msgbuf, sizeof(msgbuf), ttl, port, - sizeof(port), vrfname, sizeof(vrfname), + rlen = bfd_recv_ipv4(sd, msgbuf, sizeof(msgbuf), ttl, &ifindex, &local, &peer); else - rlen = bfd_recv_ipv6(sd, msgbuf, sizeof(msgbuf), ttl, port, - sizeof(port), vrfname, sizeof(vrfname), + rlen = bfd_recv_ipv6(sd, msgbuf, sizeof(msgbuf), ttl, &ifindex, &local, &peer); /* Short packet, better not risk reading it. */ if (rlen < (ssize_t)sizeof(*bep)) { - cp_debug(false, &peer, &local, port, vrfname, + cp_debug(false, &peer, &local, ifindex, vrfid, "small echo packet"); return -1; } @@ -813,7 +718,7 @@ int bp_bfd_echo_in(int sd, uint8_t *ttl, uint32_t *my_discr) bep = (struct bfd_echo_pkt *)msgbuf; *my_discr = ntohl(bep->my_discr); if (*my_discr == 0) { - cp_debug(false, &peer, &local, port, vrfname, + cp_debug(false, &peer, &local, ifindex, vrfid, "invalid echo packet discriminator (zero)"); return -1; } @@ -995,7 +900,7 @@ int bp_udp_mhop(void) return sd; } -int bp_peer_socket(struct bfd_peer_cfg *bpc) +int bp_peer_socket(const struct bfd_session *bs) { int sd, pcount; struct sockaddr_in sin; @@ -1020,13 +925,14 @@ int bp_peer_socket(struct bfd_peer_cfg *bpc) return -1; } - if (bpc->bpc_has_localif) { - if (bp_bind_dev(sd, bpc->bpc_localif) != 0) { + if (bs->key.ifname[0]) { + if (bp_bind_dev(sd, bs->key.ifname) != 0) { close(sd); return -1; } - } else if (bpc->bpc_mhop && bpc->bpc_has_vrfname) { - if (bp_bind_dev(sd, bpc->bpc_vrfname) != 0) { + } 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; } @@ -1034,14 +940,12 @@ int bp_peer_socket(struct bfd_peer_cfg *bpc) /* Find an available source port in the proper range */ memset(&sin, 0, sizeof(sin)); - sin = bpc->bpc_local.sa_sin; sin.sin_family = AF_INET; #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN sin.sin_len = sizeof(sin); #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ - if (bpc->bpc_mhop) - sin.sin_addr = bpc->bpc_local.sa_sin.sin_addr; - else + memcpy(&sin.sin_addr, &bs->key.local, sizeof(sin.sin_addr)); + if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0) sin.sin_addr.s_addr = INADDR_ANY; pcount = 0; @@ -1066,9 +970,8 @@ int bp_peer_socket(struct bfd_peer_cfg *bpc) * IPv6 sockets */ -int bp_peer_socketv6(struct bfd_peer_cfg *bpc) +int bp_peer_socketv6(const struct bfd_session *bs) { - struct interface *ifp; int sd, pcount; struct sockaddr_in6 sin6; static int srcPort = BFD_SRCPORTINIT; @@ -1098,20 +1001,18 @@ int bp_peer_socketv6(struct bfd_peer_cfg *bpc) #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN sin6.sin6_len = sizeof(sin6); #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ - sin6 = bpc->bpc_local.sa_sin6; - if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr)) { - ifp = if_lookup_by_name(bpc->bpc_localif, VRF_DEFAULT); - sin6.sin6_scope_id = - (ifp != NULL) ? ifp->ifindex : IFINDEX_INTERNAL; - } + memcpy(&sin6.sin6_addr, &bs->key.local, sizeof(sin6.sin6_addr)); + if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr)) + sin6.sin6_scope_id = bs->ifp->ifindex; - if (bpc->bpc_has_localif) { - if (bp_bind_dev(sd, bpc->bpc_localif) != 0) { + if (bs->key.ifname[0]) { + if (bp_bind_dev(sd, bs->key.ifname) != 0) { close(sd); return -1; } - } else if (bpc->bpc_mhop && bpc->bpc_has_vrfname) { - if (bp_bind_dev(sd, bpc->bpc_vrfname) != 0) { + } 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; } diff --git a/bfdd/bfdd.c b/bfdd/bfdd.c index 250f8d21c0..6023b5e4f0 100644 --- a/bfdd/bfdd.c +++ b/bfdd/bfdd.c @@ -32,6 +32,7 @@ DEFINE_MTYPE(BFDD, BFDD_TMP, "short-lived temporary memory"); DEFINE_MTYPE(BFDD, BFDD_CONFIG, "long-lived configuration memory"); 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"); /* Master of threads. */ @@ -153,6 +154,7 @@ struct bfd_state_str_list state_list[] = { static void bg_init(void) { TAILQ_INIT(&bglobal.bg_bcslist); + TAILQ_INIT(&bglobal.bg_obslist); bglobal.bg_shop = bp_udp_shop(); bglobal.bg_mhop = bp_udp_mhop(); diff --git a/bfdd/bfdd_vty.c b/bfdd/bfdd_vty.c index 8f8fff6b18..c139492076 100644 --- a/bfdd/bfdd_vty.c +++ b/bfdd/bfdd_vty.c @@ -51,7 +51,8 @@ */ static int bfdd_write_config(struct vty *vty); static int bfdd_peer_write_config(struct vty *vty); -static void _bfdd_peer_write_config(struct hash_backet *hb, void *arg); +static void _bfdd_peer_write_config(struct vty *vty, struct bfd_session *bs); +static void _bfdd_peer_write_config_iter(struct hash_bucket *hb, void *arg); static int bfd_configure_peer(struct bfd_peer_cfg *bpc, bool mhop, const struct sockaddr_any *peer, const struct sockaddr_any *local, @@ -64,13 +65,13 @@ 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_peer_iter(struct hash_backet *hb, void *arg); -static void _display_peer_json_iter(struct hash_backet *hb, void *arg); +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); 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_backet *hb, void *arg); -static void _display_peer_counter_json_iter(struct hash_backet *hb, void *arg); +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 struct bfd_session * _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv, @@ -78,7 +79,6 @@ _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv, const char *local_str, const char *ifname, const char *vrfname); - /* * Commands definition. */ @@ -130,6 +130,10 @@ DEFUN_NOSH( 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) { @@ -171,7 +175,6 @@ DEFPY(bfd_peer_detectmultiplier, bfd_peer_detectmultiplier_cmd, return CMD_SUCCESS; bs->detect_mult = multiplier; - bfd_set_polling(bs); return CMD_SUCCESS; } @@ -201,10 +204,10 @@ DEFPY(bfd_peer_txinterval, bfd_peer_txinterval_cmd, struct bfd_session *bs; bs = VTY_GET_CONTEXT(bfd_session); - if (bs->up_min_tx == (uint32_t)(interval * 1000)) + if (bs->timers.desired_min_tx == (uint32_t)(interval * 1000)) return CMD_SUCCESS; - bs->up_min_tx = interval * 1000; + bs->timers.desired_min_tx = interval * 1000; bfd_set_polling(bs); return CMD_SUCCESS; @@ -222,7 +225,6 @@ DEFPY(bfd_peer_echointerval, bfd_peer_echointerval_cmd, return CMD_SUCCESS; bs->timers.required_min_echo = interval * 1000; - bfd_set_polling(bs); return CMD_SUCCESS; } @@ -283,17 +285,15 @@ DEFPY(bfd_peer_echo, bfd_peer_echo_cmd, "[no] echo-mode", return CMD_SUCCESS; BFD_UNSET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO); - ptm_bfd_echo_stop(bs, 0); + ptm_bfd_echo_stop(bs); } else { if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO)) return CMD_SUCCESS; BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO); /* Apply setting immediately. */ - if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN)) { - ptm_bfd_echo_start(bs); - bfd_echo_recvtimer_update(bs); - } + if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN)) + bs_echo_timer_handler(bs); } return CMD_SUCCESS; @@ -368,22 +368,25 @@ DEFPY(bfd_no_peer, bfd_no_peer_cmd, */ static void _display_peer_header(struct vty *vty, struct bfd_session *bs) { - if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) { - vty_out(vty, "\tpeer %s", satostr(&bs->mhop.peer)); + char addr_buf[INET6_ADDRSTRLEN]; + + vty_out(vty, "\tpeer %s", + inet_ntop(bs->key.family, &bs->key.peer, addr_buf, + sizeof(addr_buf))); + + if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) vty_out(vty, " multihop"); - vty_out(vty, " local-address %s", satostr(&bs->mhop.local)); - if (bs->mhop.vrf_name[0]) - vty_out(vty, " vrf %s", bs->mhop.vrf_name); - vty_out(vty, "\n"); - } else { - vty_out(vty, "\tpeer %s", satostr(&bs->shop.peer)); - if (bs->local_address.sa_sin.sin_family != AF_UNSPEC) - vty_out(vty, " local-address %s", - satostr(&bs->local_address)); - if (bs->shop.port_name[0]) - vty_out(vty, " interface %s", bs->shop.port_name); - vty_out(vty, "\n"); - } + + if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local))) + vty_out(vty, " local-address %s", + inet_ntop(bs->key.family, &bs->key.local, addr_buf, + sizeof(addr_buf))); + + if (bs->key.vrfname[0]) + vty_out(vty, " vrf %s", bs->key.vrfname); + if (bs->key.ifname[0]) + vty_out(vty, " interface %s", bs->key.ifname); + vty_out(vty, "\n"); if (bs->pl) vty_out(vty, "\t\tlabel: %s\n", bs->pl->pl_label); @@ -433,20 +436,10 @@ static void _display_peer(struct vty *vty, struct bfd_session *bs) vty_out(vty, "\t\tLocal timers:\n"); vty_out(vty, "\t\t\tReceive interval: %" PRIu32 "ms\n", bs->timers.required_min_rx / 1000); - vty_out(vty, "\t\t\tTransmission interval: %" PRIu32 "ms", + vty_out(vty, "\t\t\tTransmission interval: %" PRIu32 "ms\n", bs->timers.desired_min_tx / 1000); - if (bs->up_min_tx != bs->timers.desired_min_tx) - vty_out(vty, " (configured %" PRIu32 "ms)\n", - bs->up_min_tx / 1000); - else - vty_out(vty, "\n"); - - vty_out(vty, "\t\t\tEcho transmission interval: "); - if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO)) - vty_out(vty, "%" PRIu32 "ms\n", - bs->timers.required_min_echo / 1000); - else - vty_out(vty, "disabled\n"); + vty_out(vty, "\t\t\tEcho transmission interval: %" PRIu32 "ms\n", + bs->timers.required_min_echo / 1000); vty_out(vty, "\t\tRemote timers:\n"); vty_out(vty, "\t\t\tReceive interval: %" PRIu32 "ms\n", @@ -462,23 +455,25 @@ static void _display_peer(struct vty *vty, struct bfd_session *bs) static struct json_object *_peer_json_header(struct bfd_session *bs) { struct json_object *jo = json_object_new_object(); + char addr_buf[INET6_ADDRSTRLEN]; - if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) { + if (bs->key.mhop) json_object_boolean_true_add(jo, "multihop"); - json_object_string_add(jo, "peer", satostr(&bs->mhop.peer)); - json_object_string_add(jo, "local", satostr(&bs->mhop.local)); - if (bs->mhop.vrf_name[0]) - json_object_string_add(jo, "vrf", bs->mhop.vrf_name); - } else { + else json_object_boolean_false_add(jo, "multihop"); - json_object_string_add(jo, "peer", satostr(&bs->shop.peer)); - if (bs->local_address.sa_sin.sin_family != AF_UNSPEC) - json_object_string_add(jo, "local", - satostr(&bs->local_address)); - if (bs->shop.port_name[0]) - json_object_string_add(jo, "interface", - bs->shop.port_name); - } + + json_object_string_add(jo, "peer", + inet_ntop(bs->key.family, &bs->key.peer, + addr_buf, sizeof(addr_buf))); + if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local))) + json_object_string_add(jo, "local", + inet_ntop(bs->key.family, &bs->key.local, + addr_buf, sizeof(addr_buf))); + + if (bs->key.vrfname[0]) + json_object_string_add(jo, "vrf", bs->key.vrfname); + if (bs->key.ifname[0]) + json_object_string_add(jo, "interface", bs->key.ifname); if (bs->pl) json_object_string_add(jo, "label", bs->pl->pl_label); @@ -548,7 +543,7 @@ static void _display_peer_json(struct vty *vty, struct bfd_session *bs) json_object_free(jo); } -static void _display_peer_iter(struct hash_backet *hb, void *arg) +static void _display_peer_iter(struct hash_bucket *hb, void *arg) { struct vty *vty = arg; struct bfd_session *bs = hb->data; @@ -556,7 +551,7 @@ static void _display_peer_iter(struct hash_backet *hb, void *arg) _display_peer(vty, bs); } -static void _display_peer_json_iter(struct hash_backet *hb, void *arg) +static void _display_peer_json_iter(struct hash_bucket *hb, void *arg) { struct json_object *jo = arg, *jon = NULL; struct bfd_session *bs = hb->data; @@ -574,7 +569,7 @@ static void _display_all_peers(struct vty *vty, bool use_json) { struct json_object *jo; - if (use_json == false) { + if (!use_json) { vty_out(vty, "BFD Peers:\n"); bfd_id_iterate(_display_peer_iter, vty); return; @@ -631,7 +626,7 @@ static void _display_peer_counters_json(struct vty *vty, struct bfd_session *bs) json_object_free(jo); } -static void _display_peer_counter_iter(struct hash_backet *hb, void *arg) +static void _display_peer_counter_iter(struct hash_bucket *hb, void *arg) { struct vty *vty = arg; struct bfd_session *bs = hb->data; @@ -639,7 +634,7 @@ static void _display_peer_counter_iter(struct hash_backet *hb, void *arg) _display_peer_counter(vty, bs); } -static void _display_peer_counter_json_iter(struct hash_backet *hb, void *arg) +static void _display_peer_counter_json_iter(struct hash_bucket *hb, void *arg) { struct json_object *jo = arg, *jon = NULL; struct bfd_session *bs = hb->data; @@ -657,7 +652,7 @@ static void _display_peers_counter(struct vty *vty, bool use_json) { struct json_object *jo; - if (use_json == false) { + if (!use_json) { vty_out(vty, "BFD Peers:\n"); bfd_id_iterate(_display_peer_counter_iter, vty); return; @@ -924,36 +919,40 @@ static int bfdd_write_config(struct vty *vty) return 0; } -static void _bfdd_peer_write_config(struct hash_backet *hb, void *arg) +static void _bfdd_peer_write_config(struct vty *vty, struct bfd_session *bs) { - struct vty *vty = arg; - struct bfd_session *bs = hb->data; + char addr_buf[INET6_ADDRSTRLEN]; + + vty_out(vty, " peer %s", + inet_ntop(bs->key.family, &bs->key.peer, addr_buf, + sizeof(addr_buf))); - if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) { - vty_out(vty, " peer %s", satostr(&bs->mhop.peer)); + if (bs->key.mhop) vty_out(vty, " multihop"); - vty_out(vty, " local-address %s", satostr(&bs->mhop.local)); - if (bs->mhop.vrf_name[0]) - vty_out(vty, " vrf %s", bs->mhop.vrf_name); - vty_out(vty, "\n"); - } else { - vty_out(vty, " peer %s", satostr(&bs->shop.peer)); - if (bs->local_address.sa_sin.sin_family != AF_UNSPEC) - vty_out(vty, " local-address %s", - satostr(&bs->local_address)); - if (bs->shop.port_name[0]) - vty_out(vty, " interface %s", bs->shop.port_name); - vty_out(vty, "\n"); - } + + if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local))) + vty_out(vty, " local-address %s", + inet_ntop(bs->key.family, &bs->key.local, addr_buf, + sizeof(addr_buf))); + + if (bs->key.vrfname[0]) + vty_out(vty, " vrf %s", bs->key.vrfname); + if (bs->key.ifname[0]) + vty_out(vty, " interface %s", bs->key.ifname); + vty_out(vty, "\n"); + + if (bs->sock == -1) + vty_out(vty, + " ! vrf, interface or local-address doesn't exist\n"); if (bs->detect_mult != BPC_DEF_DETECTMULTIPLIER) vty_out(vty, " detect-multiplier %d\n", bs->detect_mult); if (bs->timers.required_min_rx != (BPC_DEF_RECEIVEINTERVAL * 1000)) vty_out(vty, " receive-interval %" PRIu32 "\n", bs->timers.required_min_rx / 1000); - if (bs->up_min_tx != (BPC_DEF_TRANSMITINTERVAL * 1000)) + if (bs->timers.desired_min_tx != (BPC_DEF_TRANSMITINTERVAL * 1000)) vty_out(vty, " transmit-interval %" PRIu32 "\n", - bs->up_min_tx / 1000); + bs->timers.desired_min_tx / 1000); if (bs->timers.required_min_echo != (BPC_DEF_ECHOINTERVAL * 1000)) vty_out(vty, " echo-interval %" PRIu32 "\n", bs->timers.required_min_echo / 1000); @@ -968,9 +967,30 @@ static void _bfdd_peer_write_config(struct hash_backet *hb, void *arg) vty_out(vty, " !\n"); } +DEFUN_NOSH(show_debugging_bfd, + show_debugging_bfd_cmd, + "show debugging [bfd]", + SHOW_STR + DEBUG_STR + "BFD daemon\n") +{ + vty_out(vty, "BFD debugging status:\n"); + + return CMD_SUCCESS; +} + +static void _bfdd_peer_write_config_iter(struct hash_bucket *hb, void *arg) +{ + struct vty *vty = arg; + struct bfd_session *bs = hb->data; + + _bfdd_peer_write_config(vty, bs); +} + static int bfdd_peer_write_config(struct vty *vty) { - bfd_id_iterate(_bfdd_peer_write_config, vty); + bfd_id_iterate(_bfdd_peer_write_config_iter, vty); + return 1; } @@ -993,6 +1013,7 @@ void bfdd_vty_init(void) install_element(ENABLE_NODE, &bfd_show_peers_cmd); install_element(ENABLE_NODE, &bfd_show_peer_cmd); install_element(CONFIG_NODE, &bfd_enter_cmd); + install_element(ENABLE_NODE, &show_debugging_bfd_cmd); /* Install BFD node and commands. */ install_node(&bfd_node, bfdd_write_config); diff --git a/bfdd/config.c b/bfdd/config.c index 06089780c6..cd57ea9fe3 100644 --- a/bfdd/config.c +++ b/bfdd/config.c @@ -309,24 +309,7 @@ static int parse_peer_label_config(struct json_object *jo, log_debug("\tpeer-label: %s", sval); /* Translate the label into BFD address keys. */ - bpc->bpc_ipv4 = !BFD_CHECK_FLAG(pl->pl_bs->flags, BFD_SESS_FLAG_IPV6); - bpc->bpc_mhop = BFD_CHECK_FLAG(pl->pl_bs->flags, BFD_SESS_FLAG_MH); - if (bpc->bpc_mhop) { - bpc->bpc_peer = pl->pl_bs->mhop.peer; - bpc->bpc_local = pl->pl_bs->mhop.local; - if (pl->pl_bs->mhop.vrf_name[0]) { - bpc->bpc_has_vrfname = true; - strlcpy(bpc->bpc_vrfname, pl->pl_bs->mhop.vrf_name, - sizeof(bpc->bpc_vrfname)); - } - } else { - bpc->bpc_peer = pl->pl_bs->shop.peer; - if (pl->pl_bs->shop.port_name[0]) { - bpc->bpc_has_localif = true; - strlcpy(bpc->bpc_localif, pl->pl_bs->shop.port_name, - sizeof(bpc->bpc_localif)); - } - } + bs_to_bpc(pl->pl_bs, bpc); return 0; } @@ -471,7 +454,8 @@ char *config_notify_config(const char *op, struct bfd_session *bs) json_object_int_add(resp, "detect-multiplier", bs->detect_mult); json_object_int_add(resp, "receive-interval", bs->timers.required_min_rx / 1000); - json_object_int_add(resp, "transmit-interval", bs->up_min_tx / 1000); + json_object_int_add(resp, "transmit-interval", + bs->timers.desired_min_tx / 1000); json_object_int_add(resp, "echo-interval", bs->timers.required_min_echo / 1000); @@ -518,6 +502,8 @@ int config_notify_request(struct bfd_control_socket *bcs, const char *jsonstr, static int json_object_add_peer(struct json_object *jo, struct bfd_session *bs) { + char addr_buf[INET6_ADDRSTRLEN]; + /* Add peer 'key' information. */ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6)) json_object_boolean_true_add(jo, "ipv6"); @@ -527,22 +513,26 @@ static int json_object_add_peer(struct json_object *jo, struct bfd_session *bs) if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) { json_object_boolean_true_add(jo, "multihop"); json_object_string_add(jo, "peer-address", - satostr(&bs->mhop.peer)); + inet_ntop(bs->key.family, &bs->key.peer, + addr_buf, sizeof(addr_buf))); json_object_string_add(jo, "local-address", - satostr(&bs->mhop.local)); - if (strlen(bs->mhop.vrf_name) > 0) - json_object_string_add(jo, "vrf-name", - bs->mhop.vrf_name); + inet_ntop(bs->key.family, &bs->key.local, + addr_buf, sizeof(addr_buf))); + if (bs->key.vrfname[0]) + json_object_string_add(jo, "vrf-name", bs->key.vrfname); } else { json_object_boolean_false_add(jo, "multihop"); json_object_string_add(jo, "peer-address", - satostr(&bs->shop.peer)); - if (bs->local_address.sa_sin.sin_family != AF_UNSPEC) - json_object_string_add(jo, "local-address", - satostr(&bs->local_address)); - if (strlen(bs->shop.port_name) > 0) + inet_ntop(bs->key.family, &bs->key.peer, + addr_buf, sizeof(addr_buf))); + if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local))) + json_object_string_add( + jo, "local-address", + inet_ntop(bs->key.family, &bs->key.local, + addr_buf, sizeof(addr_buf))); + if (bs->key.ifname[0]) json_object_string_add(jo, "local-interface", - bs->shop.port_name); + bs->key.ifname); } if (bs->pl) @@ -574,8 +564,6 @@ struct peer_label *pl_new(const char *label, struct bfd_session *bs) struct peer_label *pl; pl = XCALLOC(MTYPE_BFDD_LABEL, sizeof(*pl)); - if (pl == NULL) - return NULL; if (strlcpy(pl->pl_label, label, sizeof(pl->pl_label)) > sizeof(pl->pl_label)) diff --git a/bfdd/control.c b/bfdd/control.c index 554a5a8d80..c308d647d8 100644 --- a/bfdd/control.c +++ b/bfdd/control.c @@ -65,7 +65,7 @@ static void control_handle_notify_add(struct bfd_control_socket *bcs, struct bfd_control_msg *bcm); static void control_handle_notify_del(struct bfd_control_socket *bcs, struct bfd_control_msg *bcm); -static void _control_handle_notify(struct hash_backet *hb, void *arg); +static void _control_handle_notify(struct hash_bucket *hb, void *arg); static void control_handle_notify(struct bfd_control_socket *bcs, struct bfd_control_msg *bcm); static void control_response(struct bfd_control_socket *bcs, uint16_t id, @@ -186,8 +186,6 @@ struct bfd_control_socket *control_new(int sd) struct bfd_control_socket *bcs; bcs = XCALLOC(MTYPE_BFDD_CONTROL, sizeof(*bcs)); - if (bcs == NULL) - return NULL; /* Disable notifications by default. */ bcs->bcs_notify = 0; @@ -247,10 +245,6 @@ struct bfd_notify_peer *control_notifypeer_new(struct bfd_control_socket *bcs, return bnp; bnp = XCALLOC(MTYPE_BFDD_CONTROL, sizeof(*bnp)); - if (bnp == NULL) { - log_warning("%s: calloc: %s", __func__, strerror(errno)); - return NULL; - } TAILQ_INSERT_TAIL(&bcs->bcs_bnplist, bnp, bnp_entry); bnp->bnp_bs = bs; @@ -285,10 +279,6 @@ struct bfd_control_queue *control_queue_new(struct bfd_control_socket *bcs) struct bfd_control_queue *bcq; bcq = XCALLOC(MTYPE_BFDD_NOTIFICATION, sizeof(*bcq)); - if (bcq == NULL) { - log_warning("%s: calloc: %s", __func__, strerror(errno)); - return NULL; - } control_reset_buf(&bcq->bcq_bcb); TAILQ_INSERT_TAIL(&bcs->bcs_bcqueue, bcq, bcq_entry); @@ -630,7 +620,7 @@ static struct bfd_session *_notify_find_peer(struct bfd_peer_cfg *bpc) return bs_peer_find(bpc); } -static void _control_handle_notify(struct hash_backet *hb, void *arg) +static void _control_handle_notify(struct hash_bucket *hb, void *arg) { struct bfd_control_socket *bcs = arg; struct bfd_session *bs = hb->data; @@ -743,11 +733,6 @@ static void control_response(struct bfd_control_socket *bcs, uint16_t id, jsonstrlen = strlen(jsonstr); bcm = XMALLOC(MTYPE_BFDD_NOTIFICATION, sizeof(struct bfd_control_msg) + jsonstrlen); - if (bcm == NULL) { - log_warning("%s: malloc: %s", __func__, strerror(errno)); - XFREE(MTYPE_BFDD_NOTIFICATION, jsonstr); - return; - } bcm->bcm_length = htonl(jsonstrlen); bcm->bcm_ver = BMV_VERSION_1; @@ -778,11 +763,6 @@ static void _control_notify(struct bfd_control_socket *bcs, jsonstrlen = strlen(jsonstr); bcm = XMALLOC(MTYPE_BFDD_NOTIFICATION, sizeof(struct bfd_control_msg) + jsonstrlen); - if (bcm == NULL) { - log_warning("%s: malloc: %s", __func__, strerror(errno)); - XFREE(MTYPE_BFDD_NOTIFICATION, jsonstr); - return; - } bcm->bcm_length = htonl(jsonstrlen); bcm->bcm_ver = BMV_VERSION_1; @@ -846,11 +826,6 @@ static void _control_notify_config(struct bfd_control_socket *bcs, jsonstrlen = strlen(jsonstr); bcm = XMALLOC(MTYPE_BFDD_NOTIFICATION, sizeof(struct bfd_control_msg) + jsonstrlen); - if (bcm == NULL) { - log_warning("%s: malloc: %s", __func__, strerror(errno)); - XFREE(MTYPE_BFDD_NOTIFICATION, jsonstr); - return; - } bcm->bcm_length = htonl(jsonstrlen); bcm->bcm_ver = BMV_VERSION_1; diff --git a/bfdd/event.c b/bfdd/event.c index 3f48921af9..5ba54c2b0b 100644 --- a/bfdd/event.c +++ b/bfdd/event.c @@ -43,7 +43,8 @@ void bfd_recvtimer_update(struct bfd_session *bs) bfd_recvtimer_delete(bs); /* Don't add event if peer is deactivated. */ - if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN)) + if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN) || + bs->sock == -1) return; tv_normalize(&tv); @@ -63,7 +64,8 @@ void bfd_echo_recvtimer_update(struct bfd_session *bs) bfd_echo_recvtimer_delete(bs); /* Don't add event if peer is deactivated. */ - if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN)) + if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN) || + bs->sock == -1) return; tv_normalize(&tv); @@ -83,7 +85,8 @@ void bfd_xmttimer_update(struct bfd_session *bs, uint64_t jitter) bfd_xmttimer_delete(bs); /* Don't add event if peer is deactivated. */ - if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN)) + if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN) || + bs->sock == -1) return; tv_normalize(&tv); @@ -102,7 +105,8 @@ void bfd_echo_xmttimer_update(struct bfd_session *bs, uint64_t jitter) bfd_echo_xmttimer_delete(bs); /* Don't add event if peer is deactivated. */ - if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN)) + if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN) || + bs->sock == -1) return; tv_normalize(&tv); diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c index a57167376a..b44d13f132 100644 --- a/bfdd/ptm_adapter.c +++ b/bfdd/ptm_adapter.c @@ -55,7 +55,7 @@ static struct zclient *zclient; /* * Prototypes */ -static int _ptm_msg_address(struct stream *msg, struct sockaddr_any *sa); +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, @@ -127,24 +127,24 @@ static void debug_printbpc(const char *func, unsigned int line, #define DEBUG_PRINTBPC(bpc) #endif /* BFD_DEBUG */ -static int _ptm_msg_address(struct stream *msg, struct sockaddr_any *sa) +static int _ptm_msg_address(struct stream *msg, int family, const void *addr) { - switch (sa->sa_sin.sin_family) { + stream_putc(msg, family); + + switch (family) { case AF_INET: - stream_putc(msg, sa->sa_sin.sin_family); - stream_put_in_addr(msg, &sa->sa_sin.sin_addr); + stream_put(msg, addr, sizeof(struct in_addr)); stream_putc(msg, 32); break; case AF_INET6: - stream_putc(msg, sa->sa_sin6.sin6_family); - stream_put(msg, &sa->sa_sin6.sin6_addr, - sizeof(sa->sa_sin6.sin6_addr)); + stream_put(msg, addr, sizeof(struct in6_addr)); stream_putc(msg, 128); break; default: - return -1; + assert(0); + break; } return 0; @@ -153,7 +153,6 @@ static int _ptm_msg_address(struct stream *msg, struct sockaddr_any *sa) int ptm_bfd_notify(struct bfd_session *bs) { struct stream *msg; - struct sockaddr_any sac; bs->stats.znotification++; @@ -195,10 +194,7 @@ int ptm_bfd_notify(struct bfd_session *bs) stream_putl(msg, IFINDEX_INTERNAL); /* BFD destination prefix information. */ - if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) - _ptm_msg_address(msg, &bs->mhop.peer); - else - _ptm_msg_address(msg, &bs->shop.peer); + _ptm_msg_address(msg, bs->key.family, &bs->key.peer); /* BFD status */ switch (bs->ses_state) { @@ -218,34 +214,7 @@ int ptm_bfd_notify(struct bfd_session *bs) } /* BFD source prefix information. */ - if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) { - _ptm_msg_address(msg, &bs->mhop.local); - } else { - if (bs->local_address.sa_sin.sin_family) - _ptm_msg_address(msg, &bs->local_address); - else if (bs->local_address.sa_sin.sin_family) - _ptm_msg_address(msg, &bs->local_ip); - else { - sac = bs->shop.peer; - switch (sac.sa_sin.sin_family) { - case AF_INET: - memset(&sac.sa_sin.sin_addr, 0, - sizeof(sac.sa_sin.sin_family)); - break; - case AF_INET6: - memset(&sac.sa_sin6.sin6_addr, 0, - sizeof(sac.sa_sin6.sin6_family)); - break; - - default: - assert(false); - break; - } - - /* No local address found yet, so send zeroes. */ - _ptm_msg_address(msg, &sac); - } - } + _ptm_msg_address(msg, bs->key.family, &bs->key.local); /* Write packet size. */ stream_putw_at(msg, 0, stream_get_endp(msg)); @@ -290,7 +259,6 @@ stream_failure: static int _ptm_msg_read(struct stream *msg, int command, struct bfd_peer_cfg *bpc, struct ptm_client **pc) { - struct interface *ifp; uint32_t pid; uint8_t ttl __attribute__((unused)); size_t ifnamelen; @@ -385,31 +353,6 @@ static int _ptm_msg_read(struct stream *msg, int command, if (bpc->bpc_has_localif) { STREAM_GET(bpc->bpc_localif, msg, ifnamelen); bpc->bpc_localif[ifnamelen] = 0; - - /* - * IPv6 link-local addresses must use scope id, - * otherwise the session lookup will always fail - * and we'll have multiple sessions showing up. - * - * This problem only happens with single hop - * since it is not possible to have link-local - * address for multi hop sessions. - */ - if (bpc->bpc_ipv4 == false - && IN6_IS_ADDR_LINKLOCAL( - &bpc->bpc_peer.sa_sin6.sin6_addr)) { - ifp = if_lookup_by_name_all_vrf( - bpc->bpc_localif); - if (ifp == NULL) { - log_error( - "ptm-read: interface %s doesn't exists", - bpc->bpc_localif); - return -1; - } - - bpc->bpc_peer.sa_sin6.sin6_scope_id = - ifp->ifindex; - } } } @@ -597,23 +540,138 @@ static void bfdd_zebra_connected(struct zclient *zc) zclient_send_message(zclient); } -static int bfdd_interface_update(int cmd, struct zclient *zc, uint16_t len, +static void bfdd_sessions_enable_interface(struct interface *ifp) +{ + struct bfd_session_observer *bso; + struct bfd_session *bs; + + TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) { + if (bso->bso_isinterface == false) + continue; + + /* Interface name mismatch. */ + bs = bso->bso_bs; + if (strcmp(ifp->name, bs->key.ifname)) + continue; + /* Skip enabled sessions. */ + if (bs->sock != -1) + continue; + + /* Try to enable it. */ + bfd_session_enable(bs); + } +} + +static void bfdd_sessions_disable_interface(struct interface *ifp) +{ + struct bfd_session_observer *bso; + struct bfd_session *bs; + + TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) { + if (bso->bso_isinterface == false) + continue; + + /* Interface name mismatch. */ + bs = bso->bso_bs; + if (strcmp(ifp->name, bs->key.ifname)) + continue; + /* Skip disabled sessions. */ + if (bs->sock == -1) + continue; + + /* Try to enable it. */ + bfd_session_disable(bs); + + TAILQ_INSERT_HEAD(&bglobal.bg_obslist, bso, bso_entry); + } +} + +static int bfdd_interface_update(int cmd, struct zclient *zc, + uint16_t len __attribute__((__unused__)), vrf_id_t vrfid) { + struct interface *ifp; + /* * `zebra_interface_add_read` will handle the interface creation * on `lib/if.c`. We'll use that data structure instead of * rolling our own. */ if (cmd == ZEBRA_INTERFACE_ADD) { - zebra_interface_add_read(zc->ibuf, vrfid); + ifp = zebra_interface_add_read(zc->ibuf, vrfid); + if (ifp == NULL) + return 0; + + bfdd_sessions_enable_interface(ifp); return 0; } /* Update interface information. */ - zebra_interface_state_read(zc->ibuf, vrfid); + ifp = zebra_interface_state_read(zc->ibuf, vrfid); + if (ifp == NULL) + return 0; + + bfdd_sessions_disable_interface(ifp); + + return 0; +} + +static int bfdd_interface_vrf_update(int command __attribute__((__unused__)), + struct zclient *zclient, + zebra_size_t length + __attribute__((__unused__)), + vrf_id_t vrfid) +{ + struct interface *ifp; + vrf_id_t nvrfid; - /* TODO: stop all sessions using this interface. */ + ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrfid, &nvrfid); + if (ifp == NULL) + return 0; + + if_update_to_new_vrf(ifp, nvrfid); + + return 0; +} + +static void bfdd_sessions_enable_address(struct connected *ifc) +{ + struct bfd_session_observer *bso; + struct bfd_session *bs; + struct prefix prefix; + + TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) { + if (bso->bso_isaddress == false) + continue; + + /* Skip enabled sessions. */ + bs = bso->bso_bs; + if (bs->sock != -1) + continue; + + /* Check address. */ + prefix = bso->bso_addr; + prefix.prefixlen = ifc->address->prefixlen; + if (prefix_cmp(&prefix, ifc->address)) + continue; + + /* Try to enable it. */ + bfd_session_enable(bs); + } +} + +static int bfdd_interface_address_update(int cmd, struct zclient *zc, + zebra_size_t len + __attribute__((__unused__)), + vrf_id_t vrfid) +{ + struct connected *ifc; + + ifc = zebra_interface_address_read(cmd, zc->ibuf, vrfid); + if (ifc == NULL) + return 0; + + bfdd_sessions_enable_address(ifc); return 0; } @@ -637,6 +695,13 @@ void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv) /* Learn interfaces from zebra instead of the OS. */ zclient->interface_add = bfdd_interface_update; zclient->interface_delete = bfdd_interface_update; + + /* Learn about interface VRF. */ + zclient->interface_vrf_update = bfdd_interface_vrf_update; + + /* Learn about new addresses being registered. */ + zclient->interface_address_add = bfdd_interface_address_update; + zclient->interface_address_delete = bfdd_interface_address_update; } void bfdd_zclient_stop(void) @@ -676,8 +741,6 @@ static struct ptm_client *pc_new(uint32_t pid) /* Allocate the client data and save it. */ pc = XCALLOC(MTYPE_BFDD_CONTROL, sizeof(*pc)); - if (pc == NULL) - return NULL; pc->pc_pid = pid; TAILQ_INSERT_HEAD(&pcqueue, pc, pc_entry); @@ -723,8 +786,6 @@ static struct ptm_client_notification *pcn_new(struct ptm_client *pc, /* Save the client notification data. */ pcn = XCALLOC(MTYPE_BFDD_NOTIFICATION, sizeof(*pcn)); - if (pcn == NULL) - return NULL; TAILQ_INSERT_HEAD(&pc->pc_pcnqueue, pcn, pcn_entry); pcn->pcn_pc = pc; diff --git a/bgpd/bgp_addpath.c b/bgpd/bgp_addpath.c index 55a86f99fc..63373cb9a7 100644 --- a/bgpd/bgp_addpath.c +++ b/bgpd/bgp_addpath.c @@ -175,6 +175,28 @@ int bgp_addpath_tx_path(enum bgp_addpath_strat strat, } } +static void bgp_addpath_flush_type_rn(struct bgp *bgp, afi_t afi, safi_t safi, + enum bgp_addpath_strat addpath_type, + struct bgp_node *rn) +{ + struct bgp_path_info *pi; + + idalloc_drain_pool( + bgp->tx_addpath.id_allocators[afi][safi][addpath_type], + &(rn->tx_addpath.free_ids[addpath_type])); + for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) { + if (pi->tx_addpath.addpath_tx_id[addpath_type] + != IDALLOC_INVALID) { + idalloc_free( + bgp->tx_addpath + .id_allocators[afi][safi][addpath_type], + pi->tx_addpath.addpath_tx_id[addpath_type]); + pi->tx_addpath.addpath_tx_id[addpath_type] = + IDALLOC_INVALID; + } + } +} + /* * Purge all addpath ID's on a BGP instance associated with the addpath * strategy, and afi/safi combination. This lets us let go of all memory held to @@ -185,26 +207,24 @@ int bgp_addpath_tx_path(enum bgp_addpath_strat strat, static void bgp_addpath_flush_type(struct bgp *bgp, afi_t afi, safi_t safi, enum bgp_addpath_strat addpath_type) { - struct bgp_node *rn; - struct bgp_path_info *pi; + struct bgp_node *rn, *nrn; for (rn = bgp_table_top(bgp->rib[afi][safi]); rn; rn = bgp_route_next(rn)) { - idalloc_drain_pool( - bgp->tx_addpath.id_allocators[afi][safi][addpath_type], - &(rn->tx_addpath.free_ids[addpath_type])); - for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) { - if (pi->tx_addpath.addpath_tx_id[addpath_type] - != IDALLOC_INVALID) { - idalloc_free( - bgp->tx_addpath - .id_allocators[afi][safi] - [addpath_type], - pi->tx_addpath - .addpath_tx_id[addpath_type]); - pi->tx_addpath.addpath_tx_id[addpath_type] = - IDALLOC_INVALID; - } + if (safi == SAFI_MPLS_VPN) { + struct bgp_table *table; + + table = bgp_node_get_bgp_table_info(rn); + if (!table) + continue; + + for (nrn = bgp_table_top(table); nrn; + nrn = bgp_route_next(nrn)) + bgp_addpath_flush_type_rn(bgp, afi, safi, + addpath_type, nrn); + } else { + bgp_addpath_flush_type_rn(bgp, afi, safi, addpath_type, + rn); } } @@ -234,8 +254,7 @@ static void bgp_addpath_populate_path(struct id_alloc *allocator, static void bgp_addpath_populate_type(struct bgp *bgp, afi_t afi, safi_t safi, enum bgp_addpath_strat addpath_type) { - struct bgp_node *rn; - struct bgp_path_info *bi; + struct bgp_node *rn, *nrn; char buf[200]; struct id_alloc *allocator; @@ -255,9 +274,29 @@ static void bgp_addpath_populate_type(struct bgp *bgp, afi_t afi, safi_t safi, allocator = bgp->tx_addpath.id_allocators[afi][safi][addpath_type]; for (rn = bgp_table_top(bgp->rib[afi][safi]); rn; - rn = bgp_route_next(rn)) - for (bi = bgp_node_get_bgp_path_info(rn); bi; bi = bi->next) - bgp_addpath_populate_path(allocator, bi, addpath_type); + rn = bgp_route_next(rn)) { + struct bgp_path_info *bi; + + if (safi == SAFI_MPLS_VPN) { + struct bgp_table *table; + + table = bgp_node_get_bgp_table_info(rn); + if (!table) + continue; + + for (nrn = bgp_table_top(table); nrn; + nrn = bgp_route_next(nrn)) + for (bi = bgp_node_get_bgp_path_info(nrn); bi; + bi = bi->next) + bgp_addpath_populate_path(allocator, bi, + addpath_type); + } else { + for (bi = bgp_node_get_bgp_path_info(rn); bi; + bi = bi->next) + bgp_addpath_populate_path(allocator, bi, + addpath_type); + } + } } /* @@ -345,7 +384,7 @@ void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi, } } - zlog_info("Resetting peer %s%s due to change in addpath config\n", + zlog_info("Resetting peer %s%s due to change in addpath config", CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP) ? "group " : "", peer->host); diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c index 208a2947ef..05eeeca156 100644 --- a/bgpd/bgp_advertise.c +++ b/bgpd/bgp_advertise.c @@ -45,8 +45,8 @@ peer. */ struct bgp_advertise_attr *baa_new(void) { - return (struct bgp_advertise_attr *)XCALLOC( - MTYPE_BGP_ADVERTISE_ATTR, sizeof(struct bgp_advertise_attr)); + return XCALLOC(MTYPE_BGP_ADVERTISE_ATTR, + sizeof(struct bgp_advertise_attr)); } static void baa_free(struct bgp_advertise_attr *baa) @@ -84,8 +84,7 @@ bool baa_hash_cmp(const void *p1, const void *p2) information. */ struct bgp_advertise *bgp_advertise_new(void) { - return (struct bgp_advertise *)XCALLOC(MTYPE_BGP_ADVERTISE, - sizeof(struct bgp_advertise)); + return XCALLOC(MTYPE_BGP_ADVERTISE, sizeof(struct bgp_advertise)); } void bgp_advertise_free(struct bgp_advertise *adv) @@ -255,8 +254,7 @@ void bgp_sync_delete(struct peer *peer) safi_t safi; FOREACH_AFI_SAFI (afi, safi) { - if (peer->sync[afi][safi]) - XFREE(MTYPE_BGP_SYNCHRONISE, peer->sync[afi][safi]); + XFREE(MTYPE_BGP_SYNCHRONISE, peer->sync[afi][safi]); peer->sync[afi][safi] = NULL; } } diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 9521a9e912..92c37fabd2 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -212,6 +212,9 @@ static struct assegment *assegment_append_asns(struct assegment *seg, { as_t *newas; + if (!seg) + return seg; + newas = XREALLOC(MTYPE_AS_SEG_DATA, seg->as, ASSEGMENT_DATA_SIZE(seg->length + num, 1)); @@ -309,8 +312,7 @@ void aspath_free(struct aspath *aspath) return; if (aspath->segments) assegment_free_all(aspath->segments); - if (aspath->str) - XFREE(MTYPE_AS_STR, aspath->str); + XFREE(MTYPE_AS_STR, aspath->str); if (aspath->json) { json_object_free(aspath->json); @@ -620,8 +622,7 @@ static void aspath_make_str_count(struct aspath *as, bool make_json) void aspath_str_update(struct aspath *as, bool make_json) { - if (as->str) - XFREE(MTYPE_AS_STR, as->str); + XFREE(MTYPE_AS_STR, as->str); if (as->json) { json_object_free(as->json); @@ -1372,7 +1373,8 @@ static struct aspath *aspath_merge(struct aspath *as1, struct aspath *as2) while (last && last->next) last = last->next; - last->next = as2->segments; + if (last) + last->next = as2->segments; as2->segments = new; aspath_str_update(as2, false); return as2; @@ -1447,7 +1449,8 @@ struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2) * bypass the merged seg2, and attach any chain after it * to chain descending from as2's head */ - as2segtail->next = as2seghead->next; + if (as2segtail) + as2segtail->next = as2seghead->next; /* as2->segments is now referenceless and useless */ assegment_free(as2seghead); @@ -2077,14 +2080,14 @@ void aspath_print_vty(struct vty *vty, const char *format, struct aspath *as, vty_out(vty, "%s", suffix); } -static void aspath_show_all_iterator(struct hash_backet *backet, +static void aspath_show_all_iterator(struct hash_bucket *bucket, struct vty *vty) { struct aspath *as; - as = (struct aspath *)backet->data; + as = (struct aspath *)bucket->data; - vty_out(vty, "[%p:%u] (%ld) ", (void *)backet, backet->key, as->refcnt); + vty_out(vty, "[%p:%u] (%ld) ", (void *)bucket, bucket->key, as->refcnt); vty_out(vty, "%s\n", as->str); } @@ -2092,7 +2095,114 @@ static void aspath_show_all_iterator(struct hash_backet *backet, `show [ip] bgp paths' command. */ void aspath_print_all_vty(struct vty *vty) { - hash_iterate(ashash, (void (*)(struct hash_backet *, + hash_iterate(ashash, (void (*)(struct hash_bucket *, void *))aspath_show_all_iterator, vty); } + +static struct aspath *bgp_aggr_aspath_lookup(struct bgp_aggregate *aggregate, + struct aspath *aspath) +{ + return hash_lookup(aggregate->aspath_hash, aspath); +} + +static void *bgp_aggr_aspath_hash_alloc(void *p) +{ + struct aspath *ref = (struct aspath *)p; + struct aspath *aspath = NULL; + + aspath = aspath_dup(ref); + return aspath; +} + +static void bgp_aggr_aspath_prepare(struct hash_backet *hb, void *arg) +{ + struct aspath *asmerge = NULL; + struct aspath *hb_aspath = hb->data; + struct aspath **aggr_aspath = arg; + + if (*aggr_aspath) { + asmerge = aspath_aggregate(*aggr_aspath, hb_aspath); + aspath_free(*aggr_aspath); + *aggr_aspath = asmerge; + } else + *aggr_aspath = aspath_dup(hb_aspath); +} + +void bgp_aggr_aspath_remove(void *arg) +{ + struct aspath *aspath = arg; + + aspath_free(aspath); +} + +void bgp_compute_aggregate_aspath(struct bgp_aggregate *aggregate, + struct aspath *aspath) +{ + struct aspath *aggr_aspath = NULL; + + if ((aggregate == NULL) || (aspath == NULL)) + return; + + /* Create hash if not already created. + */ + if (aggregate->aspath_hash == NULL) + aggregate->aspath_hash = hash_create( + aspath_key_make, aspath_cmp, + "BGP Aggregator as-path hash"); + + aggr_aspath = bgp_aggr_aspath_lookup(aggregate, aspath); + if (aggr_aspath == NULL) { + /* Insert as-path into hash. + */ + aggr_aspath = hash_get(aggregate->aspath_hash, aspath, + bgp_aggr_aspath_hash_alloc); + + /* Compute aggregate's as-path. + */ + hash_iterate(aggregate->aspath_hash, + bgp_aggr_aspath_prepare, + &aggregate->aspath); + } + + /* Increment refernce counter. + */ + aggr_aspath->refcnt++; +} + +void bgp_remove_aspath_from_aggregate(struct bgp_aggregate *aggregate, + struct aspath *aspath) +{ + struct aspath *aggr_aspath = NULL; + struct aspath *ret_aspath = NULL; + + if ((aggregate == NULL) || (aspath == NULL)) + return; + + if (aggregate->aspath_hash == NULL) + return; + + /* Look-up the aspath in the hash. + */ + aggr_aspath = bgp_aggr_aspath_lookup(aggregate, aspath); + if (aggr_aspath) { + aggr_aspath->refcnt--; + + if (aggr_aspath->refcnt == 0) { + ret_aspath = hash_release(aggregate->aspath_hash, + aggr_aspath); + aspath_free(ret_aspath); + + /* Remove aggregate's old as-path. + */ + aspath_free(aggregate->aspath); + aggregate->aspath = NULL; + + /* Compute aggregate's as-path. + */ + hash_iterate(aggregate->aspath_hash, + bgp_aggr_aspath_prepare, + &aggregate->aspath); + } + } +} diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index 9c9c687a6b..be5725c1ae 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -22,6 +22,7 @@ #define _QUAGGA_BGP_ASPATH_H #include "lib/json.h" +#include "bgpd/bgp_route.h" /* AS path segment type. */ #define AS_SET 1 @@ -130,4 +131,10 @@ extern unsigned int aspath_has_as4(struct aspath *); /* For SNMP BGP4PATHATTRASPATHSEGMENT, might be useful for debug */ extern uint8_t *aspath_snmp_pathseg(struct aspath *, size_t *); +extern void bgp_compute_aggregate_aspath(struct bgp_aggregate *aggregate, + struct aspath *aspath); +extern void bgp_remove_aspath_from_aggregate(struct bgp_aggregate *aggregate, + struct aspath *aspath); +extern void bgp_aggr_aspath_remove(void *arg); + #endif /* _QUAGGA_BGP_ASPATH_H */ diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 03f31eddfc..226bf99d2c 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -54,6 +54,7 @@ #include "bgp_encap_types.h" #include "bgp_evpn.h" #include "bgp_flowspec_private.h" +#include "bgp_mac.h" /* Attribute strings for logging. */ static const struct message attr_str[] = { @@ -158,8 +159,7 @@ static bool cluster_hash_cmp(const void *p1, const void *p2) static void cluster_free(struct cluster_list *cluster) { - if (cluster->list) - XFREE(MTYPE_CLUSTER_VAL, cluster->list); + XFREE(MTYPE_CLUSTER_VAL, cluster->list); XFREE(MTYPE_CLUSTER, cluster); } @@ -400,8 +400,7 @@ static struct hash *transit_hash; static void transit_free(struct transit *transit) { - if (transit->val) - XFREE(MTYPE_TRANSIT_VAL, transit->val); + XFREE(MTYPE_TRANSIT_VAL, transit->val); XFREE(MTYPE_TRANSIT, transit); } @@ -592,9 +591,9 @@ static void attrhash_finish(void) attrhash = NULL; } -static void attr_show_all_iterator(struct hash_backet *backet, struct vty *vty) +static void attr_show_all_iterator(struct hash_bucket *bucket, struct vty *vty) { - struct attr *attr = backet->data; + struct attr *attr = bucket->data; vty_out(vty, "attr[%ld] nexthop %s\n", attr->refcnt, inet_ntoa(attr->nexthop)); @@ -605,7 +604,7 @@ static void attr_show_all_iterator(struct hash_backet *backet, struct vty *vty) void attr_show_all(struct vty *vty) { - hash_iterate(attrhash, (void (*)(struct hash_backet *, + hash_iterate(attrhash, (void (*)(struct hash_bucket *, void *))attr_show_all_iterator, vty); } @@ -1944,7 +1943,18 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args) bgp_attr_evpn_na_flag(attr, &attr->router_flag); /* Extract the Rmac, if any */ - bgp_attr_rmac(attr, &attr->rmac); + if (bgp_attr_rmac(attr, &attr->rmac)) { + if (bgp_debug_update(peer, NULL, NULL, 1) && + bgp_mac_exist(&attr->rmac)) { + char buf1[ETHER_ADDR_STRLEN]; + + zlog_debug("%s: router mac %s is self mac", + __func__, + prefix_mac2str(&attr->rmac, buf1, + sizeof(buf1))); + } + + } return BGP_ATTR_PARSE_PROCEED; } @@ -2227,11 +2237,12 @@ bgp_attr_pmsi_tunnel(struct bgp_attr_parser_args *args) struct attr *const attr = args->attr; const bgp_size_t length = args->length; uint8_t tnl_type; + int attr_parse_len = 2 + BGP_LABEL_BYTES; /* Verify that the receiver is expecting "ingress replication" as we * can only support that. */ - if (length < 2) { + if (length < attr_parse_len) { flog_err(EC_BGP_ATTR_LEN, "Bad PMSI tunnel attribute length %d", length); return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, @@ -2258,9 +2269,10 @@ bgp_attr_pmsi_tunnel(struct bgp_attr_parser_args *args) attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL); attr->pmsi_tnl_type = tnl_type; + stream_get(&attr->label, peer->curr, BGP_LABEL_BYTES); /* Forward read pointer of input stream. */ - stream_forward_getp(peer->curr, length - 2); + stream_forward_getp(peer->curr, length - attr_parse_len); return BGP_ATTR_PARSE_PROCEED; } @@ -3445,7 +3457,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, stream_putc(s, BGP_ATTR_PMSI_TUNNEL); stream_putc(s, 9); // Length stream_putc(s, 0); // Flags - stream_putc(s, PMSI_TNLTYPE_INGR_REPL); // IR (6) + stream_putc(s, attr->pmsi_tnl_type); stream_put(s, &(attr->label), BGP_LABEL_BYTES); // MPLS Label / VXLAN VNI stream_put_ipv4(s, attr->nexthop.s_addr); diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index 3e9d05ad97..15fa322159 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -84,8 +84,8 @@ char *esi2str(struct eth_segment_id *id) return NULL; val = id->val; - ptr = (char *)XMALLOC(MTYPE_TMP, - (ESI_LEN * 2 + ESI_LEN - 1 + 1) * sizeof(char)); + ptr = XMALLOC(MTYPE_TMP, + (ESI_LEN * 2 + ESI_LEN - 1 + 1) * sizeof(char)); snprintf(ptr, (ESI_LEN * 2 + ESI_LEN - 1 + 1), "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", val[0], @@ -106,14 +106,14 @@ char *ecom_mac2str(char *ecom_mac) } /* Fetch router-mac from extended community */ -void bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac) +bool bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac) { int i = 0; struct ecommunity *ecom; ecom = attr->ecommunity; if (!ecom || !ecom->size) - return; + return false; /* If there is a router mac extended community, set RMAC in attr */ for (i = 0; i < ecom->size; i++) { @@ -130,7 +130,9 @@ void bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac) continue; memcpy(rmac, pnt, ETH_ALEN); + return true; } + return false; } /* diff --git a/bgpd/bgp_attr_evpn.h b/bgpd/bgp_attr_evpn.h index b036702151..5b0ce1da28 100644 --- a/bgpd/bgp_attr_evpn.h +++ b/bgpd/bgp_attr_evpn.h @@ -60,7 +60,7 @@ extern void bgp_add_routermac_ecom(struct attr *attr, struct ethaddr *routermac); extern int bgp_build_evpn_prefix(int type, uint32_t eth_tag, struct prefix *dst); -extern void bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac); +extern bool bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac); extern uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky); extern uint8_t bgp_attr_default_gw(struct attr *attr); diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c index 84a00488c1..7b64f349d2 100644 --- a/bgpd/bgp_clist.c +++ b/bgpd/bgp_clist.c @@ -100,16 +100,14 @@ static void community_entry_free(struct community_entry *entry) case EXTCOMMUNITY_LIST_STANDARD: /* In case of standard extcommunity-list, configuration string is made by ecommunity_ecom2str(). */ - if (entry->config) - XFREE(MTYPE_ECOMMUNITY_STR, entry->config); + XFREE(MTYPE_ECOMMUNITY_STR, entry->config); if (entry->u.ecom) ecommunity_free(&entry->u.ecom); break; case COMMUNITY_LIST_EXPANDED: case EXTCOMMUNITY_LIST_EXPANDED: case LARGE_COMMUNITY_LIST_EXPANDED: - if (entry->config) - XFREE(MTYPE_COMMUNITY_LIST_CONFIG, entry->config); + XFREE(MTYPE_COMMUNITY_LIST_CONFIG, entry->config); if (entry->reg) bgp_regex_free(entry->reg); default: @@ -127,8 +125,7 @@ static struct community_list *community_list_new(void) /* Free community-list. */ static void community_list_free(struct community_list *list) { - if (list->name) - XFREE(MTYPE_COMMUNITY_LIST_NAME, list->name); + XFREE(MTYPE_COMMUNITY_LIST_NAME, list->name); XFREE(MTYPE_COMMUNITY_LIST, list); } diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c index 614e24ca4f..67cd2be214 100644 --- a/bgpd/bgp_community.c +++ b/bgpd/bgp_community.c @@ -34,17 +34,14 @@ static struct hash *comhash; /* Allocate a new communities value. */ static struct community *community_new(void) { - return (struct community *)XCALLOC(MTYPE_COMMUNITY, - sizeof(struct community)); + return XCALLOC(MTYPE_COMMUNITY, sizeof(struct community)); } /* Free communities value. */ void community_free(struct community **com) { - if ((*com)->val) - XFREE(MTYPE_COMMUNITY_VAL, (*com)->val); - if ((*com)->str) - XFREE(MTYPE_COMMUNITY_STR, (*com)->str); + XFREE(MTYPE_COMMUNITY_VAL, (*com)->val); + XFREE(MTYPE_COMMUNITY_STR, (*com)->str); if ((*com)->json) { json_object_free((*com)->json); @@ -910,3 +907,112 @@ void community_finish(void) hash_free(comhash); comhash = NULL; } + +static struct community *bgp_aggr_community_lookup( + struct bgp_aggregate *aggregate, + struct community *community) +{ + return hash_lookup(aggregate->community_hash, community); +} + +static void *bgp_aggr_communty_hash_alloc(void *p) +{ + struct community *ref = (struct community *)p; + struct community *community = NULL; + + community = community_dup(ref); + return community; +} + +static void bgp_aggr_community_prepare(struct hash_backet *hb, void *arg) +{ + struct community *commerge = NULL; + struct community *hb_community = hb->data; + struct community **aggr_community = arg; + + if (*aggr_community) { + commerge = community_merge(*aggr_community, hb_community); + *aggr_community = community_uniq_sort(commerge); + community_free(&commerge); + } else + *aggr_community = community_dup(hb_community); +} + +void bgp_aggr_community_remove(void *arg) +{ + struct community *community = arg; + + community_free(&community); +} + +void bgp_compute_aggregate_community(struct bgp_aggregate *aggregate, + struct community *community) +{ + struct community *aggr_community = NULL; + + if ((aggregate == NULL) || (community == NULL)) + return; + + /* Create hash if not already created. + */ + if (aggregate->community_hash == NULL) + aggregate->community_hash = hash_create( + (unsigned int (*)(void *))community_hash_make, + (bool (*)(const void *, const void *))community_cmp, + "BGP Aggregator community hash"); + + aggr_community = bgp_aggr_community_lookup(aggregate, community); + if (aggr_community == NULL) { + /* Insert community into hash. + */ + aggr_community = hash_get(aggregate->community_hash, community, + bgp_aggr_communty_hash_alloc); + + /* Re-compute aggregate's community. + */ + if (aggregate->community) + community_free(&aggregate->community); + + hash_iterate(aggregate->community_hash, + bgp_aggr_community_prepare, + &aggregate->community); + } + + /* Increment refernce counter. + */ + aggr_community->refcnt++; +} + +void bgp_remove_community_from_aggregate(struct bgp_aggregate *aggregate, + struct community *community) +{ + struct community *aggr_community = NULL; + struct community *ret_comm = NULL; + + if ((aggregate == NULL) || (community == NULL)) + return; + + if (aggregate->community_hash == NULL) + return; + + /* Look-up the community in the hash. + */ + aggr_community = bgp_aggr_community_lookup(aggregate, community); + if (aggr_community) { + aggr_community->refcnt--; + + if (aggr_community->refcnt == 0) { + ret_comm = hash_release(aggregate->community_hash, + aggr_community); + community_free(&ret_comm); + + community_free(&aggregate->community); + + /* Compute aggregate's community. + */ + hash_iterate(aggregate->community_hash, + bgp_aggr_community_prepare, + &aggregate->community); + } + } +} diff --git a/bgpd/bgp_community.h b/bgpd/bgp_community.h index e1545249d7..4ff4d214a5 100644 --- a/bgpd/bgp_community.h +++ b/bgpd/bgp_community.h @@ -22,6 +22,7 @@ #define _QUAGGA_BGP_COMMUNITY_H #include "lib/json.h" +#include "bgpd/bgp_route.h" /* Communities attribute. */ struct community { @@ -89,5 +90,10 @@ extern void community_del_val(struct community *, uint32_t *); extern unsigned long community_count(void); extern struct hash *community_hash(void); extern uint32_t community_val_get(struct community *com, int i); +extern void bgp_compute_aggregate_community(struct bgp_aggregate *aggregate, + struct community *community); +extern void bgp_remove_community_from_aggregate(struct bgp_aggregate *aggregate, + struct community *community); +extern void bgp_aggr_community_remove(void *arg); #endif /* _QUAGGA_BGP_COMMUNITY_H */ diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index ed0900a721..8ef398952d 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -48,8 +48,7 @@ static struct hash *ecomhash; /* Allocate a new ecommunities. */ struct ecommunity *ecommunity_new(void) { - return (struct ecommunity *)XCALLOC(MTYPE_ECOMMUNITY, - sizeof(struct ecommunity)); + return XCALLOC(MTYPE_ECOMMUNITY, sizeof(struct ecommunity)); } void ecommunity_strfree(char **s) @@ -60,10 +59,8 @@ void ecommunity_strfree(char **s) /* Allocate ecommunities. */ void ecommunity_free(struct ecommunity **ecom) { - if ((*ecom)->val) - XFREE(MTYPE_ECOMMUNITY_VAL, (*ecom)->val); - if ((*ecom)->str) - XFREE(MTYPE_ECOMMUNITY_STR, (*ecom)->str); + XFREE(MTYPE_ECOMMUNITY_VAL, (*ecom)->val); + XFREE(MTYPE_ECOMMUNITY_STR, (*ecom)->str); XFREE(MTYPE_ECOMMUNITY, *ecom); } @@ -1026,3 +1023,112 @@ int ecommunity_fill_pbr_action(struct ecommunity_val *ecom_eval, return -1; return 0; } + +static struct ecommunity *bgp_aggr_ecommunity_lookup( + struct bgp_aggregate *aggregate, + struct ecommunity *ecommunity) +{ + return hash_lookup(aggregate->ecommunity_hash, ecommunity); +} + +static void *bgp_aggr_ecommunty_hash_alloc(void *p) +{ + struct ecommunity *ref = (struct ecommunity *)p; + struct ecommunity *ecommunity = NULL; + + ecommunity = ecommunity_dup(ref); + return ecommunity; +} + +static void bgp_aggr_ecommunity_prepare(struct hash_backet *hb, void *arg) +{ + struct ecommunity *ecommerge = NULL; + struct ecommunity *hb_ecommunity = hb->data; + struct ecommunity **aggr_ecommunity = arg; + + if (*aggr_ecommunity) { + ecommerge = ecommunity_merge(*aggr_ecommunity, hb_ecommunity); + *aggr_ecommunity = ecommunity_uniq_sort(ecommerge); + ecommunity_free(&ecommerge); + } else + *aggr_ecommunity = ecommunity_dup(hb_ecommunity); +} + +void bgp_aggr_ecommunity_remove(void *arg) +{ + struct ecommunity *ecommunity = arg; + + ecommunity_free(&ecommunity); +} + +void bgp_compute_aggregate_ecommunity(struct bgp_aggregate *aggregate, + struct ecommunity *ecommunity) +{ + struct ecommunity *aggr_ecommunity = NULL; + + if ((aggregate == NULL) || (ecommunity == NULL)) + return; + + /* Create hash if not already created. + */ + if (aggregate->ecommunity_hash == NULL) + aggregate->ecommunity_hash = hash_create( + ecommunity_hash_make, ecommunity_cmp, + "BGP Aggregator ecommunity hash"); + + aggr_ecommunity = bgp_aggr_ecommunity_lookup(aggregate, ecommunity); + if (aggr_ecommunity == NULL) { + /* Insert ecommunity into hash. + */ + aggr_ecommunity = hash_get(aggregate->ecommunity_hash, + ecommunity, + bgp_aggr_ecommunty_hash_alloc); + + /* Re-compute aggregate's ecommunity. + */ + if (aggregate->ecommunity) + ecommunity_free(&aggregate->ecommunity); + + hash_iterate(aggregate->ecommunity_hash, + bgp_aggr_ecommunity_prepare, + &aggregate->ecommunity); + } + + /* Increment refernce counter. + */ + aggr_ecommunity->refcnt++; +} + +void bgp_remove_ecommunity_from_aggregate(struct bgp_aggregate *aggregate, + struct ecommunity *ecommunity) +{ + struct ecommunity *aggr_ecommunity = NULL; + struct ecommunity *ret_ecomm = NULL; + + if ((aggregate == NULL) || (ecommunity == NULL)) + return; + + if (aggregate->ecommunity_hash == NULL) + return; + + /* Look-up the ecommunity in the hash. + */ + aggr_ecommunity = bgp_aggr_ecommunity_lookup(aggregate, ecommunity); + if (aggr_ecommunity) { + aggr_ecommunity->refcnt--; + + if (aggr_ecommunity->refcnt == 0) { + ret_ecomm = hash_release(aggregate->ecommunity_hash, + aggr_ecommunity); + ecommunity_free(&ret_ecomm); + + ecommunity_free(&aggregate->ecommunity); + + /* Compute aggregate's ecommunity. + */ + hash_iterate(aggregate->ecommunity_hash, + bgp_aggr_ecommunity_prepare, + &aggregate->ecommunity); + } + } +} diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index 519991da5a..62b2137753 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -21,6 +21,8 @@ #ifndef _QUAGGA_BGP_ECOMMUNITY_H #define _QUAGGA_BGP_ECOMMUNITY_H +#include "bgpd/bgp_route.h" + /* High-order octet of the Extended Communities type field. */ #define ECOMMUNITY_ENCODE_AS 0x00 #define ECOMMUNITY_ENCODE_IP 0x01 @@ -184,4 +186,12 @@ struct bgp_pbr_entry_action; extern int ecommunity_fill_pbr_action(struct ecommunity_val *ecom_eval, struct bgp_pbr_entry_action *api); +extern void bgp_compute_aggregate_ecommunity( + struct bgp_aggregate *aggregate, + struct ecommunity *ecommunity); +extern void bgp_remove_ecommunity_from_aggregate( + struct bgp_aggregate *aggregate, + struct ecommunity *ecommunity); +extern void bgp_aggr_ecommunity_remove(void *arg); + #endif /* _QUAGGA_BGP_ECOMMUNITY_H */ diff --git a/bgpd/bgp_encap_tlv.c b/bgpd/bgp_encap_tlv.c index 30a08098e8..964adec9b6 100644 --- a/bgpd/bgp_encap_tlv.c +++ b/bgpd/bgp_encap_tlv.c @@ -401,8 +401,7 @@ void bgp_encap_type_vxlan_to_tlv( if (bet == NULL || !bet->vnid) return; - if (attr->encap_subtlvs) - XFREE(MTYPE_ENCAP_TLV, attr->encap_subtlvs); + XFREE(MTYPE_ENCAP_TLV, attr->encap_subtlvs); tlv = XCALLOC(MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv) + 12); tlv->type = 1; /* encapsulation type */ diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 5a67cc4209..3a61c0cd74 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -48,6 +48,7 @@ #include "bgpd/bgp_zebra.h" #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_addpath.h" +#include "bgpd/bgp_mac.h" /* * Definitions and external declarations. @@ -184,8 +185,6 @@ static struct vrf_irt_node *vrf_import_rt_new(struct ecommunity_val *rt) irt = XCALLOC(MTYPE_BGP_EVPN_VRF_IMPORT_RT, sizeof(struct vrf_irt_node)); - if (!irt) - return NULL; irt->rt = *rt; irt->vrfs = list_new(); @@ -296,8 +295,6 @@ static struct irt_node *import_rt_new(struct bgp *bgp, return NULL; irt = XCALLOC(MTYPE_BGP_EVPN_IMPORT_RT, sizeof(struct irt_node)); - if (!irt) - return NULL; irt->rt = *rt; irt->vnis = list_new(); @@ -968,8 +965,6 @@ static struct in_addr *es_vtep_new(struct in_addr vtep) struct in_addr *ip; ip = XCALLOC(MTYPE_BGP_EVPN_ES_VTEP, sizeof(struct in_addr)); - if (!ip) - return NULL; ip->s_addr = vtep.s_addr; return ip; @@ -1769,8 +1764,10 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, ZEBRA_MACIP_TYPE_ROUTER_FLAG) ? 1 : 0; /* PMSI is only needed for type-3 routes */ - if (p->prefix.route_type == BGP_EVPN_IMET_ROUTE) + if (p->prefix.route_type == BGP_EVPN_IMET_ROUTE) { attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL); + attr.pmsi_tnl_type = PMSI_TNLTYPE_INGR_REPL; + } /* router mac is only needed for type-2 routes here. */ if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) @@ -2506,6 +2503,9 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, /* Perform route selection and update zebra, if required. */ bgp_process(bgp_vrf, rn, afi, safi); + /* Process for route leaking. */ + vpn_leak_from_vrf_update(bgp_get_default(), bgp_vrf, pi); + return ret; } @@ -2671,6 +2671,9 @@ static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, if (!pi) return 0; + /* Process for route leaking. */ + vpn_leak_from_vrf_withdraw(bgp_get_default(), bgp_vrf, pi); + bgp_aggregate_decrement(bgp_vrf, &rn->p, pi, afi, safi); /* Mark entry for deletion */ @@ -2943,6 +2946,41 @@ static int install_uninstall_routes_for_es(struct bgp *bgp, return 0; } +/* This API will scan evpn routes for checking attribute's rmac + * macthes with bgp instance router mac. It avoid installing + * route into bgp vrf table and remote rmac in bridge table. + */ +static int bgp_evpn_route_rmac_self_check(struct bgp *bgp_vrf, + struct prefix_evpn *evp, + struct bgp_path_info *pi) +{ + /* evpn route could have learnt prior to L3vni has come up, + * perform rmac check before installing route and + * remote router mac. + * The route will be removed from global bgp table once + * SVI comes up with MAC and stored in hash, triggers + * bgp_mac_rescan_all_evpn_tables. + */ + if (pi->attr && + memcmp(&bgp_vrf->rmac, &pi->attr->rmac, ETH_ALEN) == 0) { + if (bgp_debug_update(pi->peer, NULL, NULL, 1)) { + char buf1[PREFIX_STRLEN]; + char attr_str[BUFSIZ] = {0}; + + bgp_dump_attr(pi->attr, attr_str, BUFSIZ); + + zlog_debug("%s: bgp %u prefix %s with attr %s - DENIED due to self mac", + __func__, bgp_vrf->vrf_id, + prefix2str(evp, buf1, sizeof(buf1)), + attr_str); + } + + return 1; + } + + return 0; +} + /* * Install or uninstall mac-ip routes are appropriate for this * particular VRF. @@ -2999,6 +3037,10 @@ static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, int install) continue; if (is_route_matching_for_vrf(bgp_vrf, pi)) { + if (bgp_evpn_route_rmac_self_check( + bgp_vrf, evp, pi)) + continue; + if (install) ret = install_evpn_route_entry_in_vrf( bgp_vrf, evp, pi); @@ -3602,9 +3644,9 @@ static int delete_withdraw_vni_routes(struct bgp *bgp, struct bgpevpn *vpn) * router-id. The routes in the per-VNI table are used to create routes in * the global table and schedule them. */ -static void update_router_id_vni(struct hash_backet *backet, struct bgp *bgp) +static void update_router_id_vni(struct hash_bucket *bucket, struct bgp *bgp) { - struct bgpevpn *vpn = (struct bgpevpn *)backet->data; + struct bgpevpn *vpn = (struct bgpevpn *)bucket->data; /* Skip VNIs with configured RD. */ if (is_rd_configured(vpn)) @@ -3620,9 +3662,9 @@ static void update_router_id_vni(struct hash_backet *backet, struct bgp *bgp) * the router-id and is done only on the global route table, the routes * are needed in the per-VNI table to re-advertise with new router id. */ -static void withdraw_router_id_vni(struct hash_backet *backet, struct bgp *bgp) +static void withdraw_router_id_vni(struct hash_bucket *bucket, struct bgp *bgp) { - struct bgpevpn *vpn = (struct bgpevpn *)backet->data; + struct bgpevpn *vpn = (struct bgpevpn *)bucket->data; /* Skip VNIs with configured RD. */ if (is_rd_configured(vpn)) @@ -3635,9 +3677,9 @@ static void withdraw_router_id_vni(struct hash_backet *backet, struct bgp *bgp) * Create RT-3 for a VNI and schedule for processing and advertisement. * This is invoked upon flooding mode changing to head-end replication. */ -static void create_advertise_type3(struct hash_backet *backet, void *data) +static void create_advertise_type3(struct hash_bucket *bucket, void *data) { - struct bgpevpn *vpn = backet->data; + struct bgpevpn *vpn = bucket->data; struct bgp *bgp = data; struct prefix_evpn p; @@ -3654,9 +3696,9 @@ static void create_advertise_type3(struct hash_backet *backet, void *data) * Delete RT-3 for a VNI and schedule for processing and withdrawal. * This is invoked upon flooding mode changing to drop BUM packets. */ -static void delete_withdraw_type3(struct hash_backet *backet, void *data) +static void delete_withdraw_type3(struct hash_bucket *bucket, void *data) { - struct bgpevpn *vpn = backet->data; + struct bgpevpn *vpn = bucket->data; struct bgp *bgp = data; struct prefix_evpn p; @@ -3933,7 +3975,7 @@ static int process_type4_route(struct peer *peer, afi_t afi, safi_t safi, */ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi, struct attr *attr, uint8_t *pfx, int psize, - uint32_t addpath_id, int withdraw) + uint32_t addpath_id) { struct prefix_rd prd; struct prefix_evpn p; @@ -4019,7 +4061,7 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi, */ /* Process the route. */ - if (!withdraw) + if (attr) ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, &label, 1, 0, &evpn); @@ -4086,9 +4128,9 @@ static void evpn_mpattr_encode_type5(struct stream *s, struct prefix *p, /* * Cleanup specific VNI upon EVPN (advertise-all-vni) being disabled. */ -static void cleanup_vni_on_disable(struct hash_backet *backet, struct bgp *bgp) +static void cleanup_vni_on_disable(struct hash_bucket *bucket, struct bgp *bgp) { - struct bgpevpn *vpn = (struct bgpevpn *)backet->data; + struct bgpevpn *vpn = (struct bgpevpn *)bucket->data; /* Remove EVPN routes and schedule for processing. */ delete_routes_for_vni(bgp, vpn); @@ -4102,9 +4144,9 @@ static void cleanup_vni_on_disable(struct hash_backet *backet, struct bgp *bgp) /* * Free a VNI entry; iterator function called during cleanup. */ -static void free_vni_entry(struct hash_backet *backet, struct bgp *bgp) +static void free_vni_entry(struct hash_bucket *bucket, struct bgp *bgp) { - struct bgpevpn *vpn = (struct bgpevpn *)backet->data; + struct bgpevpn *vpn = (struct bgpevpn *)bucket->data; delete_all_vni_routes(bgp, vpn); bgp_evpn_free(bgp, vpn); @@ -4173,9 +4215,9 @@ static void bgp_evpn_handle_export_rt_change_for_vrf(struct bgp *bgp_vrf) /* * Handle autort change for a given VNI. */ -static void update_autort_vni(struct hash_backet *backet, struct bgp *bgp) +static void update_autort_vni(struct hash_bucket *bucket, struct bgp *bgp) { - struct bgpevpn *vpn = backet->data; + struct bgpevpn *vpn = bucket->data; if (!is_import_rt_configured(vpn)) { if (is_vni_live(vpn)) @@ -4226,11 +4268,13 @@ void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf, afi_t afi, safi_t safi) table = bgp_vrf->rib[afi][safi]; for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { - /* Only care about "selected" routes - non-imported. */ + /* Only care about "selected" routes. Also ensure that + * these are routes that are injectable into EVPN. + */ /* TODO: Support for AddPath for EVPN. */ for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) { if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED) - && (!pi->extra || !pi->extra->parent)) { + && is_route_injectable_into_evpn(pi)) { bgp_evpn_withdraw_type5_route(bgp_vrf, &rn->p, afi, safi); break; @@ -4297,12 +4341,13 @@ void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi, table = bgp_vrf->rib[afi][safi]; for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { /* Need to identify the "selected" route entry to use its - * attribute. Also, we only consider "non-imported" routes. + * attribute. Also, ensure that the route is injectable + * into EVPN. * TODO: Support for AddPath for EVPN. */ for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) { if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED) - && (!pi->extra || !pi->extra->parent)) { + && is_route_injectable_into_evpn(pi)) { /* apply the route-map */ if (bgp_vrf->adv_cmd_rmap[afi][safi].map) { @@ -4481,7 +4526,7 @@ void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw) * L2-VNIs */ hash_iterate(bgp->vnihash, - (void (*)(struct hash_backet *, + (void (*)(struct hash_bucket *, void *))withdraw_router_id_vni, bgp); } else { @@ -4495,7 +4540,7 @@ void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw) * new RD */ hash_iterate(bgp->vnihash, - (void (*)(struct hash_backet *, + (void (*)(struct hash_bucket *, void *))update_router_id_vni, bgp); } @@ -4507,7 +4552,7 @@ void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw) void bgp_evpn_handle_autort_change(struct bgp *bgp) { hash_iterate(bgp->vnihash, - (void (*)(struct hash_backet *, + (void (*)(struct hash_bucket *, void*))update_autort_vni, bgp); } @@ -4871,8 +4916,9 @@ int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr, break; case BGP_EVPN_IP_PREFIX_ROUTE: - if (process_type5_route(peer, afi, safi, attr, pnt, - psize, addpath_id, withdraw)) { + if (process_type5_route(peer, afi, safi, + withdraw ? NULL : attr, pnt, + psize, addpath_id)) { flog_err( EC_BGP_PKT_PROCESS, "%u:%s - Error in processing EVPN type-5 NLRI size %d", @@ -5035,6 +5081,9 @@ void bgp_evpn_derive_auto_rt_export(struct bgp *bgp, struct bgpevpn *vpn) */ void bgp_evpn_derive_auto_rd_for_vrf(struct bgp *bgp) { + if (is_vrf_rd_configured(bgp)) + return; + form_auto_rd(bgp->router_id, bgp->vrf_rd_id, &bgp->vrf_prd); } @@ -5097,8 +5146,6 @@ struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni, return NULL; vpn = XCALLOC(MTYPE_BGP_EVPN, sizeof(struct bgpevpn)); - if (!vpn) - return NULL; /* Set values - RD and RT set to defaults. */ vpn->vni = vni; @@ -5178,8 +5225,6 @@ struct evpnes *bgp_evpn_es_new(struct bgp *bgp, return NULL; es = XCALLOC(MTYPE_BGP_EVPN_ES, sizeof(struct evpnes)); - if (!es) - return NULL; /* set the ESI and originator_ip */ memcpy(&es->esi, esi, sizeof(esi_t)); @@ -5380,10 +5425,10 @@ int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, struct ethaddr *mac, return 0; } -static void link_l2vni_hash_to_l3vni(struct hash_backet *backet, +static void link_l2vni_hash_to_l3vni(struct hash_bucket *bucket, struct bgp *bgp_vrf) { - struct bgpevpn *vpn = (struct bgpevpn *)backet->data; + struct bgpevpn *vpn = (struct bgpevpn *)bucket->data; struct bgp *bgp_def = NULL; bgp_def = bgp_get_default(); @@ -5394,7 +5439,8 @@ static void link_l2vni_hash_to_l3vni(struct hash_backet *backet, } int bgp_evpn_local_l3vni_add(vni_t l3vni, vrf_id_t vrf_id, struct ethaddr *rmac, - struct in_addr originator_ip, int filter) + struct in_addr originator_ip, int filter, + ifindex_t svi_ifindex) { struct bgp *bgp_vrf = NULL; /* bgp VRF instance */ struct bgp *bgp_def = NULL; /* default bgp instance */ @@ -5442,14 +5488,11 @@ int bgp_evpn_local_l3vni_add(vni_t l3vni, vrf_id_t vrf_id, struct ethaddr *rmac, SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_AUTO); } - /* associate with l3vni */ + /* associate the vrf with l3vni and related parameters */ bgp_vrf->l3vni = l3vni; - - /* set the router mac - to be used in mac-ip routes for this vrf */ memcpy(&bgp_vrf->rmac, rmac, sizeof(struct ethaddr)); - - /* set the originator ip */ bgp_vrf->originator_ip = originator_ip; + bgp_vrf->l3vni_svi_ifindex = svi_ifindex; /* set the right filter - are we using l3vni only for prefix routes? */ if (filter) @@ -5469,7 +5512,7 @@ int bgp_evpn_local_l3vni_add(vni_t l3vni, vrf_id_t vrf_id, struct ethaddr *rmac, /* link all corresponding l2vnis */ hash_iterate(bgp_def->vnihash, - (void (*)(struct hash_backet *, + (void (*)(struct hash_bucket *, void *))link_l2vni_hash_to_l3vni, bgp_vrf); @@ -5802,7 +5845,7 @@ void bgp_evpn_flood_control_change(struct bgp *bgp) */ void bgp_evpn_cleanup_on_disable(struct bgp *bgp) { - hash_iterate(bgp->vnihash, (void (*)(struct hash_backet *, + hash_iterate(bgp->vnihash, (void (*)(struct hash_bucket *, void *))cleanup_vni_on_disable, bgp); } @@ -5814,7 +5857,7 @@ void bgp_evpn_cleanup_on_disable(struct bgp *bgp) void bgp_evpn_cleanup(struct bgp *bgp) { hash_iterate(bgp->vnihash, - (void (*)(struct hash_backet *, void *))free_vni_entry, + (void (*)(struct hash_bucket *, void *))free_vni_entry, bgp); hash_free(bgp->import_rt_hash); diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index 5c3d4ce3aa..22fb0939c9 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -88,8 +88,13 @@ static inline int is_route_parent_evpn(struct bgp_path_info *ri) !ri->extra->parent) return 0; - /* See if the parent is of family L2VPN/EVPN */ - parent_ri = (struct bgp_path_info *)ri->extra->parent; + /* Determine parent recursively */ + for (parent_ri = ri->extra->parent; + parent_ri->extra && parent_ri->extra->parent; + parent_ri = parent_ri->extra->parent) + ; + + /* See if of family L2VPN/EVPN */ rn = parent_ri->net; if (!rn) return 0; @@ -101,6 +106,38 @@ static inline int is_route_parent_evpn(struct bgp_path_info *ri) return 0; } +/* Flag if the route path's family is EVPN. */ +static inline bool is_pi_family_evpn(struct bgp_path_info *pi) +{ + return is_pi_family_matching(pi, AFI_L2VPN, SAFI_EVPN); +} + +/* Flag if the route is injectable into EVPN. This would be either a + * non-imported route or a non-EVPN imported route. + */ +static inline bool is_route_injectable_into_evpn(struct bgp_path_info *pi) +{ + struct bgp_path_info *parent_pi; + struct bgp_table *table; + struct bgp_node *rn; + + if (pi->sub_type != BGP_ROUTE_IMPORTED || + !pi->extra || + !pi->extra->parent) + return true; + + parent_pi = (struct bgp_path_info *)pi->extra->parent; + rn = parent_pi->net; + if (!rn) + return true; + table = bgp_node_table(rn); + if (table && + table->afi == AFI_L2VPN && + table->safi == SAFI_EVPN) + return false; + return true; +} + extern void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, struct prefix *p, struct attr *src_attr, afi_t afi, @@ -136,7 +173,8 @@ extern int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, uint8_t flags, uint32_t seq); extern int bgp_evpn_local_l3vni_add(vni_t vni, vrf_id_t vrf_id, struct ethaddr *rmac, - struct in_addr originator_ip, int filter); + struct in_addr originator_ip, int filter, + ifindex_t svi_ifindex); extern int bgp_evpn_local_l3vni_del(vni_t vni, vrf_id_t vrf_id); extern int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni); extern int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni, diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index a3d8b8a647..ba72761003 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -149,11 +149,11 @@ static void display_vrf_import_rt(struct vty *vty, struct vrf_irt_node *irt, } } -static void show_vrf_import_rt_entry(struct hash_backet *backet, void *args[]) +static void show_vrf_import_rt_entry(struct hash_bucket *bucket, void *args[]) { json_object *json = NULL; struct vty *vty = NULL; - struct vrf_irt_node *irt = (struct vrf_irt_node *)backet->data; + struct vrf_irt_node *irt = (struct vrf_irt_node *)bucket->data; vty = (struct vty *)args[0]; json = (struct json_object *)args[1]; @@ -256,11 +256,11 @@ static void display_import_rt(struct vty *vty, struct irt_node *irt, } } -static void show_import_rt_entry(struct hash_backet *backet, void *args[]) +static void show_import_rt_entry(struct hash_bucket *bucket, void *args[]) { json_object *json = NULL; struct vty *vty = NULL; - struct irt_node *irt = (struct irt_node *)backet->data; + struct irt_node *irt = (struct irt_node *)bucket->data; vty = args[0]; json = args[1]; @@ -709,9 +709,9 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type, } } -static void show_vni_routes_hash(struct hash_backet *backet, void *arg) +static void show_vni_routes_hash(struct hash_bucket *bucket, void *arg) { - struct bgpevpn *vpn = (struct bgpevpn *)backet->data; + struct bgpevpn *vpn = (struct bgpevpn *)bucket->data; struct vni_walk_ctx *wctx = arg; struct vty *vty = wctx->vty; json_object *json = wctx->json; @@ -835,7 +835,7 @@ static void show_l3vni_entry(struct vty *vty, struct bgp *bgp, } } -static void show_es_entry(struct hash_backet *backet, void *args[]) +static void show_es_entry(struct hash_bucket *bucket, void *args[]) { char buf[ESI_STR_LEN]; char buf1[RD_ADDRSTRLEN]; @@ -845,7 +845,7 @@ static void show_es_entry(struct hash_backet *backet, void *args[]) json_object *json = args[1]; json_object *json_vteps = NULL; struct listnode *node = NULL; - struct evpnes *es = (struct evpnes *)backet->data; + struct evpnes *es = (struct evpnes *)bucket->data; if (json) { json_vteps = json_object_new_array(); @@ -877,14 +877,14 @@ static void show_es_entry(struct hash_backet *backet, void *args[]) } } -static void show_vni_entry(struct hash_backet *backet, void *args[]) +static void show_vni_entry(struct hash_bucket *bucket, void *args[]) { struct vty *vty; json_object *json; json_object *json_vni = NULL; json_object *json_import_rtl = NULL; json_object *json_export_rtl = NULL; - struct bgpevpn *vpn = (struct bgpevpn *)backet->data; + struct bgpevpn *vpn = (struct bgpevpn *)bucket->data; char buf1[10]; char buf2[RD_ADDRSTRLEN]; char rt_buf[25]; @@ -1969,7 +1969,7 @@ static void evpn_show_vrf_import_rts(struct vty *vty, struct bgp *bgp_def, args[1] = json; hash_iterate(bgp_def->vrf_import_rt_hash, - (void (*)(struct hash_backet *, + (void (*)(struct hash_bucket *, void *))show_vrf_import_rt_entry, args); } @@ -1987,7 +1987,7 @@ static void evpn_show_import_rts(struct vty *vty, struct bgp *bgp, hash_iterate( bgp->import_rt_hash, - (void (*)(struct hash_backet *, void *))show_import_rt_entry, + (void (*)(struct hash_bucket *, void *))show_import_rt_entry, args); } @@ -2008,7 +2008,7 @@ static void evpn_show_routes_vni_all(struct vty *vty, struct bgp *bgp, wctx.vty = vty; wctx.vtep_ip = vtep_ip; wctx.json = json; - hash_iterate(bgp->vnihash, (void (*)(struct hash_backet *, + hash_iterate(bgp->vnihash, (void (*)(struct hash_bucket *, void *))show_vni_routes_hash, &wctx); } @@ -2552,7 +2552,7 @@ static void evpn_show_all_es(struct vty *vty, struct bgp *bgp, args[0] = vty; args[1] = json; hash_iterate(bgp->esihash, - (void (*)(struct hash_backet *, void *))show_es_entry, + (void (*)(struct hash_bucket *, void *))show_es_entry, args); } @@ -2612,7 +2612,7 @@ static void evpn_show_all_vnis(struct vty *vty, struct bgp *bgp, args[0] = vty; args[1] = json; hash_iterate(bgp->vnihash, - (void (*)(struct hash_backet *, void *))show_vni_entry, + (void (*)(struct hash_bucket *, void *))show_vni_entry, args); /* print all L3 VNIs */ @@ -3358,7 +3358,8 @@ DEFUN (bgp_evpn_advertise_type5, } /* advertise type-5 routes */ - bgp_evpn_advertise_type5_routes(bgp_vrf, afi, safi); + if (advertise_type5_routes(bgp_vrf, afi)) + bgp_evpn_advertise_type5_routes(bgp_vrf, afi, safi); return CMD_SUCCESS; } @@ -5211,7 +5212,7 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi, vty_out(vty, " default-originate ipv6\n"); if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_RD_CFGD)) - vty_out(vty, " rd %s\n", + vty_out(vty, " rd %s\n", prefix_rd2str(&bgp->vrf_prd, buf1, sizeof(buf1))); /* import route-target */ diff --git a/bgpd/bgp_filter.c b/bgpd/bgp_filter.c index 1ccb8fb245..80cfb97436 100644 --- a/bgpd/bgp_filter.c +++ b/bgpd/bgp_filter.c @@ -95,8 +95,7 @@ static void as_filter_free(struct as_filter *asfilter) { if (asfilter->reg) bgp_regex_free(asfilter->reg); - if (asfilter->reg_str) - XFREE(MTYPE_AS_FILTER_STR, asfilter->reg_str); + XFREE(MTYPE_AS_FILTER_STR, asfilter->reg_str); XFREE(MTYPE_AS_FILTER, asfilter); } @@ -338,8 +337,7 @@ static void as_list_filter_delete(struct as_list *aslist, /* Run hook function. */ if (as_list_master.delete_hook) (*as_list_master.delete_hook)(name); - if (name) - XFREE(MTYPE_AS_STR, name); + XFREE(MTYPE_AS_STR, name); } static int as_filter_match(struct as_filter *asfilter, struct aspath *aspath) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index b70c8bbd63..447d8da613 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -310,7 +310,8 @@ void bgp_timer_set(struct peer *peer) status start timer is on unless peer is shutdown or peer is inactive. All other timer must be turned off */ if (BGP_PEER_START_SUPPRESSED(peer) || !peer_active(peer) - || peer->bgp->vrf_id == VRF_UNKNOWN) { + || (peer->bgp->inst_type != BGP_INSTANCE_TYPE_VIEW && + peer->bgp->vrf_id == VRF_UNKNOWN)) { BGP_TIMER_OFF(peer->t_start); } else { BGP_TIMER_ON(peer->t_start, bgp_start_timer, @@ -1422,7 +1423,8 @@ int bgp_start(struct peer *peer) return 0; } - if (peer->bgp->vrf_id == VRF_UNKNOWN) { + if (peer->bgp->inst_type != BGP_INSTANCE_TYPE_VIEW && + peer->bgp->vrf_id == VRF_UNKNOWN) { if (bgp_debug_neighbor_events(peer)) flog_err( EC_BGP_FSM, diff --git a/bgpd/bgp_keepalives.c b/bgpd/bgp_keepalives.c index 910c8a7372..c2f0baff76 100644 --- a/bgpd/bgp_keepalives.c +++ b/bgpd/bgp_keepalives.c @@ -85,7 +85,7 @@ static void pkat_del(void *pkat) * * @return maximum time to wait until next update (0 if infinity) */ -static void peer_process(struct hash_backet *hb, void *arg) +static void peer_process(struct hash_bucket *hb, void *arg) { struct pkat *pkat = hb->data; diff --git a/bgpd/bgp_labelpool.c b/bgpd/bgp_labelpool.c index 181f864575..69dd0f9dac 100644 --- a/bgpd/bgp_labelpool.c +++ b/bgpd/bgp_labelpool.c @@ -180,14 +180,12 @@ static void lp_cbq_item_free(struct work_queue *wq, void *data) static void lp_lcb_free(void *goner) { - if (goner) - XFREE(MTYPE_BGP_LABEL_CB, goner); + XFREE(MTYPE_BGP_LABEL_CB, goner); } static void lp_chunk_free(void *goner) { - if (goner) - XFREE(MTYPE_BGP_LABEL_CHUNK, goner); + XFREE(MTYPE_BGP_LABEL_CHUNK, goner); } void bgp_lp_init(struct thread_master *master, struct labelpool *pool) diff --git a/bgpd/bgp_lcommunity.c b/bgpd/bgp_lcommunity.c index cfc9af7777..44766c9b6e 100644 --- a/bgpd/bgp_lcommunity.c +++ b/bgpd/bgp_lcommunity.c @@ -38,17 +38,14 @@ static struct hash *lcomhash; /* Allocate a new lcommunities. */ static struct lcommunity *lcommunity_new(void) { - return (struct lcommunity *)XCALLOC(MTYPE_LCOMMUNITY, - sizeof(struct lcommunity)); + return XCALLOC(MTYPE_LCOMMUNITY, sizeof(struct lcommunity)); } /* Allocate lcommunities. */ void lcommunity_free(struct lcommunity **lcom) { - if ((*lcom)->val) - XFREE(MTYPE_LCOMMUNITY_VAL, (*lcom)->val); - if ((*lcom)->str) - XFREE(MTYPE_LCOMMUNITY_STR, (*lcom)->str); + XFREE(MTYPE_LCOMMUNITY_VAL, (*lcom)->val); + XFREE(MTYPE_LCOMMUNITY_STR, (*lcom)->str); XFREE(MTYPE_LCOMMUNITY, *lcom); } @@ -180,7 +177,7 @@ static void set_lcommunity_string(struct lcommunity *lcom, bool make_json) { int i; int len; - bool first = 1; + bool first = true; char *str_buf; char *str_pnt; uint8_t *pnt; @@ -218,7 +215,7 @@ static void set_lcommunity_string(struct lcommunity *lcom, bool make_json) for (i = 0; i < lcom->size; i++) { if (first) - first = 0; + first = false; else *str_pnt++ = ' '; @@ -319,10 +316,10 @@ bool lcommunity_cmp(const void *arg1, const void *arg2) const struct lcommunity *lcom2 = arg2; if (lcom1 == NULL && lcom2 == NULL) - return 1; + return true; if (lcom1 == NULL || lcom2 == NULL) - return 0; + return false; return (lcom1->size == lcom2->size && memcmp(lcom1->val, lcom2->val, lcom_length(lcom1)) == 0); @@ -537,3 +534,112 @@ void lcommunity_del_val(struct lcommunity *lcom, uint8_t *ptr) i++; } } + +static struct lcommunity *bgp_aggr_lcommunity_lookup( + struct bgp_aggregate *aggregate, + struct lcommunity *lcommunity) +{ + return hash_lookup(aggregate->lcommunity_hash, lcommunity); +} + +static void *bgp_aggr_lcommunty_hash_alloc(void *p) +{ + struct lcommunity *ref = (struct lcommunity *)p; + struct lcommunity *lcommunity = NULL; + + lcommunity = lcommunity_dup(ref); + return lcommunity; +} + +static void bgp_aggr_lcommunity_prepare(struct hash_backet *hb, void *arg) +{ + struct lcommunity *lcommerge = NULL; + struct lcommunity *hb_lcommunity = hb->data; + struct lcommunity **aggr_lcommunity = arg; + + if (*aggr_lcommunity) { + lcommerge = lcommunity_merge(*aggr_lcommunity, hb_lcommunity); + *aggr_lcommunity = lcommunity_uniq_sort(lcommerge); + lcommunity_free(&lcommerge); + } else + *aggr_lcommunity = lcommunity_dup(hb_lcommunity); +} + +void bgp_aggr_lcommunity_remove(void *arg) +{ + struct lcommunity *lcommunity = arg; + + lcommunity_free(&lcommunity); +} + +void bgp_compute_aggregate_lcommunity(struct bgp_aggregate *aggregate, + struct lcommunity *lcommunity) +{ + struct lcommunity *aggr_lcommunity = NULL; + + if ((aggregate == NULL) || (lcommunity == NULL)) + return; + + /* Create hash if not already created. + */ + if (aggregate->lcommunity_hash == NULL) + aggregate->lcommunity_hash = hash_create( + lcommunity_hash_make, lcommunity_cmp, + "BGP Aggregator lcommunity hash"); + + aggr_lcommunity = bgp_aggr_lcommunity_lookup(aggregate, lcommunity); + if (aggr_lcommunity == NULL) { + /* Insert lcommunity into hash. + */ + aggr_lcommunity = hash_get(aggregate->lcommunity_hash, + lcommunity, + bgp_aggr_lcommunty_hash_alloc); + + /* Re-compute aggregate's lcommunity. + */ + if (aggregate->lcommunity) + lcommunity_free(&aggregate->lcommunity); + + hash_iterate(aggregate->lcommunity_hash, + bgp_aggr_lcommunity_prepare, + &aggregate->lcommunity); + } + + /* Increment refernce counter. + */ + aggr_lcommunity->refcnt++; +} + +void bgp_remove_lcommunity_from_aggregate(struct bgp_aggregate *aggregate, + struct lcommunity *lcommunity) +{ + struct lcommunity *aggr_lcommunity = NULL; + struct lcommunity *ret_lcomm = NULL; + + if ((aggregate == NULL) || (lcommunity == NULL)) + return; + + if (aggregate->lcommunity_hash == NULL) + return; + + /* Look-up the lcommunity in the hash. + */ + aggr_lcommunity = bgp_aggr_lcommunity_lookup(aggregate, lcommunity); + if (aggr_lcommunity) { + aggr_lcommunity->refcnt--; + + if (aggr_lcommunity->refcnt == 0) { + ret_lcomm = hash_release(aggregate->lcommunity_hash, + aggr_lcommunity); + lcommunity_free(&ret_lcomm); + + lcommunity_free(&aggregate->lcommunity); + + /* Compute aggregate's lcommunity. + */ + hash_iterate(aggregate->lcommunity_hash, + bgp_aggr_lcommunity_prepare, + &aggregate->lcommunity); + } + } +} diff --git a/bgpd/bgp_lcommunity.h b/bgpd/bgp_lcommunity.h index 23c777d9fd..aa4e8c69fe 100644 --- a/bgpd/bgp_lcommunity.h +++ b/bgpd/bgp_lcommunity.h @@ -22,6 +22,7 @@ #define _QUAGGA_BGP_LCOMMUNITY_H #include "lib/json.h" +#include "bgpd/bgp_route.h" /* Large Communities value is twelve octets long. */ #define LCOMMUNITY_SIZE 12 @@ -70,4 +71,13 @@ extern int lcommunity_match(const struct lcommunity *, extern char *lcommunity_str(struct lcommunity *, bool make_json); extern int lcommunity_include(struct lcommunity *lcom, uint8_t *ptr); extern void lcommunity_del_val(struct lcommunity *lcom, uint8_t *ptr); + +extern void bgp_compute_aggregate_lcommunity( + struct bgp_aggregate *aggregate, + struct lcommunity *lcommunity); +extern void bgp_remove_lcommunity_from_aggregate( + struct bgp_aggregate *aggregate, + struct lcommunity *lcommunity); +extern void bgp_aggr_lcommunity_remove(void *arg); + #endif /* _QUAGGA_BGP_LCOMMUNITY_H */ diff --git a/bgpd/bgp_mac.c b/bgpd/bgp_mac.c index 24f93e4373..49b5854020 100644 --- a/bgpd/bgp_mac.c +++ b/bgpd/bgp_mac.c @@ -106,10 +106,10 @@ struct bgp_mac_find_internal { const char *ifname; }; -static void bgp_mac_find_ifp_internal(struct hash_backet *backet, void *arg) +static void bgp_mac_find_ifp_internal(struct hash_bucket *bucket, void *arg) { struct bgp_mac_find_internal *bmfi = arg; - struct bgp_self_mac *bsm = backet->data; + struct bgp_self_mac *bsm = bucket->data; struct listnode *node; char *name; @@ -311,11 +311,35 @@ void bgp_mac_del_mac_entry(struct interface *ifp) bgp_mac_remove_ifp_internal(bsm, ifp->name); } -bool bgp_mac_entry_exists(struct prefix *p) +/* This API checks MAC address against any of local + * assigned (SVIs) MAC address. + * An example: router-mac attribute in any of evpn update + * requires to compare against local mac. + */ +bool bgp_mac_exist(struct ethaddr *mac) { - struct prefix_evpn *pevpn = (struct prefix_evpn *)p; struct bgp_self_mac lookup; struct bgp_self_mac *bsm; + static uint8_t tmp [ETHER_ADDR_STRLEN] = {0}; + + if (memcmp(mac, &tmp, ETH_ALEN) == 0) + return false; + + memcpy(&lookup.macaddr, mac, ETH_ALEN); + bsm = hash_lookup(bm->self_mac_hash, &lookup); + if (!bsm) + return false; + + return true; +} + +/* This API checks EVPN type-2 prefix and comapares + * mac against any of local assigned (SVIs) MAC + * address. + */ +bool bgp_mac_entry_exists(struct prefix *p) +{ + struct prefix_evpn *pevpn = (struct prefix_evpn *)p; if (pevpn->family != AF_EVPN) return false; @@ -323,18 +347,15 @@ bool bgp_mac_entry_exists(struct prefix *p) if (pevpn->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE) return false; - memcpy(&lookup.macaddr, &p->u.prefix_evpn.macip_addr.mac, ETH_ALEN); - bsm = hash_lookup(bm->self_mac_hash, &lookup); - if (!bsm) - return false; + return bgp_mac_exist(&p->u.prefix_evpn.macip_addr.mac); return true; } -static void bgp_mac_show_mac_entry(struct hash_backet *backet, void *arg) +static void bgp_mac_show_mac_entry(struct hash_bucket *bucket, void *arg) { struct vty *vty = arg; - struct bgp_self_mac *bsm = backet->data; + struct bgp_self_mac *bsm = bucket->data; struct listnode *node; char *name; char buf_mac[ETHER_ADDR_STRLEN]; diff --git a/bgpd/bgp_mac.h b/bgpd/bgp_mac.h index 1dd987ef12..68449b574a 100644 --- a/bgpd/bgp_mac.h +++ b/bgpd/bgp_mac.h @@ -37,5 +37,6 @@ void bgp_mac_dump_table(struct vty *vty); * Function to lookup the prefix and see if we have a matching mac */ bool bgp_mac_entry_exists(struct prefix *p); +bool bgp_mac_exist(struct ethaddr *mac); #endif diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 47e7c1686f..ac579b1bf0 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -281,9 +281,9 @@ static int bgp_vrf_enable(struct vrf *vrf) bgp_vrf_link(bgp, vrf); bgp_handle_socket(bgp, vrf, old_vrf_id, true); - /* Update any redistribute vrf bitmaps if the vrf_id changed */ + /* Update any redistribution if vrf_id changed */ if (old_vrf_id != bgp->vrf_id) - bgp_update_redist_vrf_bitmaps(bgp, old_vrf_id); + bgp_redistribute_redo(bgp); bgp_instance_up(bgp); vpn_leak_zebra_vrf_label_update(bgp, AFI_IP); vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6); @@ -330,9 +330,9 @@ static int bgp_vrf_disable(struct vrf *vrf) /* We have instance configured, unlink from VRF and make it * "down". */ bgp_vrf_unlink(bgp, vrf); - /* Update any redistribute vrf bitmaps if the vrf_id changed */ + /* Delete any redistribute vrf bitmaps if the vrf_id changed */ if (old_vrf_id != bgp->vrf_id) - bgp_update_redist_vrf_bitmaps(bgp, old_vrf_id); + bgp_unset_redist_vrf_bitmaps(bgp, old_vrf_id); bgp_instance_down(bgp); } diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index 241146e451..d5b3d6b197 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -671,7 +671,7 @@ void bgp_mp_dmed_deselect(struct bgp_path_info *dmed_best) bgp_path_info_mpath_count_set(dmed_best, 0); UNSET_FLAG(dmed_best->flags, BGP_PATH_MULTIPATH_CHG); - assert(bgp_path_info_mpath_first(dmed_best) == 0); + assert(bgp_path_info_mpath_first(dmed_best) == NULL); } /* diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index d0ccdcedfb..d211f1afff 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -46,6 +46,7 @@ #include "bgpd/bgp_zebra.h" #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_nht.h" +#include "bgpd/bgp_evpn.h" #if ENABLE_BGP_VNC #include "bgpd/rfapi/rfapi_backend.h" @@ -552,8 +553,12 @@ leak_update(struct bgp *bgp, /* destination bgp instance */ if (bpi->extra && bpi->extra->bgp_orig) bgp_nexthop = bpi->extra->bgp_orig; - /* No nexthop tracking for redistributed routes */ - if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE) + /* + * No nexthop tracking for redistributed routes or for + * EVPN-imported routes that get leaked. + */ + if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE || + is_pi_family_evpn(bpi_ultimate)) nh_valid = 1; else /* @@ -614,8 +619,11 @@ leak_update(struct bgp *bgp, /* destination bgp instance */ * No nexthop tracking for redistributed routes because * their originating protocols will do the tracking and * withdraw those routes if the nexthops become unreachable + * This also holds good for EVPN-imported routes that get + * leaked. */ - if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE) + if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE || + is_pi_family_evpn(bpi_ultimate)) nh_valid = 1; else /* @@ -683,11 +691,10 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */ return; } - /* loop check - should not be an imported route. */ - if (path_vrf->extra && path_vrf->extra->bgp_orig) + /* Is this route exportable into the VPN table? */ + if (!is_route_injectable_into_vpn(path_vrf)) return; - if (!vpn_leak_to_vpn_active(bgp_vrf, afi, &debugmsg)) { if (debug) zlog_debug("%s: %s skipping: %s", __func__, @@ -894,15 +901,6 @@ void vpn_leak_from_vrf_withdraw(struct bgp *bgp_vpn, /* to */ path_vrf->type, path_vrf->sub_type); } - if (path_vrf->sub_type != BGP_ROUTE_NORMAL - && path_vrf->sub_type != BGP_ROUTE_STATIC - && path_vrf->sub_type != BGP_ROUTE_REDISTRIBUTE) { - - if (debug) - zlog_debug("%s: wrong sub_type %d", __func__, - path_vrf->sub_type); - return; - } if (!bgp_vpn) return; @@ -912,6 +910,10 @@ void vpn_leak_from_vrf_withdraw(struct bgp *bgp_vpn, /* to */ return; } + /* Is this route exportable into the VPN table? */ + if (!is_route_injectable_into_vpn(path_vrf)) + return; + if (!vpn_leak_to_vpn_active(bgp_vrf, afi, &debugmsg)) { if (debug) zlog_debug("%s: skipping: %s", __func__, debugmsg); @@ -995,7 +997,7 @@ void vpn_leak_from_vrf_withdraw_all(struct bgp *bgp_vpn, /* to */ == bgp_vrf) { /* delete route */ if (debug) - zlog_debug("%s: deleting it\n", + zlog_debug("%s: deleting it", __func__); bgp_aggregate_decrement(bgp_vpn, &bn->p, bpi, afi, safi); @@ -1073,9 +1075,13 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */ return; } - if (debug) - zlog_debug("%s: updating to vrf %s", __func__, - bgp_vrf->name_pretty); + if (debug) { + char buf_prefix[PREFIX_STRLEN]; + + prefix2str(p, buf_prefix, sizeof(buf_prefix)); + zlog_debug("%s: updating %s to vrf %s", __func__, + buf_prefix, bgp_vrf->name_pretty); + } bgp_attr_dup(&static_attr, path_vpn->attr); /* shallow copy */ @@ -1088,8 +1094,6 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */ */ uint8_t nhfamily = NEXTHOP_FAMILY(path_vpn->attr->mp_nexthop_len); - if (nhfamily != AF_UNSPEC) - static_attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); memset(&nexthop_orig, 0, sizeof(nexthop_orig)); nexthop_orig.family = nhfamily; @@ -1109,6 +1113,7 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */ static_attr.mp_nexthop_len = path_vpn->attr->mp_nexthop_len; } + static_attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); break; case AF_INET6: /* save */ @@ -1132,6 +1137,7 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */ memset(&info, 0, sizeof(info)); info.peer = bgp_vrf->peer_self; info.attr = &static_attr; + info.extra = path_vpn->extra; /* Used for source-vrf filter */ ret = route_map_apply(bgp_vrf->vpn_policy[afi] .rmap[BGP_VPN_POLICY_DIR_FROMVPN], p, RMAP_BGP, &info); @@ -1348,7 +1354,10 @@ void vpn_leak_to_vrf_withdraw_all(struct bgp *bgp_vrf, /* to */ for (bpi = bgp_node_get_bgp_path_info(bn); bpi; bpi = bpi->next) { - if (bpi->extra && bpi->extra->bgp_orig != bgp_vrf) { + if (bpi->extra + && bpi->extra->bgp_orig != bgp_vrf + && bpi->extra->parent + && is_pi_family_vpn(bpi->extra->parent)) { /* delete route */ bgp_aggregate_decrement(bgp_vrf, &bn->p, bpi, diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h index 5b989e1853..2ef9570aac 100644 --- a/bgpd/bgp_mplsvpn.h +++ b/bgpd/bgp_mplsvpn.h @@ -226,6 +226,39 @@ static inline void vpn_leak_postchange(vpn_policy_direction_t direction, } } +/* Flag if the route is injectable into VPN. This would be either a + * non-imported route or a non-VPN imported route. + */ +static inline bool is_route_injectable_into_vpn(struct bgp_path_info *pi) +{ + struct bgp_path_info *parent_pi; + struct bgp_table *table; + struct bgp_node *rn; + + if (pi->sub_type != BGP_ROUTE_IMPORTED || + !pi->extra || + !pi->extra->parent) + return true; + + parent_pi = (struct bgp_path_info *)pi->extra->parent; + rn = parent_pi->net; + if (!rn) + return true; + table = bgp_node_table(rn); + if (table && + (table->afi == AFI_IP || table->afi == AFI_IP6) && + table->safi == SAFI_MPLS_VPN) + return false; + return true; +} + +/* Flag if the route path's family is VPN. */ +static inline bool is_pi_family_vpn(struct bgp_path_info *pi) +{ + return (is_pi_family_matching(pi, AFI_IP, SAFI_MPLS_VPN) || + is_pi_family_matching(pi, AFI_IP6, SAFI_MPLS_VPN)); +} + extern void vpn_policy_routemap_event(const char *rmap_name); extern vrf_id_t get_first_vrf_for_redirect_with_rt(struct ecommunity *eckey); diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 70d3d7b69c..de97b73c72 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -184,10 +184,10 @@ struct bgp_addr { struct list *ifp_name_list; }; -static void show_address_entry(struct hash_backet *backet, void *args) +static void show_address_entry(struct hash_bucket *bucket, void *args) { struct vty *vty = (struct vty *)args; - struct bgp_addr *addr = (struct bgp_addr *)backet->data; + struct bgp_addr *addr = (struct bgp_addr *)bucket->data; char *name; struct listnode *node; @@ -204,7 +204,7 @@ static void show_address_entry(struct hash_backet *backet, void *args) void bgp_nexthop_show_address_hash(struct vty *vty, struct bgp *bgp) { hash_iterate(bgp->address_hash, - (void (*)(struct hash_backet *, void *))show_address_entry, + (void (*)(struct hash_bucket *, void *))show_address_entry, vty); } diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 3018124f45..7af5827d00 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -49,7 +49,7 @@ So there is many configurable point. First of all we want set each peer whether we send capability negotiation to the peer or not. - Next, if we send capability to the peer we want to set my capabilty + Next, if we send capability to the peer we want to set my capability inforation at each peer. */ void bgp_capability_vty_out(struct vty *vty, struct peer *peer, bool use_json, diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h index 0fc321bdf3..8359f59a41 100644 --- a/bgpd/bgp_open.h +++ b/bgpd/bgp_open.h @@ -49,7 +49,7 @@ struct graceful_restart_af { #define CAPABILITY_CODE_DYNAMIC_OLD 66 /* Dynamic Capability, deprecated since 2003 */ #define CAPABILITY_CODE_DYNAMIC 67 /* Dynamic Capability */ #define CAPABILITY_CODE_ADDPATH 69 /* Addpath Capability */ -#define CAPABILITY_CODE_FQDN 73 /* Advertise hostname capabilty */ +#define CAPABILITY_CODE_FQDN 73 /* Advertise hostname capability */ #define CAPABILITY_CODE_ENHE 5 /* Extended Next Hop Encoding */ #define CAPABILITY_CODE_REFRESH_OLD 128 /* Route Refresh Capability(cisco) */ #define CAPABILITY_CODE_ORF_OLD 130 /* Cooperative Route Filtering Capability(cisco) */ diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c index c63eb83c1b..c0be36ed3f 100644 --- a/bgpd/bgp_pbr.c +++ b/bgpd/bgp_pbr.c @@ -72,9 +72,9 @@ struct bgp_pbr_rule_unique { struct bgp_pbr_rule *bpr_found; }; -static int bgp_pbr_rule_walkcb(struct hash_backet *backet, void *arg) +static int bgp_pbr_rule_walkcb(struct hash_bucket *bucket, void *arg) { - struct bgp_pbr_rule *bpr = (struct bgp_pbr_rule *)backet->data; + struct bgp_pbr_rule *bpr = (struct bgp_pbr_rule *)bucket->data; struct bgp_pbr_rule_unique *bpru = (struct bgp_pbr_rule_unique *) arg; uint32_t unique = bpru->unique; @@ -86,9 +86,9 @@ static int bgp_pbr_rule_walkcb(struct hash_backet *backet, void *arg) return HASHWALK_CONTINUE; } -static int bgp_pbr_action_walkcb(struct hash_backet *backet, void *arg) +static int bgp_pbr_action_walkcb(struct hash_bucket *bucket, void *arg) { - struct bgp_pbr_action *bpa = (struct bgp_pbr_action *)backet->data; + struct bgp_pbr_action *bpa = (struct bgp_pbr_action *)bucket->data; struct bgp_pbr_action_unique *bpau = (struct bgp_pbr_action_unique *) arg; uint32_t unique = bpau->unique; @@ -100,10 +100,10 @@ static int bgp_pbr_action_walkcb(struct hash_backet *backet, void *arg) return HASHWALK_CONTINUE; } -static int bgp_pbr_match_entry_walkcb(struct hash_backet *backet, void *arg) +static int bgp_pbr_match_entry_walkcb(struct hash_bucket *bucket, void *arg) { struct bgp_pbr_match_entry *bpme = - (struct bgp_pbr_match_entry *)backet->data; + (struct bgp_pbr_match_entry *)bucket->data; struct bgp_pbr_match_entry_unique *bpmeu = (struct bgp_pbr_match_entry_unique *)arg; uint32_t unique = bpmeu->unique; @@ -120,9 +120,9 @@ struct bgp_pbr_match_ipsetname { struct bgp_pbr_match *bpm_found; }; -static int bgp_pbr_match_pername_walkcb(struct hash_backet *backet, void *arg) +static int bgp_pbr_match_pername_walkcb(struct hash_bucket *bucket, void *arg) { - struct bgp_pbr_match *bpm = (struct bgp_pbr_match *)backet->data; + struct bgp_pbr_match *bpm = (struct bgp_pbr_match *)bucket->data; struct bgp_pbr_match_ipsetname *bpmi = (struct bgp_pbr_match_ipsetname *)arg; char *ipset_name = bpmi->ipsetname; @@ -135,9 +135,9 @@ static int bgp_pbr_match_pername_walkcb(struct hash_backet *backet, void *arg) return HASHWALK_CONTINUE; } -static int bgp_pbr_match_iptable_walkcb(struct hash_backet *backet, void *arg) +static int bgp_pbr_match_iptable_walkcb(struct hash_bucket *bucket, void *arg) { - struct bgp_pbr_match *bpm = (struct bgp_pbr_match *)backet->data; + struct bgp_pbr_match *bpm = (struct bgp_pbr_match *)bucket->data; struct bgp_pbr_match_iptable_unique *bpmiu = (struct bgp_pbr_match_iptable_unique *)arg; uint32_t unique = bpmiu->unique; @@ -154,9 +154,9 @@ struct bgp_pbr_match_unique { struct bgp_pbr_match *bpm_found; }; -static int bgp_pbr_match_walkcb(struct hash_backet *backet, void *arg) +static int bgp_pbr_match_walkcb(struct hash_bucket *bucket, void *arg) { - struct bgp_pbr_match *bpm = (struct bgp_pbr_match *)backet->data; + struct bgp_pbr_match *bpm = (struct bgp_pbr_match *)bucket->data; struct bgp_pbr_match_unique *bpmu = (struct bgp_pbr_match_unique *) arg; uint32_t unique = bpmu->unique; @@ -333,7 +333,7 @@ static bool bgp_pbr_extract_enumerate_unary(struct bgp_pbr_match_val list[], unary_operator, and_valmask, or_valmask, list[i].value, type_entry); - if (ret == false) + if (!ret) return ret; continue; } @@ -441,7 +441,7 @@ static bool bgp_pbr_extract(struct bgp_pbr_match_val list[], range->min_port = list[i].value; exact_match = true; } - if (exact_match == true && i > 0) + if (exact_match && i > 0) return false; if (list[i].compare_operator == (OPERATOR_COMPARE_GREATER_THAN + @@ -545,7 +545,7 @@ static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api) "too complex. ignoring."); return 0; } else if (api->match_icmp_type_num > 1 && - enumerate_icmp == false) { + !enumerate_icmp) { if (BGP_DEBUG(pbr, PBR)) zlog_debug("BGP: match icmp code is enumerate" ", and icmp type is not." @@ -1504,9 +1504,9 @@ struct bgp_pbr_rule_remain { struct bgp_pbr_rule *bpr_found; }; -static int bgp_pbr_get_same_rule(struct hash_backet *backet, void *arg) +static int bgp_pbr_get_same_rule(struct hash_bucket *bucket, void *arg) { - struct bgp_pbr_rule *r1 = (struct bgp_pbr_rule *)backet->data; + struct bgp_pbr_rule *r1 = (struct bgp_pbr_rule *)bucket->data; struct bgp_pbr_rule_remain *ctxt = (struct bgp_pbr_rule_remain *)arg; struct bgp_pbr_rule *r2; @@ -1543,9 +1543,9 @@ static int bgp_pbr_get_same_rule(struct hash_backet *backet, void *arg) return HASHWALK_CONTINUE; } -static int bgp_pbr_get_remaining_entry(struct hash_backet *backet, void *arg) +static int bgp_pbr_get_remaining_entry(struct hash_bucket *bucket, void *arg) { - struct bgp_pbr_match *bpm = (struct bgp_pbr_match *)backet->data; + struct bgp_pbr_match *bpm = (struct bgp_pbr_match *)bucket->data; struct bgp_pbr_match_entry_remain *bpmer = (struct bgp_pbr_match_entry_remain *)arg; struct bgp_pbr_match *bpm_temp; diff --git a/bgpd/bgp_rd.c b/bgpd/bgp_rd.c index 77f5aade5f..571139a49a 100644 --- a/bgpd/bgp_rd.c +++ b/bgpd/bgp_rd.c @@ -155,8 +155,7 @@ int str2prefix_rd(const char *str, struct prefix_rd *prd) out: if (s) stream_free(s); - if (half) - XFREE(MTYPE_TMP, half); + XFREE(MTYPE_TMP, half); return lret; } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 59ca223a2d..eca632dd44 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -254,8 +254,9 @@ static void bgp_path_info_free(struct bgp_path_info *path) bgp_unlink_nexthop(path); bgp_path_info_extra_free(&path->extra); bgp_path_info_mpath_free(&path->mpath); - bgp_addpath_free_info_data(&path->tx_addpath, - path->net ? &path->net->tx_addpath : NULL); + if (path->net) + bgp_addpath_free_info_data(&path->tx_addpath, + &path->net->tx_addpath); peer_unlock(path->peer); /* bgp_path_info peer reference */ @@ -1224,6 +1225,20 @@ static int bgp_input_modifier(struct peer *peer, struct prefix *p, } } + /* RFC 8212 to prevent route leaks. + * This specification intends to improve this situation by requiring the + * explicit configuration of both BGP Import and Export Policies for any + * External BGP (EBGP) session such as customers, peers, or + * confederation boundaries for all enabled address families. Through + * codification of the aforementioned requirement, operators will + * benefit from consistent behavior across different BGP + * implementations. + */ + if (peer->bgp->ebgp_requires_policy + == DEFAULT_EBGP_POLICY_ENABLED) + if (!bgp_inbound_policy_exists(peer, filter)) + return RMAP_DENY; + /* Route map apply. */ if (rmap) { memset(&rmap_path, 0, sizeof(struct bgp_path_info)); @@ -1777,6 +1792,20 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi, } } + /* RFC 8212 to prevent route leaks. + * This specification intends to improve this situation by requiring the + * explicit configuration of both BGP Import and Export Policies for any + * External BGP (EBGP) session such as customers, peers, or + * confederation boundaries for all enabled address families. Through + * codification of the aforementioned requirement, operators will + * benefit from consistent behavior across different BGP + * implementations. + */ + if (peer->bgp->ebgp_requires_policy + == DEFAULT_EBGP_POLICY_ENABLED) + if (!bgp_outbound_policy_exists(peer, filter)) + return 0; + if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) { if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED) { @@ -2447,8 +2476,9 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn, /* advertise/withdraw type-5 routes */ if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) { - if (advertise_type5_routes(bgp, afi) && new_select && - (!new_select->extra || !new_select->extra->parent)) { + if (advertise_type5_routes(bgp, afi) && + new_select && + is_route_injectable_into_evpn(new_select)) { /* apply the route-map */ if (bgp->adv_cmd_rmap[afi][safi].map) { @@ -2461,6 +2491,9 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn, bgp_evpn_advertise_type5_route( bgp, &rn->p, new_select->attr, afi, safi); + else + bgp_evpn_withdraw_type5_route( + bgp, &rn->p, afi, safi); } else { bgp_evpn_advertise_type5_route(bgp, &rn->p, @@ -2468,8 +2501,9 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn, afi, safi); } - } else if (advertise_type5_routes(bgp, afi) && old_select && - (!old_select->extra || !old_select->extra->parent)) + } else if (advertise_type5_routes(bgp, afi) && + old_select && + is_route_injectable_into_evpn(old_select)) bgp_evpn_withdraw_type5_route(bgp, &rn->p, afi, safi); } @@ -3062,7 +3096,7 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, goto filtered; } - if (bgp_mac_entry_exists(p)) { + if (bgp_mac_entry_exists(p) || bgp_mac_exist(&attr->rmac)) { reason = "self mac;"; goto filtered; } @@ -3251,7 +3285,7 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, extra = bgp_path_info_extra_get(pi); if (extra->label != label) { memcpy(&extra->label, label, - num_labels * sizeof(mpls_label_t)); + num_labels * sizeof(mpls_label_t)); extra->num_labels = num_labels; } if (!(afi == AFI_L2VPN && safi == SAFI_EVPN)) @@ -3423,7 +3457,8 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, if (has_valid_label) { extra = bgp_path_info_extra_get(new); if (extra->label != label) { - memcpy(&extra->label, label, num_labels * sizeof(mpls_label_t)); + memcpy(&extra->label, label, + num_labels * sizeof(mpls_label_t)); extra->num_labels = num_labels; } if (!(afi == AFI_L2VPN && safi == SAFI_EVPN)) @@ -4160,6 +4195,26 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi) } } +int bgp_outbound_policy_exists(struct peer *peer, struct bgp_filter *filter) +{ + if (peer->sort == BGP_PEER_EBGP + && (ROUTE_MAP_OUT_NAME(filter) || PREFIX_LIST_OUT_NAME(filter) + || FILTER_LIST_OUT_NAME(filter) + || DISTRIBUTE_OUT_NAME(filter))) + return 1; + return 0; +} + +int bgp_inbound_policy_exists(struct peer *peer, struct bgp_filter *filter) +{ + if (peer->sort == BGP_PEER_EBGP + && (ROUTE_MAP_IN_NAME(filter) || PREFIX_LIST_IN_NAME(filter) + || FILTER_LIST_IN_NAME(filter) + || DISTRIBUTE_IN_NAME(filter))) + return 1; + return 0; +} + static void bgp_cleanup_table(struct bgp *bgp, struct bgp_table *table, safi_t safi) { @@ -4415,12 +4470,10 @@ static struct bgp_static *bgp_static_new(void) static void bgp_static_free(struct bgp_static *bgp_static) { - if (bgp_static->rmap.name) - XFREE(MTYPE_ROUTE_MAP_NAME, bgp_static->rmap.name); + XFREE(MTYPE_ROUTE_MAP_NAME, bgp_static->rmap.name); route_map_counter_decrement(bgp_static->rmap.map); - if (bgp_static->eth_s_id) - XFREE(MTYPE_ATTR, bgp_static->eth_s_id); + XFREE(MTYPE_ATTR, bgp_static->eth_s_id); XFREE(MTYPE_BGP_STATIC, bgp_static); } @@ -4980,9 +5033,8 @@ static int bgp_static_set(struct vty *vty, const char *negate, bgp_static->backdoor = backdoor; if (rmap) { - if (bgp_static->rmap.name) - XFREE(MTYPE_ROUTE_MAP_NAME, - bgp_static->rmap.name); + XFREE(MTYPE_ROUTE_MAP_NAME, + bgp_static->rmap.name); route_map_counter_decrement( bgp_static->rmap.map); bgp_static->rmap.name = @@ -4992,9 +5044,8 @@ static int bgp_static_set(struct vty *vty, const char *negate, route_map_counter_increment( bgp_static->rmap.map); } else { - if (bgp_static->rmap.name) - XFREE(MTYPE_ROUTE_MAP_NAME, - bgp_static->rmap.name); + XFREE(MTYPE_ROUTE_MAP_NAME, + bgp_static->rmap.name); route_map_counter_decrement( bgp_static->rmap.map); bgp_static->rmap.name = NULL; @@ -5012,9 +5063,8 @@ static int bgp_static_set(struct vty *vty, const char *negate, bgp_static->label_index = label_index; if (rmap) { - if (bgp_static->rmap.name) - XFREE(MTYPE_ROUTE_MAP_NAME, - bgp_static->rmap.name); + XFREE(MTYPE_ROUTE_MAP_NAME, + bgp_static->rmap.name); route_map_counter_decrement( bgp_static->rmap.map); bgp_static->rmap.name = @@ -5298,9 +5348,7 @@ int bgp_static_set_safi(afi_t afi, safi_t safi, struct vty *vty, bgp_static->prd = prd; if (rmap_str) { - if (bgp_static->rmap.name) - XFREE(MTYPE_ROUTE_MAP_NAME, - bgp_static->rmap.name); + XFREE(MTYPE_ROUTE_MAP_NAME, bgp_static->rmap.name); route_map_counter_decrement(bgp_static->rmap.map); bgp_static->rmap.name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_str); @@ -5407,15 +5455,13 @@ static int bgp_table_map_set(struct vty *vty, afi_t afi, safi_t safi, rmap = &bgp->table_map[afi][safi]; if (rmap_name) { - if (rmap->name) - XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name); + XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name); route_map_counter_decrement(rmap->map); rmap->name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_name); rmap->map = route_map_lookup_by_name(rmap_name); route_map_counter_increment(rmap->map); } else { - if (rmap->name) - XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name); + XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name); route_map_counter_decrement(rmap->map); rmap->name = NULL; rmap->map = NULL; @@ -5434,8 +5480,7 @@ static int bgp_table_map_unset(struct vty *vty, afi_t afi, safi_t safi, struct bgp_rmap *rmap; rmap = &bgp->table_map[afi][safi]; - if (rmap->name) - XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name); + XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name); route_map_counter_decrement(rmap->map); rmap->name = NULL; rmap->map = NULL; @@ -5531,33 +5576,6 @@ DEFPY(ipv6_bgp_network, label_index ? (uint32_t)label_index : BGP_INVALID_LABEL_INDEX); } -/* Aggreagete address: - - advertise-map Set condition to advertise attribute - as-set Generate AS set path information - attribute-map Set attributes of aggregate - route-map Set parameters of aggregate - summary-only Filter more specific routes from updates - suppress-map Conditionally filter more specific routes from updates - <cr> - */ -struct bgp_aggregate { - /* Summary-only flag. */ - uint8_t summary_only; - - /* AS set generation. */ - uint8_t as_set; - - /* Route-map for aggregated route. */ - struct route_map *map; - - /* Suppress-count. */ - unsigned long count; - - /* SAFI configuration. */ - safi_t safi; -}; - static struct bgp_aggregate *bgp_aggregate_new(void) { return XCALLOC(MTYPE_BGP_AGGREGATE, sizeof(struct bgp_aggregate)); @@ -5683,8 +5701,7 @@ static void bgp_aggregate_install(struct bgp *bgp, afi_t afi, safi_t safi, /* Update an aggregate as routes are added/removed from the BGP table */ static void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, - struct bgp_path_info *pinew, afi_t afi, - safi_t safi, struct bgp_path_info *del, + afi_t afi, safi_t safi, struct bgp_aggregate *aggregate) { struct bgp_table *table; @@ -5692,13 +5709,9 @@ static void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, struct bgp_node *rn; uint8_t origin; struct aspath *aspath = NULL; - struct aspath *asmerge = NULL; struct community *community = NULL; - struct community *commerge = NULL; struct ecommunity *ecommunity = NULL; - struct ecommunity *ecommerge = NULL; struct lcommunity *lcommunity = NULL; - struct lcommunity *lcommerge = NULL; struct bgp_path_info *pi; unsigned long match = 0; uint8_t atomic_aggregate = 0; @@ -5727,9 +5740,6 @@ static void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, if (BGP_PATH_HOLDDOWN(pi)) continue; - if (del && pi == del) - continue; - if (pi->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)) atomic_aggregate = 1; @@ -5760,8 +5770,18 @@ static void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, * route MUST have the ORIGIN attribute with the value * EGP. */ - if (origin < pi->attr->origin) - origin = pi->attr->origin; + switch (pi->attr->origin) { + case BGP_ORIGIN_INCOMPLETE: + aggregate->incomplete_origin_count++; + break; + case BGP_ORIGIN_EGP: + aggregate->egp_origin_count++; + break; + default: + /*Do nothing. + */ + break; + } if (!aggregate->as_set) continue; @@ -5770,130 +5790,68 @@ static void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, * as-set aggregate route generate origin, as path, * and community aggregation. */ - if (aspath) { - asmerge = aspath_aggregate(aspath, - pi->attr->aspath); - aspath_free(aspath); - aspath = asmerge; - } else - aspath = aspath_dup(pi->attr->aspath); - - if (pi->attr->community) { - if (community) { - commerge = community_merge( - community, pi->attr->community); - community = - community_uniq_sort(commerge); - community_free(&commerge); - } else - community = community_dup( - pi->attr->community); - } - - if (pi->attr->ecommunity) { - if (ecommunity) { - ecommerge = ecommunity_merge( - ecommunity, - pi->attr->ecommunity); - ecommunity = - ecommunity_uniq_sort(ecommerge); - ecommunity_free(&ecommerge); - } else - ecommunity = ecommunity_dup( - pi->attr->ecommunity); - } - - if (pi->attr->lcommunity) { - if (lcommunity) { - lcommerge = lcommunity_merge( - lcommunity, - pi->attr->lcommunity); - lcommunity = - lcommunity_uniq_sort(lcommerge); - lcommunity_free(&lcommerge); - } else - lcommunity = lcommunity_dup( - pi->attr->lcommunity); - } + /* Compute aggregate route's as-path. + */ + bgp_compute_aggregate_aspath(aggregate, + pi->attr->aspath); + + /* Compute aggregate route's community. + */ + if (pi->attr->community) + bgp_compute_aggregate_community( + aggregate, + pi->attr->community); + + /* Compute aggregate route's extended community. + */ + if (pi->attr->ecommunity) + bgp_compute_aggregate_ecommunity( + aggregate, + pi->attr->ecommunity); + + /* Compute aggregate route's large community. + */ + if (pi->attr->lcommunity) + bgp_compute_aggregate_lcommunity( + aggregate, + pi->attr->lcommunity); } if (match) bgp_process(bgp, rn, afi, safi); } bgp_unlock_node(top); - if (pinew) { - aggregate->count++; - if (aggregate->summary_only) - (bgp_path_info_extra_get(pinew))->suppress++; + if (aggregate->incomplete_origin_count > 0) + origin = BGP_ORIGIN_INCOMPLETE; + else if (aggregate->egp_origin_count > 0) + origin = BGP_ORIGIN_EGP; - if (origin < pinew->attr->origin) - origin = pinew->attr->origin; + if (aggregate->as_set) { + if (aggregate->aspath) + /* Retrieve aggregate route's as-path. + */ + aspath = aspath_dup(aggregate->aspath); - if (aggregate->as_set) { - if (aspath) { - asmerge = aspath_aggregate(aspath, - pinew->attr->aspath); - aspath_free(aspath); - aspath = asmerge; - } else - aspath = aspath_dup(pinew->attr->aspath); + if (aggregate->community) + /* Retrieve aggregate route's community. + */ + community = community_dup(aggregate->community); - if (pinew->attr->community) { - if (community) { - commerge = community_merge( - community, - pinew->attr->community); - community = - community_uniq_sort(commerge); - community_free(&commerge); - } else - community = community_dup( - pinew->attr->community); - } + if (aggregate->ecommunity) + /* Retrieve aggregate route's ecommunity. + */ + ecommunity = ecommunity_dup(aggregate->ecommunity); - if (pinew->attr->ecommunity) { - if (ecommunity) { - ecommerge = ecommunity_merge( - ecommunity, - pinew->attr->ecommunity); - ecommunity = - ecommunity_uniq_sort(ecommerge); - ecommunity_free(&ecommerge); - } else - ecommunity = ecommunity_dup( - pinew->attr->ecommunity); - } - - if (pinew->attr->lcommunity) { - if (lcommunity) { - lcommerge = lcommunity_merge( - lcommunity, - pinew->attr->lcommunity); - lcommunity = - lcommunity_uniq_sort(lcommerge); - lcommunity_free(&lcommerge); - } else - lcommunity = lcommunity_dup( - pinew->attr->lcommunity); - } - } + if (aggregate->lcommunity) + /* Retrieve aggregate route's lcommunity. + */ + lcommunity = lcommunity_dup(aggregate->lcommunity); } bgp_aggregate_install(bgp, afi, safi, p, origin, aspath, community, ecommunity, lcommunity, atomic_aggregate, aggregate); - - if (aggregate->count == 0) { - if (aspath) - aspath_free(aspath); - if (community) - community_free(&community); - if (ecommunity) - ecommunity_free(&ecommunity); - if (lcommunity) - lcommunity_free(&lcommunity); - } } static void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi, @@ -5932,6 +5890,41 @@ static void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi, } } aggregate->count--; + + if (pi->attr->origin == BGP_ORIGIN_INCOMPLETE) + aggregate->incomplete_origin_count--; + else if (pi->attr->origin == BGP_ORIGIN_EGP) + aggregate->egp_origin_count--; + + if (aggregate->as_set) { + /* Remove as-path from aggregate. + */ + bgp_remove_aspath_from_aggregate( + aggregate, + pi->attr->aspath); + + if (pi->attr->community) + /* Remove community from aggregate. + */ + bgp_remove_community_from_aggregate( + aggregate, + pi->attr->community); + + if (pi->attr->ecommunity) + /* Remove ecommunity from aggregate. + */ + bgp_remove_ecommunity_from_aggregate( + aggregate, + pi->attr->ecommunity); + + if (pi->attr->lcommunity) + /* Remove lcommunity from aggregate. + */ + bgp_remove_lcommunity_from_aggregate( + aggregate, + pi->attr->lcommunity); + } + } /* If this node was suppressed, process the change. */ @@ -5941,6 +5934,210 @@ static void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi, bgp_unlock_node(top); } +static void bgp_add_route_to_aggregate(struct bgp *bgp, struct prefix *aggr_p, + struct bgp_path_info *pinew, afi_t afi, + safi_t safi, + struct bgp_aggregate *aggregate) +{ + uint8_t origin; + struct aspath *aspath = NULL; + uint8_t atomic_aggregate = 0; + struct community *community = NULL; + struct ecommunity *ecommunity = NULL; + struct lcommunity *lcommunity = NULL; + + /* ORIGIN attribute: If at least one route among routes that are + * aggregated has ORIGIN with the value INCOMPLETE, then the + * aggregated route must have the ORIGIN attribute with the value + * INCOMPLETE. Otherwise, if at least one route among routes that + * are aggregated has ORIGIN with the value EGP, then the aggregated + * route must have the origin attribute with the value EGP. In all + * other case the value of the ORIGIN attribute of the aggregated + * route is INTERNAL. + */ + origin = BGP_ORIGIN_IGP; + + aggregate->count++; + + if (aggregate->summary_only) + (bgp_path_info_extra_get(pinew))->suppress++; + + switch (pinew->attr->origin) { + case BGP_ORIGIN_INCOMPLETE: + aggregate->incomplete_origin_count++; + break; + case BGP_ORIGIN_EGP: + aggregate->egp_origin_count++; + break; + default: + /* Do nothing. + */ + break; + } + + if (aggregate->incomplete_origin_count > 0) + origin = BGP_ORIGIN_INCOMPLETE; + else if (aggregate->egp_origin_count > 0) + origin = BGP_ORIGIN_EGP; + + if (aggregate->as_set) { + /* Compute aggregate route's as-path. + */ + bgp_compute_aggregate_aspath(aggregate, + pinew->attr->aspath); + + /* Compute aggregate route's community. + */ + if (pinew->attr->community) + bgp_compute_aggregate_community( + aggregate, + pinew->attr->community); + + /* Compute aggregate route's extended community. + */ + if (pinew->attr->ecommunity) + bgp_compute_aggregate_ecommunity( + aggregate, + pinew->attr->ecommunity); + + /* Compute aggregate route's large community. + */ + if (pinew->attr->lcommunity) + bgp_compute_aggregate_lcommunity( + aggregate, + pinew->attr->lcommunity); + + /* Retrieve aggregate route's as-path. + */ + if (aggregate->aspath) + aspath = aspath_dup(aggregate->aspath); + + /* Retrieve aggregate route's community. + */ + if (aggregate->community) + community = community_dup(aggregate->community); + + /* Retrieve aggregate route's ecommunity. + */ + if (aggregate->ecommunity) + ecommunity = ecommunity_dup(aggregate->ecommunity); + + /* Retrieve aggregate route's lcommunity. + */ + if (aggregate->lcommunity) + lcommunity = lcommunity_dup(aggregate->lcommunity); + } + + bgp_aggregate_install(bgp, afi, safi, aggr_p, origin, + aspath, community, ecommunity, + lcommunity, atomic_aggregate, aggregate); +} + +static void bgp_remove_route_from_aggregate(struct bgp *bgp, afi_t afi, + safi_t safi, + struct bgp_path_info *pi, + struct bgp_aggregate *aggregate, + struct prefix *aggr_p) +{ + uint8_t origin; + struct aspath *aspath = NULL; + uint8_t atomic_aggregate = 0; + struct community *community = NULL; + struct ecommunity *ecommunity = NULL; + struct lcommunity *lcommunity = NULL; + unsigned long match = 0; + + if (BGP_PATH_HOLDDOWN(pi)) + return; + + if (pi->sub_type == BGP_ROUTE_AGGREGATE) + return; + + if (aggregate->summary_only + && pi->extra + && pi->extra->suppress > 0) { + pi->extra->suppress--; + + if (pi->extra->suppress == 0) { + bgp_path_info_set_flag(pi->net, pi, + BGP_PATH_ATTR_CHANGED); + match++; + } + } + + if (aggregate->count > 0) + aggregate->count--; + + if (pi->attr->origin == BGP_ORIGIN_INCOMPLETE) + aggregate->incomplete_origin_count--; + else if (pi->attr->origin == BGP_ORIGIN_EGP) + aggregate->egp_origin_count--; + + if (aggregate->as_set) { + /* Remove as-path from aggregate. + */ + bgp_remove_aspath_from_aggregate(aggregate, + pi->attr->aspath); + + if (pi->attr->community) + /* Remove community from aggregate. + */ + bgp_remove_community_from_aggregate( + aggregate, + pi->attr->community); + + if (pi->attr->ecommunity) + /* Remove ecommunity from aggregate. + */ + bgp_remove_ecommunity_from_aggregate( + aggregate, + pi->attr->ecommunity); + + if (pi->attr->lcommunity) + /* Remove lcommunity from aggregate. + */ + bgp_remove_lcommunity_from_aggregate( + aggregate, + pi->attr->lcommunity); + } + + /* If this node was suppressed, process the change. */ + if (match) + bgp_process(bgp, pi->net, afi, safi); + + origin = BGP_ORIGIN_IGP; + if (aggregate->incomplete_origin_count > 0) + origin = BGP_ORIGIN_INCOMPLETE; + else if (aggregate->egp_origin_count > 0) + origin = BGP_ORIGIN_EGP; + + if (aggregate->as_set) { + /* Retrieve aggregate route's as-path. + */ + if (aggregate->aspath) + aspath = aspath_dup(aggregate->aspath); + + /* Retrieve aggregate route's community. + */ + if (aggregate->community) + community = community_dup(aggregate->community); + + /* Retrieve aggregate route's ecommunity. + */ + if (aggregate->ecommunity) + ecommunity = ecommunity_dup(aggregate->ecommunity); + + /* Retrieve aggregate route's lcommunity. + */ + if (aggregate->lcommunity) + lcommunity = lcommunity_dup(aggregate->lcommunity); + } + + bgp_aggregate_install(bgp, afi, safi, aggr_p, origin, + aspath, community, ecommunity, + lcommunity, atomic_aggregate, aggregate); +} + void bgp_aggregate_increment(struct bgp *bgp, struct prefix *p, struct bgp_path_info *pi, afi_t afi, safi_t safi) { @@ -5967,9 +6164,8 @@ void bgp_aggregate_increment(struct bgp *bgp, struct prefix *p, for (rn = child; rn; rn = bgp_node_parent_nolock(rn)) { aggregate = bgp_node_get_bgp_aggregate_info(rn); if (aggregate != NULL && rn->p.prefixlen < p->prefixlen) { - bgp_aggregate_delete(bgp, &rn->p, afi, safi, aggregate); - bgp_aggregate_route(bgp, &rn->p, pi, afi, safi, NULL, - aggregate); + bgp_add_route_to_aggregate(bgp, &rn->p, pi, afi, + safi, aggregate); } } bgp_unlock_node(child); @@ -5998,9 +6194,8 @@ void bgp_aggregate_decrement(struct bgp *bgp, struct prefix *p, for (rn = child; rn; rn = bgp_node_parent_nolock(rn)) { aggregate = bgp_node_get_bgp_aggregate_info(rn); if (aggregate != NULL && rn->p.prefixlen < p->prefixlen) { - bgp_aggregate_delete(bgp, &rn->p, afi, safi, aggregate); - bgp_aggregate_route(bgp, &rn->p, NULL, afi, safi, del, - aggregate); + bgp_remove_route_from_aggregate(bgp, afi, safi, + del, aggregate, &rn->p); } } bgp_unlock_node(child); @@ -6042,6 +6237,59 @@ static int bgp_aggregate_unset(struct vty *vty, const char *prefix_str, /* Unlock aggregate address configuration. */ bgp_node_set_bgp_aggregate_info(rn, NULL); + + if (aggregate->community) + community_free(&aggregate->community); + + if (aggregate->community_hash) { + /* Delete all communities in the hash. + */ + hash_clean(aggregate->community_hash, + bgp_aggr_community_remove); + /* Free up the community_hash. + */ + hash_free(aggregate->community_hash); + } + + if (aggregate->ecommunity) + ecommunity_free(&aggregate->ecommunity); + + if (aggregate->ecommunity_hash) { + /* Delete all ecommunities in the hash. + */ + hash_clean(aggregate->ecommunity_hash, + bgp_aggr_ecommunity_remove); + /* Free up the ecommunity_hash. + */ + hash_free(aggregate->ecommunity_hash); + } + + if (aggregate->lcommunity) + lcommunity_free(&aggregate->lcommunity); + + if (aggregate->lcommunity_hash) { + /* Delete all lcommunities in the hash. + */ + hash_clean(aggregate->lcommunity_hash, + bgp_aggr_lcommunity_remove); + /* Free up the lcommunity_hash. + */ + hash_free(aggregate->lcommunity_hash); + } + + if (aggregate->aspath) + aspath_free(aggregate->aspath); + + if (aggregate->aspath_hash) { + /* Delete all as-paths in the hash. + */ + hash_clean(aggregate->aspath_hash, + bgp_aggr_aspath_remove); + /* Free up the aspath_hash. + */ + hash_free(aggregate->aspath_hash); + } + bgp_aggregate_free(aggregate); bgp_unlock_node(rn); bgp_unlock_node(rn); @@ -6095,7 +6343,7 @@ static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi, bgp_node_set_bgp_aggregate_info(rn, aggregate); /* Aggregate address insert into BGP routing table. */ - bgp_aggregate_route(bgp, &p, NULL, afi, safi, NULL, aggregate); + bgp_aggregate_route(bgp, &p, afi, safi, aggregate); return CMD_SUCCESS; } @@ -8405,11 +8653,15 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p, json_pmsi = json_object_new_object(); json_object_string_add(json_pmsi, "tunnelType", str); + json_object_int_add(json_pmsi, + "label", + label2vni(&attr->label)); json_object_object_add(json_path, "pmsi", json_pmsi); } else - vty_out(vty, " PMSI Tunnel Type: %s\n", - str); + vty_out(vty, + " PMSI Tunnel Type: %s, label: %d\n", + str, label2vni(&attr->label)); } } @@ -11201,8 +11453,7 @@ static int bgp_distance_unset(struct vty *vty, const char *distance_str, return CMD_WARNING_CONFIG_FAILED; } - if (bdistance->access_list) - XFREE(MTYPE_AS_LIST, bdistance->access_list); + XFREE(MTYPE_AS_LIST, bdistance->access_list); bgp_distance_free(bdistance); bgp_node_set_bgp_path_info(rn, NULL); @@ -11642,10 +11893,10 @@ DEFUN (clear_ip_bgp_dampening_address_mask, NULL, 0); } -static void show_bgp_peerhash_entry(struct hash_backet *backet, void *arg) +static void show_bgp_peerhash_entry(struct hash_bucket *bucket, void *arg) { struct vty *vty = arg; - struct peer *peer = backet->data; + struct peer *peer = bucket->data; char buf[SU_ADDRSTRLEN]; vty_out(vty, "\tPeer: %s %s\n", peer->host, @@ -11789,10 +12040,8 @@ static void bgp_config_write_network_evpn(struct vty *vty, struct bgp *bgp, decode_label(&bgp_static->label), esi, buf2, macrouter); - if (macrouter) - XFREE(MTYPE_TMP, macrouter); - if (esi) - XFREE(MTYPE_TMP, esi); + XFREE(MTYPE_TMP, macrouter); + XFREE(MTYPE_TMP, esi); } } } diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 97d4aaeeba..fc5bf0c755 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -272,6 +272,71 @@ struct bgp_static { struct prefix gatewayIp; }; +/* Aggreagete address: + * + * advertise-map Set condition to advertise attribute + * as-set Generate AS set path information + * attribute-map Set attributes of aggregate + * route-map Set parameters of aggregate + * summary-only Filter more specific routes from updates + * suppress-map Conditionally filter more specific routes from updates + * <cr> + */ +struct bgp_aggregate { + /* Summary-only flag. */ + uint8_t summary_only; + + /* AS set generation. */ + uint8_t as_set; + + /* Route-map for aggregated route. */ + struct route_map *map; + + /* Suppress-count. */ + unsigned long count; + + /* Count of routes of origin type incomplete under this aggregate. */ + unsigned long incomplete_origin_count; + + /* Count of routes of origin type egp under this aggregate. */ + unsigned long egp_origin_count; + + /* Hash containing the communities of all the + * routes under this aggregate. + */ + struct hash *community_hash; + + /* Hash containing the extended communities of all the + * routes under this aggregate. + */ + struct hash *ecommunity_hash; + + /* Hash containing the large communities of all the + * routes under this aggregate. + */ + struct hash *lcommunity_hash; + + /* Hash containing the AS-Path of all the + * routes under this aggregate. + */ + struct hash *aspath_hash; + + /* Aggregate route's community. */ + struct community *community; + + /* Aggregate route's extended community. */ + struct ecommunity *ecommunity; + + /* Aggregate route's large community. */ + struct lcommunity *lcommunity; + + /* Aggregate route's as-path. */ + struct aspath *aspath; + + /* SAFI configuration. */ + safi_t safi; +}; + #define BGP_NEXTHOP_AFI_FROM_NHLEN(nhlen) \ ((nhlen) < IPV4_MAX_BYTELEN \ ? 0 \ @@ -279,7 +344,10 @@ struct bgp_static { #define BGP_ATTR_NEXTHOP_AFI_IP6(attr) \ (!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) \ - && ((attr)->mp_nexthop_len == 16 || (attr)->mp_nexthop_len == 32)) + && ((attr)->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL \ + || (attr)->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL \ + || (attr)->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL \ + || (attr)->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL)) #define BGP_PATH_COUNTABLE(BI) \ (!CHECK_FLAG((BI)->flags, BGP_PATH_HISTORY) \ && !CHECK_FLAG((BI)->flags, BGP_PATH_REMOVED)) @@ -341,6 +409,24 @@ static inline int bgp_fibupd_safi(safi_t safi) return 0; } +/* Flag if the route path's family matches params. */ +static inline bool is_pi_family_matching(struct bgp_path_info *pi, + afi_t afi, safi_t safi) +{ + struct bgp_table *table; + struct bgp_node *rn; + + rn = pi->net; + if (!rn) + return false; + table = bgp_node_table(rn); + if (table && + table->afi == afi && + table->safi == safi) + return true; + return false; +} + /* Prototypes. */ extern void bgp_rib_remove(struct bgp_node *rn, struct bgp_path_info *pi, struct peer *peer, afi_t afi, safi_t safi); @@ -357,6 +443,8 @@ extern void bgp_clear_route(struct peer *, afi_t, safi_t); extern void bgp_clear_route_all(struct peer *); extern void bgp_clear_adj_in(struct peer *, afi_t, safi_t); extern void bgp_clear_stale_route(struct peer *, afi_t, safi_t); +extern int bgp_outbound_policy_exists(struct peer *, struct bgp_filter *); +extern int bgp_inbound_policy_exists(struct peer *, struct bgp_filter *); extern struct bgp_node *bgp_afi_node_get(struct bgp_table *table, afi_t afi, safi_t safi, struct prefix *p, diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index e28acdfbae..c276f5ef7b 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -65,6 +65,10 @@ #include "bgpd/rfapi/bgp_rfapi_cfg.h" #endif +#ifndef VTYSH_EXTRACT_PL +#include "bgpd/bgp_routemap_clippy.c" +#endif + /* Memo of route-map commands. o Cisco route-map @@ -193,8 +197,6 @@ static void *route_value_compile(const char *arg) } rv = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_value)); - if (!rv) - return NULL; rv->action = action; rv->variable = var; @@ -320,8 +322,7 @@ static void route_match_peer_free(void *rule) { struct bgp_match_peer_compiled *pc = rule; - if (pc->interface) - XFREE(MTYPE_ROUTE_MAP_COMPILED, pc->interface); + XFREE(MTYPE_ROUTE_MAP_COMPILED, pc->interface); XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } @@ -833,8 +834,6 @@ static void *route_match_vni_compile(const char *arg) char *end = NULL; vni = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(vni_t)); - if (!vni) - return NULL; *vni = strtoul(arg, &end, 10); if (*end != '\0') { @@ -905,6 +904,53 @@ struct route_map_rule_cmd route_match_evpn_route_type_cmd = { "evpn route-type", route_match_evpn_route_type, route_match_evpn_route_type_compile, route_match_evpn_route_type_free}; +/* Route map commands for VRF route leak with source vrf matching */ +static route_map_result_t +route_match_vrl_source_vrf(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct bgp_path_info *path; + char *vrf_name; + + if (type == RMAP_BGP) { + vrf_name = rule; + path = (struct bgp_path_info *)object; + + if (strncmp(vrf_name, "n/a", VRF_NAMSIZ) == 0) + return RMAP_NOMATCH; + + if (path->extra == NULL) + return RMAP_NOMATCH; + + if (strncmp(vrf_name, vrf_id_to_name( + path->extra->bgp_orig->vrf_id), VRF_NAMSIZ) + == 0) + return RMAP_MATCH; + } + + return RMAP_NOMATCH; +} + +static void *route_match_vrl_source_vrf_compile(const char *arg) +{ + uint8_t *vrf_name = NULL; + + vrf_name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); + + return vrf_name; +} + +/* Free route map's compiled `route-type' value. */ +static void route_match_vrl_source_vrf_free(void *rule) +{ + XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_vrl_source_vrf_cmd = { + "source-vrf", route_match_vrl_source_vrf, + route_match_vrl_source_vrf_compile, + route_match_vrl_source_vrf_free}; + /* `match local-preference LOCAL-PREF' */ /* Match function return 1 if match is success else return zero. */ @@ -947,9 +993,6 @@ static void *route_match_local_pref_compile(const char *arg) local_pref = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint32_t)); - if (!local_pref) - return local_pref; - *local_pref = tmpval; return local_pref; } @@ -1504,8 +1547,7 @@ static void route_set_ip_nexthop_free(void *rule) { struct rmap_ip_nexthop_set *rins = rule; - if (rins->address) - XFREE(MTYPE_ROUTE_MAP_COMPILED, rins->address); + XFREE(MTYPE_ROUTE_MAP_COMPILED, rins->address); XFREE(MTYPE_ROUTE_MAP_COMPILED, rins); } @@ -1995,22 +2037,12 @@ static route_map_result_t route_set_lcommunity_delete(void *rule, static void *route_set_lcommunity_delete_compile(const char *arg) { struct rmap_community *rcom; - char *p; - char *str; - int len; rcom = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_community)); - p = strchr(arg, ' '); - if (p) { - len = p - arg; - str = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, len + 1); - memcpy(str, arg, len); - } else - str = NULL; - - rcom->name = str; + rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); rcom->name_hash = bgp_clist_hash_key(rcom->name); + return rcom; } @@ -2090,22 +2122,12 @@ static route_map_result_t route_set_community_delete( static void *route_set_community_delete_compile(const char *arg) { struct rmap_community *rcom; - char *p; - char *str; - int len; rcom = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_community)); - p = strchr(arg, ' '); - if (p) { - len = p - arg; - str = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, len + 1); - memcpy(str, arg, len); - } else - str = NULL; - - rcom->name = str; + rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); rcom->name_hash = bgp_clist_hash_key(rcom->name); + return rcom; } @@ -3054,10 +3076,8 @@ static int bgp_route_match_delete(struct vty *vty, const char *command, break; } - if (dep_name) - XFREE(MTYPE_ROUTE_MAP_RULE, dep_name); - if (rmap_name) - XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name); + XFREE(MTYPE_ROUTE_MAP_RULE, dep_name); + XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name); return retval; } @@ -3348,7 +3368,7 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name, "Processing route_map %s update on advertise type5 route command", rmap_name); - if (route_update) { + if (route_update && advertise_type5_routes(bgp, afi)) { bgp_evpn_withdraw_type5_routes(bgp, afi, safi); bgp_evpn_advertise_type5_routes(bgp, afi, safi); } @@ -3538,6 +3558,29 @@ DEFUN (no_match_evpn_default_route, RMAP_EVENT_MATCH_DELETED); } +DEFPY(match_vrl_source_vrf, + match_vrl_source_vrf_cmd, + "match source-vrf NAME$vrf_name", + MATCH_STR + "source vrf\n" + "The VRF name\n") +{ + return bgp_route_match_add(vty, "source-vrf", vrf_name, + RMAP_EVENT_MATCH_ADDED); +} + +DEFPY(no_match_vrl_source_vrf, + no_match_vrl_source_vrf_cmd, + "no match source-vrf NAME$vrf_name", + NO_STR + MATCH_STR + "source vrf\n" + "The VRF name\n") +{ + return bgp_route_match_delete(vty, "source-vrf", vrf_name, + RMAP_EVENT_MATCH_DELETED); +} + DEFUN (match_peer, match_peer_cmd, "match peer <A.B.C.D|X:X::X:X|WORD>", @@ -4277,17 +4320,10 @@ DEFUN (set_community_delete, "Delete matching communities\n") { int idx_comm_list = 2; - char *str; - - str = XCALLOC(MTYPE_TMP, - strlen(argv[idx_comm_list]->arg) + strlen(" delete") + 1); - strcpy(str, argv[idx_comm_list]->arg); - strcpy(str + strlen(argv[idx_comm_list]->arg), " delete"); generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), "comm-list", - str); + argv[idx_comm_list]->arg); - XFREE(MTYPE_TMP, str); return CMD_SUCCESS; } @@ -4376,16 +4412,9 @@ DEFUN (set_lcommunity_delete, "Large Community-list name\n" "Delete matching large communities\n") { - char *str; - - str = XCALLOC(MTYPE_TMP, strlen(argv[2]->arg) + strlen(" delete") + 1); - strcpy(str, argv[2]->arg); - strcpy(str + strlen(argv[2]->arg), " delete"); - generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), - "large-comm-list", str); + "large-comm-list", argv[2]->arg); - XFREE(MTYPE_TMP, str); return CMD_SUCCESS; } @@ -4992,6 +5021,7 @@ void bgp_route_map_init(void) route_map_install_match(&route_match_evpn_vni_cmd); route_map_install_match(&route_match_evpn_route_type_cmd); route_map_install_match(&route_match_evpn_default_route_cmd); + route_map_install_match(&route_match_vrl_source_vrf_cmd); route_map_install_set(&route_set_ip_nexthop_cmd); route_map_install_set(&route_set_local_pref_cmd); @@ -5030,6 +5060,8 @@ void bgp_route_map_init(void) install_element(RMAP_NODE, &no_match_evpn_route_type_cmd); install_element(RMAP_NODE, &match_evpn_default_route_cmd); install_element(RMAP_NODE, &no_match_evpn_default_route_cmd); + install_element(RMAP_NODE, &match_vrl_source_vrf_cmd); + install_element(RMAP_NODE, &no_match_vrl_source_vrf_cmd); install_element(RMAP_NODE, &match_aspath_cmd); install_element(RMAP_NODE, &no_match_aspath_cmd); diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index a38d78916c..b16b9f7b1e 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -125,7 +125,7 @@ static struct rtr_socket *create_rtr_socket(struct tr_socket *tr_socket); static struct cache *find_cache(const uint8_t preference); static int add_tcp_cache(const char *host, const char *port, const uint8_t preference); -static void print_record(const struct pfx_record *record, void *data); +static void print_record(const struct pfx_record *record, struct vty *vty); static int is_synchronized(void); static int is_running(void); static void route_match_free(void *rule); @@ -271,17 +271,23 @@ static struct cache *find_cache(const uint8_t preference) return NULL; } -static void print_record(const struct pfx_record *record, void *data) +static void print_record(const struct pfx_record *record, struct vty *vty) { char ip[INET6_ADDRSTRLEN]; + + lrtr_ip_addr_to_str(&record->prefix, ip, sizeof(ip)); + vty_out(vty, "%-40s %3u - %3u %10u\n", ip, record->min_len, + record->max_len, record->asn); +} + +static void print_record_cb(const struct pfx_record *record, void *data) +{ struct rpki_for_each_record_arg *arg = data; struct vty *vty = arg->vty; (*arg->prefix_amount)++; - lrtr_ip_addr_to_str(&record->prefix, ip, sizeof(ip)); - vty_out(vty, "%-40s %3u - %3u %10u\n", ip, record->min_len, - record->max_len, record->asn); + print_record(record, vty); } static struct rtr_mgr_group *get_groups(void) @@ -663,10 +669,10 @@ static void print_prefix_table(struct vty *vty) vty_out(vty, "%-40s %s %s\n", "Prefix", "Prefix Length", "Origin-AS"); arg.prefix_amount = &number_of_ipv4_prefixes; - pfx_table_for_each_ipv4_record(pfx_table, print_record, &arg); + pfx_table_for_each_ipv4_record(pfx_table, print_record_cb, &arg); arg.prefix_amount = &number_of_ipv6_prefixes; - pfx_table_for_each_ipv6_record(pfx_table, print_record, &arg); + pfx_table_for_each_ipv6_record(pfx_table, print_record_cb, &arg); vty_out(vty, "Number of IPv4 Prefixes: %u\n", number_of_ipv4_prefixes); vty_out(vty, "Number of IPv6 Prefixes: %u\n", number_of_ipv6_prefixes); @@ -1179,6 +1185,58 @@ DEFUN (show_rpki_prefix_table, return CMD_SUCCESS; } +DEFPY (show_rpki_prefix, + show_rpki_prefix_cmd, + "show rpki prefix <A.B.C.D/M|X:X::X:X/M> [(1-4294967295)$asn]", + SHOW_STR + RPKI_OUTPUT_STRING + "Lookup IP prefix and optionally ASN in prefix table\n" + "IPv4 prefix\n" + "IPv6 prefix\n" + "AS Number\n") +{ + + if (!is_synchronized()) { + vty_out(vty, "No Conection to RPKI cache server.\n"); + return CMD_WARNING; + } + + struct lrtr_ip_addr addr; + char addr_str[INET6_ADDRSTRLEN]; + size_t addr_len = strchr(prefix_str, '/') - prefix_str; + + memset(addr_str, 0, sizeof(addr_str)); + memcpy(addr_str, prefix_str, addr_len); + + if (lrtr_ip_str_to_addr(addr_str, &addr) != 0) { + vty_out(vty, "Invalid IP prefix\n"); + return CMD_WARNING; + } + + struct pfx_record *matches = NULL; + unsigned int match_count = 0; + enum pfxv_state result; + + if (pfx_table_validate_r(rtr_config->pfx_table, &matches, &match_count, + asn, &addr, prefix->prefixlen, &result) + != PFX_SUCCESS) { + vty_out(vty, "Prefix lookup failed"); + return CMD_WARNING; + } + + vty_out(vty, "%-40s %s %s\n", "Prefix", "Prefix Length", "Origin-AS"); + for (size_t i = 0; i < match_count; ++i) { + const struct pfx_record *record = &matches[i]; + + if (record->max_len >= prefix->prefixlen + && ((asn != 0 && asn == record->asn) || asn == 0)) { + print_record(&matches[i], vty); + } + } + + return CMD_SUCCESS; +} + DEFUN (show_rpki_cache_server, show_rpki_cache_server_cmd, "show rpki cache-server", @@ -1450,6 +1508,7 @@ static void install_cli_commands(void) install_element(ENABLE_NODE, &show_rpki_prefix_table_cmd); install_element(ENABLE_NODE, &show_rpki_cache_connection_cmd); install_element(ENABLE_NODE, &show_rpki_cache_server_cmd); + install_element(ENABLE_NODE, &show_rpki_prefix_cmd); /* Install debug commands */ install_element(CONFIG_NODE, &debug_rpki_cmd); diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c index c1321dd7dc..44cbeabd69 100644 --- a/bgpd/bgp_snmp.c +++ b/bgpd/bgp_snmp.c @@ -900,11 +900,10 @@ static int bgpTrapEstablished(struct peer *peer) oid_copy_addr(index, &addr, IN_ADDR_SIZE); - smux_trap(bgp_variables, sizeof bgp_variables / sizeof(struct variable), - bgp_trap_oid, sizeof bgp_trap_oid / sizeof(oid), bgp_oid, + smux_trap(bgp_variables, array_size(bgp_variables), bgp_trap_oid, + array_size(bgp_trap_oid), bgp_oid, sizeof bgp_oid / sizeof(oid), index, IN_ADDR_SIZE, - bgpTrapList, sizeof bgpTrapList / sizeof(struct trap_object), - BGPESTABLISHED); + bgpTrapList, array_size(bgpTrapList), BGPESTABLISHED); return 0; } @@ -920,11 +919,10 @@ static int bgpTrapBackwardTransition(struct peer *peer) oid_copy_addr(index, &addr, IN_ADDR_SIZE); - smux_trap(bgp_variables, sizeof bgp_variables / sizeof(struct variable), - bgp_trap_oid, sizeof bgp_trap_oid / sizeof(oid), bgp_oid, + smux_trap(bgp_variables, array_size(bgp_variables), bgp_trap_oid, + array_size(bgp_trap_oid), bgp_oid, sizeof bgp_oid / sizeof(oid), index, IN_ADDR_SIZE, - bgpTrapList, sizeof bgpTrapList / sizeof(struct trap_object), - BGPBACKWARDTRANSITION); + bgpTrapList, array_size(bgpTrapList), BGPBACKWARDTRANSITION); return 0; } diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c index 2e2ad88314..49a435120d 100644 --- a/bgpd/bgp_updgrp.c +++ b/bgpd/bgp_updgrp.c @@ -110,8 +110,7 @@ static void sync_init(struct update_subgroup *subgrp) static void sync_delete(struct update_subgroup *subgrp) { - if (subgrp->sync) - XFREE(MTYPE_BGP_SYNCHRONISE, subgrp->sync); + XFREE(MTYPE_BGP_SYNCHRONISE, subgrp->sync); subgrp->sync = NULL; if (subgrp->hash) hash_free(subgrp->hash); @@ -144,8 +143,7 @@ static void conf_copy(struct peer *dst, struct peer *src, afi_t afi, dst->v_routeadv = src->v_routeadv; dst->flags = src->flags; dst->af_flags[afi][safi] = src->af_flags[afi][safi]; - if (dst->host) - XFREE(MTYPE_BGP_PEER_HOST, dst->host); + XFREE(MTYPE_BGP_PEER_HOST, dst->host); dst->host = XSTRDUP(MTYPE_BGP_PEER_HOST, src->host); dst->cap = src->cap; @@ -208,27 +206,19 @@ static void conf_release(struct peer *src, afi_t afi, safi_t safi) srcfilter = &src->filter[afi][safi]; - if (src->default_rmap[afi][safi].name) - XFREE(MTYPE_ROUTE_MAP_NAME, src->default_rmap[afi][safi].name); + XFREE(MTYPE_ROUTE_MAP_NAME, src->default_rmap[afi][safi].name); - if (srcfilter->dlist[FILTER_OUT].name) - XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->dlist[FILTER_OUT].name); + XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->dlist[FILTER_OUT].name); - if (srcfilter->plist[FILTER_OUT].name) - XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->plist[FILTER_OUT].name); + XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->plist[FILTER_OUT].name); - if (srcfilter->aslist[FILTER_OUT].name) - XFREE(MTYPE_BGP_FILTER_NAME, - srcfilter->aslist[FILTER_OUT].name); + XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->aslist[FILTER_OUT].name); - if (srcfilter->map[RMAP_OUT].name) - XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->map[RMAP_OUT].name); + XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->map[RMAP_OUT].name); - if (srcfilter->usmap.name) - XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->usmap.name); + XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->usmap.name); - if (src->host) - XFREE(MTYPE_BGP_PEER_HOST, src->host); + XFREE(MTYPE_BGP_PEER_HOST, src->host); src->host = NULL; } @@ -440,7 +430,7 @@ static bool updgrp_hash_cmp(const void *p1, const void *p2) return false; if (pe1->addpath_type[afi][safi] != pe2->addpath_type[afi][safi]) - return 0; + return false; if ((pe1->cap & PEER_UPDGRP_CAP_FLAGS) != (pe2->cap & PEER_UPDGRP_CAP_FLAGS)) @@ -741,12 +731,10 @@ static void update_group_delete(struct update_group *updgrp) hash_release(updgrp->bgp->update_groups[updgrp->afid], updgrp); conf_release(updgrp->conf, updgrp->afi, updgrp->safi); - if (updgrp->conf->host) - XFREE(MTYPE_BGP_PEER_HOST, updgrp->conf->host); + XFREE(MTYPE_BGP_PEER_HOST, updgrp->conf->host); updgrp->conf->host = NULL; - if (updgrp->conf->ifname) - XFREE(MTYPE_BGP_PEER_IFNAME, updgrp->conf->ifname); + XFREE(MTYPE_BGP_PEER_IFNAME, updgrp->conf->ifname); XFREE(MTYPE_BGP_PEER, updgrp->conf); XFREE(MTYPE_BGP_UPDGRP, updgrp); @@ -1393,9 +1381,9 @@ static int updgrp_policy_update_walkcb(struct update_group *updgrp, void *arg) return UPDWALK_CONTINUE; } -static int update_group_walkcb(struct hash_backet *backet, void *arg) +static int update_group_walkcb(struct hash_bucket *bucket, void *arg) { - struct update_group *updgrp = backet->data; + struct update_group *updgrp = bucket->data; struct updwalk_context *wctx = arg; int ret = (*wctx->cb)(updgrp, wctx->context); return ret; diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index cbbf8b2302..66e306cba2 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -69,8 +69,7 @@ struct bpacket *bpacket_alloc(void) { struct bpacket *pkt; - pkt = (struct bpacket *)XCALLOC(MTYPE_BGP_PACKET, - sizeof(struct bpacket)); + pkt = XCALLOC(MTYPE_BGP_PACKET, sizeof(struct bpacket)); return pkt; } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index a6d985ab9f..5350ebeec7 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -1860,6 +1860,29 @@ DEFUN (no_bgp_always_compare_med, return CMD_SUCCESS; } + +DEFUN(bgp_ebgp_requires_policy, bgp_ebgp_requires_policy_cmd, + "bgp ebgp-requires-policy", + "BGP specific commands\n" + "Require in and out policy for eBGP peers (RFC8212)\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp->ebgp_requires_policy = DEFAULT_EBGP_POLICY_ENABLED; + return CMD_SUCCESS; +} + +DEFUN(no_bgp_ebgp_requires_policy, no_bgp_ebgp_requires_policy_cmd, + "no bgp ebgp-requires-policy", + NO_STR + "BGP specific commands\n" + "Require in and out policy for eBGP peers (RFC8212)\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp->ebgp_requires_policy = DEFAULT_EBGP_POLICY_DISABLED; + return CMD_SUCCESS; +} + + /* "bgp deterministic-med" configuration. */ DEFUN (bgp_deterministic_med, bgp_deterministic_med_cmd, @@ -1945,7 +1968,7 @@ DEFUN (no_bgp_graceful_restart, DEFUN (bgp_graceful_restart_stalepath_time, bgp_graceful_restart_stalepath_time_cmd, - "bgp graceful-restart stalepath-time (1-3600)", + "bgp graceful-restart stalepath-time (1-4095)", "BGP specific commands\n" "Graceful restart capability parameters\n" "Set the max time to hold onto restarting peer's stale paths\n" @@ -1962,7 +1985,7 @@ DEFUN (bgp_graceful_restart_stalepath_time, DEFUN (bgp_graceful_restart_restart_time, bgp_graceful_restart_restart_time_cmd, - "bgp graceful-restart restart-time (1-3600)", + "bgp graceful-restart restart-time (1-4095)", "BGP specific commands\n" "Graceful restart capability parameters\n" "Set the time to wait to delete stale routes before a BGP open message is received\n" @@ -1979,7 +2002,7 @@ DEFUN (bgp_graceful_restart_restart_time, DEFUN (no_bgp_graceful_restart_stalepath_time, no_bgp_graceful_restart_stalepath_time_cmd, - "no bgp graceful-restart stalepath-time [(1-3600)]", + "no bgp graceful-restart stalepath-time [(1-4095)]", NO_STR "BGP specific commands\n" "Graceful restart capability parameters\n" @@ -1994,7 +2017,7 @@ DEFUN (no_bgp_graceful_restart_stalepath_time, DEFUN (no_bgp_graceful_restart_restart_time, no_bgp_graceful_restart_restart_time_cmd, - "no bgp graceful-restart restart-time [(1-3600)]", + "no bgp graceful-restart restart-time [(1-4095)]", NO_STR "BGP specific commands\n" "Graceful restart capability parameters\n" @@ -2032,29 +2055,6 @@ DEFUN (no_bgp_graceful_restart_preserve_fw, return CMD_SUCCESS; } -static void bgp_redistribute_redo(struct bgp *bgp) -{ - afi_t afi; - int i; - struct list *red_list; - struct listnode *node; - struct bgp_redist *red; - - for (afi = AFI_IP; afi < AFI_MAX; afi++) { - for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { - - red_list = bgp->redist[afi][i]; - if (!red_list) - continue; - - for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) { - bgp_redistribute_resend(bgp, afi, i, - red->instance); - } - } - } -} - /* "bgp graceful-shutdown" configuration */ DEFUN (bgp_graceful_shutdown, bgp_graceful_shutdown_cmd, @@ -2818,18 +2818,23 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str, as = strtoul(as_str, NULL, 10); } - /* If peer is peer group, call proper function. */ + /* If peer is peer group or interface peer, call proper function. */ ret = str2sockunion(peer_str, &su); if (ret < 0) { - /* Check for peer by interface */ + struct peer *peer; + + /* Check if existing interface peer */ + peer = peer_lookup_by_conf_if(bgp, peer_str); + ret = peer_remote_as(bgp, NULL, peer_str, &as, as_type, afi, safi); - if (ret < 0) { + + /* if not interface peer, check peer-group settings */ + if (ret < 0 && !peer) { ret = peer_group_remote_as(bgp, peer_str, &as, as_type); if (ret < 0) { vty_out(vty, - "%% Create the peer-group or interface first or specify \"interface\" keyword\n"); - vty_out(vty, "%% if using an unnumbered interface neighbor\n"); + "%% Create the peer-group or interface first\n"); return CMD_WARNING_CONFIG_FAILED; } return CMD_SUCCESS; @@ -3228,7 +3233,7 @@ DEFUN (no_neighbor_interface_peer_group_remote_as, /* look up for neighbor by interface name config. */ peer = peer_lookup_by_conf_if(bgp, argv[idx_word]->arg); if (peer) { - peer_as_change(peer, 0, AS_SPECIFIED); + peer_as_change(peer, 0, AS_UNSPECIFIED); return CMD_SUCCESS; } @@ -7140,7 +7145,7 @@ DEFUN_NOSH (address_family_vpnv6, vty->node = BGP_VPNV6_NODE; return CMD_SUCCESS; } -#endif +#endif /* KEEP_OLD_VPN_COMMANDS */ DEFUN_NOSH (address_family_evpn, address_family_evpn_cmd, @@ -7590,10 +7595,10 @@ DEFUN (show_bgp_mac_hash, return CMD_SUCCESS; } -static void show_tip_entry(struct hash_backet *backet, void *args) +static void show_tip_entry(struct hash_bucket *bucket, void *args) { struct vty *vty = (struct vty *)args; - struct tip_addr *tip = (struct tip_addr *)backet->data; + struct tip_addr *tip = (struct tip_addr *)bucket->data; vty_out(vty, "addr: %s, count: %d\n", inet_ntoa(tip->addr), tip->refcnt); @@ -7606,7 +7611,7 @@ static void bgp_show_martian_nexthops(struct vty *vty, struct bgp *bgp) vty_out(vty, "Tunnel-ip database:\n"); hash_iterate(bgp->tip_hash, - (void (*)(struct hash_backet *, void *))show_tip_entry, + (void (*)(struct hash_bucket *, void *))show_tip_entry, vty); } @@ -7761,7 +7766,7 @@ DEFUN (show_bgp_memory, if ((count = mtype_stats_alloc(MTYPE_HASH_BACKET))) vty_out(vty, "%ld hash buckets, using %s of memory\n", count, mtype_memstr(memstrbuf, sizeof(memstrbuf), - count * sizeof(struct hash_backet))); + count * sizeof(struct hash_bucket))); if ((count = mtype_stats_alloc(MTYPE_BGP_REGEXP))) vty_out(vty, "%ld compiled regexes, using %s of memory\n", count, mtype_memstr(memstrbuf, sizeof(memstrbuf), @@ -8008,7 +8013,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, json, "ribMemory", ents * sizeof(struct bgp_node)); - ents = listcount(bgp->peer); + ents = bgp->af_peer_count[afi][safi]; json_object_int_add(json, "peerCount", ents); json_object_int_add(json, "peerMemory", ents * sizeof(struct peer)); @@ -8048,7 +8053,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, bgp_node))); /* Peer related usage */ - ents = listcount(bgp->peer); + ents = bgp->af_peer_count[afi][safi]; vty_out(vty, "Peers %ld, using %s of memory\n", ents, mtype_memstr( @@ -8499,7 +8504,7 @@ const char *afi_safi_json(afi_t afi, safi_t safi) } /* Show BGP peer's information. */ -enum show_type { show_all, show_peer }; +enum show_type { show_all, show_peer, show_ipv4_all, show_ipv6_all, show_ipv4_peer, show_ipv6_peer }; static void bgp_show_peer_afi_orf_cap(struct vty *vty, struct peer *p, afi_t afi, safi_t safi, @@ -8829,6 +8834,20 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi, json_addr, "routeMapForOutgoingAdvertisements", filter->map[RMAP_OUT].name); + /* ebgp-requires-policy (inbound) */ + if (p->bgp->ebgp_requires_policy == DEFAULT_EBGP_POLICY_ENABLED + && !bgp_inbound_policy_exists(p, filter)) + json_object_string_add( + json_addr, "inboundEbgpRequiresPolicy", + "Inbound updates discarded due to missing policy"); + + /* ebgp-requires-policy (outbound) */ + if (p->bgp->ebgp_requires_policy == DEFAULT_EBGP_POLICY_ENABLED + && (!bgp_outbound_policy_exists(p, filter))) + json_object_string_add( + json_addr, "outboundEbgpRequiresPolicy", + "Outbound updates discarded due to missing policy"); + /* unsuppress-map */ if (filter->usmap.name) json_object_string_add(json_addr, @@ -9105,6 +9124,18 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi, filter->map[RMAP_OUT].map ? "*" : "", filter->map[RMAP_OUT].name); + /* ebgp-requires-policy (inbound) */ + if (p->bgp->ebgp_requires_policy == DEFAULT_EBGP_POLICY_ENABLED + && !bgp_inbound_policy_exists(p, filter)) + vty_out(vty, + " Inbound updates discarded due to missing policy\n"); + + /* ebgp-requires-policy (outbound) */ + if (p->bgp->ebgp_requires_policy == DEFAULT_EBGP_POLICY_ENABLED + && !bgp_outbound_policy_exists(p, filter)) + vty_out(vty, + " Outbound updates discarded due to missing policy\n"); + /* unsuppress-map */ if (filter->usmap.name) vty_out(vty, @@ -10896,6 +10927,14 @@ static int bgp_show_neighbor(struct vty *vty, struct bgp *bgp, struct peer *peer; int find = 0; bool nbr_output = false; + afi_t afi = AFI_MAX; + safi_t safi = SAFI_MAX; + + if (type == show_ipv4_peer || type == show_ipv4_all) { + afi = AFI_IP; + } else if (type == show_ipv6_peer || type == show_ipv6_all) { + afi = AFI_IP6; + } for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)) @@ -10924,17 +10963,54 @@ static int bgp_show_neighbor(struct vty *vty, struct bgp *bgp, } } break; + case show_ipv4_peer: + case show_ipv6_peer: + FOREACH_SAFI (safi) { + if (peer->afc[afi][safi]) { + if (conf_if) { + if ((peer->conf_if + && !strcmp(peer->conf_if, conf_if)) + || (peer->hostname + && !strcmp(peer->hostname, conf_if))) { + find = 1; + bgp_show_peer(vty, peer, use_json, + json); + break; + } + } else { + if (sockunion_same(&peer->su, su)) { + find = 1; + bgp_show_peer(vty, peer, use_json, + json); + break; + } + } + } + } + break; + case show_ipv4_all: + case show_ipv6_all: + FOREACH_SAFI (safi) { + if (peer->afc[afi][safi]) { + bgp_show_peer(vty, peer, use_json, json); + nbr_output = true; + break; + } + } + break; } } - if (type == show_peer && !find) { + if ((type == show_peer || type == show_ipv4_peer || + type == show_ipv6_peer) && !find) { if (use_json) json_object_boolean_true_add(json, "bgpNoSuchNeighbor"); else vty_out(vty, "%% No such neighbor in this view/vrf\n"); } - if (type != show_peer && !nbr_output && !use_json) + if (type != show_peer && type != show_ipv4_peer && + type != show_ipv6_peer && !nbr_output && !use_json) vty_out(vty, "%% No BGP neighbors found\n"); if (use_json) { @@ -11000,7 +11076,8 @@ static void bgp_show_all_instances_neighbors_vty(struct vty *vty, : bgp->name); } - if (type == show_peer) { + if (type == show_peer || type == show_ipv4_peer || + type == show_ipv6_peer) { ret = str2sockunion(ip_str, &su); if (ret < 0) bgp_show_neighbor(vty, bgp, type, NULL, ip_str, @@ -11009,7 +11086,7 @@ static void bgp_show_all_instances_neighbors_vty(struct vty *vty, bgp_show_neighbor(vty, bgp, type, &su, NULL, use_json, json); } else { - bgp_show_neighbor(vty, bgp, show_all, NULL, NULL, + bgp_show_neighbor(vty, bgp, type, NULL, NULL, use_json, json); } json_object_free(json); @@ -11102,6 +11179,7 @@ DEFUN (show_ip_bgp_neighbors, char *vrf = NULL; char *sh_arg = NULL; enum show_type sh_type; + afi_t afi = AFI_MAX; bool uj = use_json(argc, argv); @@ -11117,13 +11195,29 @@ DEFUN (show_ip_bgp_neighbors, vrf = argv[idx + 1]->arg; idx++; + + if (argv_find(argv, argc, "ipv4", &idx)) { + sh_type = show_ipv4_all; + afi = AFI_IP; + } else if (argv_find(argv, argc, "ipv6", &idx)) { + sh_type = show_ipv6_all; + afi = AFI_IP6; + } else { + sh_type = show_all; + } + if (argv_find(argv, argc, "A.B.C.D", &idx) || argv_find(argv, argc, "X:X::X:X", &idx) || argv_find(argv, argc, "WORD", &idx)) { sh_type = show_peer; sh_arg = argv[idx]->arg; - } else - sh_type = show_all; + } + + if (sh_type == show_peer && afi == AFI_IP) { + sh_type = show_ipv4_peer; + } else if (sh_type == show_peer && afi == AFI_IP6) { + sh_type = show_ipv6_peer; + } return bgp_show_neighbor_vty(vty, vrf, sh_type, sh_arg, uj); } @@ -11147,12 +11241,12 @@ DEFUN (show_ip_bgp_paths, #include "hash.h" -static void community_show_all_iterator(struct hash_backet *backet, +static void community_show_all_iterator(struct hash_bucket *bucket, struct vty *vty) { struct community *com; - com = (struct community *)backet->data; + com = (struct community *)bucket->data; vty_out(vty, "[%p] (%ld) %s\n", (void *)com, com->refcnt, community_str(com, false)); } @@ -11169,19 +11263,19 @@ DEFUN (show_ip_bgp_community_info, vty_out(vty, "Address Refcnt Community\n"); hash_iterate(community_hash(), - (void (*)(struct hash_backet *, + (void (*)(struct hash_bucket *, void *))community_show_all_iterator, vty); return CMD_SUCCESS; } -static void lcommunity_show_all_iterator(struct hash_backet *backet, +static void lcommunity_show_all_iterator(struct hash_bucket *bucket, struct vty *vty) { struct lcommunity *lcom; - lcom = (struct lcommunity *)backet->data; + lcom = (struct lcommunity *)bucket->data; vty_out(vty, "[%p] (%ld) %s\n", (void *)lcom, lcom->refcnt, lcommunity_str(lcom, false)); } @@ -11198,7 +11292,7 @@ DEFUN (show_ip_bgp_lcommunity_info, vty_out(vty, "Address Refcnt Large-community\n"); hash_iterate(lcommunity_hash(), - (void (*)(struct hash_backet *, + (void (*)(struct hash_bucket *, void *))lcommunity_show_all_iterator, vty); @@ -11218,8 +11312,9 @@ DEFUN (show_ip_bgp_attr_info, return CMD_SUCCESS; } -static int bgp_show_route_leak_vty(struct vty *vty, const char *name, afi_t afi, - safi_t safi, bool use_json) +static int bgp_show_route_leak_vty(struct vty *vty, const char *name, + afi_t afi, safi_t safi, + bool use_json, json_object *json) { struct bgp *bgp; struct listnode *node; @@ -11228,13 +11323,10 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name, afi_t afi, char *ecom_str; vpn_policy_direction_t dir; - if (use_json) { - json_object *json = NULL; + if (json) { json_object *json_import_vrfs = NULL; json_object *json_export_vrfs = NULL; - json = json_object_new_object(); - bgp = name ? bgp_lookup_by_name(name) : bgp_get_default(); if (!bgp) { @@ -11305,11 +11397,12 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name, afi_t afi, XFREE(MTYPE_ECOMMUNITY_STR, ecom_str); } - vty_out(vty, "%s\n", - json_object_to_json_string_ext(json, + if (use_json) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - + json_object_free(json); + } } else { bgp = name ? bgp_lookup_by_name(name) : bgp_get_default(); @@ -11373,6 +11466,54 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name, afi_t afi, return CMD_SUCCESS; } +static int bgp_show_all_instance_route_leak_vty(struct vty *vty, afi_t afi, + safi_t safi, bool use_json) +{ + struct listnode *node, *nnode; + struct bgp *bgp; + char *vrf_name = NULL; + json_object *json = NULL; + json_object *json_vrf = NULL; + json_object *json_vrfs = NULL; + + if (use_json) { + json = json_object_new_object(); + json_vrfs = json_object_new_object(); + } + + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + + if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT) + vrf_name = bgp->name; + + if (use_json) { + json_vrf = json_object_new_object(); + } else { + vty_out(vty, "\nInstance %s:\n", + (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) + ? VRF_DEFAULT_NAME : bgp->name); + } + bgp_show_route_leak_vty(vty, vrf_name, afi, safi, 0, json_vrf); + if (use_json) { + if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) + json_object_object_add(json_vrfs, + VRF_DEFAULT_NAME, json_vrf); + else + json_object_object_add(json_vrfs, vrf_name, + json_vrf); + } + } + + if (use_json) { + json_object_object_add(json, "vrfs", json_vrfs); + vty_out(vty, "%s\n", json_object_to_json_string_ext(json, + JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } + + return CMD_SUCCESS; +} + /* "show [ip] bgp route-leak" command. */ DEFUN (show_ip_bgp_route_leak, show_ip_bgp_route_leak_cmd, @@ -11392,6 +11533,7 @@ DEFUN (show_ip_bgp_route_leak, bool uj = use_json(argc, argv); int idx = 0; + json_object *json = NULL; /* show [ip] bgp */ if (argv_find(argv, argc, "ip", &idx)) { @@ -11421,7 +11563,13 @@ DEFUN (show_ip_bgp_route_leak, return CMD_WARNING; } - return bgp_show_route_leak_vty(vty, vrf, afi, safi, uj); + if (vrf && strmatch(vrf, "all")) + return bgp_show_all_instance_route_leak_vty(vty, afi, safi, uj); + + if (uj) + json = json_object_new_object(); + + return bgp_show_route_leak_vty(vty, vrf, afi, safi, uj, json); } static void bgp_show_all_instances_updgrps_vty(struct vty *vty, afi_t afi, @@ -12823,6 +12971,10 @@ void bgp_vty_init(void) install_element(BGP_NODE, &bgp_always_compare_med_cmd); install_element(BGP_NODE, &no_bgp_always_compare_med_cmd); + /* bgp ebgp-requires-policy */ + install_element(BGP_NODE, &bgp_ebgp_requires_policy_cmd); + install_element(BGP_NODE, &no_bgp_ebgp_requires_policy_cmd); + /* "bgp deterministic-med" commands */ install_element(BGP_NODE, &bgp_deterministic_med_cmd); install_element(BGP_NODE, &no_bgp_deterministic_med_cmd); @@ -14403,8 +14555,7 @@ static int lcommunity_list_set_vty(struct vty *vty, int argc, /* Free temporary community list string allocated by argv_concat(). */ - if (str) - XFREE(MTYPE_TMP, str); + XFREE(MTYPE_TMP, str); if (ret < 0) { community_list_perror(vty, ret); @@ -14455,8 +14606,7 @@ static int lcommunity_list_unset_vty(struct vty *vty, int argc, /* Free temporary community list string allocated by argv_concat(). */ - if (str) - XFREE(MTYPE_TMP, str); + XFREE(MTYPE_TMP, str); if (ret < 0) { community_list_perror(vty, ret); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 3f18d69a2d..d9749863ec 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -945,14 +945,17 @@ bgp_path_info_to_ipv6_nexthop(struct bgp_path_info *path, ifindex_t *ifindex) struct in6_addr *nexthop = NULL; /* Only global address nexthop exists. */ - if (path->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL) { + if (path->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL + || path->attr->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL) { nexthop = &path->attr->mp_nexthop_global; if (IN6_IS_ADDR_LINKLOCAL(nexthop)) *ifindex = path->attr->nh_ifindex; } /* If both global and link-local address present. */ - if (path->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { + if (path->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL + || path->attr->mp_nexthop_len + == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) { /* Check if route-map is set to prefer global over link-local */ if (path->attr->mp_nexthop_prefer_global) { nexthop = &path->attr->mp_nexthop_global; @@ -1111,20 +1114,24 @@ int bgp_zebra_get_table_range(uint32_t chunk_size, } static int update_ipv4nh_for_route_install(int nh_othervrf, + struct bgp *nh_bgp, struct in_addr *nexthop, struct attr *attr, bool is_evpn, struct zapi_nexthop *api_nh) { api_nh->gate.ipv4 = *nexthop; + api_nh->vrf_id = nh_bgp->vrf_id; /* Need to set fields appropriately for EVPN routes imported into * a VRF (which are programmed as onlink on l3-vni SVI) as well as * connected routes leaked into a VRF. */ - if (is_evpn) + if (is_evpn) { api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX; - else if (nh_othervrf && + api_nh->onlink = true; + api_nh->ifindex = nh_bgp->l3vni_svi_ifindex; + } else if (nh_othervrf && api_nh->gate.ipv4.s_addr == INADDR_ANY) { api_nh->type = NEXTHOP_TYPE_IFINDEX; api_nh->ifindex = attr->nh_ifindex; @@ -1135,7 +1142,8 @@ static int update_ipv4nh_for_route_install(int nh_othervrf, } static int -update_ipv6nh_for_route_install(int nh_othervrf, struct in6_addr *nexthop, +update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp, + struct in6_addr *nexthop, ifindex_t ifindex, struct bgp_path_info *pi, struct bgp_path_info *best_pi, bool is_evpn, struct zapi_nexthop *api_nh) @@ -1143,10 +1151,13 @@ update_ipv6nh_for_route_install(int nh_othervrf, struct in6_addr *nexthop, struct attr *attr; attr = pi->attr; + api_nh->vrf_id = nh_bgp->vrf_id; - if (is_evpn) + if (is_evpn) { api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX; - else if (nh_othervrf) { + api_nh->onlink = true; + api_nh->ifindex = nh_bgp->l3vni_svi_ifindex; + } else if (nh_othervrf) { if (IN6_IS_ADDR_UNSPECIFIED(nexthop)) { api_nh->type = NEXTHOP_TYPE_IFINDEX; api_nh->ifindex = attr->nh_ifindex; @@ -1297,8 +1308,6 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, continue; api_nh = &api.nexthops[valid_nh_count]; - api_nh->vrf_id = nh_othervrf ? info->extra->bgp_orig->vrf_id - : bgp->vrf_id; if (nh_family == AF_INET) { if (bgp_debug_zebra(&api.prefix)) { if (mpinfo->extra) { @@ -1338,6 +1347,8 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, nh_updated = update_ipv4nh_for_route_install( nh_othervrf, + nh_othervrf ? + info->extra->bgp_orig : bgp, &mpinfo_cp->attr->nexthop, mpinfo_cp->attr, is_evpn, api_nh); } else { @@ -1372,7 +1383,9 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, nexthop = bgp_path_info_to_ipv6_nexthop(mpinfo_cp, &ifindex); nh_updated = update_ipv6nh_for_route_install( - nh_othervrf, nexthop, ifindex, + nh_othervrf, nh_othervrf ? + info->extra->bgp_orig : bgp, + nexthop, ifindex, mpinfo, info, is_evpn, api_nh); } @@ -1573,8 +1586,7 @@ struct bgp_redist *bgp_redist_add(struct bgp *bgp, afi_t afi, uint8_t type, bgp->redist[afi][type] = list_new(); red_list = bgp->redist[afi][type]; - red = (struct bgp_redist *)XCALLOC(MTYPE_BGP_REDIST, - sizeof(struct bgp_redist)); + red = XCALLOC(MTYPE_BGP_REDIST, sizeof(struct bgp_redist)); red->instance = instance; listnode_add(red_list, red); @@ -1681,8 +1693,7 @@ int bgp_redistribute_rmap_set(struct bgp_redist *red, const char *name, if (red->rmap.name && (strcmp(red->rmap.name, name) == 0)) return 0; - if (red->rmap.name) - XFREE(MTYPE_ROUTE_MAP_NAME, red->rmap.name); + XFREE(MTYPE_ROUTE_MAP_NAME, red->rmap.name); /* Decrement the count for existing routemap and * increment the count for new route map. */ @@ -1795,8 +1806,7 @@ int bgp_redistribute_unset(struct bgp *bgp, afi_t afi, int type, bgp_redistribute_unreg(bgp, afi, type, instance); /* Unset route-map. */ - if (red->rmap.name) - XFREE(MTYPE_ROUTE_MAP_NAME, red->rmap.name); + XFREE(MTYPE_ROUTE_MAP_NAME, red->rmap.name); route_map_counter_decrement(red->rmap.map); red->rmap.name = NULL; red->rmap.map = NULL; @@ -1810,23 +1820,42 @@ int bgp_redistribute_unset(struct bgp *bgp, afi_t afi, int type, return CMD_SUCCESS; } -/* Update redistribute vrf bitmap during triggers like - restart networking or delete/add VRFs */ -void bgp_update_redist_vrf_bitmaps(struct bgp *bgp, vrf_id_t old_vrf_id) +void bgp_redistribute_redo(struct bgp *bgp) +{ + afi_t afi; + int i; + struct list *red_list; + struct listnode *node; + struct bgp_redist *red; + + for (afi = AFI_IP; afi < AFI_MAX; afi++) { + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { + + red_list = bgp->redist[afi][i]; + if (!red_list) + continue; + + for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) { + bgp_redistribute_resend(bgp, afi, i, + red->instance); + } + } + } +} + +/* Unset redistribute vrf bitmap during triggers like + restart networking or delete VRFs */ +void bgp_unset_redist_vrf_bitmaps(struct bgp *bgp, vrf_id_t old_vrf_id) { int i; afi_t afi; for (afi = AFI_IP; afi < AFI_MAX; afi++) for (i = 0; i < ZEBRA_ROUTE_MAX; i++) - if ((old_vrf_id == VRF_UNKNOWN) - || vrf_bitmap_check(zclient->redist[afi][i], - old_vrf_id)) { + if (vrf_bitmap_check(zclient->redist[afi][i], + old_vrf_id)) vrf_bitmap_unset(zclient->redist[afi][i], old_vrf_id); - vrf_bitmap_set(zclient->redist[afi][i], - bgp->vrf_id); - } return; } @@ -2486,6 +2515,7 @@ static int bgp_zebra_process_local_l3vni(int cmd, struct zclient *zclient, struct ethaddr rmac; struct in_addr originator_ip; struct stream *s; + ifindex_t svi_ifindex; memset(&rmac, 0, sizeof(struct ethaddr)); memset(&originator_ip, 0, sizeof(struct in_addr)); @@ -2495,20 +2525,24 @@ static int bgp_zebra_process_local_l3vni(int cmd, struct zclient *zclient, stream_get(&rmac, s, sizeof(struct ethaddr)); originator_ip.s_addr = stream_get_ipv4(s); stream_get(&filter, s, sizeof(int)); - } + svi_ifindex = stream_getl(s); - if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Rx L3-VNI %s VRF %s VNI %u RMAC %s filter %s", - (cmd == ZEBRA_L3VNI_ADD) ? "add" : "del", - vrf_id_to_name(vrf_id), l3vni, - prefix_mac2str(&rmac, buf, sizeof(buf)), - filter ? "prefix-routes-only" : "none"); + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("Rx L3-VNI ADD VRF %s VNI %u RMAC %s filter %s svi-if %u", + vrf_id_to_name(vrf_id), l3vni, + prefix_mac2str(&rmac, buf, sizeof(buf)), + filter ? "prefix-routes-only" : "none", + svi_ifindex); - if (cmd == ZEBRA_L3VNI_ADD) bgp_evpn_local_l3vni_add(l3vni, vrf_id, &rmac, originator_ip, - filter); - else + filter, svi_ifindex); + } else { + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("Rx L3-VNI DEL VRF %s VNI %u", + vrf_id_to_name(vrf_id), l3vni); + bgp_evpn_local_l3vni_del(l3vni, vrf_id); + } return 0; } diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index fc19c5e17f..b912870b80 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -49,6 +49,7 @@ extern void bgp_zebra_terminate_radv(struct bgp *bgp, struct peer *peer); extern void bgp_zebra_instance_register(struct bgp *); extern void bgp_zebra_instance_deregister(struct bgp *); +extern void bgp_redistribute_redo(struct bgp *bgp); extern struct bgp_redist *bgp_redist_lookup(struct bgp *, afi_t, uint8_t, unsigned short); extern struct bgp_redist *bgp_redist_add(struct bgp *, afi_t, uint8_t, diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index aceb990534..54e8f5f369 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -116,7 +116,7 @@ static int bgp_check_main_socket(bool create, struct bgp *bgp) { static int bgp_server_main_created; - if (create == true) { + if (create) { if (bgp_server_main_created) return 0; if (bgp_socket(bgp, bm->port, bm->address) < 0) @@ -707,6 +707,7 @@ struct peer_af *peer_af_create(struct peer *peer, afi_t afi, safi_t safi) { struct peer_af *af; int afid; + struct bgp *bgp; if (!peer) return NULL; @@ -715,6 +716,7 @@ struct peer_af *peer_af_create(struct peer *peer, afi_t afi, safi_t safi) if (afid >= BGP_AF_MAX) return NULL; + bgp = peer->bgp; assert(peer->peer_af_array[afid] == NULL); /* Allocate new peer af */ @@ -725,6 +727,7 @@ struct peer_af *peer_af_create(struct peer *peer, afi_t afi, safi_t safi) af->safi = safi; af->afid = afid; af->peer = peer; + bgp->af_peer_count[afi][safi]++; return af; } @@ -747,6 +750,7 @@ int peer_af_delete(struct peer *peer, afi_t afi, safi_t safi) { struct peer_af *af; int afid; + struct bgp *bgp; if (!peer) return -1; @@ -759,6 +763,7 @@ int peer_af_delete(struct peer *peer, afi_t afi, safi_t safi) if (!af) return -1; + bgp = peer->bgp; bgp_stop_announce_route_timer(af); if (PAF_SUBGRP(af)) { @@ -768,8 +773,12 @@ int peer_af_delete(struct peer *peer, afi_t afi, safi_t safi) af->subgroup->id, peer->host); } + update_subgroup_remove_peer(af->subgroup, af); + if (bgp->af_peer_count[afi][safi]) + bgp->af_peer_count[afi][safi]--; + peer->peer_af_array[afid] = NULL; XFREE(MTYPE_BGP_PEER_AF, af); return 0; @@ -1099,8 +1108,7 @@ static void peer_free(struct peer *peer) peer->update_if = NULL; } - if (peer->notify.data) - XFREE(MTYPE_TMP, peer->notify.data); + XFREE(MTYPE_TMP, peer->notify.data); memset(&peer->notify, 0, sizeof(struct bgp_notify)); if (peer->clear_node_queue) @@ -1322,8 +1330,7 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src) peer_dst->update_source = sockunion_dup(peer_src->update_source); } else if (peer_src->update_if) { - if (peer_dst->update_if) - XFREE(MTYPE_PEER_UPDATE_SOURCE, peer_dst->update_if); + XFREE(MTYPE_PEER_UPDATE_SOURCE, peer_dst->update_if); if (peer_dst->update_source) { sockunion_free(peer_dst->update_source); peer_dst->update_source = NULL; @@ -1333,8 +1340,7 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src) } if (peer_src->ifname) { - if (peer_dst->ifname) - XFREE(MTYPE_BGP_PEER_IFNAME, peer_dst->ifname); + XFREE(MTYPE_BGP_PEER_IFNAME, peer_dst->ifname); peer_dst->ifname = XSTRDUP(MTYPE_BGP_PEER_IFNAME, peer_src->ifname); @@ -1541,14 +1547,12 @@ struct peer *peer_create(union sockunion *su, const char *conf_if, peer->su = *su; else bgp_peer_conf_if_to_su_update(peer); - if (peer->host) - XFREE(MTYPE_BGP_PEER_HOST, peer->host); + XFREE(MTYPE_BGP_PEER_HOST, peer->host); peer->host = XSTRDUP(MTYPE_BGP_PEER_HOST, conf_if); } else if (su) { peer->su = *su; sockunion2str(su, buf, SU_ADDRSTRLEN); - if (peer->host) - XFREE(MTYPE_BGP_PEER_HOST, peer->host); + XFREE(MTYPE_BGP_PEER_HOST, peer->host); peer->host = XSTRDUP(MTYPE_BGP_PEER_HOST, buf); } peer->local_as = local_as; @@ -2384,8 +2388,7 @@ static int peer_group_cmp(struct peer_group *g1, struct peer_group *g2) /* Peer group cofiguration. */ static struct peer_group *peer_group_new(void) { - return (struct peer_group *)XCALLOC(MTYPE_PEER_GROUP, - sizeof(struct peer_group)); + return XCALLOC(MTYPE_PEER_GROUP, sizeof(struct peer_group)); } static void peer_group_free(struct peer_group *group) @@ -2416,8 +2419,7 @@ struct peer_group *peer_group_get(struct bgp *bgp, const char *name) group = peer_group_new(); group->bgp = bgp; - if (group->name) - XFREE(MTYPE_PEER_GROUP_HOST, group->name); + XFREE(MTYPE_PEER_GROUP_HOST, group->name); group->name = XSTRDUP(MTYPE_PEER_GROUP_HOST, name); group->peer = list_new(); for (afi = AFI_IP; afi < AFI_MAX; afi++) @@ -2425,8 +2427,7 @@ struct peer_group *peer_group_get(struct bgp *bgp, const char *name) group->conf = peer_new(bgp); if (!bgp_flag_check(bgp, BGP_FLAG_NO_DEFAULT_IPV4)) group->conf->afc[AFI_IP][SAFI_UNICAST] = 1; - if (group->conf->host) - XFREE(MTYPE_BGP_PEER_HOST, group->conf->host); + XFREE(MTYPE_BGP_PEER_HOST, group->conf->host); group->conf->host = XSTRDUP(MTYPE_BGP_PEER_HOST, name); group->conf->group = group; group->conf->as = 0; @@ -2722,7 +2723,7 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer, peer->sort = group->conf->sort; } - if (!group->conf->as) { + if (!group->conf->as && peer_sort(peer)) { if (peer_sort(group->conf) != BGP_PEER_INTERNAL && peer_sort(group->conf) != peer_sort(peer)) { if (as) @@ -2886,8 +2887,7 @@ static struct bgp *bgp_create(as_t *as, const char *name, bgp->vrf_id = (inst_type == BGP_INSTANCE_TYPE_DEFAULT) ? VRF_DEFAULT : VRF_UNKNOWN; bgp->peer_self = peer_new(bgp); - if (bgp->peer_self->host) - XFREE(MTYPE_BGP_PEER_HOST, bgp->peer_self->host); + XFREE(MTYPE_BGP_PEER_HOST, bgp->peer_self->host); bgp->peer_self->host = XSTRDUP(MTYPE_BGP_PEER_HOST, "Static announcement"); if (bgp->peer_self->hostname != NULL) { @@ -2936,6 +2936,7 @@ static struct bgp *bgp_create(as_t *as, const char *name, bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; bgp->dynamic_neighbors_limit = BGP_DYNAMIC_NEIGHBORS_LIMIT_DEFAULT; bgp->dynamic_neighbors_count = 0; + bgp->ebgp_requires_policy = DEFAULT_EBGP_POLICY_DISABLED; #if DFLT_BGP_IMPORT_CHECK bgp_flag_set(bgp, BGP_FLAG_IMPORT_CHECK); #endif @@ -3403,8 +3404,7 @@ void bgp_free(struct bgp *bgp) if (bgp->rib[afi][safi]) bgp_table_finish(&bgp->rib[afi][safi]); rmap = &bgp->table_map[afi][safi]; - if (rmap->name) - XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name); + XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name); } bgp_scan_finish(bgp); @@ -3434,10 +3434,8 @@ void bgp_free(struct bgp *bgp) ecommunity_free(&bgp->vpn_policy[afi].rtlist[dir]); } - if (bgp->name) - XFREE(MTYPE_BGP, bgp->name); - if (bgp->name_pretty) - XFREE(MTYPE_BGP, bgp->name_pretty); + XFREE(MTYPE_BGP, bgp->name); + XFREE(MTYPE_BGP, bgp->name_pretty); XFREE(MTYPE_BGP, bgp); } @@ -3810,6 +3808,7 @@ static const struct peer_flag_action peer_flag_action_list[] = { {PEER_FLAG_DISABLE_CONNECTED_CHECK, 0, peer_change_reset}, {PEER_FLAG_CAPABILITY_ENHE, 0, peer_change_reset}, {PEER_FLAG_ENFORCE_FIRST_AS, 0, peer_change_reset_in}, + {PEER_FLAG_IFPEER_V6ONLY, 0, peer_change_reset}, {PEER_FLAG_ROUTEADV, 0, peer_change_none}, {PEER_FLAG_TIMER, 0, peer_change_none}, {PEER_FLAG_TIMER_CONNECT, 0, peer_change_none}, @@ -4366,8 +4365,7 @@ int peer_ebgp_multihop_unset(struct peer *peer) /* Neighbor description. */ int peer_description_set(struct peer *peer, const char *desc) { - if (peer->desc) - XFREE(MTYPE_PEER_DESC, peer->desc); + XFREE(MTYPE_PEER_DESC, peer->desc); peer->desc = XSTRDUP(MTYPE_PEER_DESC, desc); @@ -4376,8 +4374,7 @@ int peer_description_set(struct peer *peer, const char *desc) int peer_description_unset(struct peer *peer) { - if (peer->desc) - XFREE(MTYPE_PEER_DESC, peer->desc); + XFREE(MTYPE_PEER_DESC, peer->desc); peer->desc = NULL; @@ -5123,15 +5120,13 @@ int peer_advertise_interval_unset(struct peer *peer) /* neighbor interface */ void peer_interface_set(struct peer *peer, const char *str) { - if (peer->ifname) - XFREE(MTYPE_BGP_PEER_IFNAME, peer->ifname); + XFREE(MTYPE_BGP_PEER_IFNAME, peer->ifname); peer->ifname = XSTRDUP(MTYPE_BGP_PEER_IFNAME, str); } void peer_interface_unset(struct peer *peer) { - if (peer->ifname) - XFREE(MTYPE_BGP_PEER_IFNAME, peer->ifname); + XFREE(MTYPE_BGP_PEER_IFNAME, peer->ifname); peer->ifname = NULL; } @@ -7577,6 +7572,11 @@ int bgp_config_write(struct vty *vty) if (bgp_flag_check(bgp, BGP_FLAG_ALWAYS_COMPARE_MED)) vty_out(vty, " bgp always-compare-med\n"); + /* RFC8212 default eBGP policy. */ + if (bgp->ebgp_requires_policy + == DEFAULT_EBGP_POLICY_ENABLED) + vty_out(vty, " bgp ebgp-requires-policy\n"); + /* BGP default ipv4-unicast. */ if (bgp_flag_check(bgp, BGP_FLAG_NO_DEFAULT_IPV4)) vty_out(vty, " no bgp default ipv4-unicast\n"); @@ -7857,9 +7857,11 @@ void bgp_master_init(struct thread_master *master) */ static void bgp_if_finish(struct bgp *bgp) { - struct vrf *vrf = vrf_lookup_by_id(bgp->vrf_id); + struct vrf *vrf; struct interface *ifp; + vrf = bgp_vrf_lookup_by_instance_type(bgp); + if (bgp->inst_type == BGP_INSTANCE_TYPE_VIEW || !vrf) return; diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index e58c46e240..91666fb374 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -99,6 +99,9 @@ enum bgp_af_index { for (afi = AFI_IP; afi < AFI_MAX; afi++) \ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) +#define FOREACH_SAFI(safi) \ + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + extern struct frr_pthread *bgp_pth_io; extern struct frr_pthread *bgp_pth_ka; @@ -374,6 +377,9 @@ struct bgp { #define BGP_CONFIG_VRF_TO_VRF_IMPORT (1 << 7) #define BGP_CONFIG_VRF_TO_VRF_EXPORT (1 << 8) + /* BGP per AF peer count */ + uint32_t af_peer_count[AFI_MAX][SAFI_MAX]; + /* Route table for next-hop lookup cache. */ struct bgp_table *nexthop_cache_table[AFI_MAX]; @@ -487,6 +493,11 @@ struct bgp { /* EVPN enable - advertise local VNIs and their MACs etc. */ int advertise_all_vni; + /* RFC 8212 - prevent route leaks. */ + int ebgp_requires_policy; +#define DEFAULT_EBGP_POLICY_DISABLED 0 +#define DEFAULT_EBGP_POLICY_ENABLED 1 + struct bgp_evpn_info *evpn_info; /* EVPN - use RFC 8365 to auto-derive RT */ @@ -512,6 +523,9 @@ struct bgp { /* originator ip - to be used as NH for type-5 routes */ struct in_addr originator_ip; + /* SVI associated with the L3-VNI corresponding to this vrf */ + ifindex_t l3vni_svi_ifindex; + /* vrf flags */ uint32_t vrf_flags; #define BGP_VRF_AUTO (1 << 0) @@ -1893,7 +1907,7 @@ static inline void bgp_vrf_unlink(struct bgp *bgp, struct vrf *vrf) bgp->vrf_id = VRF_UNKNOWN; } -extern void bgp_update_redist_vrf_bitmaps(struct bgp *, vrf_id_t); +extern void bgp_unset_redist_vrf_bitmaps(struct bgp *, vrf_id_t); /* For benefit of rfapi */ extern struct peer *peer_new(struct bgp *bgp); diff --git a/bgpd/rfapi/bgp_rfapi_cfg.c b/bgpd/rfapi/bgp_rfapi_cfg.c index 13713c11f2..2220f0ed9a 100644 --- a/bgpd/rfapi/bgp_rfapi_cfg.c +++ b/bgpd/rfapi/bgp_rfapi_cfg.c @@ -1217,8 +1217,6 @@ DEFUN (vnc_nve_group_redist_bgpdirect_no_prefixlist, if (rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi]) free(rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi]); - route_map_counter_decrement( - rfg->plist_redist[ZEBRA_ROUTE_BGP_DIRECT][afi]); rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi] = NULL; rfg->plist_redist[ZEBRA_ROUTE_BGP_DIRECT][afi] = NULL; @@ -3459,8 +3457,7 @@ static void bgp_rfapi_delete_l2_group(struct vty *vty, /* NULL = no output */ ecommunity_free(&rfg->rt_export_list); if (rfg->labels) list_delete(&rfg->labels); - if (rfg->rfp_cfg) - XFREE(MTYPE_RFAPI_RFP_GROUP_CFG, rfg->rfp_cfg); + XFREE(MTYPE_RFAPI_RFP_GROUP_CFG, rfg->rfp_cfg); listnode_delete(bgp->rfapi_cfg->l2_groups, rfg); rfapi_l2_group_del(rfg); @@ -3817,8 +3814,7 @@ struct rfapi_cfg *bgp_rfapi_cfg_new(struct rfapi_rfp_cfg *cfg) struct rfapi_cfg *h; afi_t afi; - h = (struct rfapi_cfg *)XCALLOC(MTYPE_RFAPI_CFG, - sizeof(struct rfapi_cfg)); + h = XCALLOC(MTYPE_RFAPI_CFG, sizeof(struct rfapi_cfg)); assert(h); h->nve_groups_sequential = list_new(); @@ -3880,8 +3876,7 @@ void bgp_rfapi_cfg_destroy(struct bgp *bgp, struct rfapi_cfg *h) ecommunity_free(&h->default_rt_export_list); if (h->default_rt_import_list) ecommunity_free(&h->default_rt_import_list); - if (h->default_rfp_cfg) - XFREE(MTYPE_RFAPI_RFP_GROUP_CFG, h->default_rfp_cfg); + XFREE(MTYPE_RFAPI_RFP_GROUP_CFG, h->default_rfp_cfg); for (afi = AFI_IP; afi < AFI_MAX; afi++) { agg_table_finish(h->nve_groups_vn[afi]); agg_table_finish(h->nve_groups_un[afi]); diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c index 6b37073e0e..93729c1476 100644 --- a/bgpd/rfapi/rfapi_import.c +++ b/bgpd/rfapi/rfapi_import.c @@ -2190,7 +2190,7 @@ static void rfapiItBiIndexDump(struct agg_node *rn) prefix2str(&k->extra->vnc.import.aux_prefix, buf_aux_pfx, sizeof(buf_aux_pfx)); } else - strncpy(buf_aux_pfx, "(none)", PREFIX_STRLEN); + strlcpy(buf_aux_pfx, "(none)", sizeof(buf_aux_pfx)); vnc_zlog_debug_verbose("bpi %p, peer %p, rd %s, aux_prefix %s", k, k->peer, buf, buf_aux_pfx); @@ -2221,7 +2221,7 @@ static struct bgp_path_info *rfapiItBiIndexSearch( prefix2str(aux_prefix, buf_aux_pfx, sizeof(buf_aux_pfx)); } else - strncpy(buf_aux_pfx, "(nil)", sizeof(buf_aux_pfx)); + strlcpy(buf_aux_pfx, "(nil)", sizeof(buf_aux_pfx)); vnc_zlog_debug_verbose("%s want prd=%s, peer=%p, aux_prefix=%s", __func__, @@ -4285,7 +4285,7 @@ struct rfapi *bgp_rfapi_new(struct bgp *bgp) assert(bgp->rfapi_cfg == NULL); - h = (struct rfapi *)XCALLOC(MTYPE_RFAPI, sizeof(struct rfapi)); + h = XCALLOC(MTYPE_RFAPI, sizeof(struct rfapi)); for (afi = AFI_IP; afi < AFI_MAX; afi++) { h->un[afi] = agg_table_init(); diff --git a/bgpd/rfapi/vnc_debug.c b/bgpd/rfapi/vnc_debug.c index 2b08ea493c..cb9799870b 100644 --- a/bgpd/rfapi/vnc_debug.c +++ b/bgpd/rfapi/vnc_debug.c @@ -190,7 +190,7 @@ static int bgp_vnc_config_write_debug(struct vty *vty) int write = 0; size_t i; - for (i = 0; i < (sizeof(vncdebug) / sizeof(struct vnc_debug)); ++i) { + for (i = 0; i < array_size(vncdebug); ++i) { if (conf_vnc_debug & vncdebug[i].bit) { vty_out(vty, "debug bgp vnc %s\n", vncdebug[i].name); write++; diff --git a/bgpd/rfapi/vnc_zebra.c b/bgpd/rfapi/vnc_zebra.c index 98f719969c..b08e922962 100644 --- a/bgpd/rfapi/vnc_zebra.c +++ b/bgpd/rfapi/vnc_zebra.c @@ -608,10 +608,8 @@ static void vnc_zebra_add_del_prefix(struct bgp *bgp, add); } - if (nhp_ary) - XFREE(MTYPE_TMP, nhp_ary); - if (nh_ary) - XFREE(MTYPE_TMP, nh_ary); + XFREE(MTYPE_TMP, nhp_ary); + XFREE(MTYPE_TMP, nh_ary); } void vnc_zebra_add_prefix(struct bgp *bgp, @@ -789,10 +787,8 @@ static void vnc_zebra_add_del_group_afi(struct bgp *bgp, } } } - if (nhp_ary) - XFREE(MTYPE_TMP, nhp_ary); - if (nh_ary) - XFREE(MTYPE_TMP, nh_ary); + XFREE(MTYPE_TMP, nhp_ary); + XFREE(MTYPE_TMP, nh_ary); } } diff --git a/bgpd/subdir.am b/bgpd/subdir.am index 40ea976634..d281fe4e59 100644 --- a/bgpd/subdir.am +++ b/bgpd/subdir.am @@ -191,12 +191,15 @@ noinst_HEADERS += \ bgpd_bgpd_SOURCES = bgpd/bgp_main.c bgpd_bgp_btoa_SOURCES = bgpd/bgp_btoa.c +bgpd_bgpd_CFLAGS = $(AM_CFLAGS) +bgpd_bgp_btoa_CFLAGS = $(AM_CFLAGS) + if ENABLE_BGP_VNC bgpd_bgpd_SOURCES += bgpd/rfapi/rfapi_descriptor_rfp_utils.c -bgpd_bgpd_CFLAGS = $(AM_CFLAGS) -Irfapi -I@top_srcdir@/$(RFPINC) +bgpd_bgpd_CFLAGS += -Irfapi -I@top_srcdir@/$(RFPINC) bgpd_bgp_btoa_SOURCES += bgpd/rfapi/rfapi_descriptor_rfp_utils.c -bgpd_bgp_btoa_CFLAGS = $(AM_CFLAGS) -Irfapi -I@top_srcdir@/$(RFPINC) +bgpd_bgp_btoa_CFLAGS += -Irfapi -I@top_srcdir@/$(RFPINC) endif # RFPLDADD is set in bgpd/rfp-example/librfp/subdir.am @@ -221,6 +224,8 @@ bgpd/bgp_route_clippy.c: $(CLIPPY_DEPS) bgpd/bgp_route.$(OBJEXT): bgpd/bgp_route_clippy.c bgpd/bgp_debug_clippy.c: $(CLIPPY_DEPS) bgpd/bgp_debug.$(OBJEXT): bgpd/bgp_debug_clippy.c +bgpd/bgp_routemap_clippy.c: $(CLIPPY_DEPS) +bgpd/bgp_routemap.$(OBJEXT): bgpd/bgp_routemap_clippy.c bgpd/bgp_rpki_clippy.c: $(CLIPPY_DEPS) $(AUTOMAKE_DUMMY)bgpd/bgpd_bgpd_rpki_la-bgp_rpki.lo: bgpd/bgp_rpki_clippy.c $(AUTOMAKE_DUMMY)bgpd/bgpd_rpki_la-bgp_rpki.lo: bgpd/bgp_rpki_clippy.c diff --git a/bgpd/valgrind.supp b/bgpd/valgrind.supp index 28c3f82749..7a25c88363 100644 --- a/bgpd/valgrind.supp +++ b/bgpd/valgrind.supp @@ -6,8 +6,4 @@ fun:dlopen@@GLIBC_2.2.5 fun:ly_load_plugins_dir fun:ly_load_plugins - fun:ly_ctx_new - fun:yang_init - fun:frr_init - fun:main } diff --git a/debianpkg/changelog.in b/changelog-auto.in index 8f3f4753de..127d7fe147 100644 --- a/debianpkg/changelog.in +++ b/changelog-auto.in @@ -1,4 +1,49 @@ -frr (@VERSION@) RELEASED; urgency=medium +frr (@VERSION@-0) UNRELEASED; urgency=medium + + * autoconf changelog entry -- for git autobuilds only. + remove and replace when creating releases! + (tools/tarsource.sh will handle this) + + -- FRRouting-Dev <dev@lists.frrouting.org> Thu, 25 Oct 2018 16:36:50 +0200 + +frr (6.0-2) testing; urgency=medium + + * add install-info to build deps + * remove trailing whitespace from control + * cleanup tcp-zebra configure options + * drop unused SMUX client OID MIBs + * remove /proc check + * remove --enable-poll + * remove libtool .la files + * drop texlive-latex-base, texlive-generic-recommended build deps + * consistently allow python2 or python3 + * remove bad USE_* options, add WERROR + * drop libncurses5 dep + * remove backports mechanism + * use better dependency for pythontools (binNMU compatible) + * remove bogus shlib:Depends on frr-dbg + * create frr-snmp and frr-rpki-rtrlib + * make frr-pythontools a "Recommends:" + * use redistclean target + * update to Debian Policy version 4.2.1 + * raise debhelper compat level to 9 + * ditch development-only files + * modernise dh_missing and use fail mode + * disable zeromq and FPM + * always install /etc/init.d/frr + * put frr-doc package in 'doc' section + * install HTML docs, drop tools/ + * fix install for {frr,rfptest,ospfclient} + * add watch file + * change python dependency and shebang to python3:any + * use set -e in maintscripts + * put myself in as maintainer + * update copyright file + * closes: #863249 + + -- David Lamparter <equinox-debian@diac24.net> Thu, 25 Oct 2018 16:36:50 +0200 + +frr (6.0-1) RELEASED; urgency=medium * New Enabled: PIM draft Unnumbered @@ -7,7 +52,7 @@ frr (@VERSION@) RELEASED; urgency=medium frr (3.0-1) RELEASED; urgency=medium * Added Debian 9 Backport - + -- FRRouting-Dev <dev@lists.frrouting.org> Mon, 16 Oct 2017 03:28:00 -0700 frr (3.0-0) RELEASED; urgency=medium @@ -28,7 +73,7 @@ frr (3.0-0) RELEASED; urgency=medium * New Enabled: PIM Sparse Mode * New Enabled: NHRP RFC 2332 * New Enabled: Label Manager - * Switched from hardening-wrapper to dpkg-buildflags. + * Switched from hardening-wrapper to dpkg-buildflags. -- FRRouting-Dev <dev@lists.frrouting.org> Fri, 13 Oct 2017 16:17:26 -0700 @@ -66,7 +111,7 @@ quagga (0.99.24+cl3u3) RELEASED; urgency=medium quagga (0.99.23.1-1+cl3u2) RELEASED; urgency=medium - * New Enabled: VRF - See Documentation for how to use + * New Enabled: VRF - See Documentation for how to use * New Enabled: Improved interface statistics * New Enabled: Various vtysh improvements * New Enabled: Numerous compile warnings and SA fixes @@ -84,7 +129,7 @@ quagga (0.99.23.1-1+cl3u2) RELEASED; urgency=medium * New Enabled: BGP default keepalive to 3s and holdtime to 9s * New Enabled: OSPF spf timers are now '0 50 5000' by default * New Enabled: BGP hostname is displayed by default - * New Enabled: BGP 'no-as-set' is the default for + * New Enabled: BGP 'no-as-set' is the default for 'bgp as-path multipath-relax" * New Enabled: RA is on by default if using 5549 on an interface * New Enabled: peer-group restrictions relaxed, update-groups determine @@ -108,11 +153,11 @@ quagga (0.99.23.1-1+cl3u2) RELEASED; urgency=medium * Closes: CM-9974 Get route counts right for show ip route summary * Closes: CM-9786 BGP memory leak in peer hostname * Closes: CM-9340 BGP: Ensure correct sequence of processing at exit - * Closes: CM-9270 ripd: Fix crash when a default route is passed to rip - * Closes: CM-9255 BGPD crash around bgp_config_write () + * Closes: CM-9270 ripd: Fix crash when a default route is passed to rip + * Closes: CM-9255 BGPD crash around bgp_config_write () * Closes: CM-9134 ospf6d: Fix for crash when non area 0 network entered first - * Closes: CM-8934 OSPFv3: Check area before scheduling SPF + * Closes: CM-8934 OSPFv3: Check area before scheduling SPF * Closes: CM-8514 zebra: Crash upon disabling a link * Closes: CM-8295 BGP crash in group_announce_route_walkcb * Closes: CM-8191 BGP: crash in update_subgroup_merge() @@ -148,15 +193,15 @@ quagga (0.99.22.4-4) unstable; urgency=medium quagga (0.99.22.4-3) unstable; urgency=low - * Added status to init script (thanks to Peter J. Holzer). Closes: #730625 + * Added status to init script (thanks to Peter J. Holzer). Closes: #730625 * Init script now sources /lib/lsb/init-functions. - * Switched from hardening-wrapper to dpkg-buildflags. + * Switched from hardening-wrapper to dpkg-buildflags. -- Christian Hammers <ch@debian.org> Wed, 01 Jan 2014 19:12:01 +0100 quagga (0.99.22.4-2) unstable; urgency=low - * Fixed typo in package description (thanks to Davide Prina). + * Fixed typo in package description (thanks to Davide Prina). Closes: #625860 * Added Italian Debconf translation (thanks to Beatrice Torracca) Closes: #729798 @@ -171,15 +216,15 @@ quagga (0.99.22.4-1) unstable; urgency=high the OSPF API-server (exporting the LSDB and allowing announcement of Opaque-LSAs) writes past the end of fixed on-stack buffers. This leads to an exploitable stack overflow. - + For this condition to occur, the following two conditions must be true: - Quagga is configured with --enable-opaque-lsa - ospfd is started with the "-a" command line option - + If either of these does not hold, the relevant code is not executed and the issue does not get triggered." Closes: #726724 - + * New upstream release - ospfd: protect vs. VU#229804 (malformed Router-LSA) (Quagga is said to be non-vulnerable but still adds some protection) @@ -188,7 +233,7 @@ quagga (0.99.22.4-1) unstable; urgency=high quagga (0.99.22.1-2) unstable; urgency=low - * Added autopkgtests (thanks to Yolanda Robla). Closes: #710147 + * Added autopkgtests (thanks to Yolanda Robla). Closes: #710147 * Added "status" command to init script (thanks to James Andrewartha). Closes: #690013 * Added "libsnmp-dev" to Build-Deps. There not needed for the official @@ -196,7 +241,7 @@ quagga (0.99.22.1-2) unstable; urgency=low SNMP feature (which for licence reasons cannot be done by Debian). Thanks to Ben Winslow). Closes: #694852 * Changed watchquagga_options to an array so that quotes can finally - be used as expected. Closes: #681088 + be used as expected. Closes: #681088 * Fixed bug that prevented restarting only the watchquagga daemon (thanks to Harald Kappe). Closes: #687124 @@ -215,7 +260,7 @@ quagga (0.99.22.1-1) unstable; urgency=low quagga (0.99.22-1) unstable; urgency=low - * New upstream release. + * New upstream release. - [bgpd] The semantics of default-originate route-map have changed. The route-map is now used to advertise the default route conditionally. The old behaviour which allowed to set attributes on the originated @@ -227,7 +272,7 @@ quagga (0.99.22-1) unstable; urgency=low - [isisd] is in "beta" state. - [ospf6d] is in "alpha/experimental" state - More changes are documented in the upstream changelog! - * debian/watch: Adjusted to new savannah.gnu.org site, thanks to Bart + * debian/watch: Adjusted to new savannah.gnu.org site, thanks to Bart Martens. * debian/patches/99_CVE-2012-1820_bgp_capability_orf.diff removed as its in the changelog. @@ -274,7 +319,7 @@ quagga (0.99.21-1) unstable; urgency=low - [babeld] a new routing daemon implementing the BABEL ad-hoc mesh routing protocol has been merged. - [isisd] a major overhaul has been picked up. Please note that isisd is - STILL NOT SUITABLE FOR PRODUCTION USE. + STILL NOT SUITABLE FOR PRODUCTION USE. - a lot of bugs have been fixed * Added watchquagga daemon. * Added DEP-3 conforming patch comments. @@ -309,7 +354,7 @@ quagga (0.99.20-2) unstable; urgency=low * Bumped standards version to 0.9.2. * Migrated to "dh" build system. - * Added quagga-dbg package. + * Added quagga-dbg package. -- Christian Hammers <ch@debian.org> Fri, 14 Oct 2011 23:59:26 +0200 @@ -317,7 +362,7 @@ quagga (0.99.20-1) unstable; urgency=low * New upstream release: "The primary focus of this release is a fix of SEGV regression in ospfd, - which was introduced in 0.99.19. It also features a series of minor + which was introduced in 0.99.19. It also features a series of minor improvements, including better RFC compliance in bgpd, better support of FreeBSD and some enhancements to isisd." * Fixes off-by-one bug (removed 20_ospf6_area_argv.dpatch). Closes: #519488 @@ -342,7 +387,7 @@ quagga (0.99.18-1) unstable; urgency=low * SECURITY: "This release fixes 2 denial of services in bgpd, which can be remotely triggered by malformed AS-Pathlimit or Extended-Community attributes. - These issues have been assigned CVE-2010-1674 and CVE-2010-1675. + These issues have been assigned CVE-2010-1674 and CVE-2010-1675. Support for AS-Pathlimit has been removed with this release." * Added Brazilian Portuguese debconf translation. Closes: #617735 * Changed section for quagga-doc from "doc" to "net". @@ -352,7 +397,7 @@ quagga (0.99.18-1) unstable; urgency=low quagga (0.99.17-4) unstable; urgency=low - * Added comment to init script (thanks to Marc Haber). Closes: #599524 + * Added comment to init script (thanks to Marc Haber). Closes: #599524 -- Christian Hammers <ch@debian.org> Thu, 13 Jan 2011 23:53:29 +0100 @@ -365,7 +410,7 @@ quagga (0.99.17-3) unstable; urgency=low quagga (0.99.17-2) unstable; urgency=low - * Added Danisch Debconf translation (thanks to Joe Dalton). Closes: #596259 + * Added Danisch Debconf translation (thanks to Joe Dalton). Closes: #596259 -- Christian Hammers <ch@debian.org> Sat, 18 Sep 2010 12:20:07 +0200 @@ -384,7 +429,7 @@ quagga (0.99.17-1) unstable; urgency=high quagga (0.99.16-1) unstable; urgency=low - * New upstream release. Closes: #574527 + * New upstream release. Closes: #574527 * Added chrpath to debian/rules to fix rpath problems that lintian spottet. -- Christian Hammers <ch@debian.org> Sun, 21 Mar 2010 17:05:40 +0100 @@ -401,16 +446,16 @@ quagga (0.99.15-1) unstable; urgency=low * New upstream release "This fixes some annoying little ospfd and ospf6d regressions, which made - 0.99.14 a bit of a problem release (...) This release still contains a - regression in the "no ip address ..." command, at least on Linux. - See bug #486, which contains a workaround patch. This release should be + 0.99.14 a bit of a problem release (...) This release still contains a + regression in the "no ip address ..." command, at least on Linux. + See bug #486, which contains a workaround patch. This release should be considered a 1.0.0 release candidate. Please test this release as widely as possible." - * Fixed wrong port number in zebra.8 (thanks to Thijs Kinkhorst). + * Fixed wrong port number in zebra.8 (thanks to Thijs Kinkhorst). Closes: #517860 - * Added Russian Debconf tanslation (thanks to Yuri Kozlov). + * Added Russian Debconf tanslation (thanks to Yuri Kozlov). Closes: #539464 - * Removed so-version in build-dep to libreadline-dev on request of + * Removed so-version in build-dep to libreadline-dev on request of Matthias Klose. * Added README.source with reference to dpatch as suggested by lintian. * Bumped standards versionto 3.8.3. @@ -431,8 +476,8 @@ quagga (0.99.14-1) unstable; urgency=low quagga (0.99.13-2) unstable; urgency=low - * Added Japanese Debconf translation (thanks to Hideki Yamane). - Closes: #510714 + * Added Japanese Debconf translation (thanks to Hideki Yamane). + Closes: #510714 * When checking for obsoleted config options in preinst, print filename where it occures (thanks to Michael Bussmann). Closes: #339489 @@ -456,7 +501,7 @@ quagga (0.99.12-1) unstable; urgency=high "This release fixes an urgent bug in bgpd where it could hit an assert if it received a long AS_PATH with a 4-byte ASN." Noteworthy bugfixes: + [bgpd] Fix bgp ipv4/ipv6 accept handling - + [bgpd] AS4 bugfix by Chris Caputo + + [bgpd] AS4 bugfix by Chris Caputo + [bgpd] Allow accepted peers to progress even if realpeer is in Connect + [ospfd] Switch Fletcher checksum back to old ospfd version @@ -481,7 +526,7 @@ quagga (0.99.10-1) unstable; urgency=medium + bgpd: 4-Byte AS Number support + Sessions were incorrectly reset if a partial AS-Pathlimit attribute was received. - + Advertisement of Multi-Protocol prefixes (i.e. non-IPv4) had been + + Advertisement of Multi-Protocol prefixes (i.e. non-IPv4) had been broken in the 0.99.9 release. Closes: #467656 -- Christian Hammers <ch@debian.org> Tue, 08 Jul 2008 23:32:42 +0200 @@ -516,7 +561,7 @@ quagga (0.99.9-3) unstable; urgency=low Closes: #428574 * debian/control: (thanks to Marco Rodrigues) + Bump Standards-Version to 3.7.3 (no changes needed). - + Add Homepage field. + + Add Homepage field. -- Christian Hammers <ch@debian.org> Mon, 28 Jan 2008 22:29:18 +0100 @@ -546,7 +591,7 @@ quagga (0.99.9-1) unstable; urgency=high quagga (0.99.8-1) unstable; urgency=low - * New upstream version. + * New upstream version. -- Christian Hammers <ch@debian.org> Fri, 17 Aug 2007 00:07:04 +0200 @@ -572,7 +617,7 @@ quagga (0.99.7-2) unstable; urgency=low quagga (0.99.7-1) unstable; urgency=low - * New upstream release. Closes: #421553 + * New upstream release. Closes: #421553 -- Christian Hammers <ch@debian.org> Mon, 30 Apr 2007 14:22:34 +0200 @@ -586,7 +631,7 @@ quagga (0.99.6-5) unstable; urgency=high * SECURITY: The bgpd daemon was vulnerable to a Denial-of-Service. Configured peers - could cause a Quagga bgpd to, typically, assert() and abort. The DoS + could cause a Quagga bgpd to, typically, assert() and abort. The DoS could be triggered by peers by sending an UPDATE message with a crafted, malformed Multi-Protocol reachable/unreachable NLRI attribute. This is CVE-2007-1995 and Quagga Bug#354. Closes: #418323 @@ -595,8 +640,8 @@ quagga (0.99.6-5) unstable; urgency=high quagga (0.99.6-4) unstable; urgency=low - * Improved note in README.Debian for SNMP self-builders (thanks to Matthias - Wamser). Closes: #414788 + * Improved note in README.Debian for SNMP self-builders (thanks to Matthias + Wamser). Closes: #414788 -- Christian Hammers <ch@debian.org> Wed, 14 Mar 2007 02:18:57 +0100 @@ -623,7 +668,7 @@ quagga (0.99.6-1) unstable; urgency=low quagga (0.99.5-5) unstable; urgency=high * Changed Depends on adduser to Pre-Depends to avoid uninstallability - in certain cases (thanks to Steve Langasek, Lucas Nussbaum). + in certain cases (thanks to Steve Langasek, Lucas Nussbaum). Closes: #398562 -- Christian Hammers <ch@debian.org> Wed, 15 Nov 2006 17:46:34 +0100 @@ -631,7 +676,7 @@ quagga (0.99.5-5) unstable; urgency=high quagga (0.99.5-4) unstable; urgency=low * Added default PAM file and some explanations regarding PAM authentication - of vtysh which could prevent the start at boot-time when used wrong. + of vtysh which could prevent the start at boot-time when used wrong. Now PAM permits anybody to access the vtysh tool (a malicious user could build his own vtysh without PAM anyway) and the access is controled by the read/write permissions of the vtysh socket which are only granted to @@ -652,7 +697,7 @@ quagga (0.99.5-3) unstable; urgency=medium quagga (0.99.5-2) unstable; urgency=medium - * Added LSB info section to initscript. + * Added LSB info section to initscript. * Removed unnecessary depends to libncurses5 to make checklib happy. The one to libcap should remain though as it is just temporarily unused. @@ -699,7 +744,7 @@ quagga (0.99.4-1) unstable; urgency=low quagga (0.99.3-3) unstable; urgency=low - * Added CVE numbers for the security patch in 0.99.3-2. + * Added CVE numbers for the security patch in 0.99.3-2. -- Christian Hammers <ch@debian.org> Sat, 6 May 2006 17:14:22 +0200 @@ -711,7 +756,7 @@ quagga (0.99.3-2) unstable; urgency=high CVE-2006-2223 - missing configuration to disable RIPv1 or require plaintext or MD5 authentication CVE-2006-2224 - lack of enforcement of RIPv2 authentication requirements - Closes: #365940 + Closes: #365940 * First amd64 upload. -- Christian Hammers <ch@debian.org> Thu, 4 May 2006 00:22:09 +0200 @@ -742,7 +787,7 @@ quagga (0.99.1-7) unstable; urgency=low quagga (0.99.1-6) unstable; urgency=low - * Fixed debconf dependency as requested by Joey Hess. + * Fixed debconf dependency as requested by Joey Hess. -- Christian Hammers <ch@debian.org> Mon, 26 Sep 2005 20:47:35 +0200 @@ -862,7 +907,7 @@ quagga (0.98.3-2) unstable; urgency=low quagga (0.98.3-1) unstable; urgency=low - * New upstream release. + * New upstream release. Mmost notably fixes last regression in bgpd (reannounce of prefixes with changed attributes works again), race condition in netlink handling while using IPv6, MTU changes handling in ospfd and several @@ -881,9 +926,9 @@ quagga (0.98.2-1) unstable; urgency=medium * Quoting the upstream announcement: The 0.98.1 release unfortunately was a brown paper bag release with - respect to ospfd. [...] 0.98.2 has been released, with one crucial change - to fix the unfortunate mistake in 0.98.1, which caused problems if - ospfd became DR. + respect to ospfd. [...] 0.98.2 has been released, with one crucial change + to fix the unfortunate mistake in 0.98.1, which caused problems if + ospfd became DR. * Note: the upstream tarball had a strange problem, apparently redhat.spec was twice in it? At least debuild gave a strange error message so I unpacked it by hand. No changes were made to the .orig.tar.gz! @@ -906,7 +951,7 @@ quagga (0.98.1-1) unstable; urgency=medium quagga (0.98.0-3) unstable; urgency=low - * Fixed problem in init script. Closes: #290317 + * Fixed problem in init script. Closes: #290317 * Removed obsolete "smux peer enable" patch. -- Christian Hammers <ch@debian.org> Fri, 14 Jan 2005 17:37:27 +0100 @@ -928,7 +973,7 @@ quagga (0.98.0-1) unstable; urgency=low quagga (0.97.5-1) unstable; urgency=low - * New upstream version. + * New upstream version. * Added Czech debconf translation (thanks to Miroslav Kure). Closes: #287293 * Added Brazilian debconf translation (thanks to Andre Luis Lopes). @@ -938,7 +983,7 @@ quagga (0.97.5-1) unstable; urgency=low quagga (0.97.4-2) unstable; urgency=low - * Fixed quagga.info build problem. + * Fixed quagga.info build problem. -- Christian Hammers <ch@debian.org> Wed, 5 Jan 2005 22:38:01 +0100 @@ -972,7 +1017,7 @@ quagga (0.97.2-4) unstable; urgency=low * Added Portuguese debconf translation (thanks to Andre Luis Lopes). Closes: #279352 - * Disabled ospfapi server by default on recommendation of Paul Jakma. + * Disabled ospfapi server by default on recommendation of Paul Jakma. -- Christian Hammers <ch@debian.org> Sun, 7 Nov 2004 15:07:05 +0100 @@ -988,14 +1033,14 @@ quagga (0.97.2-2) unstable; urgency=low suggestion from Paul Jakma. Still not perfect though. * Fixed upstream vtysh.conf.sample file. * "ip ospf network broadcast" is now saved correctly. Closes: #244116 - * Daemon options are now in /etc/quagga/debian.conf to be user + * Daemon options are now in /etc/quagga/debian.conf to be user configurable (thanks to Simon Raven and Hasso Tepper). Closes: #266715 -- Christian Hammers <ch@debian.org> Tue, 26 Oct 2004 23:35:45 +0200 quagga (0.97.2-1) unstable; urgency=low - * New upstream version. + * New upstream version. Closes: #254541 * Fixed warning on unmodular kernels (thanks to Christoph Biedl). Closes: #277973 @@ -1011,7 +1056,7 @@ quagga (0.97.1-2) unstable; urgency=low quagga (0.97.1-1) unstable; urgency=low - * New upstream version. + * New upstream version. * Removed some obsolete files from debian/patches. * Added patch from upstream bug 113. Closes: #254541 * Added patch from upstream that fixes a compilation problem in the @@ -1047,7 +1092,7 @@ quagga (0.96.5-10) unstable; urgency=medium quagga (0.96.5-9) unstable; urgency=low * Rewrote the documentation chapter about SNMP support. Closes: #195653 - * Added MPLS docs. + * Added MPLS docs. -- Christian Hammers <ch@debian.org> Thu, 29 Jul 2004 21:01:52 +0200 @@ -1074,7 +1119,7 @@ quagga (0.96.5-7) unstable; urgency=low quagga (0.96.5-6) unstable; urgency=low - * Try to load the capability module as it is needed now. + * Try to load the capability module as it is needed now. -- Christian Hammers <ch@debian.org> Tue, 8 Jun 2004 23:25:29 +0200 @@ -1103,9 +1148,9 @@ quagga (0.96.5-3) unstable; urgency=low quagga (0.96.5-2) unstable; urgency=low * New upstream version. - * New md5 patch version (thanks to Niklas Jakobsson and Hasso Tepper). + * New md5 patch version (thanks to Niklas Jakobsson and Hasso Tepper). Closes: #250985 - * Fixes info file generation (thanks to Peder Chr. Norgaard). + * Fixes info file generation (thanks to Peder Chr. Norgaard). Closes: #250992 * Added catalan debconf translation (thanks to Aleix Badia i Bosch). Closes: #250118 @@ -1136,14 +1181,14 @@ quagga (0.96.4x-10) unstable; urgency=low started to require it. See: CAN-2004-0230, http://www.us-cert.gov/cas/techalerts/TA04-111A.html * PATCHES: - This release contains the MD5 patch from Hasso Tepper. It also seems to + This release contains the MD5 patch from Hasso Tepper. It also seems to required a kernel patch. See /usr/share/doc/quagga/README.Debian.MD5. -- Christian Hammers <ch@debian.org> Thu, 29 Apr 2004 01:01:38 +0200 quagga (0.96.4x-9) unstable; urgency=low - * Fixed daemon loading order (thanks to Matt Kemner). + * Fixed daemon loading order (thanks to Matt Kemner). * Fixed typo in init script (thanks to Charlie Brett). Closes: #238582 -- Christian Hammers <ch@debian.org> Sun, 4 Apr 2004 15:32:18 +0200 @@ -1151,7 +1196,7 @@ quagga (0.96.4x-9) unstable; urgency=low quagga (0.96.4x-8) unstable; urgency=low * Patched upstream source so that quagga header files end up in - /usr/include/quagga/. Closes: #233792 + /usr/include/quagga/. Closes: #233792 -- Christian Hammers <ch@debian.org> Mon, 23 Feb 2004 01:42:53 +0100 @@ -1164,8 +1209,8 @@ quagga (0.96.4x-7) unstable; urgency=low quagga (0.96.4x-6) unstable; urgency=low - * Added dependency to iproute. - * Initscript now checks not only for the pid file but also for the + * Added dependency to iproute. + * Initscript now checks not only for the pid file but also for the daemons presence (thanks to Phil Gregory). Closes: #224389 * Added my patch to configure file permissions. @@ -1182,13 +1227,13 @@ quagga (0.96.4x-5) unstable; urgency=low obscure whitespaces inside an C macro. (Thanks to Marc Haber). Closes: #223529 * Now uses /usr/bin/pager. Closes: #204070 - * Added note about the "official woody backports" on my homepage. + * Added note about the "official woody backports" on my homepage. -- Christian Hammers <ch@debian.org> Mon, 15 Dec 2003 20:39:06 +0100 quagga (0.96.4x-4) unstable; urgency=high - * SECURITY: + * SECURITY: Fixes another bug that was originally reported against Zebra. . http://rhn.redhat.com/errata/RHSA-2003-307.html @@ -1210,7 +1255,7 @@ quagga (0.96.4x-3) unstable; urgency=low * Made the directory (but not the config/log files!) world accessible again on user request (thanks to Anand Kumria)). Closes: #213129 * No longer providing sample configuration in /etc/quagga/. They are - now only available in /usr/share/doc/quagga/ to avoid accidently + now only available in /usr/share/doc/quagga/ to avoid accidently using them without changing the adresses (thanks to Marc Haber). Closes: #215918 @@ -1219,13 +1264,13 @@ quagga (0.96.4x-3) unstable; urgency=low quagga (0.96.4x-2) unstable; urgency=low * Fixed permission problem with pidfile (thanks to Kir Kostuchenko). - Closes: #220938 + Closes: #220938 -- Christian Hammers <ch@debian.org> Sun, 16 Nov 2003 14:24:08 +0100 quagga (0.96.4x-1) unstable; urgency=low - * Reupload of 0.96.4. Last upload-in-a-hurry produced a totally + * Reupload of 0.96.4. Last upload-in-a-hurry produced a totally crappy .tar.gz file. Closes: #220621 -- Christian Hammers <ch@debian.org> Fri, 14 Nov 2003 19:45:57 +0100 @@ -1235,7 +1280,7 @@ quagga (0.96.4-1) unstable; urgency=high * SECURITY: Remote DoS of protocol daemons. Fix for a remote triggerable crash in vty layer. The management ports ("telnet myrouter ospfd") should not be open to the internet! - + * New upstream version. - OSPF bugfixes. - Some improvements for bgp and rip. @@ -1252,7 +1297,7 @@ quagga (0.96.3-3) unstable; urgency=low quagga (0.96.3-2) unstable; urgency=low - * Readded GNOME-PRODUCT-ZEBRA-MIB. + * Readded GNOME-PRODUCT-ZEBRA-MIB. -- Christian Hammers <ch@debian.org> Thu, 23 Oct 2003 06:17:03 +0200 diff --git a/configure.ac b/configure.ac index 0c15b501f0..9ae196fcb1 100755 --- a/configure.ac +++ b/configure.ac @@ -147,7 +147,7 @@ dnl - specifically, options to control warnings AC_USE_SYSTEM_EXTENSIONS AC_DEFUN([AC_C_FLAG], [{ - m4_pushdef([cachename],[m4_translit([frr_cv_$1],[ =-],[___])]) + m4_pushdef([cachename],[m4_translit([frr_cv_$1],[ =-+],[____])]) AC_CACHE_CHECK([[whether $CC supports $1]], cachename, [ AC_LANG_PUSH([C]) ac_c_flag_save="$CFLAGS" @@ -261,6 +261,9 @@ fi AC_C_FLAG([-Wno-unused-parameter]) AC_C_FLAG([-Wno-missing-field-initializers]) +AC_C_FLAG([-Wc++-compat], [], [CXX_COMPAT_CFLAGS="-Wc++-compat"]) +AC_SUBST([CXX_COMPAT_CFLAGS]) + dnl ICC emits a broken warning for const char *x = a ? "b" : "c"; dnl for some reason the string consts get 'promoted' to char *, dnl triggering a const to non-const conversion warning. @@ -762,7 +765,7 @@ AC_DEFINE_UNQUOTED([CONFIGFILE_MASK], [${enable_configfile_mask}], [Mask for con enable_logfile_mask=${enable_logfile_mask:-0600} AC_DEFINE_UNQUOTED([LOGFILE_MASK], [${enable_logfile_mask}], [Mask for log files]) -MPATH_NUM=1 +MPATH_NUM=16 case "${enable_multipath}" in 0) @@ -1608,7 +1611,7 @@ CFLAGS="$CFLAGS $LIBYANG_CFLAGS" AC_CHECK_MEMBER([struct lyd_node.priv], [], [ AC_MSG_ERROR([m4_normalize([ libyang needs to be compiled with ENABLE_LYD_PRIV=ON. - See http://docs.frrouting.org/projects/dev-guide/en/latest/building-libyang.html for details.]) + Instructions for this are included in the build documentation for your platform at http://docs.frrouting.org/projects/dev-guide/en/latest/building.html]) ]) ], [[#include <libyang/libyang.h>]]) CFLAGS="$ac_cflags_save" @@ -1656,6 +1659,8 @@ if test "$enable_confd" != "" -a "$enable_confd" != "no"; then fi CONFD_CFLAGS="-I${enable_confd}/include -L${enable_confd}/lib" AC_SUBST([CONFD_CFLAGS]) + CONFD_LIBS="-lconfd" + AC_SUBST([CONFD_LIBS]) AC_DEFINE([HAVE_CONFD], [1], [Enable confd integration]) fi AM_CONDITIONAL([CONFD], [test "x$enable_confd" != "x"]) @@ -1738,7 +1743,8 @@ AC_CHECK_TYPES([ vifi_t, struct sioc_vif_req, struct igmpmsg, struct ifaliasreq, struct if6_aliasreq, struct in6_aliasreq, struct nd_opt_adv_interval, struct rt_addrinfo, - struct nd_opt_homeagent_info, struct nd_opt_adv_interval], + struct nd_opt_homeagent_info, struct nd_opt_adv_interval, + struct nd_opt_rdnss, struct nd_opt_dnssl], [], [], FRR_INCLUDES) AC_CHECK_MEMBERS([struct sockaddr.sa_len, @@ -2151,6 +2157,7 @@ AC_SUBST([CFG_LIBYANG_PLUGINS]) AC_DEFINE_UNQUOTED([MODULE_PATH], ["$CFG_MODULE"], [path to modules]) AC_DEFINE_UNQUOTED([YANG_MODELS_PATH], ["$CFG_YANGMODELS"], [path to YANG data models]) AC_DEFINE_UNQUOTED([LIBYANG_PLUGINS_PATH], ["$CFG_LIBYANG_PLUGINS"], [path to libyang plugins]) +AC_DEFINE_UNQUOTED([WATCHFRR_SH_PATH], ["${CFG_SBIN%/}/watchfrr.sh"], [path to watchfrr.sh]) dnl ------------------------------------ dnl Enable RPKI and add librtr to libs @@ -2190,9 +2197,9 @@ AC_CONFIG_FILES([Makefile],[sed -e 's/^#AUTODERP# //' -i Makefile]) AC_CONFIG_FILES([ config.version + changelog-auto redhat/frr.spec solaris/Makefile - debianpkg/changelog alpine/APKBUILD snapcraft/snapcraft.yaml lib/version.h diff --git a/debianpkg/README.Debian b/debian/README.Debian index cd7be5e801..47a353310d 100644 --- a/debianpkg/README.Debian +++ b/debian/README.Debian @@ -22,6 +22,36 @@ which itself is a fork of Zebra. Zebra was developed by Kunihiro Ishiguro. +* Build Profiles used in the upstream debian/ +============================================= + +The following Build Profiles have been added: + +- pkg.frr.nortrlib (pkg.frr.rtrlib) + controls whether the RPKI module is built. + Will be enabled by default at some point, adds some extra dependencies. + +- pkg.frr.nosnmp (pkg.frr.snmp) + controls whether the SNMP module is built, see below for license issues. + Will remain default-off as long as the license issue persists. + +- pkg.frr.nosystemd + Disables both systemd unit file installation as well as watchfrr sd_notify + support at startup. Removes libsystemd dependency. + +Note that all options have a "no" form; if you want to have your decision +be sticky regardless of changes to what it defaults to, then always use one +of the two. For example, all occurrences of <pkg.frr.rtrlib> will at some +point be replaced with <!pkg.frr.nortrlib>. + +The main frr package has the exact same contents regardless of rtrlib or snmp +choices. The options only control frr-snmp and frr-rpki-rtrlib packages. + +The main frr package does NOT have the same contents if pkg.frr.nosystemd is +used. This option should only be used for systems that do not have systemd, +e.g. Ubuntu 14.04. + + * Why has SNMP support been disabled? ===================================== FRR used to link against the NetSNMP libraries to provide SNMP @@ -43,12 +73,20 @@ during the last days before the Sarge release :-( It is allowed by the used licence mix that you fetch the sources and build FRR yourself with SNMP with - <remove the "grep ^smux" block at the end of debian/frr.preinst> - # export WANT_SNMP=1 - # apt-get -b source frr + # apt-get -b source -Ppkg.frr.snmp frr Just distributing it in binary form, linked against OpenSSL, is forbidden. +* Debian Policy compliance notes +================================ + +- 4.15 Reproducibility + FRR build is reproducible as outlined in version 4.2.1 of the Policy, but + won't be reproducible when the build directory is varied. This is because + configure parameters are burned into the executables which includes CFLAGS + like -fdebug-prefix-map=/build/directory/... + + * Daemon selection: =================== diff --git a/debianpkg/README.Maintainer b/debian/README.Maintainer index 84b68e1949..9030022c5e 100644 --- a/debianpkg/README.Maintainer +++ b/debian/README.Maintainer @@ -1,4 +1,14 @@ # +# TODO +# + +- check that tests/{control,daemons} actually do something useful and sensible +- /usr/share/doc/frr-doc should be named just frr? +- debian/watch pgpsigurlmangle / signing-key +- multiarch for DSOs? +- frr try-restart + +# # To check if the patches still apply on new upstream versions: # for i in debian/patches/*.diff; do echo -e "#\n# $i\n#"; patch --fuzz=3 --dry-run -p1 < $i; done diff --git a/debian/changelog b/debian/changelog new file mode 120000 index 0000000000..021c52c2f3 --- /dev/null +++ b/debian/changelog @@ -0,0 +1 @@ +../changelog-auto
\ No newline at end of file diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000000..ec635144f6 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +9 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000000..ab2df20432 --- /dev/null +++ b/debian/control @@ -0,0 +1,131 @@ +Source: frr +Section: net +Priority: optional +Maintainer: David Lamparter <equinox-debian@diac24.net> +Uploaders: FRRouting-dev <dev@lists.frrouting.org> +Build-Depends: + autotools-dev, + bison, + chrpath, + debhelper (>= 9), + debhelper (>= 9.20160709) <!pkg.frr.nosystemd> | dh-systemd <!pkg.frr.nosystemd>, + dh-autoreconf, + flex, + gawk, + install-info, + libc-ares-dev, + libcap-dev, + libjson-c-dev | libjson0-dev, + libpam0g-dev | libpam-dev, + libpcre3-dev, + libpython3-dev, + libreadline-dev, + librtr-dev <!pkg.frr.nortrlib>, + libsnmp-dev, + libssh-dev <!pkg.frr.nortrlib>, + libsystemd-dev <!pkg.frr.nosystemd>, + libyang-dev (>= 0.16.74), + pkg-config, + python3, + python3-dev, + python3-sphinx, + python3-pytest <!nocheck>, + texinfo (>= 4.7) +Standards-Version: 4.2.1 +Homepage: https://www.frrouting.org/ +Vcs-Browser: https://github.com/FRRouting/frr/ +Vcs-Git: https://github.com/FRRouting/frr.git + +Package: frr +Architecture: linux-any +Depends: + ${misc:Depends}, + ${shlibs:Depends}, + iproute2 | iproute, + logrotate (>= 3.2-11) +Pre-Depends: adduser +Recommends: frr-pythontools +Suggests: frr-doc +Conflicts: + zebra, + zebra-pj, + pimd, + quagga, + quagga-bgpd, + quagga-core, + quagga-isisd, + quagga-ospf6d, + quagga-ospfd, + quagga-pimd, + quagga-ripd, + quagga-ripngd +Replaces: zebra, zebra-pj +Description: FRRouting suite of internet protocols (BGP, OSPF, IS-IS, ...) + FRRouting implements the routing protocols commonly used in the + internet and private networks to exchange information between routers. + Both IP and IPv6 are supported, as are BGP, OSPF, IS-IS, BABEL, EIGRP, + RIP, LDP, BFD, PIM and NHRP protocols. + . + These protocols are used to turn your system into a dynamic router, + exchanging information about available connections with other routers + in a standards-compliant way. The actual packet forwarding + functionality is provided by the OS kernel. + . + FRRouting is a fork of Quagga with an open community model. The main + git lives on https://github.com/frrouting/frr.git and the project name + is commonly abbreviated as "FRR." + +Package: frr-snmp +Architecture: linux-any +Depends: + ${misc:Depends}, + ${shlibs:Depends}, + frr (= ${binary:Version}) +Recommends: snmpd +Description: FRRouting suite - SNMP support + Adds SNMP support to FRR's daemons by attaching to net-snmp's snmpd + through the AgentX protocol. Provides read-only access to current + routing state through standard SNMP MIBs. + +Package: frr-rpki-rtrlib +Architecture: linux-any +Depends: + ${misc:Depends}, + ${shlibs:Depends}, + frr (= ${binary:Version}) +Description: FRRouting suite - BGP RPKI support (rtrlib) + Adds RPKI support to FRR's bgpd, allowing validation of BGP routes + against cryptographic information stored in WHOIS databases. This is + used to prevent hijacking of networks on the wider internet. It is only + relevant to internet service providers using their own autonomous system + number. +Build-Profiles: <!pkg.frr.nortrlib> + +Package: frr-doc +Section: doc +Architecture: all +Depends: + ${misc:Depends}, + libjs-jquery, + libjs-underscore +Suggests: frr +Conflicts: quagga-doc +Description: FRRouting suite - user manual + This provides the FRR user manual in HTML form. This is the official + manual maintained as part of the package and is also available online + at https://frrouting.readthedocs.io/ + +Package: frr-pythontools +Architecture: all +Depends: + ${misc:Depends}, + frr (<< ${source:Upstream-Version}.0-~), + frr (>= ${source:Version}~), + python3:any +Description: FRRouting suite - Python tools + The FRRouting suite uses a small Python tool to provide configuration + reload functionality, particularly useful when the interactive configuration + shell is not used. + . + Without this package installed, "reload" (as a systemd or init script + invocation) will not work for the FRR daemons. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000000..61d87260d8 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,484 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: FRR +Upstream-Contact: maintainers@frrouting.org, security@frrouting.org +Source: https://www.frrouting.org/ + +Files: * +Copyright: 1996-2003 by the original Zebra authors: + Kunihiro Ishiguro <kunihiro@zebra.org> + Toshiaki Takada <takada@zebra.org> + Yasuhiro Ohara <yasu@sfc.wide.ad.jp> + 2003-2016 by the Quagga Project + 2016-2018 by the FRRouting Project + Adam Fitzgerald 2017 + Alex Couloumbis 2017 + Alexandre Chappuis 2011 + Alexis Fasquel 2015 + Ali Rezaee 2018 + Ameya Dharkar 2018 + Amritha Nambiar 2015 + Andreas Jaggi 2017 + Andrew Certain 2012 + Andrew J. Schorr 2004-2011 + Andrew Lunn 2017 + Andrey Korolyov 2017-2018 + Ang Way Chuang 2012 + Anuradha Karuppiah 2016-2018 + Arthur Jones 2018 + Avneesh Sachdev 2012, 2016 + Ayan Banerjee 2012 + Balaji G. 2011-2016 + Barry Friedman 2011 + Bartek Kania 2008 + Baruch Siach 2016 + Bingen Eguzkitza 2016-2017 + Boian Bonev 2013 + Boris Yakubov 2013 + Brad Smith 2012 + Brett Ciphery 2013 + Brian Bennett 2015 + Brian Rak 2017 + Chirag Shah 2017-2018 + Chris Caputo 2009-2010 + Chris Hall 2010 + Chris Luke 2011 + Christian Franke 2012-2018 + Christian Hammers 2011 + Christoffer Hansen 2018 + Christoph Dwertmann 2018 + Colin Petrie 2016 + Daniel Kozlowski 2012 + Daniel Ng 2008 + Daniel Walton 2015-2018 + Daniil Baturin 2018 + Dario Wiesner 2018 + Dave Olson 2016-2017 + David BÉRARD 2010 + David Lamparter 2009-2018 + David Lebrun 2016 + David Ward 2009-2012 + David Young 2007 + Denil Vira 2015 + Denis Ovsienko 2007-2012 + Dinesh Dutt 2012-2013 + Dinesh G. Dutt 2013-2017 + Dmitrij Tejblum 2009-2011 + Dmitry Popov 2011 + Don Slice 2016-2018 + Donald Sharp 2015-2018 + Donatas Abraitis 2018 + Dongling Duan 2018 + Donnie Savage 2017 + Doug VanLeuven 2012 + Dylan Hall 2011 + Emanuele Di Pascale 2018 + Eric Pulvino 2017 + Everton Marques 2012-2014 + Evgeny Uskov 2016 + F. Aragon 2018 + Fatih USTA 2017 + Feng Lu 2014-2015 + Fernando Soto 2015 + Francesco Dolcini 2009 + Fredi Raspall 2016-2018 + Fritz Reichmann 2011 + G. Paul Ziemba 2016-2018 + Greg Troxel 2003-2007, 2010-2015 + Hasso Tepper 2003-2007, 2012-2013 + Hiroshi Yokoi 2015 + Hongguang Li 2016 + Hung-Weic Chiu 2017 + Igor Ryzhov 2016 + Ilya Shipitsin 2018 + Ingo Flaschberger 2011 + Ivan Moskalyov 2010 + JR Rivers 2012 + Jafar Al-Gharaibeh 2009, 2015-2018 + Jarad Olson 2018 + Jaroslav Fojtik 2011 + Jeremy Jackson 2008-2009 + Jingjing Duan 2008-2009 + Joachim Nilsson 2012-2013 + Joakim Tjernlund 2008-2014 + Job Snijders 2016 + John Berezovik 2016 + John Glotzer 2014 + John Kemp 2011 + Jon Andersson 2009-2011 + Jorge Boncompte 2012-2013, 2017 + Josh Bailey 2011-2012 + Juergen Kammer 2017 + Julien Courtat 2016 + Juliusz Chroboczek 2012 + Kaloyan Kovachev 2015-2017 + Ken Williams 2014 + Khiruthigai Balasubramanian 2016 + Krisztian Kovacs 2009 + Kunihiro Ishiguro 2018 + Leonard Tracy 2012 + Leonid Rosenboim 2012-2013 + Liu Xiaofeng 2016 + Lou Berger 2013, 2016-2018 + Lu Feng 2014-2015 + Lucian Cristian 2017 + Maitane Zotes 2014 + Manuel Schweizer 2017 + Marcel Röthke 2017-2018 + Mark Stapp 2018 + Martin Buck 2018 + Martin Winter 2015-2018 + Martín Beauchamp 2017 + Mathias Krause 2010 + Mathieu Goessens 2009 + Matthew Smith 2017 + Matthias Ferdinand 2011 + Matthieu Boutier 2012, 2016-2017 + Matti-Oskari Leppänen 2013 + Michael Lambert 2008-2010 + Michael Rossberg 2015 + Michael Zingg 2012 + Michal Sekletar 2014 + Mike Tancsa 2017 + Milan Kocian 2013-2014 + Mitesh Kanjariya 2017-2018 + Mladen Sablic 2017-2018 + Morgan Stewart 2015 + Nathan Van Gheem 2018 + Nick Hilliard 2009-2012 + Nico Golde 2010 + Nicolas Dichtel 2015 + Nigel Kukard 2017 + Nolan Leake 2012 + Oleg A. Arkhangelsky 2011 + Olivier Cochard-Labbé 2014 + Olivier Dugeon 2014-2018 + Ondrej Zajicek 2009 + Pascal Mathis 2018 + Paul Jakma 2002-2016 + Paul P Komkoff Jr 2008 + Pawel Wieczorkiewicz 2016 + Peter Pentchev 2011 + Peter Szilagyi 2011 + Phil Huang 2017 + Phil Laverdiere 2012 + Philippe Guibert 2016-2018 + Piotr Jurkiewicz 2018 + Pradosh Mohapatra 2013-2014 + Quentin Young 2016-2018 + Radhika Mahankali 2015-2017 + Rafael Zalamena 2017-2018 + Rakesh Garimella 2013 + Raymond P. Burkholder 2017 + Remi Gacogne 2013 + Renato Westphal 2012, 2016-2018 + Robert Bays 2010 + Roderick Schertler 2011 + Rodny Molina 2018 + Roman Hoog Antink 2010-2013 + Ruben Kerkhof 2018 + Russ White 2017-2018 + Ryan Hagelstrom 2017 + Sam Tannous 2016-2017 + Sarita Patra 2018 + Sebastian Lohff 2017 + Sergey Fionov 2018 + Sergey Y. Afonin 2011 + Serj Kalichev 2012 + Sid Khot 2016 + Silas McCroskey 2017-2018 + Stephane Litkowski 2017 + Stephen Hemminger 2008-2014 + Stephen Worley 2018 + Steve Hill 2009 + Stig Thormodsrud 2008 + Subbaiah Venkata 2012 + Svata Dedic 2011 + Sébastien Luttringer 2014 + Takashi Sogabe 2009 + Thijs Kinkhorst 2009 + Thomas Gelf 2018 + Thomas Petazzoni 2016 + Thomas Ries 2011 + Thorvald Natvig 2017 + Tigran Martirosyan 2018 + Timo Teräs 2008-2009, 2013-2017 + Timothy Redaelli 2017 + Tom Goff 2009-2011 + Tom Henderson 2009 + Tomasz Pala 2009 + Udaya Shankara KS 2016 + Ulrich Weber 2011-2013 + Vasilis Tsiligiannis 2009 + Vincent Bernat 2012, 2017-2018 + Vincent Jardin 2003-2007, 2014, 2017-2018 + Vipin Kumar 2014-2015 + Vishal Dhingra 2018 + Vishal Kumar 2012 + Vitaliy Senchyshyn 2013 + Vivek Venkatraman 2015-2018 + Vladimir L Ivanov 2010 + Vyacheslav Trushkin 2011-2012 + Vystoropskyi, Sergii 2015 + Wataru Tanitsu 2010 + Wenjian Ma 2015 + Will McLendon 2017 + YAMAMOTO Shigeru 2011 + Yasuhiro Ohara 2009 + Zefan Xu 2018 + dturlupov 2018 + heasley 2009-2011 + jaydom 2017 + jpmondet 2018 + kssoman 2018 + lihongguang 2018 + lyq140 2018 + pcarana 2018 + pogojotz 2017 + tigranmartirosyan 2017 + tmartiro 2017 + vize 2007 + 高鹏 2012 +License: GPL-2+ + +Files: lib/strl*.c +License: LGPL-2.1+ +Copyright: Copyright (C) 2016 Free Software Foundation, Inc. + +Files: lib/skiplist.* +License: BSD-0-clause +Copyright: Copyright 1990 William Pugh + +Files: lib/sha256.* +License: BSD-2-clause +Copyright: Copyright 2005,2007,2009 Colin Percival + +Files: lib/qobj.h lib/monotime.h lib/memory.* lib/hook.* lib/frratomic.h lib/ferr.* lib/compiler.h lib/module.* +License: ISC +Copyright: Copyright (c) 2015-18 David Lamparter, for NetDEF, Inc. + +Files: nhrpd/nhrp_protocol.h +License: MIT +Copyright: Copyright (c) 2007-2012 Timo Teräs <timo.teras@iki.fi> + +Files: babeld/* +License: MIT +Copyright: + Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek + Copyright 2007, 2008 by Grégoire Henry, Julien Cristau and Juliusz Chroboczek + +Files: babeld/babel_errors.* babeld/babel_memory.* +License: GPL-2+ +Copyright: Copyright (C) 2017-2018 Donald Sharp, Cumulus Networks, Inc. + +Files: ldpd/* +License: ISC +Copyright: + Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> + Copyright (c) 2003, 2004 Markus Friedl <markus@openbsd.org> + Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org> + Copyright (c) 2004, 2005, 2012 Claudio Jeker <claudio@openbsd.org> + Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> + Copyright (c) 2012 Alexander Bluhm <bluhm@openbsd.org> + Copyright (c) 2013-2016 Renato Westphal <renato@openbsd.org> + Copyright (C) 2016 by Open Source Routing. + +Files: ldpd/ldp_debug.* ldpd/ldp_vty* ldpd/ldp_zebra.c +License: GPL-2+ +Copyright: + Copyright (C) 2016 by Open Source Routing. + +Files: doc/user/*.rst doc/figures/fig* +Copyright: Copyright (c) 1996-2018 Kunihiro Ishiguro, et al. +License: FRR-docs + Permission is granted to make and distribute verbatim copies of this + manual provided the copyright notice and this permission notice are + preserved on all copies. + . + Permission is granted to copy and distribute modified versions of this + manual under the conditions for verbatim copying, provided that the + entire resulting derived work is distributed under the terms of a + permission notice identical to this one. + . + Permission is granted to copy and distribute translations of this manual + into another language, under the above conditions for modified versions, + except that this permission notice may be stated in a translation + approved by Kunihiro Ishiguro. + +Files: lib/freebsd-queue.h lib/openbsd-queue.h lib/md5.* +License: BSD-3-clause +Copyright: + Copyright (c) 1991, 1993 The Regents of the University of California. + Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + Copyright (C) 2004 6WIND <Vincent.Jardin@6WIND.com> + +Files: lib/openbsd-tree.* +License: BSD-2-clause +Copyright: + Copyright 2002 Niels Provos <provos@citi.umich.edu> + Copyright (c) 2016 David Gwynne <dlg@openbsd.org> + +Files: lib/imsg* +License: ISC +Copyright: + Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> + Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org> + Copyright (c) 2006, 2007, 2008 Reyk Floeter <reyk@openbsd.org> + +Files: isisd/dict.* +Copyright: Copyright (C) 1997 Kaz Kylheku <kaz@ashi.footprints.net> +License: custom-BSD-like + All rights are reserved by the author, with the following exceptions: + Permission is granted to freely reproduce and distribute this software, + possibly in exchange for a fee, provided that this copyright notice appears + intact. Permission is also granted to adapt this software to produce + derivative works, as long as the modified versions carry this copyright + notice and additional notices stating that the work has been modified. + This source code may be translated into executable form and incorporated + into proprietary software; there is no requirement for such software to + contain a copyright notice related to this source. + +Files: qpb/qpb.proto fpm/fpm.proto +License: ISC +Copyright: Copyright (C) 2016 Sproute Networks, Inc. + +Files: doc/extra/frrlexer.py +License: ISC +Copyright: Copyright (c) 2017 Vincent Bernat <bernat@luffy.cx> + +Files: tests/helpers/python/frrsix.py +License: MIT +Copyright: Copyright (c) 2010-2017 Benjamin Peterson + +License: GPL-2+ + This program 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 of the License, or + (at your option) any later version. + . + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + . + On Debian systems, the full text of the GNU General Public + License version 2 can be found in the file + `/usr/share/common-licenses/GPL-2'. + +License: LGPL-2.1+ + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + . + The GNU C Library 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 + Lesser General Public License for more details. + . + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. + . + On Debian systems, the full text of the GNU Lesser General Public + License version 2.1 can be found in the file + `/usr/share/common-licenses/LGPL-2.1'. + +License: BSD-0-clause + Redistribution and use in source and binary forms, with or without + modification, are permitted. + . + THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + +License: BSD-2-clause + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + . + THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + +License: BSD-3-clause + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 4. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + . + THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + +License: ISC + Permission to use, copy, modify, and 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 THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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. + +License: MIT + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + . + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + . + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. diff --git a/debian/frr-doc.doc-base b/debian/frr-doc.doc-base new file mode 100644 index 0000000000..ec7870d7aa --- /dev/null +++ b/debian/frr-doc.doc-base @@ -0,0 +1,23 @@ +Document: frr +Title: FRRouting user manual +Abstract: General user/operator description for the FRRouting suite of + routing protocol daemons. +Section: Network/Communication + +Format: HTML +Index: /usr/share/doc/frr/html/index.html +Files: /usr/share/doc/frr/html/* + +Format: info +Index: /usr/share/info/frr.info.gz +Files: + /usr/share/info/frr.info.gz + /usr/share/info/fig-normal-processing.png + /usr/share/info/fig-rs-processing.png + /usr/share/info/fig-vnc-commercial-route-reflector.png + /usr/share/info/fig-vnc-frr-route-reflector.png + /usr/share/info/fig-vnc-gw.png + /usr/share/info/fig-vnc-mesh.png + /usr/share/info/fig-vnc-redundant-route-reflectors.png + /usr/share/info/fig_topologies_full.png + /usr/share/info/fig_topologies_rs.png diff --git a/debianpkg/frr-doc.info b/debian/frr-doc.info index a83255a24f..a83255a24f 100644 --- a/debianpkg/frr-doc.info +++ b/debian/frr-doc.info diff --git a/debian/frr-doc.install b/debian/frr-doc.install new file mode 100644 index 0000000000..c48dc5a8db --- /dev/null +++ b/debian/frr-doc.install @@ -0,0 +1,10 @@ +# html docs include RST sources +usr/share/doc/frr/html + +# info + images referenced by it +usr/share/info/ +doc/user/_build/texinfo/*.png usr/share/info + +# other +README.md usr/share/doc/frr +doc/figures/*.png usr/share/doc/frr diff --git a/debian/frr-doc.lintian-overrides b/debian/frr-doc.lintian-overrides new file mode 100644 index 0000000000..d4ada822a5 --- /dev/null +++ b/debian/frr-doc.lintian-overrides @@ -0,0 +1,2 @@ +# personal name +spelling-error-in-copyright Ang And diff --git a/debian/frr-pythontools.install b/debian/frr-pythontools.install new file mode 100644 index 0000000000..28140382f6 --- /dev/null +++ b/debian/frr-pythontools.install @@ -0,0 +1 @@ +usr/lib/frr/frr-reload.py diff --git a/debian/frr-pythontools.lintian-overrides b/debian/frr-pythontools.lintian-overrides new file mode 100644 index 0000000000..d4ada822a5 --- /dev/null +++ b/debian/frr-pythontools.lintian-overrides @@ -0,0 +1,2 @@ +# personal name +spelling-error-in-copyright Ang And diff --git a/debian/frr-rpki-rtrlib.install b/debian/frr-rpki-rtrlib.install new file mode 100644 index 0000000000..0465c0d910 --- /dev/null +++ b/debian/frr-rpki-rtrlib.install @@ -0,0 +1 @@ +usr/lib/*/frr/modules/bgpd_rpki.so diff --git a/debian/frr-rpki-rtrlib.lintian-overrides b/debian/frr-rpki-rtrlib.lintian-overrides new file mode 100644 index 0000000000..3927731760 --- /dev/null +++ b/debian/frr-rpki-rtrlib.lintian-overrides @@ -0,0 +1,5 @@ +# module contains no function calls that can be hardened +frr-rpki-rtrlib binary: hardening-no-fortify-functions * + +# personal name +spelling-error-in-copyright Ang And diff --git a/debian/frr-snmp.install b/debian/frr-snmp.install new file mode 100644 index 0000000000..5517ca7eec --- /dev/null +++ b/debian/frr-snmp.install @@ -0,0 +1,2 @@ +usr/lib/*/frr/libfrrsnmp.* +usr/lib/*/frr/modules/*_snmp.so diff --git a/debian/frr-snmp.lintian-overrides b/debian/frr-snmp.lintian-overrides new file mode 100644 index 0000000000..d4ada822a5 --- /dev/null +++ b/debian/frr-snmp.lintian-overrides @@ -0,0 +1,2 @@ +# personal name +spelling-error-in-copyright Ang And diff --git a/debianpkg/frr.conf b/debian/frr.conf index dee3cd849a..dee3cd849a 100644 --- a/debianpkg/frr.conf +++ b/debian/frr.conf diff --git a/debianpkg/frr.dirs b/debian/frr.dirs index 4b05c8c907..4b05c8c907 100644 --- a/debianpkg/frr.dirs +++ b/debian/frr.dirs diff --git a/debianpkg/frr.docs b/debian/frr.docs index f72aae1967..34dbbd7bc7 100644 --- a/debianpkg/frr.docs +++ b/debian/frr.docs @@ -1,2 +1,2 @@ -tools +tools/zebra.el debian/README.Debian diff --git a/debian/frr.install b/debian/frr.install new file mode 100644 index 0000000000..ebb87a0b3e --- /dev/null +++ b/debian/frr.install @@ -0,0 +1,16 @@ +etc/ +usr/bin/vtysh +usr/bin/mtracebis +usr/lib/*/frr/libfrr.* +usr/lib/*/frr/libfrrospfapiclient.* +usr/lib/frr/*.sh +usr/lib/frr/*d +usr/lib/frr/watchfrr +usr/lib/frr/zebra +usr/lib/*/frr/modules/zebra_irdp.so +usr/lib/*/frr/modules/zebra_fpm.so +usr/share/doc/frr/examples +usr/share/man/ +usr/share/yang/ +tools/frr-reload usr/lib/frr/ +debian/frr.conf usr/lib/tmpfiles.d diff --git a/debian/frr.lintian-overrides b/debian/frr.lintian-overrides new file mode 100644 index 0000000000..a3e6fcdc25 --- /dev/null +++ b/debian/frr.lintian-overrides @@ -0,0 +1,10 @@ +# function names & co. +frr binary: spelling-error-in-binary usr/lib/*/frr/libfrr.so.0.0.0 writen written +frr binary: spelling-error-in-binary usr/lib/*/frr/libfrrospfapiclient.so.0.0.0 writen written +frr binary: spelling-error-in-binary usr/lib/frr/ospfd writen written +frr binary: spelling-error-in-binary usr/lib/frr/zebra writen written +frr binary: spelling-error-in-binary usr/lib/frr/pimd writen written +frr binary: spelling-error-in-binary usr/lib/frr/pimd iif if + +# personal name +spelling-error-in-copyright Ang And diff --git a/debianpkg/frr.logrotate b/debian/frr.logrotate index 1dc9122ac4..1dc9122ac4 100644 --- a/debianpkg/frr.logrotate +++ b/debian/frr.logrotate diff --git a/debianpkg/frr.manpages b/debian/frr.manpages index f5aa972304..f5aa972304 100644 --- a/debianpkg/frr.manpages +++ b/debian/frr.manpages diff --git a/debianpkg/frr.pam b/debian/frr.pam index 2b106d43bc..2b106d43bc 100644 --- a/debianpkg/frr.pam +++ b/debian/frr.pam diff --git a/debian/frr.postinst b/debian/frr.postinst new file mode 100644 index 0000000000..505ff8eaf8 --- /dev/null +++ b/debian/frr.postinst @@ -0,0 +1,96 @@ +#!/bin/sh +set -e + +# most of this file makes sense to execute regardless of whether this is any +# of normal "configure" or error-handling "abort-upgrade", "abort-remove" or +# "abort-deconfigure" + +addgroup --system frrvty +addgroup --system frr +adduser \ + --system \ + --ingroup frr \ + --home /nonexistent \ + --gecos "Frr routing suite" \ + --no-create-home \ + frr +usermod -a -G frrvty frr + +mkdir -p /var/log/frr +mkdir -p /etc/frr + + +# only change ownership of files when they were previously owned by root or +# quagga; this is to ensure we don't trample over some custom user setup. +# +# if we are on a freshly installed package (or we added new configfiles), +# the files should be owned by root by default so we should end up with "frr" +# owned configfiles. + +quaggauid=`id -u quagga 2>/dev/null || echo 0` +quaggagid=`id -g quagga 2>/dev/null || echo 0` + +find \ + /etc/frr \ + /var/log/frr \ + \( -uid 0 -o -uid $quaggauid \) -a \ + \( -gid 0 -o -gid $quaggauid \) | \ + while read filename; do + + # don't chown anything that has ACLs (but don't fail if we don't + # have getfacl) + if { getfacl -c "$filename" 2>/dev/null || true; } \ + | egrep -q -v '^((user|group|other)::|$)'; then + : + else + chown frr: "$filename" + chmod o-rwx "$filename" + fi +done + +# fix misconfigured vtysh.conf & frr.conf ownership caused by config save +# mishandling in earlier FRR (and Quagga) versions +find /etc/frr -maxdepth 1 \( -name vtysh.conf -o -name frr.conf \) \ + -group frrvty -exec chgrp frr {} \; + +# more Quagga -> FRR upgrade smoothing. Not technically needed, but let's +# at least do the straightforward pieces. + +check_old_config() { + oldcfg="$1" + [ -r "$oldcfg" ] || return 0 + [ -s "$oldcfg" ] || return 0 + grep -v '^[[:blank:]]*\(#\|$\)' "$oldcfg" > /dev/null || return 0 + + cat >&2 <<EOF +Note: deprecated $oldcfg is present. This file is still read by +the FRR service but its contents should be migrated to /etc/frr/daemons. +EOF +} + +rmsum() { + fname="$1" + test -f "$1" || return 0 + fhash="`sha1sum \"$fname\"`" + fhash="${fhash%% *}" + if test "$fhash" = "$2"; then + rm "$fname" + fi +} + +case "$1" in +configure) + check_old_config /etc/frr/daemons.conf + check_old_config /etc/default/frr + if test -f /etc/frr/.pkg.frr.nointegrated; then + # remove integrated config setup + # (if checksums match, the files match freshly installed + # defaults, but the user has split config in place) + rmsum /etc/frr/vtysh.conf 5e7e3a488c51751e1ff98f27c9ad6085e1ad9cbb + rmsum /etc/frr/frr.conf dac6f2af4fca9919ba40eb338885a5d1773195c8 + rm /etc/frr/.pkg.frr.nointegrated + fi + ;; +esac + +#DEBHELPER# diff --git a/debian/frr.postrm b/debian/frr.postrm new file mode 100644 index 0000000000..018f59e1c5 --- /dev/null +++ b/debian/frr.postrm @@ -0,0 +1,14 @@ +#!/bin/sh +set -e + +rm -f /etc/frr/.pkg.frr.nointegrated + +if [ "$1" = "purge" ]; then + rm -rf /run/frr || true + + # "purge" does not remove logfiles. therefore we shouldn't delete + # the "frr" user/group since that would leave files with "dangling" + # ownership. +fi + +#DEBHELPER# diff --git a/debian/frr.preinst b/debian/frr.preinst new file mode 100644 index 0000000000..0e10e39247 --- /dev/null +++ b/debian/frr.preinst @@ -0,0 +1,93 @@ +#!/bin/bash +set -e +# bash is required since /etc/frr/daemons.conf used a bash array in some +# previous versions. + +# NOTE: this code exists specifically to make migrations from Quagga to +# FRR easier. FRR is able to load most Quagga configurations, but the +# config handling itself has changed with the move towards the "integrated" +# /etc/frr/frr.conf approach instead of separate per-daemon config files. +# +# That said, with this in place there's a good chance users can use a +# preexisting Quagga config with little hassle. + +case "$1" in +install|upgrade) + ( + test -f /etc/frr/daemons && . /etc/frr/daemons + test -f /etc/frr/daemons.conf && . /etc/frr/daemons.conf + test -f /etc/default/frr && . /etc/default/frr + + if [ "$watchfrr_enable" = no -o \ + "$watchfrr_enable" = "0" ]; then + cat >&2 <<EOF +ERROR: Pre-existing frr configuration file disables watchfrr. + +This configuration is deprecated upstream and not supported by the Debian +FRR package. Refusing to $1 in order to not break running setups. +Please change your setup to use watchfrr and remove the "watchfrr_enable" +option from /etc/frr/daemons, /etc/frr/daemons.conf and/or /etc/default/frr. +EOF + exit 1 + fi + ) + vtysh='' + if test -f /etc/frr/vtysh.conf; then + if grep -q '^[[:space:]]*service[[:space:]]\+integrated-vtysh-config' /etc/frr/vtysh.conf; then + # existing vtysh.conf with integrated statement + # - do nothing (=> integrated config) + vtysh='i' + elif grep -q '^[[:space:]]*no[[:space:]]\+service[[:space:]]\+integrated-vtysh-config' /etc/frr/vtysh.conf; then + # explicit non-integrated + # => need to fix vtysh.conf & frr.conf in postinst + vtysh='ni' + if test -f /etc/frr/frr.conf; then + cat >&2 <<EOF +ERROR: Pre-existing /etc/frr/vtysh.conf specifies +"no service integrated-vtysh-config", but /etc/frr/frr.conf exists. This +will cause the frr package to malfunction. Please remove /etc/frr/frr.conf +or remove the "no service integrated-vtysh-config" statement from +/etc/frr/vtysh.conf. +EOF + exit 1 + fi + else + # vtysh.conf exists but has no statement + : + fi + fi + if test -f /etc/frr/frr.conf; then + # vtysh.conf has no explicit statement but frr.conf exists + # => integrated config used + vtysh='i' + elif test -f /etc/frr/zebra.conf \ + -o -f /etc/frr/bgpd.conf \ + -o -f /etc/frr/ospfd.conf \ + -o -f /etc/frr/ospf6d.conf \ + -o -f /etc/frr/ripd.conf \ + -o -f /etc/frr/ripngd.conf \ + -o -f /etc/frr/isisd.conf \ + -o -f /etc/frr/pimd.conf \ + -o -f /etc/frr/ldpd.conf \ + -o -f /etc/frr/nhrpd.conf \ + -o -f /etc/frr/eigrpd.conf \ + -o -f /etc/frr/babeld.conf \ + -o -f /etc/frr/pbrd.conf \ + -o -f /etc/frr/bfdd.conf; then + # no explicit statement, but some split config file exists + # => need to fix vtysh.conf & frr.conf in postinst + test -n "$vtysh" || vtysh='ni' + else + # no config at all - use integrated + : + fi + if test "$vtysh" = "ni"; then + touch /etc/frr/.pkg.frr.nointegrated + fi + ;; +abort-upgrade) + # shouldn't fail an upgrade abort + ;; +esac + +#DEBHELPER# diff --git a/debian/not-installed b/debian/not-installed new file mode 100644 index 0000000000..1a89f35853 --- /dev/null +++ b/debian/not-installed @@ -0,0 +1,3 @@ +usr/include +usr/lib/frr/ospfclient +usr/lib/frr/rfptest diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000000..a546f38d70 --- /dev/null +++ b/debian/rules @@ -0,0 +1,120 @@ +#!/usr/bin/make -f + +# standard Debian options & profiles + +export DEB_BUILD_MAINT_OPTIONS = hardening=+all + +ifneq (,$(filter terse,$(DEB_BUILD_OPTIONS))) + MAKE_SILENT="V=0" + export DH_VERBOSE=0 +else + MAKE_SILENT="V=1" + export DH_VERBOSE=1 + export DH_OPTIONS=-v +endif + +# package-specific build profiles + +ifeq ($(filter pkg.frr.nortrlib,$(DEB_BUILD_PROFILES)),) + CONF_RPKI=--enable-rpki +else + CONF_RPKI=--disable-rpki +endif + +ifeq ($(filter pkg.frr.nosystemd,$(DEB_BUILD_PROFILES)),) + DH_WITH_SYSTEMD=systemd, + CONF_SYSTEMD=--enable-systemd=yes +else + DH_WITH_SYSTEMD= + CONF_SYSTEMD=--enable-systemd=no +endif + +export PYTHON=python3 + +%: + dh $@ --with=$(DH_WITH_SYSTEMD)autoreconf --parallel + +override_dh_auto_configure: + $(shell dpkg-buildflags --export=sh); \ + dh_auto_configure -- \ + --enable-exampledir=/usr/share/doc/frr/examples/ \ + --localstatedir=/var/run/frr \ + --sbindir=/usr/lib/frr \ + --sysconfdir=/etc/frr \ + --with-vtysh-pager=/usr/bin/pager \ + --libdir=/usr/lib/$(DEB_HOST_MULTIARCH)/frr \ + --with-moduledir=/usr/lib/$(DEB_HOST_MULTIARCH)/frr/modules \ + LIBTOOLFLAGS="-rpath /usr/lib/$(DEB_HOST_MULTIARCH)/frr" \ + --disable-dependency-tracking \ + \ + $(CONF_SYSTEMD) \ + $(CONF_RPKI) \ + --with-libpam \ + --enable-doc \ + --enable-doc-html \ + --enable-snmp \ + --enable-fpm \ + --disable-protobuf \ + --disable-zeromq \ + --enable-ospfapi \ + --enable-bgp-vnc \ + --enable-multipath=256 \ + \ + --enable-user=frr \ + --enable-group=frr \ + --enable-vty-group=frrvty \ + --enable-configfile-mask=0640 \ + --enable-logfile-mask=0640 \ + # end + +override_dh_auto_install: + dh_auto_install + + sed -e '1c #!/usr/bin/python3' -i debian/tmp/usr/lib/frr/frr-reload.py + +# let dh_systemd_* and dh_installinit do their thing automatically +ifeq ($(filter pkg.frr.nosystemd,$(DEB_BUILD_PROFILES)),) + cp tools/frr.service debian/frr.service +endif + cp tools/frrinit.sh debian/frr.init + -rm -f debian/tmp/usr/lib/frr/frr + +# install config files + mkdir -p debian/tmp/etc + cp -r tools/etc/* debian/tmp/etc/ + -rm debian/tmp/etc/frr/daemons.conf + + sed -e 's#^!log file #!log file /var/log/frr/#' -i debian/tmp/usr/share/doc/frr/examples/*sample* + +# drop dev-only files + find debian/tmp -name '*.la' -o -name '*.a' -o -name 'lib*.so' | xargs rm -f + rm -rf debian/tmp/usr/include + -rm debian/tmp/usr/lib/frr/ssd + +# use installed js libraries + -rm -f debian/tmp/usr/share/doc/frr/html/_static/jquery.js + ln -s /usr/share/javascript/jquery/jquery.js debian/tmp/usr/share/doc/frr/html/_static/jquery.js + -rm -f debian/tmp/usr/share/doc/frr/html/_static/underscore.js + ln -s /usr/share/javascript/underscore/underscore.js debian/tmp/usr/share/doc/frr/html/_static/underscore.js + +override_dh_auto_build: + dh_auto_build -- $(MAKE_SILENT) + +override_dh_installinit: + dh_installinit -r + +override_dh_installsystemd: + dh_installsystemd -r + +override_dh_makeshlibs: + dh_makeshlibs -n + +override_dh_missing: + dh_missing --fail-missing + +override_dh_auto_clean: +# we generally do NOT want a full distclean since that wipes both +# debian/changelog and config.version + if test -f Makefile; then make redistclean; fi + -rm -f debian/frr.init + -rm -f debian/frr.service diff --git a/debianpkg/source/format b/debian/source/format index af745b310b..af745b310b 100644 --- a/debianpkg/source/format +++ b/debian/source/format diff --git a/debian/source/lintian-overrides b/debian/source/lintian-overrides new file mode 100644 index 0000000000..112182c779 --- /dev/null +++ b/debian/source/lintian-overrides @@ -0,0 +1,2 @@ +# Debian Jessie and Ubuntu 16.04 need dh-systemd +frr source: ored-build-depends-on-obsolete-package diff --git a/debian/tests/bgpd-snmp-rpki b/debian/tests/bgpd-snmp-rpki new file mode 100755 index 0000000000..930b8c26dc --- /dev/null +++ b/debian/tests/bgpd-snmp-rpki @@ -0,0 +1,22 @@ +#!/bin/sh +set -e + +# enable bgpd with SNMP & RPKI modules +cat >> /etc/frr/daemons <<EOF +bgpd=yes +bgpd_options="-A 127.0.0.1 -Msnmp -Mrpki" +EOF + +service frr restart + +# check that it actually started +pgrep watchfrr +pgrep zebra +pgrep bgpd + +# just for debugging +vtysh -c 'show modules' + +# ... and SNMP & RPKI should be loaded +vtysh -c 'show modules' | grep -q snmp +vtysh -c 'show modules' | grep -q rpki diff --git a/debian/tests/control b/debian/tests/control new file mode 100644 index 0000000000..5990a69370 --- /dev/null +++ b/debian/tests/control @@ -0,0 +1,11 @@ +Tests: zebra-lo +Depends: frr +Restrictions: needs-root, isolation-container + +Tests: bgpd-snmp-rpki +Depends: frr, frr-snmp, frr-rpki-rtrlib +Restrictions: needs-root, isolation-container + +Tests: py-frr-reload +Depends: frr, frr-pythontools +Restrictions: needs-root, isolation-container diff --git a/debian/tests/py-frr-reload b/debian/tests/py-frr-reload new file mode 100755 index 0000000000..e2c97e8744 --- /dev/null +++ b/debian/tests/py-frr-reload @@ -0,0 +1,28 @@ +#!/bin/sh +set -e + +# should have been started on install, but policy may have inhibited that +service frr restart + +# these should be running by default +pgrep watchfrr +pgrep zebra +pgrep staticd + +# configure interactively, save to file +vtysh -c 'configure terminal' -c 'ip route 198.51.100.0/28 127.0.0.1' +vtysh -c 'show running-config' | grep -q 'ip route 198.51.100.0/28 127.0.0.1' +vtysh -c 'write memory' + +grep -q 'ip route 198.51.100.0/28 127.0.0.1' /etc/frr/frr.conf + +# configure in file, check interactively +sed -e '/^ip route 198.51.100.0\/28 127.0.0.1/ c ip route 198.51.100.64/28 127.0.0.1' \ + -i /etc/frr/frr.conf + +service frr reload + +vtysh -c 'show running-config' | grep -q 'ip route 198.51.100.64/28 127.0.0.1' +if vtysh -c 'show running-config' | grep -q 'ip route 198.51.100.0/28 127.0.0.1'; then + exit 1 +fi diff --git a/debian/tests/zebra-lo b/debian/tests/zebra-lo new file mode 100755 index 0000000000..2a388d5da7 --- /dev/null +++ b/debian/tests/zebra-lo @@ -0,0 +1,16 @@ +#!/bin/sh +set -e + +# should have been started on install, but policy may have inhibited that +service frr status >/dev/null || service frr restart + +# these should be running by default +pgrep watchfrr +pgrep zebra +pgrep staticd + +# check vtysh works at all +vtysh -c 'show version' + +# check zebra is properly talking to the kernel +vtysh -c 'show interface lo' | grep -q LOOPBACK diff --git a/debian/watch b/debian/watch new file mode 100644 index 0000000000..c286392d7e --- /dev/null +++ b/debian/watch @@ -0,0 +1,4 @@ +version=4 + +https://github.com/FRRouting/frr/releases/ \ + download/frr-(?:\d[\d.]*)/frr-(\d[\d.]*)\.tar\.xz debian uupdate diff --git a/debianpkg/watchfrr.rc b/debian/watchfrr.rc index 4110b86399..4110b86399 100644 --- a/debianpkg/watchfrr.rc +++ b/debian/watchfrr.rc diff --git a/debianpkg/.gitignore b/debianpkg/.gitignore deleted file mode 100644 index 6d10dce740..0000000000 --- a/debianpkg/.gitignore +++ /dev/null @@ -1 +0,0 @@ -changelog diff --git a/debianpkg/backports/.gitignore b/debianpkg/backports/.gitignore deleted file mode 100644 index 3b20d26891..0000000000 --- a/debianpkg/backports/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*/*.dirhash -*/debian/changelog diff --git a/debianpkg/backports/README b/debianpkg/backports/README deleted file mode 100644 index efd322e1d9..0000000000 --- a/debianpkg/backports/README +++ /dev/null @@ -1,28 +0,0 @@ -This directory contains the debian directories for backports to other debian -platforms. These are built via the `3.0 (custom)' source format, which -allows one to build a source package directly out of tarballs (e.g. an -orig.tar.gz tarball and a debian.tar.gz file), at which point the format can -be changed to a real format (e.g. `3.0 (quilt)'). - -Source packages are assembled via targets of the same name as the system to -which the backport is done (e.g. `precise'), included in debian/rules. - -To create a new debian backport: - -* Add its name to `KNOWN_BACKPORTS', defined in debian/rules. -* Create a directory of the same name in debian/backports. -* Add the files `exclude', `versionext', and `debian/source/format' under - this directory: - * `exclude' contains whitespace-separated paths (relative to the root of - the source dir) that should be excluded from the source package (e.g. - debian/patches). - * `versionext' contains the suffix added to the version number for this - backport's build. Distributions often have guidelines for what this - should be. If left empty, no new debian/changelog entry is created. - * `debian/source/format' should contain the source format of the resulting - source package. As of of the writing of this document the only supported - format is `3.0 (quilt)'. -* Add appropriate files under the `debian/' subdirectory. These will be - included in the source package, overriding any top-level `debian/' files - with equivalent paths. - diff --git a/debianpkg/backports/debian8/debian/source/format b/debianpkg/backports/debian8/debian/source/format deleted file mode 100644 index 163aaf8d82..0000000000 --- a/debianpkg/backports/debian8/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (quilt) diff --git a/debianpkg/backports/debian8/versionext b/debianpkg/backports/debian8/versionext deleted file mode 100644 index 4824521f8c..0000000000 --- a/debianpkg/backports/debian8/versionext +++ /dev/null @@ -1 +0,0 @@ --1~debian8+1 diff --git a/debianpkg/backports/debian9/debian/source/format b/debianpkg/backports/debian9/debian/source/format deleted file mode 100644 index 163aaf8d82..0000000000 --- a/debianpkg/backports/debian9/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (quilt) diff --git a/debianpkg/backports/debian9/exclude b/debianpkg/backports/debian9/exclude deleted file mode 100644 index e69de29bb2..0000000000 --- a/debianpkg/backports/debian9/exclude +++ /dev/null diff --git a/debianpkg/backports/debian9/versionext b/debianpkg/backports/debian9/versionext deleted file mode 100644 index db85932115..0000000000 --- a/debianpkg/backports/debian9/versionext +++ /dev/null @@ -1 +0,0 @@ --1~debian9+1 diff --git a/debianpkg/backports/rules b/debianpkg/backports/rules deleted file mode 100755 index d0c6dcc066..0000000000 --- a/debianpkg/backports/rules +++ /dev/null @@ -1,137 +0,0 @@ -.PHONY: backports $(KNOWN_BACKPORTS) - -# error out if these files are missing -required_files = $(foreach backport,$(KNOWN_BACKPORTS), \ - $(addprefix debian/backports/$(backport)/, \ - debian/source/format \ - versionext \ - exclude)) -$(if $(filter-out $(wildcard $(required_files)),$(required_files)), \ - $(error missing required backports files: \ - $(filter-out $(wildcard $(required_files)),$(required_files)). \ - see debian/backports/README) \ -) - -TARBALLDIR ?= $(shell dh_testdir debian/changelog && realpath .) - -define backports-targets -# if this file is empty, no automatic changelog entry is created -VERSIONEXT_$(1) ?= $(strip \ - $(shell cat $(wildcard debian/backports/$(1)/versionext))) -DEBIAN_VERSION_$(1) = $(DEBIAN_VERSION)$$(VERSIONEXT_$(1)) -BACKPORTDIR_$(1) = $(realpath debian/backports/$(1)) - -# as of right now, must be '3.0 (quilt)' -SOURCEFORMAT_$(1) ?= $(strip \ - $(shell cat debian/backports/$(1)/debian/source/format)) - -# files checked for the dirhash (see below) -FINDCMD_$(1) = find -L debian/backports/$(1)/debian \ - -type f \ - ! -path debian/backports/$(1)/debian/changelog - -# files *not* pulled from the root debian directory into the backport tarball: -# debian/changelog (copied and edited for backport version entry) -# debian/backports itself (relevant contents are copied out separately) -# anything provided in the current backports debian dir -# anything specified in the 'exclude' file in the current backports debian dir -EXCLUDEROOT_$(1) = debian/changelog debian/backports \ - $$(subst debian/backports/$(1)/,,$$(shell $$(FINDCMD_$(1)))) \ - $$(shell cat debian/backports/$(1)/exclude) - -EXCLUDEROOT_TAR_$(1) = $$(foreach file,$$(EXCLUDEROOT_$(1)),--exclude $$(file)) -EXCLUDEROOT_FIND_$(1) = $$(foreach file,$$(EXCLUDEROOT_$(1)),-o -path $$(file)) - -# find command resulting in all files that *will* be pulled into the backport -# tarball. -FINDCMDROOT_$(1) = find -L debian/ \ - '(' -false $$(EXCLUDEROOT_FIND_$(1)) ')' -prune -o \ - -type f -a '!' '(' -false $$(EXCLUDEROOT_FIND_$(1)) ')' - -# usually using `find' output for dependencies has the downfall of not tracking -# file removal. Work around that by introducing a dependency on a file whose -# name contains the hash of `find' output, so that the name will change when a -# file is deleted. -DIRHASH_$(1) = \ - $$(shell $$(FINDCMD_$(1)) | sha1sum | sed -r 's/^(......).*/\1/') -DIRHASHROOT_$(1) = \ - $$(shell $$(FINDCMDROOT_$(1)) | sha1sum | sed -r 's/^(......).*/\1/') - -CONTROL_$(1) = $$(strip \ - $$(if $$(wildcard $$(BACKPORTDIR_$(1))/debian/control), \ - $$(BACKPORTDIR_$(1))/debian/control, \ - $(realpath debian/control) \ - )) - -# TARGETS: - -$(1): $(TARBALLDIR)/$(SRCPKG)_$$(DEBIAN_VERSION_$(1)).dsc ; - -# we use 3.0 (custom) to build a source package directly from tarballs, -# bypassing the usual checks (which wouldn't like our combination-of- -# directories approach) -$(TARBALLDIR)/$(SRCPKG)_$$(DEBIAN_VERSION_$(1)).dsc: - dpkg-source -l$$(BACKPORTDIR_$(1))/debian/changelog \ - -c$$(CONTROL_$(1)) \ - --format='3.0 (custom)' \ - --target-format='$$(SOURCEFORMAT_$(1))' \ - -b . $$^ - mv $(TARBALLDIR)/../$$(notdir $$@) $$@ - -ifeq ($$(SOURCEFORMAT_$(1)),3.0 (quilt)) -# this target depends on the orig.tar.gz file, for which there is no target in -# this makefile. It is assumed to either already exist or be built by a target -# provided elsewhere in debian/rules (e.g. via pristine-tar) -$$(if $$(findstring $(ORIG_VERSION),$$(DEBIAN_VERSION_$(1))), \ - $$(info downstream version matches upstream version (good)), \ - $$(error quilt format expects downstream version \ - ($$(DEBIAN_VERSION_$(1))) to contain upstream version \ - ($(ORIG_VERSION)). Make a new debian/changelog entry \ - to reflect the new upstream release) \ -) - -$(TARBALLDIR)/$(SRCPKG)_$$(DEBIAN_VERSION_$(1)).dsc: \ - $(TARBALLDIR)/$(SRCPKG)_$(ORIG_VERSION).orig.tar.gz \ - $(TARBALLDIR)/$(SRCPKG)_$$(DEBIAN_VERSION_$(1)).debian.tar.xz -else -$$(error unsupported source format for $(1) backport: $$(SOURCEFORMAT_$(1))) -endif #SOURCEFORMAT_$(1) - -# for 3.0 (quilt) -$(TARBALLDIR)/$(SRCPKG)_$$(DEBIAN_VERSION_$(1)).debian.tar.xz: \ - $$(BACKPORTDIR_$(1))/debian/changelog \ - $$(shell $$(FINDCMD_$(1))) \ - $$(BACKPORTDIR_$(1))/$$(DIRHASH_$(1)).backport.dirhash \ - $$(shell $$(FINDCMDROOT_$(1))) \ - $$(BACKPORTDIR_$(1))/$$(DIRHASHROOT_$(1)).root.dirhash \ - $$(BACKPORTDIR_$(1))/exclude - rm -f $$(subst .tar.xz,.tar,$$@) $$@ - tar -chf $$(subst .tar.xz,.tar,$$@) \ - --exclude-vcs $$(EXCLUDEROOT_TAR_$(1)) debian/ - cd debian/backports/$(1) && tar -uhf $$(subst .tar.xz,.tar,$$@) \ - --exclude-vcs debian/ - xz $$(subst .tar.xz,.tar,$$@) - -$$(BACKPORTDIR_$(1))/debian/changelog: \ - debian/changelog \ - debian/backports/$(1)/versionext - rm -f debian/backports/$(1)/debian/changelog - cp $$< $$@ - $(if $$(VERSIONEXT_$(1)), \ - dch -c $$@ -v '$$(DEBIAN_VERSION_$(1))' -b \ - 'backport to $(1) systems', \ - ) - -$$(BACKPORTDIR_$(1))/$$(DIRHASH_$(1)).backport.dirhash: - rm -f debian/backports/$(1)/*.backport.dirhash - touch $$@ - -$$(BACKPORTDIR_$(1))/$$(DIRHASHROOT_$(1)).root.dirhash: - rm -f debian/backports/$(1)/*.root.dirhash - touch $$@ - -endef # backports-targets -$(foreach backport,$(KNOWN_BACKPORTS),$(eval \ - $(call backports-targets,$(backport)))) - -backports: $(KNOWN_BACKPORTS) diff --git a/debianpkg/backports/ubuntu14.04/debian/control b/debianpkg/backports/ubuntu14.04/debian/control deleted file mode 100644 index 3f31f18462..0000000000 --- a/debianpkg/backports/ubuntu14.04/debian/control +++ /dev/null @@ -1,56 +0,0 @@ -Source: frr -Section: net -Priority: optional -Maintainer: Nobody <nobody@frrouting.org> -Uploaders: Nobody <nobody@frrouting.org> -XSBC-Original-Maintainer: <maintainers@frrouting.org> -Build-Depends: debhelper (>= 7.0.50~), libncurses5-dev, libreadline-dev, texlive-latex-base, texlive-generic-recommended, libpam0g-dev | libpam-dev, libcap-dev, texinfo (>= 4.7), imagemagick, ghostscript, groff, autotools-dev, libpcre3-dev, gawk, chrpath, libsnmp-dev, git, dh-autoreconf, libjson-c-dev, libjson-c2, pkg-config, python (>= 2.7), python-ipaddr -Standards-Version: 3.9.6 -Homepage: http://www.frrouting.org/ -XS-Testsuite: autopkgtest - -Package: frr -Architecture: any -Depends: ${shlibs:Depends}, logrotate (>= 3.2-11), ${misc:Depends} -Pre-Depends: adduser -Conflicts: zebra, zebra-pj, quagga -Replaces: zebra, zebra-pj -Suggests: snmpd -Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon forked from Quagga - FRR is free software which manages TCP/IP based routing protocols. - It supports BGP4, BGP4+, OSPFv2, OSPFv3, IS-IS, RIPv1, RIPv2, RIPng, - PIM and LDP as well as the IPv6 versions of these. - . - FRR is a fork of Quagga with an open community model. The main git - lives on https://github.com/frrouting/frr.git - -Package: frr-dbg -Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, frr (= ${binary:Version}) -Priority: extra -Section: debug -Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon (debug symbols) - This package provides debugging symbols for all binary packages built - from frr source package. It's highly recommended to have this package - installed before reporting any FRR crashes to either FRR developers or - Debian package maintainers. - -Package: frr-doc -Section: net -Architecture: all -Depends: ${misc:Depends} -Suggests: frr -Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon (documentation) - This package includes info files for frr, a free software which manages - TCP/IP based routing protocols. It supports BGP4, BGP4+, OSPFv2, OSPFv3, - IS-IS, RIPv1, RIPv2, RIPng, PIM and LDP as well as the IPv6 versions of these. - -Package: frr-pythontools -Section: net -Architecture: all -Depends: ${misc:Depends}, frr (= ${binary:Version}), python (>= 2.7), python-ipaddr -Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon (Python Tools) - This package includes info files for frr, a free software which manages - TCP/IP based routing protocols. It supports BGP4, BGP4+, OSPFv2, OSPFv3, - IS-IS, RIPv1, RIPv2, RIPng, PIM and LDP as well as the IPv6 versions of these. - diff --git a/debianpkg/backports/ubuntu14.04/debian/frr.install b/debianpkg/backports/ubuntu14.04/debian/frr.install deleted file mode 100644 index 7fb81c44a0..0000000000 --- a/debianpkg/backports/ubuntu14.04/debian/frr.install +++ /dev/null @@ -1,11 +0,0 @@ -etc/frr/ -usr/bin/vtysh -usr/bin/mtracebis -usr/include/frr/ -usr/lib/ -usr/share/doc/frr/ -usr/share/snmp/mibs/ -usr/share/yang/ -tools/etc/* etc/ -tools/*.service lib/systemd/system -debian/frr.conf usr/lib/tmpfiles.d diff --git a/debianpkg/backports/ubuntu14.04/debian/rules b/debianpkg/backports/ubuntu14.04/debian/rules deleted file mode 100755 index 21b442d85a..0000000000 --- a/debianpkg/backports/ubuntu14.04/debian/rules +++ /dev/null @@ -1,206 +0,0 @@ -#!/usr/bin/make -f - -# FRRouting Configuration options -###################################### -# -# WANT_xxxx --> Set to 1 for enable, 0 for disable -# The following are the defaults. They can be overridden by setting a -# env variable to a different value - -WANT_LDP ?= 1 -WANT_PIM ?= 1 -WANT_OSPFAPI ?= 1 -WANT_BGP_VNC ?= 1 -WANT_CUMULUS_MODE ?= 0 -WANT_MULTIPATH ?= 1 -WANT_SNMP ?= 0 -WANT_RPKI ?= 0 -WANT_BFD ?= 1 - -# NOTES: -# -# If you use WANT_RPKI, then there is a new dependency for librtr0 package -# and a build dependency of the librtr-dev package. -# While the librtr0 is added to the depenencies automatically, the build -# dependency can't be changed dynamically and building will fail if the -# librtr-dev isn't installed during package build -# Tested versions of both packages can be found at -# https://ci1.netdef.org/browse/RPKI-RTRLIB/latestSuccessful/artifact -# -# If multipath is enabled (WANT_MULTIPATH=1), then set number of multipaths here -# Please be aware that 0 is NOT disabled, but treated as unlimited - -MULTIPATH ?= 256 - -# Set the following to the value required (or leave alone for the default below) -# WANT_FRR_USER is used for the username and groupname of the FRR user account - -WANT_FRR_USER ?= frr -WANT_FRR_VTY_GROUP ?= frrvty - -# Don't build PDF docs by default -GENERATE_PDF ?= 0 - -# -#################################### - -export DH_VERBOSE=1 -export DEB_BUILD_MAINT_OPTIONS = hardening=+all -export DH_OPTIONS=-v - -ifeq ($(WANT_SNMP), 1) - USE_SNMP=--enable-snmp - $(warning "DEBIAN: SNMP enabled, sorry for your inconvenience") -else - USE_SNMP=--disable-snmp - $(warning "DEBIAN: SNMP disabled, see README.Debian") -endif - -ifeq ($(WANT_LDP), 1) - USE_LDP=--enable-ldpd -else - USE_LDP=--disable-ldpd -endif - -ifeq ($(WANT_PIM), 1) - USE_PIM=--enable-pimd -else - USE_PIM=--disable-pimd -endif - -ifeq ($(WANT_OSPFAPI), 1) - USE_OSPFAPI=--enable-ospfapi=yes -else - USE_OSPFAPI=--enable-ospfapi=no -endif - -ifeq ($(WANT_BGP_VNC), 1) - USE_BGP_VNC=--enable-bgp-vnc=yes -else - USE_BGP_VNC=--enable-bgp-vnc=no -endif - -USE_FRR_USER=--enable-user=$(WANT_FRR_USER) -USE_FRR_GROUP=--enable-group=$(WANT_FRR_USER) -USE_FRR_VTY_GROUP=--enable-vty-group=$(WANT_FRR_VTY_GROUP) - -ifeq ($(WANT_MULTIPATH), 1) - USE_MULTIPATH=--enable-multipath=$(MULTIPATH) -else - USE_MULTIPATH=--disable-multipath -endif - -ifeq ($(WANT_CUMULUS_MODE), 1) - USE_CUMULUS=--enable-cumulus=yes -else - USE_CUMULUS=--enable-cumulus=no -endif - -ifeq ($(WANT_RPKI), 1) - USE_RPKI=--enable-rpki -else - USE_RPKI=--disable-rpki -endif - -ifeq ($(WANT_BFD), 1) - USE_BFD=--enable-bfdd -else - USE_BFD=--disable-bfdd -endif - -ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) - DEBIAN_JOBS := $(subst parallel=,,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) -endif - -ifdef DEBIAN_JOBS -MAKEFLAGS += -j$(DEBIAN_JOBS) -endif - -%: - dh $@ --with=autoreconf --parallel --dbg-package=frr-dbg --list-missing - -override_dh_gencontrol: -ifeq ($(WANT_RPKI), 1) - dh_gencontrol -- -Vdist:Depends="librtr0 (>= 0.5)" -else - dh_gencontrol -endif - -override_dh_auto_configure: - # Frr needs /proc to check some BSD vs Linux specific stuff. - # Else it fails with an obscure error message pointing out that - # IPCTL_FORWARDING is an undefined symbol which is not very helpful. - @if ! [ -d /proc/1 ]; then \ - echo "./configure needs a mounted /proc"; \ - exit 1; \ - fi - - if ! [ -e config.status ]; then \ - dh_auto_configure -- \ - --enable-exampledir=/usr/share/doc/frr/examples/ \ - --localstatedir=/var/run/frr \ - --sbindir=/usr/lib/frr \ - --sysconfdir=/etc/frr \ - $(USE_SNMP) \ - $(USE_OSPFAPI) \ - $(USE_MULTIPATH) \ - $(USE_LDP) \ - --enable-fpm \ - $(USE_FRR_USER) $(USE_FRR_GROUP) \ - $(USE_FRR_VTY_GROUP) \ - --enable-configfile-mask=0640 \ - --enable-logfile-mask=0640 \ - --with-libpam \ - --enable-systemd=no \ - --enable-poll=yes \ - $(USE_CUMULUS) \ - $(USE_PIM) \ - --enable-dependency-tracking \ - $(USE_BGP_VNC) \ - $(USE_RPKI) \ - $(USE_BFD) \ - $(shell dpkg-buildflags --export=configure); \ - fi - -override_dh_auto_build: - #dh_auto_build - $(MAKE) - - # doc/ is a bit crazy -ifeq ($(GENERATE_PDF), 1) - dh_auto_build -- -C doc pdf -endif - rm -vf doc/_build/texinfo/frr.info - dh_auto_build -- -C doc info - -override_dh_auto_test: - -override_dh_auto_install: - dh_auto_install - - cp tools/frrinit.sh debian/frr.init - - # installed in frr-pythontools - rm debian/tmp/usr/lib/frr/frr-reload.py - - # cleaning up the info dir - rm -f debian/tmp/usr/share/info/dir* - - # install config files - mkdir -p debian/tmp/etc/frr/ - perl -pi -e 's#^!log file #!log file /var/log/frr/#' debian/tmp/usr/share/doc/frr/examples/*sample* - - # leftover from previously shipping SMUX client OID MIB - mkdir -p debian/tmp/usr/share/snmp/mibs/ - - # cleaning .la files - sed -i "/dependency_libs/ s/'.*'/''/" debian/tmp/usr/lib/*.la - sed -i "/dependency_libs/ s/'.*'/''/" debian/tmp/usr/lib/frr/modules/*.la - sed -i "/dependency_libs/ s/'.*'/''/" debian/tmp/usr/lib/frr/libyang_plugins/*.la - -override_dh_systemd_start: - dh_systemd_start frr.service - -override_dh_systemd_enable: - dh_systemd_enable frr.service - diff --git a/debianpkg/backports/ubuntu14.04/debian/source/format b/debianpkg/backports/ubuntu14.04/debian/source/format deleted file mode 100644 index 163aaf8d82..0000000000 --- a/debianpkg/backports/ubuntu14.04/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (quilt) diff --git a/debianpkg/backports/ubuntu14.04/exclude b/debianpkg/backports/ubuntu14.04/exclude deleted file mode 100644 index e69de29bb2..0000000000 --- a/debianpkg/backports/ubuntu14.04/exclude +++ /dev/null diff --git a/debianpkg/backports/ubuntu14.04/versionext b/debianpkg/backports/ubuntu14.04/versionext deleted file mode 100644 index c5be0650af..0000000000 --- a/debianpkg/backports/ubuntu14.04/versionext +++ /dev/null @@ -1 +0,0 @@ --1~ubuntu14.04+1 diff --git a/debianpkg/backports/ubuntu16.04/debian/source/format b/debianpkg/backports/ubuntu16.04/debian/source/format deleted file mode 100644 index 163aaf8d82..0000000000 --- a/debianpkg/backports/ubuntu16.04/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (quilt) diff --git a/debianpkg/backports/ubuntu16.04/exclude b/debianpkg/backports/ubuntu16.04/exclude deleted file mode 100644 index e69de29bb2..0000000000 --- a/debianpkg/backports/ubuntu16.04/exclude +++ /dev/null diff --git a/debianpkg/backports/ubuntu16.04/versionext b/debianpkg/backports/ubuntu16.04/versionext deleted file mode 100644 index dc33d97a12..0000000000 --- a/debianpkg/backports/ubuntu16.04/versionext +++ /dev/null @@ -1 +0,0 @@ --1~ubuntu16.04+1 diff --git a/debianpkg/backports/ubuntu17.10/debian/control b/debianpkg/backports/ubuntu17.10/debian/control deleted file mode 100644 index ce73f9d1b0..0000000000 --- a/debianpkg/backports/ubuntu17.10/debian/control +++ /dev/null @@ -1,54 +0,0 @@ -Source: frr -Section: net -Priority: optional -Maintainer: Nobody <nobody@frrouting.org> -Uploaders: Nobody <nobody@frrouting.org> -XSBC-Original-Maintainer: <maintainers@frrouting.org> -Build-Depends: debhelper (>= 7.0.50~), libncurses5-dev, libreadline-dev, texlive-latex-base, texlive-generic-recommended, libpam0g-dev | libpam-dev, libcap-dev, texinfo (>= 4.7), imagemagick, ghostscript, groff, autotools-dev, libpcre3-dev, gawk, chrpath, libsnmp-dev, git, dh-autoreconf, libjson-c-dev, libjson-c2 | libjson-c3, dh-systemd, libsystemd-dev, bison, flex, libc-ares-dev, pkg-config, python (>= 2.7), python-ipaddress, libpython-dev -Standards-Version: 3.9.6 -Homepage: http://www.frrouting.org/ - -Package: frr -Architecture: any -Depends: ${shlibs:Depends}, logrotate (>= 3.2-11), iproute2 | iproute, ${misc:Depends}, libc-ares2 -Pre-Depends: adduser -Conflicts: zebra, zebra-pj, quagga -Replaces: zebra, zebra-pj -Suggests: snmpd -Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon forked from Quagga - FRR is free software which manages TCP/IP based routing protocols. - It supports BGP4, BGP4+, OSPFv2, OSPFv3, IS-IS, RIPv1, RIPv2, RIPng, - PIM and LDP as well as the IPv6 versions of these. - . - FRR is a fork of Quagga with an open community model. The main git - lives on https://github.com/frrouting/frr.git - -Package: frr-dbg -Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, frr (= ${binary:Version}) -Priority: optional -Section: debug -Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon (debug symbols) - This package provides debugging symbols for all binary packages built - from frr source package. It's highly recommended to have this package - installed before reporting any FRR crashes to either FRR developers or - Debian package maintainers. - -Package: frr-doc -Section: net -Architecture: all -Depends: ${misc:Depends} -Suggests: frr -Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon (documentation) - This package includes info files for frr, a free software which manages - TCP/IP based routing protocols. It supports BGP4, BGP4+, OSPFv2, OSPFv3, - IS-IS, RIPv1, RIPv2, RIPng, PIM and LDP as well as the IPv6 versions of these. - -Package: frr-pythontools -Section: net -Architecture: all -Depends: ${misc:Depends}, frr (= ${binary:Version}), python (>= 2.7), python-ipaddress -Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon (Python Tools) - This package includes info files for frr, a free software which manages - TCP/IP based routing protocols. It supports BGP4, BGP4+, OSPFv2, OSPFv3, - IS-IS, RIPv1, RIPv2, RIPng, PIM and LDP as well as the IPv6 versions of these. diff --git a/debianpkg/backports/ubuntu17.10/debian/source/format b/debianpkg/backports/ubuntu17.10/debian/source/format deleted file mode 100644 index 163aaf8d82..0000000000 --- a/debianpkg/backports/ubuntu17.10/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (quilt) diff --git a/debianpkg/backports/ubuntu17.10/exclude b/debianpkg/backports/ubuntu17.10/exclude deleted file mode 100644 index e69de29bb2..0000000000 --- a/debianpkg/backports/ubuntu17.10/exclude +++ /dev/null diff --git a/debianpkg/backports/ubuntu17.10/versionext b/debianpkg/backports/ubuntu17.10/versionext deleted file mode 100644 index bfbeccd653..0000000000 --- a/debianpkg/backports/ubuntu17.10/versionext +++ /dev/null @@ -1 +0,0 @@ --1~ubuntu17.10+1 diff --git a/debianpkg/backports/ubuntu18.04/debian/control b/debianpkg/backports/ubuntu18.04/debian/control deleted file mode 100644 index 3fccb46b7a..0000000000 --- a/debianpkg/backports/ubuntu18.04/debian/control +++ /dev/null @@ -1,54 +0,0 @@ -Source: frr -Section: net -Priority: optional -Maintainer: Nobody <nobody@frrouting.org> -Uploaders: Nobody <nobody@frrouting.org> -XSBC-Original-Maintainer: <maintainers@frrouting.org> -Build-Depends: debhelper (>= 7.0.50~), libncurses5-dev, libreadline-dev, texlive-latex-base, texlive-generic-recommended, libpam0g-dev | libpam-dev, libcap-dev, texinfo (>= 4.7), imagemagick, ghostscript, groff, autotools-dev, libpcre3-dev, gawk, chrpath, libsnmp-dev, git, dh-autoreconf, libjson-c-dev, libjson-c2 | libjson-c3, dh-systemd, libsystemd-dev, bison, flex, libc-ares-dev, pkg-config, python (>= 2.7), python-ipaddress, python-sphinx, libpython-dev -Standards-Version: 3.9.6 -Homepage: http://www.frrouting.org/ - -Package: frr -Architecture: any -Depends: ${shlibs:Depends}, logrotate (>= 3.2-11), iproute2 | iproute, ${misc:Depends}, libc-ares2 -Pre-Depends: adduser -Conflicts: zebra, zebra-pj, quagga -Replaces: zebra, zebra-pj -Suggests: snmpd -Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon forked from Quagga - FRR is free software which manages TCP/IP based routing protocols. - It supports BGP4, BGP4+, OSPFv2, OSPFv3, IS-IS, RIPv1, RIPv2, RIPng, - PIM and LDP as well as the IPv6 versions of these. - . - FRR is a fork of Quagga with an open community model. The main git - lives on https://github.com/frrouting/frr.git - -Package: frr-dbg -Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, frr (= ${binary:Version}) -Priority: optional -Section: debug -Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon (debug symbols) - This package provides debugging symbols for all binary packages built - from frr source package. It's highly recommended to have this package - installed before reporting any FRR crashes to either FRR developers or - Debian package maintainers. - -Package: frr-doc -Section: net -Architecture: all -Depends: ${misc:Depends} -Suggests: frr -Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon (documentation) - This package includes info files for frr, a free software which manages - TCP/IP based routing protocols. It supports BGP4, BGP4+, OSPFv2, OSPFv3, - IS-IS, RIPv1, RIPv2, RIPng, PIM and LDP as well as the IPv6 versions of these. - -Package: frr-pythontools -Section: net -Architecture: all -Depends: ${misc:Depends}, frr (= ${binary:Version}), python (>= 2.7), python-ipaddress -Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon (Python Tools) - This package includes info files for frr, a free software which manages - TCP/IP based routing protocols. It supports BGP4, BGP4+, OSPFv2, OSPFv3, - IS-IS, RIPv1, RIPv2, RIPng, PIM and LDP as well as the IPv6 versions of these. diff --git a/debianpkg/backports/ubuntu18.04/debian/source/format b/debianpkg/backports/ubuntu18.04/debian/source/format deleted file mode 100644 index 163aaf8d82..0000000000 --- a/debianpkg/backports/ubuntu18.04/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (quilt) diff --git a/debianpkg/backports/ubuntu18.04/exclude b/debianpkg/backports/ubuntu18.04/exclude deleted file mode 100644 index e69de29bb2..0000000000 --- a/debianpkg/backports/ubuntu18.04/exclude +++ /dev/null diff --git a/debianpkg/backports/ubuntu18.04/versionext b/debianpkg/backports/ubuntu18.04/versionext deleted file mode 100644 index 832fb4c32b..0000000000 --- a/debianpkg/backports/ubuntu18.04/versionext +++ /dev/null @@ -1 +0,0 @@ --1~ubuntu18.04+1 diff --git a/debianpkg/compat b/debianpkg/compat deleted file mode 100644 index 7f8f011eb7..0000000000 --- a/debianpkg/compat +++ /dev/null @@ -1 +0,0 @@ -7 diff --git a/debianpkg/control b/debianpkg/control deleted file mode 100644 index ea977937bf..0000000000 --- a/debianpkg/control +++ /dev/null @@ -1,54 +0,0 @@ -Source: frr -Section: net -Priority: optional -Maintainer: Nobody <nobody@frrouting.org> -Uploaders: Nobody <nobody@frrouting.org> -XSBC-Original-Maintainer: <maintainers@frrouting.org> -Build-Depends: debhelper (>= 7.0.50~), libreadline-dev, libpam0g-dev | libpam-dev, libcap-dev, texinfo (>= 4.7), autotools-dev, libpcre3-dev, gawk, chrpath, libsnmp-dev, git, dh-autoreconf, libjson-c-dev, libjson-c2 | libjson-c3, dh-systemd, libsystemd-dev, bison, flex, libc-ares-dev, pkg-config, python (>= 2.7) | python3, python-sphinx | python3-sphinx, libpython-dev | libpython3-dev, install-info -Standards-Version: 3.9.6 -Homepage: http://www.frrouting.org/ - -Package: frr -Architecture: any -Depends: ${shlibs:Depends}, logrotate (>= 3.2-11), iproute2 | iproute, ${misc:Depends}, libc-ares2 -Pre-Depends: adduser -Conflicts: zebra, zebra-pj, quagga -Replaces: zebra, zebra-pj -Suggests: snmpd -Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon forked from Quagga - FRR is free software which manages TCP/IP based routing protocols. - It supports BGP4, BGP4+, OSPFv2, OSPFv3, IS-IS, RIPv1, RIPv2, RIPng, - PIM and LDP as well as the IPv6 versions of these. - . - FRR is a fork of Quagga with an open community model. The main git - lives on https://github.com/frrouting/frr.git - -Package: frr-dbg -Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, frr (= ${binary:Version}) -Priority: extra -Section: debug -Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon (debug symbols) - This package provides debugging symbols for all binary packages built - from frr source package. It's highly recommended to have this package - installed before reporting any FRR crashes to either FRR developers or - Debian package maintainers. - -Package: frr-doc -Section: net -Architecture: all -Depends: ${misc:Depends} -Suggests: frr -Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon (documentation) - This package includes info files for frr, a free software which manages - TCP/IP based routing protocols. It supports BGP4, BGP4+, OSPFv2, OSPFv3, - IS-IS, RIPv1, RIPv2, RIPng, PIM and LDP as well as the IPv6 versions of these. - -Package: frr-pythontools -Section: net -Architecture: all -Depends: ${misc:Depends}, frr (= ${binary:Version}), python (>= 2.7), python-ipaddr -Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon (Python Tools) - This package includes info files for frr, a free software which manages - TCP/IP based routing protocols. It supports BGP4, BGP4+, OSPFv2, OSPFv3, - IS-IS, RIPv1, RIPv2, RIPng, PIM and LDP as well as the IPv6 versions of these. diff --git a/debianpkg/copyright b/debianpkg/copyright deleted file mode 100644 index 7b873abd31..0000000000 --- a/debianpkg/copyright +++ /dev/null @@ -1,29 +0,0 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: Frr -Upstream-Contact: maintainers@frrouting.org, security@frrouting.org -Source: http://www.frrouting.org/ - -Files: * -Copyright: 1996-2003 by the original Zebra authors: - Kunihiro Ishiguro <kunihiro@zebra.org> - Toshiaki Takada <takada@zebra.org> - Yasuhiro Ohara <yasu@sfc.wide.ad.jp> - 2003-2012 by the Quagga Project, mostly Paul Jakma <paul@jakma.org> -License: GPL-2+ - This program 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 of the License, or - (at your option) any later version. - . - This program 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 this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - . - On Debian systems, the full text of the GNU General Public - License version 2 can be found in the file - `/usr/share/common-licenses/GPL-2'. diff --git a/debianpkg/frr-dbg.lintian-overrides b/debianpkg/frr-dbg.lintian-overrides deleted file mode 100644 index 7880bba29a..0000000000 --- a/debianpkg/frr-dbg.lintian-overrides +++ /dev/null @@ -1 +0,0 @@ -frr-dbg: debug-file-with-no-debug-symbols usr/lib/debug/usr/lib/libfrrfpm_pb.so.0.0.0 diff --git a/debianpkg/frr-doc.docs b/debianpkg/frr-doc.docs deleted file mode 100644 index 605353289c..0000000000 --- a/debianpkg/frr-doc.docs +++ /dev/null @@ -1,3 +0,0 @@ -README.md -doc/user/*.rst -doc/figures/*.png diff --git a/debianpkg/frr-doc.install b/debianpkg/frr-doc.install deleted file mode 100644 index 8854b2c547..0000000000 --- a/debianpkg/frr-doc.install +++ /dev/null @@ -1 +0,0 @@ -doc/user/_build/texinfo/*.png usr/share/info diff --git a/debianpkg/frr-doc.lintian-overrides b/debianpkg/frr-doc.lintian-overrides deleted file mode 100644 index 1fe64ffd53..0000000000 --- a/debianpkg/frr-doc.lintian-overrides +++ /dev/null @@ -1 +0,0 @@ -frr-doc: wrong-section-according-to-package-name frr-doc => doc diff --git a/debianpkg/frr-pythontools.install b/debianpkg/frr-pythontools.install deleted file mode 100644 index aee093cf69..0000000000 --- a/debianpkg/frr-pythontools.install +++ /dev/null @@ -1 +0,0 @@ -tools/frr-reload.py usr/lib/frr/ diff --git a/debianpkg/frr.install b/debianpkg/frr.install deleted file mode 100644 index a53c5d1385..0000000000 --- a/debianpkg/frr.install +++ /dev/null @@ -1,12 +0,0 @@ -etc/frr/ -usr/bin/vtysh -usr/bin/mtracebis -usr/include/frr/ -usr/lib/ -tools/frr usr/lib/frr -usr/share/doc/frr/ -usr/share/yang/ -tools/etc/* etc/ -tools/*.service lib/systemd/system -tools/frr-reload usr/lib/frr/ -debian/frr.conf usr/lib/tmpfiles.d diff --git a/debianpkg/frr.lintian-overrides b/debianpkg/frr.lintian-overrides deleted file mode 100644 index 2e9888ed4f..0000000000 --- a/debianpkg/frr.lintian-overrides +++ /dev/null @@ -1,6 +0,0 @@ -frr: non-dev-pkg-with-shlib-symlink usr/lib/libfrrospfapiclient.so.0.0.0 usr/lib/libfrrospfapiclient.so -frr: non-dev-pkg-with-shlib-symlink usr/lib/libfrr.so.0.0.0 usr/lib/libfrr.so -frr: non-dev-pkg-with-shlib-symlink usr/lib/libfrrfpm_pb.so.0.0.0 usr/lib/libfrrfpm_pb.so -frr: package-name-doesnt-match-sonames libfrr0 libfrrfpm-pb0 libfrrospfapiclient0 -frr: systemd-service-file-refers-to-unusual-wantedby-target lib/systemd/system/frr.service network-online.target -frr: shared-lib-without-dependency-information usr/lib/libfrrfpm_pb.so.0.0.0 diff --git a/debianpkg/frr.postinst b/debianpkg/frr.postinst deleted file mode 100644 index a8d6ab2805..0000000000 --- a/debianpkg/frr.postinst +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash -e - -###################### -frruid=`getent passwd frr | awk -F ":" '{ print $3 }'` -frrgid=`getent group frr | awk -F ":" '{ print $3 }'` -frrvtygid=`getent group frrvty | awk -F ":" '{ print $3 }'` - -[ -n ${frruid} ] || (echo "No uid for frr" && /bin/false) -[ -n ${frrgid} ] || (echo "No gid for frr" && /bin/false) -[ -n ${frrVTYgid} ] || (echo "No gid for frrvty" && /bin/false) - -chown ${frruid}:${frrgid} /etc/frr -chown ${frruid}:${frrgid} /etc/frr/* -touch /etc/frr/vtysh.conf -chgrp ${frrvtygid} /etc/frr/vtysh* -chmod 644 /etc/frr/* - -ENVIRONMENTFILE=/etc/environment -if ! egrep --quiet '^VTYSH_PAGER=' ${ENVIRONMENTFILE}; then - echo "VTYSH_PAGER=/bin/cat" >> ${ENVIRONMENTFILE} -fi -################################################## - -if [ -n "$DEBIAN_SCRIPT_DEBUG" ]; then set -v -x; DEBIAN_SCRIPT_TRACE=1; fi -${DEBIAN_SCRIPT_TRACE:+ echo "#42#DEBUG# RUNNING $0 $*"} - -# This is most likely due to the answer "no" to the "really stop the server" -# question in the prerm script. -if [ "$1" = "abort-upgrade" ]; then - exit 0 -fi - -#DEBHELPER# - diff --git a/debianpkg/frr.postrm b/debianpkg/frr.postrm deleted file mode 100644 index 26576fd136..0000000000 --- a/debianpkg/frr.postrm +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -e - -if [ -n "$DEBIAN_SCRIPT_DEBUG" ]; then set -v -x; DEBIAN_SCRIPT_TRACE=1; fi -${DEBIAN_SCRIPT_TRACE:+ echo "#42#DEBUG# RUNNING $0 $*"} -# set -u not because of debhelper - -if [ "$1" = "purge" ]; then - rm -rf /etc/frr /var/run/frr /var/log/frr - userdel frr >/dev/null 2>&1 || true -fi - -#DEBHELPER# diff --git a/debianpkg/frr.preinst b/debianpkg/frr.preinst deleted file mode 100644 index 477e690d0a..0000000000 --- a/debianpkg/frr.preinst +++ /dev/null @@ -1,81 +0,0 @@ -#!/bin/bash - -if [ -n "$DEBIAN_SCRIPT_DEBUG" ]; then set -v -x; DEBIAN_SCRIPT_TRACE=1; fi -${DEBIAN_SCRIPT_TRACE:+ echo "#42#DEBUG# RUNNING $0 $*"} -set -e -set -u - -# creating frrvty group if it isn't already there -if ! getent group frrvty >/dev/null; then - addgroup --system frrvty >/dev/null -fi - -# creating frr group if it isn't already there -if ! getent group frr >/dev/null; then - addgroup --system frr >/dev/null -fi - -# creating frr user if he isn't already there -if ! getent passwd frr >/dev/null; then - adduser \ - --system \ - --ingroup frr \ - --home /var/run/frr/ \ - --gecos "Frr routing suite" \ - --shell /bin/false \ - frr >/dev/null -fi - -# We may be installing over an older version of -# frr and as such we need to intelligently -# check to see if the frr user is in the frrvty -# group. -if ! id frr | grep &>/dev/null 'frrvty'; then - usermod -a -G frrvty frr >/dev/null -fi - -# Do not change permissions when upgrading as it would violate policy. -if [ "$1" = "install" ]; then - # Logfiles are group readable in case users were put into the frr group. - d=/var/log/frr/ - mkdir -p $d - chown frr:frr $d - chown --quiet frr:frr $d/* | true - chmod u=rwx,go=rx $d - find $d -type f -print0 | xargs -0 --no-run-if-empty chmod u=rw,g=r,o= - - # Strict permissions for the sockets. - d=/var/run/frr/ - mkdir -p $d - chown frr:frr $d - chown --quiet frr:frr $d/* | true - chmod u=rwx,go=rx $d - find $d -type f -print0 | xargs -0 --no-run-if-empty chmod u=rw,go= - - # Config files. Vtysh does not have access to the individual daemons config file - d=/etc/frr/ - mkdir -p $d - chown frr:frrvty $d - chmod ug=rwx,o=rx $d - find $d -type f -print0 | xargs -0 --no-run-if-empty chown frr:frr - find $d -type f -print0 | xargs -0 --no-run-if-empty chmod u=rw,g=r,o= - - # Exceptions for vtysh. - f=$d/vtysh.conf - if [ -f $f ]; then - chown frr:frrvty $f - chmod u=rw,g=r,o= $f - fi - - # Exceptions for vtysh. - f=$d/frr.conf - if [ -f $d/Zebra.conf ]; then - mv $d/Zebra.conf $f - fi - if [ -f $f ]; then - chown frr:frrvty $f - chmod u=rw,g=r,o= $f - fi -fi - -#DEBHELPER# diff --git a/debianpkg/frr.prerm b/debianpkg/frr.prerm deleted file mode 100644 index 4b71202810..0000000000 --- a/debianpkg/frr.prerm +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -e - -if [ -n "$DEBIAN_SCRIPT_DEBUG" ]; then set -v -x; DEBIAN_SCRIPT_TRACE=1; fi -${DEBIAN_SCRIPT_TRACE:+ echo "#42#DEBUG# RUNNING $0 $*"} - -# prerm remove -# old-prerm upgrade new-version -# new-prerm failed-upgrade old-version -# conflictor's-prerm remove in-favour package new-version -# deconfigured's-prerm deconfigure in-favour package-being-installed version removing conflicting-package -case $1 in - remove|upgrade) - ;; - - failed-upgrade) - # If frr/really_stop was negated then this script exits with return - # code 1 and is called again with "failed-upgrade". Well, exit again. - exit 1 - ;; - -esac - -#DEBHELPER# diff --git a/debianpkg/rules b/debianpkg/rules deleted file mode 100755 index 12d6c3545c..0000000000 --- a/debianpkg/rules +++ /dev/null @@ -1,199 +0,0 @@ -#!/usr/bin/make -f - -# FRRouting Configuration options -###################################### -# -# WANT_xxxx --> Set to 1 for enable, 0 for disable -# The following are the defaults. They can be overridden by setting a -# env variable to a different value - -# -Werror - don't enable this unless you're doing a dev package build -WANT_WERROR ?= 0 - -WANT_OSPFAPI ?= 1 -WANT_BGP_VNC ?= 1 -WANT_CUMULUS_MODE ?= 0 -WANT_MULTIPATH ?= 1 -WANT_SNMP ?= 0 -WANT_RPKI ?= 0 - -# NOTES: -# -# If you use WANT_RPKI, then there is a new dependency for librtr0 package -# and a build dependency of the librtr-dev package. -# While the librtr0 is added to the depenencies automatically, the build -# dependency can't be changed dynamically and building will fail if the -# librtr-dev isn't installed during package build -# Tested versions of both packages can be found at -# https://ci1.netdef.org/browse/RPKI-RTRLIB/latestSuccessful/artifact -# -# If multipath is enabled (WANT_MULTIPATH=1), then set number of multipaths here -# Please be aware that 0 is NOT disabled, but treated as unlimited - -MULTIPATH ?= 256 - -# Set the following to the value required (or leave alone for the default below) -# WANT_FRR_USER is used for the username and groupname of the FRR user account - -WANT_FRR_USER ?= frr -WANT_FRR_VTY_GROUP ?= frrvty - -# Don't build PDF docs by default -# add build deps: texlive-latex-base, texlive-generic-recommended -GENERATE_PDF ?= 0 - -# -#################################### - -export DH_VERBOSE=1 -export DEB_BUILD_MAINT_OPTIONS = hardening=+all -export DH_OPTIONS=-v - -ifeq ($(WANT_SNMP), 1) - USE_SNMP=--enable-snmp - $(warning "DEBIAN: SNMP enabled, sorry for your inconvenience") -else - USE_SNMP=--disable-snmp - $(warning "DEBIAN: SNMP disabled, see README.Debian") -endif - -ifeq ($(WANT_OSPFAPI), 1) - USE_OSPFAPI=--enable-ospfapi=yes -else - USE_OSPFAPI=--enable-ospfapi=no -endif - -ifeq ($(WANT_BGP_VNC), 1) - USE_BGP_VNC=--enable-bgp-vnc=yes -else - USE_BGP_VNC=--enable-bgp-vnc=no -endif - -USE_FRR_USER=--enable-user=$(WANT_FRR_USER) -USE_FRR_GROUP=--enable-group=$(WANT_FRR_USER) -USE_FRR_VTY_GROUP=--enable-vty-group=$(WANT_FRR_VTY_GROUP) - -ifeq ($(WANT_MULTIPATH), 1) - USE_MULTIPATH=--enable-multipath=$(MULTIPATH) -else - USE_MULTIPATH=--disable-multipath -endif - -ifeq ($(WANT_CUMULUS_MODE), 1) - USE_CUMULUS=--enable-cumulus=yes -else - USE_CUMULUS=--enable-cumulus=no -endif - -ifeq ($(WANT_RPKI), 1) - USE_RPKI=--enable-rpki -else - USE_RPKI=--disable-rpki -endif - -ifeq ($(WANT_WERROR), 1) - USE_WERROR=--enable-werror -else - USE_WERROR=--disable-werror -endif - -ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) - DEBIAN_JOBS := $(subst parallel=,,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) -endif - -ifdef DEBIAN_JOBS -MAKEFLAGS += -j$(DEBIAN_JOBS) -endif - -%: - dh $@ --with=systemd,autoreconf --parallel --dbg-package=frr-dbg --list-missing - -override_dh_gencontrol: -ifeq ($(WANT_RPKI), 1) - dh_gencontrol -- -Vdist:Depends="librtr0 (>= 0.5)" -else - dh_gencontrol -endif - -override_dh_auto_configure: - if ! [ -e config.status ]; then \ - dh_auto_configure -- \ - --enable-exampledir=/usr/share/doc/frr/examples/ \ - --localstatedir=/var/run/frr \ - --sbindir=/usr/lib/frr \ - --sysconfdir=/etc/frr \ - $(USE_SNMP) \ - $(USE_OSPFAPI) \ - $(USE_MULTIPATH) \ - --enable-fpm \ - $(USE_FRR_USER) $(USE_FRR_GROUP) \ - $(USE_FRR_VTY_GROUP) \ - --enable-configfile-mask=0640 \ - --enable-logfile-mask=0640 \ - $(USE_WERROR) \ - --with-libpam \ - --enable-systemd=yes \ - $(USE_CUMULUS) \ - --disable-dependency-tracking \ - $(USE_BGP_VNC) \ - $(USE_RPKI) \ - $(shell dpkg-buildflags --export=configure); \ - fi - -override_dh_auto_build: - dh_auto_build - -override_dh_auto_test: - -override_dh_auto_install: - dh_auto_install - - # installed in frr-pythontools - rm debian/tmp/usr/lib/frr/frr-reload.py - - # cleaning up the info dir - rm -f debian/tmp/usr/share/info/dir* - - # install config files - mkdir -p debian/tmp/etc/frr/ - perl -pi -e 's#^!log file #!log file /var/log/frr/#' debian/tmp/usr/share/doc/frr/examples/*sample* - - # we don't need .la files - rm debian/tmp/usr/lib/*.la - rm debian/tmp/usr/lib/frr/modules/*.la - rm debian/tmp/usr/lib/frr/libyang_plugins/*.la - -override_dh_systemd_start: - dh_systemd_start frr.service - -override_dh_systemd_enable: - dh_systemd_enable frr.service - -# backports -SRCPKG = frr -KNOWN_BACKPORTS = debian8 debian9 ubuntu14.04 ubuntu16.04 ubuntu17.10 ubuntu18.04 -DEBIAN_VERSION := $(shell dh_testdir && \ - dpkg-parsechangelog -c1 < debian/changelog | \ - sed -rn 's/^Version: ?//p') -ORIG_VERSION := $(DEBIAN_VERSION) --include debian/backports/rules - -ifneq ($(TARBALLDIR),) -ifeq ($(wildcard frr-$(ORIG_VERSION).tar.gz),frr-$(ORIG_VERSION).tar.gz) - -$(TARBALLDIR)/$(SRCPKG)_$(ORIG_VERSION).orig.tar.gz: \ - frr-$(ORIG_VERSION).tar.gz - cp $< $@ - -else # wildcard frr-$(ORIG_VERSION).tar.gz - -# better error message on missing .orig.tar.gz -$(TARBALLDIR)/$(SRCPKG)_$(ORIG_VERSION).orig.tar.gz: - @ echo "\`$(TARBALLDIR)/$(SRCPKG)-$(ORIG_VERSION).tar.gz'" not \ - found and not generated by debian/rules. Provided you have the \ - necessary packages installed, you can generate it yourself via \ - "\"./bootstrap.sh && ./configure && make dist\"". - exit 1 - -endif # wildcard frr-$(ORIG_VERSION).tar.gz -endif # TARBALLDIR nonempty diff --git a/debianpkg/subdir.am b/debianpkg/subdir.am deleted file mode 100644 index af17e4642a..0000000000 --- a/debianpkg/subdir.am +++ /dev/null @@ -1,62 +0,0 @@ -# -# debianpkg -# - -EXTRA_DIST += \ - debianpkg/README.Debian \ - debianpkg/README.Maintainer \ - debianpkg/changelog \ - debianpkg/compat \ - debianpkg/control \ - debianpkg/copyright \ - debianpkg/rules \ - debianpkg/source/format \ - debianpkg/tests/control \ - debianpkg/tests/daemons \ - debianpkg/watchfrr.rc \ - \ - debianpkg/backports/README \ - debianpkg/backports/rules \ - debianpkg/backports/debian8/debian/source/format \ - debianpkg/backports/debian8/exclude \ - debianpkg/backports/debian8/versionext \ - debianpkg/backports/debian9/debian/source/format \ - debianpkg/backports/debian9/exclude \ - debianpkg/backports/debian9/versionext \ - debianpkg/backports/ubuntu14.04/debian/control \ - debianpkg/backports/ubuntu14.04/debian/frr.install \ - debianpkg/backports/ubuntu14.04/debian/rules \ - debianpkg/backports/ubuntu14.04/debian/source/format \ - debianpkg/backports/ubuntu14.04/exclude \ - debianpkg/backports/ubuntu14.04/versionext \ - debianpkg/backports/ubuntu16.04/debian/source/format \ - debianpkg/backports/ubuntu16.04/exclude \ - debianpkg/backports/ubuntu16.04/versionext \ - debianpkg/backports/ubuntu17.10/debian/control \ - debianpkg/backports/ubuntu17.10/debian/source/format \ - debianpkg/backports/ubuntu17.10/exclude \ - debianpkg/backports/ubuntu17.10/versionext \ - debianpkg/backports/ubuntu18.04/debian/control \ - debianpkg/backports/ubuntu18.04/debian/source/format \ - debianpkg/backports/ubuntu18.04/exclude \ - debianpkg/backports/ubuntu18.04/versionext \ - \ - debianpkg/frr-dbg.lintian-overrides \ - debianpkg/frr-doc.docs \ - debianpkg/frr-doc.info \ - debianpkg/frr-doc.install \ - debianpkg/frr-doc.lintian-overrides \ - debianpkg/frr-pythontools.install \ - debianpkg/frr.conf \ - debianpkg/frr.dirs \ - debianpkg/frr.docs \ - debianpkg/frr.install \ - debianpkg/frr.lintian-overrides \ - debianpkg/frr.logrotate \ - debianpkg/frr.manpages \ - debianpkg/frr.pam \ - debianpkg/frr.postinst \ - debianpkg/frr.postrm \ - debianpkg/frr.preinst \ - debianpkg/frr.prerm \ - # end diff --git a/debianpkg/tests/control b/debianpkg/tests/control deleted file mode 100644 index 53fd537e2e..0000000000 --- a/debianpkg/tests/control +++ /dev/null @@ -1,3 +0,0 @@ -Tests: daemons -Depends: frr -Restrictions: needs-root diff --git a/debianpkg/tests/daemons b/debianpkg/tests/daemons deleted file mode 100644 index 43966c8347..0000000000 --- a/debianpkg/tests/daemons +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash -#--------------- -# Testing frr -#--------------- -set -e - -# modify config file to enable all daemons and copy config files -CONFIG_FILE=/etc/frr/daemons -DAEMONS=("zebra" "bgpd" "ospfd" "ospf6d" "ripd" "ripngd" "isisd" "pimd" "fabricd") - -for daemon in "${DAEMONS[@]}" -do - sed -i -e "s/${daemon}=no/${daemon}=yes/g" $CONFIG_FILE - cp /usr/share/doc/frr/examples/${daemon}.conf.sample /etc/frr/${daemon}.conf -done - -# reload frr -/etc/init.d/frr restart > /dev/null 2>&1 - -# check daemons -for daemon in "${DAEMONS[@]}" -do - echo -n "check $daemon - " - if pidof -x $daemon > /dev/null; then - echo "${daemon} OK" - else - echo "ERROR: ${daemon} IS NOT RUNNING" - exit 1 - fi -done diff --git a/doc/developer/_static/overrides.css b/doc/developer/_static/overrides.css index 0d871c961a..1d702bb6e9 100644 --- a/doc/developer/_static/overrides.css +++ b/doc/developer/_static/overrides.css @@ -3,6 +3,237 @@ div.body { max-width: none; } +/* Palette URL: http://paletton.com/#uid=70p0p0kt6uvcDRAlhBavokxLJ6w */ + +:root { +--primary-0: #F36F16; /* Main Primary color */ +--primary-1: #FFC39A; +--primary-2: #FF9A55; +--primary-3: #A34403; +--primary-4: #341500; +--primary-9: #FFF3EB; + +--secondary-1-0: #F39C16; /* Main Secondary color (1) */ +--secondary-1-1: #FFD79A; +--secondary-1-2: #FFBC55; +--secondary-1-3: #A36403; +--secondary-1-4: #341F00; +--secondary-1-9: #FFF7EB; + +--secondary-2-0: #1A599F; /* Main Secondary color (2) */ +--secondary-2-1: #92B9E5; +--secondary-2-2: #477CB8; +--secondary-2-3: #0A386B; +--secondary-2-4: #011122; +--secondary-2-9: #E3EBF4; + +--complement-0: #0E9A83; /* Main Complement color */ +--complement-1: #8AE4D4; +--complement-2: #3CB4A0; +--complement-3: #026857; +--complement-4: #00211B; +--complement-9: #E0F4F0; +} + +/* new */ + +body { + font-family: "Fira Sans", Helvetica, Arial, sans-serif; + font-weight:400; +} +h1, h2, h3, h4, h5, h6 { + font-family: "Fira Sans", Helvetica, Arial, sans-serif; + font-weight:500; +} +code, pre, tt { + font-family: "Fira Mono"; +} +h1 { + background-color:var(--secondary-1-1); + border-bottom:1px solid var(--secondary-1-0); + font-weight:300; +} +h2 { + margin-top:36pt; +} + +a, +a:hover, +a:visited, +.code-block-caption a.headerlink:hover, +.rst-content dl:not(.docutils) dt .headerlink { + color: var(--complement-0); +} +.code-block-caption a.headerlink { + visibility:hidden; +} + +/* admonitions */ + +.admonition.warning { + border:1px dashed var(--primary-2); +} +.admonition.warning .admonition-title { + color: var(--primary-3); + background-color: var(--primary-1); +} +.admonition.note, +.admonition.hint { + border:1px dashed var(--complement-2); +} +.admonition.note .admonition-title, +.admonition.hint .admonition-title { + color: var(--complement-3); + background-color: var(--complement-1); +} +.admonition.seealso, +div.seealso { + background-color:var(--complement-9); +} +.admonition.seealso .admonition-title { + color: var(--complement-3); + background-color:var(--complement-1); + border-bottom:1px solid var(--complement-2); +} +.admonition.admonition-todo .admonition-title { + background-image: repeating-linear-gradient( + 135deg, + #ffa, + #ffa 14.14213452px, + #bbb 14.14213452px, + #bbb 28.28427124px + ); + color:#000; +} +.admonition.admonition-todo { + background-image: repeating-linear-gradient( + 135deg, + #ffd, + #ffd 14.14213452px, + #eed 14.14213452px, + #eed 28.28427124px + ); +} + +.rst-content dl .admonition p.last { + margin-bottom:0 !important; +} + +/* file block */ + +.code-block-caption { +/* border-radius: 4px; */ + font-style:italic; + font-weight:300; + border-bottom: 1px solid var(--secondary-2-1); + background-color: var(--secondary-2-9); + padding:2px 8px; +} + +/* navbar */ + +.wy-nav-side { + background-color: var(--secondary-1-4); + border-right:2px solid var(--primary-3); +} +.wy-menu-vertical a, +.wy-menu-vertical a:visited, +.wy-menu-vertical a:hover, +.wy-side-nav-search>a, +.wy-side-nav-search .wy-dropdown>a { + color: var(--primary-0); +} + +nav div.wy-side-nav-search { + background-color: #eee; +} +nav div.wy-side-scroll { + background-color: var(--secondary-1-4); +} +nav .wy-menu-vertical a:hover { + background-color:var(--primary-0); + color:var(--primary-4); +} +nav .wy-menu-vertical li.current ul a:hover { + background-color:var(--secondary-1-2); + color:var(--primary-4); +} +nav .wy-menu-vertical li.current ul a { + background-color:var(--secondary-1-1); + color:var(--primary-3); +} +nav .wy-menu-vertical li.on a:hover, +nav .wy-menu-vertical li.current>a:hover { + background-color:#fcfcfc; +} +.wy-side-nav-search input[type=text] { + border-color:var(--primary-2); +} +.wy-menu-vertical li.toctree-l1.current>a { + border-top:1px solid var(--secondary-1-3); + border-bottom:1px solid var(--secondary-1-3); +} +.wy-menu-vertical li.toctree-l2.current>a { + background-color:var(--secondary-1-2); +} +.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a { + background-color:var(--secondary-1-9); +} + +.wy-nav-content { + padding: 25pt 40pt; +} +div[role=navigation] > hr { + display:none; +} +div[role=navigation] { + margin-bottom:15pt; +} +h1 { + margin-left:-40pt; + margin-right:-40pt; + padding:5pt 40pt 5pt 40pt; +} + +.rst-content pre.literal-block, .rst-content div[class^='highlight'] { + border-color:var(--secondary-1-1); +} + +span.pre { + color: var(--complement-3); +} pre { - background-color: #e2e2e2; + background-color: var(--secondary-1-9); + border-color: var(--secondary-1-1); +} +.highlight .p { color: var(--secondary-2-3); } +.highlight .k { color: var(--secondary-2-0); } +.highlight .kt { color: var(--complement-0); } +.highlight .cm { color: var(--primary-3); } +.highlight .ow { color: var(--primary-3); } +.highlight .na { color: var(--primary-2); } +.highlight .nv { color: var(--complement-0); } + +strong { + font-weight:500; +} +.rst-content dl:not(.docutils) dt { + font-family:Fira Mono; + font-weight:600; + background-color:var(--secondary-2-9); + color:var(--secondary-2-3); + border-top:2px solid var(--secondary-2-2); +} +dt code.descname { + color: var(--secondary-2-4); +} + +@media (min-width: 1200px) { + .container { width: auto; } +} +@media (min-width: 992px) { + .container { width: auto; } +} +@media (min-width: 768px) { + .container { width: auto; } } diff --git a/doc/developer/building-frr-for-centos6.rst b/doc/developer/building-frr-for-centos6.rst index c57573cb9f..732959212e 100644 --- a/doc/developer/building-frr-for-centos6.rst +++ b/doc/developer/building-frr-for-centos6.rst @@ -1,9 +1,10 @@ +.. _building-centos6: + CentOS 6 ======================================== -(As an alternative to this installation, you may prefer to create a FRR -rpm package yourself and install that package instead. See instructions -in redhat/README.rpm\_build.md on how to build a rpm package) +This document describes installation from source. If you want to build an RPM, +see :ref:`packaging-redhat`. Instructions are tested with ``CentOS 6.8`` on ``x86_64`` platform @@ -24,7 +25,7 @@ CentOS 6 restrictions: PIMd is needed - MPLS is not supported on ``CentOS 6``. MPLS requires Linux Kernel 4.5 or higher (LDP can be built, but may have limited use without MPLS) -- Zebra is unable to detect what bridge/vrf an interface is associcated +- Zebra is unable to detect what bridge/vrf an interface is associated with (IFLA\_INFO\_SLAVE\_KIND does not exist in the kernel headers, you can use a newer kernel + headers to get this functionality) - frr\_reload.py will not work, as this requires Python 2.7, and CentOS @@ -235,7 +236,7 @@ settings):: # Controls source route verification net.ipv4.conf.default.rp_filter = 0 -Load the modifed sysctl's on the system: +Load the modified sysctl's on the system: .. code-block:: shell diff --git a/doc/developer/building-frr-for-centos7.rst b/doc/developer/building-frr-for-centos7.rst index 8f82cd6c9a..89445408bd 100644 --- a/doc/developer/building-frr-for-centos7.rst +++ b/doc/developer/building-frr-for-centos7.rst @@ -1,9 +1,8 @@ CentOS 7 ======================================== -(As an alternative to this installation, you may prefer to create a FRR -rpm package yourself and install that package instead. See instructions -in redhat/README.rpm\_build.md on how to build a rpm package) +This document describes installation from source. If you want to build an RPM, +see :ref:`packaging-redhat`. CentOS 7 restrictions: ---------------------- @@ -127,7 +126,7 @@ following content: net.ipv4.conf.all.forwarding=1 net.ipv6.conf.all.forwarding=1 -Load the modifed sysctl's on the system: +Load the modified sysctl's on the system: :: diff --git a/doc/developer/building-frr-for-debian8.rst b/doc/developer/building-frr-for-debian8.rst index 97e9382d46..d0f4182bae 100644 --- a/doc/developer/building-frr-for-debian8.rst +++ b/doc/developer/building-frr-for-debian8.rst @@ -15,9 +15,9 @@ Add packages: :: - sudo apt-get install git autoconf automake libtool make gawk \ - libreadline-dev texinfo libjson-c-dev pkg-config bison flex \ - python-pip libc-ares-dev python3-dev python3-sphinx + sudo apt-get install git autoconf automake libtool make gawk \ + libreadline-dev texinfo libjson-c-dev pkg-config bison flex python-pip \ + libc-ares-dev python3-dev python3-sphinx build-essential libsystemd-dev Install newer pytest (>3.0) from pip diff --git a/doc/developer/building-frr-for-debian9.rst b/doc/developer/building-frr-for-debian9.rst index 7c9f567b8d..39e7488cd7 100644 --- a/doc/developer/building-frr-for-debian9.rst +++ b/doc/developer/building-frr-for-debian9.rst @@ -8,9 +8,10 @@ Add packages: :: - sudo apt-get install git autoconf automake libtool make \ - libreadline-dev texinfo libjson-c-dev pkg-config bison flex \ - python-pip libc-ares-dev python3-dev python-pytest python3-sphinx + sudo apt-get install git autoconf automake libtool make \ + libreadline-dev texinfo libjson-c-dev pkg-config bison flex python-pip \ + libc-ares-dev python3-dev python-pytest python3-sphinx build-essential \ + libsystemd-dev .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-fedora24.rst b/doc/developer/building-frr-for-fedora24.rst index 2edf9b3e44..708baec3ee 100644 --- a/doc/developer/building-frr-for-fedora24.rst +++ b/doc/developer/building-frr-for-fedora24.rst @@ -1,9 +1,8 @@ Fedora 24 ========================================= -(As an alternative to this installation, you may prefer to create a FRR -rpm package yourself and install that package instead. See instructions -in redhat/README.rpm\_build.md on how to build a rpm package) +This document describes installation from source. If you want to build an RPM, +see :ref:`packaging-redhat`. Install required packages ------------------------- @@ -126,7 +125,7 @@ required MPLS similar to ``net.mpls.conf.eth0.input=1``) net.mpls.conf.eth2.input=1 net.mpls.platform_labels=100000 -Load the modifed sysctl's on the system: +Load the modified sysctl's on the system: :: diff --git a/doc/developer/building-frr-for-freebsd10.rst b/doc/developer/building-frr-for-freebsd10.rst index a6539309a2..5d0a7f6cbb 100644 --- a/doc/developer/building-frr-for-freebsd10.rst +++ b/doc/developer/building-frr-for-freebsd10.rst @@ -11,7 +11,7 @@ FreeBSD 10 restrictions: Install required packages ------------------------- -Add packages: (Allow the install of the package managment tool if this +Add packages: (Allow the install of the package management tool if this is first package install and asked) :: diff --git a/doc/developer/building-frr-for-freebsd11.rst b/doc/developer/building-frr-for-freebsd11.rst index 16d06e0a66..c85255e6ee 100644 --- a/doc/developer/building-frr-for-freebsd11.rst +++ b/doc/developer/building-frr-for-freebsd11.rst @@ -11,7 +11,7 @@ FreeBSD 11 restrictions: Install required packages ------------------------- -Add packages: (Allow the install of the package managment tool if this +Add packages: (Allow the install of the package management tool if this is first package install and asked) .. code-block:: shell diff --git a/doc/developer/building-frr-for-freebsd9.rst b/doc/developer/building-frr-for-freebsd9.rst index 36492fb886..4009f1b8d3 100644 --- a/doc/developer/building-frr-for-freebsd9.rst +++ b/doc/developer/building-frr-for-freebsd9.rst @@ -11,7 +11,7 @@ FreeBSD 9 restrictions: Install required packages ------------------------- -Add packages: (Allow the install of the package managment tool if this +Add packages: (Allow the install of the package management tool if this is first package install and asked) :: diff --git a/doc/developer/building-frr-for-openwrt.rst b/doc/developer/building-frr-for-openwrt.rst index b9be1b5226..8f72ab5d9d 100644 --- a/doc/developer/building-frr-for-openwrt.rst +++ b/doc/developer/building-frr-for-openwrt.rst @@ -63,10 +63,10 @@ Usage ----- Edit ``/usr/sbin/frr.init`` and add/remove the daemons name in section -``DAEMONS=`` or don't install unneded packages For example: zebra bgpd ldpd +``DAEMONS=`` or don't install unneeded packages For example: zebra bgpd ldpd isisd nhrpd ospfd ospf6d pimd ripd ripngd -Enable the serivce +Enable the service ^^^^^^^^^^^^^^^^^^ - ``service frr enable`` diff --git a/doc/developer/building-frr-for-ubuntu1204.rst b/doc/developer/building-frr-for-ubuntu1204.rst deleted file mode 100644 index a2d58e2258..0000000000 --- a/doc/developer/building-frr-for-ubuntu1204.rst +++ /dev/null @@ -1,184 +0,0 @@ -Ubuntu 12.04LTS -=============================================== - -- MPLS is not supported on ``Ubuntu 12.04`` with default kernel. MPLS - requires Linux Kernel 4.5 or higher (LDP can be built, but may have - limited use without MPLS) For an updated Ubuntu Kernel, see - http://kernel.ubuntu.com/~kernel-ppa/mainline/ - -Install required packages -------------------------- - -Add packages: - -:: - - apt-get install \ - git autoconf automake libtool make gawk libreadline-dev texinfo \ - dejagnu pkg-config libpam0g-dev libjson0-dev flex python-pip \ - libc-ares-dev python3-dev python3-sphinx install-info - -Install newer bison from 14.04 package source (Ubuntu 12.04 package -source is too old) - -:: - - mkdir builddir - cd builddir - wget http://archive.ubuntu.com/ubuntu/pool/main/b/bison/bison_3.0.2.dfsg-2.dsc - wget http://archive.ubuntu.com/ubuntu/pool/main/b/bison/bison_3.0.2.dfsg.orig.tar.bz2 - wget http://archive.ubuntu.com/ubuntu/pool/main/b/bison/bison_3.0.2.dfsg-2.debian.tar.gz - tar -jxvf bison_3.0.2.dfsg.orig.tar.bz2 - cd bison-3.0.2.dfsg/ - tar xzf ../bison_3.0.2.dfsg-2.debian.tar.gz - sudo apt-get build-dep bison - debuild -b -uc -us - cd .. - sudo dpkg -i ./libbison-dev_3.0.2.dfsg-2_amd64.deb ./bison_3.0.2.dfsg-2_amd64.deb - cd .. - rm -rf builddir - -Install newer version of autoconf and automake: - -:: - - wget http://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.gz - tar xvf autoconf-2.69.tar.gz - cd autoconf-2.69 - ./configure --prefix=/usr - make - sudo make install - cd .. - - wget http://ftp.gnu.org/gnu/automake/automake-1.15.tar.gz - tar xvf automake-1.15.tar.gz - cd automake-1.15 - ./configure --prefix=/usr - make - sudo make install - cd .. - -Install pytest: - -:: - - pip install pytest - -.. include:: building-libyang.rst - -Get FRR, compile it and install it (from Git) ---------------------------------------------- - -**This assumes you want to build and install FRR from source and not -using any packages** - -Add frr groups and user -^^^^^^^^^^^^^^^^^^^^^^^ - -:: - - sudo groupadd -r -g 92 frr - sudo groupadd -r -g 85 frrvty - sudo adduser --system --ingroup frr --home /var/run/frr/ \ - --gecos "FRR suite" --shell /sbin/nologin frr - sudo usermod -a -G frrvty frr - -Download Source, configure and compile it -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -(You may prefer different options on configure statement. These are just -an example.) - -:: - - git clone https://github.com/frrouting/frr.git frr - cd frr - ./bootstrap.sh - ./configure \ - --prefix=/usr \ - --enable-exampledir=/usr/share/doc/frr/examples/ \ - --localstatedir=/var/run/frr \ - --sbindir=/usr/lib/frr \ - --sysconfdir=/etc/frr \ - --enable-multipath=64 \ - --enable-user=frr \ - --enable-group=frr \ - --enable-vty-group=frrvty \ - --enable-configfile-mask=0640 \ - --enable-logfile-mask=0640 \ - --enable-fpm \ - --with-pkg-git-version \ - --with-pkg-extra-version=-MyOwnFRRVersion - make - make check - sudo make install - -Create empty FRR configuration files -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -:: - - sudo install -m 755 -o frr -g frr -d /var/log/frr - sudo install -m 775 -o frr -g frrvty -d /etc/frr - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/zebra.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/bgpd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospfd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospf6d.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/isisd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripngd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/pimd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ldpd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/nhrpd.conf - sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.conf - -Enable IP & IPv6 forwarding -^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Edit ``/etc/sysctl.conf`` and uncomment the following values (ignore the -other settings) - -:: - - # Uncomment the next line to enable packet forwarding for IPv4 - net.ipv4.ip_forward=1 - - # Uncomment the next line to enable packet forwarding for IPv6 - # Enabling this option disables Stateless Address Autoconfiguration - # based on Router Advertisements for this host - net.ipv6.conf.all.forwarding=1 - -**Reboot** or use ``sysctl -p`` to apply the same config to the running -system - -Install the init.d service -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -:: - - sudo install -m 755 tools/frr /etc/init.d/frr - sudo install -m 644 tools/etc/frr/daemons /etc/frr/daemons - sudo install -m 644 -o frr -g frr tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf - -Enable daemons -^^^^^^^^^^^^^^ - -| Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for - those daemons you want to start by systemd. -| For example. - -:: - - zebra=yes - bgpd=yes - ospfd=yes - ospf6d=yes - ripd=yes - ripngd=yes - isisd=yes - -Start the init.d service -^^^^^^^^^^^^^^^^^^^^^^^^ - -- /etc/init.d/frr start -- use ``/etc/init.d/frr status`` to check its status. diff --git a/doc/developer/building-frr-for-ubuntu1404.rst b/doc/developer/building-frr-for-ubuntu1404.rst index 7952cd682a..b1eaf57e8d 100644 --- a/doc/developer/building-frr-for-ubuntu1404.rst +++ b/doc/developer/building-frr-for-ubuntu1404.rst @@ -13,10 +13,10 @@ Add packages: :: - apt-get install \ - git autoconf automake libtool make gawk libreadline-dev texinfo dejagnu \ - pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \ - libc-ares-dev python3-dev python3-sphinx install-info + apt-get install \ + git autoconf automake libtool make gawk libreadline-dev texinfo \ + dejagnu pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \ + libc-ares-dev python3-dev python3-sphinx install-info build-essential .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-ubuntu1604.rst b/doc/developer/building-frr-for-ubuntu1604.rst index f5329fef2c..0762e07eb9 100644 --- a/doc/developer/building-frr-for-ubuntu1604.rst +++ b/doc/developer/building-frr-for-ubuntu1604.rst @@ -13,11 +13,11 @@ Add packages: :: - apt-get install \ - git autoconf automake libtool make gawk libreadline-dev texinfo dejagnu \ - pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \ - libc-ares-dev python3-dev libsystemd-dev python-ipaddress \ - python3-sphinx install-info + apt-get install \ + git autoconf automake libtool make gawk libreadline-dev texinfo dejagnu \ + pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \ + libc-ares-dev python3-dev libsystemd-dev python-ipaddress \ + python3-sphinx install-info build-essential libsystemd-dev .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-ubuntu1804.rst b/doc/developer/building-frr-for-ubuntu1804.rst index 110bc6a0ee..089d5a216a 100644 --- a/doc/developer/building-frr-for-ubuntu1804.rst +++ b/doc/developer/building-frr-for-ubuntu1804.rst @@ -13,7 +13,7 @@ Required packages git autoconf automake libtool make gawk libreadline-dev texinfo \ pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \ libc-ares-dev python3-dev libsystemd-dev python-ipaddress \ - python3-sphinx install-info + python3-sphinx install-info build-essential libsystemd-dev .. include:: building-libyang.rst diff --git a/doc/developer/building-libyang.rst b/doc/developer/building-libyang.rst index c45c294b75..41fe09e322 100644 --- a/doc/developer/building-libyang.rst +++ b/doc/developer/building-libyang.rst @@ -1,57 +1,55 @@ -The libyang library can be installed from third-party packages available `here -<https://ci1.netdef.org/browse/LIBYANG-YANGRELEASE/latestSuccessful/artifact>`_. +FRR depends on the relatively new ``libyang`` library to provide YANG/NETCONF +support. Unfortunately, most distributions do not yet offer a ``libyang`` +package from their repositories. Therefore we offer two options to install this +library. -Note: the libyang dev/devel packages need to be installed in addition -to the libyang core package in order to build FRR successfully. +**Option 1: Binary Install** + +The FRR project builds binary ``libyang`` packages, which we offer for download +`here <https://ci1.netdef.org/browse/LIBYANG-YANGRELEASE/latestSuccessful/artifact>`_. .. warning:: - libyang ABI version 0.16.74 or newer will be required to build FRR in the - near future since it significantly eases build and installation - considerations. "0.16-r3" is equal to 0.16.105 and will work, "0.16-r2" - is equal to 0.16.52 and will stop working. The CI artifacts will be - updated shortly. -For example, for CentOS 7.x: + ``libyang`` version 0.16.74 or newer is required to build FRR. + +.. note:: -.. code-block:: shell + The ``libyang`` development packages need to be installed in addition to the + libyang core package in order to build FRR successfully. Make sure to + download and install those from the link above alongside the binary + packages. - wget https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-1/CentOS-7-x86_64-Packages/libyang-0.16.46-0.x86_64.rpm - wget https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-1/CentOS-7-x86_64-Packages/libyang-devel-0.16.46-0.x86_64.rpm - sudo rpm -i libyang-0.16.46-0.x86_64.rpm libyang-devel-0.16.46-0.x86_64.rpm + Depending on your platform, you may also need to install the PCRE + development package. Typically this is ``libpcre-dev`` or ``pcre-devel``. -or Ubuntu 18.04: +.. note:: -.. code-block:: shell + For Debian-based systems, the official ``libyang`` package requires recent + versions of ``swig`` (3.0.12) and ``debhelper`` (11) which are only + available in Debian buster (10). However, ``libyang`` packages built on + Debian buster can be installed on both Debian jessie (8) and Debian stretch + (9), as well as various Ubuntu systems. The ``python3-yang`` package will + not work, but the other packages (``libyang-dev`` is the one needed for FRR) + will. - wget https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-1/Ubuntu-18.04-x86_64-Packages/libyang-dev_0.16.46_amd64.deb - wget https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-1/Ubuntu-18.04-x86_64-Packages/libyang_0.16.46_amd64.deb - sudo apt install libpcre3-dev - sudo dpkg -i libyang-dev_0.16.46_amd64.deb libyang_0.16.46_amd64.deb +**Option 2: Source Install** .. note:: - For Debian-based systems, the official libyang package requires recent - versions of swig (3.0.12) and debhelper (11) which are only available in - Debian buster (10). However, libyang packages built on Debian buster can - be installed on both Debian jessie (8) and Debian stretch (9), as well as - various Ubuntu systems. The python3-yang package will not work, but the - other packages (libyang-dev is the one needed for FRR) will. -Alternatively, libyang can be built and installed manually by following -the steps below: + Ensure that the `libyang build requirements + <https://github.com/CESNET/libyang/blob/master/README.md#build-requirements>`_ + are met before continuing. Usually this entails installing ``cmake`` and + ``libpcre-dev`` or ``pcre-devel``. -.. code-block:: shell +.. code-block:: console - git clone https://github.com/opensourcerouting/libyang + git clone https://github.com/CESNET/libyang.git cd libyang - git checkout -b tmp origin/tmp mkdir build; cd build - cmake -DENABLE_LYD_PRIV=ON .. + cmake -DENABLE_LYD_PRIV=ON -DCMAKE_INSTALL_PREFIX:PATH=/usr .. make sudo make install When building libyang on CentOS 6, it's also necessary to pass the ``-DENABLE_CACHE=OFF`` parameter to cmake. -Note: please check the `libyang build requirements -<https://github.com/CESNET/libyang/blob/master/README.md#build-requirements>`_ -first. diff --git a/doc/developer/building.rst b/doc/developer/building.rst index 4c18445f9d..96559b0abe 100644 --- a/doc/developer/building.rst +++ b/doc/developer/building.rst @@ -21,7 +21,6 @@ Building FRR building-frr-for-omnios building-frr-for-openbsd6 building-frr-for-openwrt - building-frr-for-ubuntu1204 building-frr-for-ubuntu1404 building-frr-for-ubuntu1604 building-frr-for-ubuntu1804 diff --git a/doc/developer/conf.py b/doc/developer/conf.py index ad501ae39d..af8673e5fa 100644 --- a/doc/developer/conf.py +++ b/doc/developer/conf.py @@ -167,12 +167,19 @@ todo_include_todos = True # a list of builtin themes. html_theme = 'default' +try: + import sphinx_rtd_theme + + html_theme = 'sphinx_rtd_theme' +except ImportError: + pass + # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -html_theme_options = { - 'sidebarbgcolor': '#374249' -} +#html_theme_options = { +# 'sidebarbgcolor': '#374249' +#} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] diff --git a/doc/developer/hooks.rst b/doc/developer/hooks.rst index 4140a0d171..10fe6b9c43 100644 --- a/doc/developer/hooks.rst +++ b/doc/developer/hooks.rst @@ -6,7 +6,7 @@ Hooks Libfrr provides type-safe subscribable hook points where other pieces of code can add one or more callback functions. "type-safe" in this case applies to the function pointers used for subscriptions. The -implementations checks (at compile-time) wheter a callback to be added has +implementations checks (at compile-time) whether a callback to be added has the appropriate function signature (parameters) for the hook. Example: diff --git a/doc/developer/logging.rst b/doc/developer/logging.rst index 4338d900e6..1dc1885158 100644 --- a/doc/developer/logging.rst +++ b/doc/developer/logging.rst @@ -18,7 +18,7 @@ maybe by a syslog collector from all routers.) Therefore, anything that needs to get the user in the loop—and only these things—are warnings or errors. -Note that this doesn't neccessarily mean the user needs to fix something in +Note that this doesn't necessarily mean the user needs to fix something in the FRR instance. It also includes when we detect something else needs fixing, for example another router, the system we're running on, or the configuration. The common point is that the user should probably do diff --git a/doc/developer/maintainer-release-build.rst b/doc/developer/maintainer-release-build.rst index 85aaa5365a..7792173034 100644 --- a/doc/developer/maintainer-release-build.rst +++ b/doc/developer/maintainer-release-build.rst @@ -37,7 +37,7 @@ Release Build Procedure for FRR Maintainers 4. Update Changelog for Debian Packages: - Edit :file:`debianpkg/changelog.in`: + Edit :file:`debian/changelog-auto.in`: - Change last (top of list) entry from ``@VERSION@`` to previous fixed version number, i.e.:: diff --git a/doc/developer/memtypes.rst b/doc/developer/memtypes.rst index d43bc2555e..153131bab9 100644 --- a/doc/developer/memtypes.rst +++ b/doc/developer/memtypes.rst @@ -3,7 +3,7 @@ Memtypes ======== -FRR includes wrappers arround ``malloc()`` and ``free()`` that count the number +FRR includes wrappers around ``malloc()`` and ``free()`` that count the number of objects currently allocated, for each of a defined ``MTYPE``. To this extent, there are *memory groups* and *memory types*. Each memory @@ -95,7 +95,7 @@ Usage .. c:function:: void *XCALLOC(struct memtype *mtype, size_t size) -.. c:function:: void *XSTRDUP(struct memtype *mtype, size_t size) +.. c:function:: void *XSTRDUP(struct memtype *mtype, const char *name) Allocation wrappers for malloc/calloc/realloc/strdup, taking an extra mtype parameter. diff --git a/doc/developer/ospf-api.rst b/doc/developer/ospf-api.rst index 90fc52efd0..f4f38a63e9 100644 --- a/doc/developer/ospf-api.rst +++ b/doc/developer/ospf-api.rst @@ -284,7 +284,7 @@ Each message begins with the following header: The message type field can take one of the following values: +-------------------------------+---------+ -| Messages to OSPF deamon | Value | +| Messages to OSPF daemon | Value | +===============================+=========+ | MSG\_REGISTER\_OPAQUETYPE | 1 | +-------------------------------+---------+ @@ -300,7 +300,7 @@ The message type field can take one of the following values: +-------------------------------+---------+ +-----------------------------+---------+ -| Messages from OSPF deamon | Value | +| Messages from OSPF daemon | Value | +=============================+=========+ | MSG\_REPLY | 10 | +-----------------------------+---------+ diff --git a/doc/developer/ospf-sr.rst b/doc/developer/ospf-sr.rst index 4a673b155b..23bc803d76 100644 --- a/doc/developer/ospf-sr.rst +++ b/doc/developer/ospf-sr.rst @@ -31,7 +31,7 @@ Implementation details Concepts ^^^^^^^^ -Segment Routing used 3 differents OPAQUE LSA in OSPF to carry the various +Segment Routing used 3 different OPAQUE LSA in OSPF to carry the various information: * **Router Information:** flood the Segment Routing capabilities of the node. @@ -40,7 +40,7 @@ information: * **Extended Link:** flood the Adjaceny and Lan Adjacency Segment Identifier * **Extended Prefix:** flood the Prefix Segment Identifier -The implementation follow previous TE and Router Information codes. It used the +The implementation follows previous TE and Router Information codes. It used the OPAQUE LSA functions defined in ospf_opaque.[c,h] as well as the OSPF API. This latter is mandatory for the implementation as it provides the Callback to Segment Routing functions (see below) when an Extended Link / Prefix or Router @@ -71,7 +71,7 @@ The figure below shows the relation between the various files: (4.0.0.0), Extended Prefix (7.0.0.X) and Link (8.0.0.X) by ospf_ri.c, respectively ospf_ext.c. * ospf_ri.c send back to ospf_sr.c received Router Information LSA and update - Self Router Information LSA with paramters provided by ospf_sr.c i.e. SRGB + Self Router Information LSA with parameters provided by ospf_sr.c i.e. SRGB and MSD. It use ospf_opaque.c functions to send/received these Opaque LSAs. * ospf_ext.c send back to ospf_sr.c received Extended Prefix and Link Opaque LSA and send self Extended Prefix and Link Opaque LSA through ospf_opaque.c @@ -129,8 +129,8 @@ Opaque LSA it is the `ospf_opaque_lsa_install_hook()`. For deletion, it is Note that incoming LSA which is already present in the LSDB will be inserted after the old instance of this LSA remove from the LSDB. Thus, after the first time, each incoming LSA will trigger a `delete` following by an `install`. This -is not very helpfull to handle real LSA deletion. In fact, LSA deletion is done -by Flushing LSA i.e. flood LSA after seting its age to MAX_AGE. Then, a garbage +is not very helpful to handle real LSA deletion. In fact, LSA deletion is done +by Flushing LSA i.e. flood LSA after setting its age to MAX_AGE. Then, a garbage function has the role to remove all LSA with `age == MAX_AGE` in the LSDB. So, to handle LSA Flush, the best is to look to the LSA age to determine if it is an installation or a future deletion i.e. the flushed LSA is first store in the @@ -144,7 +144,7 @@ introduced. When this command is activated, function `ospf_router_info_update_sr()` is called to indicate to Router Information process that Segment Routing TLVs must be flood. Same function is called to modify the Segment Routing Global Block (SRGB) and Maximum Stack Depth (MSD) -TLV. Only Shortest Path First (SPF) Algorithm is supported, so no possiblity +TLV. Only Shortest Path First (SPF) Algorithm is supported, so no possibility to modify this TLV is offer by the code. When Opaque LSA Tyep 4 i.e. Router Information are stored in LSDB, function @@ -159,8 +159,8 @@ Extended Link Prefix LSAs ^^^^^^^^^^^^^^^^^^^^^^^^^ Like for Router Information, Segment Routing is activate at the Extended -Link/Prefix level with new `segment-routing on` command. This trigger -automtically the flooding of Extended Link LSA for all ospf interface where +Link/Prefix level with new `segment-routing on` command. This triggers +automatically the flooding of Extended Link LSA for all ospf interfaces where adjacency is full. For Extended Prefix LSA, the new CLI command `segment-routing prefix ...` will trigger the flooding of Prefix SID TLV/SubTLVs. @@ -255,7 +255,7 @@ The first segment-routing statement enable it. The Second one set the SRGB, third line the MSD and finally, set the Prefix SID index for a given prefix. Note that only prefix of Loopback interface could be configured with a Prefix SID. It is possible to add `no-php-flag` at the end of the prefix command to -disbale Penultimate Hop Popping. This advertises peers that they MUST NOT pop +disable Penultimate Hop Popping. This advertises to peers that they MUST NOT pop the MPLS label prior to sending the packet. Known limitations diff --git a/doc/developer/packaging-debian.rst b/doc/developer/packaging-debian.rst index c812a38212..b57286d5a1 100644 --- a/doc/developer/packaging-debian.rst +++ b/doc/developer/packaging-debian.rst @@ -1,31 +1,18 @@ +.. _packaging-debian: + Packaging Debian ================ -(Tested on Ubuntu 12.04, 14.04, 16.04, 17.10, 18.04, Debian 8 and 9) - -.. note:: - - If you try to build for a different distro, then it will most likely fail - because of the missing backport. See :ref:`deb-backports` about adding a new - backport. - -1. Install build dependencies for your platform as outlined in :ref:`building`. - -2. Install the following additional packages: - - - on Ubuntu 12.04, 14.04, 16.04, 17.10, Debian 8 and 9: - - .. code-block:: shell - - apt-get install realpath equivs groff fakeroot debhelper devscripts +(Tested on Ubuntu 14.04, 16.04, 17.10, 18.04, Debian jessie, stretch and +buster.) - - on Ubuntu 18.04: (realpath is now part of preinstalled by coreutils) +1. Install the Debian packaging tools: .. code-block:: shell - apt-get install equivs groff fakeroot debhelper devscripts + sudo apt install fakeroot debhelper devscripts -3. Checkout FRR under a **unprivileged** user account: +2. Checkout FRR under an **unprivileged** user account: .. code-block:: shell @@ -38,143 +25,145 @@ Packaging Debian git checkout <branch> -4. Run ``bootstrap.sh`` and make a dist tarball: +3. Install build dependencies using the `mk-build-deps` tool from the + `devscripts` package: .. code-block:: shell - ./bootstrap.sh - ./configure --with-pkg-extra-version=-MyDebPkgVersion - make dist - - .. note:: - - Configure parameters are not important for the Debian Package building - - except the `with-pkg-extra-version` if you want to give the Debian - package a specific name to mark your own unoffical build. - -5. Edit :file:`debianpkg/rules` and set the configuration as needed. - - Look for section ``dh_auto_configure`` to modify the configure options as - needed. Options might be different between the top-level ``rules``` and - :file:`backports/XXXX/debian/rules`. Please adjust as needed on all files. + sudo mk-build-deps --install debian/control -6. Create backports debian sources + Alternatively, you can manually install build dependencies for your + platform as outlined in :ref:`building`. - Rename the :file:`debianpkg` directory to :file:`debian` and create the - backports (Debian requires to not ship a :file:`debian` directory inside the - source directory to avoid build conflicts with the reserved ``debian`` - subdirectory name during the build): +4. Run ``tools/tarsource.sh -V``: .. code-block:: shell - mv debianpkg debian - make -f debian/rules backports - - This will create a :file:`frr_*.orig.tar.gz` with the source (same as the - dist tarball), as well as multiple :file:`frr_*.debian.tar.xz` and - :file:`frr_*.dsc` corresponding to each distribution for which a backport is - available. + ./tools/tarsource.sh -V -7. Create a new directory to build the package and populate with package - source. + This script sets up the ``debian/changelog-auto`` file with proper version + information. - .. code-block:: shell - - mkdir frrpkg - cd frrpkg - tar xf ~/frr/frr_*.orig.tar.gz - cd frr* - . /etc/os-release - tar xf ~/frr/frr_*${ID}${VERSION_ID}*.debian.tar.xz +5. (optional) Append a distribution identifier if needed (see below under + :ref:`multi-dist`.) -8. Build Debian package dependencies and install them as needed. +6. Build Debian Package: .. code-block:: shell - sudo mk-build-deps --install debian/control + dpkg-buildpackage $options -9. Build Debian Package + Where `$options` may contain any or all of the following items: - Building with standard options: + * build profiles specified with ``-P``, e.g. + ``-Ppkg.frr.nortrlib,pkg.frr.nosystemd``. + Multiple values are separated by commas and there must not be a space + after the ``-P``. - .. code-block:: shell + The following build profiles are currently available: - debuild -b -uc -us + +----------------+-------------------+-----------------------------------------+ + | Profile | Negation | Effect | + +================+===================+=========================================+ + | pkg.frr.rtrlib | pkg.frr.nortrlib | builds frr-rpki-rtrlib package (or not) | + +----------------+-------------------+-----------------------------------------+ + | n/a | pkg.frr.nosystemd | removes libsystemd dependency and | + | | | disables unit file installation | + +----------------+-------------------+-----------------------------------------+ - Or change some options (see `rules` file for available options): + .. note:: - .. code-block:: shell + The ``pkg.frr.nosystemd`` option is only intended to support Ubuntu + 14.04 (and should be enabled when building for that.) - debuild --set-envvar=WANT_BGP_VNC=1 --set-envvar=WANT_CUMULUS_MODE=1 -b -uc -us + * the ``-uc -us`` options to disable signing the packages with your GPG key - To build with RPKI: + (git builds of the `master` or `stable/X.X` branches won't be signed by + default since their target release is set to ``UNRELEASED``.) - - Download the librtr packages from - https://ci1.netdef.org/browse/RPKI-RTRLIB/latestSuccessful/artifact +7. Done! - - install librtr-dev on the build server + If all worked correctly, then you should end up with the Debian packages in + the parent directory of where `debuild` ran. If distributed, please make sure + you distribute it together with the sources (``frr_*.orig.tar.xz``, + ``frr_*.debian.tar.xz`` and ``frr_*.dsc``) - Then build with: +.. note:: - .. code-block:: shell + A package created from `master` or `stable/X.X` is slightly different from + a package created from the `debian` branch. The changelog for the former + is autogenerated and sets the Debian revision to ``-0``, which causes an + intentional lintian warning. The `debian` branch on the other hand has + a manually maintained changelog that contains proper Debian release + versioning. - debuild --set-envvar=WANT_RPKI=1 -b -uc -us + Furthermore, official Debian packages are built in ``3.0 (quilt)`` format + with an "orig" tarball and a "debian" tarball. These tarballs are created + by the ``tarsource.sh`` tool on any branch. The git repository however + contains a ``3.0 (git)`` source format specifier to easily allow direct + git builds. - RPKI packages have an additonal dependency of ``librtr0`` which can be found - at the same URL. -10. Done! +.. _multi-dist: -If all worked correctly, then you should end up with the Debian packages under -:file:`frrpkg`. If distributed, please make sure you distribute it together -with the sources (``frr_*.orig.tar.gz``, ``frr_*.debian.tar.xz`` and -``frr_*.dsc``) +Multi-Distribution builds +========================= -The build procedure can also be executed automatically using the ``tools/build-debian-package.sh`` -script. For example: +You can optionally append a distribution identifier in case you want to +make multiple versions of the package available in the same repository. +Do the following after creating the changelog with `tarsource.sh`: .. code-block:: shell - EXTRA_VERSION="-myversion" WANT_SNMP=1 WANT_CUMULUS_MODE=1 tools/build-debian-package.sh - -.. _deb-backports: + dch -l '~deb8u' 'build for Debian 8 (jessie)' + dch -l '~deb9u' 'build for Debian 9 (stretch)' + dch -l '~ubuntu14.04.' 'build for Ubuntu 14.04 (trusty)' + dch -l '~ubuntu16.04.' 'build for Ubuntu 16.04 (xenial)' + dch -l '~ubuntu18.04.' 'build for Ubuntu 18.04 (bionic)' + +Between building packages for specific distributions, the only difference +in the package itself lies in the automatically generated shared library +dependencies, e.g. libjson-c2 or libjson-c3. This means that the +architecture independent packages should **not** have a suffix appended. +Also, the current Debian testing/unstable releases should not have any suffix +appended. + +For example, at the end of 2018 (i.e. ``buster``/Debian 10 is the current +"testing" release), the following is a complete list of `.deb` files for +Debian 8, 9 and 10 packages for FRR 6.0.1-1 with RPKI support:: + + frr_6.0.1-1_amd64.deb + frr_6.0.1-1~deb8u1_amd64.deb + frr_6.0.1-1~deb9u1_amd64.deb + frr-dbg_6.0.1-1_amd64.deb + frr-dbg_6.0.1-1~deb8u1_amd64.deb + frr-dbg_6.0.1-1~deb9u1_amd64.deb + frr-rpki-rtrlib_6.0.1-1_amd64.deb + frr-rpki-rtrlib_6.0.1-1~deb8u1_amd64.deb + frr-rpki-rtrlib_6.0.1-1~deb9u1_amd64.deb + frr-doc_6.0.1-1_all.deb + frr-pythontools_6.0.1-1_all.deb + +Note that there are no extra versions of the `frr-doc` and `frr-pythontools` +packages (because they are for architecture ``all``, not ``amd64``), and the +version for Debian 10 does **not** have a ``~deb10u1`` suffix. + +.. warning:: + + Do not use the ``-`` character in the version suffix. The last ``-`` in + the version number is the separator between upstream version and Debian + version. ``6.0.1-1~foobar-2`` means upstream version ``6.0.1-1~foobar``, + Debian version ``2``. This is not what you want. + + The only allowed characters in the Debian version are ``0-9 A-Z a-z + . ~`` -Debian Backports ----------------- - -The :file:`debianpkg/backports` directory contains the Debian directories for -backports to other Debian platforms. These are built via the ``3.0 (custom)`` -source format, which allows one to build a source package directly out of -tarballs (e.g. an orig.tar.gz tarball and a debian.tar.gz file), at which point -the format can be changed to a real format (e.g. ``3.0 (quilt)``). - -Source packages are assembled via targets of the same name as the system to -which the backport is done (e.g. ``precise``), included in :file:`debian/rules`. - -To create a new Debian backport: - -- Add its name to ``KNOWN_BACKPORTS``, defined in :file:`debian/rules`. -- Create a directory of the same name in :file:`debian/backports`. -- Add the files ``exclude``, ``versionext``, and ``debian/source/format`` under - this directory. - -For the last point, these files should contain the following: - -``exclude`` - Contains whitespace-separated paths (relative to the root of the source dir) - that should be excluded from the source package (e.g. - :file:`debian/patches`). - -``versionext`` - Contains the suffix added to the version number for this backport's build. - Distributions often have guidelines for what this should be. If left empty, - no new :file:`debian/changelog` entry is created. +.. note:: -``debian/source/format`` - Contains the source format of the resulting source package. As of of the - writing of this document the only supported format is ``3.0 (quilt)``. + The separating character for the suffix **must** be the tilde (``~``) + because the tilde is ordered in version-comparison before the empty + string. That means the order of the above packages is the following: -- Add appropriate files under the :file:`debian/` subdirectory. These will be - included in the source package, overriding any top-level :file:`debian/` - files with equivalent paths. + ``6.0.1-1`` newer than ``6.0.1-1~deb9u1`` newer than ``6.0.1-1~deb8u1`` + If you use another character (e.g. ``+``), the untagged version will be + regarded as the "oldest"! diff --git a/doc/developer/packaging-redhat.rst b/doc/developer/packaging-redhat.rst new file mode 100644 index 0000000000..f6b9931156 --- /dev/null +++ b/doc/developer/packaging-redhat.rst @@ -0,0 +1,85 @@ +.. _packaging-redhat: + +Packaging Red Hat +================= + +Tested on CentOS 6, CentOS 7 and Fedora 24. + +1. On CentOS 6, refer to :ref:`building-centos6` for details on installing + sufficiently up-to-date package versions to enable building FRR. + + Newer automake/autoconf/bison is only needed to build the RPM and is **not** + needed to install the binary RPM package. + +2. Install the build dependencies for your platform. Refer to the + platform-specific build documentation on how to do this. + +3. Install the following additional packages:: + + yum install rpm-build net-snmp-devel pam-devel libcap-devel + + If your platform uses systemd:: + + yum install systemd-devel + + If ``yum`` is not present on your system, use ``dnf`` instead. + +3. Checkout FRR:: + + git clone https://github.com/frrouting/frr.git frr + +4. Run Bootstrap and make distribution tar.gz:: + + cd frr + ./bootstrap.sh + ./configure --with-pkg-extra-version=-MyRPMVersion SPHINXBUILD=sphinx-build2.7 + make dist + + .. note:: + + The only ``configure`` option respected when building RPMs is + ``--with-pkg-extra-version``. + +5. Create RPM directory structure and populate with sources:: + + mkdir rpmbuild + mkdir rpmbuild/SOURCES + mkdir rpmbuild/SPECS + cp redhat/*.spec rpmbuild/SPECS/ + cp frr*.tar.gz rpmbuild/SOURCES/ + +6. Edit :file:`rpm/SPECS/frr.spec` with configuration as needed. + + Look at the beginning of the file and adjust the following parameters to + enable or disable features as required:: + + ############### FRRouting (FRR) configure options ################# + # with-feature options + %{!?with_pam: %global with_pam 0 } + %{!?with_ospfclient: %global with_ospfclient 1 } + %{!?with_ospfapi: %global with_ospfapi 1 } + %{!?with_irdp: %global with_irdp 1 } + %{!?with_rtadv: %global with_rtadv 1 } + %{!?with_ldpd: %global with_ldpd 1 } + %{!?with_nhrpd: %global with_nhrpd 1 } + %{!?with_eigrp: %global with_eigrpd 1 } + %{!?with_shared: %global with_shared 1 } + %{!?with_multipath: %global with_multipath 256 } + %{!?frr_user: %global frr_user frr } + %{!?vty_group: %global vty_group frrvty } + %{!?with_fpm: %global with_fpm 0 } + %{!?with_watchfrr: %global with_watchfrr 1 } + %{!?with_bgp_vnc: %global with_bgp_vnc 0 } + %{!?with_pimd: %global with_pimd 1 } + %{!?with_rpki: %global with_rpki 0 } + +7. Build the RPM:: + + rpmbuild --define "_topdir `pwd`/rpmbuild" -ba rpmbuild/SPECS/frr.spec + + If building with RPKI, then download and install the additional RPKI + packages from + https://ci1.netdef.org/browse/RPKI-RTRLIB/latestSuccessful/artifact + +If all works correctly, then you should end up with the RPMs under +:file:`rpmbuild/RPMS` and the source RPM under :file:`rpmbuild/SRPMS`. diff --git a/doc/developer/packaging.rst b/doc/developer/packaging.rst index 27e6e155fb..b174a9660c 100644 --- a/doc/developer/packaging.rst +++ b/doc/developer/packaging.rst @@ -7,3 +7,4 @@ Packaging maintainer-release-build packaging-debian + packaging-redhat diff --git a/doc/developer/subdir.am b/doc/developer/subdir.am index 19910e7627..a0c5e6fc9d 100644 --- a/doc/developer/subdir.am +++ b/doc/developer/subdir.am @@ -5,7 +5,6 @@ dev_RSTFILES = \ doc/developer/bgp-typecodes.rst \ doc/developer/bgpd.rst \ - doc/developer/building-frr-for-openwrt.rst \ doc/developer/building-frr-for-alpine.rst \ doc/developer/building-frr-for-centos6.rst \ doc/developer/building-frr-for-centos7.rst \ @@ -19,7 +18,7 @@ dev_RSTFILES = \ doc/developer/building-frr-for-netbsd7.rst \ doc/developer/building-frr-for-omnios.rst \ doc/developer/building-frr-for-openbsd6.rst \ - doc/developer/building-frr-for-ubuntu1204.rst \ + doc/developer/building-frr-for-openwrt.rst \ doc/developer/building-frr-for-ubuntu1404.rst \ doc/developer/building-frr-for-ubuntu1604.rst \ doc/developer/building-frr-for-ubuntu1804.rst \ @@ -38,6 +37,9 @@ dev_RSTFILES = \ doc/developer/ospf-api.rst \ doc/developer/ospf-sr.rst \ doc/developer/ospf.rst \ + doc/developer/packaging-debian.rst \ + doc/developer/packaging-redhat.rst + doc/developer/packaging.rst \ doc/developer/testing.rst \ doc/developer/topotests-snippets.rst \ doc/developer/topotests.rst \ diff --git a/doc/developer/topotests-snippets.rst b/doc/developer/topotests-snippets.rst index 649229b433..fb3c928a77 100644 --- a/doc/developer/topotests-snippets.rst +++ b/doc/developer/topotests-snippets.rst @@ -48,17 +48,17 @@ A sample of this snippet in a test can be found `here Interacting with equipment ^^^^^^^^^^^^^^^^^^^^^^^^^^ -You might want to interact with the topology equipments during the tests and +You might want to interact with the topology equipment during the tests and there are different ways to do so. Notes: -1. When using the Topogen API, all the equipments code derive from ``Topogear`` +1. When using the Topogen API, all the equipment code derives from ``Topogear`` (`lib/topogen.py <lib/topogen.py>`__). If you feel brave you can look by - yourself how the abstractions that will be mentioned here works. + yourself how the abstractions that will be mentioned here work. 2. When not using the ``Topogen`` API there is only one way to interact with - the equipments, which is by calling the ``mininet`` API functions directly + the equipment, which is by calling the ``mininet`` API functions directly to spawn commands. Interacting with the Linux sandbox @@ -149,7 +149,7 @@ Translating vtysh JSON output into Python structures: .. note:: - ``vtysh_(multi)cmd`` is only available for router type of equipments. + ``vtysh_(multi)cmd`` is only available for router types of equipment. Invoking mininet CLI ^^^^^^^^^^^^^^^^^^^^ @@ -195,7 +195,7 @@ Loading JSON from a file: Comparing JSON output ^^^^^^^^^^^^^^^^^^^^^ -After obtaining JSON output formated with Python data structures, you may use +After obtaining JSON output formatted with Python data structures, you may use it to assert a minimalist schema: .. code:: py diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst index aa06c8dffd..605b9c9a0c 100644 --- a/doc/developer/topotests.rst +++ b/doc/developer/topotests.rst @@ -151,7 +151,7 @@ Collect Memory Leak Information ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FRR processes have the capabilities to report remaining memory allocations upon -exit. To enable the reporting of the memory, define an enviroment variable +exit. To enable the reporting of the memory, define an environment variable ``TOPOTESTS_CHECK_MEMLEAK`` with the file prefix, i.e.:: export TOPOTESTS_CHECK_MEMLEAK="/home/mydir/memleak_" @@ -410,7 +410,7 @@ Defining the Topology The first step to write a new test is to define the topology. This step can be done in many ways, but the recommended is to use Graphviz to generate a drawing of the topology. It allows us to see the topology graphically and to see the -names of equipments, links and addresses. +names of equipment, links and addresses. Here is an example of Graphviz dot file that generates the template topology :file:`tests/topotests/example-test/test_template.dot` (the inlined code might diff --git a/doc/developer/vtysh.rst b/doc/developer/vtysh.rst index 4a52eb0544..160676a7b1 100644 --- a/doc/developer/vtysh.rst +++ b/doc/developer/vtysh.rst @@ -43,7 +43,7 @@ simplifying the output. This is discussed in :ref:`vtysh-configuration`. Command Extraction ------------------ -When VTYSH is a built, a Perl script named :file:`extract.pl` searches the FRR +When VTYSH is built, a Perl script named :file:`extract.pl` searches the FRR codebase looking for ``DEFUN``'s. It extracts these ``DEFUN``'s, transforms them into ``DEFSH``'s and appends them to ``vtysh_cmd.c``. Each ``DEFSH`` contains the name of the command plus ``_vtysh``, as well as a flag that @@ -167,7 +167,7 @@ Protocol VTYSH communicates with FRR daemons by way of domain socket. Each daemon creates its own socket, typically in :file:`/var/run/frr/<daemon>.vty`. The protocol is very simple. In the VTYSH to daemon direction, messages are simply -NULL-terminated strings, whose content are CLI commands. Here is a typical +NUL-terminated strings, whose content are CLI commands. Here is a typical message from VTYSH to a daemon: :: @@ -178,7 +178,7 @@ message from VTYSH to a daemon: 00000010: 6c0a 00 l.. -The response format has some more data in it. First is a NULL-terminated string +The response format has some more data in it. First is a NUL-terminated string containing the plaintext response, which is just the output of the command that was sent in the request. This is displayed to the user. The plaintext response is followed by 3 null marker bytes, followed by a 1-byte status code that diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst index 1bb0886fd5..b66392f7ca 100644 --- a/doc/developer/workflow.rst +++ b/doc/developer/workflow.rst @@ -128,7 +128,7 @@ branch is required. The work can be shared by multiple people. In all cases, the must be at least one person that is in charge of the maintenance branch. The person on people responsible for a maintenance branch must be a FRR maintainer. Note that they may choose to abandon support for the maintenance branch at any time. If -noone takes over the responsibility of the LTS branch, then the support will be +no one takes over the responsibility of the LTS branch, then the support will be discontinued. The LTS branch duties are the following ones: @@ -371,7 +371,7 @@ system in which submissions from an individual representing one company should be merged by someone unaffiliated with that company. Guidelines for code review -"""""""""""""""""""""""""" +-------------------------- - As a rule of thumb, the depth of the review should be proportional to the scope and / or impact of the patch. diff --git a/doc/manpages/defines.rst b/doc/manpages/defines.rst index e1f7ec4ce8..cdf5e1967e 100644 --- a/doc/manpages/defines.rst +++ b/doc/manpages/defines.rst @@ -1,3 +1,3 @@ .. |synopsis-options| replace:: [-d|-t|-dt] [-C] [-f config-file] [-i pid-file] [-z zclient-path] [-u user] [-g group] [-A vty-addr] [-P vty-port] [-M module[:options]] [-N pathspace] [--vty_socket vty-path] [--moduledir module-path] .. |synopsis-options-hv| replace:: [-h] [-v] -.. |seealso-programs| replace:: zebra(8), vtysh(1), ripd(8), ripngd(8), ospfd(8), ospf6d(8), bgpd(8), isisd(8), babeld(8), nhrpd(8), pimd(8), pbrd(8), ldpd(8), eigrpd(8), staticd(8), mtracebis(8) +.. |seealso-programs| replace:: zebra(8), vtysh(1), ripd(8), ripngd(8), ospfd(8), ospf6d(8), bgpd(8), isisd(8), babeld(8), nhrpd(8), pimd(8), pbrd(8), ldpd(8), eigrpd(8), staticd(8), fabricd(8), mtracebis(8) diff --git a/doc/manpages/watchfrr.rst b/doc/manpages/watchfrr.rst index f0b733298d..dceb423f82 100644 --- a/doc/manpages/watchfrr.rst +++ b/doc/manpages/watchfrr.rst @@ -22,21 +22,6 @@ In order to avoid restarting the daemons in quick succession, you can supply the OPTIONS ======= -The following 3 options specify scripts that |DAEMON| uses to perform start/stop/restart actions. These options are mandatory unless the --dry option is used: - -.. option:: -s command, --start-command command - - Supply a Bourne shell command to start a single daemon. The command string should contain the '%s' placeholder to be sub‐ stituted with the daemon name. - -.. option:: -k command, --kill-command command - - Supply a Bourne shell command to stop a single daemon. The command string should contain the '%s' placeholder to be substituted with the daemon name. - -.. option:: -r command, --restart command - - Supply a Bourne shell command to restart a single daemon. The command string should contain the '%s' placeholder to be substituted with the daemon name. - -Other options: .. option:: --dry @@ -92,6 +77,20 @@ Other options: Display the usage information and exit. +The following 3 options specify scripts that |DAEMON| uses to perform start/stop/restart actions. Reasonable default values are built into watchfrr, so the use of these options should no longer be necessary: + +.. option:: -s command, --start-command command + + Supply a Bourne shell command to start a single daemon. The command string should contain the '%s' placeholder to be substituted with the daemon name. + +.. option:: -k command, --kill-command command + + Supply a Bourne shell command to stop a single daemon. The command string should contain the '%s' placeholder to be substituted with the daemon name. + +.. option:: -r command, --restart command + + Supply a Bourne shell command to restart a single daemon. The command string should contain the '%s' placeholder to be substituted with the daemon name. + PREVIOUS OPTIONS ================ Prior versions of |DAEMON| supported some additional options that no longer exist::: diff --git a/doc/user/_static/overrides.css b/doc/user/_static/overrides.css index 41fcc66f8d..638f61986f 100644 --- a/doc/user/_static/overrides.css +++ b/doc/user/_static/overrides.css @@ -3,10 +3,6 @@ div.body { max-width: none; } -pre { - background-color: #e2e2e2; -} - /* styling for the protocols vs. OS table in overview.rst */ /* first, general bits */ div.body td.mark { @@ -40,6 +36,7 @@ td.mark span { border: 1px dotted #666; width: 36pt; margin:auto; + text-align:center; } table.mark tr td:first-child { padding-left:1.5em; @@ -61,3 +58,238 @@ li span.mark { width: 36pt; text-align: center; } + +/* Palette URL: http://paletton.com/#uid=70p0p0kt6uvcDRAlhBavokxLJ6w */ + +:root { +--primary-0: #F36F16; /* Main Primary color */ +--primary-1: #FFC39A; +--primary-2: #FF9A55; +--primary-3: #A34403; +--primary-4: #341500; +--primary-9: #FFF3EB; + +--secondary-1-0: #F39C16; /* Main Secondary color (1) */ +--secondary-1-1: #FFD79A; +--secondary-1-2: #FFBC55; +--secondary-1-3: #A36403; +--secondary-1-4: #341F00; +--secondary-1-9: #FFF7EB; + +--secondary-2-0: #1A599F; /* Main Secondary color (2) */ +--secondary-2-1: #92B9E5; +--secondary-2-2: #477CB8; +--secondary-2-3: #0A386B; +--secondary-2-4: #011122; +--secondary-2-9: #E3EBF4; + +--complement-0: #0E9A83; /* Main Complement color */ +--complement-1: #8AE4D4; +--complement-2: #3CB4A0; +--complement-3: #026857; +--complement-4: #00211B; +--complement-9: #E0F4F0; +} + +/* new */ + +body { + font-family: "Fira Sans", Helvetica, Arial, sans-serif; + font-weight:400; +} +h1, h2, h3, h4, h5, h6 { + font-family: "Fira Sans", Helvetica, Arial, sans-serif; + font-weight:500; +} +code, pre, tt { + font-family: "Fira Mono"; +} +h1 { + background-color:var(--secondary-1-1); + border-bottom:1px solid var(--secondary-1-0); + font-weight:300; +} +h2 { + margin-top:36pt; +} + +a, +a:hover, +a:visited, +.code-block-caption a.headerlink:hover, +.rst-content dl:not(.docutils) dt .headerlink { + color: var(--complement-0); +} +.code-block-caption a.headerlink { + visibility:hidden; +} + +/* admonitions */ + +.admonition.warning { + border:1px dashed var(--primary-2); +} +.admonition.warning .admonition-title { + color: var(--primary-3); + background-color: var(--primary-1); +} +.admonition.note, +.admonition.hint { + border:1px dashed var(--complement-2); +} +.admonition.note .admonition-title, +.admonition.hint .admonition-title { + color: var(--complement-3); + background-color: var(--complement-1); +} +.admonition.seealso, +div.seealso { + background-color:var(--complement-9); +} +.admonition.seealso .admonition-title { + color: var(--complement-3); + background-color:var(--complement-1); + border-bottom:1px solid var(--complement-2); +} +.admonition.admonition-todo .admonition-title { + background-image: repeating-linear-gradient( + 135deg, + #ffa, + #ffa 14.14213452px, + #bbb 14.14213452px, + #bbb 28.28427124px + ); + color:#000; +} +.admonition.admonition-todo { + background-image: repeating-linear-gradient( + 135deg, + #ffd, + #ffd 14.14213452px, + #eed 14.14213452px, + #eed 28.28427124px + ); +} + +.rst-content dl .admonition p.last { + margin-bottom:0 !important; +} + +/* file block */ + +.code-block-caption { +/* border-radius: 4px; */ + font-style:italic; + font-weight:300; + border-bottom: 1px solid var(--secondary-2-1); + background-color: var(--secondary-2-9); + padding:2px 8px; +} + +/* navbar */ + +.wy-nav-side { + background-color: var(--secondary-1-4); + border-right:2px solid var(--primary-3); +} +.wy-menu-vertical a, +.wy-menu-vertical a:visited, +.wy-menu-vertical a:hover, +.wy-side-nav-search>a, +.wy-side-nav-search .wy-dropdown>a { + color: var(--primary-0); +} + +nav div.wy-side-nav-search { + background-color: #eee; +} +nav div.wy-side-scroll { + background-color: var(--secondary-1-4); +} +nav .wy-menu-vertical a:hover { + background-color:var(--primary-0); + color:var(--primary-4); +} +nav .wy-menu-vertical li.current ul a:hover { + background-color:var(--secondary-1-2); + color:var(--primary-4); +} +nav .wy-menu-vertical li.current ul a { + background-color:var(--secondary-1-1); + color:var(--primary-3); +} +nav .wy-menu-vertical li.on a:hover, +nav .wy-menu-vertical li.current>a:hover { + background-color:#fcfcfc; +} +.wy-side-nav-search input[type=text] { + border-color:var(--primary-2); +} +.wy-menu-vertical li.toctree-l1.current>a { + border-top:1px solid var(--secondary-1-3); + border-bottom:1px solid var(--secondary-1-3); +} +.wy-menu-vertical li.toctree-l2.current>a { + background-color:var(--secondary-1-2); +} +.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a { + background-color:var(--secondary-1-9); +} + +.wy-nav-content { + padding: 25pt 40pt; +} +div[role=navigation] > hr { + display:none; +} +div[role=navigation] { + margin-bottom:15pt; +} +h1 { + margin-left:-40pt; + margin-right:-40pt; + padding:5pt 40pt 5pt 40pt; +} + +.rst-content pre.literal-block, .rst-content div[class^='highlight'] { + border-color:var(--secondary-1-1); +} + +span.pre { + color: var(--complement-3); +} +pre { + background-color: var(--secondary-1-9); + border-color: var(--secondary-1-1); +} +.highlight .p { color: var(--secondary-2-3); } +.highlight .k { color: var(--secondary-2-0); } +.highlight .kt { color: var(--complement-0); } +.highlight .cm { color: var(--primary-3); } +.highlight .ow { color: var(--primary-3); } +.highlight .na { color: var(--primary-2); } +.highlight .nv { color: var(--complement-0); } + +strong { + font-weight:500; +} +.rst-content dl:not(.docutils) dt { + font-family:Fira Mono; + font-weight:600; + background-color:var(--secondary-2-9); + color:var(--secondary-2-3); + border-top:2px solid var(--secondary-2-2); +} +dt code.descname { + color: var(--secondary-2-4); +} + +@media (min-width: 1200px) { + .container { width: auto; } +} +@media (min-width: 992px) { + .container { width: auto; } +} +@media (min-width: 768px) { + .container { width: auto; } +} diff --git a/doc/user/basic.rst b/doc/user/basic.rst index 8201fdf1b9..8fbea29ee7 100644 --- a/doc/user/basic.rst +++ b/doc/user/basic.rst @@ -390,7 +390,7 @@ Terminal Mode Commands .. index:: find COMMAND... .. clicmd:: find COMMAND... - This commmand performs a simple substring search across all defined commands + This command performs a simple substring search across all defined commands in all modes. As an example, suppose you're in enable mode and can't remember where the command to turn OSPF segment routing on is: diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 5b453e75c3..be331ffb99 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -511,8 +511,8 @@ cause may lead to routing instability or oscillation across multiple speakers in iBGP topologies. This can occur with full-mesh iBGP, but is particularly problematic in non-full-mesh iBGP topologies that further reduce the routing information known to each speaker. This has primarily been documented with iBGP -route-reflection topologies. However, any route-hiding technologies potentially -could also exacerbate oscillation with MED. +:ref:`route-reflection <bgp-route-reflector>` topologies. However, any +route-hiding technologies potentially could also exacerbate oscillation with MED. This second issue occurs where speakers each have only a subset of routes, and there are cycles in the preferences between different combinations of routes - @@ -1145,7 +1145,7 @@ is 4 octet long. The following format is used to define the community value. ``graceful-shutdown`` represents well-known communities value ``GRACEFUL_SHUTDOWN`` ``0xFFFF0000`` ``65535:0``. :rfc:`8326` implements the purpose Graceful BGP Session Shutdown to reduce the amount of - lost traffic when taking BGP sessions down for maintainance. The use + lost traffic when taking BGP sessions down for maintenance. The use of the community needs to be supported from your peers side to actually have any effect. @@ -1176,20 +1176,20 @@ is 4 octet long. The following format is used to define the community value. ``llgr-stale`` ``llgr-stale`` represents well-known communities value ``LLGR_STALE`` ``0xFFFF0006`` ``65535:6``. - Assigned and intented only for use with routers supporting the + Assigned and intended only for use with routers supporting the Long-lived Graceful Restart Capability as described in [Draft-IETF-uttaro-idr-bgp-persistence]_. - Routers recieving routes with this community may (depending on + Routers receiving routes with this community may (depending on implementation) choose allow to reject or modify routes on the presence or absence of this community. ``no-llgr`` ``no-llgr`` represents well-known communities value ``NO_LLGR`` ``0xFFFF0007`` ``65535:7``. - Assigned and intented only for use with routers supporting the + Assigned and intended only for use with routers supporting the Long-lived Graceful Restart Capability as described in [Draft-IETF-uttaro-idr-bgp-persistence]_. - Routers recieving routes with this community may (depending on + Routers receiving routes with this community may (depending on implementation) choose allow to reject or modify routes on the presence or absence of this community. @@ -1251,7 +1251,7 @@ UPDATE messages. There are two types of community list: standard - This type accepts an explicit value for the atttribute. + This type accepts an explicit value for the attribute. expanded This type accepts a regular expression. Because the regex must be @@ -2240,10 +2240,15 @@ Displaying Routes by AS Path Route Reflector =============== -.. note:: This documentation is woefully incomplete. +BGP routers connected inside the same AS through BGP belong to an internal +BGP session, or IBGP. In order to prevent routing table loops, IBGP does not +advertise IBGP-learned routes to other routers in the same session. As such, +IBGP requires a full mesh of all peers. For large networks, this quickly becomes +unscalable. Introducing route reflectors removes the need for the full-mesh. -.. index:: bgp cluster-id A.B.C.D -.. clicmd:: bgp cluster-id A.B.C.D +When route reflectors are configured, these will reflect the routes announced +by the peers configured as clients. A route reflector client is configured +with: .. index:: neighbor PEER route-reflector-client .. clicmd:: neighbor PEER route-reflector-client @@ -2251,6 +2256,13 @@ Route Reflector .. index:: no neighbor PEER route-reflector-client .. clicmd:: no neighbor PEER route-reflector-client +To avoid single points of failure, multiple route reflectors can be configured. + +A cluster is a collection of route reflectors and their clients, and is used +by route reflectors to avoid looping. + +.. index:: bgp cluster-id A.B.C.D +.. clicmd:: bgp cluster-id A.B.C.D .. _routing-policy: @@ -2469,7 +2481,7 @@ certainly contains silly mistakes, if not serious flaws. route-map rm-no-export permit 20 ! route-map rm-blackhole permit 10 - description blackhole, up-pref and ensure it cant escape this AS + description blackhole, up-pref and ensure it cannot escape this AS set ip next-hop 127.0.0.1 set local-preference 10 set community additive no-export diff --git a/doc/user/conf.py b/doc/user/conf.py index 57a7c08473..5582847431 100644 --- a/doc/user/conf.py +++ b/doc/user/conf.py @@ -168,12 +168,19 @@ todo_include_todos = True # a list of builtin themes. html_theme = 'default' +try: + import sphinx_rtd_theme + + html_theme = 'sphinx_rtd_theme' +except ImportError: + pass + # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -html_theme_options = { - 'sidebarbgcolor': '#374249' -} +#html_theme_options = { +# 'sidebarbgcolor': '#374249' +#} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] diff --git a/doc/user/flowspec.rst b/doc/user/flowspec.rst index f6af88cac8..b274afe8a2 100644 --- a/doc/user/flowspec.rst +++ b/doc/user/flowspec.rst @@ -167,7 +167,7 @@ set. That VRF will then be selected. The below full configuration example depicts how Route Targets are configured and how VRFs and cross VRF configuration is done. Note that the VRF are mapped on Linux Network Namespaces. For data traffic to cross VRF boundaries, virtual ethernet -interfaces are created with private IP adressing scheme. +interfaces are created with private IP addressing scheme. .. code-block:: frr @@ -322,7 +322,7 @@ There are some other known issues: - The validation procedure depicted in :rfc:`5575` is not available. This validation procedure has not been implemented, as this feature was not - used in the existing setups you shared wih us. + used in the existing setups you shared with us. - The filtering action shaper value, if positive, is not used to apply shaping. diff --git a/doc/user/installation.rst b/doc/user/installation.rst index 4e1582ccd8..964297292f 100644 --- a/doc/user/installation.rst +++ b/doc/user/installation.rst @@ -272,10 +272,11 @@ options from the list below. .. option:: --enable-multipath=X Compile FRR with up to X way ECMP supported. This number can be from 0-999. - For backwards compatability with older configure options when setting X = 0, + For backwards compatibility with older configure options when setting X = 0, we will build FRR with 64 way ECMP. This is needed because there are hardcoded arrays that FRR builds towards, so we need to know how big to - make these arrays at build time. + make these arrays at build time. Additionally if this parameter is + not passed in FRR will default to 16 ECMP. .. option:: --enable-shell-access diff --git a/doc/user/ipv6.rst b/doc/user/ipv6.rst index 585c3a505a..cc8fd18fee 100644 --- a/doc/user/ipv6.rst +++ b/doc/user/ipv6.rst @@ -179,10 +179,56 @@ Router Advertisement hosts in proper interface configuration. The announced value is not verified to be consistent with router interface MTU. - Default: don't advertise any MTU option.:: - interface eth0 - no ipv6 nd suppress-ra - ipv6 nd prefix 2001:0DB8:5009::/64 + Default: don't advertise any MTU option. + +.. index:: + single: ipv6 nd rdnss ipv6address [lifetime] + single: no ipv6 nd rdnss ipv6address [lifetime] +.. clicmd:: [no] ipv6 nd rdnss ipv6address [lifetime] + + Recursive DNS server address to advertise using the RDNSS (type 25) option + described in RFC8106. Can be specified more than once to advertise multiple + addresses. Note that hosts may choose to limit the number of RDNSS addresses + to track. + + Optional parameter: + + - ``lifetime``: the maximum time in seconds over which the specified address + may be used for domain name resolution. Value ``infinite`` represents + infinity (i.e. a value of all one bits (``0xffffffff``)). A value of 0 + indicates that the address must no longer be used. + Range: ``(0-4294967295)`` Default: ``3 * ra-interval`` + + Default: do not emit RDNSS option + +.. index:: + single: ipv6 nd dnssl domain-name-suffix [lifetime] + single: no ipv6 nd dnssl domain-name-suffix [lifetime] +.. clicmd:: [no] ipv6 nd dnssl domain-name-suffix [lifetime] + + Advertise DNS search list using the DNSSL (type 31) option described in + RFC8106. Specify more than once to advertise multiple domain name suffixes. + Host implementations may limit the number of honored search list entries. + + Optional parameter: + + - ``lifetime``: the maximum time in seconds over which the specified domain + suffix may be used in the course of name resolution. Value ``infinite`` + represents infinity (i.e. a value of all one bits (``0xffffffff``)). A + value of 0 indicates that the name suffix must no longer be used. + Range: ``(0-4294967295)`` Default: ``3 * ra-interval`` + + Default: do not emit DNSSL option + +Router Advertisement Configuration Example +========================================== +A small example: + +.. code-block:: frr + + interface eth0 + no ipv6 nd suppress-ra + ipv6 nd prefix 2001:0DB8:5009::/64 .. seealso:: @@ -191,3 +237,4 @@ Router Advertisement - :rfc:`4861` (Neighbor Discovery for IP Version 6 (IPv6)) - :rfc:`6275` (Mobility Support in IPv6) - :rfc:`4191` (Default Router Preferences and More-Specific Routes) + - :rfc:`8106` (IPv6 Router Advertisement Options for DNS Configuration) diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst index b6a7cd5de0..ad0a8639a3 100644 --- a/doc/user/ospfd.rst +++ b/doc/user/ospfd.rst @@ -218,7 +218,7 @@ To start OSPF process you have to specify the OSPF router. SPF-triggering event occurs within the hold-time of the previous SPF calculation. - This command supercedes the *timers spf* command in previous FRR + This command supersedes the *timers spf* command in previous FRR releases. .. index:: max-metric router-lsa [on-startup|on-shutdown] (5-86400) diff --git a/doc/user/pbr.rst b/doc/user/pbr.rst index 638767c557..6230bf777a 100644 --- a/doc/user/pbr.rst +++ b/doc/user/pbr.rst @@ -88,7 +88,7 @@ end destination. When a incoming packet matches the destination prefix specified, take the packet and forward according to the nexthops specified. This command accepts - both v4 and v6 prefixes. This command is used in conjuction of the + both v4 and v6 prefixes. This command is used in conjunction of the :clicmd:`match src-ip PREFIX` command for matching. .. clicmd:: set nexthop-group NAME diff --git a/doc/user/pim.rst b/doc/user/pim.rst index feb77db1e1..f4611c520b 100644 --- a/doc/user/pim.rst +++ b/doc/user/pim.rst @@ -210,8 +210,8 @@ is in a vrf, enter the interface command with the vrf keyword at the end. Set the IGMP version used on this interface. The default value is 3. -.. index:: ip multicat boundary oil WORD -.. clicmd:: ip multicat boundary oil WORD +.. index:: ip multicast boundary oil WORD +.. clicmd:: ip multicast boundary oil WORD Set a pim multicast boundary, based upon the WORD prefix-list. If a pim join or IGMP report is received on this interface and the Group is denied by the diff --git a/doc/user/setup.rst b/doc/user/setup.rst index 3a09c50309..ffefe37905 100644 --- a/doc/user/setup.rst +++ b/doc/user/setup.rst @@ -72,13 +72,14 @@ This file has several parts. Here is an example: fabricd_options=" --daemon -A 127.0.0.1" # The list of daemons to watch is automatically generated by the init script. - watchfrr_enable=yes - watchfrr_options=(-d -r /usr/sbin/servicebBfrrbBrestartbB%s -s /usr/sbin/servicebBfrrbBstartbB%s -k /usr/sbin/servicebBfrrbBstopbB%s -b bB) + #watchfrr_options="" - # If valgrind_enable is 'yes' the frr daemons will be started via valgrind. - # The use case for doing so is tracking down memory leaks, etc in frr. - valgrind_enable=no - valgrind=/usr/bin/valgrind + # for debugging purposes, you can specify a "wrap" command to start instead + # of starting the daemon directly, e.g. to use valgrind on ospfd: + # ospfd_wrap="/usr/bin/valgrind" + # or you can use "all_wrap" for all daemons, e.g. to use perf record: + # all_wrap="/usr/bin/perf record --call-graph -" + # the normal daemon command is added to this at the end. Breaking this file down: @@ -101,22 +102,8 @@ from the service script. Usually daemons will have ``--daemon`` and ``-A <address>`` specified in order to daemonize and listen for VTY commands on a particular address. -:: - - # The list of daemons to watch is automatically generated by the init script. - watchfrr_enable=yes - watchfrr_options=(-d -r /usr/sbin/servicebBfrrbBrestartbB%s -s /usr/sbin/servicebBfrrbBstartbB%s -k /usr/sbin/servicebBfrrbBstopbB%s -b bB) - -Options for the ``watchfrr``, the watchdog daemon. - -:: - - valgrind_enable=no - valgrind=/usr/bin/valgrind - -Whether or not to start FRR daemons under Valgrind. This is primarily useful -for gathering information for bug reports and for developers. -``valgrind_enable`` should be ``no`` for production use. +The remaining file content regarding `watchfrr_options` and `*_wrap` settings +should not normally be needed; refer to the comments in case they are. Services -------- diff --git a/doc/user/sharp.rst b/doc/user/sharp.rst index a78fac8fc1..4568c2a901 100644 --- a/doc/user/sharp.rst +++ b/doc/user/sharp.rst @@ -29,7 +29,7 @@ documented elsewhere. Using SHARP =========== -All sharp commands are under the enable node and preceeded by the ``sharp`` +All sharp commands are under the enable node and preceded by the ``sharp`` keyword. At present, no sharp commands will be preserved in the config. .. index:: sharp install @@ -71,10 +71,15 @@ keyword. At present, no sharp commands will be preserved in the config. be used for pop and forward operations when the specified label is seen. .. index:: sharp watch -.. clicmd:: sharp watch nexthop <A.B.C.D|X:X::X:X> +.. clicmd:: [no] sharp watch <nexthop|import> <A.B.C.D|X:X::X:X> [connected] Instruct zebra to monitor and notify sharp when the specified nexthop is changed. The notification from zebra is written into the debug log. + The nexthop or import choice chooses the type of nexthop we are asking + zebra to watch for us. This choice affects zebra's decision on what + matches. Connected tells zebra whether or not that we want the route + matched against to be a static or connected route. The no form of + the command obviously turns this watching off. .. index:: sharp data nexthop .. clicmd:: sharp data nexthop diff --git a/doc/user/vtysh.rst b/doc/user/vtysh.rst index 07109a0e54..6d569f5fb0 100644 --- a/doc/user/vtysh.rst +++ b/doc/user/vtysh.rst @@ -22,6 +22,37 @@ administrator with an external editor. have effect for vtysh) need to be manually updated in :file:`vtysh.conf`. +Pager usage +=========== + +*vtysh* can call an external paging program (e.g. *more* or *less*) to +paginate long output from commands. This feature used to be enabled by +default but is now controlled by the ``VTYSH_PAGER`` environment variable +and the :clicmd:`terminal paginate` command: + +.. envvar:: VTYSH_PAGER + + If set, the ``VTYSH_PAGER`` environment variable causes *vtysh* to pipe + output from commands through the given command. Note that this happens + regardless of the length of the output. As such, standard pager behavior + (particularly waiting at the end of output) tends to be annoying to the + user. Using ``less -EFX`` is recommended for a better user experience. + + If this environment variable is unset, *vtysh* defaults to not using any + pager. + + This variable should be set by the user according to their preferences, + in their :file:`~/.profile` file. + +.. index:: [no] terminal paginate +.. clicmd:: [no] terminal paginate + + Enables/disables vtysh output pagination. This command is intended to + be placed in :file:`vtysh.conf` to set a system-wide default. If this + is enabled but ``VTYSH_PAGER`` is not set, the system default pager + (likely ``more`` or ``/usr/bin/pager``) will be used. + + Permissions and setup requirements ================================== diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index 9dfe1ea39c..a7bf0c74da 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -380,7 +380,7 @@ At startup, FRR detects the presence of that file. It detects that the file statistics information matches the same file statistics information as `/proc/self/ns/net` ( through stat() function). As statistics information matches, then `vrf0` stands for the new default namespace name. -Consequently, the VRF naming `Default` will be overriden by the new discovered +Consequently, the VRF naming `Default` will be overridden by the new discovered namespace name `vrf0`. For those who don't use VRF backend with *Linux network namespace*, it is @@ -422,7 +422,7 @@ in routing entry, and can be configured like a route: .. index:: [no] ip route NETWORK MASK GATEWAY|INTERFACE label LABEL .. clicmd:: [no] ip route NETWORK MASK GATEWAY|INTERFACE label LABEL - NETWORK ans MASK stand for the IP prefix entry to be added as static + NETWORK and MASK stand for the IP prefix entry to be added as static route entry. GATEWAY is the gateway IP address to reach, in order to reach the prefix. INTERFACE is the interface behind which the prefix is located. diff --git a/docker/debian/Dockerfile b/docker/debian/Dockerfile new file mode 100644 index 0000000000..4f192ec33e --- /dev/null +++ b/docker/debian/Dockerfile @@ -0,0 +1,10 @@ +FROM debian:stretch +MAINTAINER Rob Gil (rob@rem5.com) +RUN apt-get update +RUN apt-get install -y libpcre3-dev apt-transport-https ca-certificates curl wget logrotate \ + libc-ares2 libjson-c3 vim systemd procps +RUN curl -sLO https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-1/Debian-9-x86_64-Packages/libyang_0.16.46_amd64.deb && dpkg -i libyang_0.16.46_amd64.deb +RUN curl -sLO https://github.com/FRRouting/frr/releases/download/frr-6.0.2/frr_6.0.2-0.deb9u1_amd64.deb && dpkg -i frr_6.0.2-0.deb9u1_amd64.deb +ADD daemons /etc/frr/daemons +ADD docker-start /usr/sbin/docker-start +ENTRYPOINT ["/usr/sbin/docker-start"] diff --git a/docker/debian/README.md b/docker/debian/README.md new file mode 100644 index 0000000000..b10d696a78 --- /dev/null +++ b/docker/debian/README.md @@ -0,0 +1,17 @@ +# Debian9 Docker +This is a binary docker container build of debian9. + +# Build +``` +docker build --rm -t frr:6.0.2 . +``` + +# Running +``` +docker run -itd --privileged --name frr frr:latest +``` + +vtysh +``` +docker exec -it frr vtysh +``` diff --git a/docker/debian/daemons b/docker/debian/daemons new file mode 100644 index 0000000000..ed4d98e1f8 --- /dev/null +++ b/docker/debian/daemons @@ -0,0 +1,65 @@ +# This file tells the frr package which daemons to start. +# +# Sample configurations for these daemons can be found in +# /usr/share/doc/frr/examples/. +# +# ATTENTION: +# +# When activation a daemon at the first time, a config file, even if it is +# empty, has to be present *and* be owned by the user and group "frr", else +# the daemon will not be started by /etc/init.d/frr. The permissions should +# be u=rw,g=r,o=. +# When using "vtysh" such a config file is also needed. It should be owned by +# group "frrvty" and set to ug=rw,o= though. Check /etc/pam.d/frr, too. +# +# The watchfrr and zebra daemons are always started. +# +bgpd=yes +ospfd=no +ospf6d=no +ripd=no +ripngd=no +isisd=no +pimd=no +ldpd=no +nhrpd=no +eigrpd=no +babeld=no +sharpd=no +pbrd=no +bfdd=no +fabricd=no + +# +# If this option is set the /etc/init.d/frr script automatically loads +# the config via "vtysh -b" when the servers are started. +# Check /etc/pam.d/frr if you intend to use "vtysh"! +# +vtysh_enable=yes +zebra_options=" -A 127.0.0.1 -s 90000000" +bgpd_options=" -A 127.0.0.1" +ospfd_options=" -A 127.0.0.1" +ospf6d_options=" -A ::1" +ripd_options=" -A 127.0.0.1" +ripngd_options=" -A ::1" +isisd_options=" -A 127.0.0.1" +pimd_options=" -A 127.0.0.1" +ldpd_options=" -A 127.0.0.1" +nhrpd_options=" -A 127.0.0.1" +eigrpd_options=" -A 127.0.0.1" +babeld_options=" -A 127.0.0.1" +sharpd_options=" -A 127.0.0.1" +pbrd_options=" -A 127.0.0.1" +staticd_options="-A 127.0.0.1" +bfdd_options=" -A 127.0.0.1" +fabricd_options="-A 127.0.0.1" + +# The list of daemons to watch is automatically generated by the init script. +watchfrr_options="-r '/usr/lib/frr/watchfrr.sh restart %s' -s '/usr/lib/frr/watchfrr.sh start %s' -k '/usr/lib/frr/watchfrr.sh stop %s'" + +# for debugging purposes, you can specify a "wrap" command to start instead +# of starting the daemon directly, e.g. to use valgrind on ospfd: +# ospfd_wrap="/usr/bin/valgrind" +# or you can use "all_wrap" for all daemons, e.g. to use perf record: +# all_wrap="/usr/bin/perf record --call-graph -" +# the normal daemon command is added to this at the end. diff --git a/docker/debian/docker-start b/docker/debian/docker-start new file mode 100755 index 0000000000..43854ab142 --- /dev/null +++ b/docker/debian/docker-start @@ -0,0 +1,10 @@ +#!/bin/sh + +set -e + +## +# For volume mounts... +## +chown -R frr:frr /etc/frr +/etc/init.d/frr start +exec sleep 10000d diff --git a/eigrpd/eigrp_dump.c b/eigrpd/eigrp_dump.c index 6033290914..583db6622d 100644 --- a/eigrpd/eigrp_dump.c +++ b/eigrpd/eigrp_dump.c @@ -174,7 +174,7 @@ const char *eigrp_if_ip_string(struct eigrp_interface *ei) if (!ei) return "inactive"; - ifaddr = ntohl(ei->address->u.prefix4.s_addr); + ifaddr = ntohl(ei->address.u.prefix4.s_addr); snprintf(buf, EIGRP_IF_STRING_MAXLEN, "%u.%u.%u.%u", (ifaddr >> 24) & 0xff, (ifaddr >> 16) & 0xff, (ifaddr >> 8) & 0xff, ifaddr & 0xff); diff --git a/eigrpd/eigrp_fsm.c b/eigrpd/eigrp_fsm.c index 374114cf55..4d6d73e202 100644 --- a/eigrpd/eigrp_fsm.c +++ b/eigrpd/eigrp_fsm.c @@ -231,7 +231,7 @@ static const char *fsm_state2str(enum eigrp_fsm_events event) return "Query from Successor while in active state"; case EIGRP_FSM_EVENT_LR_FCN: return "Last Reply Event, Feasibility not satisfied"; - }; + } return "Unknown"; } @@ -314,7 +314,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) if (prefix->rij->count) return EIGRP_FSM_KEEP_STATE; - zlog_info("All reply received\n"); + zlog_info("All reply received"); if (head->reported_distance < prefix->fdistance) { return EIGRP_FSM_EVENT_LR_FCS; } @@ -344,7 +344,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) } else if (prefix->rij->count) { return EIGRP_FSM_KEEP_STATE; } else { - zlog_info("All reply received\n"); + zlog_info("All reply received"); return EIGRP_FSM_EVENT_LR; } } else if (msg->packet_type == EIGRP_OPC_UPDATE @@ -366,7 +366,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) if (prefix->rij->count) { return EIGRP_FSM_KEEP_STATE; } else { - zlog_info("All reply received\n"); + zlog_info("All reply received"); if (head->reported_distance < prefix->fdistance) { return EIGRP_FSM_EVENT_LR_FCS; @@ -390,7 +390,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) } else if (prefix->rij->count) { return EIGRP_FSM_KEEP_STATE; } else { - zlog_info("All reply received\n"); + zlog_info("All reply received"); return EIGRP_FSM_EVENT_LR; } } else if (msg->packet_type == EIGRP_OPC_UPDATE diff --git a/eigrpd/eigrp_hello.c b/eigrpd/eigrp_hello.c index 413a35f2fa..dacd5caeb5 100644 --- a/eigrpd/eigrp_hello.c +++ b/eigrpd/eigrp_hello.c @@ -248,7 +248,7 @@ static void eigrp_peer_termination_decode(struct eigrp_neighbor *nbr, struct TLV_Peer_Termination_type *param = (struct TLV_Peer_Termination_type *)tlv; - uint32_t my_ip = nbr->ei->address->u.prefix4.s_addr; + uint32_t my_ip = nbr->ei->address.u.prefix4.s_addr; uint32_t received_ip = param->neighbor_ip; if (my_ip == received_ip) { @@ -577,8 +577,6 @@ static uint16_t eigrp_next_sequence_encode(struct stream *s) static uint16_t eigrp_hello_parameter_encode(struct eigrp_interface *ei, struct stream *s, uint8_t flags) { - uint16_t length = EIGRP_TLV_PARAMETER_LEN; - // add in the parameters TLV stream_putw(s, EIGRP_TLV_PARAMETER); stream_putw(s, EIGRP_TLV_PARAMETER_LEN); @@ -605,7 +603,7 @@ static uint16_t eigrp_hello_parameter_encode(struct eigrp_interface *ei, // and set hold time value.. stream_putw(s, ei->params.v_wait); - return length; + return EIGRP_TLV_PARAMETER_LEN; } /** diff --git a/eigrpd/eigrp_interface.c b/eigrpd/eigrp_interface.c index 4ad1005f2f..c52a98ee25 100644 --- a/eigrpd/eigrp_interface.c +++ b/eigrpd/eigrp_interface.c @@ -68,7 +68,7 @@ struct eigrp_interface *eigrp_if_new(struct eigrp *eigrp, struct interface *ifp, /* Set zebra interface pointer. */ ei->ifp = ifp; - ei->address = p; + prefix_copy(&ei->address, p); ifp->info = ei; listnode_add(eigrp->eiflist, ei); @@ -185,7 +185,7 @@ int eigrp_if_up(struct eigrp_interface *ei) struct prefix dest_addr; - dest_addr = *ei->address; + dest_addr = ei->address; apply_mask(&dest_addr); pe = eigrp_topology_table_lookup_ipv4(eigrp->topology_table, &dest_addr); @@ -292,7 +292,7 @@ void eigrp_if_set_multicast(struct eigrp_interface *ei) /* The interface should belong to the EIGRP-all-routers group. */ if (!ei->member_allrouters - && (eigrp_if_add_allspfrouters(ei->eigrp, ei->address, + && (eigrp_if_add_allspfrouters(ei->eigrp, &ei->address, ei->ifp->ifindex) >= 0)) /* Set the flag only if the system call to join @@ -303,7 +303,7 @@ void eigrp_if_set_multicast(struct eigrp_interface *ei) * group. */ if (ei->member_allrouters) { /* Only actually drop if this is the last reference */ - eigrp_if_drop_allspfrouters(ei->eigrp, ei->address, + eigrp_if_drop_allspfrouters(ei->eigrp, &ei->address, ei->ifp->ifindex); /* Unset the flag regardless of whether the system call to leave @@ -339,7 +339,7 @@ void eigrp_if_free(struct eigrp_interface *ei, int source) eigrp_hello_send(ei, EIGRP_HELLO_GRACEFUL_SHUTDOWN, NULL); } - dest_addr = *ei->address; + dest_addr = ei->address; apply_mask(&dest_addr); pe = eigrp_topology_table_lookup_ipv4(eigrp->topology_table, &dest_addr); @@ -375,7 +375,7 @@ struct eigrp_interface *eigrp_if_lookup_by_local_addr(struct eigrp *eigrp, if (ifp && ei->ifp != ifp) continue; - if (IPV4_ADDR_SAME(&address, &ei->address->u.prefix4)) + if (IPV4_ADDR_SAME(&address, &ei->address.u.prefix4)) return ei; } diff --git a/eigrpd/eigrp_main.c b/eigrpd/eigrp_main.c index b19b383e65..3db59a838b 100644 --- a/eigrpd/eigrp_main.c +++ b/eigrpd/eigrp_main.c @@ -211,10 +211,7 @@ int main(int argc, char **argv, char **envp) /*eigrp_route_map_init(); route_map_add_hook (eigrp_rmap_update); route_map_delete_hook (eigrp_rmap_update);*/ - /*if_rmap_init (EIGRP_NODE); - if_rmap_hook_add (eigrp_if_rmap_update); - if_rmap_hook_delete (eigrp_if_rmap_update);*/ - + /*if_rmap_init (EIGRP_NODE); */ /* Distribute list install. */ distribute_list_init(EIGRP_NODE); diff --git a/eigrpd/eigrp_network.c b/eigrpd/eigrp_network.c index 6bb619f0e1..76f8cfc93b 100644 --- a/eigrpd/eigrp_network.c +++ b/eigrpd/eigrp_network.c @@ -293,7 +293,7 @@ void eigrp_if_update(struct interface *ifp) */ for (ALL_LIST_ELEMENTS(eigrp_om->eigrp, node, nnode, eigrp)) { /* EIGRP must be on and Router-ID must be configured. */ - if (!eigrp || eigrp->router_id.s_addr == 0) + if (eigrp->router_id.s_addr == 0) continue; /* Run each network for this interface. */ @@ -333,7 +333,7 @@ int eigrp_network_unset(struct eigrp *eigrp, struct prefix *p) if (rn->info == NULL) continue; - if (eigrp_network_match_iface(ei->address, &rn->p)) { + if (eigrp_network_match_iface(&ei->address, &rn->p)) { found = true; route_unlock_node(rn); break; diff --git a/eigrpd/eigrp_packet.c b/eigrpd/eigrp_packet.c index ee0476b28d..bedaf15c47 100644 --- a/eigrpd/eigrp_packet.c +++ b/eigrpd/eigrp_packet.c @@ -281,7 +281,7 @@ int eigrp_make_sha256_digest(struct eigrp_interface *ei, struct stream *s, return 0; } - inet_ntop(AF_INET, &ei->address->u.prefix4, source_ip, PREFIX_STRLEN); + inet_ntop(AF_INET, &ei->address.u.prefix4, source_ip, PREFIX_STRLEN); memset(&ctx, 0, sizeof(ctx)); buffer[0] = '\n'; @@ -362,7 +362,7 @@ int eigrp_write(struct thread *thread) } if (ep->dst.s_addr == htonl(EIGRP_MULTICAST_ADDRESS)) - eigrp_if_ipmulticast(eigrp, ei->address, ei->ifp->ifindex); + eigrp_if_ipmulticast(eigrp, &ei->address, ei->ifp->ifindex); memset(&iph, 0, sizeof(struct ip)); memset(&sa_dst, 0, sizeof(sa_dst)); @@ -418,7 +418,7 @@ int eigrp_write(struct thread *thread) iph.ip_ttl = EIGRP_IP_TTL; iph.ip_p = IPPROTO_EIGRPIGP; iph.ip_sum = 0; - iph.ip_src.s_addr = ei->address->u.prefix4.s_addr; + iph.ip_src.s_addr = ei->address.u.prefix4.s_addr; iph.ip_dst.s_addr = ep->dst.s_addr; memset(&msg, 0, sizeof(msg)); @@ -547,7 +547,7 @@ int eigrp_read(struct thread *thread) /* Self-originated packet should be discarded silently. */ if (eigrp_if_lookup_by_local_addr(eigrp, NULL, iph->ip_src) - || (IPV4_ADDR_SAME(&iph->ip_src, &ei->address->u.prefix4))) { + || (IPV4_ADDR_SAME(&iph->ip_src, &ei->address.u.prefix4))) { if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV)) zlog_debug( "eigrp_read[%s]: Dropping self-originated packet", @@ -581,7 +581,7 @@ int eigrp_read(struct thread *thread) sizeof(buf[0])), inet_ntop(AF_INET, &iph->ip_dst, buf[1], sizeof(buf[1])), - inet_ntop(AF_INET, &ei->address->u.prefix4, + inet_ntop(AF_INET, &ei->address.u.prefix4, buf[2], sizeof(buf[2]))); if (iph->ip_dst.s_addr == htonl(EIGRP_MULTICAST_ADDRESS)) { @@ -981,9 +981,9 @@ static int eigrp_check_network_mask(struct eigrp_interface *ei, if (ei->type == EIGRP_IFTYPE_POINTOPOINT) return 1; - masklen2ip(ei->address->prefixlen, &mask); + masklen2ip(ei->address.prefixlen, &mask); - me.s_addr = ei->address->u.prefix4.s_addr & mask.s_addr; + me.s_addr = ei->address.u.prefix4.s_addr & mask.s_addr; him.s_addr = ip_src.s_addr & mask.s_addr; if (IPV4_ADDR_SAME(&me, &him)) diff --git a/eigrpd/eigrp_structs.h b/eigrpd/eigrp_structs.h index 644ab0829f..a78e5a53cf 100644 --- a/eigrpd/eigrp_structs.h +++ b/eigrpd/eigrp_structs.h @@ -180,7 +180,7 @@ struct eigrp_interface { /* EIGRP Network Type. */ uint8_t type; - struct prefix *address; /* Interface prefix */ + struct prefix address; /* Interface prefix */ /* Neighbor information. */ struct list *nbrs; /* EIGRP Neighbor List */ diff --git a/eigrpd/eigrp_topology.c b/eigrpd/eigrp_topology.c index 23f5a705eb..e861cdb333 100644 --- a/eigrpd/eigrp_topology.c +++ b/eigrpd/eigrp_topology.c @@ -141,10 +141,10 @@ void eigrp_prefix_entry_add(struct route_table *topology, __PRETTY_FUNCTION__, prefix2str(pe->destination, buf, sizeof(buf))); } + route_unlock_node(rn); } rn->info = pe; - route_lock_node(rn); } /* diff --git a/eigrpd/eigrp_vty.c b/eigrpd/eigrp_vty.c index 104f35244e..fc5bdbdbc5 100644 --- a/eigrpd/eigrp_vty.c +++ b/eigrpd/eigrp_vty.c @@ -559,6 +559,7 @@ DEFPY (show_ip_eigrp_topology, tn = rn->info; eigrp_vty_display_prefix_entry(vty, eigrp, tn, argc == 5); + route_unlock_node(rn); return CMD_SUCCESS; } @@ -1498,8 +1499,6 @@ static int eigrp_config_write(struct vty *vty) { struct eigrp *eigrp; - int write = 0; - eigrp = eigrp_lookup(); if (eigrp != NULL) { /* Writes 'router eigrp' section to config */ @@ -1524,7 +1523,7 @@ static int eigrp_config_write(struct vty *vty) // config_write_eigrp_distance (vty, eigrp) } - return write; + return 0; } void eigrp_vty_show_init(void) diff --git a/eigrpd/eigrp_zebra.c b/eigrpd/eigrp_zebra.c index 09d876afaa..dc1ae675b0 100644 --- a/eigrpd/eigrp_zebra.c +++ b/eigrpd/eigrp_zebra.c @@ -258,7 +258,8 @@ static int eigrp_interface_address_delete(int command, struct zclient *zclient, return 0; /* Call interface hook functions to clean up */ - eigrp_if_free(ei, INTERFACE_DOWN_BY_ZEBRA); + if (prefix_cmp(&ei->address, c->address) == 0) + eigrp_if_free(ei, INTERFACE_DOWN_BY_ZEBRA); connected_free(c); diff --git a/eigrpd/eigrpd.c b/eigrpd/eigrpd.c index 69d947e59f..93f8b6f90e 100644 --- a/eigrpd/eigrpd.c +++ b/eigrpd/eigrpd.c @@ -206,6 +206,13 @@ static struct eigrp *eigrp_new(const char *AS) eigrp_distribute_update); distribute_list_delete_hook(eigrp->distribute_ctx, eigrp_distribute_update); + + /* + eigrp->if_rmap_ctx = if_rmap_ctx_create( + VRF_DEFAULT_NAME); + if_rmap_hook_add (eigrp_if_rmap_update); + if_rmap_hook_delete (eigrp_if_rmap_update); + */ QOBJ_REG(eigrp, eigrp); return eigrp; } diff --git a/isisd/dict.c b/isisd/dict.c index 5d3e61e6d6..d91f05d254 100644 --- a/isisd/dict.c +++ b/isisd/dict.c @@ -1095,10 +1095,10 @@ void dict_load_end(dict_load_t *load) baselevel = level = 1; complete = tree[0]; - if (complete != 0) { + if (complete != NULL) { tree[0] = 0; complete->right = dictnil; - while (tree[level] != 0) { + while (tree[level] != NULL) { tree[level]->right = complete; complete->parent = tree[level]; complete = tree[level]; @@ -1114,7 +1114,7 @@ void dict_load_end(dict_load_t *load) complete = curr; assert(level == baselevel); - while (tree[level] != 0) { + while (tree[level] != NULL) { tree[level]->right = complete; complete->parent = tree[level]; complete = tree[level]; @@ -1134,7 +1134,7 @@ void dict_load_end(dict_load_t *load) complete = dictnil; for (i = 0; i < DICT_DEPTH_MAX; i++) { - if (tree[i] != 0) { + if (tree[i] != NULL) { tree[i]->right = complete; complete->parent = tree[i]; complete = tree[i]; diff --git a/isisd/fabricd.c b/isisd/fabricd.c index e8b729c779..96af28f0a1 100644 --- a/isisd/fabricd.c +++ b/isisd/fabricd.c @@ -559,18 +559,18 @@ static void move_to_queue(struct isis_lsp *lsp, struct neighbor_entry *n, listnode_add(lsp->flooding_neighbors[type], neighbor_id); } -static void mark_neighbor_as_present(struct hash_backet *backet, void *arg) +static void mark_neighbor_as_present(struct hash_bucket *bucket, void *arg) { - struct neighbor_entry *n = backet->data; + struct neighbor_entry *n = bucket->data; n->present = true; } -static void handle_firsthops(struct hash_backet *backet, void *arg) +static void handle_firsthops(struct hash_bucket *bucket, void *arg) { struct isis_lsp *lsp = arg; struct fabricd *f = lsp->area->fabricd; - struct isis_vertex *vertex = backet->data; + struct isis_vertex *vertex = bucket->data; struct neighbor_entry *n; diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index e1cdfc30ea..62814329ea 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -140,12 +140,9 @@ void isis_delete_adj(void *arg) /* remove from SPF trees */ spftree_area_adj_del(adj->circuit->area, adj); - if (adj->area_addresses) - XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->area_addresses); - if (adj->ipv4_addresses) - XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->ipv4_addresses); - if (adj->ipv6_addresses) - XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->ipv6_addresses); + XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->area_addresses); + XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->ipv4_addresses); + XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->ipv6_addresses); adj_mt_finish(adj); diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 36d4a0d7c0..8377638b92 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -1305,8 +1305,8 @@ ferr_r isis_circuit_passwd_unset(struct isis_circuit *circuit) return ferr_ok(); } -static int isis_circuit_passwd_set(struct isis_circuit *circuit, - uint8_t passwd_type, const char *passwd) +ferr_r isis_circuit_passwd_set(struct isis_circuit *circuit, + uint8_t passwd_type, const char *passwd) { int len; @@ -1319,7 +1319,8 @@ static int isis_circuit_passwd_set(struct isis_circuit *circuit, "circuit password too long (max 254 chars)"); circuit->passwd.len = len; - strncpy((char *)circuit->passwd.passwd, passwd, 255); + strlcpy((char *)circuit->passwd.passwd, passwd, + sizeof(circuit->passwd.passwd)); circuit->passwd.type = passwd_type; return ferr_ok(); } diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h index 73ead8f7da..e0ea4f78b4 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -190,6 +190,8 @@ ferr_r isis_circuit_metric_set(struct isis_circuit *circuit, int level, int metric); ferr_r isis_circuit_passwd_unset(struct isis_circuit *circuit); +ferr_r isis_circuit_passwd_set(struct isis_circuit *circuit, + uint8_t passwd_type, const char *passwd); ferr_r isis_circuit_passwd_cleartext_set(struct isis_circuit *circuit, const char *passwd); ferr_r isis_circuit_passwd_hmac_md5_set(struct isis_circuit *circuit, diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c index c68f49f92d..ab5faf76b6 100644 --- a/isisd/isis_cli.c +++ b/isisd/isis_cli.c @@ -89,7 +89,7 @@ DEFPY(no_router_isis, no_router_isis_cmd, "no router isis WORD$tag", return CMD_ERR_NOTHING_TODO; } - nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); area = isis_area_lookup(tag); if (area && area->circuit_list && listcount(area->circuit_list)) { for (ALL_LIST_ELEMENTS(area->circuit_list, node, nnode, @@ -103,7 +103,7 @@ DEFPY(no_router_isis, no_router_isis_cmd, "no router isis WORD$tag", temp_xpath, XPATH_MAXLEN, "/frr-interface:lib/interface[name='%s'][vrf='%s']/frr-isisd:isis", circuit->interface->name, vrf_name); - nb_cli_enqueue_change(vty, temp_xpath, NB_OP_DELETE, + nb_cli_enqueue_change(vty, temp_xpath, NB_OP_DESTROY, NULL); } } @@ -279,27 +279,28 @@ DEFPY(no_ip_router_isis, no_ip_router_isis_cmd, "IS-IS routing protocol\n" "Routing process tag\n") { - const struct lyd_node *dnode = - yang_dnode_get(running_config->dnode, VTY_CURR_XPATH); + const struct lyd_node *dnode; - /* if both ipv4 and ipv6 are off delete the interface isis container too + dnode = yang_dnode_get(vty->candidate_config->dnode, + "%s/frr-isisd:isis", VTY_CURR_XPATH); + if (!dnode) + return CMD_SUCCESS; + + /* + * If both ipv4 and ipv6 are off delete the interface isis container. */ - if (!strncmp(ip, "ipv6", strlen("ipv6"))) { - if (dnode - && !yang_dnode_get_bool(dnode, - "./frr-isisd:isis/ipv4-routing")) + if (strmatch(ip, "ipv6")) { + if (!yang_dnode_get_bool(dnode, "./ipv4-routing")) nb_cli_enqueue_change(vty, "./frr-isisd:isis", - NB_OP_DELETE, NULL); + NB_OP_DESTROY, NULL); else nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv6-routing", NB_OP_MODIFY, "false"); - } else { /* no ipv4 */ - if (dnode - && !yang_dnode_get_bool(dnode, - "./frr-isisd:isis/ipv6-routing")) + } else { + if (!yang_dnode_get_bool(dnode, "./ipv6-routing")) nb_cli_enqueue_change(vty, "./frr-isisd:isis", - NB_OP_DELETE, NULL); + NB_OP_DESTROY, NULL); else nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv4-routing", @@ -336,7 +337,7 @@ DEFPY(net, net_cmd, "[no] net WORD", "XX.XXXX. ... .XXX.XX Network entity title (NET)\n") { nb_cli_enqueue_change(vty, "./area-address", - no ? NB_OP_DELETE : NB_OP_CREATE, net); + no ? NB_OP_DESTROY : NB_OP_CREATE, net); return nb_cli_apply_changes(vty, NULL); } @@ -589,7 +590,7 @@ DEFPY(no_area_passwd, no_area_passwd_cmd, "Configure the authentication password for an area\n" "Set the authentication password for a routing domain\n") { - nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, "./%s", cmd); } @@ -892,7 +893,7 @@ DEFPY(no_spf_delay_ietf, no_spf_delay_ietf_cmd, "Maximum duration needed to learn all the events related to a single failure\n" "Maximum duration needed to learn all the events related to a single failure (in milliseconds)\n") { - nb_cli_enqueue_change(vty, "./spf/ietf-backoff-delay", NB_OP_DELETE, + nb_cli_enqueue_change(vty, "./spf/ietf-backoff-delay", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); @@ -947,7 +948,7 @@ DEFPY(no_isis_mpls_te_on, no_isis_mpls_te_on_cmd, "no mpls-te [on]", "Disable the MPLS-TE functionality\n" "Enable the MPLS-TE functionality\n") { - nb_cli_enqueue_change(vty, "/frr-isisd:isis/mpls-te", NB_OP_DELETE, + nb_cli_enqueue_change(vty, "/frr-isisd:isis/mpls-te", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); @@ -1014,16 +1015,16 @@ DEFPY(isis_default_originate, isis_default_originate_cmd, "Pointer to route-map entries\n") { if (no) - nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); else { nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); nb_cli_enqueue_change(vty, "./always", NB_OP_MODIFY, always ? "true" : "false"); nb_cli_enqueue_change(vty, "./route-map", - rmap ? NB_OP_MODIFY : NB_OP_DELETE, + rmap ? NB_OP_MODIFY : NB_OP_DESTROY, rmap ? rmap : NULL); nb_cli_enqueue_change(vty, "./metric", - metric ? NB_OP_MODIFY : NB_OP_DELETE, + metric ? NB_OP_MODIFY : NB_OP_DESTROY, metric ? metric_str : NULL); if (strmatch(ip, "ipv6") && !always) { vty_out(vty, @@ -1094,14 +1095,14 @@ DEFPY(isis_redistribute, isis_redistribute_cmd, "Pointer to route-map entries\n") { if (no) - nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); else { nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); nb_cli_enqueue_change(vty, "./route-map", - route_map ? NB_OP_MODIFY : NB_OP_DELETE, + route_map ? NB_OP_MODIFY : NB_OP_DESTROY, route_map ? route_map : NULL); nb_cli_enqueue_change(vty, "./metric", - metric ? NB_OP_MODIFY : NB_OP_DELETE, + metric ? NB_OP_MODIFY : NB_OP_DESTROY, metric ? metric_str : NULL); } @@ -1182,7 +1183,7 @@ DEFPY(isis_topology, isis_topology_cmd, topology); if (no) - nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); else { nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); nb_cli_enqueue_change(vty, "./overload", NB_OP_MODIFY, @@ -1297,7 +1298,7 @@ DEFPY(no_isis_passwd, no_isis_passwd_cmd, "no isis password [<md5|clear> WORD]", "Cleartext password\n" "Circuit password\n") { - nb_cli_enqueue_change(vty, "./frr-isisd:isis/password", NB_OP_DELETE, + nb_cli_enqueue_change(vty, "./frr-isisd:isis/password", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); diff --git a/isisd/isis_dlpi.c b/isisd/isis_dlpi.c index 54a19ad239..148b438661 100644 --- a/isisd/isis_dlpi.c +++ b/isisd/isis_dlpi.c @@ -444,7 +444,7 @@ static int open_dlpi_dev(struct isis_circuit *circuit) struct strioctl sioc; pfil.Pf_Priority = 0; - pfil.Pf_FilterLen = sizeof(pf_filter) / sizeof(unsigned short); + pfil.Pf_FilterLen = array_size(pf_filter); memcpy(pfil.Pf_Filter, pf_filter, sizeof(pf_filter)); /* pfmod does not support transparent ioctls */ sioc.ic_cmd = PFIOCSETF; diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 658624370b..b56a56fa3f 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -1930,6 +1930,27 @@ int lsp_tick(struct thread *thread) area->area_tag, lsp->level, rawlspid_print(lsp->hdr.lsp_id), lsp->hdr.seqno); + + /* if we're aging out fragment 0, + * lsp_destroy() below will delete all + * other fragments too, so we need to + * skip over those + */ + while (!LSP_FRAGMENT(lsp->hdr.lsp_id) + && dnode_next) { + struct isis_lsp *nextlsp; + + nextlsp = dnode_get(dnode_next); + if (memcmp(nextlsp->hdr.lsp_id, + lsp->hdr.lsp_id, + ISIS_SYS_ID_LEN + 1)) + break; + + dnode_next = dict_next( + area->lspdb[level], + dnode_next); + } + lsp_destroy(lsp); lsp = NULL; dict_delete_free(area->lspdb[level], diff --git a/isisd/isis_main.c b/isisd/isis_main.c index 9126e40d42..e74a9baadd 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -80,7 +80,7 @@ struct zebra_privs_t isisd_privs = { .vty_group = VTY_GROUP, #endif .caps_p = _caps_p, - .cap_num_p = sizeof(_caps_p) / sizeof(*_caps_p), + .cap_num_p = array_size(_caps_p), .cap_num_i = 0}; /* isisd options */ diff --git a/isisd/isis_northbound.c b/isisd/isis_northbound.c index 9c2bb1728e..2d1d6f5927 100644 --- a/isisd/isis_northbound.c +++ b/isisd/isis_northbound.c @@ -72,7 +72,7 @@ static int isis_instance_create(enum nb_event event, return NB_OK; } -static int isis_instance_delete(enum nb_event event, +static int isis_instance_destroy(enum nb_event event, const struct lyd_node *dnode) { const char *area_tag; @@ -193,7 +193,7 @@ static int isis_instance_area_address_create(enum nb_event event, return NB_OK; } -static int isis_instance_area_address_delete(enum nb_event event, +static int isis_instance_area_address_destroy(enum nb_event event, const struct lyd_node *dnode) { struct area_addr addr, *addrp = NULL; @@ -536,7 +536,7 @@ isis_instance_spf_ietf_backoff_delay_create(enum nb_event event, } static int -isis_instance_spf_ietf_backoff_delay_delete(enum nb_event event, +isis_instance_spf_ietf_backoff_delay_destroy(enum nb_event event, const struct lyd_node *dnode) { struct isis_area *area; @@ -676,7 +676,7 @@ static int isis_instance_area_password_create(enum nb_event event, return NB_OK; } -static int isis_instance_area_password_delete(enum nb_event event, +static int isis_instance_area_password_destroy(enum nb_event event, const struct lyd_node *dnode) { struct isis_area *area; @@ -755,7 +755,7 @@ static int isis_instance_domain_password_create(enum nb_event event, return NB_OK; } -static int isis_instance_domain_password_delete(enum nb_event event, +static int isis_instance_domain_password_destroy(enum nb_event event, const struct lyd_node *dnode) { struct isis_area *area; @@ -851,7 +851,7 @@ static int isis_instance_default_information_originate_ipv4_create( return NB_OK; } -static int isis_instance_default_information_originate_ipv4_delete( +static int isis_instance_default_information_originate_ipv4_destroy( enum nb_event event, const struct lyd_node *dnode) { struct isis_area *area; @@ -889,7 +889,7 @@ static int isis_instance_default_information_originate_ipv4_route_map_modify( return NB_OK; } -static int isis_instance_default_information_originate_ipv4_route_map_delete( +static int isis_instance_default_information_originate_ipv4_route_map_destroy( enum nb_event event, const struct lyd_node *dnode) { /* It's all done by default_info_origin_apply_finish */ @@ -907,7 +907,7 @@ static int isis_instance_default_information_originate_ipv4_metric_modify( return NB_OK; } -static int isis_instance_default_information_originate_ipv4_metric_delete( +static int isis_instance_default_information_originate_ipv4_metric_destroy( enum nb_event event, const struct lyd_node *dnode) { /* It's all done by default_info_origin_apply_finish */ @@ -925,7 +925,7 @@ static int isis_instance_default_information_originate_ipv6_create( return NB_OK; } -static int isis_instance_default_information_originate_ipv6_delete( +static int isis_instance_default_information_originate_ipv6_destroy( enum nb_event event, const struct lyd_node *dnode) { struct isis_area *area; @@ -963,7 +963,7 @@ static int isis_instance_default_information_originate_ipv6_route_map_modify( return NB_OK; } -static int isis_instance_default_information_originate_ipv6_route_map_delete( +static int isis_instance_default_information_originate_ipv6_route_map_destroy( enum nb_event event, const struct lyd_node *dnode) { /* It's all done by default_info_origin_apply_finish */ @@ -981,7 +981,7 @@ static int isis_instance_default_information_originate_ipv6_metric_modify( return NB_OK; } -static int isis_instance_default_information_originate_ipv6_metric_delete( +static int isis_instance_default_information_originate_ipv6_metric_destroy( enum nb_event event, const struct lyd_node *dnode) { /* It's all done by default_info_origin_apply_finish */ @@ -1029,7 +1029,7 @@ static int isis_instance_redistribute_ipv4_create(enum nb_event event, return NB_OK; } -static int isis_instance_redistribute_ipv4_delete(enum nb_event event, +static int isis_instance_redistribute_ipv4_destroy(enum nb_event event, const struct lyd_node *dnode) { struct isis_area *area; @@ -1059,7 +1059,7 @@ isis_instance_redistribute_ipv4_route_map_modify(enum nb_event event, } static int -isis_instance_redistribute_ipv4_route_map_delete(enum nb_event event, +isis_instance_redistribute_ipv4_route_map_destroy(enum nb_event event, const struct lyd_node *dnode) { /* It's all done by redistribute_apply_finish */ @@ -1079,7 +1079,7 @@ isis_instance_redistribute_ipv4_metric_modify(enum nb_event event, } static int -isis_instance_redistribute_ipv4_metric_delete(enum nb_event event, +isis_instance_redistribute_ipv4_metric_destroy(enum nb_event event, const struct lyd_node *dnode) { /* It's all done by redistribute_apply_finish */ @@ -1097,7 +1097,7 @@ static int isis_instance_redistribute_ipv6_create(enum nb_event event, return NB_OK; } -static int isis_instance_redistribute_ipv6_delete(enum nb_event event, +static int isis_instance_redistribute_ipv6_destroy(enum nb_event event, const struct lyd_node *dnode) { struct isis_area *area; @@ -1127,7 +1127,7 @@ isis_instance_redistribute_ipv6_route_map_modify(enum nb_event event, } static int -isis_instance_redistribute_ipv6_route_map_delete(enum nb_event event, +isis_instance_redistribute_ipv6_route_map_destroy(enum nb_event event, const struct lyd_node *dnode) { /* It's all done by redistribute_apply_finish */ @@ -1147,7 +1147,7 @@ isis_instance_redistribute_ipv6_metric_modify(enum nb_event event, } static int -isis_instance_redistribute_ipv6_metric_delete(enum nb_event event, +isis_instance_redistribute_ipv6_metric_destroy(enum nb_event event, const struct lyd_node *dnode) { /* It's all done by redistribute_apply_finish */ @@ -1217,7 +1217,7 @@ isis_instance_multi_topology_ipv4_multicast_create(enum nb_event event, } static int -isis_instance_multi_topology_ipv4_multicast_delete(enum nb_event event, +isis_instance_multi_topology_ipv4_multicast_destroy(enum nb_event event, const struct lyd_node *dnode) { return isis_multi_topology_common(event, dnode, "ipv4-multicast", @@ -1245,7 +1245,7 @@ static int isis_instance_multi_topology_ipv4_management_create( return isis_multi_topology_common(event, dnode, "ipv4-mgmt", true); } -static int isis_instance_multi_topology_ipv4_management_delete( +static int isis_instance_multi_topology_ipv4_management_destroy( enum nb_event event, const struct lyd_node *dnode) { return isis_multi_topology_common(event, dnode, "ipv4-mgmt", false); @@ -1273,7 +1273,7 @@ isis_instance_multi_topology_ipv6_unicast_create(enum nb_event event, } static int -isis_instance_multi_topology_ipv6_unicast_delete(enum nb_event event, +isis_instance_multi_topology_ipv6_unicast_destroy(enum nb_event event, const struct lyd_node *dnode) { return isis_multi_topology_common(event, dnode, "ipv6-unicast", false); @@ -1302,7 +1302,7 @@ isis_instance_multi_topology_ipv6_multicast_create(enum nb_event event, } static int -isis_instance_multi_topology_ipv6_multicast_delete(enum nb_event event, +isis_instance_multi_topology_ipv6_multicast_destroy(enum nb_event event, const struct lyd_node *dnode) { return isis_multi_topology_common(event, dnode, "ipv6-multicast", @@ -1330,7 +1330,7 @@ static int isis_instance_multi_topology_ipv6_management_create( return isis_multi_topology_common(event, dnode, "ipv6-mgmt", true); } -static int isis_instance_multi_topology_ipv6_management_delete( +static int isis_instance_multi_topology_ipv6_management_destroy( enum nb_event event, const struct lyd_node *dnode) { return isis_multi_topology_common(event, dnode, "ipv6-mgmt", false); @@ -1358,7 +1358,7 @@ isis_instance_multi_topology_ipv6_dstsrc_create(enum nb_event event, } static int -isis_instance_multi_topology_ipv6_dstsrc_delete(enum nb_event event, +isis_instance_multi_topology_ipv6_dstsrc_destroy(enum nb_event event, const struct lyd_node *dnode) { return isis_multi_topology_common(event, dnode, "ipv6-dstsrc", false); @@ -1436,7 +1436,7 @@ static int isis_mpls_te_create(enum nb_event event, return NB_OK; } -static int isis_mpls_te_delete(enum nb_event event, +static int isis_mpls_te_destroy(enum nb_event event, const struct lyd_node *dnode) { struct listnode *node; @@ -1494,7 +1494,7 @@ static int isis_mpls_te_router_address_modify(enum nb_event event, return NB_OK; } -static int isis_mpls_te_router_address_delete(enum nb_event event, +static int isis_mpls_te_router_address_destroy(enum nb_event event, const struct lyd_node *dnode) { struct listnode *node; @@ -1555,7 +1555,7 @@ static int lib_interface_isis_create(enum nb_event event, return NB_OK; } -static int lib_interface_isis_delete(enum nb_event event, +static int lib_interface_isis_destroy(enum nb_event event, const struct lyd_node *dnode) { struct isis_circuit *circuit; @@ -2062,7 +2062,7 @@ static int lib_interface_isis_password_create(enum nb_event event, return NB_OK; } -static int lib_interface_isis_password_delete(enum nb_event event, +static int lib_interface_isis_password_destroy(enum nb_event event, const struct lyd_node *dnode) { struct isis_circuit *circuit; @@ -2092,8 +2092,8 @@ lib_interface_isis_password_password_modify(enum nb_event event, password = yang_dnode_get_string(dnode, NULL); circuit = yang_dnode_get_entry(dnode, true); - circuit->passwd.len = strlen(password); - strncpy((char *)circuit->passwd.passwd, password, 255); + + isis_circuit_passwd_set(circuit, circuit->passwd.type, password); return NB_OK; } @@ -2749,7 +2749,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance", .cbs.create = isis_instance_create, - .cbs.delete = isis_instance_delete, + .cbs.destroy = isis_instance_destroy, .cbs.cli_show = cli_show_router_isis, .priority = NB_DFLT_PRIORITY - 1, }, @@ -2761,7 +2761,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/area-address", .cbs.create = isis_instance_area_address_create, - .cbs.delete = isis_instance_area_address_delete, + .cbs.destroy = isis_instance_area_address_destroy, .cbs.cli_show = cli_show_isis_area_address, }, { @@ -2833,7 +2833,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/spf/ietf-backoff-delay", .cbs.create = isis_instance_spf_ietf_backoff_delay_create, - .cbs.delete = isis_instance_spf_ietf_backoff_delay_delete, + .cbs.destroy = isis_instance_spf_ietf_backoff_delay_destroy, .cbs.apply_finish = ietf_backoff_delay_apply_finish, .cbs.cli_show = cli_show_isis_spf_ietf_backoff, }, @@ -2872,7 +2872,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/area-password", .cbs.create = isis_instance_area_password_create, - .cbs.delete = isis_instance_area_password_delete, + .cbs.destroy = isis_instance_area_password_destroy, .cbs.apply_finish = area_password_apply_finish, .cbs.cli_show = cli_show_isis_area_pwd, }, @@ -2891,7 +2891,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/domain-password", .cbs.create = isis_instance_domain_password_create, - .cbs.delete = isis_instance_domain_password_delete, + .cbs.destroy = isis_instance_domain_password_destroy, .cbs.apply_finish = domain_password_apply_finish, .cbs.cli_show = cli_show_isis_domain_pwd, }, @@ -2910,7 +2910,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv4", .cbs.create = isis_instance_default_information_originate_ipv4_create, - .cbs.delete = isis_instance_default_information_originate_ipv4_delete, + .cbs.destroy = isis_instance_default_information_originate_ipv4_destroy, .cbs.apply_finish = default_info_origin_ipv4_apply_finish, .cbs.cli_show = cli_show_isis_def_origin_ipv4, }, @@ -2921,17 +2921,17 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv4/route-map", .cbs.modify = isis_instance_default_information_originate_ipv4_route_map_modify, - .cbs.delete = isis_instance_default_information_originate_ipv4_route_map_delete, + .cbs.destroy = isis_instance_default_information_originate_ipv4_route_map_destroy, }, { .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv4/metric", .cbs.modify = isis_instance_default_information_originate_ipv4_metric_modify, - .cbs.delete = isis_instance_default_information_originate_ipv4_metric_delete, + .cbs.destroy = isis_instance_default_information_originate_ipv4_metric_destroy, }, { .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv6", .cbs.create = isis_instance_default_information_originate_ipv6_create, - .cbs.delete = isis_instance_default_information_originate_ipv6_delete, + .cbs.destroy = isis_instance_default_information_originate_ipv6_destroy, .cbs.apply_finish = default_info_origin_ipv6_apply_finish, .cbs.cli_show = cli_show_isis_def_origin_ipv6, }, @@ -2942,51 +2942,51 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv6/route-map", .cbs.modify = isis_instance_default_information_originate_ipv6_route_map_modify, - .cbs.delete = isis_instance_default_information_originate_ipv6_route_map_delete, + .cbs.destroy = isis_instance_default_information_originate_ipv6_route_map_destroy, }, { .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv6/metric", .cbs.modify = isis_instance_default_information_originate_ipv6_metric_modify, - .cbs.delete = isis_instance_default_information_originate_ipv6_metric_delete, + .cbs.destroy = isis_instance_default_information_originate_ipv6_metric_destroy, }, { .xpath = "/frr-isisd:isis/instance/redistribute/ipv4", .cbs.create = isis_instance_redistribute_ipv4_create, - .cbs.delete = isis_instance_redistribute_ipv4_delete, + .cbs.destroy = isis_instance_redistribute_ipv4_destroy, .cbs.apply_finish = redistribute_ipv4_apply_finish, .cbs.cli_show = cli_show_isis_redistribute_ipv4, }, { .xpath = "/frr-isisd:isis/instance/redistribute/ipv4/route-map", .cbs.modify = isis_instance_redistribute_ipv4_route_map_modify, - .cbs.delete = isis_instance_redistribute_ipv4_route_map_delete, + .cbs.destroy = isis_instance_redistribute_ipv4_route_map_destroy, }, { .xpath = "/frr-isisd:isis/instance/redistribute/ipv4/metric", .cbs.modify = isis_instance_redistribute_ipv4_metric_modify, - .cbs.delete = isis_instance_redistribute_ipv4_metric_delete, + .cbs.destroy = isis_instance_redistribute_ipv4_metric_destroy, }, { .xpath = "/frr-isisd:isis/instance/redistribute/ipv6", .cbs.create = isis_instance_redistribute_ipv6_create, - .cbs.delete = isis_instance_redistribute_ipv6_delete, + .cbs.destroy = isis_instance_redistribute_ipv6_destroy, .cbs.apply_finish = redistribute_ipv6_apply_finish, .cbs.cli_show = cli_show_isis_redistribute_ipv6, }, { .xpath = "/frr-isisd:isis/instance/redistribute/ipv6/route-map", .cbs.modify = isis_instance_redistribute_ipv6_route_map_modify, - .cbs.delete = isis_instance_redistribute_ipv6_route_map_delete, + .cbs.destroy = isis_instance_redistribute_ipv6_route_map_destroy, }, { .xpath = "/frr-isisd:isis/instance/redistribute/ipv6/metric", .cbs.modify = isis_instance_redistribute_ipv6_metric_modify, - .cbs.delete = isis_instance_redistribute_ipv6_metric_delete, + .cbs.destroy = isis_instance_redistribute_ipv6_metric_destroy, }, { .xpath = "/frr-isisd:isis/instance/multi-topology/ipv4-multicast", .cbs.create = isis_instance_multi_topology_ipv4_multicast_create, - .cbs.delete = isis_instance_multi_topology_ipv4_multicast_delete, + .cbs.destroy = isis_instance_multi_topology_ipv4_multicast_destroy, .cbs.cli_show = cli_show_isis_mt_ipv4_multicast, }, { @@ -2996,7 +2996,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/multi-topology/ipv4-management", .cbs.create = isis_instance_multi_topology_ipv4_management_create, - .cbs.delete = isis_instance_multi_topology_ipv4_management_delete, + .cbs.destroy = isis_instance_multi_topology_ipv4_management_destroy, .cbs.cli_show = cli_show_isis_mt_ipv4_mgmt, }, { @@ -3006,7 +3006,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/multi-topology/ipv6-unicast", .cbs.create = isis_instance_multi_topology_ipv6_unicast_create, - .cbs.delete = isis_instance_multi_topology_ipv6_unicast_delete, + .cbs.destroy = isis_instance_multi_topology_ipv6_unicast_destroy, .cbs.cli_show = cli_show_isis_mt_ipv6_unicast, }, { @@ -3016,7 +3016,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/multi-topology/ipv6-multicast", .cbs.create = isis_instance_multi_topology_ipv6_multicast_create, - .cbs.delete = isis_instance_multi_topology_ipv6_multicast_delete, + .cbs.destroy = isis_instance_multi_topology_ipv6_multicast_destroy, .cbs.cli_show = cli_show_isis_mt_ipv6_multicast, }, { @@ -3026,7 +3026,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/multi-topology/ipv6-management", .cbs.create = isis_instance_multi_topology_ipv6_management_create, - .cbs.delete = isis_instance_multi_topology_ipv6_management_delete, + .cbs.destroy = isis_instance_multi_topology_ipv6_management_destroy, .cbs.cli_show = cli_show_isis_mt_ipv6_mgmt, }, { @@ -3036,7 +3036,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/multi-topology/ipv6-dstsrc", .cbs.create = isis_instance_multi_topology_ipv6_dstsrc_create, - .cbs.delete = isis_instance_multi_topology_ipv6_dstsrc_delete, + .cbs.destroy = isis_instance_multi_topology_ipv6_dstsrc_destroy, .cbs.cli_show = cli_show_isis_mt_ipv6_dstsrc, }, { @@ -3051,19 +3051,19 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/mpls-te", .cbs.create = isis_mpls_te_create, - .cbs.delete = isis_mpls_te_delete, + .cbs.destroy = isis_mpls_te_destroy, .cbs.cli_show = cli_show_isis_mpls_te, }, { .xpath = "/frr-isisd:isis/mpls-te/router-address", .cbs.modify = isis_mpls_te_router_address_modify, - .cbs.delete = isis_mpls_te_router_address_delete, + .cbs.destroy = isis_mpls_te_router_address_destroy, .cbs.cli_show = cli_show_isis_mpls_te_router_addr, }, { .xpath = "/frr-interface:lib/interface/frr-isisd:isis", .cbs.create = lib_interface_isis_create, - .cbs.delete = lib_interface_isis_delete, + .cbs.destroy = lib_interface_isis_destroy, }, { .xpath = "/frr-interface:lib/interface/frr-isisd:isis/area-tag", @@ -3174,7 +3174,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-interface:lib/interface/frr-isisd:isis/password", .cbs.create = lib_interface_isis_password_create, - .cbs.delete = lib_interface_isis_password_delete, + .cbs.destroy = lib_interface_isis_password_destroy, .cbs.cli_show = cli_show_ip_isis_password, }, { diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 330da9b216..8e9302963d 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -131,7 +131,7 @@ static int process_p2p_hello(struct iih_info *iih) if (tw_adj) { if (tw_adj->state > ISIS_THREEWAY_DOWN) { if (isis->debugs & DEBUG_ADJ_PACKETS) { - zlog_debug("ISIS-Adj (%s): Rcvd P2P IIH from (%s) with invalid three-way state: %d\n", + zlog_debug("ISIS-Adj (%s): Rcvd P2P IIH from (%s) with invalid three-way state: %d", iih->circuit->area->area_tag, iih->circuit->interface->name, tw_adj->state); @@ -144,7 +144,7 @@ static int process_p2p_hello(struct iih_info *iih) || tw_adj->neighbor_circuit_id != (uint32_t) iih->circuit->idx)) { if (isis->debugs & DEBUG_ADJ_PACKETS) { - zlog_debug("ISIS-Adj (%s): Rcvd P2P IIH from (%s) which lists IS/Circuit different from us as neighbor.\n", + zlog_debug("ISIS-Adj (%s): Rcvd P2P IIH from (%s) which lists IS/Circuit different from us as neighbor.", iih->circuit->area->area_tag, iih->circuit->interface->name); } @@ -1523,7 +1523,7 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit, } if (fabricd_initial_sync_is_complete(circuit->area) && resync_needed) - zlog_warn("OpenFabric: Needed to resync LSPDB using CSNP!\n"); + zlog_warn("OpenFabric: Needed to resync LSPDB using CSNP!"); retval = ISIS_OK; out: @@ -2146,11 +2146,11 @@ int send_csnp(struct isis_circuit *circuit, int level) * stop lsp_id in this current CSNP. */ memcpy(start, stop, ISIS_SYS_ID_LEN + 2); - loop = 0; + loop = false; for (int i = ISIS_SYS_ID_LEN + 1; i >= 0; --i) { if (start[i] < (uint8_t)0xff) { start[i] += 1; - loop = 1; + loop = true; break; } } @@ -2164,7 +2164,6 @@ int send_csnp(struct isis_circuit *circuit, int level) int send_l1_csnp(struct thread *thread) { struct isis_circuit *circuit; - int retval = ISIS_OK; circuit = THREAD_ARG(thread); assert(circuit); @@ -2181,13 +2180,12 @@ int send_l1_csnp(struct thread *thread) isis_jitter(circuit->csnp_interval[0], CSNP_JITTER), &circuit->t_send_csnp[0]); - return retval; + return ISIS_OK; } int send_l2_csnp(struct thread *thread) { struct isis_circuit *circuit; - int retval = ISIS_OK; circuit = THREAD_ARG(thread); assert(circuit); @@ -2204,7 +2202,7 @@ int send_l2_csnp(struct thread *thread) isis_jitter(circuit->csnp_interval[1], CSNP_JITTER), &circuit->t_send_csnp[1]); - return retval; + return ISIS_OK; } /* @@ -2329,7 +2327,6 @@ int send_l1_psnp(struct thread *thread) { struct isis_circuit *circuit; - int retval = ISIS_OK; circuit = THREAD_ARG(thread); assert(circuit); @@ -2342,7 +2339,7 @@ int send_l1_psnp(struct thread *thread) isis_jitter(circuit->psnp_interval[0], PSNP_JITTER), &circuit->t_send_psnp[0]); - return retval; + return ISIS_OK; } /* @@ -2352,7 +2349,6 @@ int send_l1_psnp(struct thread *thread) int send_l2_psnp(struct thread *thread) { struct isis_circuit *circuit; - int retval = ISIS_OK; circuit = THREAD_ARG(thread); assert(circuit); @@ -2366,7 +2362,7 @@ int send_l2_psnp(struct thread *thread) isis_jitter(circuit->psnp_interval[1], PSNP_JITTER), &circuit->t_send_psnp[1]); - return retval; + return ISIS_OK; } /* diff --git a/isisd/isis_redist.c b/isisd/isis_redist.c index 20f3e62a74..3a864fb356 100644 --- a/isisd/isis_redist.c +++ b/isisd/isis_redist.c @@ -504,8 +504,7 @@ void isis_redist_area_finish(struct isis_area *area) redist = &area->redist_settings[protocol][type] [level]; redist->redist = 0; - if (redist->map_name) - XFREE(MTYPE_ISIS, redist->map_name); + XFREE(MTYPE_ISIS, redist->map_name); } route_table_finish(area->ext_reach[protocol][level]); } diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 1f28309105..18eb857ec9 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -352,10 +352,10 @@ static struct isis_vertex *isis_spf_add_root(struct isis_spftree *spftree, return vertex; } -static void vertex_add_parent_firsthop(struct hash_backet *backet, void *arg) +static void vertex_add_parent_firsthop(struct hash_bucket *bucket, void *arg) { struct isis_vertex *vertex = arg; - struct isis_vertex *hop = backet->data; + struct isis_vertex *hop = bucket->data; hash_get(vertex->firsthops, hop, hash_alloc_intern); } diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c index 5a6c7bc300..fbb1e5714c 100644 --- a/isisd/isis_tlvs.c +++ b/isisd/isis_tlvs.c @@ -1913,7 +1913,7 @@ static void format_item_auth(uint16_t mtid, struct isis_item *i, default: sbuf_push(buf, indent, " Unknown (%" PRIu8 ")\n", auth->type); break; - }; + } } static void free_item_auth(struct isis_item *i) @@ -3202,8 +3202,7 @@ void isis_tlvs_set_protocols_supported(struct isis_tlvs *tlvs, struct nlpids *nlpids) { tlvs->protocols_supported.count = nlpids->count; - if (tlvs->protocols_supported.protocols) - XFREE(MTYPE_ISIS_TLV, tlvs->protocols_supported.protocols); + XFREE(MTYPE_ISIS_TLV, tlvs->protocols_supported.protocols); if (nlpids->count) { tlvs->protocols_supported.protocols = XCALLOC(MTYPE_ISIS_TLV, nlpids->count); diff --git a/isisd/isisd.c b/isisd/isisd.c index 13cd510dd1..ad02220438 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -1363,7 +1363,7 @@ struct isis_lsp *lsp_for_arg(const char *argv, dict_t *lspdb) * xxxx.xxxx.xxxx */ if (argv) - strncpy(sysid, argv, 254); + strlcpy(sysid, argv, sizeof(sysid)); if (argv && strlen(argv) > 3) { pos = argv + strlen(argv) - 3; if (strncmp(pos, "-", 1) == 0) { @@ -1639,7 +1639,8 @@ static int isis_area_passwd_set(struct isis_area *area, int level, return -1; modified.len = len; - strncpy((char *)modified.passwd, passwd, 255); + strlcpy((char *)modified.passwd, passwd, + sizeof(modified.passwd)); modified.type = passwd_type; modified.snp_auth = snp_auth; } diff --git a/lib/agg_table.h b/lib/agg_table.h index dc2ff03b67..40ffe8c755 100644 --- a/lib/agg_table.h +++ b/lib/agg_table.h @@ -23,6 +23,10 @@ #include "prefix.h" #include "table.h" +#ifdef __cplusplus +extern "C" { +#endif + struct agg_table { struct route_table *route_table; @@ -150,4 +154,9 @@ static inline struct agg_table *agg_get_table(struct agg_node *node) { return (struct agg_table *)route_table_get_info(node->table); } + +#ifdef __cplusplus +} +#endif + #endif @@ -26,6 +26,10 @@ #include "lib/json.h" #include "lib/zclient.h" +#ifdef __cplusplus +extern "C" { +#endif + #define BFD_DEF_MIN_RX 300 #define BFD_MIN_MIN_RX 50 #define BFD_MAX_MIN_RX 60000 @@ -104,4 +108,8 @@ extern void bfd_gbl_init(void); extern void bfd_gbl_exit(void); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_BFD_H */ diff --git a/lib/bitfield.h b/lib/bitfield.h index 0e031ccc49..eebfc049d9 100644 --- a/lib/bitfield.h +++ b/lib/bitfield.h @@ -44,6 +44,10 @@ #include <string.h> #include <stdlib.h> +#ifdef __cplusplus +extern "C" { +#endif + typedef unsigned int word_t; #define WORD_MAX 0xFFFFFFFF #define WORD_SIZE (sizeof(word_t) * 8) @@ -153,4 +157,8 @@ typedef unsigned int word_t; } \ } while (0) +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/buffer.h b/lib/buffer.h index 0c945a2acf..8b5a89825f 100644 --- a/lib/buffer.h +++ b/lib/buffer.h @@ -22,6 +22,10 @@ #ifndef _ZEBRA_BUFFER_H #define _ZEBRA_BUFFER_H +#ifdef __cplusplus +extern "C" { +#endif + /* Create a new buffer. Memory will be allocated in chunks of the given size. If the argument is 0, the library will supply a reasonable default size suitable for buffering socket I/O. */ @@ -99,4 +103,8 @@ extern buffer_status_t buffer_flush_all(struct buffer *, int fd); extern buffer_status_t buffer_flush_window(struct buffer *, int fd, int width, int height, int erase, int no_more); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_BUFFER_H */ diff --git a/lib/checksum.h b/lib/checksum.h index c2764e35fb..7d50371439 100644 --- a/lib/checksum.h +++ b/lib/checksum.h @@ -1,4 +1,12 @@ +#ifdef __cplusplus +extern "C" { +#endif + extern int in_cksum(void *, int); #define FLETCHER_CHECKSUM_VALIDATE 0xffff extern uint16_t fletcher_checksum(uint8_t *, const size_t len, const uint16_t offset); + +#ifdef __cplusplus +} +#endif diff --git a/lib/clippy.h b/lib/clippy.h index 8df98cbb8e..be4db6e638 100644 --- a/lib/clippy.h +++ b/lib/clippy.h @@ -22,7 +22,15 @@ #include <Python.h> +#ifdef __cplusplus +extern "C" { +#endif + extern PyObject *clippy_parse(PyObject *self, PyObject *args); extern PyMODINIT_FUNC command_py_init(void); +#ifdef __cplusplus +} +#endif + #endif /* _FRR_CLIPPY_H */ diff --git a/lib/command.c b/lib/command.c index 06879f6854..559457c119 100644 --- a/lib/command.c +++ b/lib/command.c @@ -1009,7 +1009,7 @@ enum node_type node_parent(enum node_type node) } /* Execute command by argument vline vector. */ -static int cmd_execute_command_real(vector vline, enum filter_type filter, +static int cmd_execute_command_real(vector vline, enum cmd_filter_type filter, struct vty *vty, const struct cmd_element **cmd) { @@ -1277,8 +1277,7 @@ int cmd_execute(struct vty *vty, const char *cmd, hook_call(cmd_execute_done, vty, cmd_exec); - if (cmd_out) - XFREE(MTYPE_TMP, cmd_out); + XFREE(MTYPE_TMP, cmd_out); return ret; } @@ -2408,8 +2407,7 @@ static int set_log_file(struct vty *vty, const char *fname, int loglevel) ret = zlog_set_file(fullpath, loglevel); - if (p) - XFREE(MTYPE_TMP, p); + XFREE(MTYPE_TMP, p); if (!ret) { if (vty) @@ -2417,8 +2415,7 @@ static int set_log_file(struct vty *vty, const char *fname, int loglevel) return CMD_WARNING_CONFIG_FAILED; } - if (host.logfile) - XFREE(MTYPE_HOST, host.logfile); + XFREE(MTYPE_HOST, host.logfile); host.logfile = XSTRDUP(MTYPE_HOST, fname); @@ -2487,8 +2484,7 @@ static void disable_log_file(void) { zlog_reset_file(); - if (host.logfile) - XFREE(MTYPE_HOST, host.logfile); + XFREE(MTYPE_HOST, host.logfile); host.logfile = NULL; } @@ -2637,8 +2633,7 @@ int cmd_banner_motd_file(const char *file) return CMD_ERR_NO_FILE; in = strstr(rpath, SYSCONFDIR); if (in == rpath) { - if (host.motdfile) - XFREE(MTYPE_HOST, host.motdfile); + XFREE(MTYPE_HOST, host.motdfile); host.motdfile = XSTRDUP(MTYPE_HOST, file); } else success = CMD_WARNING_CONFIG_FAILED; @@ -2723,8 +2718,7 @@ DEFUN(find, /* Set config filename. Called from vty.c */ void host_config_set(const char *filename) { - if (host.config) - XFREE(MTYPE_HOST, host.config); + XFREE(MTYPE_HOST, host.config); host.config = XSTRDUP(MTYPE_HOST, filename); } @@ -2904,24 +2898,15 @@ void cmd_terminate(void) cmdvec = NULL; } - if (host.name) - XFREE(MTYPE_HOST, host.name); - if (host.domainname) - XFREE(MTYPE_HOST, host.domainname); - if (host.password) - XFREE(MTYPE_HOST, host.password); - if (host.password_encrypt) - XFREE(MTYPE_HOST, host.password_encrypt); - if (host.enable) - XFREE(MTYPE_HOST, host.enable); - if (host.enable_encrypt) - XFREE(MTYPE_HOST, host.enable_encrypt); - if (host.logfile) - XFREE(MTYPE_HOST, host.logfile); - if (host.motdfile) - XFREE(MTYPE_HOST, host.motdfile); - if (host.config) - XFREE(MTYPE_HOST, host.config); + XFREE(MTYPE_HOST, host.name); + XFREE(MTYPE_HOST, host.domainname); + XFREE(MTYPE_HOST, host.password); + XFREE(MTYPE_HOST, host.password_encrypt); + XFREE(MTYPE_HOST, host.enable); + XFREE(MTYPE_HOST, host.enable_encrypt); + XFREE(MTYPE_HOST, host.logfile); + XFREE(MTYPE_HOST, host.motdfile); + XFREE(MTYPE_HOST, host.config); list_delete(&varhandlers); qobj_finish(); diff --git a/lib/command.h b/lib/command.h index 11514fd5e8..a5f9616dbf 100644 --- a/lib/command.h +++ b/lib/command.h @@ -30,6 +30,10 @@ #include "hash.h" #include "command_graph.h" +#ifdef __cplusplus +extern "C" { +#endif + DECLARE_MTYPE(HOST) DECLARE_MTYPE(COMPLETION) @@ -314,6 +318,9 @@ struct cmd_node { #define DEFPY_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \ DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, attr) + +#define DEFPY_HIDDEN(funcname, cmdname, cmdstr, helpstr) \ + DEFUN_HIDDEN(funcname, cmdname, cmdstr, helpstr) #endif /* VTYSH_EXTRACT_PL */ /* Some macroes */ @@ -488,4 +495,9 @@ cmd_variable_handler_register(const struct cmd_variable_handler *cvh); extern char *cmd_variable_comp2str(vector comps, unsigned short cols); extern void command_setup_early_logging(const char *dest, const char *level); + +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_COMMAND_H */ diff --git a/lib/command_graph.c b/lib/command_graph.c index 0e8669c4b5..4757fd951f 100644 --- a/lib/command_graph.c +++ b/lib/command_graph.c @@ -471,7 +471,7 @@ void cmd_graph_node_print_cb(struct graph_node *gn, struct buffer *buf) struct cmd_token *tok = gn->data; const char *color; - if (wasend == true) { + if (wasend) { wasend = false; return; } diff --git a/lib/command_graph.h b/lib/command_graph.h index 82d562694c..903d515834 100644 --- a/lib/command_graph.h +++ b/lib/command_graph.h @@ -32,6 +32,10 @@ #include "vector.h" #include "graph.h" +#ifdef __cplusplus +extern "C" { +#endif + DECLARE_MTYPE(CMD_ARG) struct vty; @@ -114,7 +118,7 @@ extern void cmd_token_varname_set(struct cmd_token *token, const char *varname); extern void cmd_graph_parse(struct graph *graph, struct cmd_element *cmd); extern void cmd_graph_names(struct graph *graph); -extern void cmd_graph_merge(struct graph *old, struct graph *new, +extern void cmd_graph_merge(struct graph *old, struct graph *n, int direction); /* * Print callback for DOT dumping. @@ -133,4 +137,8 @@ extern void cmd_graph_node_print_cb(struct graph_node *gn, struct buffer *buf); */ char *cmd_graph_dump_dot(struct graph *cmdgraph); +#ifdef __cplusplus +} +#endif + #endif /* _FRR_COMMAND_GRAPH_H */ diff --git a/lib/command_match.h b/lib/command_match.h index c636d2dd95..fcb333120f 100644 --- a/lib/command_match.h +++ b/lib/command_match.h @@ -28,10 +28,14 @@ #include "linklist.h" #include "command.h" +#ifdef __cplusplus +extern "C" { +#endif + /* These definitions exist in command.c in the current engine but should be * relocated here in the new engine */ -enum filter_type { FILTER_RELAXED, FILTER_STRICT }; +enum cmd_filter_type { FILTER_RELAXED, FILTER_STRICT }; /* matcher result value */ enum matcher_rv { @@ -98,4 +102,8 @@ enum matcher_rv command_match(struct graph *cmdgraph, vector vline, enum matcher_rv command_complete(struct graph *cmdgraph, vector vline, struct list **completions); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_COMMAND_MATCH_H */ diff --git a/lib/compiler.h b/lib/compiler.h index 24b8fafd10..cb4f7531ec 100644 --- a/lib/compiler.h +++ b/lib/compiler.h @@ -17,6 +17,10 @@ #ifndef _FRR_COMPILER_H #define _FRR_COMPILER_H +#ifdef __cplusplus +extern "C" { +#endif + /* function attributes, use like * void prototype(void) __attribute__((_CONSTRUCTOR(100))); */ @@ -88,4 +92,8 @@ #define CPP_NOTICE(text) #endif +#ifdef __cplusplus +} +#endif + #endif /* _FRR_COMPILER_H */ @@ -70,6 +70,10 @@ #include <stdarg.h> #include <sys/queue.h> +#ifdef __cplusplus +extern "C" { +#endif + typedef struct _csv_field_t_ csv_field_t; typedef struct _csv_record_t_ csv_record_t; typedef struct _csv_t_ csv_t; @@ -185,4 +189,8 @@ void csv_clone_record(csv_t *csv, csv_record_t *in_rec, csv_record_t **out_rec); */ int csv_num_records(csv_t *csv); +#ifdef __cplusplus +} +#endif + #endif @@ -38,6 +38,10 @@ #include <sqlite3.h> +#ifdef __cplusplus +extern "C" { +#endif + extern int db_init(const char *path_fmt, ...); extern int db_close(void); extern int db_bindf(struct sqlite3_stmt *ss, const char *fmt, ...); @@ -48,5 +52,9 @@ extern int db_loadf(struct sqlite3_stmt *ss, const char *fmt, ...); extern void db_finalize(struct sqlite3_stmt **ss); extern int db_execute(const char *stmt_fmt, ...); +#ifdef __cplusplus +} +#endif + #endif /* HAVE_SQLITE3 */ #endif /* _FRR_DB_H_ */ diff --git a/lib/debug.h b/lib/debug.h index d0fa27d3fe..ace060d057 100644 --- a/lib/debug.h +++ b/lib/debug.h @@ -24,6 +24,10 @@ #include "command.h" #include "frratomic.h" +#ifdef __cplusplus +extern "C" { +#endif + /* * Debugging modes. * @@ -76,7 +80,7 @@ * Human-readable description of this debugging record. */ struct debug { - _Atomic uint32_t flags; + atomic_uint_fast32_t flags; const char *desc; }; @@ -231,4 +235,8 @@ struct debug_callbacks { */ void debug_init(const struct debug_callbacks *cb); +#ifdef __cplusplus +} +#endif + #endif /* _FRRDEBUG_H */ diff --git a/lib/distribute.c b/lib/distribute.c index 3a6b775bc8..fa8ac5242e 100644 --- a/lib/distribute.c +++ b/lib/distribute.c @@ -44,16 +44,15 @@ static void distribute_free(struct distribute *dist) { int i = 0; - if (dist->ifname) - XFREE(MTYPE_DISTRIBUTE_IFNAME, dist->ifname); + XFREE(MTYPE_DISTRIBUTE_IFNAME, dist->ifname); - for (i = 0; i < DISTRIBUTE_MAX; i++) - if (dist->list[i]) - XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[i]); + for (i = 0; i < DISTRIBUTE_MAX; i++) { + XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[i]); + } - for (i = 0; i < DISTRIBUTE_MAX; i++) - if (dist->prefix[i]) - XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[i]); + for (i = 0; i < DISTRIBUTE_MAX; i++) { + XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[i]); + } XFREE(MTYPE_DISTRIBUTE, dist); } @@ -83,8 +82,7 @@ struct distribute *distribute_lookup(struct distribute_ctx *ctx, dist = hash_lookup(ctx->disthash, &key); - if (key.ifname) - XFREE(MTYPE_DISTRIBUTE_IFNAME, key.ifname); + XFREE(MTYPE_DISTRIBUTE_IFNAME, key.ifname); return dist; } @@ -128,8 +126,7 @@ static struct distribute *distribute_get(struct distribute_ctx *ctx, ret = hash_get(ctx->disthash, &key, (void *(*)(void *))distribute_hash_alloc); - if (key.ifname) - XFREE(MTYPE_DISTRIBUTE_IFNAME, key.ifname); + XFREE(MTYPE_DISTRIBUTE_IFNAME, key.ifname); return ret; } @@ -163,8 +160,7 @@ static void distribute_list_set(struct distribute_ctx *ctx, dist = distribute_get(ctx, ifname); - if (dist->list[type]) - XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[type]); + XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[type]); dist->list[type] = XSTRDUP(MTYPE_DISTRIBUTE_NAME, alist_name); /* Apply this distribute-list to the interface. */ @@ -210,8 +206,7 @@ static void distribute_list_prefix_set(struct distribute_ctx *ctx, dist = distribute_get(ctx, ifname); - if (dist->prefix[type]) - XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[type]); + XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[type]); dist->prefix[type] = XSTRDUP(MTYPE_DISTRIBUTE_NAME, plist_name); /* Apply this distribute-list to the interface. */ @@ -409,7 +404,7 @@ int config_show_distribute(struct vty *vty, struct distribute_ctx *dist_ctxt) { unsigned int i; int has_print = 0; - struct hash_backet *mp; + struct hash_bucket *mp; struct distribute *dist; /* Output filter configuration. */ @@ -512,7 +507,7 @@ int config_write_distribute(struct vty *vty, unsigned int i; int j; int output, v6; - struct hash_backet *mp; + struct hash_bucket *mp; int write = 0; for (i = 0; i < dist_ctxt->disthash->size; i++) diff --git a/lib/distribute.h b/lib/distribute.h index 44c699b38a..4016d3b133 100644 --- a/lib/distribute.h +++ b/lib/distribute.h @@ -25,6 +25,10 @@ #include "if.h" #include "filter.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Disctirubte list types. */ enum distribute_type { DISTRIBUTE_V4_IN, @@ -81,4 +85,8 @@ extern enum filter_type distribute_apply_in(struct interface *, extern enum filter_type distribute_apply_out(struct interface *, struct prefix *); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_DISTRIBUTE_H */ diff --git a/lib/event_counter.c b/lib/event_counter.c index c520937a38..57dbfb5fd1 100644 --- a/lib/event_counter.c +++ b/lib/event_counter.c @@ -62,7 +62,7 @@ const char *event_counter_format(const struct event_counter *counter) || strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %T %z", last_change) == 0) { - strncpy(timebuf, "???", sizeof(timebuf)); + strlcpy(timebuf, "???", sizeof(timebuf)); } snprintf(rv, sizeof(rv), "%5llu last: %s", counter->count, diff --git a/lib/event_counter.h b/lib/event_counter.h index de5dbc0665..8ae276ffef 100644 --- a/lib/event_counter.h +++ b/lib/event_counter.h @@ -43,6 +43,10 @@ #ifndef _ZEBRA_EVENT_COUNTER_H #define _ZEBRA_EVENT_COUNTER_H +#ifdef __cplusplus +extern "C" { +#endif + struct event_counter { unsigned long long count; time_t last; @@ -51,4 +55,8 @@ struct event_counter { void event_counter_inc(struct event_counter *counter); const char *event_counter_format(const struct event_counter *counter); +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/ferr.h b/lib/ferr.h index 335875c166..93d0ced538 100644 --- a/lib/ferr.h +++ b/lib/ferr.h @@ -27,6 +27,10 @@ #include "vty.h" +#ifdef __cplusplus +extern "C" { +#endif + /* return type when this error indication stuff is used. * * guaranteed to have boolean evaluation to "false" when OK, "true" when error @@ -253,4 +257,8 @@ DEFUN("bla") #endif /* THIS_IS_AN_EXAMPLE */ +#ifdef __cplusplus +} +#endif + #endif /* _FERR_H */ diff --git a/lib/fifo.h b/lib/fifo.h index f59e4dc6cd..6f9c59b5c1 100644 --- a/lib/fifo.h +++ b/lib/fifo.h @@ -20,6 +20,10 @@ #ifndef __LIB_FIFO_H__ #define __LIB_FIFO_H__ +#ifdef __cplusplus +extern "C" { +#endif + /* FIFO -- first in first out structure and macros. */ struct fifo { struct fifo *next; @@ -55,4 +59,8 @@ struct fifo { #define FIFO_TOP(F) (FIFO_EMPTY(F) ? NULL : ((struct fifo *)(F))->next) +#ifdef __cplusplus +} +#endif + #endif /* __LIB_FIFO_H__ */ diff --git a/lib/filter.c b/lib/filter.c index 317c1b68b7..276df4b4d7 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -128,8 +128,7 @@ static struct access_master *access_master_get(afi_t afi) /* Allocate new filter structure. */ static struct filter *filter_new(void) { - return (struct filter *)XCALLOC(MTYPE_ACCESS_FILTER, - sizeof(struct filter)); + return XCALLOC(MTYPE_ACCESS_FILTER, sizeof(struct filter)); } static void filter_free(struct filter *filter) @@ -202,8 +201,7 @@ static int filter_match_zebra(struct filter *mfilter, const struct prefix *p) /* Allocate new access list structure. */ static struct access_list *access_list_new(void) { - return (struct access_list *)XCALLOC(MTYPE_ACCESS_LIST, - sizeof(struct access_list)); + return XCALLOC(MTYPE_ACCESS_LIST, sizeof(struct access_list)); } /* Free allocated access_list. */ @@ -242,11 +240,9 @@ static void access_list_delete(struct access_list *access) else list->head = access->next; - if (access->name) - XFREE(MTYPE_ACCESS_LIST_STR, access->name); + XFREE(MTYPE_ACCESS_LIST_STR, access->name); - if (access->remark) - XFREE(MTYPE_TMP, access->remark); + XFREE(MTYPE_TMP, access->remark); access_list_free(access); } diff --git a/lib/filter.h b/lib/filter.h index 97854b1e97..3dd2eaaf15 100644 --- a/lib/filter.h +++ b/lib/filter.h @@ -24,6 +24,10 @@ #include "if.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Maximum ACL name length */ #define ACL_NAMSIZ 128 @@ -62,4 +66,8 @@ extern struct access_list *access_list_lookup(afi_t, const char *); extern enum filter_type access_list_apply(struct access_list *access, const void *object); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_FILTER_H */ diff --git a/lib/freebsd-queue.h b/lib/freebsd-queue.h index 4fcfe85a68..793cfff8d3 100644 --- a/lib/freebsd-queue.h +++ b/lib/freebsd-queue.h @@ -33,6 +33,10 @@ #ifndef _SYS_QUEUE_H_ #define _SYS_QUEUE_H_ +#ifdef __cplusplus +extern "C" { +#endif + /* * This file defines four types of data structures: singly-linked lists, * singly-linked tail queues, lists and tail queues. @@ -675,4 +679,8 @@ struct qm_trace { (head2)->tqh_last = &(head2)->tqh_first; \ } while (0) +#ifdef __cplusplus +} +#endif + #endif /* !_SYS_QUEUE_H_ */ diff --git a/lib/frr_pthread.c b/lib/frr_pthread.c index d7f655271b..2a18e5cfc6 100644 --- a/lib/frr_pthread.c +++ b/lib/frr_pthread.c @@ -110,8 +110,7 @@ void frr_pthread_destroy(struct frr_pthread *fpt) pthread_mutex_destroy(&fpt->mtx); pthread_mutex_destroy(fpt->running_cond_mtx); pthread_cond_destroy(fpt->running_cond); - if (fpt->name) - XFREE(MTYPE_FRR_PTHREAD, fpt->name); + XFREE(MTYPE_FRR_PTHREAD, fpt->name); XFREE(MTYPE_PTHREAD_PRIM, fpt->running_cond_mtx); XFREE(MTYPE_PTHREAD_PRIM, fpt->running_cond); XFREE(MTYPE_FRR_PTHREAD, fpt); diff --git a/lib/frr_pthread.h b/lib/frr_pthread.h index e6b3f031b3..9bc7b94033 100644 --- a/lib/frr_pthread.h +++ b/lib/frr_pthread.h @@ -25,6 +25,10 @@ #include "memory.h" #include "thread.h" +#ifdef __cplusplus +extern "C" { +#endif + DECLARE_MTYPE(FRR_PTHREAD); DECLARE_MTYPE(PTHREAD_PRIM); @@ -73,7 +77,7 @@ struct frr_pthread { */ pthread_cond_t *running_cond; pthread_mutex_t *running_cond_mtx; - _Atomic bool running; + atomic_bool running; /* * Fake thread-specific storage. No constraints on usage. Helpful when @@ -211,4 +215,8 @@ void frr_pthread_stop_all(void); #define pthread_condattr_setclock(A, B) #endif +#ifdef __cplusplus +} +#endif + #endif /* _FRR_PTHREAD_H */ diff --git a/lib/frr_zmq.c b/lib/frr_zmq.c index cfea238d95..7781beae5e 100644 --- a/lib/frr_zmq.c +++ b/lib/frr_zmq.c @@ -176,8 +176,6 @@ int funcname_frrzmq_thread_add_read(struct thread_master *master, cb = *cbp; else { cb = XCALLOC(MTYPE_ZEROMQ_CB, sizeof(struct frrzmq_cb)); - if (!cb) - return -1; cb->write.cancelled = 1; *cbp = cb; @@ -286,8 +284,6 @@ int funcname_frrzmq_thread_add_write(struct thread_master *master, cb = *cbp; else { cb = XCALLOC(MTYPE_ZEROMQ_CB, sizeof(struct frrzmq_cb)); - if (!cb) - return -1; cb->read.cancelled = 1; *cbp = cb; diff --git a/lib/frr_zmq.h b/lib/frr_zmq.h index 1146b87964..4303df9ccd 100644 --- a/lib/frr_zmq.h +++ b/lib/frr_zmq.h @@ -23,6 +23,10 @@ #include "thread.h" #include <zmq.h> +#ifdef __cplusplus +extern "C" { +#endif + /* linking/packaging note: this is a separate library that needs to be * linked into any daemon/library/module that wishes to use its * functionality. The purpose of this is to encapsulate the libzmq @@ -124,4 +128,8 @@ extern void frrzmq_thread_cancel(struct frrzmq_cb **cb, struct cb_core *core); extern void frrzmq_check_events(struct frrzmq_cb **cbp, struct cb_core *core, int event); +#ifdef __cplusplus +} +#endif + #endif /* _FRRZMQ_H */ diff --git a/lib/frratomic.h b/lib/frratomic.h index 1f1d1b569a..e86030f83c 100644 --- a/lib/frratomic.h +++ b/lib/frratomic.h @@ -26,7 +26,23 @@ #endif /* ISO C11 */ -#ifdef HAVE_STDATOMIC_H +#ifdef __cplusplus +#include <stdint.h> +#include <atomic> +using std::atomic_int; +using std::memory_order; +using std::memory_order_relaxed; +using std::memory_order_acquire; +using std::memory_order_release; +using std::memory_order_acq_rel; +using std::memory_order_consume; +using std::memory_order_seq_cst; + +typedef std::atomic<bool> atomic_bool; +typedef std::atomic<size_t> atomic_size_t; +typedef std::atomic<uint_fast32_t> atomic_uint_fast32_t; + +#elif defined(HAVE_STDATOMIC_H) #include <stdatomic.h> /* These are available in gcc, but not in stdatomic */ @@ -39,6 +55,7 @@ #elif defined(HAVE___ATOMIC) #define _Atomic volatile +#define _ATOMIC_WANT_TYPEDEFS #define memory_order_relaxed __ATOMIC_RELAXED #define memory_order_consume __ATOMIC_CONSUME @@ -74,6 +91,7 @@ #elif defined(HAVE___SYNC) #define _Atomic volatile +#define _ATOMIC_WANT_TYPEDEFS #define memory_order_relaxed 0 #define memory_order_consume 0 @@ -198,4 +216,15 @@ #error no atomic functions... #endif +#ifdef _ATOMIC_WANT_TYPEDEFS +#undef _ATOMIC_WANT_TYPEDEFS + +#include <stdint.h> +#include <stdbool.h> + +typedef _Atomic bool atomic_bool; +typedef _Atomic size_t atomic_size_t; +typedef _Atomic uint_fast32_t atomic_uint_fast32_t; +#endif + #endif /* _FRRATOMIC_H */ diff --git a/lib/frrstr.c b/lib/frrstr.c index 85d968182b..fd337073f8 100644 --- a/lib/frrstr.c +++ b/lib/frrstr.c @@ -155,13 +155,13 @@ void frrstr_strvec_free(vector v) bool begins_with(const char *str, const char *prefix) { if (!str || !prefix) - return 0; + return false; size_t lenstr = strlen(str); size_t lenprefix = strlen(prefix); if (lenprefix > lenstr) - return 0; + return false; return strncmp(str, prefix, lenprefix) == 0; } diff --git a/lib/frrstr.h b/lib/frrstr.h index 891a3f337c..8b591849a3 100644 --- a/lib/frrstr.h +++ b/lib/frrstr.h @@ -27,6 +27,10 @@ #include "vector.h" +#ifdef __cplusplus +extern "C" { +#endif + /* * Tokenizes a string, storing tokens in a vector. Whitespace is ignored. * Delimiter characters are not included. @@ -108,4 +112,8 @@ bool begins_with(const char *str, const char *prefix); */ int all_digit(const char *str); +#ifdef __cplusplus +} +#endif + #endif /* _FRRSTR_H_ */ diff --git a/lib/graph.h b/lib/graph.h index 87262a07b8..8e126e6be4 100644 --- a/lib/graph.h +++ b/lib/graph.h @@ -28,6 +28,10 @@ #include "vector.h" #include "buffer.h" +#ifdef __cplusplus +extern "C" { +#endif + struct graph { vector nodes; }; @@ -164,4 +168,9 @@ char *graph_dump_dot(struct graph *graph, struct graph_node *start, void (*pcb)(struct graph_node *, struct buffer *buf)); #endif /* BUILDING_CLIPPY */ + +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_COMMAND_GRAPH_H */ diff --git a/lib/hash.c b/lib/hash.c index 6c3c953e97..c02b81814c 100644 --- a/lib/hash.c +++ b/lib/hash.c @@ -46,7 +46,7 @@ struct hash *hash_create_size(unsigned int size, assert((size & (size - 1)) == 0); hash = XCALLOC(MTYPE_HASH, sizeof(struct hash)); hash->index = - XCALLOC(MTYPE_HASH_INDEX, sizeof(struct hash_backet *) * size); + XCALLOC(MTYPE_HASH_INDEX, sizeof(struct hash_bucket *) * size); hash->size = size; hash->hash_key = hash_key; hash->hash_cmp = hash_cmp; @@ -86,7 +86,7 @@ void *hash_alloc_intern(void *arg) static void hash_expand(struct hash *hash) { unsigned int i, new_size; - struct hash_backet *hb, *hbnext, **new_index; + struct hash_bucket *hb, *hbnext, **new_index; new_size = hash->size * 2; @@ -94,9 +94,7 @@ static void hash_expand(struct hash *hash) return; new_index = XCALLOC(MTYPE_HASH_INDEX, - sizeof(struct hash_backet *) * new_size); - if (new_index == NULL) - return; + sizeof(struct hash_bucket *) * new_size); hash->stats.empty = new_size; @@ -133,7 +131,7 @@ void *hash_get(struct hash *hash, void *data, void *(*alloc_func)(void *)) unsigned int key; unsigned int index; void *newdata; - struct hash_backet *backet; + struct hash_bucket *bucket; if (!alloc_func && !hash->count) return NULL; @@ -141,10 +139,10 @@ void *hash_get(struct hash *hash, void *data, void *(*alloc_func)(void *)) key = (*hash->hash_key)(data); index = key & (hash->size - 1); - for (backet = hash->index[index]; backet != NULL; - backet = backet->next) { - if (backet->key == key && (*hash->hash_cmp)(backet->data, data)) - return backet->data; + for (bucket = hash->index[index]; bucket != NULL; + bucket = bucket->next) { + if (bucket->key == key && (*hash->hash_cmp)(bucket->data, data)) + return bucket->data; } if (alloc_func) { @@ -157,26 +155,26 @@ void *hash_get(struct hash *hash, void *data, void *(*alloc_func)(void *)) index = key & (hash->size - 1); } - backet = XCALLOC(MTYPE_HASH_BACKET, sizeof(struct hash_backet)); - backet->data = newdata; - backet->key = key; - backet->next = hash->index[index]; - hash->index[index] = backet; + bucket = XCALLOC(MTYPE_HASH_BACKET, sizeof(struct hash_bucket)); + bucket->data = newdata; + bucket->key = key; + bucket->next = hash->index[index]; + hash->index[index] = bucket; hash->count++; - int oldlen = backet->next ? backet->next->len : 0; + int oldlen = bucket->next ? bucket->next->len : 0; int newlen = oldlen + 1; if (newlen == 1) hash->stats.empty--; else - backet->next->len = 0; + bucket->next->len = 0; - backet->len = newlen; + bucket->len = newlen; hash_update_ssq(hash, oldlen, newlen); - return backet->data; + return bucket->data; } return NULL; } @@ -201,22 +199,22 @@ void *hash_release(struct hash *hash, void *data) void *ret; unsigned int key; unsigned int index; - struct hash_backet *backet; - struct hash_backet *pp; + struct hash_bucket *bucket; + struct hash_bucket *pp; key = (*hash->hash_key)(data); index = key & (hash->size - 1); - for (backet = pp = hash->index[index]; backet; backet = backet->next) { - if (backet->key == key - && (*hash->hash_cmp)(backet->data, data)) { + for (bucket = pp = hash->index[index]; bucket; bucket = bucket->next) { + if (bucket->key == key + && (*hash->hash_cmp)(bucket->data, data)) { int oldlen = hash->index[index]->len; int newlen = oldlen - 1; - if (backet == pp) - hash->index[index] = backet->next; + if (bucket == pp) + hash->index[index] = bucket->next; else - pp->next = backet->next; + pp->next = bucket->next; if (hash->index[index]) hash->index[index]->len = newlen; @@ -225,26 +223,26 @@ void *hash_release(struct hash *hash, void *data) hash_update_ssq(hash, oldlen, newlen); - ret = backet->data; - XFREE(MTYPE_HASH_BACKET, backet); + ret = bucket->data; + XFREE(MTYPE_HASH_BACKET, bucket); hash->count--; return ret; } - pp = backet; + pp = bucket; } return NULL; } -void hash_iterate(struct hash *hash, void (*func)(struct hash_backet *, void *), +void hash_iterate(struct hash *hash, void (*func)(struct hash_bucket *, void *), void *arg) { unsigned int i; - struct hash_backet *hb; - struct hash_backet *hbnext; + struct hash_bucket *hb; + struct hash_bucket *hbnext; for (i = 0; i < hash->size; i++) for (hb = hash->index[i]; hb; hb = hbnext) { - /* get pointer to next hash backet here, in case (*func) + /* get pointer to next hash bucket here, in case (*func) * decides to delete hb by calling hash_release */ hbnext = hb->next; @@ -252,17 +250,17 @@ void hash_iterate(struct hash *hash, void (*func)(struct hash_backet *, void *), } } -void hash_walk(struct hash *hash, int (*func)(struct hash_backet *, void *), +void hash_walk(struct hash *hash, int (*func)(struct hash_bucket *, void *), void *arg) { unsigned int i; - struct hash_backet *hb; - struct hash_backet *hbnext; + struct hash_bucket *hb; + struct hash_bucket *hbnext; int ret = HASHWALK_CONTINUE; for (i = 0; i < hash->size; i++) { for (hb = hash->index[i]; hb; hb = hbnext) { - /* get pointer to next hash backet here, in case (*func) + /* get pointer to next hash bucket here, in case (*func) * decides to delete hb by calling hash_release */ hbnext = hb->next; @@ -276,8 +274,8 @@ void hash_walk(struct hash *hash, int (*func)(struct hash_backet *, void *), void hash_clean(struct hash *hash, void (*free_func)(void *)) { unsigned int i; - struct hash_backet *hb; - struct hash_backet *next; + struct hash_bucket *hb; + struct hash_bucket *next; for (i = 0; i < hash->size; i++) { for (hb = hash->index[i]; hb; hb = next) { @@ -296,7 +294,7 @@ void hash_clean(struct hash *hash, void (*free_func)(void *)) hash->stats.empty = hash->size; } -static void hash_to_list_iter(struct hash_backet *hb, void *arg) +static void hash_to_list_iter(struct hash_bucket *hb, void *arg) { struct list *list = arg; @@ -324,8 +322,7 @@ void hash_free(struct hash *hash) } pthread_mutex_unlock(&_hashes_mtx); - if (hash->name) - XFREE(MTYPE_HASH, hash->name); + XFREE(MTYPE_HASH, hash->name); XFREE(MTYPE_HASH_INDEX, hash->index); XFREE(MTYPE_HASH, hash); diff --git a/lib/hash.h b/lib/hash.h index 45ae6ce60a..60c412b8e0 100644 --- a/lib/hash.h +++ b/lib/hash.h @@ -24,6 +24,10 @@ #include "memory.h" #include "frratomic.h" +#ifdef __cplusplus +extern "C" { +#endif + DECLARE_MTYPE(HASH) DECLARE_MTYPE(HASH_BACKET) @@ -35,15 +39,20 @@ DECLARE_MTYPE(HASH_BACKET) #define HASHWALK_CONTINUE 0 #define HASHWALK_ABORT -1 -struct hash_backet { +#if CONFDATE > 20200225 +CPP_NOTICE("hash.h: time to remove hash_backet #define") +#endif +#define hash_backet hash_bucket + +struct hash_bucket { /* - * if this backet is the head of the linked listed, len denotes the + * if this bucket is the head of the linked listed, len denotes the * number of elements in the list */ int len; /* Linked list. */ - struct hash_backet *next; + struct hash_bucket *next; /* Hash key. */ unsigned int key; @@ -54,14 +63,14 @@ struct hash_backet { struct hashstats { /* number of empty hash buckets */ - _Atomic uint_fast32_t empty; + atomic_uint_fast32_t empty; /* sum of squares of bucket length */ - _Atomic uint_fast32_t ssq; + atomic_uint_fast32_t ssq; }; struct hash { - /* Hash backet. */ - struct hash_backet **index; + /* Hash bucket. */ + struct hash_bucket **index; /* Hash table size. Must be power of 2 */ unsigned int size; @@ -168,9 +177,9 @@ hash_create_size(unsigned int size, unsigned int (*hash_key)(void *), * hash table to operate on * * data - * data to insert or retrieve - A hash backet will not be created if + * data to insert or retrieve - A hash bucket will not be created if * the alloc_func returns a NULL pointer and nothing will be added to - * the hash. As such backet->data will always be non-NULL. + * the hash. As such bucket->data will always be non-NULL. * * alloc_func * function to call if the item is not found in the hash table. This @@ -239,7 +248,7 @@ extern void *hash_release(struct hash *hash, void *data); * during the walk will cause undefined behavior in that some new entries * will be walked and some will not. So do not do this. * - * The backet passed to func will have a non-NULL data pointer. + * The bucket passed to func will have a non-NULL data pointer. * * hash * hash table to operate on @@ -251,7 +260,7 @@ extern void *hash_release(struct hash *hash, void *data); * arbitrary argument passed as the second parameter in each call to 'func' */ extern void hash_iterate(struct hash *hash, - void (*func)(struct hash_backet *, void *), void *arg); + void (*func)(struct hash_bucket *, void *), void *arg); /* * Iterate over the elements in a hash table, stopping on condition. @@ -261,7 +270,7 @@ extern void hash_iterate(struct hash *hash, * during the walk will cause undefined behavior in that some new entries * will be walked and some will not. So do not do this. * - * The backet passed to func will have a non-NULL data pointer. + * The bucket passed to func will have a non-NULL data pointer. * * hash * hash table to operate on @@ -274,7 +283,7 @@ extern void hash_iterate(struct hash *hash, * arbitrary argument passed as the second parameter in each call to 'func' */ extern void hash_walk(struct hash *hash, - int (*func)(struct hash_backet *, void *), void *arg); + int (*func)(struct hash_bucket *, void *), void *arg); /* * Remove all elements from a hash table. @@ -325,4 +334,8 @@ extern unsigned int string_hash_make(const char *); */ extern void hash_cmd_init(void); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_HASH_H */ diff --git a/lib/hook.h b/lib/hook.h index 96fec97d7e..f7fb7b8a5c 100644 --- a/lib/hook.h +++ b/lib/hook.h @@ -22,6 +22,10 @@ #include "module.h" #include "memory.h" +#ifdef __cplusplus +extern "C" { +#endif + /* type-safe subscribable hook points * * where "type-safe" applies to the function pointers used for subscriptions @@ -219,4 +223,8 @@ extern void _hook_unregister(struct hook *hook, void *funcptr, void *arg, #define DEFINE_KOOH(hookname, arglist, passlist) \ DEFINE_HOOK_INT(hookname, arglist, passlist, true) +#ifdef __cplusplus +} +#endif + #endif /* _FRR_HOOK_H */ diff --git a/lib/id_alloc.h b/lib/id_alloc.h index efe355658a..8705ffb37d 100644 --- a/lib/id_alloc.h +++ b/lib/id_alloc.h @@ -24,6 +24,10 @@ #include <limits.h> #include <stdint.h> +#ifdef __cplusplus +extern "C" { +#endif + #define IDALLOC_INVALID 0 #define IDALLOC_DIR_BITS 8 @@ -87,4 +91,8 @@ uint32_t idalloc_reserve(struct id_alloc *alloc, uint32_t id); struct id_alloc *idalloc_new(const char *name); void idalloc_destroy(struct id_alloc *alloc); +#ifdef __cplusplus +} +#endif + #endif @@ -234,8 +234,7 @@ void if_delete(struct interface *ifp) if_link_params_free(ifp); - if (ifp->desc) - XFREE(MTYPE_TMP, ifp->desc); + XFREE(MTYPE_TMP, ifp->desc); XFREE(MTYPE_IF, ifp); } @@ -709,8 +708,7 @@ void connected_free(struct connected *connected) if (connected->destination) prefix_free(connected->destination); - if (connected->label) - XFREE(MTYPE_CONNECTED_LABEL, connected->label); + XFREE(MTYPE_CONNECTED_LABEL, connected->label); XFREE(MTYPE_CONNECTED, connected); } @@ -1161,7 +1159,7 @@ DEFPY (no_interface, if (!vrfname) vrfname = VRF_DEFAULT_NAME; - nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); return nb_cli_apply_changes( vty, "/frr-interface:lib/interface[name='%s'][vrf='%s']", @@ -1208,7 +1206,7 @@ DEFPY (no_interface_desc, NO_STR "Interface specific description\n") { - nb_cli_enqueue_change(vty, "./description", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, "./description", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); } @@ -1355,8 +1353,7 @@ static int lib_interface_description_modify(enum nb_event event, return NB_OK; ifp = yang_dnode_get_entry(dnode, true); - if (ifp->desc) - XFREE(MTYPE_TMP, ifp->desc); + XFREE(MTYPE_TMP, ifp->desc); description = yang_dnode_get_string(dnode, NULL); ifp->desc = XSTRDUP(MTYPE_TMP, description); @@ -1372,8 +1369,7 @@ static int lib_interface_description_delete(enum nb_event event, return NB_OK; ifp = yang_dnode_get_entry(dnode, true); - if (ifp->desc) - XFREE(MTYPE_TMP, ifp->desc); + XFREE(MTYPE_TMP, ifp->desc); return NB_OK; } @@ -1385,13 +1381,13 @@ const struct frr_yang_module_info frr_interface_info = { { .xpath = "/frr-interface:lib/interface", .cbs.create = lib_interface_create, - .cbs.delete = lib_interface_delete, + .cbs.destroy = lib_interface_delete, .cbs.cli_show = cli_show_interface, }, { .xpath = "/frr-interface:lib/interface/description", .cbs.modify = lib_interface_description_modify, - .cbs.delete = lib_interface_description_delete, + .cbs.destroy = lib_interface_description_delete, .cbs.cli_show = cli_show_interface_desc, }, { @@ -27,6 +27,10 @@ #include "qobj.h" #include "hook.h" +#ifdef __cplusplus +extern "C" { +#endif + DECLARE_MTYPE(IF) DECLARE_MTYPE(CONNECTED_LABEL) @@ -290,9 +294,9 @@ struct interface { }; RB_HEAD(if_name_head, interface); -RB_PROTOTYPE(if_name_head, interface, name_entry, if_cmp_func); +RB_PROTOTYPE(if_name_head, interface, name_entry, if_cmp_func) RB_HEAD(if_index_head, interface); -RB_PROTOTYPE(if_index_head, interface, index_entry, if_cmp_func); +RB_PROTOTYPE(if_index_head, interface, index_entry, if_cmp_func) DECLARE_QOBJ_TYPE(interface) #define IFNAME_RB_INSERT(vrf, ifp) \ @@ -545,4 +549,8 @@ void if_link_params_free(struct interface *); extern void if_cmd_init(void); extern const struct frr_yang_module_info frr_interface_info; +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_IF_H */ diff --git a/lib/if_rmap.c b/lib/if_rmap.c index 69da695dcb..955c1417c4 100644 --- a/lib/if_rmap.c +++ b/lib/if_rmap.c @@ -26,14 +26,12 @@ #include "if.h" #include "if_rmap.h" +DEFINE_MTYPE_STATIC(LIB, IF_RMAP_CTX, "Interface route map container") +DEFINE_MTYPE_STATIC(LIB, IF_RMAP_CTX_NAME, "Interface route map container name") DEFINE_MTYPE_STATIC(LIB, IF_RMAP, "Interface route map") DEFINE_MTYPE_STATIC(LIB, IF_RMAP_NAME, "I.f. route map name") -struct hash *ifrmaphash; - -/* Hook functions. */ -static void (*if_rmap_add_hook)(struct if_rmap *) = NULL; -static void (*if_rmap_delete_hook)(struct if_rmap *) = NULL; +struct list *if_rmap_ctx_list; static struct if_rmap *if_rmap_new(void) { @@ -46,18 +44,15 @@ static struct if_rmap *if_rmap_new(void) static void if_rmap_free(struct if_rmap *if_rmap) { - if (if_rmap->ifname) - XFREE(MTYPE_IF_RMAP_NAME, if_rmap->ifname); + XFREE(MTYPE_IF_RMAP_NAME, if_rmap->ifname); - if (if_rmap->routemap[IF_RMAP_IN]) - XFREE(MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_IN]); - if (if_rmap->routemap[IF_RMAP_OUT]) - XFREE(MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_OUT]); + XFREE(MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_IN]); + XFREE(MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_OUT]); XFREE(MTYPE_IF_RMAP, if_rmap); } -struct if_rmap *if_rmap_lookup(const char *ifname) +struct if_rmap *if_rmap_lookup(struct if_rmap_ctx *ctx, const char *ifname) { struct if_rmap key; struct if_rmap *if_rmap; @@ -65,22 +60,25 @@ struct if_rmap *if_rmap_lookup(const char *ifname) /* temporary copy */ key.ifname = (ifname) ? XSTRDUP(MTYPE_IF_RMAP_NAME, ifname) : NULL; - if_rmap = hash_lookup(ifrmaphash, &key); + if_rmap = hash_lookup(ctx->ifrmaphash, &key); - if (key.ifname) - XFREE(MTYPE_IF_RMAP_NAME, key.ifname); + XFREE(MTYPE_IF_RMAP_NAME, key.ifname); return if_rmap; } -void if_rmap_hook_add(void (*func)(struct if_rmap *)) +void if_rmap_hook_add(struct if_rmap_ctx *ctx, + void (*func)(struct if_rmap_ctx *ctx, + struct if_rmap *)) { - if_rmap_add_hook = func; + ctx->if_rmap_add_hook = func; } -void if_rmap_hook_delete(void (*func)(struct if_rmap *)) +void if_rmap_hook_delete(struct if_rmap_ctx *ctx, + void (*func)(struct if_rmap_ctx *ctx, + struct if_rmap *)) { - if_rmap_delete_hook = func; + ctx->if_rmap_delete_hook = func; } static void *if_rmap_hash_alloc(void *arg) @@ -94,7 +92,7 @@ static void *if_rmap_hash_alloc(void *arg) return if_rmap; } -static struct if_rmap *if_rmap_get(const char *ifname) +static struct if_rmap *if_rmap_get(struct if_rmap_ctx *ctx, const char *ifname) { struct if_rmap key; struct if_rmap *ret; @@ -102,10 +100,9 @@ static struct if_rmap *if_rmap_get(const char *ifname) /* temporary copy */ key.ifname = (ifname) ? XSTRDUP(MTYPE_IF_RMAP_NAME, ifname) : NULL; - ret = hash_get(ifrmaphash, &key, if_rmap_hash_alloc); + ret = hash_get(ctx->ifrmaphash, &key, if_rmap_hash_alloc); - if (key.ifname) - XFREE(MTYPE_IF_RMAP_NAME, key.ifname); + XFREE(MTYPE_IF_RMAP_NAME, key.ifname); return ret; } @@ -125,40 +122,38 @@ static bool if_rmap_hash_cmp(const void *arg1, const void *arg2) return strcmp(if_rmap1->ifname, if_rmap2->ifname) == 0; } -static struct if_rmap *if_rmap_set(const char *ifname, enum if_rmap_type type, +static struct if_rmap *if_rmap_set(struct if_rmap_ctx *ctx, + const char *ifname, enum if_rmap_type type, const char *routemap_name) { struct if_rmap *if_rmap; - if_rmap = if_rmap_get(ifname); + if_rmap = if_rmap_get(ctx, ifname); if (type == IF_RMAP_IN) { - if (if_rmap->routemap[IF_RMAP_IN]) - XFREE(MTYPE_IF_RMAP_NAME, - if_rmap->routemap[IF_RMAP_IN]); + XFREE(MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_IN]); if_rmap->routemap[IF_RMAP_IN] = XSTRDUP(MTYPE_IF_RMAP_NAME, routemap_name); } if (type == IF_RMAP_OUT) { - if (if_rmap->routemap[IF_RMAP_OUT]) - XFREE(MTYPE_IF_RMAP_NAME, - if_rmap->routemap[IF_RMAP_OUT]); + XFREE(MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_OUT]); if_rmap->routemap[IF_RMAP_OUT] = XSTRDUP(MTYPE_IF_RMAP_NAME, routemap_name); } - if (if_rmap_add_hook) - (*if_rmap_add_hook)(if_rmap); + if (ctx->if_rmap_add_hook) + (ctx->if_rmap_add_hook)(ctx, if_rmap); return if_rmap; } -static int if_rmap_unset(const char *ifname, enum if_rmap_type type, +static int if_rmap_unset(struct if_rmap_ctx *ctx, + const char *ifname, enum if_rmap_type type, const char *routemap_name) { struct if_rmap *if_rmap; - if_rmap = if_rmap_lookup(ifname); + if_rmap = if_rmap_lookup(ctx, ifname); if (!if_rmap) return 0; @@ -182,12 +177,12 @@ static int if_rmap_unset(const char *ifname, enum if_rmap_type type, if_rmap->routemap[IF_RMAP_OUT] = NULL; } - if (if_rmap_delete_hook) - (*if_rmap_delete_hook)(if_rmap); + if (ctx->if_rmap_delete_hook) + ctx->if_rmap_delete_hook(ctx, if_rmap); if (if_rmap->routemap[IF_RMAP_IN] == NULL && if_rmap->routemap[IF_RMAP_OUT] == NULL) { - hash_release(ifrmaphash, if_rmap); + hash_release(ctx->ifrmaphash, if_rmap); if_rmap_free(if_rmap); } @@ -207,6 +202,8 @@ DEFUN (if_rmap, int idx_in_out = 2; int idx_ifname = 3; enum if_rmap_type type; + struct if_rmap_ctx *ctx = + (struct if_rmap_ctx *)listnode_head(if_rmap_ctx_list); if (strncmp(argv[idx_in_out]->text, "in", 1) == 0) type = IF_RMAP_IN; @@ -217,7 +214,8 @@ DEFUN (if_rmap, return CMD_WARNING_CONFIG_FAILED; } - if_rmap_set(argv[idx_ifname]->arg, type, argv[idx_rmap_name]->arg); + if_rmap_set(ctx, argv[idx_ifname]->arg, + type, argv[idx_rmap_name]->arg); return CMD_SUCCESS; } @@ -237,6 +235,8 @@ DEFUN (no_if_rmap, int idx_ifname = 4; int ret; enum if_rmap_type type; + struct if_rmap_ctx *ctx = + (struct if_rmap_ctx *)listnode_head(if_rmap_ctx_list); if (strncmp(argv[idx_in_out]->arg, "i", 1) == 0) type = IF_RMAP_IN; @@ -247,7 +247,7 @@ DEFUN (no_if_rmap, return CMD_WARNING_CONFIG_FAILED; } - ret = if_rmap_unset(argv[idx_ifname]->arg, type, + ret = if_rmap_unset(ctx, argv[idx_ifname]->arg, type, argv[idx_routemap_name]->arg); if (!ret) { vty_out(vty, "route-map doesn't exist\n"); @@ -258,11 +258,13 @@ DEFUN (no_if_rmap, /* Configuration write function. */ -int config_write_if_rmap(struct vty *vty) +int config_write_if_rmap(struct vty *vty, + struct if_rmap_ctx *ctx) { unsigned int i; - struct hash_backet *mp; + struct hash_bucket *mp; int write = 0; + struct hash *ifrmaphash = ctx->ifrmaphash; for (i = 0; i < ifrmaphash->size; i++) for (mp = ifrmaphash->index[i]; mp; mp = mp->next) { @@ -287,18 +289,44 @@ int config_write_if_rmap(struct vty *vty) return write; } -void if_rmap_reset(void) +void if_rmap_ctx_delete(struct if_rmap_ctx *ctx) { - hash_clean(ifrmaphash, (void (*)(void *))if_rmap_free); + hash_clean(ctx->ifrmaphash, (void (*)(void *))if_rmap_free); + if (ctx->name) + XFREE(MTYPE_IF_RMAP_CTX_NAME, ctx); + XFREE(MTYPE_IF_RMAP_CTX, ctx); +} + +/* name is optional: either vrf name, or other */ +struct if_rmap_ctx *if_rmap_ctx_create(const char *name) +{ + struct if_rmap_ctx *ctx; + + ctx = XCALLOC(MTYPE_IF_RMAP_CTX, sizeof(struct if_rmap_ctx)); + + if (ctx->name) + ctx->name = XSTRDUP(MTYPE_IF_RMAP_CTX_NAME, name); + ctx->ifrmaphash = hash_create_size(4, if_rmap_hash_make, if_rmap_hash_cmp, + "Interface Route-Map Hash"); + if (!if_rmap_ctx_list) + if_rmap_ctx_list = list_new(); + listnode_add(if_rmap_ctx_list, ctx); + return ctx; } void if_rmap_init(int node) { - ifrmaphash = hash_create_size(4, if_rmap_hash_make, if_rmap_hash_cmp, - "Interface Route-Map Hash"); if (node == RIPNG_NODE) { } else if (node == RIP_NODE) { install_element(RIP_NODE, &if_rmap_cmd); install_element(RIP_NODE, &no_if_rmap_cmd); } + if_rmap_ctx_list = list_new(); +} + +void if_rmap_terminate(void) +{ + if (!if_rmap_ctx_list) + return; + list_delete(&if_rmap_ctx_list); } diff --git a/lib/if_rmap.h b/lib/if_rmap.h index 4468b9fb9c..dfc7298823 100644 --- a/lib/if_rmap.h +++ b/lib/if_rmap.h @@ -21,6 +21,10 @@ #ifndef _ZEBRA_IF_RMAP_H #define _ZEBRA_IF_RMAP_H +#ifdef __cplusplus +extern "C" { +#endif + enum if_rmap_type { IF_RMAP_IN, IF_RMAP_OUT, IF_RMAP_MAX }; struct if_rmap { @@ -30,11 +34,36 @@ struct if_rmap { char *routemap[IF_RMAP_MAX]; }; -extern void if_rmap_init(int); -extern void if_rmap_reset(void); -extern void if_rmap_hook_add(void (*)(struct if_rmap *)); -extern void if_rmap_hook_delete(void (*)(struct if_rmap *)); -extern struct if_rmap *if_rmap_lookup(const char *); -extern int config_write_if_rmap(struct vty *); +struct if_rmap_ctx { + /* if_rmap */ + struct hash *ifrmaphash; + + /* Hook functions. */ + void (*if_rmap_add_hook)(struct if_rmap_ctx *ctx, + struct if_rmap *ifrmap); + void (*if_rmap_delete_hook)(struct if_rmap_ctx *ctx, + struct if_rmap *ifrmap); + + /* naming information */ + char *name; +}; + +extern struct if_rmap_ctx *if_rmap_ctx_create(const char *name); +extern void if_rmap_ctx_delete(struct if_rmap_ctx *ctx); +extern void if_rmap_init(int node); +extern void if_rmap_terminate(void); +void if_rmap_hook_add(struct if_rmap_ctx *ctx, + void (*func)(struct if_rmap_ctx *ctx, + struct if_rmap *)); +void if_rmap_hook_delete(struct if_rmap_ctx *ctx, + void (*func)(struct if_rmap_ctx *ctx, + struct if_rmap *)); +extern struct if_rmap *if_rmap_lookup(struct if_rmap_ctx *ctx, + const char *ifname); +extern int config_write_if_rmap(struct vty *, struct if_rmap_ctx *ctx); + +#ifdef __cplusplus +} +#endif #endif /* _ZEBRA_IF_RMAP_H */ diff --git a/lib/imsg.c b/lib/imsg.c index 935d137727..57e70617d2 100644 --- a/lib/imsg.c +++ b/lib/imsg.c @@ -18,6 +18,7 @@ #include <zebra.h> +#include "memory.h" #include "queue.h" #include "imsg.h" @@ -35,7 +36,7 @@ static int available_fds(unsigned int n) unsigned int i; int ret, fds[256]; - if (n > (sizeof(fds) / sizeof(fds[0]))) + if (n > (unsigned int)array_size(fds)) return (1); ret = 0; diff --git a/lib/imsg.h b/lib/imsg.h index eed7074e4a..3f81b76bea 100644 --- a/lib/imsg.h +++ b/lib/imsg.h @@ -21,6 +21,10 @@ #ifndef _IMSG_H_ #define _IMSG_H_ +#ifdef __cplusplus +extern "C" { +#endif + #define IBUF_READ_SIZE 65535 #define IMSG_HEADER_SIZE sizeof(struct imsg_hdr) #define MAX_IMSGSIZE 16384 @@ -108,4 +112,8 @@ void imsg_free(struct imsg *); int imsg_flush(struct imsgbuf *); void imsg_clear(struct imsgbuf *); +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/ipaddr.h b/lib/ipaddr.h index 7f2d06548b..f4ddadc66e 100644 --- a/lib/ipaddr.h +++ b/lib/ipaddr.h @@ -25,6 +25,10 @@ #include <zebra.h> +#ifdef __cplusplus +extern "C" { +#endif + /* * Generic IP address - union of IPv4 and IPv6 address. */ @@ -112,4 +116,8 @@ static inline void ipv4_mapped_ipv6_to_ipv4(struct in6_addr *in6, memcpy(in, (char *)in6 + 12, sizeof(struct in_addr)); } +#ifdef __cplusplus +} +#endif + #endif /* __IPADDR_H__ */ diff --git a/lib/jhash.c b/lib/jhash.c index cb6946f37e..0d561ef3a4 100644 --- a/lib/jhash.c +++ b/lib/jhash.c @@ -116,7 +116,7 @@ uint32_t jhash(const void *key, uint32_t length, uint32_t initval) /* fallthru */ case 1: a += k[0]; - }; + } __jhash_mix(a, b, c); @@ -151,7 +151,7 @@ uint32_t jhash2(const uint32_t *k, uint32_t length, uint32_t initval) /* fallthru */ case 1: a += k[0]; - }; + } __jhash_mix(a, b, c); diff --git a/lib/jhash.h b/lib/jhash.h index f8ab4209a8..977421495c 100644 --- a/lib/jhash.h +++ b/lib/jhash.h @@ -20,6 +20,10 @@ #ifndef _QUAGGA_JHASH_H #define _QUAGGA_JHASH_H +#ifdef __cplusplus +extern "C" { +#endif + /* The most generic version, hashes an arbitrary sequence * of bytes. No alignment or length assumptions are made about * the input key. @@ -42,4 +46,8 @@ extern uint32_t jhash_3words(uint32_t a, uint32_t b, uint32_t c, extern uint32_t jhash_2words(uint32_t a, uint32_t b, uint32_t initval); extern uint32_t jhash_1word(uint32_t a, uint32_t initval); +#ifdef __cplusplus +} +#endif + #endif /* _QUAGGA_JHASH_H */ diff --git a/lib/json.h b/lib/json.h index d349162304..a5251662be 100644 --- a/lib/json.h +++ b/lib/json.h @@ -21,6 +21,10 @@ #ifndef _QUAGGA_JSON_H #define _QUAGGA_JSON_H +#ifdef __cplusplus +extern "C" { +#endif + #if defined(HAVE_JSON_C_JSON_H) #include <json-c/json.h> @@ -81,4 +85,8 @@ extern void json_object_free(struct json_object *obj); #define JSON_C_TO_STRING_NOSLASHESCAPE (1<<4) #endif +#ifdef __cplusplus +} +#endif + #endif /* _QUAGGA_JSON_H */ diff --git a/lib/keychain.c b/lib/keychain.c index 9aa3ef695f..0a96c4cf0e 100644 --- a/lib/keychain.c +++ b/lib/keychain.c @@ -116,8 +116,7 @@ static struct keychain *keychain_get(const char *name) static void keychain_delete(struct keychain *keychain) { - if (keychain->name) - XFREE(MTYPE_KEYCHAIN, keychain->name); + XFREE(MTYPE_KEYCHAIN, keychain->name); list_delete(&keychain->key); listnode_delete(keychain_list, keychain); @@ -217,8 +216,7 @@ static void key_delete(struct keychain *keychain, struct key *key) { listnode_delete(keychain->key, key); - if (key->string) - XFREE(MTYPE_KEY, key->string); + XFREE(MTYPE_KEY, key->string); key_free(key); } diff --git a/lib/keychain.h b/lib/keychain.h index 49da9ba459..e5cf39f7c6 100644 --- a/lib/keychain.h +++ b/lib/keychain.h @@ -23,6 +23,10 @@ #include "qobj.h" +#ifdef __cplusplus +extern "C" { +#endif + struct keychain { char *name; @@ -57,4 +61,8 @@ extern struct key *key_lookup_for_accept(const struct keychain *, uint32_t); extern struct key *key_match_for_accept(const struct keychain *, const char *); extern struct key *key_lookup_for_send(const struct keychain *); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_KEYCHAIN_H */ diff --git a/lib/lib_errors.h b/lib/lib_errors.h index 86a83df46c..fc405c2098 100644 --- a/lib/lib_errors.h +++ b/lib/lib_errors.h @@ -23,6 +23,10 @@ #include "lib/ferr.h" +#ifdef __cplusplus +extern "C" { +#endif + enum lib_log_refs { EC_LIB_PRIVILEGES = LIB_FERR_START, EC_LIB_VRF_START, @@ -82,4 +86,8 @@ enum lib_log_refs { extern void lib_error_init(void); +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/libfrr.c b/lib/libfrr.c index 9119b04992..1afe30d618 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -61,7 +61,7 @@ static char dbfile_default[512]; #endif static char vtypath_default[256]; -bool debug_memstats_at_exit = 0; +bool debug_memstats_at_exit = false; static bool nodetach_term, nodetach_daemon; static char comb_optstr[256]; diff --git a/lib/libfrr.h b/lib/libfrr.h index 2705397b85..891e2c1282 100644 --- a/lib/libfrr.h +++ b/lib/libfrr.h @@ -30,6 +30,10 @@ #include "hook.h" #include "northbound.h" +#ifdef __cplusplus +extern "C" { +#endif + /* The following options disable specific command line options that * are not applicable for a particular daemon. */ @@ -152,4 +156,8 @@ extern char frr_protonameinst[]; extern bool debug_memstats_at_exit; +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_FRR_H */ diff --git a/lib/libospf.h b/lib/libospf.h index 45aedb6a7d..d2bb29d80e 100644 --- a/lib/libospf.h +++ b/lib/libospf.h @@ -22,6 +22,10 @@ #ifndef _LIBOSPFD_H #define _LIBOSPFD_H +#ifdef __cplusplus +extern "C" { +#endif + /* IP precedence. */ #ifndef IPTOS_PREC_INTERNETCONTROL #define IPTOS_PREC_INTERNETCONTROL 0xC0 @@ -94,4 +98,8 @@ #define OSPF_LSA_MAXAGE_CHECK_INTERVAL 30 #define OSPF_LSA_MAXAGE_REMOVE_DELAY_DEFAULT 60 +#ifdef __cplusplus +} +#endif + #endif /* _LIBOSPFD_H */ diff --git a/lib/linklist.h b/lib/linklist.h index 0475391e9f..76fad45d08 100644 --- a/lib/linklist.h +++ b/lib/linklist.h @@ -21,6 +21,10 @@ #ifndef _ZEBRA_LINKLIST_H #define _ZEBRA_LINKLIST_H +#ifdef __cplusplus +extern "C" { +#endif + /* listnodes must always contain data to be valid. Adding an empty node * to a list is invalid */ @@ -291,7 +295,8 @@ extern void list_add_list(struct list *list, struct list *add); #define ALL_LIST_ELEMENTS(list, node, nextnode, data) \ (node) = listhead(list), ((data) = NULL); \ (node) != NULL \ - && ((data) = listgetdata(node), (nextnode) = node->next, 1); \ + && ((data) = static_cast(data, listgetdata(node)), \ + (nextnode) = node->next, 1); \ (node) = (nextnode), ((data) = NULL) /* read-only list iteration macro. @@ -302,7 +307,7 @@ extern void list_add_list(struct list *list, struct list *add); */ #define ALL_LIST_ELEMENTS_RO(list, node, data) \ (node) = listhead(list), ((data) = NULL); \ - (node) != NULL && ((data) = listgetdata(node), 1); \ + (node) != NULL && ((data) = static_cast(data, listgetdata(node)), 1); \ (node) = listnextnode(node), ((data) = NULL) /* these *do not* cleanup list nodes and referenced data, as the functions @@ -336,4 +341,8 @@ extern void list_add_list(struct list *list, struct list *add); (L)->count--; \ } while (0) +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_LINKLIST_H */ @@ -851,8 +851,7 @@ void closezlog(void) if (zl->fp != NULL) fclose(zl->fp); - if (zl->filename != NULL) - XFREE(MTYPE_ZLOG, zl->filename); + XFREE(MTYPE_ZLOG, zl->filename); XFREE(MTYPE_ZLOG, zl); zlog_default = NULL; @@ -911,8 +910,7 @@ int zlog_reset_file(void) logfile_fd = -1; zl->maxlvl[ZLOG_DEST_FILE] = ZLOG_DISABLED; - if (zl->filename) - XFREE(MTYPE_ZLOG, zl->filename); + XFREE(MTYPE_ZLOG, zl->filename); zl->filename = NULL; pthread_mutex_unlock(&loglock); @@ -29,6 +29,10 @@ #include <stdarg.h> #include "lib/hook.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Hook for external logging function */ DECLARE_HOOK(zebra_ext_log, (int priority, const char *format, va_list args), (priority, format, args)); @@ -93,11 +97,11 @@ extern void zlog_debug(const char *format, ...) PRINTF_ATTRIBUTE(1, 2); /* For logs which have error codes associated with them */ #define flog_err(ferr_id, format, ...) \ - zlog_err("[EC %"PRIu32"] " format, ferr_id, ##__VA_ARGS__) + zlog_err("[EC %" PRIu32 "] " format, ferr_id, ##__VA_ARGS__) #define flog_err_sys(ferr_id, format, ...) \ flog_err(ferr_id, format, ##__VA_ARGS__) #define flog_warn(ferr_id, format, ...) \ - zlog_warn("[EC %"PRIu32"] " format, ferr_id, ##__VA_ARGS__) + zlog_warn("[EC %" PRIu32 "] " format, ferr_id, ##__VA_ARGS__) extern void zlog_thread_info(int log_level); @@ -196,4 +200,8 @@ struct timestamp_control { "Local use\n" \ "Local use\n" +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_LOG_H */ diff --git a/lib/log_int.h b/lib/log_int.h index a7f8be9ae7..58ae031e1b 100644 --- a/lib/log_int.h +++ b/lib/log_int.h @@ -24,6 +24,10 @@ #include "log.h" +#ifdef __cplusplus +extern "C" { +#endif + struct zlog { const char *ident; /* daemon name (first arg to openlog) */ const char *protoname; @@ -49,4 +53,8 @@ extern const char *zlog_priority[]; extern void vzlog(int priority, const char *format, va_list args); extern void zlog(int priority, const char *format, ...) PRINTF_ATTRIBUTE(2, 3); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_LOG_PRIVATE_H */ diff --git a/lib/logicalrouter.h b/lib/logicalrouter.h index 5a0780c009..d18832ef70 100644 --- a/lib/logicalrouter.h +++ b/lib/logicalrouter.h @@ -20,6 +20,10 @@ #ifndef _ZEBRA_LOGICAL_ROUTER_H #define _ZEBRA_LOGICAL_ROUTER_H +#ifdef __cplusplus +extern "C" { +#endif + /* Logical Router Backend defines */ #define LOGICALROUTER_BACKEND_OFF 0 #define LOGICALROUTER_BACKEND_NETNS 1 @@ -38,4 +42,8 @@ extern void logicalrouter_terminate(void); */ extern void logicalrouter_configure_backend(int backend_netns); +#ifdef __cplusplus +} +#endif + #endif /*_ZEBRA_LOGICAL_ROUTER_H*/ @@ -29,6 +29,10 @@ #include <lualib.h> #include <lauxlib.h> +#ifdef __cplusplus +extern "C" { +#endif + /* * These functions are helper functions that * try to glom some of the lua_XXX functionality @@ -75,5 +79,10 @@ enum lua_rm_status lua_run_rm_rule(lua_State *L, const char *rule); */ const char *get_string(lua_State *L, const char *key); int get_integer(lua_State *L, const char *key); + +#ifdef __cplusplus +} +#endif + #endif #endif @@ -38,6 +38,10 @@ #ifndef _LIBZEBRA_MD5_H_ #define _LIBZEBRA_MD5_H_ +#ifdef __cplusplus +extern "C" { +#endif + #define MD5_BUFLEN 64 typedef struct { @@ -82,4 +86,8 @@ extern void md5_result(uint8_t *, md5_ctxt *); void hmac_md5(unsigned char *text, int text_len, unsigned char *key, int key_len, uint8_t *digest); +#ifdef __cplusplus +} +#endif + #endif /* ! _LIBZEBRA_MD5_H_*/ diff --git a/lib/memory.h b/lib/memory.h index 1a0269f8bb..91a02b7966 100644 --- a/lib/memory.h +++ b/lib/memory.h @@ -22,6 +22,10 @@ #include <frratomic.h> #include "compiler.h" +#ifdef __cplusplus +extern "C" { +#endif + #define array_size(ar) (sizeof(ar) / sizeof(ar[0])) #if defined(HAVE_MALLOC_SIZE) && !defined(HAVE_MALLOC_USABLE_SIZE) @@ -33,12 +37,12 @@ struct memtype { struct memtype *next, **ref; const char *name; - _Atomic size_t n_alloc; - _Atomic size_t n_max; - _Atomic size_t size; + atomic_size_t n_alloc; + atomic_size_t n_max; + atomic_size_t size; #ifdef HAVE_MALLOC_USABLE_SIZE - _Atomic size_t total; - _Atomic size_t max_size; + atomic_size_t total; + atomic_size_t max_size; #endif }; @@ -176,4 +180,8 @@ extern int log_memstats(FILE *fp, const char *); extern void memory_oom(size_t size, const char *name); +#ifdef __cplusplus +} +#endif + #endif /* _QUAGGA_MEMORY_H */ diff --git a/lib/memory_vty.h b/lib/memory_vty.h index b66c3b6d6e..941255be1d 100644 --- a/lib/memory_vty.h +++ b/lib/memory_vty.h @@ -23,9 +23,18 @@ #include "memory.h" +#ifdef __cplusplus +extern "C" { +#endif + extern void memory_init(void); /* Human friendly string for given byte count */ #define MTYPE_MEMSTR_LEN 20 extern const char *mtype_memstr(char *, size_t, unsigned long); + +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_MEMORY_VTY_H */ diff --git a/lib/mlag.h b/lib/mlag.h index 73725ca3fd..2b904d44f4 100644 --- a/lib/mlag.h +++ b/lib/mlag.h @@ -22,6 +22,10 @@ #ifndef __MLAG_H__ #define __MLAG_H__ +#ifdef __cplusplus +extern "C" { +#endif + enum mlag_role { MLAG_ROLE_NONE, MLAG_ROLE_PRIMARY, @@ -29,4 +33,9 @@ enum mlag_role { }; extern char *mlag_role2str(enum mlag_role role, char *buf, size_t size); + +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/module.c b/lib/module.c index 6754b94579..098c550684 100644 --- a/lib/module.c +++ b/lib/module.c @@ -141,8 +141,7 @@ struct frrmod_runtime *frrmod_load(const char *spec, const char *dir, char *err, return rtinfo; out_fail: - if (rtinfo->load_args) - XFREE(MTYPE_MODULE_LOADARGS, rtinfo->load_args); + XFREE(MTYPE_MODULE_LOADARGS, rtinfo->load_args); XFREE(MTYPE_MODULE_LOADNAME, rtinfo->load_name); return NULL; } diff --git a/lib/module.h b/lib/module.h index 68ed959270..c5f96db85b 100644 --- a/lib/module.h +++ b/lib/module.h @@ -20,6 +20,10 @@ #include <stdint.h> #include <stdbool.h> +#ifdef __cplusplus +extern "C" { +#endif + #if !defined(__GNUC__) #error module code needs GCC visibility extensions #elif __GNUC__ < 4 @@ -78,9 +82,10 @@ extern union _frrmod_runtime_u _frrmod_this_module; #define FRR_COREMOD_SETUP(...) \ static const struct frrmod_info _frrmod_info = {__VA_ARGS__}; \ - DSO_LOCAL union _frrmod_runtime_u _frrmod_this_module = { \ - .r.info = &_frrmod_info, \ - }; + DSO_LOCAL union _frrmod_runtime_u _frrmod_this_module = {{ \ + NULL, \ + &_frrmod_info, \ + }}; #define FRR_MODULE_SETUP(...) \ FRR_COREMOD_SETUP(__VA_ARGS__) \ DSO_SELF struct frrmod_runtime *frr_module = &_frrmod_this_module.r; @@ -95,4 +100,8 @@ extern struct frrmod_runtime *frrmod_load(const char *spec, const char *dir, extern void frrmod_unload(struct frrmod_runtime *module); #endif +#ifdef __cplusplus +} +#endif + #endif /* _FRR_MODULE_H */ diff --git a/lib/monotime.h b/lib/monotime.h index 00b9400462..6aac966ea1 100644 --- a/lib/monotime.h +++ b/lib/monotime.h @@ -21,6 +21,10 @@ #include <time.h> #include <sys/time.h> +#ifdef __cplusplus +extern "C" { +#endif + #ifndef TIMESPEC_TO_TIMEVAL /* should be in sys/time.h on BSD & Linux libcs */ #define TIMESPEC_TO_TIMEVAL(tv, ts) \ @@ -91,4 +95,8 @@ static inline char *time_to_string(time_t ts) return ctime(&tbuf); } +#ifdef __cplusplus +} +#endif + #endif /* _FRR_MONOTIME_H */ diff --git a/lib/mpls.h b/lib/mpls.h index 6146985610..b140c8e317 100644 --- a/lib/mpls.h +++ b/lib/mpls.h @@ -25,6 +25,10 @@ #include <zebra.h> #include <arpa/inet.h> +#ifdef __cplusplus +extern "C" { +#endif + #ifdef MPLS_LABEL_MAX #undef MPLS_LABEL_MAX #endif @@ -209,4 +213,8 @@ int mpls_str2label(const char *label_str, uint8_t *num_labels, char *mpls_label2str(uint8_t num_labels, mpls_label_t *labels, char *buf, int len, int pretty); +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/netns_linux.c b/lib/netns_linux.c index ef2f5dc953..55c66fdc3d 100644 --- a/lib/netns_linux.c +++ b/lib/netns_linux.c @@ -344,8 +344,7 @@ void ns_delete(struct ns *ns) // if_terminate (&ns->iflist); RB_REMOVE(ns_head, &ns_tree, ns); - if (ns->name) - XFREE(MTYPE_NS_NAME, ns->name); + XFREE(MTYPE_NS_NAME, ns->name); XFREE(MTYPE_NS, ns); } diff --git a/lib/network.h b/lib/network.h index 4703dc9b63..a00c5a0a65 100644 --- a/lib/network.h +++ b/lib/network.h @@ -22,6 +22,10 @@ #ifndef _ZEBRA_NETWORK_H #define _ZEBRA_NETWORK_H +#ifdef __cplusplus +extern "C" { +#endif + /* Both readn and writen are deprecated and will be removed. They are not suitable for use with non-blocking file descriptors. */ @@ -41,4 +45,8 @@ extern int set_cloexec(int fd); extern float htonf(float); extern float ntohf(float); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_NETWORK_H */ diff --git a/lib/nexthop.h b/lib/nexthop.h index e4af405d5f..fd27ca207b 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -26,6 +26,10 @@ #include "prefix.h" #include "mpls.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Maximum next hop string length - gateway + ifindex */ #define NEXTHOP_STRLEN (INET6_ADDRSTRLEN + 30) @@ -79,7 +83,6 @@ struct nexthop { #define NEXTHOP_FLAG_MATCHED (1 << 4) /* Already matched vs a nexthop */ #define NEXTHOP_FLAG_FILTERED (1 << 5) /* rmap filtered, used by static only */ #define NEXTHOP_FLAG_DUPLICATE (1 << 6) /* nexthop duplicates another active one */ -#define NEXTHOP_FLAG_EVPN_RVTEP (1 << 7) /* EVPN remote vtep nexthop */ #define NEXTHOP_IS_ACTIVE(flags) \ (CHECK_FLAG(flags, NEXTHOP_FLAG_ACTIVE) \ && !CHECK_FLAG(flags, NEXTHOP_FLAG_DUPLICATE)) @@ -146,4 +149,9 @@ extern int nexthop_same_firsthop(struct nexthop *next1, struct nexthop *next2); extern const char *nexthop2str(const struct nexthop *nexthop, char *str, int size); extern struct nexthop *nexthop_next(struct nexthop *nexthop); extern unsigned int nexthop_level(struct nexthop *nexthop); + +#ifdef __cplusplus +} +#endif + #endif /*_LIB_NEXTHOP_H */ diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index 23ea96f75c..27ab04279c 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -188,11 +188,25 @@ static int nhgc_cmp_helper(const char *a, const char *b) return strcmp(a, b); } +static int nhgc_addr_cmp_helper(const union sockunion *a, const union sockunion *b) +{ + if (!a && !b) + return 0; + + if (a && !b) + return -1; + + if (!a && b) + return 1; + + return sockunion_cmp(a, b); +} + static int nhgl_cmp(struct nexthop_hold *nh1, struct nexthop_hold *nh2) { int ret; - ret = sockunion_cmp(&nh1->addr, &nh2->addr); + ret = nhgc_addr_cmp_helper(nh1->addr, nh2->addr); if (ret) return ret; @@ -205,11 +219,12 @@ static int nhgl_cmp(struct nexthop_hold *nh1, struct nexthop_hold *nh2) static void nhgl_delete(struct nexthop_hold *nh) { - if (nh->intf) - XFREE(MTYPE_TMP, nh->intf); + XFREE(MTYPE_TMP, nh->intf); - if (nh->nhvrf_name) - XFREE(MTYPE_TMP, nh->nhvrf_name); + XFREE(MTYPE_TMP, nh->nhvrf_name); + + if (nh->addr) + sockunion_free(nh->addr); XFREE(MTYPE_TMP, nh); } @@ -294,8 +309,8 @@ static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc, nh->nhvrf_name = XSTRDUP(MTYPE_TMP, nhvrf_name); if (intf) nh->intf = XSTRDUP(MTYPE_TMP, intf); - - nh->addr = *addr; + if (addr) + nh->addr = sockunion_dup(addr); listnode_add_sort(nhgc->nhg_list, nh); } @@ -310,7 +325,7 @@ static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc, for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) { if (nhgc_cmp_helper(nhvrf_name, nh->nhvrf_name) == 0 && - sockunion_cmp(addr, &nh->addr) == 0 && + nhgc_addr_cmp_helper(addr, nh->addr) == 0 && nhgc_cmp_helper(intf, nh->intf) == 0) break; } @@ -322,13 +337,7 @@ static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc, return; list_delete_node(nhgc->nhg_list, node); - - if (nh->nhvrf_name) - XFREE(MTYPE_TMP, nh->nhvrf_name); - if (nh->intf) - XFREE(MTYPE_TMP, nh->intf); - - XFREE(MTYPE_TMP, nh); + nhgl_delete(nh); } static bool nexthop_group_parse_nexthop(struct nexthop *nhop, @@ -349,36 +358,45 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop, nhop->vrf_id = vrf->vrf_id; - if (addr->sa.sa_family == AF_INET) { - nhop->gate.ipv4.s_addr = addr->sin.sin_addr.s_addr; - if (intf) { - nhop->type = NEXTHOP_TYPE_IPV4_IFINDEX; - nhop->ifindex = ifname2ifindex(intf, vrf->vrf_id); - if (nhop->ifindex == IFINDEX_INTERNAL) - return false; - } else - nhop->type = NEXTHOP_TYPE_IPV4; - } else { - memcpy(&nhop->gate.ipv6, &addr->sin6.sin6_addr, 16); - if (intf) { - nhop->type = NEXTHOP_TYPE_IPV6_IFINDEX; - nhop->ifindex = ifname2ifindex(intf, vrf->vrf_id); - if (nhop->ifindex == IFINDEX_INTERNAL) - return false; - } else - nhop->type = NEXTHOP_TYPE_IPV6; + if (intf) { + nhop->ifindex = ifname2ifindex(intf, vrf->vrf_id); + if (nhop->ifindex == IFINDEX_INTERNAL) + return false; } + if (addr) { + if (addr->sa.sa_family == AF_INET) { + nhop->gate.ipv4.s_addr = addr->sin.sin_addr.s_addr; + if (intf) + nhop->type = NEXTHOP_TYPE_IPV4_IFINDEX; + else + nhop->type = NEXTHOP_TYPE_IPV4; + } else { + nhop->gate.ipv6 = addr->sin6.sin6_addr; + if (intf) + nhop->type = NEXTHOP_TYPE_IPV6_IFINDEX; + else + nhop->type = NEXTHOP_TYPE_IPV6; + } + } else + nhop->type = NEXTHOP_TYPE_IFINDEX; + return true; } DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, - "[no] nexthop <A.B.C.D|X:X::X:X>$addr [INTERFACE]$intf [nexthop-vrf NAME$name]", + "[no] nexthop\ + <\ + <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\ + |INTERFACE$intf\ + >\ + [nexthop-vrf NAME$name]", NO_STR "Specify one of the nexthops in this ECMP group\n" "v4 Address\n" "v6 Address\n" "Interface to use\n" + "Interface to use\n" "If the nexthop is in a different vrf tell us\n" "The nexthop-vrf Name\n") { @@ -387,13 +405,6 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, struct nexthop *nh; bool legal; - /* - * This is impossible to happen as that the cli parser refuses - * to let you get here without an addr, but the SA system - * does not understand this intricacy - */ - assert(addr); - legal = nexthop_group_parse_nexthop(&nhop, addr, intf, name); if (nhop.type == NEXTHOP_TYPE_IPV6 @@ -482,9 +493,10 @@ static void nexthop_group_write_nexthop_internal(struct vty *vty, { char buf[100]; - vty_out(vty, "nexthop "); + vty_out(vty, "nexthop"); - vty_out(vty, "%s", sockunion2str(&nh->addr, buf, sizeof(buf))); + if (nh->addr) + vty_out(vty, " %s", sockunion2str(nh->addr, buf, sizeof(buf))); if (nh->intf) vty_out(vty, " %s", nh->intf); @@ -506,7 +518,7 @@ static int nexthop_group_write(struct vty *vty) vty_out(vty, "nexthop-group %s\n", nhgc->name); for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) { - vty_out(vty, " "); + vty_out(vty, " "); nexthop_group_write_nexthop_internal(vty, nh); } @@ -528,7 +540,7 @@ void nexthop_group_enable_vrf(struct vrf *vrf) struct nexthop nhop; struct nexthop *nh; - if (!nexthop_group_parse_nexthop(&nhop, &nhh->addr, + if (!nexthop_group_parse_nexthop(&nhop, nhh->addr, nhh->intf, nhh->nhvrf_name)) continue; @@ -564,7 +576,7 @@ void nexthop_group_disable_vrf(struct vrf *vrf) struct nexthop nhop; struct nexthop *nh; - if (!nexthop_group_parse_nexthop(&nhop, &nhh->addr, + if (!nexthop_group_parse_nexthop(&nhop, nhh->addr, nhh->intf, nhh->nhvrf_name)) continue; @@ -602,7 +614,7 @@ void nexthop_group_interface_state_change(struct interface *ifp, struct nexthop nhop; if (!nexthop_group_parse_nexthop( - &nhop, &nhh->addr, nhh->intf, + &nhop, nhh->addr, nhh->intf, nhh->nhvrf_name)) continue; diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h index 473ecb34fc..c6e290eeea 100644 --- a/lib/nexthop_group.h +++ b/lib/nexthop_group.h @@ -23,6 +23,10 @@ #include <vty.h> +#ifdef __cplusplus +extern "C" { +#endif + /* * What is a nexthop group? * @@ -64,7 +68,7 @@ void copy_nexthops(struct nexthop **tnh, struct nexthop *nh, struct nexthop_hold { char *nhvrf_name; - union sockunion addr; + union sockunion *addr; char *intf; }; @@ -92,12 +96,12 @@ DECLARE_QOBJ_TYPE(nexthop_group_cmd) * code */ void nexthop_group_init( - void (*new)(const char *name), + void (*create)(const char *name), void (*add_nexthop)(const struct nexthop_group_cmd *nhgc, const struct nexthop *nhop), void (*del_nexthop)(const struct nexthop_group_cmd *nhgc, const struct nexthop *nhop), - void (*delete)(const char *name)); + void (*destroy)(const char *name)); void nexthop_group_enable_vrf(struct vrf *vrf); void nexthop_group_disable_vrf(struct vrf *vrf); @@ -110,4 +114,9 @@ extern struct nexthop *nexthop_exists(struct nexthop_group *nhg, extern struct nexthop_group_cmd *nhgc_find(const char *name); extern void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh); + +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/northbound.c b/lib/northbound.c index 6fe612d72a..edf7e0eca6 100644 --- a/lib/northbound.c +++ b/lib/northbound.c @@ -184,8 +184,8 @@ static unsigned int nb_node_validate_cbs(const struct nb_node *nb_node) !!nb_node->cbs.create, false); error += nb_node_validate_cb(nb_node, NB_OP_MODIFY, !!nb_node->cbs.modify, false); - error += nb_node_validate_cb(nb_node, NB_OP_DELETE, - !!nb_node->cbs.delete, false); + error += nb_node_validate_cb(nb_node, NB_OP_DESTROY, + !!nb_node->cbs.destroy, false); error += nb_node_validate_cb(nb_node, NB_OP_MOVE, !!nb_node->cbs.move, false); error += nb_node_validate_cb(nb_node, NB_OP_APPLY_FINISH, @@ -348,39 +348,58 @@ static void nb_config_diff_del_changes(struct nb_config_cbs *changes) * configurations. Given a new subtree, calculate all new YANG data nodes, * excluding default leafs and leaf-lists. This is a recursive function. */ -static void nb_config_diff_new_subtree(const struct lyd_node *dnode, - struct nb_config_cbs *changes) +static void nb_config_diff_created(const struct lyd_node *dnode, + struct nb_config_cbs *changes) { + enum nb_operation operation; struct lyd_node *child; - LY_TREE_FOR (dnode->child, child) { - enum nb_operation operation; + switch (dnode->schema->nodetype) { + case LYS_LEAF: + case LYS_LEAFLIST: + if (lyd_wd_default((struct lyd_node_leaf_list *)dnode)) + break; - switch (child->schema->nodetype) { - case LYS_LEAF: - case LYS_LEAFLIST: - if (lyd_wd_default((struct lyd_node_leaf_list *)child)) - break; + if (nb_operation_is_valid(NB_OP_CREATE, dnode->schema)) + operation = NB_OP_CREATE; + else if (nb_operation_is_valid(NB_OP_MODIFY, dnode->schema)) + operation = NB_OP_MODIFY; + else + return; - if (nb_operation_is_valid(NB_OP_CREATE, child->schema)) - operation = NB_OP_CREATE; - else if (nb_operation_is_valid(NB_OP_MODIFY, - child->schema)) - operation = NB_OP_MODIFY; - else - continue; + nb_config_diff_add_change(changes, operation, dnode); + break; + case LYS_CONTAINER: + case LYS_LIST: + if (nb_operation_is_valid(NB_OP_CREATE, dnode->schema)) + nb_config_diff_add_change(changes, NB_OP_CREATE, dnode); - nb_config_diff_add_change(changes, operation, child); - break; - case LYS_CONTAINER: - case LYS_LIST: - if (nb_operation_is_valid(NB_OP_CREATE, child->schema)) - nb_config_diff_add_change(changes, NB_OP_CREATE, - child); - nb_config_diff_new_subtree(child, changes); - break; - default: - break; + /* Process child nodes recursively. */ + LY_TREE_FOR (dnode->child, child) { + nb_config_diff_created(child, changes); + } + break; + default: + break; + } +} + +static void nb_config_diff_deleted(const struct lyd_node *dnode, + struct nb_config_cbs *changes) +{ + if (nb_operation_is_valid(NB_OP_DESTROY, dnode->schema)) + nb_config_diff_add_change(changes, NB_OP_DESTROY, dnode); + else if (CHECK_FLAG(dnode->schema->nodetype, LYS_CONTAINER)) { + struct lyd_node *child; + + /* + * Non-presence containers need special handling since they + * don't have "destroy" callbacks. In this case, what we need to + * do is to call the "destroy" callbacks of their child nodes + * when applicable (i.e. optional nodes). + */ + LY_TREE_FOR (dnode->child, child) { + nb_config_diff_deleted(child, changes); } } } @@ -399,42 +418,27 @@ static void nb_config_diff(const struct nb_config *config1, for (int i = 0; diff->type[i] != LYD_DIFF_END; i++) { LYD_DIFFTYPE type; struct lyd_node *dnode; - enum nb_operation operation; type = diff->type[i]; switch (type) { case LYD_DIFF_CREATED: dnode = diff->second[i]; - - if (nb_operation_is_valid(NB_OP_CREATE, dnode->schema)) - operation = NB_OP_CREATE; - else if (nb_operation_is_valid(NB_OP_MODIFY, - dnode->schema)) - operation = NB_OP_MODIFY; - else - continue; + nb_config_diff_created(dnode, changes); break; case LYD_DIFF_DELETED: dnode = diff->first[i]; - operation = NB_OP_DELETE; + nb_config_diff_deleted(dnode, changes); break; case LYD_DIFF_CHANGED: dnode = diff->second[i]; - operation = NB_OP_MODIFY; + nb_config_diff_add_change(changes, NB_OP_MODIFY, dnode); break; case LYD_DIFF_MOVEDAFTER1: case LYD_DIFF_MOVEDAFTER2: default: continue; } - - nb_config_diff_add_change(changes, operation, dnode); - - if (type == LYD_DIFF_CREATED - && CHECK_FLAG(dnode->schema->nodetype, - LYS_CONTAINER | LYS_LIST)) - nb_config_diff_new_subtree(dnode, changes); } lyd_free_diff(diff); @@ -485,7 +489,7 @@ int nb_candidate_edit(struct nb_config *candidate, lyd_validate(&dnode, LYD_OPT_CONFIG, ly_native_ctx); } break; - case NB_OP_DELETE: + case NB_OP_DESTROY: dnode = yang_dnode_get(candidate->dnode, xpath_edit); if (!dnode) /* @@ -741,8 +745,8 @@ static int nb_configuration_callback(const enum nb_event event, case NB_OP_MODIFY: ret = (*nb_node->cbs.modify)(event, dnode, resource); break; - case NB_OP_DELETE: - ret = (*nb_node->cbs.delete)(event, dnode); + case NB_OP_DESTROY: + ret = (*nb_node->cbs.destroy)(event, dnode); break; case NB_OP_MOVE: ret = (*nb_node->cbs.move)(event, dnode); @@ -912,7 +916,7 @@ static void nb_transaction_apply_finish(struct nb_transaction *transaction) * (the 'apply_finish' callbacks from the node ancestors should * be called though). */ - if (change->cb.operation == NB_OP_DELETE) { + if (change->cb.operation == NB_OP_DESTROY) { char xpath[XPATH_MAXLEN]; dnode = dnode->parent; @@ -1359,7 +1363,7 @@ bool nb_operation_is_valid(enum nb_operation operation, return false; } return true; - case NB_OP_DELETE: + case NB_OP_DESTROY: if (!CHECK_FLAG(snode->flags, LYS_CONFIG_W)) return false; @@ -1511,8 +1515,8 @@ const char *nb_operation_name(enum nb_operation operation) return "create"; case NB_OP_MODIFY: return "modify"; - case NB_OP_DELETE: - return "delete"; + case NB_OP_DESTROY: + return "destroy"; case NB_OP_MOVE: return "move"; case NB_OP_APPLY_FINISH: diff --git a/lib/northbound.h b/lib/northbound.h index 9d35a4e64a..bb6b62af7d 100644 --- a/lib/northbound.h +++ b/lib/northbound.h @@ -27,6 +27,10 @@ #include "yang.h" #include "yang_translator.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Forward declaration(s). */ struct vty; @@ -65,7 +69,7 @@ enum nb_event { enum nb_operation { NB_OP_CREATE, NB_OP_MODIFY, - NB_OP_DELETE, + NB_OP_DESTROY, NB_OP_MOVE, NB_OP_APPLY_FINISH, NB_OP_GET_ELEM, @@ -168,7 +172,7 @@ struct nb_callbacks { * - NB_ERR_INCONSISTENCY when an inconsistency was detected. * - NB_ERR for other errors. */ - int (*delete)(enum nb_event event, const struct lyd_node *dnode); + int (*destroy)(enum nb_event event, const struct lyd_node *dnode); /* * Configuration callback. @@ -839,4 +843,8 @@ extern void nb_init(struct thread_master *tm, const struct frr_yang_module_info */ extern void nb_terminate(void); +#ifdef __cplusplus +} +#endif + #endif /* _FRR_NORTHBOUND_H_ */ diff --git a/lib/northbound_cli.h b/lib/northbound_cli.h index 884f250941..209239ca63 100644 --- a/lib/northbound_cli.h +++ b/lib/northbound_cli.h @@ -22,6 +22,10 @@ #include "northbound.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Possible formats in which a configuration can be displayed. */ enum nb_cfg_format { NB_CFG_FMT_CMDS = 0, @@ -111,4 +115,8 @@ extern void nb_cli_install_default(int node); extern void nb_cli_init(struct thread_master *tm); extern void nb_cli_terminate(void); +#ifdef __cplusplus +} +#endif + #endif /* _FRR_NORTHBOUND_CLI_H_ */ diff --git a/lib/northbound_confd.c b/lib/northbound_confd.c index 53149d0fd2..a499d48c12 100644 --- a/lib/northbound_confd.c +++ b/lib/northbound_confd.c @@ -228,7 +228,7 @@ frr_confd_cdb_diff_iter(confd_hkeypath_t *kp, enum cdb_iter_op cdb_op, nb_op = NB_OP_CREATE; break; case MOP_DELETED: - nb_op = NB_OP_DELETE; + nb_op = NB_OP_DESTROY; break; case MOP_VALUE_SET: if (nb_operation_is_valid(NB_OP_MODIFY, nb_node->snode)) @@ -1383,7 +1383,7 @@ error: static int frr_confd_finish(void) { - if (confd_connected == false) + if (!confd_connected) return 0; frr_confd_finish_cdb(); diff --git a/lib/northbound_db.h b/lib/northbound_db.h index ad60966441..14df09caa3 100644 --- a/lib/northbound_db.h +++ b/lib/northbound_db.h @@ -22,6 +22,10 @@ #include "northbound.h" +#ifdef __cplusplus +extern "C" { +#endif + /* * Initialize the northbound database. * @@ -101,4 +105,8 @@ extern int nb_db_transactions_iterate( const char *date, const char *comment), void *arg); +#ifdef __cplusplus +} +#endif + #endif /* _FRR_NORTHBOUND_DB_H_ */ diff --git a/lib/northbound_sysrepo.c b/lib/northbound_sysrepo.c index 860c27edbd..f426f52bd9 100644 --- a/lib/northbound_sysrepo.c +++ b/lib/northbound_sysrepo.c @@ -202,10 +202,10 @@ static int frr_sr_process_change(struct nb_config *candidate, * notified about the removal of all of its leafs, even the ones * that are non-optional. We need to ignore these notifications. */ - if (!nb_operation_is_valid(NB_OP_DELETE, nb_node->snode)) + if (!nb_operation_is_valid(NB_OP_DESTROY, nb_node->snode)) return NB_OK; - nb_op = NB_OP_DELETE; + nb_op = NB_OP_DESTROY; break; case SR_OP_MOVED: nb_op = NB_OP_MOVE; @@ -26,6 +26,10 @@ #include "linklist.h" #include "vty.h" +#ifdef __cplusplus +extern "C" { +#endif + typedef uint32_t ns_id_t; /* the default NS ID */ @@ -174,4 +178,8 @@ extern int ns_enable(struct ns *ns, void (*func)(ns_id_t, void *)); extern struct ns *ns_get_created(struct ns *ns, char *name, ns_id_t ns_id); extern void ns_disable(struct ns *ns); +#ifdef __cplusplus +} +#endif + #endif /*_ZEBRA_NS_H*/ diff --git a/lib/openbsd-queue.h b/lib/openbsd-queue.h index e09cc3d4e5..d4c08a3be8 100644 --- a/lib/openbsd-queue.h +++ b/lib/openbsd-queue.h @@ -35,6 +35,10 @@ #ifndef _SYS_QUEUE_H_ #define _SYS_QUEUE_H_ +#ifdef __cplusplus +extern "C" { +#endif + /* * This file defines five types of data structures: singly-linked lists, * lists, simple queues, tail queues and XOR simple queues. @@ -572,4 +576,8 @@ } \ } while (0) +#ifdef __cplusplus +} +#endif + #endif /* !_SYS_QUEUE_H_ */ diff --git a/lib/openbsd-tree.h b/lib/openbsd-tree.h index 1383ef6de0..d2f0781333 100644 --- a/lib/openbsd-tree.h +++ b/lib/openbsd-tree.h @@ -27,6 +27,10 @@ #ifndef _SYS_TREE_H_ #define _SYS_TREE_H_ +#ifdef __cplusplus +extern "C" { +#endif + /* * This file defines data structures for different types of trees: * splay trees and red-black trees. @@ -397,31 +401,36 @@ 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 _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 _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) \ { \ - return _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) \ { \ - return _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) \ { \ - return _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( \ @@ -433,43 +442,45 @@ int _rb_check(const struct rb_type *, void *, unsigned long); __attribute__((__unused__)) static inline struct _type \ *_name##_RB_MIN(struct _name *head) \ { \ - return _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) \ { \ - return _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 \ *_name##_RB_NEXT(struct _type *elm) \ { \ - return _rb_next(_name##_RB_TYPE, elm); \ + return (struct _type *)_rb_next(_name##_RB_TYPE, elm); \ } \ \ __attribute__((__unused__)) static inline struct _type \ *_name##_RB_PREV(struct _type *elm) \ { \ - return _rb_prev(_name##_RB_TYPE, elm); \ + return (struct _type *)_rb_prev(_name##_RB_TYPE, elm); \ } \ \ __attribute__((__unused__)) static inline struct _type \ *_name##_RB_LEFT(struct _type *elm) \ { \ - return _rb_left(_name##_RB_TYPE, elm); \ + return (struct _type *)_rb_left(_name##_RB_TYPE, elm); \ } \ \ __attribute__((__unused__)) static inline struct _type \ *_name##_RB_RIGHT(struct _type *elm) \ { \ - return _rb_right(_name##_RB_TYPE, elm); \ + return (struct _type *)_rb_right(_name##_RB_TYPE, elm); \ } \ \ __attribute__((__unused__)) static inline struct _type \ *_name##_RB_PARENT(struct _type *elm) \ { \ - return _rb_parent(_name##_RB_TYPE, elm); \ + return (struct _type *)_rb_parent(_name##_RB_TYPE, elm); \ } \ \ __attribute__((__unused__)) static inline void _name##_RB_SET_LEFT( \ @@ -560,4 +571,8 @@ int _rb_check(const struct rb_type *, void *, unsigned long); for ((_e) = RB_MAX(_name, (_head)); \ (_e) != NULL && ((_n) = RB_PREV(_name, (_e)), 1); (_e) = (_n)) +#ifdef __cplusplus +} +#endif + #endif /* _SYS_TREE_H_ */ @@ -24,6 +24,10 @@ #include "stream.h" #include "prefix.h" +#ifdef __cplusplus +extern "C" { +#endif + #define PBR_STR "Policy Based Routing\n" /* @@ -121,4 +125,8 @@ struct pbr_rule { extern int zapi_pbr_rule_encode(uint8_t cmd, struct stream *s, struct pbr_rule *zrule); +#ifdef __cplusplus +} +#endif + #endif /* _PBR_H */ diff --git a/lib/plist.c b/lib/plist.c index 41c8e4f8c0..2a97e1e5b2 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -326,8 +326,7 @@ static void prefix_list_delete(struct prefix_list *plist) else list->head = plist->next; - if (plist->desc) - XFREE(MTYPE_TMP, plist->desc); + XFREE(MTYPE_TMP, plist->desc); /* Make sure master's recent changed prefix-list information is cleared. */ @@ -338,8 +337,7 @@ static void prefix_list_delete(struct prefix_list *plist) if (master->delete_hook) (*master->delete_hook)(plist); - if (plist->name) - XFREE(MTYPE_MPREFIX_LIST_STR, plist->name); + XFREE(MTYPE_MPREFIX_LIST_STR, plist->name); XFREE(MTYPE_PREFIX_LIST_TRIE, plist->trie); diff --git a/lib/plist.h b/lib/plist.h index 8a4fa8d3ce..ba2846d74a 100644 --- a/lib/plist.h +++ b/lib/plist.h @@ -27,6 +27,10 @@ #include "stream.h" #include "vty.h" +#ifdef __cplusplus +extern "C" { +#endif + enum prefix_list_type { PREFIX_DENY, PREFIX_PERMIT, @@ -75,4 +79,8 @@ extern void prefix_bgp_orf_remove_all(afi_t, char *); extern int prefix_bgp_show_prefix_list(struct vty *vty, afi_t afi, char *name, bool use_json); +#ifdef __cplusplus +} +#endif + #endif /* _QUAGGA_PLIST_H */ diff --git a/lib/plist_int.h b/lib/plist_int.h index 6bc2d034d6..443b0c614d 100644 --- a/lib/plist_int.h +++ b/lib/plist_int.h @@ -22,6 +22,10 @@ #ifndef _QUAGGA_PLIST_INT_H #define _QUAGGA_PLIST_INT_H +#ifdef __cplusplus +extern "C" { +#endif + enum prefix_name_type { PREFIX_TYPE_STRING, PREFIX_TYPE_NUMBER }; struct pltrie_table; @@ -68,4 +72,8 @@ struct prefix_list_entry { struct prefix_list_entry *next_best; }; +#ifdef __cplusplus +} +#endif + #endif /* _QUAGGA_PLIST_INT_H */ diff --git a/lib/pqueue.c b/lib/pqueue.c index 1565de216e..87b54a681a 100644 --- a/lib/pqueue.c +++ b/lib/pqueue.c @@ -133,8 +133,6 @@ static int pqueue_expand(struct pqueue *queue) newarray = XCALLOC(MTYPE_PQUEUE_DATA, queue->array_size * DATA_SIZE * 2); - if (newarray == NULL) - return 0; memcpy(newarray, queue->array, queue->array_size * DATA_SIZE); diff --git a/lib/pqueue.h b/lib/pqueue.h index 53e5aa8332..032ee9db4c 100644 --- a/lib/pqueue.h +++ b/lib/pqueue.h @@ -21,6 +21,10 @@ #ifndef _ZEBRA_PQUEUE_H #define _ZEBRA_PQUEUE_H +#ifdef __cplusplus +extern "C" { +#endif + struct pqueue { void **array; int array_size; @@ -43,4 +47,8 @@ extern void pqueue_remove(void *data, struct pqueue *queue); extern void trickle_down(int index, struct pqueue *queue); extern void trickle_up(int index, struct pqueue *queue); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_PQUEUE_H */ diff --git a/lib/prefix.c b/lib/prefix.c index babd4304d1..52bb266f11 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -866,7 +866,7 @@ int str2prefix_ipv4(const char *str, struct prefix_ipv4 *p) return ret; } else { cp = XMALLOC(MTYPE_TMP, (pnt - str) + 1); - strncpy(cp, str, pnt - str); + memcpy(cp, str, pnt - str); *(cp + (pnt - str)) = '\0'; ret = inet_aton(cp, &p->prefix); XFREE(MTYPE_TMP, cp); @@ -913,7 +913,7 @@ int str2prefix_eth(const char *str, struct prefix_eth *p) } cp = XMALLOC(MTYPE_TMP, (pnt - str) + 1); - strncpy(cp, str, pnt - str); + memcpy(cp, str, pnt - str); *(cp + (pnt - str)) = '\0'; str_addr = cp; @@ -944,8 +944,7 @@ int str2prefix_eth(const char *str, struct prefix_eth *p) ret = 1; done: - if (cp) - XFREE(MTYPE_TMP, cp); + XFREE(MTYPE_TMP, cp); return ret; } @@ -1030,7 +1029,7 @@ int str2prefix_ipv6(const char *str, struct prefix_ipv6 *p) int plen; cp = XMALLOC(MTYPE_TMP, (pnt - str) + 1); - strncpy(cp, str, pnt - str); + memcpy(cp, str, pnt - str); *(cp + (pnt - str)) = '\0'; ret = inet_pton(AF_INET6, cp, &p->prefix); XFREE(MTYPE_TMP, cp); @@ -1503,8 +1502,7 @@ char *prefix_mac2str(const struct ethaddr *mac, char *buf, int size) if (!mac) return NULL; if (!buf) - ptr = (char *)XMALLOC(MTYPE_TMP, - ETHER_ADDR_STRLEN * sizeof(char)); + ptr = XMALLOC(MTYPE_TMP, ETHER_ADDR_STRLEN * sizeof(char)); else { assert(size >= ETHER_ADDR_STRLEN); ptr = buf; @@ -1585,8 +1583,7 @@ char *esi_to_str(const esi_t *esi, char *buf, int size) if (!esi) return NULL; if (!buf) - ptr = (char *)XMALLOC(MTYPE_TMP, - ESI_STR_LEN * sizeof(char)); + ptr = XMALLOC(MTYPE_TMP, ESI_STR_LEN * sizeof(char)); else { assert(size >= ESI_STR_LEN); ptr = buf; diff --git a/lib/prefix.h b/lib/prefix.h index aaffb1e0c5..ae931288c0 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -35,6 +35,10 @@ #include "ipaddr.h" #include "compiler.h" +#ifdef __cplusplus +extern "C" { +#endif + #ifndef ETH_ALEN #define ETH_ALEN 6 #endif @@ -276,20 +280,29 @@ struct prefix_sg { * side, which strips type safety since the cast will accept any pointer * type.) */ +#ifndef __cplusplus +#define prefixtype(uname, typename, fieldname) \ + typename *fieldname; +#else +#define prefixtype(uname, typename, fieldname) \ + typename *fieldname; \ + uname(typename *x) { this->fieldname = x; } +#endif + union prefixptr { - struct prefix *p; - struct prefix_ipv4 *p4; - struct prefix_ipv6 *p6; - struct prefix_evpn *evp; - const struct prefix_fs *fs; + prefixtype(prefixptr, struct prefix, p) + prefixtype(prefixptr, struct prefix_ipv4, p4) + prefixtype(prefixptr, struct prefix_ipv6, p6) + prefixtype(prefixptr, struct prefix_evpn, evp) + prefixtype(prefixptr, struct prefix_fs, fs) } __attribute__((transparent_union)); union prefixconstptr { - const struct prefix *p; - const struct prefix_ipv4 *p4; - const struct prefix_ipv6 *p6; - const struct prefix_evpn *evp; - const struct prefix_fs *fs; + prefixtype(prefixconstptr, const struct prefix, p) + prefixtype(prefixconstptr, const struct prefix_ipv4, p4) + prefixtype(prefixconstptr, const struct prefix_ipv6, p6) + prefixtype(prefixconstptr, const struct prefix_evpn, evp) + prefixtype(prefixconstptr, const struct prefix_fs, fs) } __attribute__((transparent_union)); #ifndef INET_ADDRSTRLEN @@ -497,4 +510,9 @@ static inline int is_host_route(struct prefix *p) return (p->prefixlen == IPV6_MAX_BITLEN); return 0; } + +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_PREFIX_H */ diff --git a/lib/privs.c b/lib/privs.c index 838ff8fc92..59f24afe4a 100644 --- a/lib/privs.c +++ b/lib/privs.c @@ -706,13 +706,21 @@ struct zebra_privs_t *_zprivs_raise(struct zebra_privs_t *privs, if (!privs) return NULL; - errno = 0; - if (privs->change(ZPRIVS_RAISE)) { - zlog_err("%s: Failed to raise privileges (%s)", - funcname, safe_strerror(errno)); + /* If we're already elevated, just return */ + pthread_mutex_lock(&(privs->mutex)); + { + if (++(privs->refcount) == 1) { + errno = 0; + if (privs->change(ZPRIVS_RAISE)) { + zlog_err("%s: Failed to raise privileges (%s)", + funcname, safe_strerror(errno)); + } + errno = save_errno; + privs->raised_in_funcname = funcname; + } } - errno = save_errno; - privs->raised_in_funcname = funcname; + pthread_mutex_unlock(&(privs->mutex)); + return privs; } @@ -723,13 +731,22 @@ void _zprivs_lower(struct zebra_privs_t **privs) if (!*privs) return; - errno = 0; - if ((*privs)->change(ZPRIVS_LOWER)) { - zlog_err("%s: Failed to lower privileges (%s)", - (*privs)->raised_in_funcname, safe_strerror(errno)); + /* Don't lower privs if there's another caller */ + pthread_mutex_lock(&(*privs)->mutex); + { + if (--((*privs)->refcount) == 0) { + errno = 0; + if ((*privs)->change(ZPRIVS_LOWER)) { + zlog_err("%s: Failed to lower privileges (%s)", + (*privs)->raised_in_funcname, + safe_strerror(errno)); + } + errno = save_errno; + (*privs)->raised_in_funcname = NULL; + } } - errno = save_errno; - (*privs)->raised_in_funcname = NULL; + pthread_mutex_unlock(&(*privs)->mutex); + *privs = NULL; } @@ -743,6 +760,9 @@ void zprivs_preinit(struct zebra_privs_t *zprivs) exit(1); } + pthread_mutex_init(&(zprivs->mutex), NULL); + zprivs->refcount = 0; + if (zprivs->vty_group) { /* in a "NULL" setup, this is allowed to fail too, but still * try. */ @@ -789,7 +809,7 @@ void zprivs_preinit(struct zebra_privs_t *zprivs) void zprivs_init(struct zebra_privs_t *zprivs) { - gid_t groups[NGROUPS_MAX]; + gid_t groups[NGROUPS_MAX] = {}; int i, ngroups = 0; int found = 0; @@ -799,7 +819,7 @@ void zprivs_init(struct zebra_privs_t *zprivs) return; if (zprivs->user) { - ngroups = sizeof(groups); + ngroups = array_size(groups); if (getgrouplist(zprivs->user, zprivs_state.zgid, groups, &ngroups) < 0) { diff --git a/lib/privs.h b/lib/privs.h index b061370b75..01ddba4622 100644 --- a/lib/privs.h +++ b/lib/privs.h @@ -23,6 +23,12 @@ #ifndef _ZEBRA_PRIVS_H #define _ZEBRA_PRIVS_H +#include <pthread.h> + +#ifdef __cplusplus +extern "C" { +#endif + /* list of zebra capabilities */ typedef enum { ZCAP_SETID, @@ -55,6 +61,14 @@ struct zebra_privs_t { zebra_capabilities_t *caps_i; /* caps to allow inheritance of */ int cap_num_p; /* number of caps in arrays */ int cap_num_i; + + /* Mutex and counter used to avoid race conditions in multi-threaded + * processes. The privs elevation is process-wide, so we need to + * avoid changing the privilege status across threads. + */ + pthread_mutex_t mutex; + uint32_t refcount; + const char *user; /* user and group to run as */ const char *group; const char *vty_group; /* group to chown vty socket to */ @@ -120,4 +134,8 @@ extern void _zprivs_lower(struct zebra_privs_t **privs); _zprivs_raise(privs, __func__); \ _once == NULL; _once = (void *)1) +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_PRIVS_H */ diff --git a/lib/ptm_lib.h b/lib/ptm_lib.h index fc4d520dcb..c2170407c0 100644 --- a/lib/ptm_lib.h +++ b/lib/ptm_lib.h @@ -20,6 +20,10 @@ #ifndef __PTM_LIB_H__ #define __PTM_LIB_H__ +#ifdef __cplusplus +extern "C" { +#endif + #define PTMLIB_MSG_SZ 1024 #define PTMLIB_MSG_HDR_LEN 37 #define PTMLIB_MSG_VERSION 2 @@ -65,4 +69,8 @@ int ptm_lib_append_msg(ptm_lib_handle_t *, void *, const char *, const char *); int ptm_lib_complete_msg(ptm_lib_handle_t *, void *, char *, int *); int ptm_lib_cleanup_msg(ptm_lib_handle_t *, void *); +#ifdef __cplusplus +} +#endif + #endif @@ -20,6 +20,10 @@ #ifndef _FRR_PW_H #define _FRR_PW_H +#ifdef __cplusplus +extern "C" { +#endif + /* L2VPN name length. */ #define L2VPN_NAME_LEN 32 @@ -44,9 +48,10 @@ union pw_protocol_fields { uint32_t pwid; char vpn_name[L2VPN_NAME_LEN]; } ldp; - struct { - /* TODO */ - } bgp; }; +#ifdef __cplusplus +} +#endif + #endif /* _FRR_PW_H */ diff --git a/lib/qobj.h b/lib/qobj.h index b701eeec5f..d63988cbab 100644 --- a/lib/qobj.h +++ b/lib/qobj.h @@ -21,6 +21,10 @@ #include <stdlib.h> #include <stddef.h> +#ifdef __cplusplus +extern "C" { +#endif + /* reserve a specific amount of bytes for a struct, which can grow up to * that size (or be dummy'd out if not needed) * @@ -28,11 +32,17 @@ * this is intentional to prevent the struct from growing beyond the allocated * space. */ +#ifndef __cplusplus #define RESERVED_SPACE_STRUCT(name, fieldname, size) \ struct { \ struct name fieldname; \ char padding##fieldname[size - sizeof(struct name)]; \ }; +#else +#define RESERVED_SPACE_STRUCT(name, fieldname, size) \ + struct name fieldname; \ + char padding##fieldname[size - sizeof(struct name)]; +#endif /* don't need struct definitions for these here. code actually using * these needs to define the struct *before* including this header. @@ -127,4 +137,8 @@ void *qobj_get_typed(uint64_t id, struct qobj_nodetype *type); void qobj_init(void); void qobj_finish(void); +#ifdef __cplusplus +} +#endif + #endif /* _QOBJ_H */ diff --git a/lib/queue.h b/lib/queue.h index 11e28b4c91..dab43e3c54 100644 --- a/lib/queue.h +++ b/lib/queue.h @@ -19,6 +19,10 @@ #ifndef _FRR_QUEUE_H #define _FRR_QUEUE_H +#ifdef __cplusplus +extern "C" { +#endif + #if defined(__OpenBSD__) && !defined(STAILQ_HEAD) #include "openbsd-queue.h" @@ -85,4 +89,8 @@ }; _elm; }) #endif +#ifdef __cplusplus +} +#endif + #endif /* _FRR_QUEUE_H */ diff --git a/lib/ringbuf.h b/lib/ringbuf.h index 15049e3eea..b8f4d9798d 100644 --- a/lib/ringbuf.h +++ b/lib/ringbuf.h @@ -25,6 +25,10 @@ #include "memory.h" +#ifdef __cplusplus +extern "C" { +#endif + struct ringbuf { size_t size; ssize_t start; @@ -122,4 +126,8 @@ void ringbuf_reset(struct ringbuf *buf); */ void ringbuf_wipe(struct ringbuf *buf); +#ifdef __cplusplus +} +#endif + #endif /* _FRR_RINGBUF_H_ */ diff --git a/lib/routemap.c b/lib/routemap.c index 61e597520e..4898a8d0fa 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -538,10 +538,8 @@ int generic_match_delete(struct vty *vty, struct route_map_index *index, break; } - if (dep_name) - XFREE(MTYPE_ROUTE_MAP_RULE, dep_name); - if (rmap_name) - XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name); + XFREE(MTYPE_ROUTE_MAP_RULE, dep_name); + XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name); return retval; } @@ -1075,8 +1073,7 @@ static void route_map_index_delete(struct route_map_index *index, int notify) index->map->head = index->next; /* Free 'char *nextrm' if not NULL */ - if (index->nextrm) - XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm); + XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm); /* Execute event hook. */ if (route_map_master.event_hook && notify) { @@ -1231,8 +1228,7 @@ static void route_map_rule_delete(struct route_map_rule_list *list, if (rule->cmd->func_free) (*rule->cmd->func_free)(rule->value); - if (rule->rule_str) - XFREE(MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str); + XFREE(MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str); if (rule->next) rule->next->prev = rule->prev; @@ -1664,9 +1660,9 @@ static bool route_map_dep_hash_cmp(const void *p1, const void *p2) == 0); } -static void route_map_clear_reference(struct hash_backet *backet, void *arg) +static void route_map_clear_reference(struct hash_bucket *bucket, void *arg) { - struct route_map_dep *dep = (struct route_map_dep *)backet->data; + struct route_map_dep *dep = (struct route_map_dep *)bucket->data; char *rmap_name; if (arg) { @@ -1720,9 +1716,9 @@ static unsigned int route_map_dep_hash_make_key(void *p) return (string_hash_make((char *)p)); } -static void route_map_print_dependency(struct hash_backet *backet, void *data) +static void route_map_print_dependency(struct hash_bucket *bucket, void *data) { - char *rmap_name = (char *)backet->data; + char *rmap_name = (char *)bucket->data; char *dep_name = (char *)data; zlog_debug("%s: Dependency for %s: %s", __FUNCTION__, dep_name, @@ -1779,8 +1775,7 @@ static int route_map_dep_update(struct hash *dephash, const char *dep_name, } ret_map_name = (char *)hash_release(dep->dep_rmap_hash, rname); - if (ret_map_name) - XFREE(MTYPE_ROUTE_MAP_NAME, ret_map_name); + XFREE(MTYPE_ROUTE_MAP_NAME, ret_map_name); if (!dep->dep_rmap_hash->count) { dep = hash_release(dephash, dname); @@ -1846,9 +1841,9 @@ static struct hash *route_map_get_dep_hash(route_map_event_t event) return (upd8_hash); } -static void route_map_process_dependency(struct hash_backet *backet, void *data) +static void route_map_process_dependency(struct hash_bucket *bucket, void *data) { - char *rmap_name = (char *)backet->data; + char *rmap_name = (char *)bucket->data; route_map_event_t type = (route_map_event_t)(ptrdiff_t)data; if (rmap_debug) diff --git a/lib/routemap.h b/lib/routemap.h index 6fd88ba5de..e43e74a633 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -26,6 +26,10 @@ #include "qobj.h" #include "vty.h" +#ifdef __cplusplus +extern "C" { +#endif + DECLARE_MTYPE(ROUTE_MAP_NAME) DECLARE_MTYPE(ROUTE_MAP_RULE) DECLARE_MTYPE(ROUTE_MAP_COMPILED) @@ -388,4 +392,8 @@ extern void route_map_counter_increment(struct route_map *map); /* Decrement the route-map used counter */ extern void route_map_counter_decrement(struct route_map *map); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_ROUTEMAP_H */ diff --git a/lib/sbuf.h b/lib/sbuf.h index c38e96912f..b1518a3aa8 100644 --- a/lib/sbuf.h +++ b/lib/sbuf.h @@ -23,6 +23,10 @@ #ifndef SBUF_H #define SBUF_H +#ifdef __cplusplus +extern "C" { +#endif + /* * sbuf provides a simple string buffer. One application where this comes * in handy is the parsing of binary data: If there is an error in the parsing @@ -76,4 +80,8 @@ void sbuf_free(struct sbuf *buf); void sbuf_push(struct sbuf *buf, int indent, const char *format, ...) PRINTF_ATTRIBUTE(3, 4); +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/sha256.h b/lib/sha256.h index 2473da7bda..c93d253051 100644 --- a/lib/sha256.h +++ b/lib/sha256.h @@ -29,6 +29,10 @@ #ifndef _SHA256_H_ #define _SHA256_H_ +#ifdef __cplusplus +extern "C" { +#endif + typedef struct SHA256Context { uint32_t state[8]; uint32_t count[2]; @@ -55,4 +59,8 @@ void HMAC__SHA256_Final(unsigned char[32], HMAC_SHA256_CTX *); void PBKDF2_SHA256(const uint8_t *, size_t, const uint8_t *, size_t, uint64_t, uint8_t *, size_t); +#ifdef __cplusplus +} +#endif + #endif /* !_SHA256_H_ */ diff --git a/lib/sigevent.h b/lib/sigevent.h index d4ab5741ac..a0ad88fcaa 100644 --- a/lib/sigevent.h +++ b/lib/sigevent.h @@ -25,6 +25,10 @@ #include <thread.h> +#ifdef __cplusplus +extern "C" { +#endif + #define QUAGGA_SIGNAL_TIMER_INTERVAL 2L struct quagga_signal_t { @@ -47,4 +51,8 @@ extern void signal_init(struct thread_master *m, int sigc, /* check whether there are signals to handle, process any found */ extern int quagga_sigevent_process(void); +#ifdef __cplusplus +} +#endif + #endif /* _QUAGGA_SIGNAL_H */ diff --git a/lib/skiplist.h b/lib/skiplist.h index a2e8c374b1..2ab37331c9 100644 --- a/lib/skiplist.h +++ b/lib/skiplist.h @@ -31,6 +31,10 @@ #ifndef _ZEBRA_SKIPLIST_H #define _ZEBRA_SKIPLIST_H +#ifdef __cplusplus +extern "C" { +#endif + #define SKIPLIST_0TIMER_DEBUG 1 /* @@ -122,4 +126,8 @@ extern void skiplist_debug(struct vty *vty, struct skiplist *l); extern void skiplist_test(struct vty *vty); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_SKIPLIST_H */ diff --git a/lib/smux.h b/lib/smux.h index 9adfacb3e4..3f860db0dc 100644 --- a/lib/smux.h +++ b/lib/smux.h @@ -26,6 +26,10 @@ #include "thread.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Structures here are mostly compatible with UCD SNMP 4.1.1 */ #define MATCH_FAILED (-1) #define MATCH_SUCCEEDED 0 @@ -103,4 +107,8 @@ extern void oid2in_addr(oid[], int, struct in_addr *); extern void *oid_copy(void *, const void *, size_t); extern void oid_copy_addr(oid[], struct in_addr *, int); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_SNMP_H */ diff --git a/lib/sockopt.h b/lib/sockopt.h index f54f60ffd7..8fa5987cff 100644 --- a/lib/sockopt.h +++ b/lib/sockopt.h @@ -23,6 +23,10 @@ #include "sockunion.h" +#ifdef __cplusplus +extern "C" { +#endif + extern void setsockopt_so_recvbuf(int sock, int size); extern void setsockopt_so_sendbuf(const int sock, int size); extern int getsockopt_so_sendbuf(const int sock); @@ -98,4 +102,9 @@ extern void sockopt_iphdrincl_swab_systoh(struct ip *iph); extern int sockopt_tcp_rtt(int); extern int sockopt_tcp_signature(int sock, union sockunion *su, const char *password); + +#ifdef __cplusplus +} +#endif + #endif /*_ZEBRA_SOCKOPT_H */ diff --git a/lib/sockunion.h b/lib/sockunion.h index b585aee5b4..d7d26ba85a 100644 --- a/lib/sockunion.h +++ b/lib/sockunion.h @@ -28,6 +28,10 @@ #include <netmpls/mpls.h> #endif +#ifdef __cplusplus +extern "C" { +#endif + union sockunion { struct sockaddr sa; struct sockaddr_in sin; @@ -99,4 +103,8 @@ extern union sockunion *sockunion_dup(const union sockunion *); extern void sockunion_free(union sockunion *); extern void sockunion_init(union sockunion *); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_SOCKUNION_H */ diff --git a/lib/spf_backoff.h b/lib/spf_backoff.h index 6de5804ace..11b2701e3e 100644 --- a/lib/spf_backoff.h +++ b/lib/spf_backoff.h @@ -26,6 +26,10 @@ #ifndef _ZEBRA_SPF_BACKOFF_H #define _ZEBRA_SPF_BACKOFF_H +#ifdef __cplusplus +extern "C" { +#endif + struct spf_backoff; struct thread_master; struct vty; @@ -58,4 +62,8 @@ long spf_backoff_long_delay(struct spf_backoff *backoff); long spf_backoff_holddown(struct spf_backoff *backoff); long spf_backoff_timetolearn(struct spf_backoff *backoff); +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/srcdest_table.h b/lib/srcdest_table.h index 54acb51b03..8845931de7 100644 --- a/lib/srcdest_table.h +++ b/lib/srcdest_table.h @@ -46,6 +46,10 @@ #include "prefix.h" #include "table.h" +#ifdef __cplusplus +extern "C" { +#endif + #define SRCDEST2STR_BUFFER (2*PREFIX2STR_BUFFER + sizeof(" from ")) /* extended route node for IPv6 srcdest routing */ @@ -84,7 +88,8 @@ static inline int rnode_is_srcnode(struct route_node *rn) static inline struct route_table *srcdest_rnode_table(struct route_node *rn) { if (rnode_is_srcnode(rn)) { - struct route_node *dst_rn = route_table_get_info(rn->table); + struct route_node *dst_rn = + (struct route_node *)route_table_get_info(rn->table); return dst_rn->table; } else { return rn->table; @@ -95,4 +100,8 @@ static inline void *srcdest_rnode_table_info(struct route_node *rn) return route_table_get_info(srcdest_rnode_table(rn)); } +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_SRC_DEST_TABLE_H */ diff --git a/lib/stream.h b/lib/stream.h index 32b6fb5af1..5341bfa40b 100644 --- a/lib/stream.h +++ b/lib/stream.h @@ -28,6 +28,10 @@ #include "mpls.h" #include "prefix.h" +#ifdef __cplusplus +extern "C" { +#endif + /* * A stream is an arbitrary buffer, whose contents generally are assumed to * be in network order. @@ -115,9 +119,9 @@ struct stream_fifo { pthread_mutex_t mtx; /* number of streams in this fifo */ - _Atomic size_t count; + atomic_size_t count; #if defined DEV_BUILD - _Atomic size_t max_count; + atomic_size_t max_count; #endif struct stream *head; @@ -404,4 +408,8 @@ static inline uint8_t *ptr_get_be32(uint8_t *ptr, uint32_t *out) goto stream_failure; \ } while (0) +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_STREAM_H */ diff --git a/lib/systemd.h b/lib/systemd.h index a13ea7bfdd..6e43df527d 100644 --- a/lib/systemd.h +++ b/lib/systemd.h @@ -19,6 +19,10 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#ifdef __cplusplus +extern "C" { +#endif + /* * Wrapper functions to systemd calls. * @@ -37,3 +41,7 @@ void systemd_send_stopping(void); * process? */ void systemd_send_started(struct thread_master *master, int the_process); + +#ifdef __cplusplus +} +#endif diff --git a/lib/table.h b/lib/table.h index 541d74d77b..ce578e795c 100644 --- a/lib/table.h +++ b/lib/table.h @@ -25,6 +25,11 @@ #include "memory.h" #include "hash.h" #include "prefix.h" + +#ifdef __cplusplus +extern "C" { +#endif + DECLARE_MTYPE(ROUTE_TABLE) DECLARE_MTYPE(ROUTE_NODE) @@ -318,4 +323,8 @@ static inline int route_table_iter_started(route_table_iter_t *iter) return iter->state != RT_ITER_STATE_INIT; } +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_TABLE_H */ diff --git a/lib/termtable.h b/lib/termtable.h index ca5cc1df9f..491010a856 100644 --- a/lib/termtable.h +++ b/lib/termtable.h @@ -22,6 +22,10 @@ #include <zebra.h> +#ifdef __cplusplus +extern "C" { +#endif + enum ttable_align { LEFT, RIGHT, @@ -294,4 +298,8 @@ void ttable_rowseps(struct ttable *tt, unsigned int row, */ char *ttable_dump(struct ttable *tt, const char *newline); +#ifdef __cplusplus +} +#endif + #endif /* _TERMTABLE_H */ diff --git a/lib/thread.c b/lib/thread.c index ae8e375a27..19ab409439 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -93,7 +93,8 @@ static void cpu_record_hash_free(void *a) static void vty_out_cpu_thread_history(struct vty *vty, struct cpu_thread_history *a) { - vty_out(vty, "%5d %10lu.%03lu %9u %8lu %9lu %8lu %9lu", a->total_active, + vty_out(vty, "%5"PRIdFAST32" %10lu.%03lu %9"PRIuFAST32 + " %8lu %9lu %8lu %9lu", a->total_active, a->cpu.total / 1000, a->cpu.total % 1000, a->total_calls, a->cpu.total / a->total_calls, a->cpu.max, a->real.total / a->total_calls, a->real.max); @@ -105,7 +106,7 @@ static void vty_out_cpu_thread_history(struct vty *vty, a->types & (1 << THREAD_EXECUTE) ? 'X' : ' ', a->funcname); } -static void cpu_record_hash_print(struct hash_backet *bucket, void *args[]) +static void cpu_record_hash_print(struct hash_bucket *bucket, void *args[]) { struct cpu_thread_history *totals = args[0]; struct cpu_thread_history copy; @@ -177,7 +178,7 @@ static void cpu_record_print(struct vty *vty, uint8_t filter) if (m->cpu_record->count) hash_iterate( m->cpu_record, - (void (*)(struct hash_backet *, + (void (*)(struct hash_bucket *, void *))cpu_record_hash_print, args); else @@ -201,7 +202,7 @@ static void cpu_record_print(struct vty *vty, uint8_t filter) vty_out_cpu_thread_history(vty, &tmp); } -static void cpu_record_hash_clear(struct hash_backet *bucket, void *args[]) +static void cpu_record_hash_clear(struct hash_bucket *bucket, void *args[]) { uint8_t *filter = args[0]; struct hash *cpu_record = args[1]; @@ -228,7 +229,7 @@ static void cpu_record_clear(uint8_t filter) void *args[2] = {tmp, m->cpu_record}; hash_iterate( m->cpu_record, - (void (*)(struct hash_backet *, + (void (*)(struct hash_bucket *, void *))cpu_record_hash_clear, args); } @@ -413,8 +414,6 @@ struct thread_master *thread_master_create(const char *name) pthread_once(&init_once, &initializer); rv = XCALLOC(MTYPE_THREAD_MASTER, sizeof(struct thread_master)); - if (rv == NULL) - return NULL; /* Initialize master mutex */ pthread_mutex_init(&rv->mtx, NULL); @@ -483,8 +482,7 @@ void thread_master_set_name(struct thread_master *master, const char *name) { pthread_mutex_lock(&master->mtx); { - if (master->name) - XFREE(MTYPE_THREAD_MASTER, master->name); + XFREE(MTYPE_THREAD_MASTER, master->name); master->name = XSTRDUP(MTYPE_THREAD_MASTER, name); } pthread_mutex_unlock(&master->mtx); @@ -648,8 +646,7 @@ void thread_master_free(struct thread_master *m) hash_free(m->cpu_record); m->cpu_record = NULL; - if (m->name) - XFREE(MTYPE_THREAD_MASTER, m->name); + XFREE(MTYPE_THREAD_MASTER, m->name); XFREE(MTYPE_THREAD_MASTER, m->handler.pfds); XFREE(MTYPE_THREAD_MASTER, m->handler.copy); XFREE(MTYPE_THREAD_MASTER, m); diff --git a/lib/thread.h b/lib/thread.h index f404d92755..ec774a6543 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -27,6 +27,10 @@ #include "monotime.h" #include "frratomic.h" +#ifdef __cplusplus +extern "C" { +#endif + struct rusage_t { struct rusage cpu; struct timeval real; @@ -119,13 +123,13 @@ struct thread { struct cpu_thread_history { int (*func)(struct thread *); - _Atomic unsigned int total_calls; - _Atomic unsigned int total_active; + atomic_uint_fast32_t total_calls; + atomic_uint_fast32_t total_active; struct time_stats { - _Atomic unsigned long total, max; + atomic_size_t total, max; } real; struct time_stats cpu; - _Atomic uint32_t types; + atomic_uint_fast32_t types; const char *funcname; }; @@ -233,4 +237,8 @@ extern unsigned long thread_consumed_time(RUSAGE_T *after, RUSAGE_T *before, /* only for use in logging functions! */ extern pthread_key_t thread_current; +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_THREAD_H */ diff --git a/lib/vector.h b/lib/vector.h index 97e15da040..d5857eb599 100644 --- a/lib/vector.h +++ b/lib/vector.h @@ -24,6 +24,10 @@ #include "memory.h" +#ifdef __cplusplus +extern "C" { +#endif + /* struct for vector */ struct _vector { unsigned int active; /* number of active slots */ @@ -63,4 +67,9 @@ extern void *vector_lookup(vector, unsigned int); extern void *vector_lookup_ensure(vector, unsigned int); extern void vector_to_array(vector v, void ***dest, int *argc); extern vector array_to_vector(void **src, int argc); + +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_VECTOR_H */ diff --git a/lib/vlan.h b/lib/vlan.h index 6d15e62dfc..eea2633d4e 100644 --- a/lib/vlan.h +++ b/lib/vlan.h @@ -22,8 +22,16 @@ #ifndef __VLAN_H__ #define __VLAN_H__ +#ifdef __cplusplus +extern "C" { +#endif + /* VLAN Identifier */ typedef uint16_t vlanid_t; #define VLANID_MAX 4095 +#ifdef __cplusplus +} +#endif + #endif /* __VLAN_H__ */ @@ -472,7 +472,7 @@ static const struct cmd_variable_handler vrf_var_handlers[] = { /* Initialize VRF module. */ void vrf_init(int (*create)(struct vrf *), int (*enable)(struct vrf *), - int (*disable)(struct vrf *), int (*delete)(struct vrf *), + int (*disable)(struct vrf *), int (*destroy)(struct vrf *), int ((*update)(struct vrf *))) { struct vrf *default_vrf; @@ -486,7 +486,7 @@ void vrf_init(int (*create)(struct vrf *), int (*enable)(struct vrf *), vrf_master.vrf_new_hook = create; vrf_master.vrf_enable_hook = enable; vrf_master.vrf_disable_hook = disable; - vrf_master.vrf_delete_hook = delete; + vrf_master.vrf_delete_hook = destroy; vrf_master.vrf_update_name_hook = update; /* The default VRF always exists. */ @@ -666,7 +666,7 @@ int vrf_netns_handler_create(struct vty *vty, struct vrf *vrf, char *pathname, "VRF %u is already configured with VRF %s\n", vrf->vrf_id, vrf->name); else - zlog_info("VRF %u is already configured with VRF %s\n", + zlog_info("VRF %u is already configured with VRF %s", vrf->vrf_id, vrf->name); return CMD_WARNING_CONFIG_FAILED; } @@ -28,6 +28,10 @@ #include "vty.h" #include "ns.h" +#ifdef __cplusplus +extern "C" { +#endif + /* The default VRF ID */ #define VRF_UNKNOWN UINT32_MAX @@ -201,7 +205,7 @@ extern int vrf_bitmap_check(vrf_bitmap_t, vrf_id_t); * the system ( 2 and 3 ) above. */ extern void vrf_init(int (*create)(struct vrf *vrf), int (*enable)(struct vrf *vrf), - int (*disable)(struct vrf *vrf), int (*delete)(struct vrf *vrf), + int (*disable)(struct vrf *vrf), int (*destroy)(struct vrf *vrf), int (*update)(struct vrf *vrf)); /* @@ -293,4 +297,8 @@ extern int vrf_enable(struct vrf *vrf); extern void vrf_delete(struct vrf *vrf); extern vrf_id_t vrf_generate_id(void); +#ifdef __cplusplus +} +#endif + #endif /*_ZEBRA_VRF_H*/ diff --git a/lib/vrf_int.h b/lib/vrf_int.h index d7fe735817..8dc078e4f3 100644 --- a/lib/vrf_int.h +++ b/lib/vrf_int.h @@ -25,6 +25,10 @@ #include "vrf.h" +#ifdef __cplusplus +extern "C" { +#endif + /* * These functions should only be called by: * zebra/if_netlink.c -> The interface from OS into Zebra @@ -52,4 +56,8 @@ extern int vrf_enable(struct vrf *); */ extern void vrf_delete(struct vrf *); +#ifdef __cplusplus +} +#endif + #endif @@ -974,8 +974,7 @@ static void vty_complete_command(struct vty *vty) default: break; } - if (matched) - XFREE(MTYPE_TMP, matched); + XFREE(MTYPE_TMP, matched); } static void vty_describe_fold(struct vty *vty, int cmd_width, @@ -1169,8 +1168,7 @@ static void vty_hist_add(struct vty *vty) } /* Insert history entry. */ - if (vty->hist[vty->hindex]) - XFREE(MTYPE_VTY_HIST, vty->hist[vty->hindex]); + XFREE(MTYPE_VTY_HIST, vty->hist[vty->hindex]); vty->hist[vty->hindex] = XSTRDUP(MTYPE_VTY_HIST, vty->buf); /* History index rotation. */ @@ -2232,9 +2230,9 @@ void vty_close(struct vty *vty) buffer_free(vty->lbuf); /* Free command history. */ - for (i = 0; i < VTY_MAXHIST; i++) - if (vty->hist[i]) - XFREE(MTYPE_VTY_HIST, vty->hist[i]); + for (i = 0; i < VTY_MAXHIST; i++) { + XFREE(MTYPE_VTY_HIST, vty->hist[i]); + } /* Unset vector. */ if (vty->fd != -1) @@ -2255,8 +2253,7 @@ void vty_close(struct vty *vty) if (vty->fd == STDIN_FILENO) was_stdio = true; - if (vty->buf) - XFREE(MTYPE_VTY, vty->buf); + XFREE(MTYPE_VTY, vty->buf); if (vty->error) { vty->error->del = vty_error_delete; @@ -2546,8 +2543,7 @@ bool vty_read_config(struct nb_config *config, const char *config_file, host_config_set(fullpath); tmp_free_and_out: - if (tmp) - XFREE(MTYPE_TMP, tmp); + XFREE(MTYPE_TMP, tmp); return read_success; } @@ -3163,8 +3159,7 @@ void vty_init(struct thread_master *master_thread) void vty_terminate(void) { - if (vty_cwd) - XFREE(MTYPE_TMP, vty_cwd); + XFREE(MTYPE_TMP, vty_cwd); if (vtyvec && Vvty_serv_thread) { vty_reset(); @@ -31,6 +31,10 @@ #include "compiler.h" #include "northbound.h" +#ifdef __cplusplus +extern "C" { +#endif + #define VTY_BUFSIZ 4096 #define VTY_MAXHIST 20 #define VTY_MAXDEPTH 8 @@ -333,4 +337,8 @@ extern void vty_stdio_close(void); an async-signal-safe function. */ extern void vty_log_fixed(char *buf, size_t len); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_VTY_H */ diff --git a/lib/vxlan.h b/lib/vxlan.h index bcf8354539..2a8077f8cf 100644 --- a/lib/vxlan.h +++ b/lib/vxlan.h @@ -22,6 +22,10 @@ #ifndef __VXLAN_H__ #define __VXLAN_H__ +#ifdef __cplusplus +extern "C" { +#endif + /* VxLAN Network Identifier - 24-bit (RFC 7348) */ typedef uint32_t vni_t; #define VNI_MAX 16777215 /* (2^24 - 1) */ @@ -35,4 +39,9 @@ enum vxlan_flood_control { VXLAN_FLOOD_HEAD_END_REPL = 0, VXLAN_FLOOD_DISABLED, }; + +#ifdef __cplusplus +} +#endif + #endif /* __VXLAN_H__ */ diff --git a/lib/wheel.h b/lib/wheel.h index c8e83fafcb..e66751c1d0 100644 --- a/lib/wheel.h +++ b/lib/wheel.h @@ -20,6 +20,10 @@ #ifndef __WHEEL_H__ #define __WHEEL_H__ +#ifdef __cplusplus +extern "C" { +#endif + struct timer_wheel { char *name; struct thread_master *master; @@ -115,4 +119,8 @@ int wheel_add_item(struct timer_wheel *wheel, void *item); */ int wheel_remove_item(struct timer_wheel *wheel, void *item); +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/workqueue.c b/lib/workqueue.c index fa69ec600e..066d81f350 100644 --- a/lib/workqueue.c +++ b/lib/workqueue.c @@ -274,7 +274,7 @@ int work_queue_run(struct thread *thread) wq->cycles.granularity = WORK_QUEUE_MIN_GRANULARITY; STAILQ_FOREACH_SAFE (item, &wq->items, wq, titem) { - assert(item && item->data); + assert(item->data); /* dont run items which are past their allowed retries */ if (item->ran > wq->spec.max_retries) { diff --git a/lib/workqueue.h b/lib/workqueue.h index cbbacc0561..7c610f5dd6 100644 --- a/lib/workqueue.h +++ b/lib/workqueue.h @@ -25,6 +25,11 @@ #include "memory.h" #include "queue.h" + +#ifdef __cplusplus +extern "C" { +#endif + DECLARE_MTYPE(WORK_QUEUE) /* Hold time for the initial schedule of a queue run, in millisec */ @@ -176,4 +181,8 @@ extern int work_queue_run(struct thread *); extern void workqueue_cmd_init(void); +#ifdef __cplusplus +} +#endif + #endif /* _QUAGGA_WORK_QUEUE_H */ diff --git a/lib/yang.c b/lib/yang.c index f62a8163f9..1d8e82eb28 100644 --- a/lib/yang.c +++ b/lib/yang.c @@ -649,6 +649,29 @@ CPP_NOTICE("lib/yang: time to remove non-LIBYANG_EXT_BUILTIN support") extern struct lytype_plugin_list frr_user_types[]; #endif +struct ly_ctx *yang_ctx_new_setup(void) +{ + struct ly_ctx *ctx; + const char *yang_models_path = YANG_MODELS_PATH; + + if (access(yang_models_path, R_OK | X_OK)) { + yang_models_path = NULL; + if (errno == ENOENT) + zlog_info("yang model directory \"%s\" does not exist", + YANG_MODELS_PATH); + else + flog_err_sys(EC_LIB_LIBYANG, + "cannot access yang model directory \"%s\"", + YANG_MODELS_PATH); + } + + ctx = ly_ctx_new(yang_models_path, LY_CTX_DISABLE_SEARCHDIR_CWD); + if (!ctx) + return NULL; + ly_ctx_set_module_imp_clb(ctx, yang_module_imp_clb, NULL); + return ctx; +} + void yang_init(void) { #ifndef LIBYANG_EXT_BUILTIN @@ -677,13 +700,11 @@ CPP_NOTICE("lib/yang: deprecated libyang <0.16.74 extension loading in use!") #endif /* Initialize libyang container for native models. */ - ly_native_ctx = - ly_ctx_new(YANG_MODELS_PATH, LY_CTX_DISABLE_SEARCHDIR_CWD); + ly_native_ctx = yang_ctx_new_setup(); if (!ly_native_ctx) { flog_err(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__); exit(1); } - ly_ctx_set_module_imp_clb(ly_native_ctx, yang_module_imp_clb, NULL); ly_ctx_set_priv_dup_clb(ly_native_ctx, ly_dup_cb); #ifndef LIBYANG_EXT_BUILTIN diff --git a/lib/yang.h b/lib/yang.h index 3259189e98..885218272a 100644 --- a/lib/yang.h +++ b/lib/yang.h @@ -29,6 +29,10 @@ #include "yang_wrappers.h" +#ifdef __cplusplus +extern "C" { +#endif + DECLARE_MTYPE(YANG_MODULE) DECLARE_MTYPE(YANG_DATA) @@ -510,6 +514,11 @@ extern void yang_data_free(struct yang_data *data); extern struct list *yang_data_list_new(void); /* + * Create and set up a libyang context (for use by the translator) + */ +extern struct ly_ctx *yang_ctx_new_setup(void); + +/* * Initialize the YANG subsystem. Should be called only once during the * daemon initialization process. */ @@ -521,4 +530,8 @@ extern void yang_init(void); */ extern void yang_terminate(void); +#ifdef __cplusplus +} +#endif + #endif /* _FRR_YANG_H_ */ diff --git a/lib/yang_translator.c b/lib/yang_translator.c index c3092e56e5..76a6cc5fd1 100644 --- a/lib/yang_translator.c +++ b/lib/yang_translator.c @@ -162,8 +162,7 @@ struct yang_translator *yang_translator_load(const char *path) RB_INSERT(yang_translators, &yang_translators, translator); /* Initialize the translator libyang context. */ - translator->ly_ctx = - ly_ctx_new(YANG_MODELS_PATH, LY_CTX_DISABLE_SEARCHDIR_CWD); + translator->ly_ctx = yang_ctx_new_setup(); if (!translator->ly_ctx) { flog_warn(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__); goto error; @@ -512,7 +511,7 @@ static void str_replace(char *o_string, const char *s_string, if (!ch) return; - strncpy(buffer, o_string, ch - o_string); + memcpy(buffer, o_string, ch - o_string); buffer[ch - o_string] = 0; sprintf(buffer + (ch - o_string), "%s%s", r_string, @@ -525,8 +524,7 @@ static void str_replace(char *o_string, const char *s_string, void yang_translator_init(void) { - ly_translator_ctx = - ly_ctx_new(YANG_MODELS_PATH, LY_CTX_DISABLE_SEARCHDIR_CWD); + ly_translator_ctx = yang_ctx_new_setup(); if (!ly_translator_ctx) { flog_err(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__); exit(1); diff --git a/lib/yang_translator.h b/lib/yang_translator.h index 6b49d1acf3..55f396a434 100644 --- a/lib/yang_translator.h +++ b/lib/yang_translator.h @@ -20,6 +20,10 @@ #ifndef _FRR_YANG_TRANSLATOR_H_ #define _FRR_YANG_TRANSLATOR_H_ +#ifdef __cplusplus +extern "C" { +#endif + #define YANG_TRANSLATE_TO_NATIVE 0 #define YANG_TRANSLATE_FROM_NATIVE 1 #define YANG_TRANSLATE_MAX 2 @@ -141,4 +145,8 @@ extern void yang_translator_init(void); */ extern void yang_translator_terminate(void); +#ifdef __cplusplus +} +#endif + #endif /* _FRR_YANG_TRANSLATOR_H_ */ diff --git a/lib/yang_wrappers.c b/lib/yang_wrappers.c index 6273dff3ce..7ecea5f445 100644 --- a/lib/yang_wrappers.c +++ b/lib/yang_wrappers.c @@ -62,7 +62,7 @@ bool yang_str2bool(const char *value) struct yang_data *yang_data_new_bool(const char *xpath, bool value) { - return yang_data_new(xpath, (value == true) ? "true" : "false"); + return yang_data_new(xpath, (value) ? "true" : "false"); } bool yang_dnode_get_bool(const struct lyd_node *dnode, const char *xpath_fmt, diff --git a/lib/zclient.c b/lib/zclient.c index 9db1dd74f2..55f2393c56 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -2504,7 +2504,7 @@ static int zclient_read(struct thread *thread) length -= ZEBRA_HEADER_SIZE; if (zclient_debug) - zlog_debug("zclient 0x%p command 0x%x VRF %u\n", + zlog_debug("zclient 0x%p command 0x%x VRF %u", (void *)zclient, command, vrf_id); switch (command) { @@ -2574,14 +2574,14 @@ static int zclient_read(struct thread *thread) break; case ZEBRA_NEXTHOP_UPDATE: if (zclient_debug) - zlog_debug("zclient rcvd nexthop update\n"); + zlog_debug("zclient rcvd nexthop update"); if (zclient->nexthop_update) (*zclient->nexthop_update)(command, zclient, length, vrf_id); break; case ZEBRA_IMPORT_CHECK_UPDATE: if (zclient_debug) - zlog_debug("zclient rcvd import check update\n"); + zlog_debug("zclient rcvd import check update"); if (zclient->import_check_update) (*zclient->import_check_update)(command, zclient, length, vrf_id); @@ -2608,7 +2608,7 @@ static int zclient_read(struct thread *thread) break; case ZEBRA_FEC_UPDATE: if (zclient_debug) - zlog_debug("zclient rcvd fec update\n"); + zlog_debug("zclient rcvd fec update"); if (zclient->fec_update) (*zclient->fec_update)(command, zclient, length); break; diff --git a/lib/zebra.h b/lib/zebra.h index 43ab4309c2..b96fb5a206 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -232,6 +232,15 @@ typedef unsigned char uint8_t; #include "zassert.h" +/* + * Add explicit static cast only when using a C++ compiler. + */ +#ifdef __cplusplus +#define static_cast(l, r) static_cast<decltype(l)>((r)) +#else +#define static_cast(l, r) (r) +#endif + #ifndef HAVE_STRLCAT size_t strlcat(char *__restrict dest, const char *__restrict src, size_t destsize); diff --git a/nhrpd/netlink_arp.c b/nhrpd/netlink_arp.c index 4c6827cb3d..6666c6e96b 100644 --- a/nhrpd/netlink_arp.c +++ b/nhrpd/netlink_arp.c @@ -122,7 +122,7 @@ static int netlink_route_recv(struct thread *t) zbuf_init(&zb, buf, sizeof(buf), 0); while (zbuf_recv(&zb, fd) > 0) { - while ((n = znl_nlmsg_pull(&zb, &payload)) != 0) { + while ((n = znl_nlmsg_pull(&zb, &payload)) != NULL) { debugf(NHRP_DEBUG_KERNEL, "Netlink: Received msg_type %u, msg_flags %u", n->nlmsg_type, n->nlmsg_flags); @@ -217,7 +217,7 @@ static int netlink_log_recv(struct thread *t) zbuf_init(&zb, buf, sizeof(buf), 0); while (zbuf_recv(&zb, fd) > 0) { - while ((n = znl_nlmsg_pull(&zb, &payload)) != 0) { + while ((n = znl_nlmsg_pull(&zb, &payload)) != NULL) { debugf(NHRP_DEBUG_KERNEL, "Netlink-log: Received msg_type %u, msg_flags %u", n->nlmsg_type, n->nlmsg_flags); diff --git a/nhrpd/nhrp_cache.c b/nhrpd/nhrp_cache.c index 1316a4aad3..5508778243 100644 --- a/nhrpd/nhrp_cache.c +++ b/nhrpd/nhrp_cache.c @@ -345,7 +345,7 @@ struct nhrp_cache_iterator_ctx { void *ctx; }; -static void nhrp_cache_iterator(struct hash_backet *b, void *ctx) +static void nhrp_cache_iterator(struct hash_bucket *b, void *ctx) { struct nhrp_cache_iterator_ctx *ic = ctx; ic->cb(b->data, ic->ctx); diff --git a/nhrpd/nhrp_vc.c b/nhrpd/nhrp_vc.c index 79a655396b..f92ea4ac90 100644 --- a/nhrpd/nhrp_vc.c +++ b/nhrpd/nhrp_vc.c @@ -183,7 +183,7 @@ struct nhrp_vc_iterator_ctx { void *ctx; }; -static void nhrp_vc_iterator(struct hash_backet *b, void *ctx) +static void nhrp_vc_iterator(struct hash_bucket *b, void *ctx) { struct nhrp_vc_iterator_ctx *ic = ctx; ic->cb(b->data, ic->ctx); diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index 30f0e9e774..484e5adae6 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -138,11 +138,11 @@ static void ospf6_area_stub_update(struct ospf6_area *area) if (IS_AREA_STUB(area)) { if (IS_OSPF6_DEBUG_ORIGINATE(ROUTER)) - zlog_debug("Stubbing out area for if %s\n", area->name); + zlog_debug("Stubbing out area for if %s", area->name); OSPF6_OPT_CLEAR(area->options, OSPF6_OPT_E); } else if (IS_AREA_ENABLED(area)) { if (IS_OSPF6_DEBUG_ORIGINATE(ROUTER)) - zlog_debug("Normal area for if %s\n", area->name); + zlog_debug("Normal area for if %s", area->name); OSPF6_OPT_SET(area->options, OSPF6_OPT_E); ospf6_asbr_send_externals_to_area(area); } @@ -450,7 +450,7 @@ DEFUN (area_range, range->path.u.cost_config = cost; - zlog_debug("%s: for prefix %s, flag = %x\n", __func__, + zlog_debug("%s: for prefix %s, flag = %x", __func__, argv[idx_ipv6_prefixlen]->arg, range->flag); if (range->rnode == NULL) { ospf6_route_add(range, oa->range_table); @@ -1022,3 +1022,16 @@ void ospf6_area_init(void) install_element(OSPF6_NODE, &area_filter_list_cmd); install_element(OSPF6_NODE, &no_area_filter_list_cmd); } + +void ospf6_area_interface_delete(struct ospf6_interface *oi) +{ + struct ospf6_area *oa; + struct listnode *node, *nnode; + + if (!ospf6) + return; + for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, oa)) + if(listnode_lookup(oa->if_list, oi)) + listnode_delete(oa->if_list, oi); + +} diff --git a/ospf6d/ospf6_area.h b/ospf6d/ospf6_area.h index ba497a168e..5648b1dfec 100644 --- a/ospf6d/ospf6_area.h +++ b/ospf6d/ospf6_area.h @@ -132,5 +132,7 @@ extern void ospf6_area_show(struct vty *, struct ospf6_area *); extern void ospf6_area_plist_update(struct prefix_list *plist, int add); extern void ospf6_area_config_write(struct vty *vty); extern void ospf6_area_init(void); +struct ospf6_interface; +extern void ospf6_area_interface_delete(struct ospf6_interface *oi); #endif /* OSPF_AREA_H */ diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 3153c29aa1..2795bb9abd 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -1006,7 +1006,7 @@ void ospf6_asbr_send_externals_to_area(struct ospf6_area *oa) for (ALL_LSDB(oa->ospf6->lsdb, lsa)) { if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL) { - zlog_debug("%s: Flooding AS-External LSA %s\n", + zlog_debug("%s: Flooding AS-External LSA %s", __func__, lsa->name); ospf6_flood_area(NULL, lsa, oa); } diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index dd08144daa..692c84ad08 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -177,8 +177,7 @@ struct ospf6_interface *ospf6_interface_create(struct interface *ifp) struct ospf6_interface *oi; unsigned int iobuflen; - oi = (struct ospf6_interface *)XCALLOC(MTYPE_OSPF6_IF, - sizeof(struct ospf6_interface)); + oi = XCALLOC(MTYPE_OSPF6_IF, sizeof(struct ospf6_interface)); oi->area = (struct ospf6_area *)NULL; oi->neighbor_list = list_new(); @@ -269,6 +268,9 @@ void ospf6_interface_delete(struct ospf6_interface *oi) ospf6_bfd_info_free(&(oi->bfd_info)); + /* disable from area list if possible */ + ospf6_area_interface_delete(oi); + XFREE(MTYPE_OSPF6_IF, oi); } diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index 40b3522c3d..9acbd09b1a 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -518,16 +518,14 @@ struct ospf6_lsa *ospf6_lsa_create(struct ospf6_lsa_header *header) lsa_size = ntohs(header->length); /* XXX vulnerable */ /* allocate memory for this LSA */ - new_header = (struct ospf6_lsa_header *)XMALLOC(MTYPE_OSPF6_LSA_HEADER, - lsa_size); + new_header = XMALLOC(MTYPE_OSPF6_LSA_HEADER, lsa_size); /* copy LSA from original header */ memcpy(new_header, header, lsa_size); /* LSA information structure */ /* allocate memory */ - lsa = (struct ospf6_lsa *)XCALLOC(MTYPE_OSPF6_LSA, - sizeof(struct ospf6_lsa)); + lsa = XCALLOC(MTYPE_OSPF6_LSA, sizeof(struct ospf6_lsa)); lsa->header = (struct ospf6_lsa_header *)new_header; @@ -546,16 +544,15 @@ struct ospf6_lsa *ospf6_lsa_create_headeronly(struct ospf6_lsa_header *header) struct ospf6_lsa_header *new_header = NULL; /* allocate memory for this LSA */ - new_header = (struct ospf6_lsa_header *)XMALLOC( - MTYPE_OSPF6_LSA_HEADER, sizeof(struct ospf6_lsa_header)); + new_header = XMALLOC(MTYPE_OSPF6_LSA_HEADER, + sizeof(struct ospf6_lsa_header)); /* copy LSA from original header */ memcpy(new_header, header, sizeof(struct ospf6_lsa_header)); /* LSA information structure */ /* allocate memory */ - lsa = (struct ospf6_lsa *)XCALLOC(MTYPE_OSPF6_LSA, - sizeof(struct ospf6_lsa)); + lsa = XCALLOC(MTYPE_OSPF6_LSA, sizeof(struct ospf6_lsa)); lsa->header = (struct ospf6_lsa_header *)new_header; SET_FLAG(lsa->flag, OSPF6_LSA_HEADERONLY); diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c index 5e02c0c917..b551dbdfa6 100644 --- a/ospf6d/ospf6_lsdb.c +++ b/ospf6d/ospf6_lsdb.c @@ -39,10 +39,6 @@ struct ospf6_lsdb *ospf6_lsdb_create(void *data) struct ospf6_lsdb *lsdb; lsdb = XCALLOC(MTYPE_OSPF6_LSDB, sizeof(struct ospf6_lsdb)); - if (lsdb == NULL) { - zlog_warn("Can't malloc lsdb"); - return NULL; - } memset(lsdb, 0, sizeof(struct ospf6_lsdb)); lsdb->data = data; diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c index 046badc824..61094c7cdb 100644 --- a/ospf6d/ospf6_main.c +++ b/ospf6d/ospf6_main.c @@ -43,6 +43,7 @@ #include "ospf6d.h" #include "ospf6_top.h" #include "ospf6_message.h" +#include "ospf6_network.h" #include "ospf6_asbr.h" #include "ospf6_lsa.h" #include "ospf6_interface.h" @@ -84,8 +85,10 @@ static void __attribute__((noreturn)) ospf6_exit(int status) frr_early_fini(); - if (ospf6) + if (ospf6) { ospf6_delete(ospf6); + ospf6 = NULL; + } bfd_gbl_exit(); @@ -97,6 +100,7 @@ static void __attribute__((noreturn)) ospf6_exit(int status) ospf6_asbr_terminate(); ospf6_lsa_terminate(); + ospf6_serv_close(); /* reverse access_list_init */ access_list_reset(); diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index cd688bbf89..4acb5e3b2e 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -1505,10 +1505,8 @@ int ospf6_iobuf_size(unsigned int size) recvnew = XMALLOC(MTYPE_OSPF6_MESSAGE, size); sendnew = XMALLOC(MTYPE_OSPF6_MESSAGE, size); - if (recvbuf) - XFREE(MTYPE_OSPF6_MESSAGE, recvbuf); - if (sendbuf) - XFREE(MTYPE_OSPF6_MESSAGE, sendbuf); + XFREE(MTYPE_OSPF6_MESSAGE, recvbuf); + XFREE(MTYPE_OSPF6_MESSAGE, sendbuf); recvbuf = recvnew; sendbuf = sendnew; iobuflen = size; diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c index bb451c239e..46dc621ae7 100644 --- a/ospf6d/ospf6_neighbor.c +++ b/ospf6d/ospf6_neighbor.c @@ -86,10 +86,7 @@ struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id, struct ospf6_neighbor *on; char buf[16]; - on = (struct ospf6_neighbor *)XMALLOC(MTYPE_OSPF6_NEIGHBOR, - sizeof(struct ospf6_neighbor)); - - memset(on, 0, sizeof(struct ospf6_neighbor)); + on = XCALLOC(MTYPE_OSPF6_NEIGHBOR, sizeof(struct ospf6_neighbor)); inet_ntop(AF_INET, &router_id, buf, sizeof(buf)); snprintf(on->name, sizeof(on->name), "%s%%%s", buf, oi->interface->name); diff --git a/ospf6d/ospf6_network.c b/ospf6d/ospf6_network.c index 8df5f1cc47..625ad884f2 100644 --- a/ospf6d/ospf6_network.c +++ b/ospf6d/ospf6_network.c @@ -73,6 +73,15 @@ static void ospf6_set_checksum(void) #endif /* DISABLE_IPV6_CHECKSUM */ } +void ospf6_serv_close(void) +{ + if (ospf6_sock > 0) { + close(ospf6_sock); + ospf6_sock = -1; + return; + } +} + /* Make ospf6d's server socket. */ int ospf6_serv_sock(void) { @@ -163,6 +172,7 @@ int ospf6_sendmsg(struct in6_addr *src, struct in6_addr *dst, assert(dst); assert(*ifindex); + memset(&cmsgbuf, 0, sizeof(cmsgbuf)); scmsgp = (struct cmsghdr *)&cmsgbuf; pktinfo = (struct in6_pktinfo *)(CMSG_DATA(scmsgp)); memset(&dst_sin6, 0, sizeof(struct sockaddr_in6)); diff --git a/ospf6d/ospf6_network.h b/ospf6d/ospf6_network.h index 7c7c155fbf..7fe6e33ff2 100644 --- a/ospf6d/ospf6_network.h +++ b/ospf6d/ospf6_network.h @@ -26,6 +26,7 @@ extern struct in6_addr allspfrouters6; extern struct in6_addr alldrouters6; extern int ospf6_serv_sock(void); +extern void ospf6_serv_close(void); extern int ospf6_sso(ifindex_t ifindex, struct in6_addr *group, int option); extern int ospf6_sendmsg(struct in6_addr *, struct in6_addr *, ifindex_t *, diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index 79e1a44392..b71b353e1f 100644 --- a/ospf6d/ospf6_route.c +++ b/ospf6d/ospf6_route.c @@ -174,8 +174,7 @@ struct ospf6_nexthop *ospf6_nexthop_create(void) void ospf6_nexthop_delete(struct ospf6_nexthop *nh) { - if (nh) - XFREE(MTYPE_OSPF6_NEXTHOP, nh); + XFREE(MTYPE_OSPF6_NEXTHOP, nh); } void ospf6_clear_nexthops(struct list *nh_list) diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c index 376950e84a..fc7c6177d7 100644 --- a/ospf6d/ospf6_snmp.c +++ b/ospf6d/ospf6_snmp.c @@ -1358,13 +1358,10 @@ static int ospf6TrapNbrStateChange(struct ospf6_neighbor *on, int next_state, index[1] = on->ospf6_if->instance_id; index[2] = ntohl(on->router_id); - smux_trap(ospfv3_variables, - sizeof ospfv3_variables / sizeof(struct variable), - ospfv3_trap_oid, sizeof ospfv3_trap_oid / sizeof(oid), - ospfv3_oid, sizeof ospfv3_oid / sizeof(oid), index, 3, - ospf6NbrTrapList, - sizeof ospf6NbrTrapList / sizeof(struct trap_object), - NBRSTATECHANGE); + smux_trap(ospfv3_variables, array_size(ospfv3_variables), + ospfv3_trap_oid, array_size(ospfv3_trap_oid), ospfv3_oid, + sizeof ospfv3_oid / sizeof(oid), index, 3, ospf6NbrTrapList, + array_size(ospf6NbrTrapList), NBRSTATECHANGE); return 0; } @@ -1383,13 +1380,10 @@ static int ospf6TrapIfStateChange(struct ospf6_interface *oi, int next_state, index[0] = oi->interface->ifindex; index[1] = oi->instance_id; - smux_trap(ospfv3_variables, - sizeof ospfv3_variables / sizeof(struct variable), - ospfv3_trap_oid, sizeof ospfv3_trap_oid / sizeof(oid), - ospfv3_oid, sizeof ospfv3_oid / sizeof(oid), index, 2, - ospf6IfTrapList, - sizeof ospf6IfTrapList / sizeof(struct trap_object), - IFSTATECHANGE); + smux_trap(ospfv3_variables, array_size(ospfv3_variables), + ospfv3_trap_oid, array_size(ospfv3_trap_oid), ospfv3_oid, + sizeof ospfv3_oid / sizeof(oid), index, 2, ospf6IfTrapList, + array_size(ospf6IfTrapList), IFSTATECHANGE); return 0; } diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index 2d271c1dab..f08426fb47 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -107,8 +107,7 @@ static struct ospf6_vertex *ospf6_vertex_create(struct ospf6_lsa *lsa) { struct ospf6_vertex *v; - v = (struct ospf6_vertex *)XMALLOC(MTYPE_OSPF6_VERTEX, - sizeof(struct ospf6_vertex)); + v = XMALLOC(MTYPE_OSPF6_VERTEX, sizeof(struct ospf6_vertex)); /* type */ if (ntohs(lsa->header->type) == OSPF6_LSTYPE_ROUTER) { @@ -476,7 +475,7 @@ void ospf6_spf_calculation(uint32_t router_id, lsa = ospf6_create_single_router_lsa(oa, oa->lsdb_self, router_id); if (lsa == NULL) { if (IS_OSPF6_DEBUG_SPF(PROCESS)) - zlog_debug("%s: No router LSA for area %s\n", __func__, + zlog_debug("%s: No router LSA for area %s", __func__, oa->name); return; } @@ -1016,8 +1015,7 @@ struct ospf6_lsa *ospf6_create_single_router_lsa(struct ospf6_area *area, new_header = XMALLOC(MTYPE_OSPF6_LSA_HEADER, total_lsa_length); /* LSA information structure */ - lsa = (struct ospf6_lsa *)XCALLOC(MTYPE_OSPF6_LSA, - sizeof(struct ospf6_lsa)); + lsa = XCALLOC(MTYPE_OSPF6_LSA, sizeof(struct ospf6_lsa)); lsa->header = (struct ospf6_lsa_header *)new_header; diff --git a/ospfd/ospf_api.c b/ospfd/ospf_api.c index a3b337a0c0..f06e45392e 100644 --- a/ospfd/ospf_api.c +++ b/ospfd/ospf_api.c @@ -74,12 +74,12 @@ void api_opaque_lsa_print(struct lsa_header *data) olsa = (struct opaque_lsa *)data; opaquelen = ntohs(data->length) - OSPF_LSA_HEADER_SIZE; - zlog_debug("apiserver_lsa_print: opaquelen=%d\n", opaquelen); + zlog_debug("apiserver_lsa_print: opaquelen=%d", opaquelen); for (i = 0; i < opaquelen; i++) { zlog_debug("0x%x ", olsa->mydata[i]); } - zlog_debug("\n"); + zlog_debug(" "); } /* ----------------------------------------------------------- @@ -242,7 +242,7 @@ const char *ospf_api_errname(int errcode) void msg_print(struct msg *msg) { if (!msg) { - zlog_debug("msg_print msg=NULL!\n"); + zlog_debug("msg_print msg=NULL!"); return; } diff --git a/ospfd/ospf_apiserver.c b/ospfd/ospf_apiserver.c index d0ee818722..d6f1fba28b 100644 --- a/ospfd/ospf_apiserver.c +++ b/ospfd/ospf_apiserver.c @@ -2024,7 +2024,7 @@ int ospf_apiserver_del_if(struct interface *ifp) /* zlog_warn for debugging */ zlog_warn("ospf_apiserver_del_if"); - zlog_warn("ifp name=%s status=%d index=%d\n", ifp->name, ifp->status, + zlog_warn("ifp name=%s status=%d index=%d", ifp->name, ifp->status, ifp->ifindex); oi = ospf_apiserver_if_lookup_by_ifp(ifp); @@ -2110,7 +2110,6 @@ void ospf_apiserver_show_info(struct vty *vty, struct ospf_lsa *lsa) for (i = 0; i < opaquelen; i++) { zlog_debug("0x%x ", olsa->data[i]); } - zlog_debug("\n"); } return; } diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c index ba2e04bf76..ea919017d3 100644 --- a/ospfd/ospf_asbr.c +++ b/ospfd/ospf_asbr.c @@ -79,8 +79,7 @@ struct external_info *ospf_external_info_new(uint8_t type, { struct external_info *new; - new = (struct external_info *)XCALLOC(MTYPE_OSPF_EXTERNAL_INFO, - sizeof(struct external_info)); + new = XCALLOC(MTYPE_OSPF_EXTERNAL_INFO, sizeof(struct external_info)); new->type = type; new->instance = instance; diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c index 48d210d279..f74d9733ee 100644 --- a/ospfd/ospf_dump.c +++ b/ospfd/ospf_dump.c @@ -538,8 +538,7 @@ static void ospf_header_dump(struct ospf_header *ospfh) case OSPF_AUTH_NULL: break; case OSPF_AUTH_SIMPLE: - memset(buf, 0, 9); - strncpy(buf, (char *)ospfh->u.auth_data, 8); + strlcpy(buf, (char *)ospfh->u.auth_data, sizeof(buf)); zlog_debug(" Simple Password %s", buf); break; case OSPF_AUTH_CRYPTOGRAPHIC: diff --git a/ospfd/ospf_errors.c b/ospfd/ospf_errors.c index b912a80692..dd02160195 100644 --- a/ospfd/ospf_errors.c +++ b/ospfd/ospf_errors.c @@ -172,11 +172,8 @@ static struct log_ref ferr_ospf_err[] = { { .code = EC_OSPF_LARGE_HELLO, .title = "OSPF Encountered a Large Hello", - .description = "OSPF attempted to send a Hello larger than MTU " - "but did not", - .suggestion = "Too many neighbors configured on a single interface." - " Suggestion is to decrease the number of neighbors on" - " a single interface/subnet" + .description = "OSPF attempted to send a Hello larger than MTU but did not", + .suggestion = "Too many neighbors configured on a single interface. Suggestion is to decrease the number of neighbors on a single interface/subnet" }, { .code = END_FERR, diff --git a/ospfd/ospf_ism.c b/ospfd/ospf_ism.c index 9fd9a70c78..419081fe59 100644 --- a/ospfd/ospf_ism.c +++ b/ospfd/ospf_ism.c @@ -380,12 +380,10 @@ static int ism_interface_up(struct ospf_interface *oi) static int ism_loop_ind(struct ospf_interface *oi) { - int ret = 0; - /* call ism_interface_down. */ /* ret = ism_interface_down (oi); */ - return ret; + return 0; } /* Interface down event handler. */ diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index ecc55c2ee5..b3c91b9006 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -3326,8 +3326,7 @@ static int ospf_make_hello(struct ospf_interface *oi, struct stream *s) > ospf_packet_max(oi)) { flog_err( EC_OSPF_LARGE_HELLO, - "Oversized Hello packet!" - " Larger than MTU. Not sending it out"); + "Oversized Hello packet! Larger than MTU. Not sending it out"); return 0; } diff --git a/ospfd/ospf_ri.c b/ospfd/ospf_ri.c index 4a0d4add15..5f01edfbdf 100644 --- a/ospfd/ospf_ri.c +++ b/ospfd/ospf_ri.c @@ -1372,14 +1372,14 @@ static uint16_t show_vty_sr_algorithm(struct vty *vty, struct tlv_header *tlvh) } else { - zlog_debug(" Segment Routing Algorithm TLV:\n"); + zlog_debug(" Segment Routing Algorithm TLV:"); for (i = 0; i < ntohs(algo->header.length); i++) switch (algo->value[i]) { case 0: - zlog_debug(" Algorithm %d: SPF\n", i); + zlog_debug(" Algorithm %d: SPF", i); break; case 1: - zlog_debug(" Algorithm %d: Strict SPF\n", i); + zlog_debug(" Algorithm %d: Strict SPF", i); break; default: zlog_debug( diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c index 755634a2f1..c26545344a 100644 --- a/ospfd/ospf_snmp.c +++ b/ospfd/ospf_snmp.c @@ -901,7 +901,7 @@ static struct ospf_lsa *lsdb_lookup_next(struct ospf_area *area, uint8_t *type, /* Sanity check, if LSA type unknwon merley skip any LSA */ if ((i < OSPF_MIN_LSA) || (i >= OSPF_MAX_LSA)) { - zlog_debug("Strange request with LSA type %d\n", i); + zlog_debug("Strange request with LSA type %d", i); return NULL; } @@ -2590,13 +2590,10 @@ static void ospfTrapNbrStateChange(struct ospf_neighbor *on) oid_copy_addr(index, &(on->address.u.prefix4), IN_ADDR_SIZE); index[IN_ADDR_SIZE] = 0; - smux_trap(ospf_variables, - sizeof ospf_variables / sizeof(struct variable), - ospf_trap_oid, sizeof ospf_trap_oid / sizeof(oid), ospf_oid, + smux_trap(ospf_variables, array_size(ospf_variables), ospf_trap_oid, + array_size(ospf_trap_oid), ospf_oid, sizeof ospf_oid / sizeof(oid), index, IN_ADDR_SIZE + 1, - ospfNbrTrapList, - sizeof ospfNbrTrapList / sizeof(struct trap_object), - NBRSTATECHANGE); + ospfNbrTrapList, array_size(ospfNbrTrapList), NBRSTATECHANGE); } static void ospfTrapVirtNbrStateChange(struct ospf_neighbor *on) @@ -2608,12 +2605,10 @@ static void ospfTrapVirtNbrStateChange(struct ospf_neighbor *on) oid_copy_addr(index, &(on->address.u.prefix4), IN_ADDR_SIZE); index[IN_ADDR_SIZE] = 0; - smux_trap(ospf_variables, - sizeof ospf_variables / sizeof(struct variable), - ospf_trap_oid, sizeof ospf_trap_oid / sizeof(oid), ospf_oid, + smux_trap(ospf_variables, array_size(ospf_variables), ospf_trap_oid, + array_size(ospf_trap_oid), ospf_oid, sizeof ospf_oid / sizeof(oid), index, IN_ADDR_SIZE + 1, - ospfVirtNbrTrapList, - sizeof ospfVirtNbrTrapList / sizeof(struct trap_object), + ospfVirtNbrTrapList, array_size(ospfVirtNbrTrapList), VIRTNBRSTATECHANGE); } @@ -2649,13 +2644,10 @@ static void ospfTrapIfStateChange(struct ospf_interface *oi) oid_copy_addr(index, &(oi->address->u.prefix4), IN_ADDR_SIZE); index[IN_ADDR_SIZE] = 0; - smux_trap(ospf_variables, - sizeof ospf_variables / sizeof(struct variable), - ospf_trap_oid, sizeof ospf_trap_oid / sizeof(oid), ospf_oid, + smux_trap(ospf_variables, array_size(ospf_variables), ospf_trap_oid, + array_size(ospf_trap_oid), ospf_oid, sizeof ospf_oid / sizeof(oid), index, IN_ADDR_SIZE + 1, - ospfIfTrapList, - sizeof ospfIfTrapList / sizeof(struct trap_object), - IFSTATECHANGE); + ospfIfTrapList, array_size(ospfIfTrapList), IFSTATECHANGE); } static void ospfTrapVirtIfStateChange(struct ospf_interface *oi) @@ -2667,12 +2659,10 @@ static void ospfTrapVirtIfStateChange(struct ospf_interface *oi) oid_copy_addr(index, &(oi->address->u.prefix4), IN_ADDR_SIZE); index[IN_ADDR_SIZE] = 0; - smux_trap(ospf_variables, - sizeof ospf_variables / sizeof(struct variable), - ospf_trap_oid, sizeof ospf_trap_oid / sizeof(oid), ospf_oid, + smux_trap(ospf_variables, array_size(ospf_variables), ospf_trap_oid, + array_size(ospf_trap_oid), ospf_oid, sizeof ospf_oid / sizeof(oid), index, IN_ADDR_SIZE + 1, - ospfVirtIfTrapList, - sizeof ospfVirtIfTrapList / sizeof(struct trap_object), + ospfVirtIfTrapList, array_size(ospfVirtIfTrapList), VIRTIFSTATECHANGE); } diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c index 9c223facd3..74dba273e6 100644 --- a/ospfd/ospf_spf.c +++ b/ospfd/ospf_spf.c @@ -1140,13 +1140,13 @@ ospf_rtrs_print (struct route_table *rtrs) if (path->nexthop.s_addr == 0) { if (IS_DEBUG_OSPF_EVENT) - zlog_debug (" directly attached to %s\r\n", + zlog_debug (" directly attached to %s\r", ifindex2ifname (path->ifindex), VRF_DEFAULT); } else { if (IS_DEBUG_OSPF_EVENT) - zlog_debug (" via %s, %s\r\n", + zlog_debug (" via %s, %s\r", inet_ntoa (path->nexthop), ifindex2ifname (path->ifindex), VRF_DEFAULT); } diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c index 43842e414e..a493520868 100644 --- a/ospfd/ospf_sr.c +++ b/ospfd/ospf_sr.c @@ -1020,10 +1020,10 @@ static void update_ext_prefix_sid(struct sr_node *srn, struct sr_prefix *srp) * When change the FRR Self SRGB, update the NHLFE Input Label * for all Extended Prefix with SID index through hash_iterate() */ -static void update_in_nhlfe(struct hash_backet *backet, void *args) +static void update_in_nhlfe(struct hash_bucket *bucket, void *args) { struct listnode *node; - struct sr_node *srn = (struct sr_node *)backet->data; + struct sr_node *srn = (struct sr_node *)bucket->data; struct sr_prefix *srp; struct sr_nhlfe new; @@ -1052,10 +1052,10 @@ static void update_in_nhlfe(struct hash_backet *backet, void *args) * When SRGB has changed, update NHLFE Output Label for all Extended Prefix * with SID index which use the given SR-Node as nexthop though hash_iterate() */ -static void update_out_nhlfe(struct hash_backet *backet, void *args) +static void update_out_nhlfe(struct hash_bucket *bucket, void *args) { struct listnode *node; - struct sr_node *srn = (struct sr_node *)backet->data; + struct sr_node *srn = (struct sr_node *)bucket->data; struct sr_node *srnext = (struct sr_node *)args; struct sr_prefix *srp; struct sr_nhlfe new; @@ -1192,7 +1192,7 @@ void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa) /* Update NHLFE if it is a neighbor SR node */ if (srn->neighbor == OspfSR.self) hash_iterate(OspfSR.neighbors, - (void (*)(struct hash_backet *, + (void (*)(struct hash_bucket *, void *))update_out_nhlfe, (void *)srn); } @@ -1531,10 +1531,10 @@ void ospf_sr_update_prefix(struct interface *ifp, struct prefix *p) * Following functions are used to update MPLS LFIB after a SPF run */ -static void ospf_sr_nhlfe_update(struct hash_backet *backet, void *args) +static void ospf_sr_nhlfe_update(struct hash_bucket *bucket, void *args) { - struct sr_node *srn = (struct sr_node *)backet->data; + struct sr_node *srn = (struct sr_node *)bucket->data; struct listnode *node; struct sr_prefix *srp; struct sr_nhlfe old; @@ -1593,14 +1593,14 @@ static int ospf_sr_update_schedule(struct thread *t) if (IS_DEBUG_OSPF_SR) zlog_debug("SR (%s): Start SPF update", __func__); - hash_iterate(OspfSR.neighbors, (void (*)(struct hash_backet *, + hash_iterate(OspfSR.neighbors, (void (*)(struct hash_bucket *, void *))ospf_sr_nhlfe_update, NULL); monotime(&stop_time); if (IS_DEBUG_OSPF_SR) - zlog_debug("SR (%s): SPF Processing Time(usecs): %lld\n", + zlog_debug("SR (%s): SPF Processing Time(usecs): %lld", __func__, (stop_time.tv_sec - start_time.tv_sec) * 1000000LL + (stop_time.tv_usec - start_time.tv_usec)); @@ -1818,7 +1818,7 @@ DEFUN (sr_sid_label_range, /* Update NHLFE entries */ hash_iterate(OspfSR.neighbors, - (void (*)(struct hash_backet *, void *))update_in_nhlfe, + (void (*)(struct hash_bucket *, void *))update_in_nhlfe, NULL); return CMD_SUCCESS; @@ -1850,7 +1850,7 @@ DEFUN (no_sr_sid_label_range, /* Update NHLFE entries */ hash_iterate(OspfSR.neighbors, - (void (*)(struct hash_backet *, void *))update_in_nhlfe, + (void (*)(struct hash_bucket *, void *))update_in_nhlfe, NULL); return CMD_SUCCESS; @@ -2281,18 +2281,18 @@ static void show_sr_node(struct vty *vty, struct json_object *json, vty_out(vty, "\n"); } -static void show_vty_srdb(struct hash_backet *backet, void *args) +static void show_vty_srdb(struct hash_bucket *bucket, void *args) { struct vty *vty = (struct vty *)args; - struct sr_node *srn = (struct sr_node *)backet->data; + struct sr_node *srn = (struct sr_node *)bucket->data; show_sr_node(vty, NULL, srn); } -static void show_json_srdb(struct hash_backet *backet, void *args) +static void show_json_srdb(struct hash_bucket *bucket, void *args) { struct json_object *json = (struct json_object *)args; - struct sr_node *srn = (struct sr_node *)backet->data; + struct sr_node *srn = (struct sr_node *)bucket->data; show_sr_node(NULL, json, srn); } @@ -2366,14 +2366,14 @@ DEFUN (show_ip_opsf_srdb, /* No parameters have been provided, Iterate through all the SRDB */ if (uj) { - hash_iterate(OspfSR.neighbors, (void (*)(struct hash_backet *, + hash_iterate(OspfSR.neighbors, (void (*)(struct hash_bucket *, void *))show_json_srdb, (void *)json_node_array); vty_out(vty, "%s\n", json_object_to_json_string_ext( json, JSON_C_TO_STRING_PRETTY)); json_object_free(json); } else { - hash_iterate(OspfSR.neighbors, (void (*)(struct hash_backet *, + hash_iterate(OspfSR.neighbors, (void (*)(struct hash_bucket *, void *))show_vty_srdb, (void *)vty); } diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index c1dc1f0d6f..b5d8739fcb 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -954,8 +954,9 @@ static int ospf_vl_set_security(struct ospf_vl_data *vl_data, if (vl_config->auth_key) { memset(IF_DEF_PARAMS(ifp)->auth_simple, 0, OSPF_AUTH_SIMPLE_SIZE + 1); - strncpy((char *)IF_DEF_PARAMS(ifp)->auth_simple, - vl_config->auth_key, OSPF_AUTH_SIMPLE_SIZE); + strlcpy((char *)IF_DEF_PARAMS(ifp)->auth_simple, + vl_config->auth_key, + sizeof(IF_DEF_PARAMS(ifp)->auth_simple)); } else if (vl_config->md5_key) { if (ospf_crypt_key_lookup(IF_DEF_PARAMS(ifp)->auth_crypt, vl_config->crypto_key_id) @@ -967,8 +968,8 @@ static int ospf_vl_set_security(struct ospf_vl_data *vl_data, ck = ospf_crypt_key_new(); ck->key_id = vl_config->crypto_key_id; memset(ck->auth_key, 0, OSPF_AUTH_MD5_SIZE + 1); - strncpy((char *)ck->auth_key, vl_config->md5_key, - OSPF_AUTH_MD5_SIZE); + strlcpy((char *)ck->auth_key, vl_config->md5_key, + sizeof(ck->auth_key)); ospf_crypt_key_add(IF_DEF_PARAMS(ifp)->auth_crypt, ck); } else if (vl_config->crypto_key_id != 0) { @@ -1147,14 +1148,12 @@ DEFUN (ospf_area_vlink, if (vl_config.crypto_key_id < 0) return CMD_WARNING_CONFIG_FAILED; - memset(md5_key, 0, OSPF_AUTH_MD5_SIZE + 1); - strncpy(md5_key, argv[idx + 3]->arg, OSPF_AUTH_MD5_SIZE); + strlcpy(md5_key, argv[idx + 3]->arg, sizeof(md5_key)); vl_config.md5_key = md5_key; } if (argv_find(argv, argc, "authentication-key", &idx)) { - memset(auth_key, 0, OSPF_AUTH_SIMPLE_SIZE + 1); - strncpy(auth_key, argv[idx + 1]->arg, OSPF_AUTH_SIMPLE_SIZE); + strlcpy(auth_key, argv[idx + 1]->arg, sizeof(auth_key)); vl_config.auth_key = auth_key; } @@ -3030,13 +3029,13 @@ static int show_ip_ospf_common(struct vty *vty, struct ospf *ospf, if (ospf->stub_router_startup_time != OSPF_STUB_ROUTER_UNCONFIGURED) json_object_int_add( - json_vrf, "postStartEnabledMsecs", - ospf->stub_router_startup_time / 1000); + json_vrf, "postStartEnabledSecs", + ospf->stub_router_startup_time); if (ospf->stub_router_shutdown_time != OSPF_STUB_ROUTER_UNCONFIGURED) json_object_int_add( - json_vrf, "preShutdownEnabledMsecs", - ospf->stub_router_shutdown_time / 1000); + json_vrf, "preShutdownEnabledSecs", + ospf->stub_router_shutdown_time); } else { vty_out(vty, " Stub router advertisement is configured\n"); @@ -3512,8 +3511,8 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_object_int_add(json_interface_sub, "cost", oi->output_cost); json_object_int_add( - json_interface_sub, "transmitDelayMsecs", - 1000 / OSPF_IF_PARAM(oi, transmit_delay)); + json_interface_sub, "transmitDelaySecs", + OSPF_IF_PARAM(oi, transmit_delay)); json_object_string_add(json_interface_sub, "state", lookup_msg(ospf_ism_state_msg, oi->state, NULL)); @@ -3617,20 +3616,20 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, if (OSPF_IF_PARAM(oi, fast_hello) == 0) json_object_int_add( json_interface_sub, "timerMsecs", - 1000 / OSPF_IF_PARAM(oi, v_hello)); + OSPF_IF_PARAM(oi, v_hello) * 1000); else json_object_int_add( json_interface_sub, "timerMsecs", 1000 / OSPF_IF_PARAM(oi, fast_hello)); json_object_int_add(json_interface_sub, - "timerDeadMsecs", - 1000 / OSPF_IF_PARAM(oi, v_wait)); + "timerDeadSecs", + OSPF_IF_PARAM(oi, v_wait)); json_object_int_add(json_interface_sub, - "timerWaitMsecs", - 1000 / OSPF_IF_PARAM(oi, v_wait)); + "timerWaitSecs", + OSPF_IF_PARAM(oi, v_wait)); json_object_int_add( - json_interface_sub, "timerRetransmit", - 1000 / OSPF_IF_PARAM(oi, retransmit_interval)); + json_interface_sub, "timerRetransmitSecs", + OSPF_IF_PARAM(oi, retransmit_interval)); } else { vty_out(vty, " Timer intervals configured,"); vty_out(vty, " Hello "); @@ -6895,9 +6894,8 @@ DEFUN (ip_ospf_authentication_key, ospf_if_update_params(ifp, addr); } - memset(params->auth_simple, 0, OSPF_AUTH_SIMPLE_SIZE + 1); - strncpy((char *)params->auth_simple, argv[3]->arg, - OSPF_AUTH_SIMPLE_SIZE); + strlcpy((char *)params->auth_simple, argv[3]->arg, + sizeof(params->auth_simple)); SET_IF_PARAM(params, auth_simple); return CMD_SUCCESS; @@ -7006,8 +7004,7 @@ DEFUN (ip_ospf_message_digest_key, ck = ospf_crypt_key_new(); ck->key_id = (uint8_t)key_id; - memset(ck->auth_key, 0, OSPF_AUTH_MD5_SIZE + 1); - strncpy((char *)ck->auth_key, cryptkey, OSPF_AUTH_MD5_SIZE); + strlcpy((char *)ck->auth_key, cryptkey, sizeof(ck->auth_key)); ospf_crypt_key_add(params->auth_crypt, ck); SET_IF_PARAM(params, auth_crypt); diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index ea2c492e18..4cbd817ad8 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -560,8 +560,7 @@ struct ospf_external *ospf_external_add(struct ospf *ospf, uint8_t type, ospf->external[type] = list_new(); ext_list = ospf->external[type]; - ext = (struct ospf_external *)XCALLOC(MTYPE_OSPF_EXTERNAL, - sizeof(struct ospf_external)); + ext = XCALLOC(MTYPE_OSPF_EXTERNAL, sizeof(struct ospf_external)); ext->instance = instance; EXTERNAL_INFO(ext) = route_table_init(); @@ -621,8 +620,7 @@ struct ospf_redist *ospf_redist_add(struct ospf *ospf, uint8_t type, ospf->redist[type] = list_new(); red_list = ospf->redist[type]; - red = (struct ospf_redist *)XCALLOC(MTYPE_OSPF_REDISTRIBUTE, - sizeof(struct ospf_redist)); + red = XCALLOC(MTYPE_OSPF_REDISTRIBUTE, sizeof(struct ospf_redist)); red->instance = instance; red->dmetric.type = -1; red->dmetric.value = -1; diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index a18e2de725..073a51561b 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -234,8 +234,12 @@ static struct ospf *ospf_new(unsigned short instance, const char *name) new->instance = instance; new->router_id.s_addr = htonl(0); new->router_id_static.s_addr = htonl(0); - if (name && !strmatch(name, VRF_DEFAULT_NAME)) { - new->vrf_id = VRF_UNKNOWN; + if (name) { + vrf = vrf_lookup_by_name(name); + if (vrf) + new->vrf_id = vrf->vrf_id; + else + new->vrf_id = VRF_UNKNOWN; /* Freed in ospf_finish_final */ new->name = XSTRDUP(MTYPE_OSPF_TOP, name); if (IS_DEBUG_OSPF_EVENT) diff --git a/pbrd/pbr_map.c b/pbrd/pbr_map.c index eb2c082fb9..5e67990d5e 100644 --- a/pbrd/pbr_map.c +++ b/pbrd/pbr_map.c @@ -71,8 +71,7 @@ static int pbr_map_sequence_compare(const struct pbr_map_sequence *pbrms1, static void pbr_map_sequence_delete(struct pbr_map_sequence *pbrms) { - if (pbrms->internal_nhg_name) - XFREE(MTYPE_TMP, pbrms->internal_nhg_name); + XFREE(MTYPE_TMP, pbrms->internal_nhg_name); XFREE(MTYPE_PBR_MAP_SEQNO, pbrms); } @@ -121,6 +120,17 @@ void pbr_map_reason_string(unsigned int reason, char *buf, int size) } } +void pbr_map_final_interface_deletion(struct pbr_map *pbrm, + struct pbr_map_interface *pmi) +{ + if (pmi->delete == true) { + listnode_delete(pbrm->incoming, pmi); + pmi->pbrm = NULL; + + bf_release_index(pbrm->ifi_bitfield, pmi->install_bit); + XFREE(MTYPE_PBR_MAP_INTERFACE, pmi); + } +} void pbr_map_interface_delete(struct pbr_map *pbrm, struct interface *ifp_del) { @@ -409,7 +419,8 @@ void pbr_map_schedule_policy_from_nhg(const char *nh_group) pbrm->name); for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) { DEBUGD(&pbr_dbg_map, "\tNH Grp name: %s", - pbrms->nhgrp_name ? pbrms->nhgrp_name : "NULL"); + pbrms->nhgrp_name ? + pbrms->nhgrp_name : pbrms->internal_nhg_name); if (pbrms->nhgrp_name && (strcmp(nh_group, pbrms->nhgrp_name) == 0)) { @@ -465,11 +476,7 @@ void pbr_map_policy_delete(struct pbr_map *pbrm, struct pbr_map_interface *pmi) for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) pbr_send_pbr_map(pbrms, pmi, false); - listnode_delete(pbrm->incoming, pmi); - pmi->pbrm = NULL; - - bf_release_index(pbrm->ifi_bitfield, pmi->install_bit); - XFREE(MTYPE_PBR_MAP_INTERFACE, pmi); + pmi->delete = true; } /* @@ -526,12 +533,9 @@ void pbr_map_check(struct pbr_map_sequence *pbrms) DEBUGD(&pbr_dbg_map, "%s: for %s(%u)", __PRETTY_FUNCTION__, pbrm->name, pbrms->seqno); if (pbr_map_check_valid(pbrm->name)) - DEBUGD(&pbr_dbg_map, "We are totally valid %s\n", + DEBUGD(&pbr_dbg_map, "We are totally valid %s", pbrm->name); - DEBUGD(&pbr_dbg_map, "%s: Installing %s(%u) reason: %" PRIu64, - __PRETTY_FUNCTION__, pbrm->name, pbrms->seqno, pbrms->reason); - if (pbrms->reason == PBR_MAP_VALID_SEQUENCE_NUMBER) { install = true; DEBUGD(&pbr_dbg_map, "%s: Installing %s(%u) reason: %" PRIu64, diff --git a/pbrd/pbr_map.h b/pbrd/pbr_map.h index 7cd079d169..945f76bb2b 100644 --- a/pbrd/pbr_map.h +++ b/pbrd/pbr_map.h @@ -147,6 +147,8 @@ extern void pbr_map_delete_nexthop_group(struct pbr_map_sequence *pbrms); extern void pbr_map_add_interface(struct pbr_map *pbrm, struct interface *ifp); extern void pbr_map_interface_delete(struct pbr_map *pbrm, struct interface *ifp); +extern void pbr_map_final_interface_deletion(struct pbr_map *pbrm, + struct pbr_map_interface *pmi); extern void pbr_map_write_interfaces(struct vty *vty, struct interface *ifp); extern void pbr_map_init(void); diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c index 6103bd7db5..7504752725 100644 --- a/pbrd/pbr_nht.c +++ b/pbrd/pbr_nht.c @@ -50,7 +50,7 @@ static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache *pnhgc, static void pbr_nht_uninstall_nexthop_group(struct pbr_nexthop_group_cache *pnhgc, struct nexthop_group nhg, - enum nexthop_types_t nh_afi); + enum nexthop_types_t nh_type); /* * Nexthop refcount. @@ -124,7 +124,7 @@ static void pbr_nh_delete(struct pbr_nexthop_cache **pnhc) XFREE(MTYPE_PBR_NHG, *pnhc); } -static void pbr_nh_delete_iterate(struct hash_backet *b, void *p) +static void pbr_nh_delete_iterate(struct hash_bucket *b, void *p) { pbr_nh_delete((struct pbr_nexthop_cache **)&b->data); } @@ -157,15 +157,15 @@ static bool pbr_nh_hash_equal(const void *arg1, const void *arg2) switch (pbrnc1->nexthop->type) { case NEXTHOP_TYPE_IFINDEX: - return true; + return pbrnc1->nexthop->ifindex == pbrnc2->nexthop->ifindex; case NEXTHOP_TYPE_IPV4_IFINDEX: case NEXTHOP_TYPE_IPV4: return pbrnc1->nexthop->gate.ipv4.s_addr == pbrnc2->nexthop->gate.ipv4.s_addr; case NEXTHOP_TYPE_IPV6_IFINDEX: case NEXTHOP_TYPE_IPV6: - return !!memcmp(&pbrnc1->nexthop->gate.ipv6, - &pbrnc2->nexthop->gate.ipv6, 16); + return !memcmp(&pbrnc1->nexthop->gate.ipv6, + &pbrnc2->nexthop->gate.ipv6, 16); case NEXTHOP_TYPE_BLACKHOLE: return pbrnc1->nexthop->bh_type == pbrnc2->nexthop->bh_type; } @@ -264,6 +264,14 @@ void pbr_nhgroup_add_nexthop_cb(const struct nexthop_group_cmd *nhgc, pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg); pbr_map_check_nh_group_change(nhgc->name); + + if (nhop->type == NEXTHOP_TYPE_IFINDEX) { + struct interface *ifp; + + ifp = if_lookup_by_index(nhop->ifindex, nhop->vrf_id); + if (ifp) + pbr_nht_nexthop_interface_update(ifp); + } } void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc, @@ -274,7 +282,7 @@ void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc, struct pbr_nexthop_group_cache *pnhgc; struct pbr_nexthop_cache pnhc_find = {}; struct pbr_nexthop_cache *pnhc; - enum nexthop_types_t nh_afi = nhop->type; + enum nexthop_types_t nh_type = nhop->type; /* find pnhgc by name */ strlcpy(pnhgc_find.name, nhgc->name, sizeof(pnhgc_find.name)); @@ -296,7 +304,7 @@ void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc, if (pnhgc->nhh->count) pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg); else - pbr_nht_uninstall_nexthop_group(pnhgc, nhgc->nhg, nh_afi); + pbr_nht_uninstall_nexthop_group(pnhgc, nhgc->nhg, nh_type); pbr_map_check_nh_group_change(nhgc->name); } @@ -319,7 +327,7 @@ static struct pbr_nexthop_cache *pbr_nht_lookup_nexthop(struct nexthop *nexthop) } #endif -static void pbr_nht_find_nhg_from_table_install(struct hash_backet *b, +static void pbr_nht_find_nhg_from_table_install(struct hash_bucket *b, void *data) { struct pbr_nexthop_group_cache *pnhgc = @@ -348,7 +356,7 @@ void pbr_nht_route_installed_for_table(uint32_t table_id) &table_id); } -static void pbr_nht_find_nhg_from_table_remove(struct hash_backet *b, +static void pbr_nht_find_nhg_from_table_remove(struct hash_bucket *b, void *data) { ; @@ -372,39 +380,53 @@ void pbr_nht_route_removed_for_table(uint32_t table_id) * - AFI_MAX on error */ static afi_t pbr_nht_which_afi(struct nexthop_group nhg, - enum nexthop_types_t nh_afi) + enum nexthop_types_t nh_type) { struct nexthop *nexthop; afi_t install_afi = AFI_MAX; bool v6, v4, bh; + if (nh_type) { + switch (nh_type) { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + return AFI_IP; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + return AFI_IP6; + case NEXTHOP_TYPE_IFINDEX: + case NEXTHOP_TYPE_BLACKHOLE: + return AFI_MAX; + } + } + v6 = v4 = bh = false; - if (!nh_afi) { - for (ALL_NEXTHOPS(nhg, nexthop)) { - nh_afi = nexthop->type; + for (ALL_NEXTHOPS(nhg, nexthop)) { + nh_type = nexthop->type; + + switch (nh_type) { + case NEXTHOP_TYPE_IFINDEX: + break; + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + v6 = true; + install_afi = AFI_IP; + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + v4 = true; + install_afi = AFI_IP6; + break; + case NEXTHOP_TYPE_BLACKHOLE: + bh = true; break; } } - switch (nh_afi) { - case NEXTHOP_TYPE_IFINDEX: - break; - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV4_IFINDEX: - v6 = true; - install_afi = AFI_IP; - break; - case NEXTHOP_TYPE_IPV6: - case NEXTHOP_TYPE_IPV6_IFINDEX: - v4 = true; - install_afi = AFI_IP6; - break; - case NEXTHOP_TYPE_BLACKHOLE: - bh = true; + /* Interface and/or blackhole nexthops only. */ + if (!v4 && !v6) install_afi = AFI_MAX; - break; - } if (!bh && v6 && v4) DEBUGD(&pbr_dbg_nht, @@ -423,9 +445,9 @@ static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache *pnhgc, struct nexthop_group nhg) { afi_t install_afi; - enum nexthop_types_t nh_afi = 0; + enum nexthop_types_t nh_type = 0; - install_afi = pbr_nht_which_afi(nhg, nh_afi); + install_afi = pbr_nht_which_afi(nhg, nh_type); route_add(pnhgc, nhg, install_afi); } @@ -433,11 +455,11 @@ static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache *pnhgc, static void pbr_nht_uninstall_nexthop_group(struct pbr_nexthop_group_cache *pnhgc, struct nexthop_group nhg, - enum nexthop_types_t nh_afi) + enum nexthop_types_t nh_type) { afi_t install_afi; - install_afi = pbr_nht_which_afi(nhg, nh_afi); + install_afi = pbr_nht_which_afi(nhg, nh_type); pnhgc->installed = false; pnhgc->valid = false; @@ -526,7 +548,7 @@ void pbr_nht_delete_individual_nexthop(struct pbr_map_sequence *pbrms) struct listnode *node; struct pbr_map_interface *pmi; struct nexthop *nh; - enum nexthop_types_t nh_afi = 0; + enum nexthop_types_t nh_type = 0; if (pbrm->valid && pbrms->nhs_installed && pbrm->incoming->count) { for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi)) @@ -542,13 +564,13 @@ void pbr_nht_delete_individual_nexthop(struct pbr_map_sequence *pbrms) pnhgc = hash_lookup(pbr_nhg_hash, &find); nh = pbrms->nhg->nexthop; - nh_afi = nh->type; + nh_type = nh->type; lup.nexthop = nh; pnhc = hash_lookup(pnhgc->nhh, &lup); pnhc->parent = NULL; hash_release(pnhgc->nhh, pnhc); pbr_nh_delete(&pnhc); - pbr_nht_uninstall_nexthop_group(pnhgc, *pbrms->nhg, nh_afi); + pbr_nht_uninstall_nexthop_group(pnhgc, *pbrms->nhg, nh_type); hash_release(pbr_nhg_hash, pnhgc); @@ -653,11 +675,12 @@ bool pbr_nht_nexthop_group_valid(const char *name) struct pbr_nht_individual { struct zapi_route *nhr; + struct interface *ifp; uint32_t valid; }; -static void pbr_nht_individual_nexthop_update_lookup(struct hash_backet *b, +static void pbr_nht_individual_nexthop_update_lookup(struct hash_bucket *b, void *data) { struct pbr_nexthop_cache *pnhc = b->data; @@ -689,7 +712,7 @@ static void pbr_nht_individual_nexthop_update_lookup(struct hash_backet *b, pnhi->valid += 1; } -static void pbr_nht_nexthop_update_lookup(struct hash_backet *b, void *data) +static void pbr_nht_nexthop_update_lookup(struct hash_bucket *b, void *data) { struct pbr_nexthop_group_cache *pnhgc = b->data; struct pbr_nht_individual pnhi; @@ -716,6 +739,56 @@ void pbr_nht_nexthop_update(struct zapi_route *nhr) hash_iterate(pbr_nhg_hash, pbr_nht_nexthop_update_lookup, nhr); } +static void +pbr_nht_individual_nexthop_interface_update_lookup(struct hash_backet *b, + void *data) +{ + struct pbr_nexthop_cache *pnhc = b->data; + struct pbr_nht_individual *pnhi = data; + bool old_valid; + + old_valid = pnhc->valid; + + if (pnhc->nexthop->type == NEXTHOP_TYPE_IFINDEX + && pnhc->nexthop->ifindex == pnhi->ifp->ifindex) + pnhc->valid = !!if_is_up(pnhi->ifp); + + DEBUGD(&pbr_dbg_nht, "\tFound %s: old: %d new: %d", pnhi->ifp->name, + old_valid, pnhc->valid); + + if (pnhc->valid) + pnhi->valid += 1; +} + +static void pbr_nht_nexthop_interface_update_lookup(struct hash_backet *b, + void *data) +{ + struct pbr_nexthop_group_cache *pnhgc = b->data; + struct pbr_nht_individual pnhi; + bool old_valid; + + old_valid = pnhgc->valid; + + pnhi.ifp = data; + pnhi.valid = 0; + hash_iterate(pnhgc->nhh, + pbr_nht_individual_nexthop_interface_update_lookup, &pnhi); + + /* + * If any of the specified nexthops are valid we are valid + */ + pnhgc->valid = !!pnhi.valid; + + if (old_valid != pnhgc->valid) + pbr_map_check_nh_group_change(pnhgc->name); +} + +void pbr_nht_nexthop_interface_update(struct interface *ifp) +{ + hash_iterate(pbr_nhg_hash, pbr_nht_nexthop_interface_update_lookup, + ifp); +} + static uint32_t pbr_nhg_hash_key(void *arg) { struct pbr_nexthop_group_cache *nhgc = @@ -740,7 +813,7 @@ uint32_t pbr_nht_get_next_tableid(bool peek) bool found = false; for (i = pbr_nhg_low_table; i <= pbr_nhg_high_table; i++) { - if (nhg_tableid[i] == false) { + if (!nhg_tableid[i]) { found = true; break; } @@ -822,7 +895,7 @@ bool pbr_nht_get_installed(const char *name) return pnhgc->installed; } -static void pbr_nht_show_nhg_nexthops(struct hash_backet *b, void *data) +static void pbr_nht_show_nhg_nexthops(struct hash_bucket *b, void *data) { struct pbr_nexthop_cache *pnhc = b->data; struct vty *vty = data; @@ -836,7 +909,7 @@ struct pbr_nht_show { const char *name; }; -static void pbr_nht_show_nhg(struct hash_backet *b, void *data) +static void pbr_nht_show_nhg(struct hash_bucket *b, void *data) { struct pbr_nexthop_group_cache *pnhgc = b->data; struct pbr_nht_show *pns = data; diff --git a/pbrd/pbr_nht.h b/pbrd/pbr_nht.h index d37803fbe3..4ef41cede7 100644 --- a/pbrd/pbr_nht.h +++ b/pbrd/pbr_nht.h @@ -117,5 +117,10 @@ extern void pbr_nht_show_nexthop_group(struct vty *vty, const char *name); */ extern void pbr_nht_nexthop_update(struct zapi_route *nhr); +/* + * When we get a callback from zebra about an interface status update. + */ +extern void pbr_nht_nexthop_interface_update(struct interface *ifp); + extern void pbr_nht_init(void); #endif diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c index a4b87f99d9..067d5c01fd 100644 --- a/pbrd/pbr_vty.c +++ b/pbrd/pbr_vty.c @@ -221,13 +221,19 @@ DEFPY(pbr_map_nexthop_group, pbr_map_nexthop_group_cmd, } DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd, - "[no] set nexthop <A.B.C.D|X:X::X:X>$addr [INTERFACE]$intf [nexthop-vrf NAME$name]", + "[no] set nexthop\ + <\ + <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\ + |INTERFACE$intf\ + >\ + [nexthop-vrf NAME$name]", NO_STR "Set for the PBR-MAP\n" "Specify one of the nexthops in this map\n" "v4 Address\n" "v6 Address\n" "Interface to use\n" + "Interface to use\n" "If the nexthop is in a different vrf tell us\n" "The nexthop-vrf Name\n") { @@ -255,44 +261,38 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd, memset(&nhop, 0, sizeof(nhop)); nhop.vrf_id = vrf->vrf_id; - /* - * Make SA happy. CLIPPY is not going to give us a NULL - * addr. - */ - assert(addr); - if (addr->sa.sa_family == AF_INET) { - nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr; - if (intf) { - nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX; - nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id); - if (nhop.ifindex == IFINDEX_INTERNAL) { - vty_out(vty, - "Specified Intf %s does not exist in vrf: %s\n", - intf, vrf->name); - return CMD_WARNING_CONFIG_FAILED; - } - } else - nhop.type = NEXTHOP_TYPE_IPV4; - } else { - memcpy(&nhop.gate.ipv6, &addr->sin6.sin6_addr, 16); - if (intf) { - nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX; - nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id); - if (nhop.ifindex == IFINDEX_INTERNAL) { - vty_out(vty, - "Specified Intf %s does not exist in vrf: %s\n", - intf, vrf->name); - return CMD_WARNING_CONFIG_FAILED; - } + if (intf) { + nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id); + if (nhop.ifindex == IFINDEX_INTERNAL) { + vty_out(vty, + "Specified Intf %s does not exist in vrf: %s\n", + intf, vrf->name); + return CMD_WARNING_CONFIG_FAILED; + } + } + + if (addr) { + if (addr->sa.sa_family == AF_INET) { + nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr; + if (intf) + nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX; + else + nhop.type = NEXTHOP_TYPE_IPV4; } else { - if (IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) { - vty_out(vty, - "Specified a v6 LL with no interface, rejecting\n"); - return CMD_WARNING_CONFIG_FAILED; + nhop.gate.ipv6 = addr->sin6.sin6_addr; + if (intf) + nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX; + else { + if (IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) { + vty_out(vty, + "Specified a v6 LL with no interface, rejecting\n"); + return CMD_WARNING_CONFIG_FAILED; + } + nhop.type = NEXTHOP_TYPE_IPV6; } - nhop.type = NEXTHOP_TYPE_IPV6; } - } + } else + nhop.type = NEXTHOP_TYPE_IFINDEX; if (pbrms->nhg) nh = nexthop_exists(pbrms->nhg, &nhop); @@ -300,7 +300,7 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd, char buf[PBR_NHC_NAMELEN]; if (no) { - vty_out(vty, "No nexthops to delete"); + vty_out(vty, "No nexthops to delete\n"); return CMD_WARNING_CONFIG_FAILED; } @@ -335,6 +335,14 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd, pbr_map_check(pbrms); } + if (nhop.type == NEXTHOP_TYPE_IFINDEX) { + struct interface *ifp; + + ifp = if_lookup_by_index(nhop.ifindex, nhop.vrf_id); + if (ifp) + pbr_nht_nexthop_interface_update(ifp); + } + return CMD_SUCCESS; } @@ -349,6 +357,7 @@ DEFPY (pbr_policy, struct pbr_map *pbrm, *old_pbrm; struct pbr_interface *pbr_ifp = ifp->info; + old_pbrm = NULL; pbrm = pbrm_find(mapname); if (!pbr_ifp) { @@ -369,12 +378,23 @@ DEFPY (pbr_policy, } else { if (strcmp(pbr_ifp->mapname, "") != 0) { old_pbrm = pbrm_find(pbr_ifp->mapname); - if (old_pbrm) + + /* + * So if we have an old pbrm we should only + * delete it if we are actually deleting and + * moving to a new pbrm + */ + if (old_pbrm && old_pbrm != pbrm) pbr_map_interface_delete(old_pbrm, ifp); } snprintf(pbr_ifp->mapname, sizeof(pbr_ifp->mapname), "%s", mapname); - if (pbrm) + + /* + * So only reinstall if the old_pbrm and this pbrm are + * different. + */ + if (pbrm && pbrm != old_pbrm) pbr_map_add_interface(pbrm, ifp); } @@ -604,18 +624,18 @@ static int pbr_vty_map_config_write_sequence(struct vty *vty, vty_out(vty, "pbr-map %s seq %u\n", pbrm->name, pbrms->seqno); if (pbrms->src) - vty_out(vty, " match src-ip %s\n", + vty_out(vty, " match src-ip %s\n", prefix2str(pbrms->src, buff, sizeof(buff))); if (pbrms->dst) - vty_out(vty, " match dst-ip %s\n", + vty_out(vty, " match dst-ip %s\n", prefix2str(pbrms->dst, buff, sizeof(buff))); if (pbrms->nhgrp_name) - vty_out(vty, " set nexthop-group %s\n", pbrms->nhgrp_name); + vty_out(vty, " set nexthop-group %s\n", pbrms->nhgrp_name); if (pbrms->nhg) { - vty_out(vty, " set "); + vty_out(vty, " set "); nexthop_group_write_nexthop(vty, pbrms->nhg->nexthop); } diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c index 7974bbfb4e..44c8daa97b 100644 --- a/pbrd/pbr_zebra.c +++ b/pbrd/pbr_zebra.c @@ -69,9 +69,14 @@ static int interface_add(int command, struct zclient *zclient, if (!ifp) return 0; + DEBUGD(&pbr_dbg_zebra, + "%s: %s", __PRETTY_FUNCTION__, ifp->name); + if (!ifp->info) pbr_if_new(ifp); + pbr_nht_nexthop_interface_update(ifp); + return 0; } @@ -89,6 +94,9 @@ static int interface_delete(int command, struct zclient *zclient, if (ifp == NULL) return 0; + DEBUGD(&pbr_dbg_zebra, + "%s: %s", __PRETTY_FUNCTION__, ifp->name); + if_set_index(ifp, IFINDEX_INTERNAL); return 0; @@ -97,7 +105,14 @@ static int interface_delete(int command, struct zclient *zclient, static int interface_address_add(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { - zebra_interface_address_read(command, zclient->ibuf, vrf_id); + struct connected *c; + char buf[PREFIX_STRLEN]; + + c = zebra_interface_address_read(command, zclient->ibuf, vrf_id); + + DEBUGD(&pbr_dbg_zebra, + "%s: %s added %s", __PRETTY_FUNCTION__, c->ifp->name, + prefix2str(c->address, buf, sizeof(buf))); return 0; } @@ -106,12 +121,17 @@ static int interface_address_delete(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct connected *c; + char buf[PREFIX_STRLEN]; c = zebra_interface_address_read(command, zclient->ibuf, vrf_id); if (!c) return 0; + DEBUGD(&pbr_dbg_zebra, + "%s: %s deleted %s", __PRETTY_FUNCTION__, c->ifp->name, + prefix2str(c->address, buf, sizeof(buf))); + connected_free(c); return 0; } @@ -119,8 +139,14 @@ static int interface_address_delete(int command, struct zclient *zclient, static int interface_state_up(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { + struct interface *ifp; - zebra_interface_state_read(zclient->ibuf, vrf_id); + ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); + + DEBUGD(&pbr_dbg_zebra, + "%s: %s is up", __PRETTY_FUNCTION__, ifp->name); + + pbr_nht_nexthop_interface_update(ifp); return 0; } @@ -128,8 +154,14 @@ static int interface_state_up(int command, struct zclient *zclient, static int interface_state_down(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { + struct interface *ifp; - zebra_interface_state_read(zclient->ibuf, vrf_id); + ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); + + DEBUGD(&pbr_dbg_zebra, + "%s: %s is down", __PRETTY_FUNCTION__, ifp->name); + + pbr_nht_nexthop_interface_update(ifp); return 0; } @@ -142,11 +174,11 @@ static int route_notify_owner(int command, struct zclient *zclient, uint32_t table_id; char buf[PREFIX_STRLEN]; - prefix2str(&p, buf, sizeof(buf)); - if (!zapi_route_notify_decode(zclient->ibuf, &p, &table_id, ¬e)) return -1; + prefix2str(&p, buf, sizeof(buf)); + switch (note) { case ZAPI_ROUTE_FAIL_INSTALL: DEBUGD(&pbr_dbg_zebra, @@ -207,28 +239,32 @@ static int rule_notify_owner(int command, struct zclient *zclient, switch (note) { case ZAPI_RULE_FAIL_INSTALL: - DEBUGD(&pbr_dbg_zebra, "%s: Received RULE_FAIL_INSTALL", - __PRETTY_FUNCTION__); pbrms->installed &= ~installed; + DEBUGD(&pbr_dbg_zebra, "%s: Received RULE_FAIL_INSTALL: %lu", + __PRETTY_FUNCTION__, pbrms->installed); break; case ZAPI_RULE_INSTALLED: pbrms->installed |= installed; - DEBUGD(&pbr_dbg_zebra, "%s: Received RULE_INSTALLED", - __PRETTY_FUNCTION__); + DEBUGD(&pbr_dbg_zebra, "%s: Received RULE_INSTALLED: %lu", + __PRETTY_FUNCTION__, pbrms->installed); break; case ZAPI_RULE_FAIL_REMOVE: case ZAPI_RULE_REMOVED: pbrms->installed &= ~installed; - DEBUGD(&pbr_dbg_zebra, "%s: Received RULE REMOVED", - __PRETTY_FUNCTION__); + DEBUGD(&pbr_dbg_zebra, "%s: Received RULE REMOVED: %lu", + __PRETTY_FUNCTION__, pbrms->installed); break; } + pbr_map_final_interface_deletion(pbrms->parent, pmi); + return 0; } static void zebra_connected(struct zclient *zclient) { + DEBUGD(&pbr_dbg_zebra, "%s: Registering for fun and profit", + __PRETTY_FUNCTION__); zclient_send_reg_requests(zclient, VRF_DEFAULT); } @@ -236,11 +272,15 @@ static void route_add_helper(struct zapi_route *api, struct nexthop_group nhg, uint8_t install_afi) { struct zapi_nexthop *api_nh; + char buf[PREFIX_STRLEN]; struct nexthop *nhop; int i; api->prefix.family = install_afi; + DEBUGD(&pbr_dbg_zebra, "\tEncoding %s", + prefix2str(&api->prefix, buf, sizeof(buf))); + i = 0; for (ALL_NEXTHOPS(nhg, nhop)) { api_nh = &api->nexthops[i]; @@ -284,6 +324,9 @@ void route_add(struct pbr_nexthop_group_cache *pnhgc, struct nexthop_group nhg, { struct zapi_route api; + DEBUGD(&pbr_dbg_zebra, "%s for Table: %d", __PRETTY_FUNCTION__, + pnhgc->table_id); + memset(&api, 0, sizeof(api)); api.vrf_id = VRF_DEFAULT; @@ -323,6 +366,9 @@ void route_delete(struct pbr_nexthop_group_cache *pnhgc, afi_t afi) { struct zapi_route api; + DEBUGD(&pbr_dbg_zebra, "%s for Table: %d", __PRETTY_FUNCTION__, + pnhgc->table_id); + memset(&api, 0, sizeof(api)); api.vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_PBR; diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index d2d2445a15..f058b7adbf 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -1191,7 +1191,7 @@ static void pim_show_interfaces_single(struct pim_instance *pim, vty_out(vty, "Designated Router\n"); vty_out(vty, "-----------------\n"); vty_out(vty, "Address : %s\n", dr_str); - vty_out(vty, "Priority : %d(%d)\n", + vty_out(vty, "Priority : %u(%d)\n", pim_ifp->pim_dr_priority, pim_ifp->pim_dr_num_nondrpri_neighbors); vty_out(vty, "Uptime : %s\n", dr_uptime); @@ -2370,9 +2370,10 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty, up->t_join_timer); /* - * If we have a J/P timer for the neighbor display that + * If the upstream is not dummy and it has a J/P timer for the + * neighbor display that */ - if (!up->t_join_timer) { + if (!up->t_join_timer && up->rpf.source_nexthop.interface) { struct pim_neighbor *nbr; nbr = pim_neighbor_find( @@ -2412,8 +2413,10 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty, json_row = json_object_new_object(); json_object_pim_upstream_add(json_row, up); json_object_string_add( - json_row, "inboundInterface", - up->rpf.source_nexthop.interface->name); + json_row, "inboundInterface", + up->rpf.source_nexthop.interface + ? up->rpf.source_nexthop.interface->name + : "Unknown"); /* * The RPF address we use is slightly different @@ -2463,8 +2466,10 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty, } else { vty_out(vty, "%-10s%-15s %-15s %-11s %-8s %-9s %-9s %-9s %6d\n", - up->rpf.source_nexthop.interface->name, src_str, - grp_str, state_str, uptime, join_timer, + up->rpf.source_nexthop.interface + ? up->rpf.source_nexthop.interface->name + : "Unknown", + src_str, grp_str, state_str, uptime, join_timer, rs_timer, ka_timer, up->ref_count); } } @@ -2789,9 +2794,9 @@ struct pnc_cache_walk_data { struct pim_instance *pim; }; -static int pim_print_pnc_cache_walkcb(struct hash_backet *backet, void *arg) +static int pim_print_pnc_cache_walkcb(struct hash_bucket *bucket, void *arg) { - struct pim_nexthop_cache *pnc = backet->data; + struct pim_nexthop_cache *pnc = bucket->data; struct pnc_cache_walk_data *cwd = arg; struct vty *vty = cwd->vty; struct pim_instance *pim = cwd->pim; @@ -5159,16 +5164,14 @@ static int pim_cmd_spt_switchover(struct pim_instance *pim, switch (pim->spt.switchover) { case PIM_SPT_IMMEDIATE: - if (pim->spt.plist) - XFREE(MTYPE_PIM_SPT_PLIST_NAME, pim->spt.plist); + XFREE(MTYPE_PIM_SPT_PLIST_NAME, pim->spt.plist); pim_upstream_add_lhr_star_pimreg(pim); break; case PIM_SPT_INFINITY: pim_upstream_remove_lhr_star_pimreg(pim, plist); - if (pim->spt.plist) - XFREE(MTYPE_PIM_SPT_PLIST_NAME, pim->spt.plist); + XFREE(MTYPE_PIM_SPT_PLIST_NAME, pim->spt.plist); if (plist) pim->spt.plist = @@ -6353,8 +6356,8 @@ DEFUN (interface_ip_pim_drprio, pim_ifp->pim_dr_priority = strtol(argv[idx_number]->arg, NULL, 10); if (old_dr_prio != pim_ifp->pim_dr_priority) { - if (pim_if_dr_election(ifp)) - pim_hello_restart_now(ifp); + pim_if_dr_election(ifp); + pim_hello_restart_now(ifp); } return CMD_SUCCESS; @@ -6379,8 +6382,8 @@ DEFUN (interface_no_ip_pim_drprio, if (pim_ifp->pim_dr_priority != PIM_DEFAULT_DR_PRIORITY) { pim_ifp->pim_dr_priority = PIM_DEFAULT_DR_PRIORITY; - if (pim_if_dr_election(ifp)) - pim_hello_restart_now(ifp); + pim_if_dr_election(ifp); + pim_hello_restart_now(ifp); } return CMD_SUCCESS; @@ -6404,6 +6407,56 @@ static int pim_cmd_interface_add(struct interface *ifp) return 1; } +DEFPY_HIDDEN (pim_test_sg_keepalive, + pim_test_sg_keepalive_cmd, + "test pim [vrf NAME$name] keepalive-reset A.B.C.D$source A.B.C.D$group", + "Test code\n" + PIM_STR + VRF_CMD_HELP_STR + "Reset the Keepalive Timer\n" + "The Source we are resetting\n" + "The Group we are resetting\n") +{ + struct pim_upstream *up; + struct pim_instance *pim; + struct prefix_sg sg; + + sg.src = source; + sg.grp = group; + + if (!name) + pim = pim_get_pim_instance(VRF_DEFAULT); + else { + struct vrf *vrf = vrf_lookup_by_name(name); + + if (!vrf) { + vty_out(vty, "%% Vrf specified: %s does not exist\n", + name); + return CMD_WARNING; + } + + pim = pim_get_pim_instance(vrf->vrf_id); + } + + if (!pim) { + vty_out(vty, "%% Unable to find pim instance\n"); + return CMD_WARNING; + } + + up = pim_upstream_find(pim, &sg); + if (!up) { + vty_out(vty, "%% Unable to find %s specified\n", + pim_str_sg_dump(&sg)); + return CMD_WARNING; + } + + vty_out(vty, "Setting %s to current keep alive time: %d\n", + pim_str_sg_dump(&sg), pim->keep_alive_time); + pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time); + + return CMD_SUCCESS; +} + DEFPY_HIDDEN (interface_ip_pim_activeactive, interface_ip_pim_activeactive_cmd, "[no$no] ip pim active-active", @@ -8667,7 +8720,6 @@ DEFUN (show_ip_msdp_sa_sg_vrf_all, return CMD_SUCCESS; } - void pim_cmd_init(void) { install_node(&interface_node, @@ -8676,6 +8728,8 @@ void pim_cmd_init(void) install_node(&debug_node, pim_debug_config_write); + install_element(ENABLE_NODE, &pim_test_sg_keepalive_cmd); + install_element(CONFIG_NODE, &ip_pim_rp_cmd); install_element(VRF_NODE, &ip_pim_rp_cmd); install_element(CONFIG_NODE, &no_ip_pim_rp_cmd); diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 6933f4d5bd..92d21cf429 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -208,8 +208,7 @@ void pim_if_delete(struct interface *ifp) list_delete(&pim_ifp->upstream_switch_list); list_delete(&pim_ifp->sec_addr_list); - if (pim_ifp->boundary_oil_plist) - XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist); + XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist); while (!RB_EMPTY(pim_ifchannel_rb, &pim_ifp->ifchannel_rb)) { ch = RB_ROOT(pim_ifchannel_rb, &pim_ifp->ifchannel_rb); diff --git a/pimd/pim_igmp_mtrace.c b/pimd/pim_igmp_mtrace.c index 1fb624a6a0..f51e0c0d2f 100644 --- a/pimd/pim_igmp_mtrace.c +++ b/pimd/pim_igmp_mtrace.c @@ -133,6 +133,13 @@ static bool mtrace_fwd_info(struct pim_instance *pim, if (!up) return false; + if (!up->rpf.source_nexthop.interface) { + if (PIM_DEBUG_TRACE) + zlog_debug("%s: up %s RPF is not present", + __PRETTY_FUNCTION__, up->sg_str); + return false; + } + ifp_in = up->rpf.source_nexthop.interface; nh_addr = up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4; total = htonl(MTRACE_UNKNOWN_COUNT); diff --git a/pimd/pim_join.c b/pimd/pim_join.c index ae5032be73..cbacaf3ea8 100644 --- a/pimd/pim_join.c +++ b/pimd/pim_join.c @@ -439,9 +439,6 @@ int pim_joinprune_send(struct pim_rpf *rpf, struct list *groups) size_t packet_size = 0; size_t group_size = 0; - on_trace(__PRETTY_FUNCTION__, rpf->source_nexthop.interface, - rpf->rpf_addr.u.prefix4); - if (rpf->source_nexthop.interface) pim_ifp = rpf->source_nexthop.interface->info; else { @@ -450,6 +447,9 @@ int pim_joinprune_send(struct pim_rpf *rpf, struct list *groups) return -1; } + on_trace(__PRETTY_FUNCTION__, rpf->source_nexthop.interface, + rpf->rpf_addr.u.prefix4); + if (!pim_ifp) { zlog_warn("%s: multicast not enabled on interface %s", __PRETTY_FUNCTION__, diff --git a/pimd/pim_jp_agg.c b/pimd/pim_jp_agg.c index 7726ffda57..06a9e6d0d6 100644 --- a/pimd/pim_jp_agg.c +++ b/pimd/pim_jp_agg.c @@ -213,8 +213,18 @@ void pim_jp_agg_upstream_verification(struct pim_upstream *up, bool ignore) { #ifdef PIM_JP_AGG_DEBUG struct interface *ifp; - struct pim_interface *pim_ifp = up->rpf.source_nexthop.interface->info; - struct pim_instance *pim = pim_ifp->pim; + struct pim_interface *pim_ifp; + struct pim_instance *pim; + + if (!up->rpf.source_nexthop.interface) { + if (PIM_DEBUG_TRACE) + zlog_debug("%s: up %s RPF is not present", + __PRETTY_FUNCTION__, up->sg_str); + return; + } + + pim_ifp = up->rpf.source_nexthop.interface->info; + pim = pim_ifp->pim; FOR_ALL_INTERFACES (pim->vrf, ifp) { pim_ifp = ifp->info; diff --git a/pimd/pim_main.c b/pimd/pim_main.c index dc42899c7b..5a8991c4c0 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -68,7 +68,7 @@ struct zebra_privs_t pimd_privs = { .vty_group = VTY_GROUP, #endif .caps_p = _caps_p, - .cap_num_p = sizeof(_caps_p) / sizeof(_caps_p[0]), + .cap_num_p = array_size(_caps_p), .cap_num_i = 0}; static const struct frr_yang_module_info *pimd_yang_modules[] = { diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index dd9e21cae8..67b1a95f74 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -234,7 +234,8 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp, up->channel_oil->cc.pktcnt++; PIM_UPSTREAM_FLAG_SET_FHR(up->flags); // resolve mfcc_parent prior to mroute_add in channel_add_oif - if (up->channel_oil->oil.mfcc_parent >= MAXVIFS) { + if (up->rpf.source_nexthop.interface && + up->channel_oil->oil.mfcc_parent >= MAXVIFS) { int vif_index = 0; vif_index = pim_if_find_vifindex_by_ifindex( pim_ifp->pim, @@ -301,6 +302,13 @@ static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp, return 0; } + if (!up->rpf.source_nexthop.interface) { + if (PIM_DEBUG_TRACE) + zlog_debug("%s: up %s RPF is not present", + __PRETTY_FUNCTION__, up->sg_str); + return 0; + } + pim_ifp = up->rpf.source_nexthop.interface->info; rpg = pim_ifp ? RP(pim_ifp->pim, sg.grp) : NULL; diff --git a/pimd/pim_msdp.c b/pimd/pim_msdp.c index a4f87fa1a6..395c4af35f 100644 --- a/pimd/pim_msdp.c +++ b/pimd/pim_msdp.c @@ -1256,8 +1256,7 @@ static void pim_msdp_mg_free(struct pim_instance *pim) if (PIM_DEBUG_MSDP_EVENTS) { zlog_debug("MSDP mesh-group %s deleted", mg->mesh_group_name); } - if (mg->mesh_group_name) - XFREE(MTYPE_PIM_MSDP_MG_NAME, mg->mesh_group_name); + XFREE(MTYPE_PIM_MSDP_MG_NAME, mg->mesh_group_name); if (mg->mbr_list) list_delete(&mg->mbr_list); diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c index 2d808639b5..9b5379384c 100644 --- a/pimd/pim_nht.c +++ b/pimd/pim_nht.c @@ -39,6 +39,7 @@ #include "pim_jp_agg.h" #include "pim_zebra.h" #include "pim_zlookup.h" +#include "pim_rp.h" /** * pim_sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister @@ -170,6 +171,8 @@ void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr, struct pim_nexthop_cache *pnc = NULL; struct pim_nexthop_cache lookup; struct zclient *zclient = NULL; + struct listnode *upnode = NULL; + struct pim_upstream *upstream = NULL; zclient = pim_zebra_zclient_get(); @@ -177,8 +180,30 @@ void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr, lookup.rpf.rpf_addr = *addr; pnc = hash_lookup(pim->rpf_hash, &lookup); if (pnc) { - if (rp) + if (rp) { + /* Release the (*, G)upstream from pnc->upstream_hash, + * whose Group belongs to the RP getting deleted + */ + for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, + upstream)) { + struct prefix grp; + struct rp_info *trp_info; + + if (upstream->sg.src.s_addr != INADDR_ANY) + continue; + + grp.family = AF_INET; + grp.prefixlen = IPV4_MAX_BITLEN; + grp.u.prefix4 = upstream->sg.grp; + + trp_info = pim_rp_find_match_group(pim, &grp); + if (trp_info == rp) + hash_release(pnc->upstream_hash, + upstream); + } listnode_delete(pnc->rp_list, rp); + } + if (up) hash_release(pnc->upstream_hash, up); @@ -207,6 +232,17 @@ void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr, } } +void pim_rp_nexthop_del(struct rp_info *rp_info) +{ + rp_info->rp.source_nexthop.interface = NULL; + rp_info->rp.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr = + PIM_NET_INADDR_ANY; + rp_info->rp.source_nexthop.mrib_metric_preference = + router->infinite_assert_metric.metric_preference; + rp_info->rp.source_nexthop.mrib_route_metric = + router->infinite_assert_metric.route_metric; +} + /* Update RP nexthop info based on Nexthop update received from Zebra.*/ static void pim_update_rp_nh(struct pim_instance *pim, struct pim_nexthop_cache *pnc) @@ -220,9 +256,11 @@ static void pim_update_rp_nh(struct pim_instance *pim, continue; // Compute PIM RPF using cached nexthop - pim_ecmp_nexthop_search(pim, pnc, &rp_info->rp.source_nexthop, - &rp_info->rp.rpf_addr, &rp_info->group, - 1); + if (!pim_ecmp_nexthop_search(pim, pnc, + &rp_info->rp.source_nexthop, + &rp_info->rp.rpf_addr, &rp_info->group, + 1)) + pim_rp_nexthop_del(rp_info); } } @@ -266,10 +304,10 @@ void pim_resolve_upstream_nh(struct pim_instance *pim, struct prefix *nht_p) } /* Update Upstream nexthop info based on Nexthop update received from Zebra.*/ -static int pim_update_upstream_nh_helper(struct hash_backet *backet, void *arg) +static int pim_update_upstream_nh_helper(struct hash_bucket *bucket, void *arg) { struct pim_instance *pim = (struct pim_instance *)arg; - struct pim_upstream *up = (struct pim_upstream *)backet->data; + struct pim_upstream *up = (struct pim_upstream *)bucket->data; int vif_index = 0; enum pim_rpf_result rpf_result; @@ -278,12 +316,12 @@ static int pim_update_upstream_nh_helper(struct hash_backet *backet, void *arg) old.source_nexthop.interface = up->rpf.source_nexthop.interface; rpf_result = pim_rpf_update(pim, up, &old, 0); if (rpf_result == PIM_RPF_FAILURE) { - pim_mroute_del(up->channel_oil, __PRETTY_FUNCTION__); + pim_upstream_rpf_clear(pim, up); return HASHWALK_CONTINUE; } /* update kernel multicast forwarding cache (MFC) */ - if (up->channel_oil) { + if (up->rpf.source_nexthop.interface) { ifindex_t ifindex = up->rpf.source_nexthop.interface->ifindex; vif_index = pim_if_find_vifindex_by_ifindex(pim, ifindex); @@ -306,9 +344,10 @@ static int pim_update_upstream_nh_helper(struct hash_backet *backet, void *arg) if (PIM_DEBUG_PIM_NHT) { zlog_debug("%s: NHT upstream %s(%s) old ifp %s new ifp %s", - __PRETTY_FUNCTION__, up->sg_str, pim->vrf->name, - old.source_nexthop.interface->name, - up->rpf.source_nexthop.interface->name); + __PRETTY_FUNCTION__, up->sg_str, pim->vrf->name, + old.source_nexthop.interface + ? old.source_nexthop.interface->name : "Unknwon", + up->rpf.source_nexthop.interface->name); } return HASHWALK_CONTINUE; diff --git a/pimd/pim_nht.h b/pimd/pim_nht.h index 796fbf9731..6eff7bbc89 100644 --- a/pimd/pim_nht.h +++ b/pimd/pim_nht.h @@ -68,4 +68,5 @@ void pim_sendmsg_zebra_rnh(struct pim_instance *pim, struct zclient *zclient, void pim_resolve_upstream_nh(struct pim_instance *pim, struct prefix *nht_p); int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance *pim, struct prefix *src, struct prefix *grp); +void pim_rp_nexthop_del(struct rp_info *rp_info); #endif diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c index 2e12d728cf..55d26113f7 100644 --- a/pimd/pim_oil.c +++ b/pimd/pim_oil.c @@ -168,13 +168,15 @@ struct channel_oil *pim_channel_oil_add(struct pim_instance *pim, return c_oil; } - ifp = pim_if_find_by_vif_index(pim, input_vif_index); - if (!ifp) { - /* warning only */ - zlog_warn( - "%s: (S,G)=%s could not find input interface for input_vif_index=%d", - __PRETTY_FUNCTION__, pim_str_sg_dump(sg), - input_vif_index); + if (input_vif_index != MAXVIFS) { + ifp = pim_if_find_by_vif_index(pim, input_vif_index); + if (!ifp) { + /* warning only */ + zlog_warn( + "%s: (S,G)=%s could not find input interface for input_vif_index=%d", + __PRETTY_FUNCTION__, pim_str_sg_dump(sg), + input_vif_index); + } } c_oil = XCALLOC(MTYPE_PIM_CHANNEL_OIL, sizeof(*c_oil)); @@ -447,25 +449,31 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif, channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = PIM_MROUTE_MIN_TTL; - if (pim_mroute_add(channel_oil, __PRETTY_FUNCTION__)) { - if (PIM_DEBUG_MROUTE) { - char group_str[INET_ADDRSTRLEN]; - char source_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<group?>", - channel_oil->oil.mfcc_mcastgrp, - group_str, sizeof(group_str)); - pim_inet4_dump("<source?>", - channel_oil->oil.mfcc_origin, source_str, - sizeof(source_str)); - zlog_debug( - "%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)", - __FILE__, __PRETTY_FUNCTION__, oif->name, - pim_ifp->mroute_vif_index, source_str, - group_str); - } + /* channel_oil->oil.mfcc_parent != MAXVIFS indicate this entry is not + * valid to get installed in kernel. + */ + if (channel_oil->oil.mfcc_parent != MAXVIFS) { + if (pim_mroute_add(channel_oil, __PRETTY_FUNCTION__)) { + if (PIM_DEBUG_MROUTE) { + char group_str[INET_ADDRSTRLEN]; + char source_str[INET_ADDRSTRLEN]; + pim_inet4_dump("<group?>", + channel_oil->oil.mfcc_mcastgrp, + group_str, sizeof(group_str)); + pim_inet4_dump("<source?>", + channel_oil->oil.mfcc_origin, source_str, + sizeof(source_str)); + zlog_debug( + "%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)", + __FILE__, __PRETTY_FUNCTION__, oif->name, + pim_ifp->mroute_vif_index, source_str, + group_str); + } - channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl; - return -5; + channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] + = old_ttl; + return -5; + } } channel_oil->oif_creation[pim_ifp->mroute_vif_index] = diff --git a/pimd/pim_oil.h b/pimd/pim_oil.h index 94d3840e98..5dd4e8b326 100644 --- a/pimd/pim_oil.h +++ b/pimd/pim_oil.h @@ -64,6 +64,25 @@ struct channel_counts { Each channel_oil.oil is used to control an (S,G) entry in the Kernel Multicast Forwarding Cache. + + There is a case when we create a channel_oil but don't install in the kernel + + Case where (S, G) entry not installed in the kernel: + FRR receives IGMP/PIM (*, G) join and RP is not configured or + not-reachable, then create a channel_oil for the group G with the incoming + interface(channel_oil.oil.mfcc_parent) as invalid i.e "MAXVIF" and populate + the outgoing interface where join is received. Keep this entry in the stack, + but don't install in the kernel(channel_oil.installed = 0). + + Case where (S, G) entry installed in the kernel: + When RP is configured and is reachable for the group G, and receiving a + join if channel_oil is already present then populate the incoming interface + and install the entry in the kernel, if channel_oil not present, then create + a new_channel oil(channel_oil.installed = 1). + + is_valid: indicate if this entry is valid to get installed in kernel. + installed: indicate if this entry is installed in the kernel. + */ struct channel_oil { diff --git a/pimd/pim_register.c b/pimd/pim_register.c index b9908ae22b..a4965b8ffe 100644 --- a/pimd/pim_register.c +++ b/pimd/pim_register.c @@ -97,7 +97,7 @@ void pim_register_stop_send(struct interface *ifp, struct prefix_sg *sg, pinfo = (struct pim_interface *)ifp->info; if (!pinfo) { if (PIM_DEBUG_PIM_TRACE) - zlog_debug("%s: No pinfo!\n", __PRETTY_FUNCTION__); + zlog_debug("%s: No pinfo!", __PRETTY_FUNCTION__); return; } if (pim_msg_send(pinfo->pim_sock_fd, src, originator, buffer, @@ -189,8 +189,8 @@ void pim_register_send(const uint8_t *buf, int buf_size, struct in_addr src, if (PIM_DEBUG_PIM_REG) { char rp_str[INET_ADDRSTRLEN]; - strncpy(rp_str, inet_ntoa(rpg->rpf_addr.u.prefix4), - INET_ADDRSTRLEN - 1); + strlcpy(rp_str, inet_ntoa(rpg->rpf_addr.u.prefix4), + sizeof(rp_str)); zlog_debug("%s: Sending %s %sRegister Packet to %s on %s", __PRETTY_FUNCTION__, up->sg_str, null_register ? "NULL " : "", rp_str, ifp->name); diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index 08f2ffc4ea..7094b93a45 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -45,7 +45,9 @@ #include "pim_iface.h" #include "pim_msdp.h" #include "pim_nht.h" - +#include "pim_mroute.h" +#include "pim_oil.h" +#include "pim_zebra.h" /* Cleanup pim->rpf_hash each node data */ void pim_rp_list_hash_clean(void *data) @@ -65,8 +67,7 @@ void pim_rp_list_hash_clean(void *data) static void pim_rp_info_free(struct rp_info *rp_info) { - if (rp_info->plist) - XFREE(MTYPE_PIM_FILTER_NAME, rp_info->plist); + XFREE(MTYPE_PIM_FILTER_NAME, rp_info->plist); XFREE(MTYPE_PIM_RP, rp_info); } @@ -201,7 +202,7 @@ static struct rp_info *pim_rp_find_exact(struct pim_instance *pim, /* * Given a group, return the rp_info for that group */ -static struct rp_info *pim_rp_find_match_group(struct pim_instance *pim, +struct rp_info *pim_rp_find_match_group(struct pim_instance *pim, const struct prefix *group) { struct listnode *node; @@ -334,6 +335,77 @@ static void pim_rp_check_interfaces(struct pim_instance *pim, } } +void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up) +{ + struct pim_rpf old_rpf; + enum pim_rpf_result rpf_result; + struct in_addr old_upstream_addr; + struct in_addr new_upstream_addr; + struct prefix nht_p; + + old_upstream_addr = up->upstream_addr; + pim_rp_set_upstream_addr(pim, &new_upstream_addr, up->sg.src, + up->sg.grp); + + if (PIM_DEBUG_TRACE) + zlog_debug("%s: pim upstream update for old upstream %s", + __PRETTY_FUNCTION__, + inet_ntoa(old_upstream_addr)); + + if (old_upstream_addr.s_addr == new_upstream_addr.s_addr) + return; + + /* Lets consider a case, where a PIM upstream has a better RP as a + * result of a new RP configuration with more precise group range. + * This upstream has to be added to the upstream hash of new RP's + * NHT(pnc) and has to be removed from old RP's NHT upstream hash + */ + if (old_upstream_addr.s_addr != INADDR_ANY) { + /* Deregister addr with Zebra NHT */ + nht_p.family = AF_INET; + nht_p.prefixlen = IPV4_MAX_BITLEN; + nht_p.u.prefix4 = old_upstream_addr; + if (PIM_DEBUG_TRACE) { + char buf[PREFIX2STR_BUFFER]; + + prefix2str(&nht_p, buf, sizeof(buf)); + zlog_debug("%s: Deregister upstream %s addr %s with Zebra NHT", + __PRETTY_FUNCTION__, up->sg_str, buf); + } + pim_delete_tracked_nexthop(pim, &nht_p, up, NULL); + } + + /* Update the upstream address */ + up->upstream_addr = new_upstream_addr; + + old_rpf.source_nexthop.interface = up->rpf.source_nexthop.interface; + + rpf_result = pim_rpf_update(pim, up, &old_rpf, 1); + if (rpf_result == PIM_RPF_FAILURE) + pim_mroute_del(up->channel_oil, __PRETTY_FUNCTION__); + + /* update kernel multicast forwarding cache (MFC) */ + if (up->rpf.source_nexthop.interface && up->channel_oil) { + ifindex_t ifindex = up->rpf.source_nexthop.interface->ifindex; + int vif_index = pim_if_find_vifindex_by_ifindex(pim, ifindex); + /* Pass Current selected NH vif index to mroute download */ + if (vif_index) + pim_scan_individual_oil(up->channel_oil, vif_index); + else { + if (PIM_DEBUG_PIM_NHT) + zlog_debug( + "%s: NHT upstream %s channel_oil IIF %s vif_index is not valid", + __PRETTY_FUNCTION__, up->sg_str, + up->rpf.source_nexthop.interface->name); + } + } + + if (rpf_result == PIM_RPF_CHANGED) + pim_zebra_upstream_rpf_changed(pim, up, &old_rpf); + + pim_zebra_update_all_interfaces(pim); +} + int pim_rp_new(struct pim_instance *pim, const char *rp, const char *group_range, const char *plist) { @@ -348,6 +420,8 @@ int pim_rp_new(struct pim_instance *pim, const char *rp, struct prefix temp; struct pim_nexthop_cache pnc; struct route_node *rn; + struct pim_upstream *up; + struct listnode *upnode; rp_info = XCALLOC(MTYPE_PIM_RP, sizeof(*rp_info)); @@ -469,6 +543,27 @@ int pim_rp_new(struct pim_instance *pim, const char *rp, "%s: NHT Register rp_all addr %s grp %s ", __PRETTY_FUNCTION__, buf, buf1); } + + for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, + up)) { + /* Find (*, G) upstream whose RP is not + * configured yet + */ + if ((up->upstream_addr.s_addr == INADDR_ANY) + && (up->sg.src.s_addr == INADDR_ANY)) { + struct prefix grp; + struct rp_info *trp_info; + + grp.family = AF_INET; + grp.prefixlen = IPV4_MAX_BITLEN; + grp.u.prefix4 = up->sg.grp; + trp_info = pim_rp_find_match_group(pim, + &grp); + if (trp_info == rp_all) + pim_upstream_update(pim, up); + } + } + memset(&pnc, 0, sizeof(struct pim_nexthop_cache)); if (pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_all, &pnc)) { @@ -536,6 +631,21 @@ int pim_rp_new(struct pim_instance *pim, const char *rp, rn->lock); } + for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) { + if (up->sg.src.s_addr == INADDR_ANY) { + struct prefix grp; + struct rp_info *trp_info; + + grp.family = AF_INET; + grp.prefixlen = IPV4_MAX_BITLEN; + grp.u.prefix4 = up->sg.grp; + trp_info = pim_rp_find_match_group(pim, &grp); + + if (trp_info == rp_info) + pim_upstream_update(pim, up); + } + } + /* Register addr with Zebra NHT */ nht_p.family = AF_INET; nht_p.prefixlen = IPV4_MAX_BITLEN; @@ -578,6 +688,9 @@ int pim_rp_del(struct pim_instance *pim, const char *rp, struct prefix nht_p; struct route_node *rn; bool was_plist = false; + struct rp_info *trp_info; + struct pim_upstream *up; + struct listnode *upnode; if (group_range == NULL) result = str2prefix("224.0.0.0/4", &group); @@ -622,6 +735,23 @@ int pim_rp_del(struct pim_instance *pim, const char *rp, rp_all = pim_rp_find_match_group(pim, &g_all); if (rp_all == rp_info) { + for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) { + /* Find the upstream (*, G) whose upstream address is + * same as the deleted RP + */ + if ((up->upstream_addr.s_addr == rp_addr.s_addr) && + (up->sg.src.s_addr == INADDR_ANY)) { + struct prefix grp; + grp.family = AF_INET; + grp.prefixlen = IPV4_MAX_BITLEN; + grp.u.prefix4 = up->sg.grp; + trp_info = pim_rp_find_match_group(pim, &grp); + if (trp_info == rp_all) { + pim_upstream_rpf_clear(pim, up); + up->upstream_addr.s_addr = INADDR_ANY; + } + } + } rp_all->rp.rpf_addr.family = AF_INET; rp_all->rp.rpf_addr.u.prefix4.s_addr = INADDR_NONE; rp_all->i_am_rp = 0; @@ -656,6 +786,34 @@ int pim_rp_del(struct pim_instance *pim, const char *rp, pim_rp_refresh_group_to_rp_mapping(pim); + for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) { + /* Find the upstream (*, G) whose upstream address is same as + * the deleted RP + */ + if ((up->upstream_addr.s_addr == rp_addr.s_addr) && + (up->sg.src.s_addr == INADDR_ANY)) { + struct prefix grp; + + grp.family = AF_INET; + grp.prefixlen = IPV4_MAX_BITLEN; + grp.u.prefix4 = up->sg.grp; + + trp_info = pim_rp_find_match_group(pim, &grp); + + /* RP not found for the group grp */ + if (pim_rpf_addr_is_inaddr_none(&trp_info->rp)) { + pim_upstream_rpf_clear(pim, up); + pim_rp_set_upstream_addr(pim, + &up->upstream_addr, + up->sg.src, up->sg.grp); + } + + /* RP found for the group grp */ + else + pim_upstream_update(pim, up); + } + } + XFREE(MTYPE_PIM_RP, rp_info); return PIM_SUCCESS; } @@ -682,6 +840,7 @@ void pim_rp_setup(struct pim_instance *pim) else { if (PIM_DEBUG_PIM_NHT_RP) { char buf[PREFIX2STR_BUFFER]; + prefix2str(&nht_p, buf, sizeof(buf)); zlog_debug( "%s: NHT Local Nexthop not found for RP %s ", @@ -870,7 +1029,7 @@ struct pim_rpf *pim_rp_g(struct pim_instance *pim, struct in_addr group) * the rp configured and the source address * * If we have don't have a RP configured and the source address is * - * then return failure. + * then set the upstream addr as INADDR_ANY and return failure. * */ int pim_rp_set_upstream_addr(struct pim_instance *pim, struct in_addr *up, @@ -891,6 +1050,7 @@ int pim_rp_set_upstream_addr(struct pim_instance *pim, struct in_addr *up, if (PIM_DEBUG_PIM_NHT_RP) zlog_debug("%s: Received a (*,G) with no RP configured", __PRETTY_FUNCTION__); + up->s_addr = INADDR_ANY; return 0; } diff --git a/pimd/pim_rp.h b/pimd/pim_rp.h index 672a696319..7769864c08 100644 --- a/pimd/pim_rp.h +++ b/pimd/pim_rp.h @@ -71,4 +71,7 @@ void pim_rp_show_information(struct pim_instance *pim, struct vty *vty, bool uj); void pim_resolve_rp_nh(struct pim_instance *pim); int pim_rp_list_cmp(void *v1, void *v2); +struct rp_info *pim_rp_find_match_group(struct pim_instance *pim, + const struct prefix *group); +void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up); #endif diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c index 814d2e076b..ee145a5b51 100644 --- a/pimd/pim_rpf.c +++ b/pimd/pim_rpf.c @@ -205,6 +205,12 @@ enum pim_rpf_result pim_rpf_update(struct pim_instance *pim, struct prefix src, grp; bool neigh_needed = true; + if (up->upstream_addr.s_addr == INADDR_ANY) { + zlog_debug("%s: RP is not configured yet for %s", + __PRETTY_FUNCTION__, up->sg_str); + return PIM_RPF_OK; + } + saved.source_nexthop = rpf->source_nexthop; saved.rpf_addr = rpf->rpf_addr; @@ -308,6 +314,33 @@ enum pim_rpf_result pim_rpf_update(struct pim_instance *pim, } /* + * In the case of RP deletion and RP unreachablity, + * uninstall the mroute in the kernel and clear the + * rpf information in the pim upstream and pim channel + * oil data structure. + */ +void pim_upstream_rpf_clear(struct pim_instance *pim, + struct pim_upstream *up) +{ + if (up->rpf.source_nexthop.interface) { + if (up->channel_oil) { + up->channel_oil->oil.mfcc_parent = MAXVIFS; + pim_mroute_del(up->channel_oil, __PRETTY_FUNCTION__); + + } + pim_upstream_switch(pim, up, PIM_UPSTREAM_NOTJOINED); + up->rpf.source_nexthop.interface = NULL; + up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr = + PIM_NET_INADDR_ANY; + up->rpf.source_nexthop.mrib_metric_preference = + router->infinite_assert_metric.metric_preference; + up->rpf.source_nexthop.mrib_route_metric = + router->infinite_assert_metric.route_metric; + up->rpf.rpf_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY; + } +} + +/* RFC 4601: 4.1.6. State Summarization Macros neighbor RPF'(S,G) { diff --git a/pimd/pim_rpf.h b/pimd/pim_rpf.h index b9fe162f21..a4793df667 100644 --- a/pimd/pim_rpf.h +++ b/pimd/pim_rpf.h @@ -64,7 +64,8 @@ int pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop, enum pim_rpf_result pim_rpf_update(struct pim_instance *pim, struct pim_upstream *up, struct pim_rpf *old, uint8_t is_new); - +void pim_upstream_rpf_clear(struct pim_instance *pim, + struct pim_upstream *up); int pim_rpf_addr_is_inaddr_none(struct pim_rpf *rpf); int pim_rpf_addr_is_inaddr_any(struct pim_rpf *rpf); diff --git a/pimd/pim_ssm.c b/pimd/pim_ssm.c index dfc7063fd0..6a70a73b45 100644 --- a/pimd/pim_ssm.c +++ b/pimd/pim_ssm.c @@ -151,8 +151,7 @@ void pim_ssm_terminate(struct pim_ssm *ssm) if (!ssm) return; - if (ssm->plist_name) - XFREE(MTYPE_PIM_FILTER_NAME, ssm->plist_name); + XFREE(MTYPE_PIM_FILTER_NAME, ssm->plist_name); XFREE(MTYPE_PIM_SSM_INFO, ssm); } diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index c6ab8f5a2a..cb89e30a50 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -219,17 +219,25 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim, pim_msdp_up_del(pim, &up->sg); } - /* Deregister addr with Zebra NHT */ - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4 = up->upstream_addr; - if (PIM_DEBUG_TRACE) { - char buf[PREFIX2STR_BUFFER]; - prefix2str(&nht_p, buf, sizeof(buf)); - zlog_debug("%s: Deregister upstream %s addr %s with Zebra NHT", - __PRETTY_FUNCTION__, up->sg_str, buf); + /* When RP gets deleted, pim_rp_del() deregister addr with Zebra NHT + * and assign up->upstream_addr as INADDR_ANY. + * So before de-registering the upstream address, check if is not equal + * to INADDR_ANY. This is done in order to avoid de-registering for + * 255.255.255.255 which is maintained for some reason.. + */ + if (up->upstream_addr.s_addr != INADDR_ANY) { + /* Deregister addr with Zebra NHT */ + nht_p.family = AF_INET; + nht_p.prefixlen = IPV4_MAX_BITLEN; + nht_p.u.prefix4 = up->upstream_addr; + if (PIM_DEBUG_TRACE) { + char buf[PREFIX2STR_BUFFER]; + prefix2str(&nht_p, buf, sizeof(buf)); + zlog_debug("%s: Deregister upstream %s addr %s with Zebra NHT", + __PRETTY_FUNCTION__, up->sg_str, buf); + } + pim_delete_tracked_nexthop(pim, &nht_p, up, NULL); } - pim_delete_tracked_nexthop(pim, &nht_p, up, NULL); XFREE(MTYPE_PIM_UPSTREAM, up); @@ -238,6 +246,13 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim, void pim_upstream_send_join(struct pim_upstream *up) { + if (!up->rpf.source_nexthop.interface) { + if (PIM_DEBUG_TRACE) + zlog_debug("%s: up %s RPF is not present", + __PRETTY_FUNCTION__, up->sg_str); + return; + } + if (PIM_DEBUG_TRACE) { char rpf_str[PREFIX_STRLEN]; pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_str, @@ -263,6 +278,13 @@ static int on_join_timer(struct thread *t) up = THREAD_ARG(t); + if (!up->rpf.source_nexthop.interface) { + if (PIM_DEBUG_TRACE) + zlog_debug("%s: up %s RPF is not present", + __PRETTY_FUNCTION__, up->sg_str); + return 0; + } + /* * In the case of a HFR we will not ahve anyone to send this to. */ @@ -284,12 +306,13 @@ static int on_join_timer(struct thread *t) static void join_timer_stop(struct pim_upstream *up) { - struct pim_neighbor *nbr; + struct pim_neighbor *nbr = NULL; THREAD_OFF(up->t_join_timer); - nbr = pim_neighbor_find(up->rpf.source_nexthop.interface, - up->rpf.rpf_addr.u.prefix4); + if (up->rpf.source_nexthop.interface) + nbr = pim_neighbor_find(up->rpf.source_nexthop.interface, + up->rpf.rpf_addr.u.prefix4); if (nbr) pim_jp_agg_remove_group(nbr->upstream_jp_agg, up); @@ -356,6 +379,13 @@ void pim_upstream_join_suppress(struct pim_upstream *up, long t_joinsuppress_msec; long join_timer_remain_msec; + if (!up->rpf.source_nexthop.interface) { + if (PIM_DEBUG_TRACE) + zlog_debug("%s: up %s RPF is not present", + __PRETTY_FUNCTION__, up->sg_str); + return; + } + t_joinsuppress_msec = MIN(pim_if_t_suppressed_msec(up->rpf.source_nexthop.interface), 1000 * holdtime); @@ -389,6 +419,13 @@ void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label, long join_timer_remain_msec; int t_override_msec; + if (!up->rpf.source_nexthop.interface) { + if (PIM_DEBUG_TRACE) + zlog_debug("%s: up %s RPF is not present", + __PRETTY_FUNCTION__, up->sg_str); + return; + } + join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer); t_override_msec = pim_if_t_override_msec(up->rpf.source_nexthop.interface); @@ -511,6 +548,20 @@ void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up, { enum pim_upstream_state old_state = up->join_state; + if (up->upstream_addr.s_addr == INADDR_ANY) { + if (PIM_DEBUG_PIM_EVENTS) + zlog_debug("%s: RPF not configured for %s", + __PRETTY_FUNCTION__, up->sg_str); + return; + } + + if (!up->rpf.source_nexthop.interface) { + if (PIM_DEBUG_PIM_EVENTS) + zlog_debug("%s: RP not reachable for %s", + __PRETTY_FUNCTION__, up->sg_str); + return; + } + if (PIM_DEBUG_PIM_EVENTS) { zlog_debug("%s: PIM_UPSTREAM_%s: (S,G) old: %s new: %s", __PRETTY_FUNCTION__, up->sg_str, @@ -558,11 +609,14 @@ void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up, && !I_am_RP(pim, up->sg.grp)) { if (PIM_DEBUG_PIM_TRACE_DETAIL) zlog_debug( - "%s: *,G IIF %s S,G IIF %s ", - __PRETTY_FUNCTION__, - up->parent->rpf.source_nexthop - .interface->name, - up->rpf.source_nexthop.interface->name); + "%s: *,G IIF %s S,G IIF %s ", + __PRETTY_FUNCTION__, + up->parent->rpf.source_nexthop.interface ? + up->parent->rpf.source_nexthop.interface->name + : "Unknown", + up->rpf.source_nexthop.interface ? + up->rpf.source_nexthop.interface->name : + "Unknown"); pim_jp_agg_single_upstream_send(&up->parent->rpf, up->parent, 1 /* (W,G) Join */); @@ -611,15 +665,14 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim, ch->upstream = up; up = hash_get(pim->upstream_hash, up, hash_alloc_intern); + /* Set up->upstream_addr as INADDR_ANY, if RP is not + * configured and retain the upstream data structure + */ if (!pim_rp_set_upstream_addr(pim, &up->upstream_addr, sg->src, sg->grp)) { if (PIM_DEBUG_TRACE) zlog_debug("%s: Received a (*,G) with no RP configured", __PRETTY_FUNCTION__); - - hash_release(pim->upstream_hash, up); - XFREE(MTYPE_PIM_UPSTREAM, up); - return NULL; } up->parent = pim_upstream_find_parent(pim, up); @@ -659,45 +712,34 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim, if (up->sg.src.s_addr != INADDR_ANY) wheel_add_item(pim->upstream_sg_wheel, up); - rpf_result = pim_rpf_update(pim, up, NULL, 1); - if (rpf_result == PIM_RPF_FAILURE) { - struct prefix nht_p; - - if (PIM_DEBUG_TRACE) - zlog_debug( - "%s: Attempting to create upstream(%s), Unable to RPF for source", - __PRETTY_FUNCTION__, up->sg_str); - - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4 = up->upstream_addr; - pim_delete_tracked_nexthop(pim, &nht_p, up, NULL); + if (up->upstream_addr.s_addr == INADDR_ANY) + /* Create a dummmy channel oil with incoming ineterface MAXVIFS, + * since RP is not configured + */ + up->channel_oil = pim_channel_oil_add(pim, &up->sg, MAXVIFS); - if (up->parent) { - listnode_delete(up->parent->sources, up); - up->parent = NULL; + else { + rpf_result = pim_rpf_update(pim, up, NULL, 1); + if (rpf_result == PIM_RPF_FAILURE) { + if (PIM_DEBUG_TRACE) + zlog_debug( + "%s: Attempting to create upstream(%s), Unable to RPF for source", + __PRETTY_FUNCTION__, up->sg_str); + /* Create a dummmy channel oil with incoming ineterface + * MAXVIFS, since RP is not reachable + */ + up->channel_oil = pim_channel_oil_add( + pim, &up->sg, MAXVIFS); } - if (up->sg.src.s_addr != INADDR_ANY) - wheel_remove_item(pim->upstream_sg_wheel, up); - - pim_upstream_remove_children(pim, up); - if (up->sources) - list_delete(&up->sources); - - list_delete(&up->ifchannels); - - hash_release(pim->upstream_hash, up); - XFREE(MTYPE_PIM_UPSTREAM, up); - return NULL; + if (up->rpf.source_nexthop.interface) { + pim_ifp = up->rpf.source_nexthop.interface->info; + if (pim_ifp) + up->channel_oil = pim_channel_oil_add(pim, + &up->sg, pim_ifp->mroute_vif_index); + } } - if (up->rpf.source_nexthop.interface) { - pim_ifp = up->rpf.source_nexthop.interface->info; - if (pim_ifp) - up->channel_oil = pim_channel_oil_add( - pim, &up->sg, pim_ifp->mroute_vif_index); - } listnode_add_sort(pim->upstream_list, up); if (PIM_DEBUG_TRACE) { @@ -783,7 +825,7 @@ struct pim_upstream *pim_upstream_add(struct pim_instance *pim, zlog_debug("%s(%s): %s, iif %s (%s) found: %d: ref_count: %d", __PRETTY_FUNCTION__, name, up->sg_str, buf, up->rpf.source_nexthop.interface ? - up->rpf.source_nexthop.interface->name : "NIL" , + up->rpf.source_nexthop.interface->name : "Unknown" , found, up->ref_count); } else zlog_debug("%s(%s): (%s) failure to create", @@ -896,7 +938,7 @@ void pim_upstream_update_join_desired(struct pim_instance *pim, PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags); /* switched from false to true */ - if (is_join_desired && !was_join_desired) { + if (is_join_desired && (up->join_state == PIM_UPSTREAM_NOTJOINED)) { pim_upstream_switch(pim, up, PIM_UPSTREAM_JOINED); return; } @@ -973,7 +1015,9 @@ void pim_upstream_rpf_interface_changed(struct pim_upstream *up, (old_rpf_ifp == ch->interface) && /* RPF_interface(S) stopped being I */ (ch->upstream->rpf.source_nexthop - .interface != ch->interface)) { + .interface) && + (ch->upstream->rpf.source_nexthop + .interface != ch->interface)) { assert_action_a5(ch); } } /* PIM_IFASSERT_I_AM_LOSER */ @@ -1339,6 +1383,13 @@ static int pim_upstream_register_stop_timer(struct thread *t) case PIM_REG_JOIN: break; case PIM_REG_PRUNE: + if (!up->rpf.source_nexthop.interface) { + if (PIM_DEBUG_TRACE) + zlog_debug("%s: up %s RPF is not present", + __PRETTY_FUNCTION__, up->sg_str); + return 0; + } + pim_ifp = up->rpf.source_nexthop.interface->info; if (!pim_ifp) { if (PIM_DEBUG_TRACE) @@ -1515,11 +1566,19 @@ void pim_upstream_find_new_rpf(struct pim_instance *pim) * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr */ for (ALL_LIST_ELEMENTS(pim->upstream_list, up_node, up_nextnode, up)) { + if (up->upstream_addr.s_addr == INADDR_ANY) { + if (PIM_DEBUG_TRACE) + zlog_debug( + "%s: RP not configured for Upstream %s", + __PRETTY_FUNCTION__, up->sg_str); + continue; + } + if (pim_rpf_addr_is_inaddr_any(&up->rpf)) { if (PIM_DEBUG_TRACE) zlog_debug( - "Upstream %s without a path to send join, checking", - up->sg_str); + "%s: Upstream %s without a path to send join, checking", + __PRETTY_FUNCTION__, up->sg_str); pim_rpf_update(pim, up, NULL, 1); } } @@ -1586,7 +1645,8 @@ static bool pim_upstream_kat_start_ok(struct pim_upstream *up) /* "iif == RPF_interface(S)" check has to be done by the kernel or hw * so we will skip that here */ - if (pim_if_connected_to_source(up->rpf.source_nexthop.interface, + if (up->rpf.source_nexthop.interface && + pim_if_connected_to_source(up->rpf.source_nexthop.interface, up->sg.src)) { return true; } @@ -1679,7 +1739,8 @@ static void pim_upstream_sg_running(void *arg) } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags)) pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time); - if (up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE) { + if ((up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE) && + (up->rpf.source_nexthop.interface)) { pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface); } return; diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h index f44b95c811..70e70140d1 100644 --- a/pimd/pim_upstream.h +++ b/pimd/pim_upstream.h @@ -88,10 +88,30 @@ enum pim_upstream_sptbit { /* Upstream (S,G) channel in Joined state - (S,G) in the "Not Joined" state is not represented - See RFC 4601: 4.5.7. Sending (S,G) Join/Prune Message + + upstream_addr : Who we are talking to. + For (*, G), upstream_addr is RP address or INADDR_ANY(if RP not configured) + For (S, G), upstream_addr is source address + + rpf: contains the nexthop information to whom we are talking to. + + join_state: JOINED/NOTJOINED + + In the case when FRR receives IGMP/PIM (*, G) join for group G and RP is not + configured, then create a pim_upstream with the below information. + pim_upstream->upstream address: INADDR_ANY + pim_upstream->rpf: Unknown + pim_upstream->state: NOTJOINED + + When a new RP gets configured for G, find the corresponding pim upstream (*,G) + entries and update the upstream address as new RP address if it the better one + for the group G. + + When RP becomes reachable, populate the nexthop information in + pim_upstream->rpf and update the state to JOINED. + */ struct pim_upstream { struct pim_upstream *parent; diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 11ca6e8a10..78cccd5877 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -472,55 +472,72 @@ void pim_zebra_upstream_rpf_changed(struct pim_instance *pim, struct pim_upstream *up, struct pim_rpf *old) { - struct pim_neighbor *nbr; + if (old->source_nexthop.interface) { + struct pim_neighbor *nbr; - nbr = pim_neighbor_find(old->source_nexthop.interface, - old->rpf_addr.u.prefix4); - if (nbr) - pim_jp_agg_remove_group(nbr->upstream_jp_agg, up); + nbr = pim_neighbor_find(old->source_nexthop.interface, + old->rpf_addr.u.prefix4); + if (nbr) + pim_jp_agg_remove_group(nbr->upstream_jp_agg, up); - /* - * We have detected a case where we might need - * to rescan the inherited o_list so do it. - */ - if (up->channel_oil->oil_inherited_rescan) { - pim_upstream_inherited_olist_decide(pim, up); - up->channel_oil->oil_inherited_rescan = 0; - } - - if (up->join_state == PIM_UPSTREAM_JOINED) { /* - * If we come up real fast we can be here - * where the mroute has not been installed - * so install it. + * We have detected a case where we might need + * to rescan the inherited o_list so do it. */ - if (!up->channel_oil->installed) - pim_mroute_add(up->channel_oil, __PRETTY_FUNCTION__); + if (up->channel_oil->oil_inherited_rescan) { + pim_upstream_inherited_olist_decide(pim, up); + up->channel_oil->oil_inherited_rescan = 0; + } + + if (up->join_state == PIM_UPSTREAM_JOINED) { + /* + * If we come up real fast we can be here + * where the mroute has not been installed + * so install it. + */ + if (!up->channel_oil->installed) + pim_mroute_add(up->channel_oil, + __PRETTY_FUNCTION__); + + /* + * RFC 4601: 4.5.7. Sending (S,G) + * Join/Prune Messages + * + * Transitions from Joined State + * + * RPF'(S,G) changes not due to an Assert + * + * The upstream (S,G) state machine remains + * in Joined state. Send Join(S,G) to the new + * upstream neighbor, which is the new value + * of RPF'(S,G). Send Prune(S,G) to the old + * upstream neighbor, which is the old value + * of RPF'(S,G). Set the Join Timer (JT) to + * expire after t_periodic seconds. + */ + pim_jp_agg_switch_interface(old, &up->rpf, up); + + pim_upstream_join_timer_restart(up, old); + } /* up->join_state == PIM_UPSTREAM_JOINED */ + } + else { /* - * RFC 4601: 4.5.7. Sending (S,G) - * Join/Prune Messages - * - * Transitions from Joined State - * - * RPF'(S,G) changes not due to an Assert - * - * The upstream (S,G) state machine remains - * in Joined state. Send Join(S,G) to the new - * upstream neighbor, which is the new value - * of RPF'(S,G). Send Prune(S,G) to the old - * upstream neighbor, which is the old value - * of RPF'(S,G). Set the Join Timer (JT) to - * expire after t_periodic seconds. + * We have detected a case where we might need + * to rescan the inherited o_list so do it. */ - pim_jp_agg_switch_interface(old, &up->rpf, up); + if (up->channel_oil->oil_inherited_rescan) { + pim_upstream_inherited_olist_decide(pim, up); + up->channel_oil->oil_inherited_rescan = 0; + } - pim_upstream_join_timer_restart(up, old); - } /* up->join_state == PIM_UPSTREAM_JOINED */ + if (!up->channel_oil->installed) + pim_mroute_add(up->channel_oil, __PRETTY_FUNCTION__); + } - /* FIXME can join_desired actually be changed by - pim_rpf_update() - returning PIM_RPF_CHANGED ? */ + /* FIXME can join_desired actually be changed by pim_rpf_update() + * returning PIM_RPF_CHANGED ? + */ pim_upstream_update_join_desired(pim, up); } @@ -535,6 +552,14 @@ static void scan_upstream_rpf_cache(struct pim_instance *pim) struct pim_rpf old; struct prefix nht_p; + if (up->upstream_addr.s_addr == INADDR_ANY) { + if (PIM_DEBUG_TRACE) + zlog_debug( + "%s: RP not configured for Upstream %s", + __PRETTY_FUNCTION__, up->sg_str); + continue; + } + nht_p.family = AF_INET; nht_p.prefixlen = IPV4_MAX_BITLEN; nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr; @@ -561,10 +586,9 @@ void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index) int input_iface_vif_index; int old_vif_index; - if (!pim_rp_set_upstream_addr(c_oil->pim, &vif_source, + pim_rp_set_upstream_addr(c_oil->pim, &vif_source, c_oil->oil.mfcc_origin, - c_oil->oil.mfcc_mcastgrp)) - return; + c_oil->oil.mfcc_mcastgrp); if (in_vif_index) input_iface_vif_index = in_vif_index; @@ -950,112 +974,141 @@ void igmp_source_forward_start(struct pim_instance *pim, struct pim_upstream *up = NULL; if (!pim_rp_set_upstream_addr(pim, &vif_source, - source->source_addr, sg.grp)) - return; - - /* Register addr with Zebra NHT */ - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4 = vif_source; - memset(&out_pnc, 0, sizeof(struct pim_nexthop_cache)); + source->source_addr, sg.grp)) { + /*Create a dummy channel oil */ + source->source_channel_oil = + pim_channel_oil_add(pim, &sg, MAXVIFS); - src.family = AF_INET; - src.prefixlen = IPV4_MAX_BITLEN; - src.u.prefix4 = vif_source; // RP or Src address - grp.family = AF_INET; - grp.prefixlen = IPV4_MAX_BITLEN; - grp.u.prefix4 = sg.grp; + if (!source->source_channel_oil) { + if (PIM_DEBUG_IGMP_TRACE) { + zlog_debug( + "%s %s: could not create OIL for channel (S,G)=%s", + __FILE__, __PRETTY_FUNCTION__, + pim_str_sg_dump(&sg)); + } + return; + } + } - if (pim_find_or_track_nexthop(pim, &nht_p, NULL, NULL, + else { + /* Register addr with Zebra NHT */ + nht_p.family = AF_INET; + nht_p.prefixlen = IPV4_MAX_BITLEN; + nht_p.u.prefix4 = vif_source; + memset(&out_pnc, 0, sizeof(struct pim_nexthop_cache)); + + src.family = AF_INET; + src.prefixlen = IPV4_MAX_BITLEN; + src.u.prefix4 = vif_source; // RP or Src address + grp.family = AF_INET; + grp.prefixlen = IPV4_MAX_BITLEN; + grp.u.prefix4 = sg.grp; + + if (pim_find_or_track_nexthop(pim, &nht_p, NULL, NULL, &out_pnc)) { - if (out_pnc.nexthop_num) { - up = pim_upstream_find(pim, &sg); - memset(&nexthop, 0, sizeof(nexthop)); - if (up) - memcpy(&nexthop, - &up->rpf.source_nexthop, - sizeof(struct pim_nexthop)); - pim_ecmp_nexthop_search(pim, &out_pnc, &nexthop, - &src, &grp, 0); - if (nexthop.interface) - input_iface_vif_index = + if (out_pnc.nexthop_num) { + up = pim_upstream_find(pim, &sg); + memset(&nexthop, 0, sizeof(nexthop)); + if (up) + memcpy(&nexthop, + &up->rpf.source_nexthop, + sizeof(struct pim_nexthop)); + pim_ecmp_nexthop_search(pim, &out_pnc, + &nexthop, + &src, &grp, 0); + if (nexthop.interface) + input_iface_vif_index = pim_if_find_vifindex_by_ifindex( - pim, - nexthop.interface->ifindex); - } else { - if (PIM_DEBUG_ZEBRA) { - char buf1[INET_ADDRSTRLEN]; - char buf2[INET_ADDRSTRLEN]; - pim_inet4_dump("<source?>", + pim, + nexthop.interface->ifindex); + } else { + if (PIM_DEBUG_ZEBRA) { + char buf1[INET_ADDRSTRLEN]; + char buf2[INET_ADDRSTRLEN]; + + pim_inet4_dump("<source?>", nht_p.u.prefix4, buf1, sizeof(buf1)); - pim_inet4_dump("<source?>", + pim_inet4_dump("<source?>", grp.u.prefix4, buf2, sizeof(buf2)); - zlog_debug( + zlog_debug( "%s: NHT Nexthop not found for addr %s grp %s", __PRETTY_FUNCTION__, buf1, buf2); + } } - } - } else - input_iface_vif_index = - pim_ecmp_fib_lookup_if_vif_index(pim, &src, + } else + input_iface_vif_index = + pim_ecmp_fib_lookup_if_vif_index(pim, &src, &grp); - if (PIM_DEBUG_ZEBRA) { - char buf2[INET_ADDRSTRLEN]; - pim_inet4_dump("<source?>", vif_source, buf2, - sizeof(buf2)); - zlog_debug("%s: NHT %s vif_source %s vif_index:%d ", - __PRETTY_FUNCTION__, pim_str_sg_dump(&sg), - buf2, input_iface_vif_index); - } - - if (input_iface_vif_index < 1) { - if (PIM_DEBUG_IGMP_TRACE) { - char source_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<source?>", source->source_addr, - source_str, sizeof(source_str)); - zlog_debug( - "%s %s: could not find input interface for source %s", - __FILE__, __PRETTY_FUNCTION__, - source_str); - } - return; - } + if (PIM_DEBUG_ZEBRA) { + char buf2[INET_ADDRSTRLEN]; - /* - Protect IGMP against adding looped MFC entries created by both - source and receiver attached to the same interface. See TODO - T22. - */ - if (input_iface_vif_index == pim_oif->mroute_vif_index) { - /* ignore request for looped MFC entry */ - if (PIM_DEBUG_IGMP_TRACE) { - zlog_debug( - "%s: ignoring request for looped MFC entry (S,G)=%s: igmp_sock=%d oif=%s vif_index=%d", + pim_inet4_dump("<source?>", vif_source, buf2, + sizeof(buf2)); + zlog_debug("%s: NHT %s vif_source %s vif_index:%d ", __PRETTY_FUNCTION__, pim_str_sg_dump(&sg), - source->source_group->group_igmp_sock - ->fd, - source->source_group->group_igmp_sock - ->interface->name, - input_iface_vif_index); + buf2, input_iface_vif_index); } - return; - } - source->source_channel_oil = - pim_channel_oil_add(pim, &sg, input_iface_vif_index); - if (!source->source_channel_oil) { - if (PIM_DEBUG_IGMP_TRACE) { - zlog_debug( - "%s %s: could not create OIL for channel (S,G)=%s", - __FILE__, __PRETTY_FUNCTION__, - pim_str_sg_dump(&sg)); + if (input_iface_vif_index < 1) { + if (PIM_DEBUG_IGMP_TRACE) { + char source_str[INET_ADDRSTRLEN]; + pim_inet4_dump("<source?>", + source->source_addr, + source_str, sizeof(source_str)); + zlog_debug( + "%s %s: could not find input interface for source %s", + __FILE__, __PRETTY_FUNCTION__, + source_str); + } + source->source_channel_oil = + pim_channel_oil_add(pim, &sg, MAXVIFS); + } + + else { + /* + * Protect IGMP against adding looped MFC + * entries created by both source and receiver + * attached to the same interface. See TODO + * T22. + */ + if (input_iface_vif_index == + pim_oif->mroute_vif_index) { + /* ignore request for looped MFC entry + */ + if (PIM_DEBUG_IGMP_TRACE) { + zlog_debug( + "%s: ignoring request for looped MFC entry (S,G)=%s: igmp_sock=%d oif=%s vif_index=%d", + __PRETTY_FUNCTION__, + pim_str_sg_dump(&sg), + source->source_group + ->group_igmp_sock->fd, + source->source_group + ->group_igmp_sock + ->interface->name, + input_iface_vif_index); + } + return; + } + + source->source_channel_oil = + pim_channel_oil_add(pim, &sg, + input_iface_vif_index); + if (!source->source_channel_oil) { + if (PIM_DEBUG_IGMP_TRACE) { + zlog_debug( + "%s %s: could not create OIL for channel (S,G)=%s", + __FILE__, + __PRETTY_FUNCTION__, + pim_str_sg_dump(&sg)); + } + return; + } } - return; } } @@ -1188,15 +1241,13 @@ void pim_forward_start(struct pim_ifchannel *ch) sizeof(upstream_str)); zlog_debug("%s: (S,G)=(%s,%s) oif=%s (%s)", __PRETTY_FUNCTION__, source_str, group_str, ch->interface->name, - upstream_str); + inet_ntoa(up->upstream_addr)); } /* Resolve IIF for upstream as mroute_del sets mfcc_parent to MAXVIFS, as part of mroute_del called by pim_forward_stop. */ - if (!up->channel_oil - || (up->channel_oil - && up->channel_oil->oil.mfcc_parent >= MAXVIFS)) { + if ((up->upstream_addr.s_addr != INADDR_ANY) && (!up->channel_oil)) { struct prefix nht_p, src, grp; struct pim_nexthop_cache out_pnc; @@ -1267,17 +1318,33 @@ void pim_forward_start(struct pim_ifchannel *ch) __FILE__, __PRETTY_FUNCTION__, source_str); } - return; + up->channel_oil = pim_channel_oil_add(pim, &up->sg, + MAXVIFS); } + + else { + up->channel_oil = pim_channel_oil_add(pim, &up->sg, + input_iface_vif_index); + if (!up->channel_oil) { + if (PIM_DEBUG_PIM_TRACE) + zlog_debug( + "%s %s: could not create OIL for channel (S,G)=%s", + __FILE__, __PRETTY_FUNCTION__, + up->sg_str); + return; + } + } + if (PIM_DEBUG_TRACE) { struct interface *in_intf = pim_if_find_by_vif_index( pim, input_iface_vif_index); zlog_debug( "%s: Update channel_oil IIF %s VIFI %d entry %s ", __PRETTY_FUNCTION__, - in_intf ? in_intf->name : "NIL", + in_intf ? in_intf->name : "Unknown", input_iface_vif_index, up->sg_str); } + up->channel_oil = pim_channel_oil_add(pim, &up->sg, input_iface_vif_index); if (!up->channel_oil) { diff --git a/pimd/pimd.c b/pimd/pimd.c index 656b000579..889a83a136 100644 --- a/pimd/pimd.c +++ b/pimd/pimd.c @@ -127,8 +127,6 @@ void pim_terminate(void) { struct zclient *zclient; - pim_free(); - /* reverse prefix_list_init */ prefix_list_add_hook(NULL); prefix_list_delete_hook(NULL); @@ -142,6 +140,8 @@ void pim_terminate(void) zclient_free(zclient); } + pim_free(); pim_router_terminate(); + frr_fini(); } diff --git a/redhat/README.rpm_build.md b/redhat/README.rpm_build.md deleted file mode 100644 index a3f095786d..0000000000 --- a/redhat/README.rpm_build.md +++ /dev/null @@ -1,119 +0,0 @@ -Building your own FRRouting RPM -====================================== -(Tested on CentOS 6, CentOS 7 and Fedora 24.) - -1. On CentOS 6 (which doesn't provide a bison/automake/autoconf of a recent enough version): - - Check out ../doc/developer/building-frr-for-centos6.rst for details on installing - a bison/automake/autoconf to support frr building. - - Newer automake/autoconf/bison is only needed to build the rpm and is - **not** needed to install the binary rpm package - -2. Install the build packages as documented in doc/developer/building-frr-for-xxxxx.rst and the following additional packages: - - yum install rpm-build net-snmp-devel pam-devel libcap-devel - - Additionally, on systems with systemd (CentOS 7, Fedora) - - yum install systemd-devel - - (use `dnf install` on new Fedora instead of `yum install`) - -3. Checkout FRR under a **unpriviledged** user account - - git clone https://github.com/frrouting/frr.git frr - -4. Run Bootstrap and make distribution tar.gz - - cd frr - ./bootstrap.sh - ./configure --with-pkg-extra-version=-MyRPMVersion \ - SPHINXBUILD=sphinx-build2.7 - make dist - - Note: configure parameters are not important for the RPM building - except the `with-pkg-extra-version` if you want to give the RPM a specific name to - mark your own unoffical build - -5. Create RPM directory structure and populate with sources - - mkdir rpmbuild - mkdir rpmbuild/SOURCES - mkdir rpmbuild/SPECS - cp redhat/*.spec rpmbuild/SPECS/ - cp frr*.tar.gz rpmbuild/SOURCES/ - -6. Edit rpm/SPECS/frr.spec with configuration as needed - Look at the beginning of the file and adjust the following parameters to enable or disable features as required: - - ############### FRRouting (FRR) configure options ################# - # with-feature options - %{!?with_pam: %global with_pam 0 } - %{!?with_ospfclient: %global with_ospfclient 1 } - %{!?with_ospfapi: %global with_ospfapi 1 } - %{!?with_irdp: %global with_irdp 1 } - %{!?with_rtadv: %global with_rtadv 1 } - %{!?with_ldpd: %global with_ldpd 1 } - %{!?with_nhrpd: %global with_nhrpd 1 } - %{!?with_eigrp: %global with_eigrpd 1 } - %{!?with_shared: %global with_shared 1 } - %{!?with_multipath: %global with_multipath 256 } - %{!?frr_user: %global frr_user frr } - %{!?vty_group: %global vty_group frrvty } - %{!?with_fpm: %global with_fpm 0 } - %{!?with_watchfrr: %global with_watchfrr 1 } - %{!?with_bgp_vnc: %global with_bgp_vnc 0 } - %{!?with_pimd: %global with_pimd 1 } - %{!?with_rpki: %global with_rpki 0 } - -7. Build the RPM - - rpmbuild --define "_topdir `pwd`/rpmbuild" -ba rpmbuild/SPECS/frr.spec - - If building with RPKI, then download and install the additional RPKI - packages from - https://ci1.netdef.org/browse/RPKI-RTRLIB/latestSuccessful/artifact - -DONE. - -If all works correctly, then you should end up with the RPMs under -`rpmbuild/RPMS` and the Source RPM under `rpmbuild/SRPMS` - - -Enabling daemons after installation of the package: ---------------------------------------------------- - -### init.d based systems (ie CentOS 6): - -1. Edit /etc/frr/daemons and enable required routing daemons (Zebra is probably needed for most deployments, so make sure to enable it.) - -2. Enable the daemons as needed to run after boot (Zebra is mandatory) - - chkconfig frr on - -3. Check your firewall / IPtables to make sure the routing protocols are -allowed. - -5. Start the FRR daemons (or reboot) - - service frr start - -Configuration is stored in `/etc/frr/*.conf` files and daemon selection is stored in `/etc/frr/daemons`. - - -### systemd based systems (ie CentOS 7, Fedora 24) - -1. Edit /etc/frr/daemons and enable required routing daemons (Zebra is probably needed for most deployments, so make sure to enable it.) - -2. Enable the frr daemons to run after boot. - - systemctl enable frr - -2. Check your firewall / IPtables to make sure the routing protocols are -allowed. - -3. Start the daemons (or reboot) - - systemctl start frr - -Configuration is stored in `/etc/frr/*.conf` files and daemon selection is stored in `/etc/frr/daemons`. - diff --git a/redhat/daemons b/redhat/daemons deleted file mode 100644 index 7f3ff36df9..0000000000 --- a/redhat/daemons +++ /dev/null @@ -1,86 +0,0 @@ -# This file tells the frr package which daemons to start. -# -# Entries are in the format: <daemon>=(yes|no|priority) -# 0, "no" = disabled -# 1, "yes" = highest priority -# 2 .. 10 = lower priorities -# -# For daemons which support multiple instances, a 2nd line listing -# the instances can be added. Eg for ospfd: -# ospfd=yes -# ospfd_instances="1,2" -# -# Priorities were suggested by Dancer <dancer@zeor.simegen.com>. -# They're used to start the FRR daemons in more than one step -# (for example start one or two at network initialization and the -# rest later). The number of FRR daemons being small, priorities -# must be between 1 and 9, inclusive (or the initscript has to be -# changed). /etc/init.d/frr then can be started as -# -# /etc/init.d/frr <start|stop|restart|<priority>> -# -# where priority 0 is the same as 'stop', priority 10 or 'start' -# means 'start all' -# -# Sample configurations for these daemons can be found in -# /usr/share/doc/frr/examples/. -# -# ATTENTION: -# -# When activation a daemon at the first time, a config file, even if it is -# empty, has to be present *and* be owned by the user and group "frr", else -# the daemon will not be started by /etc/init.d/frr. The permissions should -# be u=rw,g=r,o=. -# When using "vtysh" such a config file is also needed. It should be owned by -# group "frrvty" and set to ug=rw,o= though. Check /etc/pam.d/frr, too. -# -watchfrr_enable=yes -watchfrr_options="-r '/usr/lib/frr/frr restart %s' -s '/usr/lib/frr/frr start %s' -k '/usr/lib/frr/frr stop %s'" -# -zebra=no -bgpd=no -ospfd=no -ospf6d=no -ripd=no -ripngd=no -isisd=no -ldpd=no -pimd=no -nhrpd=no -eigrpd=no -babeld=no -sharpd=no -pbrd=no -staticd=no -bfdd=no -fabricd=no - -# -# Command line options for the daemons -# -zebra_options=("-A 127.0.0.1") -bgpd_options=("-A 127.0.0.1") -ospfd_options=("-A 127.0.0.1") -ospf6d_options=("-A ::1") -ripd_options=("-A 127.0.0.1") -ripngd_options=("-A ::1") -isisd_options=("-A 127.0.0.1") -ldpd_options=("-A 127.0.0.1") -pimd_options=("-A 127.0.0.1") -nhrpd_options=("-A 127.0.0.1") -eigrpd_options=("-A 127.0.0.1") -babeld_options=("-A 127.0.0.1") -sharpd_options=("-A 127.0.0.1") -pbrd_options=("-A 127.0.0.1") -staticd_options=("-A 127.0.0.1") -bfdd_options=("-A 127.0.0.1") -fabricd_options=("-A 127.0.0.1") - -# -# If the vtysh_enable is yes, then the unified config is read -# and applied if it exists. If no unified frr.conf exists -# then the per-daemon <daemon>.conf files are used) -# If vtysh_enable is no or non-existant, the frr.conf is ignored. -# it is highly suggested to have this set to yes -vtysh_enable=yes - diff --git a/redhat/frr.init b/redhat/frr.init deleted file mode 100755 index b59656adcd..0000000000 --- a/redhat/frr.init +++ /dev/null @@ -1,577 +0,0 @@ -#!/bin/bash -# -# /etc/rc.d/init.d/frr -# -# Start/Stop the FRR Routing daemons -# <any general comments about this init script> -# -# chkconfig: 2345 15 85 -# -# description: FRRouting (FRR) is a routing suite for IP routing protocols -# like BGP, OSPF, RIP and others. This script contols the main -# daemon "frr" as well as the individual protocol daemons. -# -### BEGIN INIT INFO -# Provides: frr -# Required-Start: $local_fs $network $syslog -# Required-Stop: $local_fs $syslog -# Should-Start: $syslog -# Should-Stop: $network $syslog -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: Start/Stop the FRR Routing daemons -# Description: FRRouting (FRR) is a routing suite for IP routing protocols -# like BGP, OSPF, RIP and others. This script contols the main -# daemon "frr" as well as the individual protocol daemons. -### END INIT INFO - -PATH=/bin:/usr/bin:/sbin:/usr/sbin -D_PATH=/usr/lib/frr -C_PATH=/etc/frr -V_PATH=/var/run/frr - -# Local Daemon selection may be done by using /etc/frr/daemons. -# See /usr/share/doc/frr/README.Debian.gz for further information. -# Keep zebra first and do not list watchfrr! -DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd pimd pbrd ldpd nhrpd eigrpd babeld staticd sharpd bfdd fabricd" -MAX_INSTANCES=5 -RELOAD_SCRIPT=/usr/lib/frr/frr-reload.py - -. /etc/init.d/functions - -# Print the name of the pidfile. -pidfile() -{ - echo "$V_PATH/$1.pid" -} - -# Print the name of the vtysh. -vtyfile() -{ - echo "$V_PATH/$1.vty" -} - -# Check if daemon is started by using the pidfile. -started() -{ - [ ! -e `pidfile $1` ] && return 3 - if [ -n "$2" ] && [ "$2" == "log" ]; then - status -p `pidfile $1` $1 && return 0 || return $? - else - kill -0 `cat \`pidfile $1\`` 2> /dev/null || return 1 - return 0 - fi -} - -# Loads the config via vtysh -b if configured to do so. -vtysh_b () -{ - # Rember, that all variables have been incremented by 1 in convert_daemon_prios() - if [ "$vtysh_enable" = 2 -a -f $C_PATH/frr.conf ]; then - /usr/bin/vtysh -b -n - fi -} - -# Check if the daemon is activated and if its executable and config files -# are in place. -# params: daemon name -# returns: 0=ok, 1=error -check_daemon() -{ - # If the integrated config file is used the others are not checked. - if [ -r "$C_PATH/frr.conf" ]; then - return 0 - fi - - # vtysh_enable has no config file nor binary so skip check. - # (Not sure why vtysh_enable is in this list but does not hurt) - if [ $1 != "watchfrr" -a $1 != "vtysh_enable" ]; then - # check for daemon binary - if [ ! -x "$D_PATH/$1" ]; then return 1; fi - - # check for config file - if [ -n "$2" ]; then - if [ ! -r "$C_PATH/$1-$2.conf" ]; then - touch "$C_PATH/$1-$2.conf" - chown frr:frr "$C_PATH/$1-$2.conf" - fi - elif [ ! -r "$C_PATH/$1.conf" ]; then - touch "$C_PATH/$1.conf" - chown frr:frr "$C_PATH/$1.conf" - fi - fi - return 0 -} - -# Starts the server if it's not already running according to the pid file. -# The Frr daemons creates the pidfile when starting. -start() -{ - local dmn inst - dmn="$1" - inst="$2" - - ulimit -n $MAX_FDS > /dev/null 2> /dev/null - if [ "$dmn" = "watchfrr" ]; then - - # We may need to restart watchfrr if new daemons are added and/or - # removed - if started "$dmn" ; then - stop watchfrr - else - # Echo only once. watchfrr is printed in the stop above - echo -n " $dmn" - fi - - if [ -e /var/run/frr/watchfrr.started ] ; then - rm /var/run/frr/watchfrr.started - fi - # redhat /etc/init.d/functions daemon() re-expands args :( - # eval "set - $watchfrr_options" - daemon --pidfile=`pidfile $dmn` "$D_PATH/$dmn" -d "$watchfrr_options" - RETVAL=$? - [ $RETVAL -ne 0 ] && break - for i in `seq 1 10`; - do - if [ -e /var/run/frr/watchfrr.started ] ; then - RETVAL=0 - break - else - sleep 1 - fi - done - RETVAL=1 - elif [ -n "$inst" ]; then - echo -n " $dmn-$inst" - if ! check_daemon $dmn $inst ; then - echo -n " (binary does not exist)" - return; - fi - daemon --pidfile=`pidfile $dmn-$inst` "$D_PATH/$dmn" -d `eval echo "$""$dmn""_options"` -n "$inst" - RETVAL=$? - else - echo -n " $dmn " - if ! check_daemon $dmn; then - echo " (binary does not exist)" - return; - fi - daemon --pidfile=`pidfile $dmn` "$D_PATH/$dmn" -d `eval echo "$""$dmn""_options"` - RETVAL=$? - fi - echo - [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$dmn - return $RETVAL -} - -# Stop the daemon given in the parameter, printing its name to the terminal. -stop() -{ - local inst - - if [ -n "$2" ]; then - inst="$1-$2" - else - inst="$1" - fi - - if ! started "$inst" ; then - # echo -n " ($inst)" - return 0 - else - echo -n " $inst" - PIDFILE=`pidfile $inst` - PID=`cat $PIDFILE 2>/dev/null` - killproc -p "$PIDFILE" "$D_PATH/$1" - RETVAL=$? - [ $RETVAL -eq 0 ] && rm -f $lockfile - rm -f `pidfile $inst` - rm -f `vtyfile $inst` - echo - return $RETVAL - fi -} - -# Converts values from /etc/frr/daemons to all-numeric values. -convert_daemon_prios() -{ - for name in $DAEMONS zebra vtysh_enable watchfrr_enable; do - # First, assign the value set by the user to $value - eval value=\${${name}:0:3} - - # Daemon not activated or entry missing? - if [ "$value" = "no" -o "$value" = "" ]; then value=0; fi - - # These strings parsed for backwards compatibility. - if [ "$value" = "yes" -o "$value" = "true" ]; then - value=1; - fi - - # Zebra is threatened special. It must be between 0=off and the first - # user assigned value "1" so we increase all other enabled daemons' values. - if [ "$name" != "zebra" -a "$value" -gt 0 ]; then value=`expr "$value" + 1`; fi - - # If e.g. name is zebra then we set "zebra=yes". - eval $name=$value - done -} - -# Starts watchfrr for all wanted daemons. -start_watchfrr() -{ - local daemon_name - local daemon_prio - local found_one - local daemon_inst - - # Start the monitor daemon only if desired. - if [ 0 -eq "$watchfrr_enable" ]; then - return - fi - - # Check variable type - if declare -p watchfrr_options | grep -q '^declare \-a'; then - # old array support - watchfrr_options="${watchfrr_options[@]}" - fi - - # Which daemons have been started? - found_one=0 - for daemon_name in $DAEMONS; do - eval daemon_prio=\$$daemon_name - if [ "$daemon_prio" -gt 0 ]; then - eval "daemon_inst=\${${daemon_name}_instances//,/ }" - if [ -n "$daemon_inst" ]; then - for inst in ${daemon_inst}; do - eval "inst_disable=\${${daemon_name}_${inst}}" - if [ -z ${inst_disable} ] || [ ${inst_disable} != 0 ]; then - if check_daemon $daemon_name $inst; then - watchfrr_options="$watchfrr_options ${daemon_name}-${inst}" - fi - fi - done - else - if check_daemon $daemon_name; then - watchfrr_options="$watchfrr_options $daemon_name" - fi - fi - found_one=1 - fi - done - - # Start if at least one daemon is activated. - if [ $found_one -eq 1 ]; then - echo "Starting FRRouting monitor daemon:" - start watchfrr - fi -} - -# Stopps watchfrr. -stop_watchfrr() -{ - echo "Stopping FRRouting monitor daemon:" - stop watchfrr -} - -# Stops all daemons that have a lower level of priority than the given. -# (technically if daemon_prio >= wanted_prio) -stop_prio() -{ - local wanted_prio - local daemon_prio - local daemon_list - local daemon_inst - local inst - - if [ -n "$2" ] && [[ "$2" =~ (.*)-(.*) ]]; then - daemon=${BASH_REMATCH[1]} - inst=${BASH_REMATCH[2]} - else - daemon="$2" - fi - - wanted_prio=$1 - daemon_list=${daemon:-$DAEMONS} - - echo "Stopping FRRouting daemons (prio:$wanted_prio):" - - for prio_i in `seq 10 -1 $wanted_prio`; do - for daemon_name in $daemon_list; do - eval daemon_prio=\${${daemon_name}:0:3} - daemon_inst="" - if [ $daemon_prio -eq $prio_i ]; then - eval "daemon_inst=\${${daemon_name}_instances//,/ }" - if [ -n "$daemon_inst" ]; then - for i in ${daemon_inst}; do - if [ -n "$inst" ] && [ "$i" == "$inst" ]; then - stop "$daemon_name" "$inst" - elif [ x"$inst" == x ]; then - stop "$daemon_name" "$i" - fi - done - else - stop "$daemon_name" - fi - fi - done - done - - if [ -z "$inst" ]; then - # Now stop other daemons that're prowling, coz the daemons file changed - echo "Stopping other FRRouting daemons" - if [ -n "$daemon" ]; then - eval "file_list_suffix="$V_PATH"/"$daemon*"" - else - eval "file_list_suffix="$V_PATH/*"" - fi - for pidfile in $file_list_suffix.pid; do - if [ -f "$pidfile" ]; then - filename=${pidfile##*/} - daemon=${filename%.*} - echo -n " $daemon" - killproc -p "$pidfile" "$daemon" - RETVAL=$? - [ $RETVAL -eq 0 ] && rm -f $lockfile - rm -f "$pidfile" - echo - fi - done - echo -n "Removing remaining .vty files" - for vtyfile in $file_list_suffix.vty; do - rm -rf "$vtyfile" - done - echo - fi -} - -# Starts all daemons that have a higher level of priority than the given. -# (technically if daemon_prio <= wanted_prio) -start_prio() -{ - local wanted_prio - local daemon_prio - local daemon_list - local daemon_name - local daemon_inst - local inst - - if [ -n "$2" ] && [[ "$2" =~ (.*)-(.*) ]]; then - daemon=${BASH_REMATCH[1]} - inst=${BASH_REMATCH[2]} - else - daemon="$2" - fi - - wanted_prio=$1 - daemon_list=${daemon:-$DAEMONS} - - echo "Starting FRRouting daemons (prio:$wanted_prio):" - - for prio_i in `seq 1 $wanted_prio`; do - for daemon_name in $daemon_list; do - eval daemon_prio=\$${daemon_name} - daemon_inst="" - if [ $daemon_prio -eq $prio_i ]; then - eval "daemon_inst=\${${daemon_name}_instances//,/ }" - if [ -n "$daemon_inst" ]; then - if [ `echo "$daemon_inst" | wc -w` -gt ${MAX_INSTANCES} ]; then - echo "Max instances supported is ${MAX_INSTANCES}. Aborting" - exit 1 - fi - # Check if we're starting again by switching from single instance - # to MI version - if started "$daemon_name"; then - PIDFILE=`pidfile $daemon_name` - killproc -p "$PIDFILE" "$daemon_name" - rm -f `pidfile $1` - rm -f `vtyfile $1` - fi - - for i in ${daemon_inst}; do - if [ -n "$inst" ] && [ "$i" == "$inst" ]; then - start "$daemon_name" "$inst" - elif [ x"$inst" == x ]; then - start "$daemon_name" "$i" - fi - done - else - # Check if we're starting again by switching from - # single instance to MI version - eval "file_list_suffix="$V_PATH"/"$daemon_name-*"" - for pidfile in $file_list_suffix.pid; do - if [ -f "$pidfile" ]; then - killproc -p "$pidfile" "$daemon_name" - rm -rf "$pidfile" - fi - done - for vtyfile in $file_list_suffix.vty; do - rm -rf "$vtyfile" - done - - start "$daemon_name" - fi - fi - done - done -} - -check_status() -{ - local daemon_name - local daemon_prio - local daemon_inst - local failed_status=0 - - if [ -n "$1" ] && [[ "$1" =~ (.*)-(.*) ]]; then - daemon=${BASH_REMATCH[1]} - inst=${BASH_REMATCH[2]} - else - daemon="$1" - fi - - daemon_list=${daemon:-$DAEMONS} - - # Which daemons have been started? - for daemon_name in $daemon_list; do - eval daemon_prio=\$$daemon_name - if [ "$daemon_prio" -gt 0 ]; then - eval "daemon_inst=\${${daemon_name}_instances//,/ }" - if [ -n "$daemon_inst" ]; then - for i in ${daemon_inst}; do - if [ -n "$inst" -a "$inst" = "$i" ]; then - started "$1" "log" || failed_status=$? - elif [ -z "$inst" ]; then - started "$daemon_name-$i" "log" || failed_status=$? - fi - done - else - started "$daemon_name" "log" || failed_status=$? - fi - fi - done - - # All daemons that need to have been started are up and running - return $failed_status -} - -######################################################### -# Main program # -######################################################### - -# Config broken but script must exit silently. -[ ! -r "$C_PATH/daemons" ] && exit 0 - -# Load configuration -. "$C_PATH/daemons" - -# Read configuration variable file if it is present -[ -r /etc/sysconfig/frr ] && . /etc/sysconfig/frr - -MAX_INSTANCES=${MAX_INSTANCES:=5} - -# Set priority of un-startable daemons to 'no' and substitute 'yes' to '0' -convert_daemon_prios - -if [ ! -d $V_PATH ]; then - echo "Creating $V_PATH" - mkdir -p $V_PATH - chown frr:frr $V_PATH - chmod 755 /$V_PATH -fi - -if [ -n "$3" ] && [ "$3" != "all" ]; then - dmn="$2"-"$3" -elif [ -n "$2" ] && [ "$2" != "all" ]; then - dmn="$2" -fi - -case "$1" in - start) - # Try to load this necessary (at least for 2.6) module. - if [ -d /lib/modules/`uname -r` ] ; then - echo "Loading capability module if not yet done." - LC_ALL=C modprobe -a capability 2>&1 | egrep -v "(not found|Can't locate)" - fi - - # Start all daemons - cd $C_PATH/ - if [ "$2" != "watchfrr" ]; then - start_prio 10 $dmn - fi - start_watchfrr - vtysh_b - ;; - - 1|2|3|4|5|6|7|8|9|10) - # Stop/start daemons for the appropriate priority level - stop_prio $1 - start_prio $1 - vtysh_b - ;; - - stop|0) - # Stop all daemons at level '0' or 'stop' - stop_watchfrr - if [ "$dmn" != "watchfrr" ]; then - [ -n "${dmn}" ] && eval "${dmn/-/_}=0" - stop_prio 0 $dmn - fi - - if [ -z "$dmn" -o "$dmn" = "zebra" ]; then - echo "Removing all routes made by zebra." - ip route flush proto zebra - # At least in CentOS/RHEL 6, iproute2 doesn't know - # about the new protocol names, so we have to flush them - # by number (it also doesn't support rt_protos.d - ip route flush proto 186 - ip route flush proto 187 - ip route flush proto 188 - ip route flush proto 189 - ip route flush proto 190 - ip route flush proto 191 - ip route flush proto 192 - ip route flush proto 193 - ip route flush proto 194 - else - [ -n "$dmn" ] && eval "${dmn/-/_}=0" - start_watchfrr - fi - ;; - - reload) - # Just apply the commands that have changed, no restart necessary - if [ ! -x "$RELOAD_SCRIPT" ]; then - echo "frr-reload - reload not supported. Use restart or install frr-pythontools package" - exit 1 - fi - NEW_CONFIG_FILE="${2:-$C_PATH/frr.conf}" - if [ ! -r $NEW_CONFIG_FILE ]; then - echo "Unable to read configuration file $NEW_CONFIG_FILE. Only supporting integrated config" - exit 1 - fi - echo "Applying only incremental changes to running configuration from frr.conf" - "$RELOAD_SCRIPT" --reload /etc/frr/frr.conf - exit $? - ;; - - status) - check_status $dmn - exit $? - ;; - - restart|force-reload) - $0 stop $dmn - sleep 1 - $0 start $dmn - ;; - - *) - echo "Usage: /etc/init.d/frr {start|stop|status|reload|restart|force-reload|<priority>} [daemon]" - echo " E.g. '/etc/init.d/frr 5' would start all daemons with a prio 1-5." - echo " reload applies only modifications from the running config to all daemons." - echo " reload neither restarts starts any daemon nor starts any new ones." - echo " Read /usr/share/doc/frr/README.Debian for details." - exit 1 - ;; -esac - -exit 0 diff --git a/redhat/frr.service b/redhat/frr.service deleted file mode 100644 index 01934a94e2..0000000000 --- a/redhat/frr.service +++ /dev/null @@ -1,24 +0,0 @@ -[Unit] -Description=FRRouting (FRR) -Wants=network.target -After=network-pre.target systemd-sysctl.service -Before=network.target -OnFailure=heartbeat-failed@%n.service - -[Service] -Nice=-5 -Type=forking -NotifyAccess=all -StartLimitInterval=3m -StartLimitBurst=3 -TimeoutSec=2m -WatchdogSec=60s -RestartSec=5 -Restart=on-abnormal -LimitNOFILE=1024 -ExecStart=/usr/lib/frr/frr start -ExecStop=/usr/lib/frr/frr stop -ExecReload=/usr/lib/frr/frr reload - -[Install] -WantedBy=multi-user.target diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in index 7a6344aa4c..36f9259865 100644 --- a/redhat/frr.spec.in +++ b/redhat/frr.spec.in @@ -162,7 +162,7 @@ BuildRequires: make BuildRequires: ncurses-devel BuildRequires: readline-devel BuildRequires: texinfo -BuildRequires: libyang >= 0.16.7 +BuildRequires: libyang-devel >= 0.16.74 %if 0%{?rhel} && 0%{?rhel} < 7 #python27-devel is available from ius community repo for RedHat/CentOS 6 BuildRequires: python27-devel @@ -171,6 +171,7 @@ BuildRequires: python27-sphinx BuildRequires: python-devel >= 2.7 BuildRequires: python-sphinx %endif +Requires: initscripts %if %{with_pam} BuildRequires: pam-devel %endif @@ -188,7 +189,6 @@ Requires(post): chkconfig Requires(preun): chkconfig # Initscripts > 5.60 is required for IPv6 support Requires(pre): initscripts >= 5.60 -Requires: initscripts %endif Provides: routingdaemon = %{version}-%{release} Obsoletes: gated mrt zebra frr-sysvinit @@ -376,15 +376,13 @@ rm -vf %{buildroot}%{_libdir}/frr/libyang_plugins/*.la # install /etc sources %if "%{initsystem}" == "systemd" mkdir -p %{buildroot}%{_unitdir} -install -m644 %{zeb_rh_src}/frr.service %{buildroot}%{_unitdir}/frr.service -install %{zeb_rh_src}/frr.init %{buildroot}%{_sbindir}/frr +install -m644 %{zeb_src}/tools/frr.service %{buildroot}%{_unitdir}/frr.service %else mkdir -p %{buildroot}%{_initddir} -install %{zeb_rh_src}/frr.init %{buildroot}%{_sbindir}/frr -ln -s %{_sbindir}/frr %{buildroot}%{_initddir}/frr +ln -s %{_sbindir}/frrinit.sh %{buildroot}%{_initddir}/frr %endif -install %{zeb_rh_src}/daemons %{buildroot}%{_sysconfdir}/frr +install %{zeb_src}/tools/etc/frr/daemons %{buildroot}%{_sysconfdir}/frr # add rpki module to daemon %if %{with_rpki} sed -i -e 's/^\(bgpd_options=\)\(.*\)\(".*\)/\1\2 -M rpki\3/' %{buildroot}%{_sysconfdir}/frr/daemons @@ -474,7 +472,7 @@ zebra_spec_add_service fabricd 2618/tcp "Fabricd vty" # Fix bad path in previous config files # Config files won't get replaced by default, so we do this ugly hack to fix it -%__sed -i 's|/etc/init.d/|%{_sbindir}/|g' %{configdir}/daemons 2> /dev/null || true +%__sed -i 's|watchfrr_options=|#watchfrr_options=|g' %{configdir}/daemons 2> /dev/null || true # With systemd, watchfrr is mandatory. Fix config to make sure it's enabled if # we install or upgrade to a frr built with systemd @@ -624,7 +622,6 @@ fi %{_libdir}/frr/modules/bgpd_rpki.so %endif %{_libdir}/frr/modules/zebra_irdp.so -%{_libdir}/frr/libyang_plugins/frr_user_types.so %{_bindir}/* %config(noreplace) %{configdir}/[!v]*.conf* %config(noreplace) %attr(750,%{frr_user},%{frr_user}) %{configdir}/daemons @@ -633,7 +630,6 @@ fi %else %{_initddir}/frr %endif -%{_sbindir}/frr %config(noreplace) %{_sysconfdir}/pam.d/frr %config(noreplace) %{_sysconfdir}/logrotate.d/frr %{_sbindir}/frr-reload diff --git a/ripd/rip_cli.c b/ripd/rip_cli.c index 5bb81ef157..62aaad5d97 100644 --- a/ripd/rip_cli.c +++ b/ripd/rip_cli.c @@ -62,7 +62,7 @@ DEFPY (no_router_rip, "Enable a routing process\n" "Routing Information Protocol (RIP)\n") { - nb_cli_enqueue_change(vty, "/frr-ripd:ripd/instance", NB_OP_DELETE, + nb_cli_enqueue_change(vty, "/frr-ripd:ripd/instance", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); @@ -213,9 +213,9 @@ DEFPY (rip_distance_source, nb_cli_enqueue_change(vty, "./distance", NB_OP_MODIFY, distance_str); nb_cli_enqueue_change(vty, "./access-list", - acl ? NB_OP_MODIFY : NB_OP_DELETE, acl); + acl ? NB_OP_MODIFY : NB_OP_DESTROY, acl); } else - nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, "./distance/source[prefix='%s']", prefix_str); @@ -244,7 +244,7 @@ DEFPY (rip_neighbor, "Neighbor address\n") { nb_cli_enqueue_change(vty, "./explicit-neighbor", - no ? NB_OP_DELETE : NB_OP_CREATE, neighbor_str); + no ? NB_OP_DESTROY : NB_OP_CREATE, neighbor_str); return nb_cli_apply_changes(vty, NULL); } @@ -266,7 +266,7 @@ DEFPY (rip_network_prefix, "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n") { nb_cli_enqueue_change(vty, "./network", - no ? NB_OP_DELETE : NB_OP_CREATE, network_str); + no ? NB_OP_DESTROY : NB_OP_CREATE, network_str); return nb_cli_apply_changes(vty, NULL); } @@ -288,7 +288,7 @@ DEFPY (rip_network_if, "Interface name\n") { nb_cli_enqueue_change(vty, "./interface", - no ? NB_OP_DELETE : NB_OP_CREATE, network); + no ? NB_OP_DESTROY : NB_OP_CREATE, network); return nb_cli_apply_changes(vty, NULL); } @@ -319,7 +319,7 @@ DEFPY (rip_offset_list, nb_cli_enqueue_change(vty, "./metric", NB_OP_MODIFY, metric_str); } else - nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); return nb_cli_apply_changes( vty, "./offset-list[interface='%s'][direction='%s']", @@ -378,10 +378,19 @@ DEFPY (rip_passive_interface, "Suppress routing updates on an interface\n" "Interface name\n") { - nb_cli_enqueue_change(vty, "./passive-interface", - no ? NB_OP_DELETE : NB_OP_CREATE, ifname); - nb_cli_enqueue_change(vty, "./non-passive-interface", - no ? NB_OP_CREATE : NB_OP_DELETE, ifname); + bool passive_default = + yang_dnode_get_bool(vty->candidate_config->dnode, "%s%s", + VTY_CURR_XPATH, "/passive-default"); + + if (passive_default) { + nb_cli_enqueue_change(vty, "./non-passive-interface", + no ? NB_OP_CREATE : NB_OP_DESTROY, + ifname); + } else { + nb_cli_enqueue_change(vty, "./passive-interface", + no ? NB_OP_DESTROY : NB_OP_CREATE, + ifname); + } return nb_cli_apply_changes(vty, NULL); } @@ -417,13 +426,13 @@ DEFPY (rip_redistribute, if (!no) { nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); nb_cli_enqueue_change(vty, "./route-map", - route_map ? NB_OP_MODIFY : NB_OP_DELETE, + route_map ? NB_OP_MODIFY : NB_OP_DESTROY, route_map); nb_cli_enqueue_change(vty, "./metric", - metric_str ? NB_OP_MODIFY : NB_OP_DELETE, + metric_str ? NB_OP_MODIFY : NB_OP_DESTROY, metric_str); } else - nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, "./redistribute[protocol='%s']", protocol); @@ -454,7 +463,7 @@ DEFPY (rip_route, "IP prefix <network>/<length>\n") { nb_cli_enqueue_change(vty, "./static-route", - no ? NB_OP_DELETE : NB_OP_CREATE, route_str); + no ? NB_OP_DESTROY : NB_OP_CREATE, route_str); return nb_cli_apply_changes(vty, NULL); } @@ -942,7 +951,7 @@ DEFPY (no_ip_rip_authentication_key_chain, "Authentication key-chain\n" "name of key-chain\n") { - nb_cli_enqueue_change(vty, "./authentication-key-chain", NB_OP_DELETE, + nb_cli_enqueue_change(vty, "./authentication-key-chain", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, "./frr-ripd:rip"); diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c index 9575f6b8a8..8bad6b8b14 100644 --- a/ripd/rip_interface.c +++ b/ripd/rip_interface.c @@ -510,11 +510,9 @@ static void rip_interface_reset(struct rip_interface *ri) ri->ri_receive = yang_get_default_enum("%s/version-receive", RIP_IFACE); ri->v2_broadcast = yang_get_default_bool("%s/v2-broadcast", RIP_IFACE); - if (ri->auth_str) - XFREE(MTYPE_RIP_INTERFACE_STRING, ri->auth_str); + XFREE(MTYPE_RIP_INTERFACE_STRING, ri->auth_str); - if (ri->key_chain) - XFREE(MTYPE_RIP_INTERFACE_STRING, ri->key_chain); + XFREE(MTYPE_RIP_INTERFACE_STRING, ri->key_chain); ri->list[RIP_FILTER_IN] = NULL; ri->list[RIP_FILTER_OUT] = NULL; diff --git a/ripd/rip_northbound.c b/ripd/rip_northbound.c index 4e445bd46d..f3b5dc2dc3 100644 --- a/ripd/rip_northbound.c +++ b/ripd/rip_northbound.c @@ -937,8 +937,7 @@ lib_interface_rip_authentication_password_modify(enum nb_event event, ifp = yang_dnode_get_entry(dnode, true); ri = ifp->info; - if (ri->auth_str) - XFREE(MTYPE_RIP_INTERFACE_STRING, ri->auth_str); + XFREE(MTYPE_RIP_INTERFACE_STRING, ri->auth_str); ri->auth_str = XSTRDUP(MTYPE_RIP_INTERFACE_STRING, yang_dnode_get_string(dnode, NULL)); @@ -978,8 +977,7 @@ lib_interface_rip_authentication_key_chain_modify(enum nb_event event, ifp = yang_dnode_get_entry(dnode, true); ri = ifp->info; - if (ri->key_chain) - XFREE(MTYPE_RIP_INTERFACE_STRING, ri->key_chain); + XFREE(MTYPE_RIP_INTERFACE_STRING, ri->key_chain); ri->key_chain = XSTRDUP(MTYPE_RIP_INTERFACE_STRING, yang_dnode_get_string(dnode, NULL)); @@ -1305,7 +1303,7 @@ const struct frr_yang_module_info frr_ripd_info = { { .xpath = "/frr-ripd:ripd/instance", .cbs.create = ripd_instance_create, - .cbs.delete = ripd_instance_delete, + .cbs.destroy = ripd_instance_delete, .cbs.cli_show = cli_show_router_rip, }, { @@ -1331,7 +1329,7 @@ const struct frr_yang_module_info frr_ripd_info = { { .xpath = "/frr-ripd:ripd/instance/distance/source", .cbs.create = ripd_instance_distance_source_create, - .cbs.delete = ripd_instance_distance_source_delete, + .cbs.destroy = ripd_instance_distance_source_delete, .cbs.cli_show = cli_show_rip_distance_source, }, { @@ -1341,30 +1339,30 @@ const struct frr_yang_module_info frr_ripd_info = { { .xpath = "/frr-ripd:ripd/instance/distance/source/access-list", .cbs.modify = ripd_instance_distance_source_access_list_modify, - .cbs.delete = ripd_instance_distance_source_access_list_delete, + .cbs.destroy = ripd_instance_distance_source_access_list_delete, }, { .xpath = "/frr-ripd:ripd/instance/explicit-neighbor", .cbs.create = ripd_instance_explicit_neighbor_create, - .cbs.delete = ripd_instance_explicit_neighbor_delete, + .cbs.destroy = ripd_instance_explicit_neighbor_delete, .cbs.cli_show = cli_show_rip_neighbor, }, { .xpath = "/frr-ripd:ripd/instance/network", .cbs.create = ripd_instance_network_create, - .cbs.delete = ripd_instance_network_delete, + .cbs.destroy = ripd_instance_network_delete, .cbs.cli_show = cli_show_rip_network_prefix, }, { .xpath = "/frr-ripd:ripd/instance/interface", .cbs.create = ripd_instance_interface_create, - .cbs.delete = ripd_instance_interface_delete, + .cbs.destroy = ripd_instance_interface_delete, .cbs.cli_show = cli_show_rip_network_interface, }, { .xpath = "/frr-ripd:ripd/instance/offset-list", .cbs.create = ripd_instance_offset_list_create, - .cbs.delete = ripd_instance_offset_list_delete, + .cbs.destroy = ripd_instance_offset_list_delete, .cbs.cli_show = cli_show_rip_offset_list, }, { @@ -1383,36 +1381,36 @@ const struct frr_yang_module_info frr_ripd_info = { { .xpath = "/frr-ripd:ripd/instance/passive-interface", .cbs.create = ripd_instance_passive_interface_create, - .cbs.delete = ripd_instance_passive_interface_delete, + .cbs.destroy = ripd_instance_passive_interface_delete, .cbs.cli_show = cli_show_rip_passive_interface, }, { .xpath = "/frr-ripd:ripd/instance/non-passive-interface", .cbs.create = ripd_instance_non_passive_interface_create, - .cbs.delete = ripd_instance_non_passive_interface_delete, + .cbs.destroy = ripd_instance_non_passive_interface_delete, .cbs.cli_show = cli_show_rip_non_passive_interface, }, { .xpath = "/frr-ripd:ripd/instance/redistribute", .cbs.create = ripd_instance_redistribute_create, - .cbs.delete = ripd_instance_redistribute_delete, + .cbs.destroy = ripd_instance_redistribute_delete, .cbs.apply_finish = ripd_instance_redistribute_apply_finish, .cbs.cli_show = cli_show_rip_redistribute, }, { .xpath = "/frr-ripd:ripd/instance/redistribute/route-map", .cbs.modify = ripd_instance_redistribute_route_map_modify, - .cbs.delete = ripd_instance_redistribute_route_map_delete, + .cbs.destroy = ripd_instance_redistribute_route_map_delete, }, { .xpath = "/frr-ripd:ripd/instance/redistribute/metric", .cbs.modify = ripd_instance_redistribute_metric_modify, - .cbs.delete = ripd_instance_redistribute_metric_delete, + .cbs.destroy = ripd_instance_redistribute_metric_delete, }, { .xpath = "/frr-ripd:ripd/instance/static-route", .cbs.create = ripd_instance_static_route_create, - .cbs.delete = ripd_instance_static_route_delete, + .cbs.destroy = ripd_instance_static_route_delete, .cbs.cli_show = cli_show_rip_route, }, { @@ -1475,18 +1473,18 @@ const struct frr_yang_module_info frr_ripd_info = { { .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-scheme/md5-auth-length", .cbs.modify = lib_interface_rip_authentication_scheme_md5_auth_length_modify, - .cbs.delete = lib_interface_rip_authentication_scheme_md5_auth_length_delete, + .cbs.destroy = lib_interface_rip_authentication_scheme_md5_auth_length_delete, }, { .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-password", .cbs.modify = lib_interface_rip_authentication_password_modify, - .cbs.delete = lib_interface_rip_authentication_password_delete, + .cbs.destroy = lib_interface_rip_authentication_password_delete, .cbs.cli_show = cli_show_ip_rip_authentication_string, }, { .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-key-chain", .cbs.modify = lib_interface_rip_authentication_key_chain_modify, - .cbs.delete = lib_interface_rip_authentication_key_chain_delete, + .cbs.destroy = lib_interface_rip_authentication_key_chain_delete, .cbs.cli_show = cli_show_ip_rip_authentication_key_chain, }, { diff --git a/ripd/ripd.c b/ripd/ripd.c index 38b4aed5bc..d2fc9eb303 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -71,6 +71,9 @@ static int rip_update_jitter(unsigned long); static void rip_distribute_update(struct distribute_ctx *ctx, struct distribute *dist); +static void rip_if_rmap_update(struct if_rmap_ctx *ctx, + struct if_rmap *if_rmap); + /* RIP output routes type. */ enum { rip_all_route, rip_changed_route }; @@ -851,7 +854,7 @@ static int rip_auth_md5(struct rip_packet *packet, struct sockaddr_in *from, MD5_CTX ctx; uint8_t digest[RIP_AUTH_MD5_SIZE]; uint16_t packet_len; - char auth_str[RIP_AUTH_MD5_SIZE]; + char auth_str[RIP_AUTH_MD5_SIZE] = {}; if (IS_RIP_DEBUG_EVENT) zlog_debug("RIPv2 MD5 authentication from %s", @@ -895,8 +898,6 @@ static int rip_auth_md5(struct rip_packet *packet, struct sockaddr_in *from, /* retrieve authentication data */ md5data = (struct rip_md5_data *)(((uint8_t *)packet) + packet_len); - memset(auth_str, 0, RIP_AUTH_MD5_SIZE); - if (ri->key_chain) { keychain = keychain_lookup(ri->key_chain); if (keychain == NULL) @@ -906,9 +907,9 @@ static int rip_auth_md5(struct rip_packet *packet, struct sockaddr_in *from, if (key == NULL || key->string == NULL) return 0; - strncpy(auth_str, key->string, RIP_AUTH_MD5_SIZE); + strlcpy(auth_str, key->string, sizeof(auth_str)); } else if (ri->auth_str) - strncpy(auth_str, ri->auth_str, RIP_AUTH_MD5_SIZE); + strlcpy(auth_str, ri->auth_str, sizeof(auth_str)); if (auth_str[0] == 0) return 0; @@ -941,9 +942,9 @@ static void rip_auth_prepare_str_send(struct rip_interface *ri, struct key *key, memset(auth_str, 0, len); if (key && key->string) - strncpy(auth_str, key->string, len); + strlcpy(auth_str, key->string, len); else if (ri->auth_str) - strncpy(auth_str, ri->auth_str, len); + strlcpy(auth_str, ri->auth_str, len); return; } @@ -1389,13 +1390,12 @@ static int rip_send_packet(uint8_t *buf, int size, struct sockaddr_in *to, if (IS_RIP_DEBUG_PACKET) { #define ADDRESS_SIZE 20 char dst[ADDRESS_SIZE]; - dst[ADDRESS_SIZE - 1] = '\0'; if (to) { - strncpy(dst, inet_ntoa(to->sin_addr), ADDRESS_SIZE - 1); + strlcpy(dst, inet_ntoa(to->sin_addr), sizeof(dst)); } else { sin.sin_addr.s_addr = htonl(INADDR_RIP_GROUP); - strncpy(dst, inet_ntoa(sin.sin_addr), ADDRESS_SIZE - 1); + strlcpy(dst, inet_ntoa(sin.sin_addr), sizeof(dst)); } #undef ADDRESS_SIZE zlog_debug("rip_send_packet %s > %s (%s)", @@ -2100,8 +2100,7 @@ void rip_output_process(struct connected *ifc, struct sockaddr_in *to, key = key_lookup_for_send(keychain); } /* to be passed to auth functions later */ - rip_auth_prepare_str_send(ri, key, auth_str, - RIP_AUTH_SIMPLE_SIZE); + rip_auth_prepare_str_send(ri, key, auth_str, sizeof(auth_str)); if (strlen(auth_str) == 0) return; } @@ -2712,6 +2711,12 @@ int rip_create(int socket) rip_distribute_update); distribute_list_delete_hook(rip->distribute_ctx, rip_distribute_update); + + /* if rmap install. */ + rip->if_rmap_ctx = if_rmap_ctx_create(VRF_DEFAULT_NAME); + if_rmap_hook_add(rip->if_rmap_ctx, rip_if_rmap_update); + if_rmap_hook_delete(rip->if_rmap_ctx, rip_if_rmap_update); + return 0; } @@ -3228,7 +3233,7 @@ static int config_write_rip(struct vty *vty) rip->distribute_ctx); /* Interface routemap configuration */ - write += config_write_if_rmap(vty); + write += config_write_if_rmap(vty, rip->if_rmap_ctx); } return write; } @@ -3381,25 +3386,33 @@ void rip_clean(void) route_table_finish(rip->neighbor); distribute_list_delete(&rip->distribute_ctx); + + if_rmap_ctx_delete(rip->if_rmap_ctx); + XFREE(MTYPE_RIP, rip); rip = NULL; } - rip_clean_network(); rip_passive_nondefault_clean(); rip_offset_clean(); rip_interfaces_clean(); rip_distance_reset(); rip_redistribute_clean(); + if_rmap_terminate(); } -static void rip_if_rmap_update(struct if_rmap *if_rmap) +static void rip_if_rmap_update(struct if_rmap_ctx *ctx, + struct if_rmap *if_rmap) { - struct interface *ifp; + struct interface *ifp = NULL; struct rip_interface *ri; struct route_map *rmap; + struct vrf *vrf = NULL; - ifp = if_lookup_by_name(if_rmap->ifname, VRF_DEFAULT); + if (ctx->name) + vrf = vrf_lookup_by_name(ctx->name); + if (vrf) + ifp = if_lookup_by_name(if_rmap->ifname, vrf->vrf_id); if (ifp == NULL) return; @@ -3426,10 +3439,18 @@ static void rip_if_rmap_update(struct if_rmap *if_rmap) void rip_if_rmap_update_interface(struct interface *ifp) { struct if_rmap *if_rmap; + struct if_rmap_ctx *ctx; - if_rmap = if_rmap_lookup(ifp->name); + if (!rip) + return; + if (ifp->vrf_id != VRF_DEFAULT) + return; + ctx = rip->if_rmap_ctx; + if (!ctx) + return; + if_rmap = if_rmap_lookup(ctx, ifp->name); if (if_rmap) - rip_if_rmap_update(if_rmap); + rip_if_rmap_update(ctx, if_rmap); } static void rip_routemap_update_redistribute(void) @@ -3497,8 +3518,6 @@ void rip_init(void) route_map_delete_hook(rip_routemap_update); if_rmap_init(RIP_NODE); - if_rmap_hook_add(rip_if_rmap_update); - if_rmap_hook_delete(rip_if_rmap_update); /* Distance control. */ rip_distance_table = route_table_init(); diff --git a/ripd/ripd.h b/ripd/ripd.h index 7b8fe3a906..383df3707b 100644 --- a/ripd/ripd.h +++ b/ripd/ripd.h @@ -154,6 +154,9 @@ struct rip { /* For distribute-list container */ struct distribute_ctx *distribute_ctx; + + /* For if_rmap container */ + struct if_rmap_ctx *if_rmap_ctx; }; /* RIP routing table entry which belong to rip_packet. */ @@ -419,8 +422,7 @@ extern void rip_zebra_ipv4_add(struct route_node *); extern void rip_zebra_ipv4_delete(struct route_node *); extern void rip_interface_multicast_set(int, struct connected *); extern void rip_distribute_update_interface(struct interface *); -extern void rip_if_rmap_update_interface(struct interface *); - +extern void rip_if_rmap_update_interface(struct interface *ifp); extern int rip_show_network_config(struct vty *); extern void rip_show_redistribute_config(struct vty *); diff --git a/ripngd/ripng_cli.c b/ripngd/ripng_cli.c index a187e80fd7..23a4803170 100644 --- a/ripngd/ripng_cli.c +++ b/ripngd/ripng_cli.c @@ -62,7 +62,7 @@ DEFPY (no_router_ripng, "Enable a routing process\n" "Make RIPng instance command\n") { - nb_cli_enqueue_change(vty, "/frr-ripngd:ripngd/instance", NB_OP_DELETE, + nb_cli_enqueue_change(vty, "/frr-ripngd:ripngd/instance", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); @@ -170,7 +170,7 @@ DEFPY (ripng_network_prefix, "IPv6 network\n") { nb_cli_enqueue_change(vty, "./network", - no ? NB_OP_DELETE : NB_OP_CREATE, network_str); + no ? NB_OP_DESTROY : NB_OP_CREATE, network_str); return nb_cli_apply_changes(vty, NULL); } @@ -192,7 +192,7 @@ DEFPY (ripng_network_if, "Interface name\n") { nb_cli_enqueue_change(vty, "./interface", - no ? NB_OP_DELETE : NB_OP_CREATE, network); + no ? NB_OP_DESTROY : NB_OP_CREATE, network); return nb_cli_apply_changes(vty, NULL); } @@ -223,7 +223,7 @@ DEFPY (ripng_offset_list, nb_cli_enqueue_change(vty, "./metric", NB_OP_MODIFY, metric_str); } else - nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); return nb_cli_apply_changes( vty, "./offset-list[interface='%s'][direction='%s']", @@ -257,7 +257,7 @@ DEFPY (ripng_passive_interface, "Interface name\n") { nb_cli_enqueue_change(vty, "./passive-interface", - no ? NB_OP_DELETE : NB_OP_CREATE, ifname); + no ? NB_OP_DESTROY : NB_OP_CREATE, ifname); return nb_cli_apply_changes(vty, NULL); } @@ -286,13 +286,13 @@ DEFPY (ripng_redistribute, if (!no) { nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); nb_cli_enqueue_change(vty, "./route-map", - route_map ? NB_OP_MODIFY : NB_OP_DELETE, + route_map ? NB_OP_MODIFY : NB_OP_DESTROY, route_map); nb_cli_enqueue_change(vty, "./metric", - metric_str ? NB_OP_MODIFY : NB_OP_DELETE, + metric_str ? NB_OP_MODIFY : NB_OP_DESTROY, metric_str); } else - nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, "./redistribute[protocol='%s']", protocol); @@ -323,7 +323,7 @@ DEFPY (ripng_route, "Set static RIPng route announcement\n") { nb_cli_enqueue_change(vty, "./static-route", - no ? NB_OP_DELETE : NB_OP_CREATE, route_str); + no ? NB_OP_DESTROY : NB_OP_CREATE, route_str); return nb_cli_apply_changes(vty, NULL); } @@ -345,7 +345,7 @@ DEFPY (ripng_aggregate_address, "Aggregate network\n") { nb_cli_enqueue_change(vty, "./aggregate-address", - no ? NB_OP_DELETE : NB_OP_CREATE, + no ? NB_OP_DESTROY : NB_OP_CREATE, aggregate_address_str); return nb_cli_apply_changes(vty, NULL); diff --git a/ripngd/ripng_interface.c b/ripngd/ripng_interface.c index e5dc6e6af6..ea32b622a6 100644 --- a/ripngd/ripng_interface.c +++ b/ripngd/ripng_interface.c @@ -90,7 +90,7 @@ static int ripng_multicast_join(struct interface *ifp) * group on * an interface that has just gone down. */ - zlog_warn("ripng join on %s EADDRINUSE (ignoring)\n", + zlog_warn("ripng join on %s EADDRINUSE (ignoring)", ifp->name); return 0; /* not an error */ } @@ -124,7 +124,7 @@ static int ripng_multicast_leave(struct interface *ifp) ret = setsockopt(ripng->sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, (char *)&mreq, sizeof(mreq)); if (ret < 0) - zlog_warn("can't setsockopt IPV6_LEAVE_GROUP: %s\n", + zlog_warn("can't setsockopt IPV6_LEAVE_GROUP: %s", safe_strerror(errno)); if (IS_RIPNG_DEBUG_EVENT) diff --git a/ripngd/ripng_northbound.c b/ripngd/ripng_northbound.c index 7993714e8d..b6998b4ddb 100644 --- a/ripngd/ripng_northbound.c +++ b/ripngd/ripng_northbound.c @@ -845,7 +845,7 @@ const struct frr_yang_module_info frr_ripngd_info = { { .xpath = "/frr-ripngd:ripngd/instance", .cbs.create = ripngd_instance_create, - .cbs.delete = ripngd_instance_delete, + .cbs.destroy = ripngd_instance_delete, .cbs.cli_show = cli_show_router_ripng, }, { @@ -866,19 +866,19 @@ const struct frr_yang_module_info frr_ripngd_info = { { .xpath = "/frr-ripngd:ripngd/instance/network", .cbs.create = ripngd_instance_network_create, - .cbs.delete = ripngd_instance_network_delete, + .cbs.destroy = ripngd_instance_network_delete, .cbs.cli_show = cli_show_ripng_network_prefix, }, { .xpath = "/frr-ripngd:ripngd/instance/interface", .cbs.create = ripngd_instance_interface_create, - .cbs.delete = ripngd_instance_interface_delete, + .cbs.destroy = ripngd_instance_interface_delete, .cbs.cli_show = cli_show_ripng_network_interface, }, { .xpath = "/frr-ripngd:ripngd/instance/offset-list", .cbs.create = ripngd_instance_offset_list_create, - .cbs.delete = ripngd_instance_offset_list_delete, + .cbs.destroy = ripngd_instance_offset_list_delete, .cbs.cli_show = cli_show_ripng_offset_list, }, { @@ -892,36 +892,36 @@ const struct frr_yang_module_info frr_ripngd_info = { { .xpath = "/frr-ripngd:ripngd/instance/passive-interface", .cbs.create = ripngd_instance_passive_interface_create, - .cbs.delete = ripngd_instance_passive_interface_delete, + .cbs.destroy = ripngd_instance_passive_interface_delete, .cbs.cli_show = cli_show_ripng_passive_interface, }, { .xpath = "/frr-ripngd:ripngd/instance/redistribute", .cbs.create = ripngd_instance_redistribute_create, - .cbs.delete = ripngd_instance_redistribute_delete, + .cbs.destroy = ripngd_instance_redistribute_delete, .cbs.apply_finish = ripngd_instance_redistribute_apply_finish, .cbs.cli_show = cli_show_ripng_redistribute, }, { .xpath = "/frr-ripngd:ripngd/instance/redistribute/route-map", .cbs.modify = ripngd_instance_redistribute_route_map_modify, - .cbs.delete = ripngd_instance_redistribute_route_map_delete, + .cbs.destroy = ripngd_instance_redistribute_route_map_delete, }, { .xpath = "/frr-ripngd:ripngd/instance/redistribute/metric", .cbs.modify = ripngd_instance_redistribute_metric_modify, - .cbs.delete = ripngd_instance_redistribute_metric_delete, + .cbs.destroy = ripngd_instance_redistribute_metric_delete, }, { .xpath = "/frr-ripngd:ripngd/instance/static-route", .cbs.create = ripngd_instance_static_route_create, - .cbs.delete = ripngd_instance_static_route_delete, + .cbs.destroy = ripngd_instance_static_route_delete, .cbs.cli_show = cli_show_ripng_route, }, { .xpath = "/frr-ripngd:ripngd/instance/aggregate-address", .cbs.create = ripngd_instance_aggregate_address_create, - .cbs.delete = ripngd_instance_aggregate_address_delete, + .cbs.destroy = ripngd_instance_aggregate_address_delete, .cbs.cli_show = cli_show_ripng_aggregate_address, }, { diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index 70655beff1..9faebcf0d0 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -60,6 +60,9 @@ void ripng_output_process(struct interface *, struct sockaddr_in6 *, int); int ripng_triggered_update(struct thread *); +static void ripng_if_rmap_update(struct if_rmap_ctx *ctx, + struct if_rmap *if_rmap); + /* RIPng next hop specification. */ struct ripng_nexthop { enum ripng_nexthop_type { @@ -1816,6 +1819,12 @@ int ripng_create(int socket) ripng_distribute_update); distribute_list_delete_hook(ripng->distribute_ctx, ripng_distribute_update); + + /* if rmap install. */ + ripng->if_rmap_ctx = if_rmap_ctx_create(VRF_DEFAULT_NAME); + if_rmap_hook_add(ripng->if_rmap_ctx, ripng_if_rmap_update); + if_rmap_hook_delete(ripng->if_rmap_ctx, ripng_if_rmap_update); + /* Make socket. */ ripng->sock = socket; @@ -2303,7 +2312,7 @@ static int ripng_config_write(struct vty *vty) config_write_distribute(vty, ripng->distribute_ctx); - config_write_if_rmap(vty); + config_write_if_rmap(vty, ripng->if_rmap_ctx); write = 1; } @@ -2474,15 +2483,21 @@ void ripng_clean(void) ripng_offset_clean(); ripng_interface_clean(); ripng_redistribute_clean(); + if_rmap_terminate(); } -static void ripng_if_rmap_update(struct if_rmap *if_rmap) +static void ripng_if_rmap_update(struct if_rmap_ctx *ctx, + struct if_rmap *if_rmap) { - struct interface *ifp; + struct interface *ifp = NULL; struct ripng_interface *ri; struct route_map *rmap; + struct vrf *vrf = NULL; - ifp = if_lookup_by_name(if_rmap->ifname, VRF_DEFAULT); + if (ctx->name) + vrf = vrf_lookup_by_name(ctx->name); + if (vrf) + ifp = if_lookup_by_name(if_rmap->ifname, vrf->vrf_id); if (ifp == NULL) return; @@ -2510,10 +2525,18 @@ static void ripng_if_rmap_update(struct if_rmap *if_rmap) void ripng_if_rmap_update_interface(struct interface *ifp) { struct if_rmap *if_rmap; + struct if_rmap_ctx *ctx; - if_rmap = if_rmap_lookup(ifp->name); + if (ifp->vrf_id != VRF_DEFAULT) + return; + if (!ripng) + return; + ctx = ripng->if_rmap_ctx; + if (!ctx) + return; + if_rmap = if_rmap_lookup(ctx, ifp->name); if (if_rmap) - ripng_if_rmap_update(if_rmap); + ripng_if_rmap_update(ctx, if_rmap); } static void ripng_routemap_update_redistribute(void) @@ -2590,6 +2613,4 @@ void ripng_init(void) route_map_delete_hook(ripng_routemap_update); if_rmap_init(RIPNG_NODE); - if_rmap_hook_add(ripng_if_rmap_update); - if_rmap_hook_delete(ripng_if_rmap_update); } diff --git a/ripngd/ripngd.h b/ripngd/ripngd.h index 1db7a83b11..3f0ef13a05 100644 --- a/ripngd/ripngd.h +++ b/ripngd/ripngd.h @@ -132,6 +132,9 @@ struct ripng { /* For distribute-list container */ struct distribute_ctx *distribute_ctx; + + /* For if_rmap container */ + struct if_rmap_ctx *if_rmap_ctx; }; /* Routing table entry. */ diff --git a/sharpd/Makefile b/sharpd/Makefile new file mode 100644 index 0000000000..6a904d1a6d --- /dev/null +++ b/sharpd/Makefile @@ -0,0 +1,10 @@ +all: ALWAYS + @$(MAKE) -s -C .. sharpd/sharpd +%: ALWAYS + @$(MAKE) -s -C .. sharpd/$@ + +Makefile: + #nothing +ALWAYS: +.PHONY: ALWAYS makefiles +.SUFFIXES: diff --git a/sharpd/sharp_globals.h b/sharpd/sharp_globals.h index 065fb092d4..4e5c933667 100644 --- a/sharpd/sharp_globals.h +++ b/sharpd/sharp_globals.h @@ -38,6 +38,7 @@ struct sharp_routes { int32_t repeat; uint8_t inst; + vrf_id_t vrf_id; struct timeval t_start; struct timeval t_end; diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index 0c02bd304d..fbcbbe3fdc 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -39,14 +39,33 @@ #endif DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd, - "sharp watch nexthop X:X::X:X$nhop [connected$connected]", + "sharp watch [vrf NAME$name] <nexthop$n|import$import> X:X::X:X$nhop [connected$connected]", "Sharp routing Protocol\n" "Watch for changes\n" + "The vrf we would like to watch if non-default\n" + "The NAME of the vrf\n" "Watch for nexthop changes\n" + "Watch for import check changes\n" "The v6 nexthop to signal for watching\n" "Should the route be connected\n") { + struct vrf *vrf; struct prefix p; + bool type_import; + + if (!name) + name = VRF_DEFAULT_NAME; + vrf = vrf_lookup_by_name(name); + if (!vrf) { + vty_out(vty, "The vrf NAME specified: %s does not exist\n", + name); + return CMD_WARNING; + } + + if (n) + type_import = false; + else + type_import = true; memset(&p, 0, sizeof(p)); @@ -55,29 +74,50 @@ DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd, p.family = AF_INET6; sharp_nh_tracker_get(&p); - sharp_zebra_nexthop_watch(&p, true, !!connected); + sharp_zebra_nexthop_watch(&p, vrf->vrf_id, type_import, + true, !!connected); return CMD_SUCCESS; } DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd, - "sharp watch nexthop A.B.C.D$nhop [connected$connected]", + "sharp watch [vrf NAME$name] <nexthop$n|import$import> A.B.C.D$nhop [connected$connected]", "Sharp routing Protocol\n" "Watch for changes\n" + "The vrf we would like to watch if non-default\n" + "The NAME of the vrf\n" "Watch for nexthop changes\n" + "Watch for import check changes\n" "The v4 nexthop to signal for watching\n" "Should the route be connected\n") { + struct vrf *vrf; struct prefix p; + bool type_import; + + if (!name) + name = VRF_DEFAULT_NAME; + vrf = vrf_lookup_by_name(name); + if (!vrf) { + vty_out(vty, "The vrf NAME specified: %s does not exist\n", + name); + return CMD_WARNING; + } memset(&p, 0, sizeof(p)); + if (n) + type_import = false; + else + type_import = true; + p.prefixlen = 32; p.u.prefix4 = nhop; p.family = AF_INET; sharp_nh_tracker_get(&p); - sharp_zebra_nexthop_watch(&p, true, !!connected); + sharp_zebra_nexthop_watch(&p, vrf->vrf_id, type_import, + true, !!connected); return CMD_SUCCESS; } @@ -117,10 +157,12 @@ DEFPY (install_routes_data_dump, DEFPY (install_routes, install_routes_cmd, - "sharp install routes <A.B.C.D$start4|X:X::X:X$start6> <nexthop <A.B.C.D$nexthop4|X:X::X:X$nexthop6>|nexthop-group NAME$nexthop_group> (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt]", + "sharp install routes [vrf NAME$name] <A.B.C.D$start4|X:X::X:X$start6> <nexthop <A.B.C.D$nexthop4|X:X::X:X$nexthop6>|nexthop-group NAME$nexthop_group> (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt]", "Sharp routing Protocol\n" "install some routes\n" "Routes to install\n" + "The vrf we would like to install into if non-default\n" + "The NAME of the vrf\n" "v4 Address to start /32 generation at\n" "v6 Address to start /32 generation at\n" "Nexthop to use(Can be an IPv4 or IPv6 address)\n" @@ -134,6 +176,7 @@ DEFPY (install_routes, "Should we repeat this command\n" "How many times to repeat this command\n") { + struct vrf *vrf; struct prefix prefix; uint32_t rts; @@ -161,6 +204,16 @@ DEFPY (install_routes, } sg.r.orig_prefix = prefix; + if (!name) + name = VRF_DEFAULT_NAME; + + vrf = vrf_lookup_by_name(name); + if (!vrf) { + vty_out(vty, "The vrf NAME specified: %s does not exist\n", + name); + return CMD_WARNING; + } + if (nexthop_group) { struct nexthop_group_cmd *nhgc = nhgc_find(nexthop_group); if (!nhgc) { @@ -180,12 +233,15 @@ DEFPY (install_routes, sg.r.nhop.type = NEXTHOP_TYPE_IPV6; } + sg.r.nhop.vrf_id = vrf->vrf_id; sg.r.nhop_group.nexthop = &sg.r.nhop; } sg.r.inst = instance; + sg.r.vrf_id = vrf->vrf_id; rts = routes; - sharp_install_routes_helper(&prefix, sg.r.inst, &sg.r.nhop_group, rts); + sharp_install_routes_helper(&prefix, sg.r.vrf_id, + sg.r.inst, &sg.r.nhop_group, rts); return CMD_SUCCESS; } @@ -222,16 +278,19 @@ DEFPY(vrf_label, vrf_label_cmd, DEFPY (remove_routes, remove_routes_cmd, - "sharp remove routes <A.B.C.D$start4|X:X::X:X$start6> (1-1000000)$routes [instance (0-255)$instance]", + "sharp remove routes [vrf NAME$name] <A.B.C.D$start4|X:X::X:X$start6> (1-1000000)$routes [instance (0-255)$instance]", "Sharp Routing Protocol\n" "Remove some routes\n" "Routes to remove\n" + "The vrf we would like to remove from if non-default\n" + "The NAME of the vrf\n" "v4 Starting spot\n" "v6 Starting spot\n" "Routes to uninstall\n" "instance to use\n" "Value of instance\n") { + struct vrf *vrf; struct prefix prefix; sg.r.total_routes = routes; @@ -250,9 +309,18 @@ DEFPY (remove_routes, prefix.u.prefix6 = start6; } + vrf = vrf_lookup_by_name(name ? name : VRF_DEFAULT_NAME); + if (!vrf) { + vty_out(vty, "The vrf NAME specified: %s does not exist\n", + name ? name : VRF_DEFAULT_NAME); + return CMD_WARNING; + } + sg.r.inst = instance; + sg.r.vrf_id = vrf->vrf_id; rts = routes; - sharp_remove_routes_helper(&prefix, sg.r.inst, rts); + sharp_remove_routes_helper(&prefix, sg.r.vrf_id, + sg.r.inst, rts); return CMD_SUCCESS; } diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index 30e616a057..f1e83628c2 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -131,8 +131,8 @@ static int interface_state_down(int command, struct zclient *zclient, return 0; } -void sharp_install_routes_helper(struct prefix *p, uint8_t instance, - struct nexthop_group *nhg, +void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id, + uint8_t instance, struct nexthop_group *nhg, uint32_t routes) { uint32_t temp, i; @@ -148,7 +148,7 @@ void sharp_install_routes_helper(struct prefix *p, uint8_t instance, monotime(&sg.r.t_start); for (i = 0; i < routes; i++) { - route_add(p, (uint8_t)instance, nhg); + route_add(p, vrf_id, (uint8_t)instance, nhg); if (v4) p->u.prefix4.s_addr = htonl(++temp); else @@ -156,8 +156,8 @@ void sharp_install_routes_helper(struct prefix *p, uint8_t instance, } } -void sharp_remove_routes_helper(struct prefix *p, uint8_t instance, - uint32_t routes) +void sharp_remove_routes_helper(struct prefix *p, vrf_id_t vrf_id, + uint8_t instance, uint32_t routes) { uint32_t temp, i; bool v4 = false; @@ -172,7 +172,7 @@ void sharp_remove_routes_helper(struct prefix *p, uint8_t instance, monotime(&sg.r.t_start); for (i = 0; i < routes; i++) { - route_delete(p, (uint8_t)instance); + route_delete(p, vrf_id, (uint8_t)instance); if (v4) p->u.prefix4.s_addr = htonl(++temp); else @@ -190,12 +190,14 @@ static void handle_repeated(bool installed) if (installed) { sg.r.removed_routes = 0; - sharp_remove_routes_helper(&p, sg.r.inst, sg.r.total_routes); + sharp_remove_routes_helper(&p, sg.r.vrf_id, + sg.r.inst, sg.r.total_routes); } if (installed) { sg.r.installed_routes = 0; - sharp_install_routes_helper(&p, sg.r.inst, &sg.r.nhop_group, + sharp_install_routes_helper(&p, sg.r.vrf_id, sg.r.inst, + &sg.r.nhop_group, sg.r.total_routes); } } @@ -255,7 +257,8 @@ void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label) zclient_send_vrf_label(zclient, vrf_id, afi, label, ZEBRA_LSP_SHARP); } -void route_add(struct prefix *p, uint8_t instance, struct nexthop_group *nhg) +void route_add(struct prefix *p, vrf_id_t vrf_id, + uint8_t instance, struct nexthop_group *nhg) { struct zapi_route api; struct zapi_nexthop *api_nh; @@ -263,7 +266,7 @@ void route_add(struct prefix *p, uint8_t instance, struct nexthop_group *nhg) int i = 0; memset(&api, 0, sizeof(api)); - api.vrf_id = VRF_DEFAULT; + api.vrf_id = vrf_id; api.type = ZEBRA_ROUTE_SHARP; api.instance = instance; api.safi = SAFI_UNICAST; @@ -274,7 +277,7 @@ void route_add(struct prefix *p, uint8_t instance, struct nexthop_group *nhg) for (ALL_NEXTHOPS_PTR(nhg, nh)) { api_nh = &api.nexthops[i]; - api_nh->vrf_id = VRF_DEFAULT; + api_nh->vrf_id = nh->vrf_id; api_nh->type = nh->type; switch (nh->type) { case NEXTHOP_TYPE_IPV4: @@ -305,12 +308,12 @@ void route_add(struct prefix *p, uint8_t instance, struct nexthop_group *nhg) zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api); } -void route_delete(struct prefix *p, uint8_t instance) +void route_delete(struct prefix *p, vrf_id_t vrf_id, uint8_t instance) { struct zapi_route api; memset(&api, 0, sizeof(api)); - api.vrf_id = VRF_DEFAULT; + api.vrf_id = vrf_id; api.type = ZEBRA_ROUTE_SHARP; api.safi = SAFI_UNICAST; api.instance = instance; @@ -320,14 +323,24 @@ void route_delete(struct prefix *p, uint8_t instance) return; } -void sharp_zebra_nexthop_watch(struct prefix *p, bool watch, bool connected) +void sharp_zebra_nexthop_watch(struct prefix *p, vrf_id_t vrf_id, bool import, + bool watch, bool connected) { - int command = ZEBRA_NEXTHOP_REGISTER; + int command; - if (!watch) - command = ZEBRA_NEXTHOP_UNREGISTER; + if (!import) { + command = ZEBRA_NEXTHOP_REGISTER; - if (zclient_send_rnh(zclient, command, p, connected, VRF_DEFAULT) < 0) + if (!watch) + command = ZEBRA_NEXTHOP_UNREGISTER; + } else { + command = ZEBRA_IMPORT_ROUTE_REGISTER; + + if (!watch) + command = ZEBRA_IMPORT_ROUTE_UNREGISTER; + } + + if (zclient_send_rnh(zclient, command, p, connected, vrf_id) < 0) zlog_warn("%s: Failure to send nexthop to zebra", __PRETTY_FUNCTION__); } @@ -405,4 +418,5 @@ void sharp_zebra_init(void) zclient->interface_address_delete = interface_address_delete; zclient->route_notify_owner = route_notify_owner; zclient->nexthop_update = sharp_nexthop_update; + zclient->import_check_update = sharp_nexthop_update; } diff --git a/sharpd/sharp_zebra.h b/sharpd/sharp_zebra.h index 7e6ac7670b..57ffcc7690 100644 --- a/sharpd/sharp_zebra.h +++ b/sharpd/sharp_zebra.h @@ -25,15 +25,16 @@ extern void sharp_zebra_init(void); extern void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label); -extern void route_add(struct prefix *p, uint8_t instance, +extern void route_add(struct prefix *p, vrf_id_t, uint8_t instance, struct nexthop_group *nhg); -extern void route_delete(struct prefix *p, uint8_t instance); -extern void sharp_zebra_nexthop_watch(struct prefix *p, bool watch, - bool connected); +extern void route_delete(struct prefix *p, vrf_id_t vrf_id, uint8_t instance); +extern void sharp_zebra_nexthop_watch(struct prefix *p, vrf_id_t vrf_id, + bool import, bool watch, bool connected); -extern void sharp_install_routes_helper(struct prefix *p, uint8_t instance, - struct nexthop_group *nhg, - uint32_t routes); -extern void sharp_remove_routes_helper(struct prefix *p, uint8_t instance, - uint32_t routes); +extern void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id, + uint8_t instance, + struct nexthop_group *nhg, + uint32_t routes); +extern void sharp_remove_routes_helper(struct prefix *p, vrf_id_t vrf_id, + uint8_t instance, uint32_t routes); #endif diff --git a/staticd/static_vty.c b/staticd/static_vty.c index f09c304359..3a9e4e8fa4 100644 --- a/staticd/static_vty.c +++ b/staticd/static_vty.c @@ -104,30 +104,18 @@ static int static_list_compare_helper(const char *s1, const char *s2) static void static_list_delete(struct static_hold_route *shr) { - if (shr->vrf_name) - XFREE(MTYPE_STATIC_ROUTE, shr->vrf_name); - if (shr->nhvrf_name) - XFREE(MTYPE_STATIC_ROUTE, shr->nhvrf_name); - if (shr->dest_str) - XFREE(MTYPE_STATIC_ROUTE, shr->dest_str); - if (shr->mask_str) - XFREE(MTYPE_STATIC_ROUTE, shr->mask_str); - if (shr->src_str) - XFREE(MTYPE_STATIC_ROUTE, shr->src_str); - if (shr->gate_str) - XFREE(MTYPE_STATIC_ROUTE, shr->gate_str); - if (shr->ifname) - XFREE(MTYPE_STATIC_ROUTE, shr->ifname); - if (shr->flag_str) - XFREE(MTYPE_STATIC_ROUTE, shr->flag_str); - if (shr->tag_str) - XFREE(MTYPE_STATIC_ROUTE, shr->tag_str); - if (shr->distance_str) - XFREE(MTYPE_STATIC_ROUTE, shr->distance_str); - if (shr->label_str) - XFREE(MTYPE_STATIC_ROUTE, shr->label_str); - if (shr->table_str) - XFREE(MTYPE_STATIC_ROUTE, shr->table_str); + XFREE(MTYPE_STATIC_ROUTE, shr->vrf_name); + XFREE(MTYPE_STATIC_ROUTE, shr->nhvrf_name); + XFREE(MTYPE_STATIC_ROUTE, shr->dest_str); + XFREE(MTYPE_STATIC_ROUTE, shr->mask_str); + XFREE(MTYPE_STATIC_ROUTE, shr->src_str); + XFREE(MTYPE_STATIC_ROUTE, shr->gate_str); + XFREE(MTYPE_STATIC_ROUTE, shr->ifname); + XFREE(MTYPE_STATIC_ROUTE, shr->flag_str); + XFREE(MTYPE_STATIC_ROUTE, shr->tag_str); + XFREE(MTYPE_STATIC_ROUTE, shr->distance_str); + XFREE(MTYPE_STATIC_ROUTE, shr->label_str); + XFREE(MTYPE_STATIC_ROUTE, shr->table_str); XFREE(MTYPE_STATIC_ROUTE, shr); } diff --git a/tests/.gitignore b/tests/.gitignore index 5453c0d80a..de648015f1 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -19,6 +19,7 @@ /lib/cli/test_commands /lib/cli/test_commands_defun.c /lib/northbound/test_oper_data +/lib/cxxcompat /lib/test_buffer /lib/test_checksum /lib/test_graph diff --git a/tests/bgpd/test_bgp_table.c b/tests/bgpd/test_bgp_table.c index 73243dcacf..7b38df5f66 100644 --- a/tests/bgpd/test_bgp_table.c +++ b/tests/bgpd/test_bgp_table.c @@ -158,7 +158,7 @@ static void test_range_lookup(void) "1.16.160.0/19", "1.16.32.0/20", "1.16.32.0/21", "16.0.0.0/16"}; - int num_prefixes = sizeof(prefixes) / sizeof(prefixes[0]); + int num_prefixes = array_size(prefixes); for (int i = 0; i < num_prefixes; i++) add_node(table, prefixes[i]); diff --git a/tests/bgpd/test_mpath.c b/tests/bgpd/test_mpath.c index 04fbda42eb..0ecd0fdfec 100644 --- a/tests/bgpd/test_mpath.c +++ b/tests/bgpd/test_mpath.c @@ -205,7 +205,7 @@ struct peer test_mp_list_peer[] = { {.local_as = 1, .as = 2}, {.local_as = 1, .as = 2}, {.local_as = 1, .as = 2}, }; -int test_mp_list_peer_count = sizeof(test_mp_list_peer) / sizeof(struct peer); +int test_mp_list_peer_count = array_size(test_mp_list_peer); struct attr test_mp_list_attr[4]; struct bgp_path_info test_mp_list_info[] = { {.peer = &test_mp_list_peer[0], .attr = &test_mp_list_attr[0]}, @@ -214,8 +214,7 @@ struct bgp_path_info test_mp_list_info[] = { {.peer = &test_mp_list_peer[3], .attr = &test_mp_list_attr[2]}, {.peer = &test_mp_list_peer[4], .attr = &test_mp_list_attr[3]}, }; -int test_mp_list_info_count = - sizeof(test_mp_list_info) / sizeof(struct bgp_path_info); +int test_mp_list_info_count = array_size(test_mp_list_info); static int setup_bgp_mp_list(testcase_t *t) { @@ -370,7 +369,7 @@ testcase_t *all_tests[] = { &test_bgp_path_info_mpath_update, }; -int all_tests_count = (sizeof(all_tests) / sizeof(testcase_t *)); +int all_tests_count = array_size(all_tests); /*========================================================= * Test Driver Functions diff --git a/tests/lib/cxxcompat.c b/tests/lib/cxxcompat.c new file mode 100644 index 0000000000..530468642e --- /dev/null +++ b/tests/lib/cxxcompat.c @@ -0,0 +1,113 @@ +/* + * C++ compatibility compile-time smoketest + * Copyright (C) 2019 David Lamparter for NetDEF, Inc. + * + * This program 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 of the License, or (at your option) + * any later version. + * + * This program 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 this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "lib/zebra.h" + +#include "lib/agg_table.h" +#include "lib/bfd.h" +#include "lib/bitfield.h" +#include "lib/buffer.h" +#include "lib/checksum.h" +#include "lib/command.h" +#include "lib/command_graph.h" +#include "lib/command_match.h" +#include "lib/compiler.h" +#include "lib/csv.h" +#include "lib/debug.h" +#include "lib/distribute.h" +#include "lib/event_counter.h" +#include "lib/ferr.h" +#include "lib/fifo.h" +#include "lib/filter.h" +#include "lib/frr_pthread.h" +#include "lib/frratomic.h" +#include "lib/frrstr.h" +#include "lib/getopt.h" +#include "lib/graph.h" +#include "lib/hash.h" +#include "lib/hook.h" +#include "lib/id_alloc.h" +#include "lib/if.h" +#include "lib/if_rmap.h" +#include "lib/imsg.h" +#include "lib/ipaddr.h" +#include "lib/jhash.h" +#include "lib/json.h" +#include "lib/keychain.h" +#include "lib/lib_errors.h" +#include "lib/libfrr.h" +#include "lib/libospf.h" +#include "lib/linklist.h" +#include "lib/log.h" +#include "lib/logicalrouter.h" +#include "lib/md5.h" +#include "lib/memory.h" +#include "lib/memory_vty.h" +#include "lib/mlag.h" +#include "lib/module.h" +#include "lib/monotime.h" +#include "lib/mpls.h" +#include "lib/network.h" +#include "lib/nexthop.h" +#include "lib/nexthop_group.h" +#include "lib/northbound.h" +#include "lib/northbound_cli.h" +#include "lib/northbound_db.h" +#include "lib/ns.h" +#include "lib/openbsd-tree.h" +#include "lib/pbr.h" +#include "lib/plist.h" +#include "lib/pqueue.h" +#include "lib/prefix.h" +#include "lib/privs.h" +#include "lib/ptm_lib.h" +#include "lib/pw.h" +#include "lib/qobj.h" +#include "lib/queue.h" +#include "lib/ringbuf.h" +#include "lib/routemap.h" +#include "lib/sbuf.h" +#include "lib/sha256.h" +#include "lib/sigevent.h" +#include "lib/skiplist.h" +#include "lib/sockopt.h" +#include "lib/sockunion.h" +#include "lib/spf_backoff.h" +#include "lib/srcdest_table.h" +#include "lib/stream.h" +#include "lib/table.h" +#include "lib/termtable.h" +#include "lib/thread.h" +#include "lib/vector.h" +#include "lib/vlan.h" +#include "lib/vrf.h" +#include "lib/vty.h" +#include "lib/vxlan.h" +#include "lib/wheel.h" +/* #include "lib/workqueue.h" -- macro problem with STAILQ_LAST */ +#include "lib/yang.h" +#include "lib/yang_translator.h" +#include "lib/yang_wrappers.h" +#include "lib/zassert.h" +#include "lib/zclient.h" + +int main(int argc, char **argv) +{ + return 0; +} diff --git a/tests/lib/test_privs.c b/tests/lib/test_privs.c index e203da8f6e..fc3d908661 100644 --- a/tests/lib/test_privs.c +++ b/tests/lib/test_privs.c @@ -37,7 +37,7 @@ struct zebra_privs_t test_privs = { .vty_group = VTY_GROUP, #endif .caps_p = _caps_p, - .cap_num_p = sizeof(_caps_p) / sizeof(_caps_p[0]), + .cap_num_p = array_size(_caps_p), .cap_num_i = 0}; struct option longopts[] = {{"help", no_argument, NULL, 'h'}, diff --git a/tests/lib/test_srcdest_table.c b/tests/lib/test_srcdest_table.c index 959358bbec..19a40b2184 100644 --- a/tests/lib/test_srcdest_table.c +++ b/tests/lib/test_srcdest_table.c @@ -105,7 +105,7 @@ static unsigned int log_key(void *data) static bool log_cmp(const void *a, const void *b) { if (a == NULL || b == NULL) - return 0; + return false; return !memcmp(a, b, 2 * sizeof(struct prefix)); } @@ -195,10 +195,10 @@ static void test_state_del_route(struct test_state *test, XFREE(MTYPE_TMP, hash_entry_intern); } -static void verify_log(struct hash_backet *backet, void *arg) +static void verify_log(struct hash_bucket *bucket, void *arg) { struct test_state *test = arg; - struct prefix *hash_entry = backet->data; + struct prefix *hash_entry = bucket->data; struct prefix *dst_p = &hash_entry[0]; struct prefix_ipv6 *src_p = (struct prefix_ipv6 *)&hash_entry[1]; struct route_node *rn = srcdest_rnode_lookup(test->table, dst_p, src_p); @@ -209,9 +209,9 @@ static void verify_log(struct hash_backet *backet, void *arg) route_unlock_node(rn); } -static void dump_log(struct hash_backet *backet, void *arg) +static void dump_log(struct hash_bucket *bucket, void *arg) { - struct prefix *hash_entry = backet->data; + struct prefix *hash_entry = bucket->data; struct prefix_ipv6 *dst_p = (struct prefix_ipv6 *)&hash_entry[0]; struct prefix_ipv6 *src_p = (struct prefix_ipv6 *)&hash_entry[1]; char *route_id = format_srcdest(dst_p, src_p); diff --git a/tests/lib/test_table.c b/tests/lib/test_table.c index 2b65040627..90d6c76bf1 100644 --- a/tests/lib/test_table.c +++ b/tests/lib/test_table.c @@ -478,7 +478,7 @@ static void test_iter_pause(void) const char *prefixes[] = {"1.0.1.0/24", "1.0.1.0/25", "1.0.1.128/25", "1.0.2.0/24", "2.0.0.0/8"}; - num_prefixes = sizeof(prefixes) / sizeof(prefixes[0]); + num_prefixes = array_size(prefixes); printf("\n\nTesting that route_table_iter_pause() works as expected\n"); table = route_table_init(); diff --git a/tests/subdir.am b/tests/subdir.am index 42730cb83a..365fe00cc6 100644 --- a/tests/subdir.am +++ b/tests/subdir.am @@ -46,6 +46,7 @@ tests/ospf6d/tests_ospf6d_test_lsdb-test_lsdb.$(OBJEXT): tests/ospf6d/test_lsdb_ tests/ospf6d/test_lsdb-test_lsdb.$(OBJEXT): tests/ospf6d/test_lsdb_clippy.c check_PROGRAMS = \ + tests/lib/cxxcompat \ tests/lib/test_buffer \ tests/lib/test_checksum \ tests/lib/test_heavy_thread \ @@ -170,6 +171,10 @@ tests_isisd_test_isis_vertex_queue_CPPFLAGS = $(TESTS_CPPFLAGS) tests_isisd_test_isis_vertex_queue_LDADD = $(ISISD_TEST_LDADD) tests_isisd_test_isis_vertex_queue_SOURCES = tests/isisd/test_isis_vertex_queue.c +tests_lib_cxxcompat_CFLAGS = $(TESTS_CFLAGS) $(CXX_COMPAT_CFLAGS) $(WERROR) +tests_lib_cxxcompat_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_cxxcompat_SOURCES = tests/lib/cxxcompat.c +tests_lib_cxxcompat_LDADD = $(ALL_TESTS_LDADD) tests_lib_cli_test_cli_CFLAGS = $(TESTS_CFLAGS) tests_lib_cli_test_cli_CPPFLAGS = $(TESTS_CPPFLAGS) tests_lib_cli_test_cli_LDADD = $(ALL_TESTS_LDADD) diff --git a/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref b/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref new file mode 100644 index 0000000000..e75d896721 --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref @@ -0,0 +1,12 @@ +C>* 192.168.0.0/24 is directly connected, r1-eth0, XX:XX:XX +C>* 192.168.1.0/26 is directly connected, r1-eth1, XX:XX:XX +C>* 192.168.2.0/26 is directly connected, r1-eth2, XX:XX:XX +C>* 192.168.3.0/26 is directly connected, r1-eth3, XX:XX:XX +C>* 192.168.4.0/26 is directly connected, r1-eth4, XX:XX:XX +C>* 192.168.5.0/26 is directly connected, r1-eth5, XX:XX:XX +C>* 192.168.6.0/26 is directly connected, r1-eth6, XX:XX:XX +C>* 192.168.7.0/26 is directly connected, r1-eth7, XX:XX:XX +C>* 192.168.8.0/26 is directly connected, r1-eth8, XX:XX:XX +C>* 192.168.9.0/26 is directly connected, r1-eth9, XX:XX:XX +O 192.168.0.0/24 [110/10] is directly connected, r1-eth0, XX:XX:XX +O 192.168.3.0/26 [110/10] is directly connected, r1-eth3, XX:XX:XX diff --git a/tests/topotests/all-protocol-startup/r1/ipv6_routes.ref b/tests/topotests/all-protocol-startup/r1/ipv6_routes.ref new file mode 100644 index 0000000000..88cee964d6 --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/ipv6_routes.ref @@ -0,0 +1,22 @@ +C>* fc00:0:0:1::/64 is directly connected, r1-eth1, XX:XX:XX +C>* fc00:0:0:2::/64 is directly connected, r1-eth2, XX:XX:XX +C>* fc00:0:0:3::/64 is directly connected, r1-eth3, XX:XX:XX +C>* fc00:0:0:4::/64 is directly connected, r1-eth4, XX:XX:XX +C>* fc00:0:0:5::/64 is directly connected, r1-eth5, XX:XX:XX +C>* fc00:0:0:6::/64 is directly connected, r1-eth6, XX:XX:XX +C>* fc00:0:0:7::/64 is directly connected, r1-eth7, XX:XX:XX +C>* fc00:0:0:8::/64 is directly connected, r1-eth8, XX:XX:XX +C>* fc00:0:0:9::/64 is directly connected, r1-eth9, XX:XX:XX +C>* fc00::/64 is directly connected, r1-eth0, XX:XX:XX +C>* fe80::/64 is directly connected, lo, XX:XX:XX +C * fe80::/64 is directly connected, r1-eth0, XX:XX:XX +C * fe80::/64 is directly connected, r1-eth1, XX:XX:XX +C * fe80::/64 is directly connected, r1-eth2, XX:XX:XX +C * fe80::/64 is directly connected, r1-eth3, XX:XX:XX +C * fe80::/64 is directly connected, r1-eth4, XX:XX:XX +C * fe80::/64 is directly connected, r1-eth5, XX:XX:XX +C * fe80::/64 is directly connected, r1-eth6, XX:XX:XX +C * fe80::/64 is directly connected, r1-eth7, XX:XX:XX +C * fe80::/64 is directly connected, r1-eth8, XX:XX:XX +C * fe80::/64 is directly connected, r1-eth9, XX:XX:XX +O fc00:0:0:4::/64 [110/10] is directly connected, r1-eth4, XX:XX:XX diff --git a/tests/topotests/all-protocol-startup/r1/show_bgp_ipv6_summary.ref b/tests/topotests/all-protocol-startup/r1/show_bgp_ipv6_summary.ref index 6777cd9fc3..85388c738d 100644 --- a/tests/topotests/all-protocol-startup/r1/show_bgp_ipv6_summary.ref +++ b/tests/topotests/all-protocol-startup/r1/show_bgp_ipv6_summary.ref @@ -1,7 +1,7 @@ BGP router identifier 192.168.0.1, local AS number 100 vrf-id 0 BGP table version 1 RIB entries 1, using XXXX bytes of memory -Peers 4, using XXXX KiB of memory +Peers 2, using XXXX KiB of memory Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd fc00:0:0:8::1000 4 100 0 0 0 0 0 never Active diff --git a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py index fb2100e03d..239de55bd6 100755 --- a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py +++ b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py @@ -296,10 +296,53 @@ def test_converge_protocols(): sleep(60) # Make sure that all daemons are running + failures = 0 for i in range(1, 2): fatal_error = net['r%s' % i].checkRouterRunning() assert fatal_error == "", fatal_error + print("Show that v4 routes are right\n"); + v4_routesFile = '%s/r%s/ipv4_routes.ref' % (thisDir, i) + expected = open(v4_routesFile).read().rstrip() + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + actual = net['r%s' %i].cmd('vtysh -c "show ip route" | /usr/bin/tail -n +7 | sort 2> /dev/null').rstrip() + # Drop time in last update + actual = re.sub(r" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + diff = topotest.get_textdiff(actual, expected, + title1="Actual IP Routing Table", + title2="Expected IP RoutingTable") + if diff: + sys.stderr.write('r%s failed IP Routing table check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" %i) + + assert failures == 0, "IP Routing table failed for r%s\n%s" % (i, diff) + + failures = 0 + + print("Show that v6 routes are right\n") + v6_routesFile = '%s/r%s/ipv6_routes.ref' % (thisDir, i) + expected = open(v6_routesFile).read().rstrip() + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + actual = net['r%s' %i].cmd('vtysh -c "show ipv6 route" | /usr/bin/tail -n +7 | sort 2> /dev/null').rstrip() + # Drop time in last update + actual = re.sub(r" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + diff = topotest.get_textdiff(actual, expected, + title1="Actual IPv6 Routing Table", + title2="Expected IPv6 RoutingTable") + if diff: + sys.stderr.write('r%s failed IPv6 Routing table check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" %i) + + assert failures == 0, "IPv6 Routing table failed for r%s\n%s" % (i, diff) + # For debugging after starting FRR/Quagga daemons, uncomment the next line ## CLI(net) diff --git a/debianpkg/backports/debian8/exclude b/tests/topotests/bfd-topo2/__init__.py index e69de29bb2..e69de29bb2 100644 --- a/debianpkg/backports/debian8/exclude +++ b/tests/topotests/bfd-topo2/__init__.py diff --git a/tests/topotests/bfd-topo2/r1/bfdd.conf b/tests/topotests/bfd-topo2/r1/bfdd.conf new file mode 100644 index 0000000000..5c2571bdbd --- /dev/null +++ b/tests/topotests/bfd-topo2/r1/bfdd.conf @@ -0,0 +1,5 @@ +bfd + peer 2001:db8:4::1 multihop local-address 2001:db8:1::1 + no shutdown + ! +! diff --git a/tests/topotests/bfd-topo2/r1/bgpd.conf b/tests/topotests/bfd-topo2/r1/bgpd.conf new file mode 100644 index 0000000000..1623b4578b --- /dev/null +++ b/tests/topotests/bfd-topo2/r1/bgpd.conf @@ -0,0 +1,13 @@ +router bgp 101 + bgp router-id 10.254.254.1 + neighbor r2g peer-group + neighbor r2g remote-as external + neighbor r2g bfd + neighbor r1-eth0 interface peer-group r2g + address-family ipv4 unicast + redistribute connected + exit-address-family + address-family ipv6 unicast + neighbor r2g activate + exit-address-family +! diff --git a/tests/topotests/bfd-topo2/r1/ipv4_routes.json b/tests/topotests/bfd-topo2/r1/ipv4_routes.json new file mode 100644 index 0000000000..8a2ec25baa --- /dev/null +++ b/tests/topotests/bfd-topo2/r1/ipv4_routes.json @@ -0,0 +1,68 @@ +{ + "10.0.3.0/24": [ + { + "distance": 20, + "protocol": "bgp", + "internalFlags": 8, + "metric": 0, + "selected": true, + "installed": true, + "prefix": "10.0.3.0/24", + "internalStatus": 34, + "nexthops": [ + { + "interfaceName": "r1-eth0", + "interfaceIndex": 2, + "fib": true, + "flags": 3, + "active": true, + "afi": "ipv6" + } + ] + } + ], + "10.254.254.2/32": [ + { + "distance": 20, + "protocol": "bgp", + "internalFlags": 8, + "metric": 0, + "selected": true, + "installed": true, + "prefix": "10.254.254.2/32", + "internalStatus": 34, + "nexthops": [ + { + "interfaceName": "r1-eth0", + "interfaceIndex": 2, + "fib": true, + "flags": 3, + "active": true, + "afi": "ipv6" + } + ] + } + ], + "10.254.254.1/32": [ + { + "distance": 0, + "protocol": "connected", + "internalFlags": 8, + "metric": 0, + "selected": true, + "installed": true, + "prefix": "10.254.254.1/32", + "internalStatus": 32, + "nexthops": [ + { + "directlyConnected": true, + "interfaceName": "lo", + "interfaceIndex": 1, + "fib": true, + "flags": 3, + "active": true + } + ] + } + ] +} diff --git a/tests/topotests/bfd-topo2/r1/ipv6_routes.json b/tests/topotests/bfd-topo2/r1/ipv6_routes.json new file mode 100644 index 0000000000..618853bd42 --- /dev/null +++ b/tests/topotests/bfd-topo2/r1/ipv6_routes.json @@ -0,0 +1,63 @@ +{ + "2001:db8:4::/64": [ + { + "distance": 20, + "protocol": "bgp", + "internalFlags": 8, + "metric": 0, + "selected": true, + "installed": true, + "prefix": "2001:db8:4::/64", + "internalStatus": 34, + "nexthops": [ + { + "interfaceName": "r1-eth0", + "interfaceIndex": 2, + "fib": true, + "flags": 3, + "active": true, + "afi": "ipv6" + } + ] + } + ], + "2001:db8:1::/64": [ + { + "distance": 20, + "protocol": "bgp", + "internalFlags": 0, + "metric": 0, + "internalStatus": 2, + "prefix": "2001:db8:1::/64", + "nexthops": [ + { + "interfaceName": "r1-eth0", + "interfaceIndex": 2, + "flags": 1, + "active": true, + "afi": "ipv6" + } + ] + }, + { + "distance": 0, + "protocol": "connected", + "internalFlags": 8, + "metric": 0, + "selected": true, + "installed": true, + "prefix": "2001:db8:1::/64", + "internalStatus": 32, + "nexthops": [ + { + "directlyConnected": true, + "interfaceName": "r1-eth0", + "interfaceIndex": 2, + "fib": true, + "flags": 3, + "active": true + } + ] + } + ] +} diff --git a/tests/topotests/bfd-topo2/r1/peers.json b/tests/topotests/bfd-topo2/r1/peers.json new file mode 100644 index 0000000000..b14351cd81 --- /dev/null +++ b/tests/topotests/bfd-topo2/r1/peers.json @@ -0,0 +1,29 @@ +[ + { + "multihop":true, + "peer":"2001:db8:4::1", + "local":"2001:db8:1::1", + "status":"up", + "diagnostic":"ok", + "remote-diagnostic":"ok", + "receive-interval":300, + "transmit-interval":300, + "echo-interval":0, + "remote-receive-interval":300, + "remote-transmit-interval":300, + "remote-echo-interval":50 + }, + { + "multihop":false, + "interface":"r1-eth0", + "status":"up", + "diagnostic":"ok", + "remote-diagnostic":"ok", + "receive-interval":300, + "transmit-interval":300, + "echo-interval":0, + "remote-receive-interval":300, + "remote-transmit-interval":300, + "remote-echo-interval":50 + } +] diff --git a/tests/topotests/bfd-topo2/r1/zebra.conf b/tests/topotests/bfd-topo2/r1/zebra.conf new file mode 100644 index 0000000000..7fe5eb218f --- /dev/null +++ b/tests/topotests/bfd-topo2/r1/zebra.conf @@ -0,0 +1,6 @@ +interface lo + ip address 10.254.254.1/32 +! +interface r1-eth0 + ipv6 address 2001:db8:1::1/64 +! diff --git a/tests/topotests/bfd-topo2/r2/bgpd.conf b/tests/topotests/bfd-topo2/r2/bgpd.conf new file mode 100644 index 0000000000..bf42d21812 --- /dev/null +++ b/tests/topotests/bfd-topo2/r2/bgpd.conf @@ -0,0 +1,16 @@ +router bgp 102 + bgp router-id 10.254.254.2 + neighbor r2g peer-group + neighbor r2g remote-as external + neighbor r2g bfd + neighbor r2-eth0 interface peer-group r2g + ! + address-family ipv4 unicast + redistribute connected + exit-address-family + ! + address-family ipv6 unicast + redistribute connected + neighbor r2g activate + exit-address-family +! diff --git a/tests/topotests/bfd-topo2/r2/ipv4_routes.json b/tests/topotests/bfd-topo2/r2/ipv4_routes.json new file mode 100644 index 0000000000..b9d8afb430 --- /dev/null +++ b/tests/topotests/bfd-topo2/r2/ipv4_routes.json @@ -0,0 +1,108 @@ +{ + "10.0.3.0/24": [ + { + "distance": 110, + "protocol": "ospf", + "internalFlags": 0, + "metric": 10, + "internalStatus": 2, + "prefix": "10.0.3.0/24", + "nexthops": [ + { + "active": true, + "directlyConnected": true, + "flags": 1, + "interfaceIndex": 3, + "interfaceName": "r2-eth1" + } + ] + }, + { + "distance": 0, + "protocol": "connected", + "internalFlags": 8, + "metric": 0, + "selected": true, + "installed": true, + "prefix": "10.0.3.0/24", + "internalStatus": 32, + "nexthops": [ + { + "directlyConnected": true, + "interfaceName": "r2-eth1", + "interfaceIndex": 3, + "fib": true, + "flags": 3, + "active": true + } + ] + } + ], + "10.254.254.3/32": [ + { + "distance": 110, + "protocol": "ospf", + "internalFlags": 8, + "metric": 20, + "selected": true, + "installed": true, + "prefix": "10.254.254.3/32", + "internalStatus": 34, + "nexthops": [ + { + "interfaceName": "r2-eth1", + "ip": "10.0.3.1", + "interfaceIndex": 3, + "fib": true, + "flags": 3, + "active": true, + "afi": "ipv4" + } + ] + } + ], + "10.254.254.2/32": [ + { + "distance": 0, + "protocol": "connected", + "internalFlags": 8, + "metric": 0, + "selected": true, + "installed": true, + "prefix": "10.254.254.2/32", + "internalStatus": 32, + "nexthops": [ + { + "directlyConnected": true, + "interfaceName": "lo", + "interfaceIndex": 1, + "fib": true, + "flags": 3, + "active": true + } + ] + } + ], + "10.254.254.1/32": [ + { + "distance": 20, + "protocol": "bgp", + "internalFlags": 8, + "metric": 0, + "selected": true, + "installed": true, + "prefix": "10.254.254.1/32", + "internalStatus": 34, + "nexthops": [ + { + "interfaceName": "r2-eth0", + "interfaceIndex": 2, + "fib": true, + "flags": 3, + "active": true, + "afi": "ipv6" + } + ] + } + ] +} diff --git a/tests/topotests/bfd-topo2/r2/ipv6_routes.json b/tests/topotests/bfd-topo2/r2/ipv6_routes.json new file mode 100644 index 0000000000..004e7588aa --- /dev/null +++ b/tests/topotests/bfd-topo2/r2/ipv6_routes.json @@ -0,0 +1,63 @@ +{ + "2001:db8:4::/64": [ + { + "distance": 110, + "protocol": "ospf6", + "internalFlags": 0, + "metric": 10, + "internalStatus": 2, + "prefix": "2001:db8:4::/64", + "nexthops": [ + { + "active": true, + "directlyConnected": true, + "flags": 1, + "interfaceIndex": 4, + "interfaceName": "r2-eth2" + } + ] + }, + { + "distance": 0, + "protocol": "connected", + "internalFlags": 8, + "metric": 0, + "selected": true, + "installed": true, + "prefix": "2001:db8:4::/64", + "internalStatus": 32, + "nexthops": [ + { + "directlyConnected": true, + "interfaceName": "r2-eth2", + "interfaceIndex": 4, + "fib": true, + "flags": 3, + "active": true + } + ] + } + ], + "2001:db8:1::/64": [ + { + "distance": 0, + "protocol": "connected", + "internalFlags": 8, + "metric": 0, + "selected": true, + "installed": true, + "prefix": "2001:db8:1::/64", + "internalStatus": 32, + "nexthops": [ + { + "directlyConnected": true, + "interfaceName": "r2-eth0", + "interfaceIndex": 2, + "fib": true, + "flags": 3, + "active": true + } + ] + } + ] +} diff --git a/tests/topotests/bfd-topo2/r2/ospf6d.conf b/tests/topotests/bfd-topo2/r2/ospf6d.conf new file mode 100644 index 0000000000..f1cdb50285 --- /dev/null +++ b/tests/topotests/bfd-topo2/r2/ospf6d.conf @@ -0,0 +1,9 @@ +interface r2-eth2 + ipv6 ospf6 bfd +! +router ospf6 + ospf6 router-id 10.254.254.2 + redistribute connected + redistribute bgp + interface r2-eth2 area 0.0.0.1 +! diff --git a/tests/topotests/bfd-topo2/r2/ospfd.conf b/tests/topotests/bfd-topo2/r2/ospfd.conf new file mode 100644 index 0000000000..8e0c45980d --- /dev/null +++ b/tests/topotests/bfd-topo2/r2/ospfd.conf @@ -0,0 +1,9 @@ +interface r2-eth1 + ip ospf area 0.0.0.1 + ip ospf bfd +! +router ospf + ospf router-id 10.254.254.2 + redistribute connected + redistribute bgp +! diff --git a/tests/topotests/bfd-topo2/r2/peers.json b/tests/topotests/bfd-topo2/r2/peers.json new file mode 100644 index 0000000000..29075fcc80 --- /dev/null +++ b/tests/topotests/bfd-topo2/r2/peers.json @@ -0,0 +1,42 @@ +[ + { + "status": "up", + "transmit-interval": 300, + "remote-receive-interval": 300, + "echo-interval": 0, + "diagnostic": "ok", + "multihop": false, + "interface": "r2-eth0", + "remote-transmit-interval": 300, + "receive-interval": 300, + "remote-echo-interval": 50, + "remote-diagnostic": "ok" + }, + { + "status": "up", + "transmit-interval": 300, + "remote-receive-interval": 300, + "echo-interval": 0, + "diagnostic": "ok", + "multihop": false, + "interface": "r2-eth2", + "remote-transmit-interval": 300, + "receive-interval": 300, + "remote-echo-interval": 50, + "remote-diagnostic": "ok" + }, + { + "status": "up", + "transmit-interval": 300, + "remote-receive-interval": 300, + "echo-interval": 0, + "diagnostic": "ok", + "multihop": false, + "interface": "r2-eth1", + "remote-transmit-interval": 300, + "receive-interval": 300, + "remote-echo-interval": 50, + "remote-diagnostic": "ok", + "peer": "10.0.3.1" + } +] diff --git a/tests/topotests/bfd-topo2/r2/zebra.conf b/tests/topotests/bfd-topo2/r2/zebra.conf new file mode 100644 index 0000000000..cccbf6574a --- /dev/null +++ b/tests/topotests/bfd-topo2/r2/zebra.conf @@ -0,0 +1,15 @@ +ip forwarding +ipv6 forwarding +! +interface lo + ip address 10.254.254.2/32 +! +interface r2-eth0 + ipv6 address 2001:db8:1::2/64 +! +interface r2-eth1 + ip address 10.0.3.2/24 +! +interface r2-eth2 + ipv6 address 2001:db8:4::2/64 +! diff --git a/tests/topotests/bfd-topo2/r3/ipv4_routes.json b/tests/topotests/bfd-topo2/r3/ipv4_routes.json new file mode 100644 index 0000000000..14dfc692fe --- /dev/null +++ b/tests/topotests/bfd-topo2/r3/ipv4_routes.json @@ -0,0 +1,109 @@ +{ + "10.0.3.0/24": [ + { + "distance": 110, + "protocol": "ospf", + "internalFlags": 0, + "metric": 10, + "internalStatus": 0, + "prefix": "10.0.3.0/24", + "nexthops": [ + { + "active": true, + "directlyConnected": true, + "flags": 1, + "interfaceIndex": 2, + "interfaceName": "r3-eth0" + } + ] + }, + { + "distance": 0, + "protocol": "connected", + "internalFlags": 8, + "metric": 0, + "selected": true, + "installed": true, + "prefix": "10.0.3.0/24", + "internalStatus": 32, + "nexthops": [ + { + "directlyConnected": true, + "interfaceName": "r3-eth0", + "interfaceIndex": 2, + "fib": true, + "flags": 3, + "active": true + } + ] + } + ], + "10.254.254.3/32": [ + { + "distance": 0, + "protocol": "connected", + "internalFlags": 8, + "metric": 0, + "selected": true, + "installed": true, + "prefix": "10.254.254.3/32", + "internalStatus": 32, + "nexthops": [ + { + "directlyConnected": true, + "interfaceName": "lo", + "interfaceIndex": 1, + "fib": true, + "flags": 3, + "active": true + } + ] + } + ], + "10.254.254.2/32": [ + { + "distance": 110, + "protocol": "ospf", + "internalFlags": 8, + "metric": 20, + "selected": true, + "installed": true, + "prefix": "10.254.254.2/32", + "internalStatus": 34, + "nexthops": [ + { + "interfaceName": "r3-eth0", + "ip": "10.0.3.2", + "interfaceIndex": 2, + "fib": true, + "flags": 3, + "active": true, + "afi": "ipv4" + } + ] + } + ], + "10.254.254.1/32": [ + { + "distance": 110, + "protocol": "ospf", + "internalFlags": 8, + "metric": 20, + "selected": true, + "installed": true, + "prefix": "10.254.254.1/32", + "internalStatus": 34, + "nexthops": [ + { + "interfaceName": "r3-eth0", + "ip": "10.0.3.2", + "interfaceIndex": 2, + "fib": true, + "flags": 3, + "active": true, + "afi": "ipv4" + } + ] + } + ] +} diff --git a/tests/topotests/bfd-topo2/r3/ipv6_routes.json b/tests/topotests/bfd-topo2/r3/ipv6_routes.json new file mode 100644 index 0000000000..2c63c08510 --- /dev/null +++ b/tests/topotests/bfd-topo2/r3/ipv6_routes.json @@ -0,0 +1,2 @@ +{ +} diff --git a/tests/topotests/bfd-topo2/r3/ospfd.conf b/tests/topotests/bfd-topo2/r3/ospfd.conf new file mode 100644 index 0000000000..cf2a1bdf76 --- /dev/null +++ b/tests/topotests/bfd-topo2/r3/ospfd.conf @@ -0,0 +1,8 @@ +interface r3-eth0 + ip ospf area 0.0.0.1 + ip ospf bfd +! +router ospf + ospf router-id 10.254.254.3 + redistribute connected +! diff --git a/tests/topotests/bfd-topo2/r3/peers.json b/tests/topotests/bfd-topo2/r3/peers.json new file mode 100644 index 0000000000..6698bff201 --- /dev/null +++ b/tests/topotests/bfd-topo2/r3/peers.json @@ -0,0 +1,16 @@ +[ + { + "status": "up", + "transmit-interval": 300, + "remote-receive-interval": 300, + "echo-interval": 0, + "diagnostic": "ok", + "multihop": false, + "interface": "r3-eth0", + "remote-transmit-interval": 300, + "receive-interval": 300, + "remote-echo-interval": 50, + "remote-diagnostic": "ok", + "peer": "10.0.3.2" + } +] diff --git a/tests/topotests/bfd-topo2/r3/zebra.conf b/tests/topotests/bfd-topo2/r3/zebra.conf new file mode 100644 index 0000000000..96fd08c729 --- /dev/null +++ b/tests/topotests/bfd-topo2/r3/zebra.conf @@ -0,0 +1,6 @@ +interface lo + ip address 10.254.254.3/32 +! +interface r3-eth0 + ip address 10.0.3.1/24 +! diff --git a/tests/topotests/bfd-topo2/r4/bfdd.conf b/tests/topotests/bfd-topo2/r4/bfdd.conf new file mode 100644 index 0000000000..fdb4412446 --- /dev/null +++ b/tests/topotests/bfd-topo2/r4/bfdd.conf @@ -0,0 +1,5 @@ +bfd + peer 2001:db8:1::1 multihop local-address 2001:db8:4::1 + no shutdown + ! +! diff --git a/tests/topotests/bfd-topo2/r4/ipv4_routes.json b/tests/topotests/bfd-topo2/r4/ipv4_routes.json new file mode 100644 index 0000000000..ae1e97b017 --- /dev/null +++ b/tests/topotests/bfd-topo2/r4/ipv4_routes.json @@ -0,0 +1,24 @@ +{ + "10.254.254.4/32": [ + { + "distance": 0, + "protocol": "connected", + "internalFlags": 8, + "metric": 0, + "selected": true, + "installed": true, + "prefix": "10.254.254.4/32", + "internalStatus": 32, + "nexthops": [ + { + "directlyConnected": true, + "interfaceName": "lo", + "interfaceIndex": 1, + "fib": true, + "flags": 3, + "active": true + } + ] + } + ] +} diff --git a/tests/topotests/bfd-topo2/r4/ipv6_routes.json b/tests/topotests/bfd-topo2/r4/ipv6_routes.json new file mode 100644 index 0000000000..33608b45aa --- /dev/null +++ b/tests/topotests/bfd-topo2/r4/ipv6_routes.json @@ -0,0 +1,63 @@ +{ + "2001:db8:4::/64": [ + { + "distance": 110, + "protocol": "ospf6", + "internalFlags": 0, + "metric": 10, + "internalStatus": 2, + "prefix": "2001:db8:4::/64", + "nexthops": [ + { + "active": true, + "directlyConnected": true, + "flags": 1, + "interfaceIndex": 2, + "interfaceName": "r4-eth0" + } + ] + }, + { + "distance": 0, + "protocol": "connected", + "internalFlags": 8, + "metric": 0, + "selected": true, + "installed": true, + "prefix": "2001:db8:4::/64", + "internalStatus": 32, + "nexthops": [ + { + "directlyConnected": true, + "interfaceName": "r4-eth0", + "interfaceIndex": 2, + "fib": true, + "flags": 3, + "active": true + } + ] + } + ], + "2001:db8:1::/64": [ + { + "distance": 110, + "protocol": "ospf6", + "internalFlags": 8, + "metric": 10, + "selected": true, + "installed": true, + "prefix": "2001:db8:1::/64", + "internalStatus": 34, + "nexthops": [ + { + "interfaceName": "r4-eth0", + "interfaceIndex": 2, + "fib": true, + "flags": 3, + "active": true, + "afi": "ipv6" + } + ] + } + ] +} diff --git a/tests/topotests/bfd-topo2/r4/ospf6d.conf b/tests/topotests/bfd-topo2/r4/ospf6d.conf new file mode 100644 index 0000000000..756597d6f8 --- /dev/null +++ b/tests/topotests/bfd-topo2/r4/ospf6d.conf @@ -0,0 +1,8 @@ +interface r4-eth0 + ipv6 ospf6 bfd +! +router ospf6 + ospf6 router-id 10.254.254.4 + redistribute connected + interface r4-eth0 area 0.0.0.1 +! diff --git a/tests/topotests/bfd-topo2/r4/peers.json b/tests/topotests/bfd-topo2/r4/peers.json new file mode 100644 index 0000000000..83101eb47f --- /dev/null +++ b/tests/topotests/bfd-topo2/r4/peers.json @@ -0,0 +1,29 @@ +[ + { + "multihop":true, + "peer":"2001:db8:1::1", + "local":"2001:db8:4::1", + "status":"up", + "diagnostic":"ok", + "remote-diagnostic":"ok", + "receive-interval":300, + "transmit-interval":300, + "echo-interval":0, + "remote-receive-interval":300, + "remote-transmit-interval":300, + "remote-echo-interval":50 + }, + { + "multihop":false, + "interface":"r4-eth0", + "status":"up", + "diagnostic":"ok", + "remote-diagnostic":"ok", + "receive-interval":300, + "transmit-interval":300, + "echo-interval":0, + "remote-receive-interval":300, + "remote-transmit-interval":300, + "remote-echo-interval":50 + } +] diff --git a/tests/topotests/bfd-topo2/r4/zebra.conf b/tests/topotests/bfd-topo2/r4/zebra.conf new file mode 100644 index 0000000000..e4f8fd8514 --- /dev/null +++ b/tests/topotests/bfd-topo2/r4/zebra.conf @@ -0,0 +1,6 @@ +interface lo + ip address 10.254.254.4/32 +! +interface r4-eth0 + ipv6 address 2001:db8:4::1/64 +! diff --git a/tests/topotests/bfd-topo2/test_bfd_topo2.dot b/tests/topotests/bfd-topo2/test_bfd_topo2.dot new file mode 100644 index 0000000000..6b68fb398f --- /dev/null +++ b/tests/topotests/bfd-topo2/test_bfd_topo2.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-topo2"; + + # 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\n2001:db8:1::/64", + fillcolor="#d0e0d0", + style=filled, + ]; + sw2 [ + shape=oval, + label="sw2\n10.0.3.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + sw3 [ + shape=oval, + label="sw3\n2001:db8:4::/64", + fillcolor="#d0e0d0", + style=filled, + ]; + + # Connections + r1 -- sw1 [label="eth0"]; + r2 -- sw1 [label="eth0"]; + + r2 -- sw2 [label="eth1"]; + r3 -- sw2 [label="eth0"]; + + r2 -- sw3 [label="eth2"]; + r4 -- sw3 [label="eth0"]; +} diff --git a/tests/topotests/bfd-topo2/test_bfd_topo2.jpg b/tests/topotests/bfd-topo2/test_bfd_topo2.jpg Binary files differnew file mode 100644 index 0000000000..35fe562a80 --- /dev/null +++ b/tests/topotests/bfd-topo2/test_bfd_topo2.jpg diff --git a/tests/topotests/bfd-topo2/test_bfd_topo2.py b/tests/topotests/bfd-topo2/test_bfd_topo2.py new file mode 100644 index 0000000000..773db129f0 --- /dev/null +++ b/tests/topotests/bfd-topo2/test_bfd_topo2.py @@ -0,0 +1,191 @@ +#!/usr/bin/env python + +# +# test_bfd_topo2.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2019 by +# Network Device Education Foundation, Inc. ("NetDEF") +# +# 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_topo2.py: Test the FRR/Quagga BFD daemon with multihop and BGP +unnumbered. +""" + +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() + for rname, router in router_list.iteritems(): + router.load_config( + TopoRouter.RD_ZEBRA, + os.path.join(CWD, '{}/zebra.conf'.format(rname)) + ) + 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)) + ) + router.load_config( + TopoRouter.RD_OSPF, + os.path.join(CWD, '{}/ospfd.conf'.format(rname)) + ) + router.load_config( + TopoRouter.RD_OSPF6, + os.path.join(CWD, '{}/ospf6d.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() + tgen.stop_topology() + + +def test_protocols_convergence(): + """ + Assert that all protocols have converged before checking for the BFD + statuses as they depend on it. + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Check IPv4 routing tables. + logger.info("Checking IPv4 routes for convergence") + for router in tgen.routers().values(): + json_file = '{}/{}/ipv4_routes.json'.format(CWD, router.name) + if not os.path.isfile(json_file): + logger.info('skipping file {}'.format(json_file)) + continue + + expected = json.loads(open(json_file).read()) + test_func = partial(topotest.router_json_cmp, + router, 'show ip route json', expected) + _, result = topotest.run_and_expect(test_func, None, count=160, + wait=0.5) + assertmsg = '"{}" JSON output mismatches'.format(router.name) + assert result is None, assertmsg + + # Check IPv6 routing tables. + logger.info("Checking IPv6 routes for convergence") + for router in tgen.routers().values(): + json_file = '{}/{}/ipv6_routes.json'.format(CWD, router.name) + if not os.path.isfile(json_file): + logger.info('skipping file {}'.format(json_file)) + continue + + expected = json.loads(open(json_file).read()) + test_func = partial(topotest.router_json_cmp, + router, 'show ipv6 route json', expected) + _, result = topotest.run_and_expect(test_func, None, count=160, + wait=0.5) + assertmsg = '"{}" JSON output mismatches'.format(router.name) + assert result is None, assertmsg + + +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_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/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py index 31e23faede..ce542413ba 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py @@ -141,7 +141,10 @@ class ThisTestTopo(Topo): switch[1].add_link(tgen.gears['r2'], nodeif='r2-eth2') switch[1].add_link(tgen.gears['r3'], nodeif='r3-eth1') +l3mdev_accept = 0 + def ltemplatePreRouterStartHook(): + global l3mdev_accept cc = ltemplateRtrCmd() krel = platform.release() tgen = get_topogen() @@ -172,7 +175,7 @@ def ltemplatePreRouterStartHook(): 'ip ru add oif {0}-cust1 table 10', 'ip ru add iif {0}-cust1 table 10', 'ip link set dev {0}-cust1 up', - 'sysctl -w net.ipv4.udp_l3mdev_accept={}'.format(l3mdev_accept)] + 'sysctl -w net.ipv4.tcp_l3mdev_accept={}'.format(l3mdev_accept)] for rtr in rtrs: router = tgen.gears[rtr] for cmd in cmds: @@ -202,7 +205,7 @@ def ltemplatePreRouterStartHook(): 'ip ru add oif {0}-cust2 table 20', 'ip ru add iif {0}-cust2 table 20', 'ip link set dev {0}-cust2 up', - 'sysctl -w net.ipv4.udp_l3mdev_accept={}'.format(l3mdev_accept)] + 'sysctl -w net.ipv4.tcp_l3mdev_accept={}'.format(l3mdev_accept)] for rtr in rtrs: for cmd in cmds: cc.doCmd(tgen, rtr, cmd.format(rtr)) diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py index 778d504040..f5d73a8c49 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py @@ -1,11 +1,12 @@ from lutil import luCommand - -rtrs = ['r1', 'r3', 'r4', 'ce1', 'ce2', 'ce3', 'ce4'] -for rtr in rtrs: +from customize import l3mdev_accept +l3mdev_rtrs = ['r1', 'r3', 'r4', 'ce4'] +for rtr in l3mdev_rtrs: luCommand(rtr,'sysctl net.ipv4.tcp_l3mdev_accept',' = \d*','none','') found = luLast() - luCommand(rtr,'ss -aep',':bgp','pass','IPv4:bgp, l3mdev%s' % found.group(0)) - luCommand(rtr,'ss -aep',':.:bgp','pass','IPv6:bgp') + luCommand(rtr,'ss -naep',':179','pass','IPv4:bgp, l3mdev{}'.format(found.group(0))) + luCommand(rtr,'ss -naep',':.*:179','pass','IPv6:bgp') + luCommand(rtr,'sysctl net.ipv4.tcp_l3mdev_accept',' = {}'.format(l3mdev_accept),'pass','l3mdev matches expected (real/expected{}/{})'.format(found.group(0),l3mdev_accept)) rtrs = ['r1', 'r3', 'r4'] for rtr in rtrs: diff --git a/tests/topotests/docker/build.sh b/tests/topotests/docker/build.sh index 344fb2ffcb..70ce2efe85 100755 --- a/tests/topotests/docker/build.sh +++ b/tests/topotests/docker/build.sh @@ -26,5 +26,5 @@ cd "$(dirname "$0")"/.. exec docker build --pull \ --compress \ - -t frrouting/frr:topotests-latest \ + -t frrouting/topotests:latest \ . diff --git a/tests/topotests/docker/frr-topotests.sh b/tests/topotests/docker/frr-topotests.sh index 6d8bea0002..ef916abcf3 100755 --- a/tests/topotests/docker/frr-topotests.sh +++ b/tests/topotests/docker/frr-topotests.sh @@ -136,7 +136,7 @@ if [ -z "$TOPOTEST_BUILDCACHE" ]; then fi if [ "${TOPOTEST_PULL:-1}" = "1" ]; then - docker pull frrouting/frr:topotests-latest + docker pull frrouting/topotests:latest fi set -- --rm -i \ @@ -149,7 +149,7 @@ set -- --rm -i \ -e "TOPOTEST_SANITIZER=$TOPOTEST_SANITIZER" \ --privileged \ $TOPOTEST_OPTIONS \ - frrouting/frr:topotests-latest "$@" + frrouting/topotests:latest "$@" if [ -t 0 ]; then set -- -t "$@" diff --git a/tests/topotests/eigrp-topo1/r1/zebra.conf b/tests/topotests/eigrp-topo1/r1/zebra.conf index 8537f6dd80..56ae4a66f4 100644 --- a/tests/topotests/eigrp-topo1/r1/zebra.conf +++ b/tests/topotests/eigrp-topo1/r1/zebra.conf @@ -1,4 +1,5 @@ log file zebra.log +debug zebra rib detail ! hostname r1 ! diff --git a/tests/topotests/eigrp-topo1/test_eigrp_topo1.py b/tests/topotests/eigrp-topo1/test_eigrp_topo1.py index 8ea2f0b506..1c00face43 100755 --- a/tests/topotests/eigrp-topo1/test_eigrp_topo1.py +++ b/tests/topotests/eigrp-topo1/test_eigrp_topo1.py @@ -171,6 +171,16 @@ def test_zebra_ipv4_routingTable(): assertmsg = 'Zebra IPv4 Routing Table verification failed for router {}'.format(router.name) assert topotest.json_cmp(output, expected) is None, assertmsg +def test_shut_interface_and_recover(): + "Test shutdown of an interface and recovery of the interface" + + tgen = get_topogen() + router = tgen.gears['r1'] + router.run('ip link set r1-eth1 down') + topotest.sleep(5, 'Waiting for EIGRP convergence') + router.run('ip link set r1-eth1 up') + + def test_shutdown_check_stderr(): if os.environ.get('TOPOTESTS_CHECK_STDERR') is None: diff --git a/tools/build-debian-package.sh b/tools/build-debian-package.sh index 73231f0aec..d21f468bf5 100755 --- a/tools/build-debian-package.sh +++ b/tools/build-debian-package.sh @@ -2,39 +2,26 @@ # # Written by Daniil Baturin, 2018 # This file is public domain +set -e -git diff-index --quiet HEAD || echo "Warning: git working directory is not clean!" - -# Set the defaults -if [ "$EXTRA_VERSION" = "" ]; then - EXTRA_VERSION="-MyDebPkgVersion" -fi +cd "`dirname $0`" +cd .. -if [ "$WANT_SNMP" = "" ]; then - WANT_SNMP=0 +if [ "`id -u`" = 0 ]; then + echo "Running as root - installing dependencies" + apt-get install fakeroot debhelper devscripts + mk-build-deps --install debian/control + exit 0 fi -if [ "$WANT_CUMULUS_MODE" = "" ]; then - WANT_CUMULUS_MODE=0 -fi +git diff-index --quiet HEAD || echo "Warning: git working directory is not clean!" echo "Preparing the build" -./bootstrap.sh -./configure --with-pkg-extra-version=$EXTRA_VERSION -make dist - -echo "Preparing Debian source package" -mv debianpkg debian -make -f debian/rules backports - -echo "Unpacking the source to frrpkg/" -mkdir frrpkg -cd frrpkg -tar xf ../frr_*.orig.tar.gz -cd frr* -. /etc/os-release -tar xf ../../frr_*${ID}${VERSION_ID}*.debian.tar.xz +tools/tarsource.sh -V echo "Building the Debian package" -debuild --no-lintian --set-envvar=WANT_SNMP=$WANT_SNMP --set-envvar=WANT_CUMULUS_MODE=$WANT_CUMULUS_MODE -b -uc -us - +if test $# -eq 0; then + dpkg-buildpackage -b -uc -us +else + dpkg-buildpackage "$@" +fi diff --git a/tools/coccinelle/alloc_cast.cocci b/tools/coccinelle/alloc_cast.cocci new file mode 100644 index 0000000000..b1497c750f --- /dev/null +++ b/tools/coccinelle/alloc_cast.cocci @@ -0,0 +1,101 @@ +/// Remove casting the values returned by memory allocation functions +/// like XMALLOC and XCALLOC. +/// +// This makes an effort to find cases of casting of values returned by # +// XMALLOC and XCALLOC and removes the casting as it is not required. The +// result in the patch case may need some reformatting. +// +// Confidence: High +// Copyright: (C) 2014 Himangi Saraogi GPLv2. +// Copyright: (C) 2017 Himanshu Jha GPLv2. +// Copyright: (C) 2019 Quentin Young GPLv2. +// Comments: +// Options: --no-includes --include-headers +// + +virtual context +virtual patch +virtual org +virtual report + +@initialize:python@ +@@ +import re +pattern = '__' +m = re.compile(pattern) + +@r1 depends on context || patch@ +type T; +@@ + + (T *) + \(XMALLOC\|XCALLOC\)(...) + +//---------------------------------------------------------- +// For context mode +//---------------------------------------------------------- + +@script:python depends on context@ +t << r1.T; +@@ + +if m.search(t) != None: + cocci.include_match(False) + +@depends on context && r1@ +type r1.T; +@@ + +* (T *) + \(XMALLOC\|XCALLOC\)(...) + +//---------------------------------------------------------- +// For patch mode +//---------------------------------------------------------- + +@script:python depends on patch@ +t << r1.T; +@@ + +if m.search(t) != None: + cocci.include_match(False) + +@depends on patch && r1@ +type r1.T; +@@ + +- (T *) + \(XMALLOC\|XCALLOC\)(...) + +//---------------------------------------------------------- +// For org and report mode +//---------------------------------------------------------- + +@r2 depends on org || report@ +type T; +position p; +@@ + + (T@p *) + \(XMALLOC\|XCALLOC\)(...) + +@script:python depends on org@ +p << r2.p; +t << r2.T; +@@ + +if m.search(t) != None: + cocci.include_match(False) +else: + coccilib.org.print_safe_todo(p[0], t) + +@script:python depends on report@ +p << r2.p; +t << r2.T; +@@ + +if m.search(t) != None: + cocci.include_match(False) +else: + msg="WARNING: casting value returned by memory allocation function to (%s *) is useless." % (t) + coccilib.report.print_report(p[0], msg) diff --git a/tools/coccinelle/array_size.cocci b/tools/coccinelle/array_size.cocci new file mode 100644 index 0000000000..f977b8aef2 --- /dev/null +++ b/tools/coccinelle/array_size.cocci @@ -0,0 +1,83 @@ +/// Use array_size instead of dividing sizeof array with sizeof an element +/// +//# This makes an effort to find cases where array_size can be used such as +//# where there is a division of sizeof the array by the sizeof its first +//# element or by any indexed element or the element type. It replaces the +//# division of the two sizeofs by array_size. +// +// Confidence: High +// Copyright: (C) 2014 Himangi Saraogi. GPLv2. +// Copyright: (C) 2019 Quentin Young. GPLv2. +// Comments: +// Options: --no-includes --include-headers + +virtual patch +virtual context +virtual org +virtual report + +//---------------------------------------------------------- +// For context mode +//---------------------------------------------------------- + +@depends on context@ +type T; +T[] E; +@@ +( +* (sizeof(E)/sizeof(*E)) +| +* (sizeof(E)/sizeof(E[...])) +| +* (sizeof(E)/sizeof(T)) +) + +//---------------------------------------------------------- +// For patch mode +//---------------------------------------------------------- + +@depends on patch@ +type T; +T[] E; +@@ +( +- (sizeof(E)/sizeof(*E)) ++ array_size(E) +| +- (sizeof(E)/sizeof(E[...])) ++ array_size(E) +| +- (sizeof(E)/sizeof(T)) ++ array_size(E) +) + +//---------------------------------------------------------- +// For org and report mode +//---------------------------------------------------------- + +@r depends on (org || report)@ +type T; +T[] E; +position p; +@@ +( + (sizeof(E)@p /sizeof(*E)) +| + (sizeof(E)@p /sizeof(E[...])) +| + (sizeof(E)@p /sizeof(T)) +) + +@script:python depends on org@ +p << r.p; +@@ + +coccilib.org.print_todo(p[0], "WARNING should use array_size") + +@script:python depends on report@ +p << r.p; +@@ + +msg="WARNING: Use array_size" +coccilib.report.print_report(p[0], msg) + diff --git a/tools/coccinelle/badty.cocci b/tools/coccinelle/badty.cocci new file mode 100644 index 0000000000..481cf301cc --- /dev/null +++ b/tools/coccinelle/badty.cocci @@ -0,0 +1,76 @@ +/// Use ARRAY_SIZE instead of dividing sizeof array with sizeof an element +/// +//# This makes an effort to find cases where the argument to sizeof is wrong +//# in memory allocation functions by checking the type of the allocated memory +//# when it is a double pointer and ensuring the sizeof argument takes a pointer +//# to the the memory being allocated. There are false positives in cases the +//# sizeof argument is not used in constructing the return value. The result +//# may need some reformatting. +// +// Confidence: Moderate +// Copyright: (C) 2014 Himangi Saraogi. GPLv2. +// Comments: +// Options: + +virtual patch +virtual context +virtual org +virtual report + +//---------------------------------------------------------- +// For context mode +//---------------------------------------------------------- + +@depends on context disable sizeof_type_expr@ +type T; +T **x; +@@ + + x = + <+...sizeof( +* T + )...+> + +//---------------------------------------------------------- +// For patch mode +//---------------------------------------------------------- + +@depends on patch disable sizeof_type_expr@ +type T; +T **x; +@@ + + x = + <+...sizeof( +- T ++ *x + )...+> + +//---------------------------------------------------------- +// For org and report mode +//---------------------------------------------------------- + +@r depends on (org || report) disable sizeof_type_expr@ +type T; +T **x; +position p; +@@ + + x = + <+...sizeof( + T@p + )...+> + +@script:python depends on org@ +p << r.p; +@@ + +coccilib.org.print_todo(p[0], "WARNING sizeof argument should be pointer type, not structure type") + +@script:python depends on report@ +p << r.p; +@@ + +msg="WARNING: Use correct pointer type argument for sizeof" +coccilib.report.print_report(p[0], msg) + diff --git a/tools/coccinelle/badzero.cocci b/tools/coccinelle/badzero.cocci new file mode 100644 index 0000000000..f597c8007b --- /dev/null +++ b/tools/coccinelle/badzero.cocci @@ -0,0 +1,238 @@ +/// Compare pointer-typed values to NULL rather than 0 +/// +//# This makes an effort to choose between !x and x == NULL. !x is used +//# if it has previously been used with the function used to initialize x. +//# This relies on type information. More type information can be obtained +//# using the option -all_includes and the option -I to specify an +//# include path. +// +// Confidence: High +// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Requires: 1.0.0 +// Options: + +virtual patch +virtual context +virtual org +virtual report + +@initialize:ocaml@ +@@ +let negtable = Hashtbl.create 101 + +@depends on patch@ +expression *E; +identifier f; +@@ + +( + (E = f(...)) == +- 0 ++ NULL +| + (E = f(...)) != +- 0 ++ NULL +| +- 0 ++ NULL + == (E = f(...)) +| +- 0 ++ NULL + != (E = f(...)) +) + + +@t1 depends on !patch@ +expression *E; +identifier f; +position p; +@@ + +( + (E = f(...)) == +* 0@p +| + (E = f(...)) != +* 0@p +| +* 0@p + == (E = f(...)) +| +* 0@p + != (E = f(...)) +) + +@script:python depends on org@ +p << t1.p; +@@ + +coccilib.org.print_todo(p[0], "WARNING comparing pointer to 0") + +@script:python depends on report@ +p << t1.p; +@@ + +coccilib.report.print_report(p[0], "WARNING comparing pointer to 0") + +// Tests of returned values + +@s@ +identifier f; +expression E,E1; +@@ + + E = f(...) + ... when != E = E1 + !E + +@script:ocaml depends on s@ +f << s.f; +@@ + +try let _ = Hashtbl.find negtable f in () +with Not_found -> Hashtbl.add negtable f () + +@ r disable is_zero,isnt_zero exists @ +expression *E; +identifier f; +@@ + +E = f(...) +... +(E == 0 +|E != 0 +|0 == E +|0 != E +) + +@script:ocaml@ +f << r.f; +@@ + +try let _ = Hashtbl.find negtable f in () +with Not_found -> include_match false + +// This rule may lead to inconsistent path problems, if E is defined in two +// places +@ depends on patch disable is_zero,isnt_zero @ +expression *E; +expression E1; +identifier r.f; +@@ + +E = f(...) +<... +( +- E == 0 ++ !E +| +- E != 0 ++ E +| +- 0 == E ++ !E +| +- 0 != E ++ E +) +...> +?E = E1 + +@t2 depends on !patch disable is_zero,isnt_zero @ +expression *E; +expression E1; +identifier r.f; +position p1; +position p2; +@@ + +E = f(...) +<... +( +* E == 0@p1 +| +* E != 0@p2 +| +* 0@p1 == E +| +* 0@p1 != E +) +...> +?E = E1 + +@script:python depends on org@ +p << t2.p1; +@@ + +coccilib.org.print_todo(p[0], "WARNING comparing pointer to 0, suggest !E") + +@script:python depends on org@ +p << t2.p2; +@@ + +coccilib.org.print_todo(p[0], "WARNING comparing pointer to 0") + +@script:python depends on report@ +p << t2.p1; +@@ + +coccilib.report.print_report(p[0], "WARNING comparing pointer to 0, suggest !E") + +@script:python depends on report@ +p << t2.p2; +@@ + +coccilib.report.print_report(p[0], "WARNING comparing pointer to 0") + +@ depends on patch disable is_zero,isnt_zero @ +expression *E; +@@ + +( + E == +- 0 ++ NULL +| + E != +- 0 ++ NULL +| +- 0 ++ NULL + == E +| +- 0 ++ NULL + != E +) + +@ t3 depends on !patch disable is_zero,isnt_zero @ +expression *E; +position p; +@@ + +( +* E == 0@p +| +* E != 0@p +| +* 0@p == E +| +* 0@p != E +) + +@script:python depends on org@ +p << t3.p; +@@ + +coccilib.org.print_todo(p[0], "WARNING comparing pointer to 0") + +@script:python depends on report@ +p << t3.p; +@@ + +coccilib.report.print_report(p[0], "WARNING comparing pointer to 0") diff --git a/tools/coccinelle/boolconv.cocci b/tools/coccinelle/boolconv.cocci new file mode 100644 index 0000000000..33c464d6bc --- /dev/null +++ b/tools/coccinelle/boolconv.cocci @@ -0,0 +1,90 @@ +/// Remove unneeded conversion to bool +/// +//# Relational and logical operators evaluate to bool, +//# explicit conversion is overly verbose and unneeded. +// +// Copyright: (C) 2016 Andrew F. Davis <afd@ti.com> GPLv2. + +virtual patch +virtual context +virtual org +virtual report + +//---------------------------------------------------------- +// For patch mode +//---------------------------------------------------------- + +@depends on patch@ +expression A, B; +symbol true, false; +@@ + +( + A == B +| + A != B +| + A > B +| + A < B +| + A >= B +| + A <= B +| + A && B +| + A || B +) +- ? true : false + +//---------------------------------------------------------- +// For context mode +//---------------------------------------------------------- + +@r depends on !patch@ +expression A, B; +symbol true, false; +position p; +@@ + +( + A == B +| + A != B +| + A > B +| + A < B +| + A >= B +| + A <= B +| + A && B +| + A || B +) +* ? true : false@p + +//---------------------------------------------------------- +// For org mode +//---------------------------------------------------------- + +@script:python depends on r&&org@ +p << r.p; +@@ + +msg = "WARNING: conversion to bool not needed here" +coccilib.org.print_todo(p[0], msg) + +//---------------------------------------------------------- +// For report mode +//---------------------------------------------------------- + +@script:python depends on r&&report@ +p << r.p; +@@ + +msg = "WARNING: conversion to bool not needed here" +coccilib.report.print_report(p[0], msg) diff --git a/tools/coccinelle/boolinit.cocci b/tools/coccinelle/boolinit.cocci new file mode 100644 index 0000000000..aabb581fab --- /dev/null +++ b/tools/coccinelle/boolinit.cocci @@ -0,0 +1,194 @@ +/// Bool initializations should use true and false. Bool tests don't need +/// comparisons. Based on contributions from Joe Perches, Rusty Russell +/// and Bruce W Allan. +/// +// Confidence: High +// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Options: --include-headers + +virtual patch +virtual context +virtual org +virtual report + +@boolok@ +symbol true,false; +@@ +( +true +| +false +) + +@depends on patch@ +bool t; +@@ + +( +- t == true ++ t +| +- true == t ++ t +| +- t != true ++ !t +| +- true != t ++ !t +| +- t == false ++ !t +| +- false == t ++ !t +| +- t != false ++ t +| +- false != t ++ t +) + +@depends on patch disable is_zero, isnt_zero@ +bool t; +@@ + +( +- t == 1 ++ t +| +- t != 1 ++ !t +| +- t == 0 ++ !t +| +- t != 0 ++ t +) + +@depends on patch && boolok@ +bool b; +@@ +( + b = +- 0 ++ false +| + b = +- 1 ++ true +) + +// --------------------------------------------------------------------- + +@r1 depends on !patch@ +bool t; +position p; +@@ + +( +* t@p == true +| +* true == t@p +| +* t@p != true +| +* true != t@p +| +* t@p == false +| +* false == t@p +| +* t@p != false +| +* false != t@p +) + +@r2 depends on !patch disable is_zero, isnt_zero@ +bool t; +position p; +@@ + +( +* t@p == 1 +| +* t@p != 1 +| +* t@p == 0 +| +* t@p != 0 +) + +@r3 depends on !patch && boolok@ +bool b; +position p1; +@@ +( +*b@p1 = 0 +| +*b@p1 = 1 +) + +@r4 depends on !patch@ +bool b; +position p2; +identifier i; +constant c != {0,1}; +@@ +( + b = i +| +*b@p2 = c +) + +@script:python depends on org@ +p << r1.p; +@@ + +cocci.print_main("WARNING: Comparison to bool",p) + +@script:python depends on org@ +p << r2.p; +@@ + +cocci.print_main("WARNING: Comparison of 0/1 to bool variable",p) + +@script:python depends on org@ +p1 << r3.p1; +@@ + +cocci.print_main("WARNING: Assignment of 0/1 to bool variable",p1) + +@script:python depends on org@ +p2 << r4.p2; +@@ + +cocci.print_main("ERROR: Assignment of non-0/1 constant to bool variable",p2) + +@script:python depends on report@ +p << r1.p; +@@ + +coccilib.report.print_report(p[0],"WARNING: Comparison to bool") + +@script:python depends on report@ +p << r2.p; +@@ + +coccilib.report.print_report(p[0],"WARNING: Comparison of 0/1 to bool variable") + +@script:python depends on report@ +p1 << r3.p1; +@@ + +coccilib.report.print_report(p1[0],"WARNING: Assignment of 0/1 to bool variable") + +@script:python depends on report@ +p2 << r4.p2; +@@ + +coccilib.report.print_report(p2[0],"ERROR: Assignment of non-0/1 constant to bool variable") diff --git a/tools/coccinelle/boolreturn.cocci b/tools/coccinelle/boolreturn.cocci new file mode 100644 index 0000000000..29d2bf41e9 --- /dev/null +++ b/tools/coccinelle/boolreturn.cocci @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0 +/// Return statements in functions returning bool should use +/// true/false instead of 1/0. +// +// Confidence: High +// Options: --no-includes --include-headers + +virtual patch +virtual report +virtual context + +@r1 depends on patch@ +identifier fn; +typedef bool; +symbol false; +symbol true; +@@ + +bool fn ( ... ) +{ +<... +return +( +- 0 ++ false +| +- 1 ++ true +) + ; +...> +} + +@r2 depends on report || context@ +identifier fn; +position p; +@@ + +bool fn ( ... ) +{ +<... +return +( +* 0@p +| +* 1@p +) + ; +...> +} + + +@script:python depends on report@ +p << r2.p; +fn << r2.fn; +@@ + +msg = "WARNING: return of 0/1 in function '%s' with return type bool" % fn +coccilib.report.print_report(p[0], msg) diff --git a/tools/coccinelle/cond_no_effect.cocci b/tools/coccinelle/cond_no_effect.cocci new file mode 100644 index 0000000000..8467dbd1c4 --- /dev/null +++ b/tools/coccinelle/cond_no_effect.cocci @@ -0,0 +1,64 @@ +///Find conditions where if and else branch are functionally +// identical. +// +// There can be false positives in cases where the positional +// information is used (as with lockdep) or where the identity +// is a placeholder for not yet handled cases. +// Unfortunately there also seems to be a tendency to use +// the last if else/else as a "default behavior" - which some +// might consider a legitimate coding pattern. From discussion +// on kernelnewbies though it seems that this is not really an +// accepted pattern and if at all it would need to be commented +// +// In the Linux kernel it does not seem to actually report +// false positives except for those that were documented as +// being intentional. +// the two known cases are: +// arch/sh/kernel/traps_64.c:read_opcode() +// } else if ((pc & 1) == 0) { +// /* SHcompact */ +// /* TODO : provide handling for this. We don't really support +// user-mode SHcompact yet, and for a kernel fault, this would +// have to come from a module built for SHcompact. */ +// return -EFAULT; +// } else { +// /* misaligned */ +// return -EFAULT; +// } +// fs/kernfs/file.c:kernfs_fop_open() +// * Both paths of the branch look the same. They're supposed to +// * look that way and give @of->mutex different static lockdep keys. +// */ +// if (has_mmap) +// mutex_init(&of->mutex); +// else +// mutex_init(&of->mutex); +// +// All other cases look like bugs or at least lack of documentation +// +// Confidence: Moderate +// Copyright: (C) 2016 Nicholas Mc Guire, OSADL. GPLv2. +// Comments: +// Options: --no-includes --include-headers + +virtual org +virtual report + +@cond@ +statement S1; +position p; +@@ + +* if@p (...) S1 else S1 + +@script:python depends on org@ +p << cond.p; +@@ + +cocci.print_main("WARNING: possible condition with no effect (if == else)",p) + +@script:python depends on report@ +p << cond.p; +@@ + +coccilib.report.print_report(p[0],"WARNING: possible condition with no effect (if == else)") diff --git a/tools/coccinelle/deref_null.cocci b/tools/coccinelle/deref_null.cocci new file mode 100644 index 0000000000..cbc6184e69 --- /dev/null +++ b/tools/coccinelle/deref_null.cocci @@ -0,0 +1,282 @@ +/// +/// A variable is dereferenced under a NULL test. +/// Even though it is known to be NULL. +/// +// Confidence: Moderate +// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2. +// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. +// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: -I ... -all_includes can give more complete results +// Options: + +virtual context +virtual org +virtual report + +// The following two rules are separate, because both can match a single +// expression in different ways +@pr1 expression@ +expression E; +identifier f; +position p1; +@@ + + (E != NULL && ...) ? <+...E->f@p1...+> : ... + +@pr2 expression@ +expression E; +identifier f; +position p2; +@@ + +( + (E != NULL) && ... && <+...E->f@p2...+> +| + (E == NULL) || ... || <+...E->f@p2...+> +| + sizeof(<+...E->f@p2...+>) +) + +@ifm@ +expression *E; +statement S1,S2; +position p1; +@@ + +if@p1 ((E == NULL && ...) || ...) S1 else S2 + +// For org and report modes + +@r depends on !context && (org || report) exists@ +expression subE <= ifm.E; +expression *ifm.E; +expression E1,E2; +identifier f; +statement S1,S2,S3,S4; +iterator iter; +position p!={pr1.p1,pr2.p2}; +position ifm.p1; +@@ + +if@p1 ((E == NULL && ...) || ...) +{ + ... when != if (...) S1 else S2 +( + iter(subE,...) S4 // no use +| + list_remove_head(E2,subE,...) +| + subE = E1 +| + for(subE = E1;...;...) S4 +| + subE++ +| + ++subE +| + --subE +| + subE-- +| + &subE +| + E->f@p // bad use +) + ... when any + return ...; +} +else S3 + +@script:python depends on !context && !org && report@ +p << r.p; +p1 << ifm.p1; +x << ifm.E; +@@ + +msg="ERROR: %s is NULL but dereferenced." % (x) +coccilib.report.print_report(p[0], msg) +cocci.include_match(False) + +@script:python depends on !context && org && !report@ +p << r.p; +p1 << ifm.p1; +x << ifm.E; +@@ + +msg="ERROR: %s is NULL but dereferenced." % (x) +msg_safe=msg.replace("[","@(").replace("]",")") +cocci.print_main(msg_safe,p) +cocci.include_match(False) + +@s depends on !context && (org || report) exists@ +expression subE <= ifm.E; +expression *ifm.E; +expression E1,E2; +identifier f; +statement S1,S2,S3,S4; +iterator iter; +position p!={pr1.p1,pr2.p2}; +position ifm.p1; +@@ + +if@p1 ((E == NULL && ...) || ...) +{ + ... when != if (...) S1 else S2 +( + iter(subE,...) S4 // no use +| + list_remove_head(E2,subE,...) +| + subE = E1 +| + for(subE = E1;...;...) S4 +| + subE++ +| + ++subE +| + --subE +| + subE-- +| + &subE +| + E->f@p // bad use +) + ... when any +} +else S3 + +@script:python depends on !context && !org && report@ +p << s.p; +p1 << ifm.p1; +x << ifm.E; +@@ + +msg="ERROR: %s is NULL but dereferenced." % (x) +coccilib.report.print_report(p[0], msg) + +@script:python depends on !context && org && !report@ +p << s.p; +p1 << ifm.p1; +x << ifm.E; +@@ + +msg="ERROR: %s is NULL but dereferenced." % (x) +msg_safe=msg.replace("[","@(").replace("]",")") +cocci.print_main(msg_safe,p) + +// For context mode + +@depends on context && !org && !report exists@ +expression subE <= ifm.E; +expression *ifm.E; +expression E1,E2; +identifier f; +statement S1,S2,S3,S4; +iterator iter; +position p!={pr1.p1,pr2.p2}; +position ifm.p1; +@@ + +if@p1 ((E == NULL && ...) || ...) +{ + ... when != if (...) S1 else S2 +( + iter(subE,...) S4 // no use +| + list_remove_head(E2,subE,...) +| + subE = E1 +| + for(subE = E1;...;...) S4 +| + subE++ +| + ++subE +| + --subE +| + subE-- +| + &subE +| +* E->f@p // bad use +) + ... when any + return ...; +} +else S3 + +// The following three rules are duplicates of ifm, pr1 and pr2 respectively. +// It is need because the previous rule as already made a "change". + +@pr11 depends on context && !org && !report expression@ +expression E; +identifier f; +position p1; +@@ + + (E != NULL && ...) ? <+...E->f@p1...+> : ... + +@pr12 depends on context && !org && !report expression@ +expression E; +identifier f; +position p2; +@@ + +( + (E != NULL) && ... && <+...E->f@p2...+> +| + (E == NULL) || ... || <+...E->f@p2...+> +| + sizeof(<+...E->f@p2...+>) +) + +@ifm1 depends on context && !org && !report@ +expression *E; +statement S1,S2; +position p1; +@@ + +if@p1 ((E == NULL && ...) || ...) S1 else S2 + +@depends on context && !org && !report exists@ +expression subE <= ifm1.E; +expression *ifm1.E; +expression E1,E2; +identifier f; +statement S1,S2,S3,S4; +iterator iter; +position p!={pr11.p1,pr12.p2}; +position ifm1.p1; +@@ + +if@p1 ((E == NULL && ...) || ...) +{ + ... when != if (...) S1 else S2 +( + iter(subE,...) S4 // no use +| + list_remove_head(E2,subE,...) +| + subE = E1 +| + for(subE = E1;...;...) S4 +| + subE++ +| + ++subE +| + --subE +| + subE-- +| + &subE +| +* E->f@p // bad use +) + ... when any +} +else S3 diff --git a/tools/coccinelle/double_lock.cocci b/tools/coccinelle/double_lock.cocci new file mode 100644 index 0000000000..002752f97d --- /dev/null +++ b/tools/coccinelle/double_lock.cocci @@ -0,0 +1,92 @@ +/// Find double locks. False positives may occur when some paths cannot +/// occur at execution, due to the values of variables, and when there is +/// an intervening function call that releases the lock. +/// +// Confidence: Moderate +// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2. +// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. +// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: --no-includes --include-headers + +virtual org +virtual report + +@locked@ +position p1; +expression E1; +position p; +@@ + +( +mutex_lock@p1 +| +mutex_trylock@p1 +| +spin_lock@p1 +| +spin_trylock@p1 +| +read_lock@p1 +| +read_trylock@p1 +| +write_lock@p1 +| +write_trylock@p1 +) (E1@p,...); + +@balanced@ +position p1 != locked.p1; +position locked.p; +identifier lock,unlock; +expression x <= locked.E1; +expression E,locked.E1; +expression E2; +@@ + +if (E) { + <+... when != E1 + lock(E1@p,...) + ...+> +} +... when != E1 + when != \(x = E2\|&x\) + when forall +if (E) { + <+... when != E1 + unlock@p1(E1,...) + ...+> +} + +@r depends on !balanced exists@ +expression x <= locked.E1; +expression locked.E1; +expression E2; +identifier lock; +position locked.p,p1,p2; +@@ + +lock@p1 (E1@p,...); +... when != E1 + when != \(x = E2\|&x\) +lock@p2 (E1,...); + +@script:python depends on org@ +p1 << r.p1; +p2 << r.p2; +lock << r.lock; +@@ + +cocci.print_main(lock,p1) +cocci.print_secs("second lock",p2) + +@script:python depends on report@ +p1 << r.p1; +p2 << r.p2; +lock << r.lock; +@@ + +msg = "second lock on line %s" % (p2[0].line) +coccilib.report.print_report(p1[0],msg) diff --git a/tools/coccinelle/doublebitand.cocci b/tools/coccinelle/doublebitand.cocci new file mode 100644 index 0000000000..72f1572aae --- /dev/null +++ b/tools/coccinelle/doublebitand.cocci @@ -0,0 +1,54 @@ +/// Find bit operations that include the same argument more than once +//# One source of false positives is when the argument performs a side +//# effect. Another source of false positives is when a neutral value +//# such as 0 for | is used to indicate no information, to maintain the +//# same structure as other similar expressions +/// +// Confidence: Moderate +// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2. +// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. +// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: --no-includes --include-headers + +virtual context +virtual org +virtual report + +@r expression@ +expression E; +position p; +@@ + +( +* E@p + & ... & E +| +* E@p + | ... | E +| +* E@p + & ... & !E +| +* E@p + | ... | !E +| +* !E@p + & ... & E +| +* !E@p + | ... | E +) + +@script:python depends on org@ +p << r.p; +@@ + +cocci.print_main("duplicated argument to & or |",p) + +@script:python depends on report@ +p << r.p; +@@ + +coccilib.report.print_report(p[0],"duplicated argument to & or |") diff --git a/tools/coccinelle/doubleinit.cocci b/tools/coccinelle/doubleinit.cocci new file mode 100644 index 0000000000..c0c3371d25 --- /dev/null +++ b/tools/coccinelle/doubleinit.cocci @@ -0,0 +1,53 @@ +/// Find duplicate field initializations. This has a high rate of false +/// positives due to #ifdefs, which Coccinelle is not aware of in a structure +/// initialization. +/// +// Confidence: Low +// Copyright: (C) 2010-2012 Nicolas Palix. GPLv2. +// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: requires at least Coccinelle 0.2.4, lex or parse error otherwise +// Options: --no-includes --include-headers + +virtual org +virtual report + +@r@ +identifier I, s, fld; +position p0,p; +expression E; +@@ + +struct I s =@p0 { ..., .fld@p = E, ...}; + +@s@ +identifier I, s, r.fld; +position r.p0,p; +expression E; +@@ + +struct I s =@p0 { ..., .fld@p = E, ...}; + +@script:python depends on org@ +p0 << r.p0; +fld << r.fld; +ps << s.p; +pr << r.p; +@@ + +if int(ps[0].line) < int(pr[0].line) or (int(ps[0].line) == int(pr[0].line) and int(ps[0].column) < int(pr[0].column)): + cocci.print_main(fld,p0) + cocci.print_secs("s",ps) + cocci.print_secs("r",pr) + +@script:python depends on report@ +p0 << r.p0; +fld << r.fld; +ps << s.p; +pr << r.p; +@@ + +if int(ps[0].line) < int(pr[0].line) or (int(ps[0].line) == int(pr[0].line) and int(ps[0].column) < int(pr[0].column)): + msg = "%s: first occurrence line %s, second occurrence line %s" % (fld,ps[0].line,pr[0].line) + coccilib.report.print_report(p0[0],msg) diff --git a/tools/coccinelle/doubletest.cocci b/tools/coccinelle/doubletest.cocci new file mode 100644 index 0000000000..7af2ce7eb9 --- /dev/null +++ b/tools/coccinelle/doubletest.cocci @@ -0,0 +1,58 @@ +/// Find &&/|| operations that include the same argument more than once +//# A common source of false positives is when the expression, or +//# another expresssion in the same && or || operation, performs a +//# side effect. +/// +// Confidence: Moderate +// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2. +// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. +// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: --no-includes --include-headers + +virtual context +virtual org +virtual report + +@r expression@ +expression E; +position p; +@@ + +( + E@p || ... || E +| + E@p && ... && E +) + +@bad@ +expression r.E,e1,e2,fn; +position r.p; +assignment operator op; +@@ + +( +E@p +& + <+... \(fn(...)\|e1 op e2\|e1++\|e1--\|++e1\|--e1\) ...+> +) + +@depends on context && !bad@ +expression r.E; +position r.p; +@@ + +*E@p + +@script:python depends on org && !bad@ +p << r.p; +@@ + +cocci.print_main("duplicated argument to && or ||",p) + +@script:python depends on report && !bad@ +p << r.p; +@@ + +coccilib.report.print_report(p[0],"duplicated argument to && or ||") diff --git a/tools/coccinelle/ifaddr.cocci b/tools/coccinelle/ifaddr.cocci new file mode 100644 index 0000000000..c2663c677a --- /dev/null +++ b/tools/coccinelle/ifaddr.cocci @@ -0,0 +1,34 @@ +/// The address of a variable or field is likely always to be non-zero. +/// +// Confidence: High +// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: --no-includes --include-headers + +virtual org +virtual report +virtual context + +@r@ +expression x; +statement S1,S2; +position p; +@@ + +*if@p (&x) + S1 else S2 + +@script:python depends on org@ +p << r.p; +@@ + +cocci.print_main("test of a variable/field address",p) + +@script:python depends on report@ +p << r.p; +@@ + +msg = "ERROR: test of a variable/field address" +coccilib.report.print_report(p[0],msg) diff --git a/tools/coccinelle/ifnullxfree.cocci b/tools/coccinelle/ifnullxfree.cocci new file mode 100644 index 0000000000..85fc23e394 --- /dev/null +++ b/tools/coccinelle/ifnullxfree.cocci @@ -0,0 +1,15 @@ +/// NULL check before some freeing functions is not needed. +/// +// Copyright: (C) 2014 Fabian Frederick. GPLv2. +// Copyright: (C) 2019 Quentin Young. GPLv2. +// Comments: - +// Options: --no-includes --include-headers + +virtual patch + +@r2 depends on patch@ +expression E; +expression Y; +@@ +- if (E != NULL) +XFREE(Y, E); diff --git a/tools/coccinelle/itnull.cocci b/tools/coccinelle/itnull.cocci new file mode 100644 index 0000000000..f58732b56a --- /dev/null +++ b/tools/coccinelle/itnull.cocci @@ -0,0 +1,94 @@ +/// Many iterators have the property that the first argument is always bound +/// to a real list element, never NULL. +//# False positives arise for some iterators that do not have this property, +//# or in cases when the loop cursor is reassigned. The latter should only +//# happen when the matched code is on the way to a loop exit (break, goto, +//# or return). +/// +// Confidence: Moderate +// Copyright: (C) 2010-2012 Nicolas Palix. GPLv2. +// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: --no-includes --include-headers + +virtual patch +virtual context +virtual org +virtual report + +@depends on patch@ +iterator I; +expression x,E,E1,E2; +statement S,S1,S2; +@@ + +I(x,...) { <... +( +- if (x == NULL && ...) S +| +- if (x != NULL || ...) + S +| +- (x == NULL) || + E +| +- (x != NULL) && + E +| +- (x == NULL && ...) ? E1 : + E2 +| +- (x != NULL || ...) ? + E1 +- : E2 +| +- if (x == NULL && ...) S1 else + S2 +| +- if (x != NULL || ...) + S1 +- else S2 +| ++ BAD( + x == NULL ++ ) +| ++ BAD( + x != NULL ++ ) +) + ...> } + +@r depends on !patch exists@ +iterator I; +expression x,E; +position p1,p2; +@@ + +*I@p1(x,...) +{ ... when != x = E +( +* x@p2 == NULL +| +* x@p2 != NULL +) + ... when any +} + +@script:python depends on org@ +p1 << r.p1; +p2 << r.p2; +@@ + +cocci.print_main("iterator-bound variable",p1) +cocci.print_secs("useless NULL test",p2) + +@script:python depends on report@ +p1 << r.p1; +p2 << r.p2; +@@ + +msg = "ERROR: iterator variable bound on line %s cannot be NULL" % (p1[0].line) +coccilib.report.print_report(p2[0], msg) diff --git a/tools/coccinelle/mini_lock.cocci b/tools/coccinelle/mini_lock.cocci new file mode 100644 index 0000000000..19c6ee5b98 --- /dev/null +++ b/tools/coccinelle/mini_lock.cocci @@ -0,0 +1,98 @@ +/// Find missing unlocks. This semantic match considers the specific case +/// where the unlock is missing from an if branch, and there is a lock +/// before the if and an unlock after the if. False positives are due to +/// cases where the if branch represents a case where the function is +/// supposed to exit with the lock held, or where there is some preceding +/// function call that releases the lock. +/// +// Confidence: Moderate +// Copyright: (C) 2010-2012 Nicolas Palix. GPLv2. +// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: --no-includes --include-headers + +virtual context +virtual org +virtual report + +@prelocked@ +position p1,p; +expression E1; +@@ + +( +mutex_lock@p1 +| +mutex_trylock@p1 +| +spin_lock@p1 +| +spin_trylock@p1 +| +read_lock@p1 +| +read_trylock@p1 +| +write_lock@p1 +| +write_trylock@p1 +| +read_lock_irq@p1 +| +write_lock_irq@p1 +| +read_lock_irqsave@p1 +| +write_lock_irqsave@p1 +| +spin_lock_irq@p1 +| +spin_lock_irqsave@p1 +) (E1@p,...); + +@looped@ +position r; +@@ + +for(...;...;...) { <+... return@r ...; ...+> } + +@err exists@ +expression E1; +position prelocked.p; +position up != prelocked.p1; +position r!=looped.r; +identifier lock,unlock; +@@ + +*lock(E1@p,...); +... when != E1 + when any +if (...) { + ... when != E1 +* return@r ...; +} +... when != E1 + when any +*unlock@up(E1,...); + +@script:python depends on org@ +p << prelocked.p1; +lock << err.lock; +unlock << err.unlock; +p2 << err.r; +@@ + +cocci.print_main(lock,p) +cocci.print_secs(unlock,p2) + +@script:python depends on report@ +p << prelocked.p1; +lock << err.lock; +unlock << err.unlock; +p2 << err.r; +@@ + +msg = "preceding lock on line %s" % (p[0].line) +coccilib.report.print_report(p2[0],msg) diff --git a/tools/coccinelle/noderef.cocci b/tools/coccinelle/noderef.cocci new file mode 100644 index 0000000000..ca289d5741 --- /dev/null +++ b/tools/coccinelle/noderef.cocci @@ -0,0 +1,81 @@ +/// sizeof when applied to a pointer typed expression gives the size of +/// the pointer +/// +// Confidence: High +// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: --no-includes --include-headers + +virtual org +virtual report +virtual context +virtual patch + +@depends on patch@ +expression *x; +expression f; +expression i; +type T; +@@ + +( +x = <+... sizeof( +- x ++ *x + ) ...+> +| +f(...,(T)(x),...,sizeof( +- x ++ *x + ),...) +| +f(...,sizeof( +- x ++ *x + ),...,(T)(x),...) +| +f(...,(T)(x),...,i*sizeof( +- x ++ *x + ),...) +| +f(...,i*sizeof( +- x ++ *x + ),...,(T)(x),...) +) + +@r depends on !patch@ +expression *x; +expression f; +expression i; +position p; +type T; +@@ + +( +*x = <+... sizeof@p(x) ...+> +| +*f(...,(T)(x),...,sizeof@p(x),...) +| +*f(...,sizeof@p(x),...,(T)(x),...) +| +*f(...,(T)(x),...,i*sizeof@p(x),...) +| +*f(...,i*sizeof@p(x),...,(T)(x),...) +) + +@script:python depends on org@ +p << r.p; +@@ + +cocci.print_main("application of sizeof to pointer",p) + +@script:python depends on report@ +p << r.p; +@@ + +msg = "ERROR: application of sizeof to pointer" +coccilib.report.print_report(p[0],msg)<Paste> diff --git a/tools/coccinelle/replace-strncpy.cocci b/tools/coccinelle/replace-strncpy.cocci new file mode 100644 index 0000000000..18ff1314b0 --- /dev/null +++ b/tools/coccinelle/replace-strncpy.cocci @@ -0,0 +1,8 @@ +@@ +type T; +T[] E; +expression buf, srclen; +@@ + +- strncpy(E, src, srclen) ++ strlcpy(E, src, sizeof(E)) diff --git a/tools/coccinelle/returnvar.cocci b/tools/coccinelle/returnvar.cocci new file mode 100644 index 0000000000..d8286ef530 --- /dev/null +++ b/tools/coccinelle/returnvar.cocci @@ -0,0 +1,66 @@ +/// +/// Remove unneeded variable used to store return value. +/// +// Confidence: Moderate +// Copyright: (C) 2012 Peter Senna Tschudin, INRIA/LIP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: Comments on code can be deleted if near code that is removed. +// "when strict" can be removed to get more hits, but adds false +// positives +// Options: --no-includes --include-headers + +virtual patch +virtual report +virtual context +virtual org + +@depends on patch@ +type T; +constant C; +identifier ret; +@@ +- T ret = C; +... when != ret + when strict +return +- ret ++ C +; + +@depends on context@ +type T; +constant C; +identifier ret; +@@ +* T ret = C; +... when != ret + when strict +* return ret; + +@r1 depends on report || org@ +type T; +constant C; +identifier ret; +position p1, p2; +@@ +T ret@p1 = C; +... when != ret + when strict +return ret@p2; + +@script:python depends on report@ +p1 << r1.p1; +p2 << r1.p2; +C << r1.C; +ret << r1.ret; +@@ +coccilib.report.print_report(p1[0], "Unneeded variable: \"" + ret + "\". Return \"" + C + "\" on line " + p2[0].line) + +@script:python depends on org@ +p1 << r1.p1; +p2 << r1.p2; +C << r1.C; +ret << r1.ret; +@@ +cocci.print_main("unneeded \"" + ret + "\" variable", p1) +cocci.print_sec("return " + C + " here", p2) diff --git a/tools/coccinelle/semicolon.cocci b/tools/coccinelle/semicolon.cocci new file mode 100644 index 0000000000..6740c659a2 --- /dev/null +++ b/tools/coccinelle/semicolon.cocci @@ -0,0 +1,83 @@ +/// +/// Remove unneeded semicolon. +/// +// Confidence: Moderate +// Copyright: (C) 2012 Peter Senna Tschudin, INRIA/LIP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: Some false positives on empty default cases in switch statements. +// Options: --no-includes --include-headers + +virtual patch +virtual report +virtual context +virtual org + +@r_default@ +position p; +@@ +switch (...) +{ +default: ...;@p +} + +@r_case@ +position p; +@@ +( +switch (...) +{ +case ...:;@p +} +| +switch (...) +{ +case ...:... +case ...:;@p +} +| +switch (...) +{ +case ...:... +case ...: +case ...:;@p +} +) + +@r1@ +statement S; +position p1; +position p != {r_default.p, r_case.p}; +identifier label; +@@ +( +label:; +| +S@p1;@p +) + +@script:python@ +p << r1.p; +p1 << r1.p1; +@@ +if p[0].line != p1[0].line_end: + cocci.include_match(False) + +@depends on patch@ +position r1.p; +@@ +-;@p + +@script:python depends on report@ +p << r1.p; +@@ +coccilib.report.print_report(p[0],"Unneeded semicolon") + +@depends on context@ +position r1.p; +@@ +*;@p + +@script:python depends on org@ +p << r1.p; +@@ +cocci.print_main("Unneeded semicolon",p) diff --git a/tools/coccinelle/strncpy_truncation.cocci b/tools/coccinelle/strncpy_truncation.cocci new file mode 100644 index 0000000000..28b5c2a290 --- /dev/null +++ b/tools/coccinelle/strncpy_truncation.cocci @@ -0,0 +1,41 @@ +/// Use strlcpy rather than strncpy(dest,..,sz) + dest[sz-1] = '\0' +/// +// Confidence: High +// Comments: +// Options: --no-includes --include-headers + +virtual patch +virtual context +virtual report +virtual org + +@r@ +expression dest, src, sz; +position p; +@@ + +strncpy@p(dest, src, sz); +dest[sz - 1] = '\0'; + +@script:python depends on org@ +p << r.p; +@@ + +cocci.print_main("strncpy followed by truncation can be strlcpy",p) + +@script:python depends on report@ +p << r.p; +@@ + +msg = "SUGGESTION: strncpy followed by truncation can be strlcpy" +coccilib.report.print_report(p[0],msg) + +@ok depends on patch@ +expression r.dest, r.src, r.sz; +position r.p; +@@ + +-strncpy@p( ++strlcpy( + dest, src, sz); +-dest[sz - 1] = '\0'; diff --git a/tools/coccinelle/unsigned_lesser_than_zero.cocci b/tools/coccinelle/unsigned_lesser_than_zero.cocci new file mode 100644 index 0000000000..8fa5a3c7b7 --- /dev/null +++ b/tools/coccinelle/unsigned_lesser_than_zero.cocci @@ -0,0 +1,75 @@ +/// Unsigned expressions cannot be lesser than zero. Presence of +/// comparisons 'unsigned (<|<=|>|>=) 0' often indicates a bug, +/// usually wrong type of variable. +/// +/// To reduce number of false positives following tests have been added: +/// - parts of range checks are skipped, eg. "if (u < 0 || u > 15) ...", +/// developers prefer to keep such code, +/// - comparisons "<= 0" and "> 0" are performed only on results of +/// signed functions/macros, +/// - hardcoded list of signed functions/macros with always non-negative +/// result is used to avoid false positives difficult to detect by other ways +/// +// Confidence: Average +// Copyright: (C) 2015 Andrzej Hajda, Samsung Electronics Co., Ltd. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Options: --all-includes + +virtual context +virtual org +virtual report + +@r_cmp@ +position p; +typedef bool, u8, u16, u32, u64; +{unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long, + size_t, bool, u8, u16, u32, u64} v; +expression e; +@@ + + \( v = e \| &v \) + ... + (\( v@p < 0 \| v@p <= 0 \| v@p >= 0 \| v@p > 0 \)) + +@r@ +position r_cmp.p; +typedef s8, s16, s32, s64; +{char, short, int, long, long long, ssize_t, s8, s16, s32, s64} vs; +expression c, e, v; +identifier f !~ "^(ata_id_queue_depth|btrfs_copy_from_user|dma_map_sg|dma_map_sg_attrs|fls|fls64|gameport_time|get_write_extents|nla_len|ntoh24|of_flat_dt_match|of_get_child_count|uart_circ_chars_pending|[A-Z0-9_]+)$"; +@@ + +( + v = f(...)@vs; + ... when != v = e; +* (\( v@p <=@e 0 \| v@p >@e 0 \)) + ... when any +| +( + (\( v@p < 0 \| v@p <= 0 \)) || ... || (\( v >= c \| v > c \)) +| + (\( v >= c \| v > c \)) || ... || (\( v@p < 0 \| v@p <= 0 \)) +| + (\( v@p >= 0 \| v@p > 0 \)) && ... && (\( v < c \| v <= c \)) +| + ((\( v < c \| v <= c \) && ... && \( v@p >= 0 \| v@p > 0 \))) +| +* (\( v@p <@e 0 \| v@p >=@e 0 \)) +) +) + +@script:python depends on org@ +p << r_cmp.p; +e << r.e; +@@ + +msg = "WARNING: Unsigned expression compared with zero: %s" % (e) +coccilib.org.print_todo(p[0], msg) + +@script:python depends on report@ +p << r_cmp.p; +e << r.e; +@@ + +msg = "WARNING: Unsigned expression compared with zero: %s" % (e) +coccilib.report.print_report(p[0], msg) diff --git a/tools/vty_check.cocci b/tools/coccinelle/vty_check.cocci index 7e5fcc405b..7e5fcc405b 100644 --- a/tools/vty_check.cocci +++ b/tools/coccinelle/vty_check.cocci diff --git a/tools/vty_index.cocci b/tools/coccinelle/vty_index.cocci index eabbaa1aa5..eabbaa1aa5 100644 --- a/tools/vty_index.cocci +++ b/tools/coccinelle/vty_index.cocci diff --git a/tools/coccinelle/xcalloc-simple.cocci b/tools/coccinelle/xcalloc-simple.cocci new file mode 100644 index 0000000000..5be4dafb2b --- /dev/null +++ b/tools/coccinelle/xcalloc-simple.cocci @@ -0,0 +1,52 @@ +/// +/// Use zeroing allocator rather than allocator followed by memset with 0 +/// +/// This considers some simple cases that are common and easy to validate +/// Note in particular that there are no ...s in the rule, so all of the +/// matched code has to be contiguous +/// +// Confidence: High +// Copyright: (C) 2009-2010 Julia Lawall, Nicolas Palix, DIKU. GPLv2. +// Copyright: (C) 2009-2010 Gilles Muller, INRIA/LiP6. GPLv2. +// Copyright: (C) 2017 Himanshu Jha GPLv2. +// Copyright: (C) 2019 Quentin Young. GPLv2. +// URL: http://coccinelle.lip6.fr/rules/kzalloc.html +// Options: --no-includes --include-headers +// +// Keywords: XMALLOC, XCALLOC +// Version min: < 2.6.12 kmalloc +// Version min: 2.6.14 kzalloc +// + +virtual context +virtual patch + +//---------------------------------------------------------- +// For context mode +//---------------------------------------------------------- + +@depends on context@ +type T, T2; +expression x; +expression E1; +expression t; +@@ + +* x = (T)XMALLOC(t, E1); +* memset((T2)x,0,E1); + +//---------------------------------------------------------- +// For patch mode +//---------------------------------------------------------- + +@depends on patch@ +type T, T2; +expression x; +expression E1; +expression t; +@@ + +- x = (T)XMALLOC(t, E1); ++ x = (T)XCALLOC(t, E1); +- memset((T2)x,0,E1); + diff --git a/tools/coccinelle/xfree.cocci b/tools/coccinelle/xfree.cocci new file mode 100644 index 0000000000..eb38f0d5a8 --- /dev/null +++ b/tools/coccinelle/xfree.cocci @@ -0,0 +1,122 @@ +/// Find a use after free. +//# Values of variables may imply that some +//# execution paths are not possible, resulting in false positives. +//# Another source of false positives are macros such as +//# SCTP_DBG_OBJCNT_DEC that do not actually evaluate their argument +/// +// Confidence: Moderate +// Copyright: (C) 2010-2012 Nicolas Palix. GPLv2. +// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. GPLv2. +// Copyright: (C) 2019 Quentin Young. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: --no-includes --include-headers + +virtual org +virtual report + +@free@ +expression E, t; +position p1; +@@ + +* XFREE@p1(t, E) + +@print expression@ +constant char [] c; +expression free.E,E2; +type T; +position p; +identifier f; +@@ + +( + f(...,c,...,(T)E@p,...) +| + E@p == E2 +| + E@p != E2 +| + E2 == E@p +| + E2 != E@p +| + !E@p +| + E@p || ... +) + +@sz@ +expression free.E; +position p; +@@ + + sizeof(<+...E@p...+>) + +@loop exists@ +expression E, t; +identifier l; +position ok; +@@ + +while (1) { ... +* XFREE@ok(t, E) + ... when != break; + when != goto l; + when forall +} + +@r exists@ +expression free.E, subE<=free.E, E2; +expression E1; +iterator iter; +statement S; +position free.p1!=loop.ok,p2!={print.p,sz.p}; +@@ + +* XFREE@p1(t, E) +... +( + iter(...,subE,...) S // no use +| + list_remove_head(E1,subE,...) +| + subE = E2 +| + subE++ +| + ++subE +| + --subE +| + subE-- +| + &subE +| + BUG(...) +| + BUG_ON(...) +| + return_VALUE(...) +| + return_ACPI_STATUS(...) +| + E@p2 // bad use +) + +@script:python depends on org@ +p1 << free.p1; +p2 << r.p2; +@@ + +cocci.print_main("kfree",p1) +cocci.print_secs("ref",p2) + +@script:python depends on report@ +p1 << free.p1; +p2 << r.p2; +@@ + +msg = "ERROR: reference preceded by free on line %s" % (p1[0].line) +coccilib.report.print_report(p2[0],msg) diff --git a/tools/coccinelle/xfreeaddr.cocci b/tools/coccinelle/xfreeaddr.cocci new file mode 100644 index 0000000000..c99c7ac3f5 --- /dev/null +++ b/tools/coccinelle/xfreeaddr.cocci @@ -0,0 +1,33 @@ +/// Free of a structure field +/// +// Confidence: High +// Copyright: (C) 2013 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2019 Quentin Young. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: --no-includes --include-headers + +virtual org +virtual report +virtual context + +@r depends on context || report || org @ +expression e, t; +identifier f; +position p; +@@ + +* XFREE@p(t, &e->f) + +@script:python depends on org@ +p << r.p; +@@ + +cocci.print_main("XFREE",p) + +@script:python depends on report@ +p << r.p; +@@ + +msg = "ERROR: invalid free of structure field" +coccilib.report.print_report(p[0],msg) diff --git a/tools/coccinelle/xmalloc_returnval.cocci b/tools/coccinelle/xmalloc_returnval.cocci new file mode 100644 index 0000000000..8e0ad1027d --- /dev/null +++ b/tools/coccinelle/xmalloc_returnval.cocci @@ -0,0 +1,37 @@ +/// XMALLOC, XCALLOC etc either return non-null, or abort the program. +/// Never nullcheck these. +// +// Copyright: (C) 2019 Quentin Young. GPLv2. + +virtual patch + +//---------------------------------------------------------- +// For patch mode +//---------------------------------------------------------- + +@depends on patch@ +identifier alloc; +@@ + +alloc = XMALLOC(...); + +... + +- if (alloc == NULL) +- { +- ... +- } + +@depends on patch@ +identifier alloc; +@@ + +alloc = XCALLOC(...); + +... + +- if (alloc == NULL) +- { +- ... +- } + diff --git a/tools/zprivs.cocci b/tools/coccinelle/zprivs.cocci index 76d13c3f0d..76d13c3f0d 100644 --- a/tools/zprivs.cocci +++ b/tools/coccinelle/zprivs.cocci diff --git a/tools/etc/frr/daemons b/tools/etc/frr/daemons index 2d56fe1b98..2abff422c9 100644 --- a/tools/etc/frr/daemons +++ b/tools/etc/frr/daemons @@ -5,7 +5,7 @@ # # ATTENTION: # -# When activation a daemon at the first time, a config file, even if it is +# When activating a daemon for the first time, a config file, even if it is # empty, has to be present *and* be owned by the user and group "frr", else # the daemon will not be started by /etc/init.d/frr. The permissions should # be u=rw,g=r,o=. @@ -55,7 +55,7 @@ bfdd_options=" -A 127.0.0.1" fabricd_options="-A 127.0.0.1" # The list of daemons to watch is automatically generated by the init script. -watchfrr_options="-r '/usr/lib/frr/watchfrr.sh restart %s' -s '/usr/lib/frr/watchfrr.sh start %s' -k '/usr/lib/frr/watchfrr.sh stop %s'" +#watchfrr_options="" # for debugging purposes, you can specify a "wrap" command to start instead # of starting the daemon directly, e.g. to use valgrind on ospfd: diff --git a/tools/etc/frr/support_bundle_commands.conf b/tools/etc/frr/support_bundle_commands.conf new file mode 100644 index 0000000000..d52824ff07 --- /dev/null +++ b/tools/etc/frr/support_bundle_commands.conf @@ -0,0 +1,83 @@ +# FRR Support Bundle Command List +# Do Not modify the lines that start with +# PROC_NAME, CMD_LIST_START and CMD_LIST_END +# Add the new command for each process between +# CMD_LIST_START and CMD_LIST_END lines + +# BGP Support Bundle Command List +PROC_NAME:bgp +CMD_LIST_START +show bgp summary +show ip bgp +show ip bgp neighbors +show ip bgp summary +show ip bgp statistics + +show ip bgp update-groups advertise-queue +show ip bgp update-groups advertised-routes +show ip bgp update-groups packet-queue +show ip bgp update-groups statistics +show ip bgp peer-group +show ip bgp memory + +show bgp ipv6 +show bgp ipv6 neighbors +show bgp ipv6 summary +show bgp ipv6 update-groups advertise-queue +show bgp ipv6 update-groups advertised-routes +show bgp ipv6 update-groups packet-queue +show bgp ipv6 update-groups statistics +show ip bgp statistics + +show bgp evpn route +CMD_LIST_END + +# Zebra Support Bundle Command List +PROC_NAME:zebra +CMD_LIST_START +show zebra +show zebra client summary +show ip route + +show route-map +show memory +show interface +show vrf +show error all +show work-queues +show running-config +show thread cpu +show thread poll +show daemons +show version +CMD_LIST_END + +# OSPF Support Bundle Command List +# PROC_NAME:ospf +# CMD_LIST_START +# CMD_LIST_END + +# RIP Support Bundle Command List +# PROC_NAME:rip +# CMD_LIST_START +# CMD_LIST_END + +# ISIS Support Bundle Command List +# PROC_NAME:isis +# CMD_LIST_START +# CMD_LIST_END + +# BFD Support Bundle Command List +# PROC_NAME:bfd +# CMD_LIST_START +# CMD_LIST_END + +# STATIC Support Bundle Command List +# PROC_NAME:static +# CMD_LIST_START +# CMD_LIST_END + +# PIM Support Bundle Command List +# PROC_NAME:pim +# CMD_LIST_START +# CMD_LIST_END diff --git a/tools/frr-reload.py b/tools/frr-reload.py index c48c8b97ad..59f1bcf52b 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -300,13 +300,11 @@ class Config(object): ''' More fixups in user specification and what running config shows. - "null0" in routes must be replaced by Null0, and "blackhole" must - be replaced by Null0 as well. + "null0" in routes must be replaced by Null0. ''' if (key[0].startswith('ip route') or key[0].startswith('ipv6 route') and - 'null0' in key[0] or 'blackhole' in key[0]): + 'null0' in key[0]): key[0] = re.sub(r'\s+null0(\s*$)', ' Null0', key[0]) - key[0] = re.sub(r'\s+blackhole(\s*$)', ' Null0', key[0]) if lines: if tuple(key) not in self.contexts: @@ -435,7 +433,7 @@ end self.save_contexts(ctx_keys, current_context_lines) new_ctx = True - elif line in ["end", "exit-vrf"]: + elif line == "end": self.save_contexts(ctx_keys, current_context_lines) log.debug('LINE %-50s: exiting old context, %-50s', line, ctx_keys) @@ -445,6 +443,17 @@ end ctx_keys = [] current_context_lines = [] + elif line == "exit-vrf": + self.save_contexts(ctx_keys, current_context_lines) + current_context_lines.append(line) + log.debug('LINE %-50s: append to current_context_lines, %-50s', line, ctx_keys) + + #Start a new context + new_ctx = True + main_ctx_key = [] + ctx_keys = [] + current_context_lines = [] + elif line in ["exit-address-family", "exit", "exit-vnc"]: # if this exit is for address-family ipv4 unicast, ignore the pop if main_ctx_key: diff --git a/tools/frrcommon.sh.in b/tools/frrcommon.sh.in index fa2fdc94b2..897e6d6558 100644 --- a/tools/frrcommon.sh.in +++ b/tools/frrcommon.sh.in @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # # This is a "library" of sorts for use by the other FRR shell scripts. It # has most of the daemon start/stop logic, but expects the following shell @@ -67,9 +67,9 @@ vtysh_b () { daemon_inst() { # note this sets global variables ($dmninst, $daemon, $inst) dmninst="$1" - daemon="${dmninst%:*}" + daemon="${dmninst%-*}" inst="" - [ "$daemon" != "$dmninst" ] && inst="${dmninst#*:}" + [ "$daemon" != "$dmninst" ] && inst="${dmninst#*-}" } daemon_list() { @@ -85,13 +85,19 @@ daemon_list() { eval inst=\$${daemon}_instances [ "$daemon" = zebra -o "$daemon" = staticd ] && cfg=yes if [ -n "$cfg" -a "$cfg" != "no" -a "$cfg" != "0" ]; then + if ! daemon_prep "$daemon" "$inst"; then + continue + fi debug "$daemon enabled" enabled="$enabled $daemon" if [ -n "$inst" ]; then debug "$daemon multi-instance $inst" + oldifs="${IFS}" + IFS="${IFS}," for i in $inst; do - enabled="$enabled $daemon:$inst" + enabled="$enabled $daemon-$i" done + IFS="${oldifs}" fi else debug "$daemon disabled" @@ -116,7 +122,7 @@ daemon_prep() { inst="$2" [ "$daemon" = "watchfrr" ] && return 0 [ -x "$D_PATH/$daemon" ] || { - log_failure_msg "cannot start $daemon${inst:+ (instance $inst)}: daemon binary not installed\n" + log_failure_msg "cannot start $daemon${inst:+ (instance $inst)}: daemon binary not installed" return 1 } [ -r "$C_PATH/frr.conf" ] && return 0 @@ -276,7 +282,7 @@ load_old_config() { } [ -r "$C_PATH/daemons" ] || { - log_failure_msg "cannot run $@: $C_PATH/daemons does not exist\n" + log_failure_msg "cannot run $@: $C_PATH/daemons does not exist" exit 1 } . "$C_PATH/daemons" @@ -285,6 +291,13 @@ load_old_config "$C_PATH/daemons.conf" load_old_config "/etc/default/frr" load_old_config "/etc/sysconfig/frr" +if { declare -p watchfrr_options 2>/dev/null || true; } | grep -q '^declare \-a'; then + log_warning_msg "watchfrr_options contains a bash array value." \ + "The configured value is intentionally ignored since it is likely wrong." \ + "Please remove or fix the setting." + unset watchfrr_options +fi + # # other defaults and dispatch # diff --git a/tools/frrinit.sh.in b/tools/frrinit.sh.in index 3dddf5bd44..0f5ed85864 100644 --- a/tools/frrinit.sh.in +++ b/tools/frrinit.sh.in @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # ### BEGIN INIT INFO # Provides: frr diff --git a/tools/gen_northbound_callbacks.c b/tools/gen_northbound_callbacks.c index eded87c12e..f6c757f5d7 100644 --- a/tools/gen_northbound_callbacks.c +++ b/tools/gen_northbound_callbacks.c @@ -54,7 +54,7 @@ static struct nb_callback_info { "enum nb_event event, const struct lyd_node *dnode, union nb_resource *resource", }, { - .operation = NB_OP_DELETE, + .operation = NB_OP_DESTROY, .return_type = "int ", .return_value = "NB_OK", .arguments = diff --git a/tools/generate_support_bundle.py b/tools/generate_support_bundle.py new file mode 100644 index 0000000000..118ca113a5 --- /dev/null +++ b/tools/generate_support_bundle.py @@ -0,0 +1,110 @@ +######################################################## +### Python Script to generate the FRR support bundle ### +######################################################## +import os +import subprocess +import datetime + +TOOLS_DIR="tools/" +ETC_DIR="/etc/frr/" +LOG_DIR="/var/log/frr/" +SUCCESS = 1 +FAIL = 0 + +inputFile = ETC_DIR + "support_bundle_commands.conf" + +# Open support bundle configuration file +def openConfFile(i_file): + try: + with open(i_file) as supportBundleConfFile: + lines = filter(None, (line.rstrip() for line in supportBundleConfFile)) + return lines + except IOError: + return ([]) + +# Create the output file name +def createOutputFile(procName): + fileName = procName + "_support_bundle.log" + oldFile = LOG_DIR + fileName + cpFileCmd = "cp " + oldFile + " " + oldFile + ".prev" + rmFileCmd = "rm -rf " + oldFile + print "Making backup of " + oldFile + os.system(cpFileCmd) + print "Removing " + oldFile + os.system(rmFileCmd) + return fileName + +# Open the output file for this process +def openOutputFile(fileName): + crt_file_cmd = LOG_DIR + fileName + print crt_file_cmd + try: + outputFile = open(crt_file_cmd, "w") + return outputFile + except IOError: + return () + +# Close the output file for this process +def closeOutputFile(file): + try: + file.close() + return SUCCESS + except IOError: + return FAIL + +# Execute the command over vtysh and store in the +# output file +def executeCommand(cmd, outputFile): + cmd_exec_str = "vtysh -c \"" + cmd + "\" " + try: + cmd_output = subprocess.check_output(cmd_exec_str, shell=True) + try: + dateTime = datetime.datetime.now() + outputFile.write(">>[" + str(dateTime) + "]" + cmd + "\n") + outputFile.write(cmd_output) + outputFile.write("########################################################\n") + outputFile.write('\n') + except: + print "Writing to ouptut file Failed" + except subprocess.CalledProcessError as e: + dateTime = datetime.datetime.now() + outputFile.write(">>[" + str(dateTime) + "]" + cmd + "\n") + outputFile.write(e.output) + outputFile.write("########################################################\n") + outputFile.write('\n') + print "Error:" + e.output + + +# Process the support bundle configuration file +# and call appropriate functions +def processConfFile(lines): + for line in lines: + if line[0][0] == '#': + continue + cmd_line = line.split(':') + if cmd_line[0] == "PROC_NAME": + outputFileName = createOutputFile(cmd_line[1]) + if outputFileName: + print outputFileName, "created for", cmd_line[1] + elif cmd_line[0] == "CMD_LIST_START": + outputFile = openOutputFile(outputFileName) + if outputFile: + print outputFileName, "opened" + else: + print outputFileName, "open failed" + return FAIL + elif cmd_line[0] == "CMD_LIST_END": + if closeOutputFile(outputFile): + print outputFileName, "closed" + else: + print outputFileName, "close failed" + else: + print "Execute:" , cmd_line[0] + executeCommand(cmd_line[0], outputFile) + +# Main Function +lines = openConfFile(inputFile) +if not lines: + print "File support_bundle_commands.conf not present in /etc/frr/ directory" +else: + processConfFile(lines) diff --git a/tools/tarsource.sh b/tools/tarsource.sh new file mode 100755 index 0000000000..eee2a9739b --- /dev/null +++ b/tools/tarsource.sh @@ -0,0 +1,331 @@ +#!/bin/bash +# 2018 by David Lamparter, placed in the Public Domain + +help() { + cat <<EOF +FRR tarball/dsc helper, intended to run from a git checkout + +Usage: + ./tarsource.sh [-dDn] [-i GITPATH] [-o OUTDIR] [-S KEYID] + [-C COMMIT] [-e EXTRAVERSION] [-z gz|xz] + +options: + -i GITPATH path to git working tree or bare repository. + - default: parent directory containing this script + -o OUTDIR path to place the generated output files in. + - default: current directory + -C COMMIT build tarball for specified git commit + - default: current HEAD + -e EXTRAVERSION override automatic package extraversion + - default "-YYYYMMDD-NN-gGGGGGGGGGGGG", but the script + autodetects if a release tag is checked out + -z gz|xz compression format to use + - default: xz + -S KEYID sign the output with gpg key + -d use dirty git tree with local changes + -D generate Debian .dsc and .debian.tar.xz too + (note: output files are moved to parent directory) + -l remove Debian auto-build changelog entry + (always done for releases) + -V write version information to config.version and exit + -n allow executing from non-git source (NOT RECOMMENDED) + -h show this help text + +Note(1) that this script tries very hard to generate a deterministic, +reproducible tarball by eliminating timestamps and similar things. However, +since the tarball includes autoconf/automake files, the versions of these +tools need to be _exactly_ identical to get the same tarball. + +Note(2) the debian ".orig" tarball is always identical to the "plain" tarball +generated without the -D option. + +Note(3) if you want the tool to identify github PRs, you need to edit your +.git/config to fetch PRs from github like this: + + [remote "origin"] + url = git@github.com:frrouting/frr.git + fetch = +refs/heads/*:refs/remotes/origin/* +ADD: fetch = +refs/pull/*/head:refs/remotes/origin/pull/* +EOF +} + +set -e + +options=`getopt -o 'hi:o:C:S:e:z:DdnlV' -l help -- "$@"` +debian=false +dirty=false +nongit=false +zip=xz +adjchangelog=false +writeversion=false +extraset=false +set - $options +while test $# -gt 0; do + arg="$1"; shift; optarg=$1 + case "$arg" in + -h|--help) help; exit 0;; + -d) dirty=true;; + -D) debian=true;; + -n) nongit=true;; + -i) eval src=$optarg; shift;; + -C) eval commit=$optarg; shift;; + -o) eval outdir=$optarg; shift;; + -e) eval extraver=$optarg; extraset=true; shift;; + -z) eval zip=$optarg; shift;; + -S) eval keyid=$optarg; shift;; + -l) adjchangelog=true;; + -V) writeversion=true;; + --) break;; + *) echo something went wrong with getopt >&2 + exit 1 + ;; + esac +done + +cwd="`pwd`" +outdir="${outdir:-$cwd}" + +if test -e "$outdir" -a \! -d "$outdir"; then + echo "output $outdir must be a directory" >&2 + exit 1 +elif test \! -d "$outdir"; then + mkdir -p "$outdir" +fi + +cd "$outdir" +outdir="`pwd`" +cd "$cwd" +cd "`dirname $0`/.." +selfdir="`pwd`" +src="${src:-$selfdir}" + +if $writeversion; then + if $nongit; then + echo "The -V option cannot be used without a git tree" >&2 + exit 1 + fi + dirty=true +fi + +case "$zip" in +gz) ziptarget=dist-gzip; ziptool="gzip -n -9"; unzip="gzip -k -c";; +xz) ziptarget=dist-xz; ziptool="xz -z -e"; unzip="xz -d -k -c";; +*) echo "unknown compression format $zip" >&2 + exit 1 +esac + +# always overwrite file ownership in tars +taropt="--owner=root --group=root" + +onexit() { + rv="$?" + set +e + test -n "$tmpdir" -a -d "$tmpdir" && rm -rf "$tmpdir" + + if test "$rv" -ne 0; then + echo -e "\n\033[31;1mfailed\n" >&2 + if test "$dirty" = true; then + echo please try running the script without the -d option.>&2 + fi + fi + exit $rv +} +trap onexit EXIT +tmpdir="`mktemp -d -t frrtar.XXXXXX`" + +if test -e "$src/.git"; then + commit="`git -C \"$src\" rev-parse \"${commit:-HEAD}\"`" + + if $dirty; then + cd "$src" + echo -e "\033[31;1mgit: using dirty worktree in $src\033[m" >&2 + else + echo -e "\033[33;1mgit: preparing a clean clone of $src\033[m" + branch="${tmpdir##*/}" + cd "$tmpdir" + + git -C "$src" branch "$branch" "$commit" + git clone --single-branch -s -b "$branch" "$src" source + git -C "$src" branch -D "$branch" + cd source + fi + + # if we're creating a tarball from git, force the timestamps inside + # the tar to match the commit date - this makes the tarball itself + # reproducible + gitts="`TZ=UTC git show -s --format=%cd --date=local $commit`" + gitts="`TZ=UTC date -d "$gitts" '+%Y-%m-%dT%H:%M:%SZ'`" + taropt="--mtime=$gitts $taropt" + + # check if we're on a release tag + gittag="`git -C \"$src\" describe --tags --match 'frr-*' --first-parent --long $commit`" + gittag="${gittag%-g*}" + gittag="${gittag%-*}" + + # if there have been changes to packaging or tests, it's still the + # same release + changes="`git diff --name-only "$gittag" $commit | \ + egrep -v '\.git|^m4/|^config|^README|^alpine/|^debian/|^pkgsrc/|^ports/|^redhat/|^snapcraft/|^solaris/|^tests/|^tools/|^gdb/|^docker/|^\.' | \ + wc -l`" + if test "$changes" -eq 0; then + adjchangelog=true + echo "detected release build for tag $gittag" >&2 + $extraset || extraver="" + elif ! $adjchangelog; then + gitdate="`TZ=UTC date -d "$gitts" '+%Y%m%d'`" + gitrev="`git rev-parse --short $commit`" + dayseq="`git rev-list --since \"${gitts%T*} 00:00:00 +0000\" $commit | wc -l`" + dayseq="`printf '%02d' $(( $dayseq - 1 ))`" + + $extraset || extraver="-$gitdate-$dayseq-g$gitrev" + + git -C "$src" remote -v | grep fetch | sed -e 's% (fetch)$%%' \ + | egrep -i '\b(git@github\.com:frrouting/frr\.git|https://github\.com/FRRouting/frr\.git)$' \ + | while read remote; do + remote="${remote%% *}" + + git -C "$src" var -l | egrep "^remote.$remote.fetch=" \ + | while read fetch; do + fetch="${fetch#*=}" + from="${fetch%:*}" + to="${fetch#*:}" + if test "$from" = "+refs/pull/*/head"; then + name="`git -C \"$src\" name-rev --name-only --refs \"$to\" $commit`" + test "$name" = "undefined" && continue + realname="${name%~*}" + realname="${realname%%^*}" + realname="${realname%%@*}" + if test "$realname" = "$name"; then + echo "${name##*/}" > "$tmpdir/.gitpr" + break + fi + fi + done || true + test -n "$gitpr" && break + done || true + test $extraset = false -a -f "$tmpdir/.gitpr" && extraver="-PR`cat \"$tmpdir/.gitpr\"`$extraver" + fi + + debsrc="git ls-files debian/" +else + if $nongit; then + echo -e "\033[31;1mWARNING: this script should be executed from a git tree\033[m" >&2 + else + echo -e "\033[31;1mERROR: this script should be executed from a git tree\033[m" >&2 + exit 1 + fi + debsrc="echo debian" +fi + +if $writeversion; then + pkgver="`egrep ^AC_INIT configure.ac`" + pkgver="${pkgver#*,}" + pkgver="${pkgver%,*}" + pkgver="`echo $pkgver`" # strip whitespace + pkgver="${pkgver#[}" + pkgver="${pkgver%]}" + + echo -e "\033[32;1mwriting version ID \033[36;1mfrr-$pkgver$extraver\033[m" + + cat > config.version <<EOF +# config.version override by tarsource.sh +EXTRAVERSION="$extraver" +DIST_PACKAGE_VERSION="$pkgver$extraver" +gitts="$gitts" +taropt="$taropt" +EOF + sed -e "s%@VERSION@%$pkgver$extraver%" \ + < changelog-auto.in \ + > changelog-auto + exit 0 +fi + +echo -e "\033[33;1mpreparing source tree\033[m" + +# config.version will also overwrite gitts and taropt when tarsource.sh +# was used to write the config.version file before - but configure will +# overwrite config.version down below! +if test -f config.version; then + # never executed for clean git build + . ./config.version + if $nongit; then + $extraset || extraver="$EXTRAVERSION" + fi +fi +if test \! -f configure; then + # always executed for clean git build + ./bootstrap.sh +fi +if test "$EXTRAVERSION" != "$extraver" -o \! -f config.status; then + # always executed for clean git build + # options don't matter really - we just want to make a dist tarball + ./configure --with-pkg-extra-version=$extraver +fi + +. ./config.version +PACKAGE_VERSION="$DIST_PACKAGE_VERSION" + +echo -e "\033[33;1mpacking up \033[36;1mfrr-$PACKAGE_VERSION\033[m" + +make GZIP_ENV="-n9" am__tar="tar -chof - $taropt \"\$\$tardir\"" $ziptarget +mv frr-${PACKAGE_VERSION}.tar.$zip "$outdir" || true +lsfiles="frr-${PACKAGE_VERSION}.tar.$zip" + +if $debian; then + mkdir -p "$tmpdir/debian/source" + cat debian/changelog > "$tmpdir/debian/changelog" + if $adjchangelog; then + if grep -q 'autoconf changelog entry' debian/changelog; then + tail -n +9 debian/changelog > "$tmpdir/debian/changelog" + fi + fi + echo '3.0 (quilt)' > "$tmpdir/debian/source/format" + DEBVER="`dpkg-parsechangelog -l\"$tmpdir/debian/changelog\" -SVersion`" + + eval $debsrc | tar -cho $taropt \ + --exclude-vcs --exclude debian/source/format \ + --exclude debian/changelog \ + --exclude debian/changelog-auto \ + --exclude debian/changelog-auto.in \ + --exclude debian/subdir.am \ + -T - -f ../frr_${DEBVER}.debian.tar + # add specially prepared files from above + tar -uf ../frr_${DEBVER}.debian.tar $taropt -C "$tmpdir" debian/source/format debian/changelog + + test -f ../frr_${DEBVER}.debian.tar.$zip && rm -f ../frr_${DEBVER}.debian.tar.$zip + $ziptool ../frr_${DEBVER}.debian.tar + + # pack up debian files proper + ln -s "$outdir/frr-${PACKAGE_VERSION}.tar.$zip" ../frr_${PACKAGE_VERSION}.orig.tar.$zip + dpkg-source -l"$tmpdir/debian/changelog" \ + --format='3.0 (custom)' --target-format='3.0 (quilt)' \ + -b . frr_${PACKAGE_VERSION}.orig.tar.$zip frr_${DEBVER}.debian.tar.$zip + + mv ../frr_${DEBVER}.dsc "$outdir" || true + mv ../frr_${DEBVER}.debian.tar.$zip "$outdir" || true + if test -h ../frr_${PACKAGE_VERSION}.orig.tar.$zip; then + rm ../frr_${PACKAGE_VERSION}.orig.tar.$zip || true + fi + ln -s frr-${PACKAGE_VERSION}.tar.$zip "$outdir/frr_${PACKAGE_VERSION}.orig.tar.$zip" || true + + cd "$outdir" + test -n "$keyid" && debsign -k "$keyid" "frr_${DEBVER}.dsc" + + lsfiles="$lsfiles \ + frr_${DEBVER}.dsc \ + frr_${DEBVER}.debian.tar.$zip \ + frr_${PACKAGE_VERSION}.orig.tar.$zip" +fi + +cd "$outdir" +if test -n "$keyid"; then + $unzip frr-${PACKAGE_VERSION}.tar.$zip > frr-${PACKAGE_VERSION}.tar + test -f frr-${PACKAGE_VERSION}.tar.asc && rm frr-${PACKAGE_VERSION}.tar.asc + if gpg -a --detach-sign -u "$keyid" frr-${PACKAGE_VERSION}.tar; then + lsfiles="$lsfiles frr-${PACKAGE_VERSION}.tar.asc" + fi + rm frr-${PACKAGE_VERSION}.tar +fi + +echo -e "\n\033[32;1mdone: \033[36;1mfrr-$PACKAGE_VERSION\033[m\n" +ls -l $lsfiles diff --git a/tools/watchfrr.sh.in b/tools/watchfrr.sh.in index 3051d91044..712f962a0a 100644 --- a/tools/watchfrr.sh.in +++ b/tools/watchfrr.sh.in @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # # This is NOT the init script! This is the watchfrr start/stop/restart # command handler, passed to watchfrr with the -s/-r/-k commands. It is used diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 340c9be601..1f1152d364 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -104,7 +104,7 @@ static int vty_close_pager(struct vty *vty) return 0; } -static void vtysh_pager_envdef(void) +static void vtysh_pager_envdef(bool fallback) { char *pager_defined; @@ -112,7 +112,7 @@ static void vtysh_pager_envdef(void) if (pager_defined) vtysh_pager_name = strdup(pager_defined); - else + else if (fallback) vtysh_pager_name = strdup(VTYSH_PAGER); } @@ -1305,6 +1305,7 @@ DEFUNSH(VTYSH_BGPD, router_bgp, router_bgp_cmd, return CMD_SUCCESS; } +#ifdef KEEP_OLD_VPN_COMMANDS DEFUNSH(VTYSH_BGPD, address_family_vpnv4, address_family_vpnv4_cmd, "address-family vpnv4 [unicast]", "Enter Address Family command mode\n" @@ -1324,6 +1325,7 @@ DEFUNSH(VTYSH_BGPD, address_family_vpnv6, address_family_vpnv6_cmd, vty->node = BGP_VPNV6_NODE; return CMD_SUCCESS; } +#endif /* KEEP_OLD_VPN_COMMANDS */ DEFUNSH(VTYSH_BGPD, address_family_ipv4, address_family_ipv4_cmd, "address-family ipv4 [unicast]", @@ -2893,7 +2895,7 @@ DEFUN (vtysh_terminal_paginate, vtysh_pager_name = NULL; if (strcmp(argv[0]->text, "no")) - vtysh_pager_envdef(); + vtysh_pager_envdef(true); return CMD_SUCCESS; } @@ -2913,7 +2915,7 @@ DEFUN (vtysh_terminal_length, if (!strcmp(argv[0]->text, "no") || !strcmp(argv[1]->text, "no")) { /* "terminal no length" = use VTYSH_PAGER */ - vtysh_pager_envdef(); + vtysh_pager_envdef(true); return CMD_SUCCESS; } @@ -2922,7 +2924,7 @@ DEFUN (vtysh_terminal_length, vty_out(vty, "%% The \"terminal length\" command is deprecated and its value is ignored.\n" "%% Please use \"terminal paginate\" instead with OS TTY length handling.\n"); - vtysh_pager_envdef(); + vtysh_pager_envdef(true); } return CMD_SUCCESS; @@ -3330,7 +3332,7 @@ static void vtysh_client_sorted_insert(struct vtysh_client *head_client, #define MAXIMUM_INSTANCES 10 -static void vtysh_update_all_insances(struct vtysh_client *head_client) +static void vtysh_update_all_instances(struct vtysh_client *head_client) { struct vtysh_client *client; DIR *dir; @@ -3373,7 +3375,7 @@ static int vtysh_connect_all_instances(struct vtysh_client *head_client) struct vtysh_client *client; int rc = 0; - vtysh_update_all_insances(head_client); + vtysh_update_all_instances(head_client); client = head_client->next; while (client) { @@ -3479,6 +3481,7 @@ void vtysh_init_vty(void) /* set default output */ vty->of = stdout; + vtysh_pager_envdef(false); /* Initialize commands. */ cmd_init(0); @@ -3734,8 +3737,10 @@ void vtysh_init_vty(void) install_element(CONFIG_NODE, &router_isis_cmd); install_element(CONFIG_NODE, &router_openfabric_cmd); install_element(CONFIG_NODE, &router_bgp_cmd); +#ifdef KEEP_OLD_VPN_COMMANDS install_element(BGP_NODE, &address_family_vpnv4_cmd); install_element(BGP_NODE, &address_family_vpnv6_cmd); +#endif /* KEEP_OLD_VPN_COMMANDS */ #if defined(ENABLE_BGP_VNC) install_element(BGP_NODE, &vnc_vrf_policy_cmd); install_element(BGP_NODE, &vnc_defaults_cmd); @@ -3812,6 +3817,7 @@ void vtysh_init_vty(void) /* "write memory" command. */ install_element(ENABLE_NODE, &vtysh_write_memory_cmd); + install_element(CONFIG_NODE, &vtysh_terminal_paginate_cmd); install_element(VIEW_NODE, &vtysh_terminal_paginate_cmd); install_element(VIEW_NODE, &vtysh_terminal_length_cmd); install_element(VIEW_NODE, &vtysh_terminal_no_length_cmd); diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index 91e49c45c1..7ca3ed9c5e 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -74,8 +74,7 @@ static int config_cmp(struct config *c1, struct config *c2) static void config_del(struct config *config) { list_delete(&config->line); - if (config->name) - XFREE(MTYPE_VTYSH_CONFIG_LINE, config->name); + XFREE(MTYPE_VTYSH_CONFIG_LINE, config->name); XFREE(MTYPE_VTYSH_CONFIG, config); } diff --git a/vtysh/vtysh_user.c b/vtysh/vtysh_user.c index dcf8ca0470..aaf70ab08b 100644 --- a/vtysh/vtysh_user.c +++ b/vtysh/vtysh_user.c @@ -204,7 +204,7 @@ char *vtysh_get_home(void) struct passwd *passwd; char *homedir; - if ((homedir = getenv("HOME")) != 0) + if ((homedir = getenv("HOME")) != NULL) return homedir; /* Fallback if HOME is undefined */ diff --git a/watchfrr/watchfrr.c b/watchfrr/watchfrr.c index e28da6db8c..34f8dabdf1 100644 --- a/watchfrr/watchfrr.c +++ b/watchfrr/watchfrr.c @@ -53,6 +53,10 @@ #define DEFAULT_MIN_RESTART 60 #define DEFAULT_MAX_RESTART 600 +#define DEFAULT_RESTART_CMD WATCHFRR_SH_PATH " restart %s" +#define DEFAULT_START_CMD WATCHFRR_SH_PATH " start %s" +#define DEFAULT_STOP_CMD WATCHFRR_SH_PATH " stop %s" + #define PING_TOKEN "PING" DEFINE_MGROUP(WATCHFRR, "watchfrr") @@ -83,6 +87,7 @@ static const char *phase_str[] = { }; #define PHASE_TIMEOUT (3*gs.restart_timeout) +#define STARTUP_TIMEOUT 55 * 1000 struct restart_info { const char *name; @@ -97,6 +102,7 @@ struct restart_info { static struct global_state { restart_phase_t phase; struct thread *t_phase_hanging; + struct thread *t_startup_timeout; const char *vtydir; long period; long timeout; @@ -122,6 +128,9 @@ static struct global_state { .loglevel = DEFAULT_LOGLEVEL, .min_restart_interval = DEFAULT_MIN_RESTART, .max_restart_interval = DEFAULT_MAX_RESTART, + .restart_command = DEFAULT_RESTART_CMD, + .start_command = DEFAULT_START_CMD, + .stop_command = DEFAULT_STOP_CMD, }; typedef enum { @@ -225,14 +234,17 @@ Otherwise, the interval is doubled (but capped at the -M value).\n\n", -r, --restart Supply a Bourne shell command to use to restart a single\n\ daemon. The command string should include '%%s' where the\n\ name of the daemon should be substituted.\n\ + (default: '%s')\n\ -s, --start-command\n\ Supply a Bourne shell to command to use to start a single\n\ daemon. The command string should include '%%s' where the\n\ name of the daemon should be substituted.\n\ + (default: '%s')\n\ -k, --kill-command\n\ Supply a Bourne shell to command to use to stop a single\n\ daemon. The command string should include '%%s' where the\n\ name of the daemon should be substituted.\n\ + (default: '%s')\n\ --dry Do not start or restart anything, just log.\n\ -p, --pid-file Set process identifier file name\n\ (default is %s/watchfrr.pid).\n\ @@ -245,7 +257,9 @@ Otherwise, the interval is doubled (but capped at the -M value).\n\n", -h, --help Display this help and exit\n", frr_vtydir, DEFAULT_LOGLEVEL, LOG_EMERG, LOG_DEBUG, LOG_DEBUG, DEFAULT_MIN_RESTART, DEFAULT_MAX_RESTART, DEFAULT_PERIOD, - DEFAULT_TIMEOUT, DEFAULT_RESTART_TIMEOUT, frr_vtydir); + DEFAULT_TIMEOUT, DEFAULT_RESTART_TIMEOUT, + DEFAULT_RESTART_CMD, DEFAULT_START_CMD, DEFAULT_STOP_CMD, + frr_vtydir); } static pid_t run_background(char *shell_cmd) @@ -630,23 +644,38 @@ static int handle_read(struct thread *t_read) * Wait till we notice that all daemons are ready before * we send we are ready to systemd */ -static void daemon_send_ready(void) +static void daemon_send_ready(int exitcode) { + FILE *fp; static int sent = 0; - if (!sent && gs.numdown == 0) { - FILE *fp; + if (sent) + return; + + if (exitcode == 0) zlog_notice("all daemons up, doing startup-complete notify"); - frr_detach(); + else if (gs.numdown < gs.numdaemons) + flog_err(EC_WATCHFRR_CONNECTION, + "startup did not complete within timeout" + " (%d/%d daemons running)", + gs.numdaemons - gs.numdown, gs.numdaemons); + else { + flog_err(EC_WATCHFRR_CONNECTION, + "all configured daemons failed to start" + " -- exiting watchfrr"); + exit(exitcode); + + } - fp = fopen(DAEMON_VTY_DIR "/watchfrr.started", "w"); - if (fp) - fclose(fp); + frr_detach(); + + fp = fopen(DAEMON_VTY_DIR "/watchfrr.started", "w"); + if (fp) + fclose(fp); #if defined HAVE_SYSTEMD - systemd_send_started(master, 0); + systemd_send_started(master, 0); #endif - sent = 1; - } + sent = 1; } static void daemon_up(struct daemon *dmn, const char *why) @@ -655,7 +684,8 @@ static void daemon_up(struct daemon *dmn, const char *why) gs.numdown--; dmn->connect_tries = 0; zlog_notice("%s state -> up : %s", dmn->name, why); - daemon_send_ready(); + if (gs.numdown == 0) + daemon_send_ready(0); SET_WAKEUP_ECHO(dmn); phase_check(); } @@ -1030,6 +1060,12 @@ static char *translate_blanks(const char *cmd, const char *blankstr) return res; } +static int startup_timeout(struct thread *t_wakeup) +{ + daemon_send_ready(1); + return 0; +} + static void watchfrr_init(int argc, char **argv) { const char *special = "zebra"; @@ -1037,6 +1073,9 @@ static void watchfrr_init(int argc, char **argv) struct daemon *dmn, **add = &gs.daemons; char alldaemons[512] = "", *p = alldaemons; + thread_add_timer_msec(master, startup_timeout, NULL, STARTUP_TIMEOUT, + &gs.t_startup_timeout); + for (i = optind; i < argc; i++) { dmn = XCALLOC(MTYPE_WATCHFRR_DAEMON, sizeof(*dmn)); diff --git a/zebra/connected.c b/zebra/connected.c index c449855f6d..128f397552 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -594,5 +594,5 @@ int connected_is_unnumbered(struct interface *ifp) return CHECK_FLAG(connected->flags, ZEBRA_IFA_UNNUMBERED); } - return 0; + return 1; } diff --git a/zebra/if_ioctl.c b/zebra/if_ioctl.c index debc151d75..8bec256355 100644 --- a/zebra/if_ioctl.c +++ b/zebra/if_ioctl.c @@ -147,7 +147,7 @@ static int if_get_hwaddr(struct interface *ifp) struct ifreq ifreq; int i; - strncpy(ifreq.ifr_name, ifp->name, IFNAMSIZ); + strlcpy(ifreq.ifr_name, ifp->name, sizeof(ifreq.ifr_name)); ifreq.ifr_addr.sa_family = AF_INET; /* Fetch Hardware address if available. */ diff --git a/zebra/if_ioctl_solaris.c b/zebra/if_ioctl_solaris.c index 2c29930c3f..8b539a9049 100644 --- a/zebra/if_ioctl_solaris.c +++ b/zebra/if_ioctl_solaris.c @@ -247,7 +247,8 @@ static int if_get_addr(struct interface *ifp, struct sockaddr *addr, * We need to use the logical interface name / label, if we've been * given one, in order to get the right address */ - strncpy(lifreq.lifr_name, (label ? label : ifp->name), IFNAMSIZ); + strlcpy(lifreq.lifr_name, (label ? label : ifp->name), + sizeof(lifreq.lifr_name)); /* Interface's address. */ memcpy(&lifreq.lifr_addr, addr, ADDRLEN(addr)); diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index faca52fe41..b2f470bc8d 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -68,6 +68,7 @@ #include "zebra/kernel_netlink.h" #include "zebra/if_netlink.h" #include "zebra/zebra_errors.h" +#include "zebra/zebra_vxlan.h" extern struct zebra_privs_t zserv_privs; @@ -1111,6 +1112,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) ifindex_t bridge_ifindex = IFINDEX_INTERNAL; ifindex_t bond_ifindex = IFINDEX_INTERNAL; ifindex_t link_ifindex = IFINDEX_INTERNAL; + uint8_t old_hw_addr[INTERFACE_HWADDR_MAX]; zns = zebra_ns_lookup(ns_id); @@ -1192,8 +1194,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) ifp = if_lookup_by_name_per_ns(zns, name); if (ifp) { - if (ifp->desc) - XFREE(MTYPE_TMP, ifp->desc); + XFREE(MTYPE_TMP, ifp->desc); if (desc) ifp->desc = XSTRDUP(MTYPE_TMP, desc); } @@ -1312,6 +1313,8 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) was_bond_slave = IS_ZEBRA_IF_BOND_SLAVE(ifp); zebra_if_set_ziftype(ifp, zif_type, zif_slave_type); + memcpy(old_hw_addr, ifp->hw_addr, INTERFACE_HWADDR_MAX); + netlink_interface_update_hw_addr(tb, ifp); if (if_is_no_ptm_operative(ifp)) { @@ -1330,6 +1333,22 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) "Intf %s(%u) PTM up, notifying clients", name, ifp->ifindex); zebra_interface_up_update(ifp); + + /* Update EVPN VNI when SVI MAC change + */ + if (IS_ZEBRA_IF_VLAN(ifp) && + memcmp(old_hw_addr, ifp->hw_addr, + INTERFACE_HWADDR_MAX)) { + struct interface *link_if; + + link_if = + if_lookup_by_index_per_ns( + zebra_ns_lookup(NS_DEFAULT), + link_ifindex); + if (link_if) + zebra_vxlan_svi_up(ifp, + link_if); + } } } else { ifp->flags = ifi->ifi_flags & 0x0000fffff; diff --git a/zebra/interface.c b/zebra/interface.c index c88aadc683..229f9c1da4 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -135,6 +135,8 @@ static int if_zebra_new_hook(struct interface *ifp) rtadv->DefaultPreference = RTADV_PREF_MEDIUM; rtadv->AdvPrefixList = list_new(); + rtadv->AdvRDNSSList = list_new(); + rtadv->AdvDNSSLList = list_new(); } #endif /* HAVE_RTADV */ @@ -175,6 +177,8 @@ static int if_zebra_delete_hook(struct interface *ifp) rtadv = &zebra_if->rtadv; list_delete(&rtadv->AdvPrefixList); + list_delete(&rtadv->AdvRDNSSList); + list_delete(&rtadv->AdvDNSSLList); #endif /* HAVE_RTADV */ THREAD_OFF(zebra_if->speed_update); diff --git a/zebra/interface.h b/zebra/interface.h index 01dd697772..1dbcf33fad 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -168,6 +168,22 @@ struct rtadvconf { int DefaultPreference; #define RTADV_PREF_MEDIUM 0x0 /* Per RFC4191. */ + /* + * List of recursive DNS servers to include in the RDNSS option. + * See [RFC8106 5.1] + * + * Default: empty list; do not emit RDNSS option + */ + struct list *AdvRDNSSList; + + /* + * List of DNS search domains to include in the DNSSL option. + * See [RFC8106 5.2] + * + * Default: empty list; do not emit DNSSL option + */ + struct list *AdvDNSSLList; + uint8_t inFastRexmit; /* True if we're rexmits faster than usual */ /* Track if RA was configured by BGP or by the Operator or both */ @@ -182,6 +198,41 @@ struct rtadvconf { #define RTADV_NUM_FAST_REXMITS 4 /* Fast Rexmit RA 4 times on certain events */ }; +struct rtadv_rdnss { + /* Address of recursive DNS server to advertise */ + struct in6_addr addr; + + /* + * Lifetime in seconds; all-ones means infinity, zero + * stop using it. + */ + uint32_t lifetime; + + /* If lifetime not set, use a default of 3*MaxRtrAdvInterval */ + int lifetime_set; +}; + +/* + * [RFC1035 2.3.4] sets the maximum length of a domain name (a sequence of + * labels, each prefixed by a length octet) at 255 octets. + */ +#define RTADV_MAX_ENCODED_DOMAIN_NAME 255 + +struct rtadv_dnssl { + /* Domain name without trailing root zone dot (NUL-terminated) */ + char name[RTADV_MAX_ENCODED_DOMAIN_NAME - 1]; + + /* Name encoded as in [RFC1035 3.1] */ + uint8_t encoded_name[RTADV_MAX_ENCODED_DOMAIN_NAME]; + + /* Actual length of encoded_name */ + size_t encoded_len; + + /* Lifetime as for RDNSS */ + uint32_t lifetime; + int lifetime_set; +}; + #endif /* HAVE_RTADV */ /* Zebra interface type - ones of interest. */ diff --git a/zebra/ioctl.c b/zebra/ioctl.c index ebe1edcaef..9499c731ef 100644 --- a/zebra/ioctl.c +++ b/zebra/ioctl.c @@ -213,7 +213,7 @@ int if_set_prefix(struct interface *ifp, struct connected *ifc) rib_lookup_and_pushup(p, ifp->vrf_id); memset(&addreq, 0, sizeof addreq); - strncpy((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name); + strlcpy(addreq.ifra_name, ifp->name, sizeof(addreq.ifra_name)); memset(&addr, 0, sizeof(struct sockaddr_in)); addr.sin_addr = p->prefix; @@ -267,7 +267,7 @@ int if_unset_prefix(struct interface *ifp, struct connected *ifc) p = (struct prefix_ipv4 *)ifc->address; memset(&addreq, 0, sizeof addreq); - strncpy((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name); + strlcpy(addreq.ifra_name, ifp->name, sizeof(addreq.ifra_name)); memset(&addr, 0, sizeof(struct sockaddr_in)); addr.sin_addr = p->prefix; @@ -412,7 +412,7 @@ void if_get_flags(struct interface *ifp) if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION)) { (void)memset(&ifmr, 0, sizeof(ifmr)); - strncpy(ifmr.ifm_name, ifp->name, IFNAMSIZ); + strlcpy(ifmr.ifm_name, ifp->name, sizeof(ifmr.ifm_name)); /* Seems not all interfaces implement this ioctl */ if (if_ioctl(SIOCGIFMEDIA, (caddr_t)&ifmr) == -1 && @@ -514,7 +514,7 @@ int if_prefix_add_ipv6(struct interface *ifp, struct connected *ifc) p = (struct prefix_ipv6 *)ifc->address; memset(&addreq, 0, sizeof addreq); - strncpy((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name); + strlcpy(addreq.ifra_name, ifp->name, sizeof(addreq.ifra_name)); memset(&addr, 0, sizeof(struct sockaddr_in6)); addr.sin6_addr = p->prefix; @@ -557,7 +557,7 @@ int if_prefix_delete_ipv6(struct interface *ifp, struct connected *ifc) p = (struct prefix_ipv6 *)ifc->address; memset(&addreq, 0, sizeof addreq); - strncpy((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name); + strlcpy(addreq.ifra_name, ifp->name, sizeof(addreq.ifra_name)); memset(&addr, 0, sizeof(struct sockaddr_in6)); addr.sin6_addr = p->prefix; diff --git a/zebra/ioctl_solaris.c b/zebra/ioctl_solaris.c index fc554219bc..c523ee983d 100644 --- a/zebra/ioctl_solaris.c +++ b/zebra/ioctl_solaris.c @@ -44,7 +44,7 @@ extern struct zebra_privs_t zserv_privs; /* clear and set interface name string */ void lifreq_set_name(struct lifreq *lifreq, const char *ifname) { - strncpy(lifreq->lifr_name, ifname, IFNAMSIZ); + strlcpy(lifreq->lifr_name, ifname, sizeof(lifreq->lifr_name)); } int vrf_if_ioctl(unsigned long request, caddr_t buffer, vrf_id_t vrf_id) @@ -199,7 +199,7 @@ int if_set_prefix(struct interface *ifp, struct connected *ifc) ifaddr = *p; - strncpy(ifreq.ifr_name, ifp->name, IFNAMSIZ); + strlcpy(ifreq.ifr_name, ifp->name, sizeof(ifreq.ifr_name)); addr.sin_addr = p->prefix; addr.sin_family = p->family; @@ -250,7 +250,7 @@ int if_unset_prefix(struct interface *ifp, struct connected *ifc) p = (struct prefix_ipv4 *)ifc->address; - strncpy(ifreq.ifr_name, ifp->name, IFNAMSIZ); + strlcpy(ifreq.ifr_name, ifp->name, sizeof(ifreq.ifr_name)); memset(&addr, 0, sizeof(struct sockaddr_in)); addr.sin_family = p->family; diff --git a/zebra/irdp_main.c b/zebra/irdp_main.c index a9734056bc..38d241eaa5 100644 --- a/zebra/irdp_main.c +++ b/zebra/irdp_main.c @@ -241,7 +241,7 @@ int irdp_send_thread(struct thread *t_advert) timer = MAX_INITIAL_ADVERT_INTERVAL; if (irdp->flags & IF_DEBUG_MISC) - zlog_debug("IRDP: New timer for %s set to %u\n", ifp->name, + zlog_debug("IRDP: New timer for %s set to %u", ifp->name, timer); irdp->t_advertise = NULL; diff --git a/zebra/irdp_packet.c b/zebra/irdp_packet.c index 774d84d66d..2804787620 100644 --- a/zebra/irdp_packet.c +++ b/zebra/irdp_packet.c @@ -166,7 +166,7 @@ static void parse_irdp_packet(char *p, int len, struct interface *ifp) case ICMP_ROUTERSOLICIT: if (irdp->flags & IF_DEBUG_MESSAGES) - zlog_debug("IRDP: RX Solicit on %s from %s\n", + zlog_debug("IRDP: RX Solicit on %s from %s", ifp->name, inet_ntoa(src)); process_solicit(ifp); @@ -253,7 +253,7 @@ int irdp_read_raw(struct thread *r) if (!(irdp->flags & IF_ACTIVE)) { if (irdp->flags & IF_DEBUG_MISC) - zlog_debug("IRDP: RX ICMP for disabled interface %s\n", + zlog_debug("IRDP: RX ICMP for disabled interface %s", ifp->name); return 0; } diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 2f850c6338..c5fbfd4481 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -652,7 +652,7 @@ static void netlink_parse_extended_ack(struct nlmsghdr *h) off = *(uint32_t *)RTA_DATA(tb[NLMSGERR_ATTR_OFFS]); if (off > h->nlmsg_len) { - zlog_err("Invalid offset for NLMSGERR_ATTR_OFFS\n"); + zlog_err("Invalid offset for NLMSGERR_ATTR_OFFS"); } else if (!(h->nlmsg_flags & NLM_F_CAPPED)) { /* * Header of failed message diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 792756efeb..ad46191903 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -622,7 +622,7 @@ int ifm_read(struct if_msghdr *ifm) * RTA_IFP) is required. */ if (!ifnlen) { - zlog_debug("Interface index %d (new) missing ifname\n", + zlog_debug("Interface index %d (new) missing ifname", ifm->ifm_index); return -1; } diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 3868412b20..cf61eb6cb4 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -835,7 +835,7 @@ int netlink_route_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE)) { /* If this is not route add/delete message print warning. */ - zlog_debug("Kernel message: %s NS %u\n", + zlog_debug("Kernel message: %s NS %u", nl_msg_type_to_str(h->nlmsg_type), ns_id); return 0; } @@ -927,7 +927,7 @@ static void _netlink_route_nl_add_gateway_info(uint8_t route_family, uint8_t gw_family, struct nlmsghdr *nlmsg, size_t req_size, int bytelen, - struct nexthop *nexthop) + const struct nexthop *nexthop) { if (route_family == AF_MPLS) { struct gw_family_t gw_fam; @@ -954,7 +954,7 @@ static void _netlink_route_rta_add_gateway_info(uint8_t route_family, struct rtattr *rta, struct rtnexthop *rtnh, size_t req_size, int bytelen, - struct nexthop *nexthop) + const struct nexthop *nexthop) { if (route_family == AF_MPLS) { struct gw_family_t gw_fam; @@ -990,7 +990,7 @@ static void _netlink_route_rta_add_gateway_info(uint8_t route_family, * @param req_size: The size allocated for the message. */ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen, - struct nexthop *nexthop, + const struct nexthop *nexthop, struct nlmsghdr *nlmsg, struct rtmsg *rtmsg, size_t req_size, int cmd) @@ -1009,7 +1009,7 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen, label_buf[0] = '\0'; assert(nexthop); - for (struct nexthop *nh = nexthop; nh; nh = nh->rparent) { + for (const struct nexthop *nh = nexthop; nh; nh = nh->rparent) { char label_buf1[20]; nh_label = nh->nh_label; @@ -1175,11 +1175,11 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen, * the prefsrc should be stored. */ static void _netlink_route_build_multipath(const char *routedesc, int bytelen, - struct nexthop *nexthop, + const struct nexthop *nexthop, struct rtattr *rta, struct rtnexthop *rtnh, struct rtmsg *rtmsg, - union g_addr **src) + const union g_addr **src) { struct mpls_label_stack *nh_label; mpls_lse_t out_lse[MPLS_MAX_LABELS]; @@ -1200,7 +1200,7 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen, label_buf[0] = '\0'; assert(nexthop); - for (struct nexthop *nh = nexthop; nh; nh = nh->rparent) { + for (const struct nexthop *nh = nexthop; nh; nh = nh->rparent) { char label_buf1[20]; nh_label = nh->nh_label; @@ -1342,7 +1342,7 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen, } static inline void _netlink_mpls_build_singlepath(const char *routedesc, - zebra_nhlfe_t *nhlfe, + const zebra_nhlfe_t *nhlfe, struct nlmsghdr *nlmsg, struct rtmsg *rtmsg, size_t req_size, int cmd) @@ -1358,9 +1358,9 @@ static inline void _netlink_mpls_build_singlepath(const char *routedesc, static inline void -_netlink_mpls_build_multipath(const char *routedesc, zebra_nhlfe_t *nhlfe, +_netlink_mpls_build_multipath(const char *routedesc, const zebra_nhlfe_t *nhlfe, struct rtattr *rta, struct rtnexthop *rtnh, - struct rtmsg *rtmsg, union g_addr **src) + struct rtmsg *rtmsg, const union g_addr **src) { int bytelen; uint8_t family; @@ -1438,7 +1438,6 @@ static int netlink_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla, static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) { int bytelen; - struct sockaddr_nl snl; struct nexthop *nexthop = NULL; unsigned int nexthop_num; int family; @@ -1466,10 +1465,9 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; - if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_UPDATE) { - if ((p->family == AF_INET) || v6_rr_semantics) - req.n.nlmsg_flags |= NLM_F_REPLACE; - } + if ((cmd == RTM_NEWROUTE) && + ((p->family == AF_INET) || v6_rr_semantics)) + req.n.nlmsg_flags |= NLM_F_REPLACE; req.n.nlmsg_type = cmd; @@ -1657,7 +1655,7 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) char buf[NL_PKT_BUF_SIZE]; struct rtattr *rta = (void *)buf; struct rtnexthop *rtnh; - union g_addr *src1 = NULL; + const union g_addr *src1 = NULL; rta->rta_type = RTA_MULTIPATH; rta->rta_len = RTA_LENGTH(0); @@ -1748,11 +1746,6 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) } skip: - - /* Destination netlink address. */ - memset(&snl, 0, sizeof(snl)); - snl.nl_family = AF_NETLINK; - /* Talk to netlink socket. */ return netlink_talk_info(netlink_talk_filter, &req.n, dplane_ctx_get_ns(ctx), 0); @@ -1972,23 +1965,38 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id) /* The interface should exist. */ ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), ndm->ndm_ifindex); - if (!ifp || !ifp->info) + if (!ifp || !ifp->info) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("\t%s without associated interface: %u", + __PRETTY_FUNCTION__, ndm->ndm_ifindex); return 0; + } /* The interface should be something we're interested in. */ - if (!IS_ZEBRA_IF_BRIDGE_SLAVE(ifp)) + if (!IS_ZEBRA_IF_BRIDGE_SLAVE(ifp)) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("\t%s Not interested in %s, not a slave", + __PRETTY_FUNCTION__, ifp->name); return 0; + } /* Drop "permanent" entries. */ - if (ndm->ndm_state & NUD_PERMANENT) + if (ndm->ndm_state & NUD_PERMANENT) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("\t%s Entry is PERMANENT, dropping", + __PRETTY_FUNCTION__); return 0; + } zif = (struct zebra_if *)ifp->info; if ((br_if = zif->brslave_info.br_if) == NULL) { - zlog_debug("%s family %s IF %s(%u) brIF %u - no bridge master", - nl_msg_type_to_str(h->nlmsg_type), - nl_family_to_str(ndm->ndm_family), ifp->name, - ndm->ndm_ifindex, zif->brslave_info.bridge_ifindex); + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "%s family %s IF %s(%u) brIF %u - no bridge master", + nl_msg_type_to_str(h->nlmsg_type), + nl_family_to_str(ndm->ndm_family), ifp->name, + ndm->ndm_ifindex, + zif->brslave_info.bridge_ifindex); return 0; } @@ -1997,20 +2005,24 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id) netlink_parse_rtattr(tb, NDA_MAX, NDA_RTA(ndm), len); if (!tb[NDA_LLADDR]) { - zlog_debug("%s family %s IF %s(%u) brIF %u - no LLADDR", - nl_msg_type_to_str(h->nlmsg_type), - nl_family_to_str(ndm->ndm_family), ifp->name, - ndm->ndm_ifindex, zif->brslave_info.bridge_ifindex); + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s family %s IF %s(%u) brIF %u - no LLADDR", + nl_msg_type_to_str(h->nlmsg_type), + nl_family_to_str(ndm->ndm_family), ifp->name, + ndm->ndm_ifindex, + zif->brslave_info.bridge_ifindex); return 0; } if (RTA_PAYLOAD(tb[NDA_LLADDR]) != ETH_ALEN) { - zlog_debug( - "%s family %s IF %s(%u) brIF %u - LLADDR is not MAC, len %lu", - nl_msg_type_to_str(h->nlmsg_type), - nl_family_to_str(ndm->ndm_family), ifp->name, - ndm->ndm_ifindex, zif->brslave_info.bridge_ifindex, - (unsigned long)RTA_PAYLOAD(tb[NDA_LLADDR])); + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "%s family %s IF %s(%u) brIF %u - LLADDR is not MAC, len %lu", + nl_msg_type_to_str(h->nlmsg_type), + nl_family_to_str(ndm->ndm_family), ifp->name, + ndm->ndm_ifindex, + zif->brslave_info.bridge_ifindex, + (unsigned long)RTA_PAYLOAD(tb[NDA_LLADDR])); return 0; } @@ -2043,8 +2055,12 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id) prefix_mac2str(&mac, buf, sizeof(buf)), dst_present ? dst_buf : ""); - if (filter_vlan && vid != filter_vlan) + if (filter_vlan && vid != filter_vlan) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("\tFiltered due to filter vlan: %d", + filter_vlan); return 0; + } /* If add or update, do accordingly if learnt on a "local" interface; if * the notification is over VxLAN, this has to be related to @@ -2052,10 +2068,6 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id) * so perform an implicit delete of any local entry (if it exists). */ if (h->nlmsg_type == RTM_NEWNEIGH) { - /* Drop "permanent" entries. */ - if (ndm->ndm_state & NUD_PERMANENT) - return 0; - if (IS_ZEBRA_IF_VXLAN(ifp)) return zebra_vxlan_check_del_local_mac(ifp, br_if, &mac, vid); @@ -2072,8 +2084,11 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id) * Ignore the notification from VxLan driver as it is also generated * when mac moves from remote to local. */ - if (dst_present) + if (dst_present) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("\tNo Destination Present"); return 0; + } if (IS_ZEBRA_IF_VXLAN(ifp)) return zebra_vxlan_check_readd_remote_mac(ifp, br_if, &mac, @@ -2386,6 +2401,9 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) /* if kernel deletes our rfc5549 neighbor entry, re-install it */ if (h->nlmsg_type == RTM_DELNEIGH && (ndm->ndm_state & NUD_PERMANENT)) { netlink_handle_5549(ndm, zif, ifp, &ip); + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "\tNeighbor Entry Received is a 5549 entry, finished"); return 0; } @@ -2411,20 +2429,27 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) return 0; } else if (IS_ZEBRA_IF_BRIDGE(ifp)) link_if = ifp; - else + else { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "\tNeighbor Entry received is not on a VLAN or a BRIDGE, ignoring"); return 0; + } memset(&mac, 0, sizeof(struct ethaddr)); if (h->nlmsg_type == RTM_NEWNEIGH) { if (tb[NDA_LLADDR]) { if (RTA_PAYLOAD(tb[NDA_LLADDR]) != ETH_ALEN) { - zlog_debug( - "%s family %s IF %s(%u) - LLADDR is not MAC, len %lu", - nl_msg_type_to_str(h->nlmsg_type), - nl_family_to_str(ndm->ndm_family), - ifp->name, ndm->ndm_ifindex, - (unsigned long)RTA_PAYLOAD( - tb[NDA_LLADDR])); + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "%s family %s IF %s(%u) - LLADDR is not MAC, len %lu", + nl_msg_type_to_str( + h->nlmsg_type), + nl_family_to_str( + ndm->ndm_family), + ifp->name, ndm->ndm_ifindex, + (unsigned long)RTA_PAYLOAD( + tb[NDA_LLADDR])); return 0; } @@ -2751,7 +2776,7 @@ int kernel_upd_neigh(struct interface *ifp, struct ipaddr *ip, int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx) { mpls_lse_t lse; - zebra_nhlfe_t *nhlfe; + const zebra_nhlfe_t *nhlfe; struct nexthop *nexthop = NULL; unsigned int nexthop_num; const char *routedesc; @@ -2854,7 +2879,7 @@ int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx) char buf[NL_PKT_BUF_SIZE]; struct rtattr *rta = (void *)buf; struct rtnexthop *rtnh; - union g_addr *src1 = NULL; + const union g_addr *src1 = NULL; rta->rta_type = RTA_MULTIPATH; rta->rta_len = RTA_LENGTH(0); diff --git a/zebra/rtadv.c b/zebra/rtadv.c index 86edc6fb5e..5088e2e8e1 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -66,6 +66,9 @@ extern struct zebra_privs_t zserv_privs; #define ALLNODE "ff02::1" #define ALLROUTER "ff02::2" +DEFINE_MTYPE_STATIC(ZEBRA, RTADV_RDNSS, "Router Advertisement RDNSS") +DEFINE_MTYPE_STATIC(ZEBRA, RTADV_DNSSL, "Router Advertisement DNSSL") + /* Order is intentional. Matches RFC4191. This array is also used for command matching, so only modify with care. */ const char *rtadv_pref_strs[] = {"medium", "high", "INVALID", "low", 0}; @@ -355,6 +358,78 @@ static void rtadv_send_packet(int sock, struct interface *ifp) len += sizeof(struct nd_opt_mtu); } + /* + * There is no limit on the number of configurable recursive DNS + * servers or search list entries. We don't want the RA message + * to exceed the link's MTU (risking fragmentation) or even + * blow the stack buffer allocated for it. + */ + size_t max_len = MIN(ifp->mtu6 - 40, sizeof(buf)); + + /* Recursive DNS servers */ + struct rtadv_rdnss *rdnss; + + for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvRDNSSList, node, rdnss)) { + size_t opt_len = + sizeof(struct nd_opt_rdnss) + sizeof(struct in6_addr); + + if (len + opt_len > max_len) { + zlog_warn( + "%s(%u): Tx RA: RDNSS option would exceed MTU, omitting it", + ifp->name, ifp->ifindex); + goto no_more_opts; + } + struct nd_opt_rdnss *opt = (struct nd_opt_rdnss *)(buf + len); + + opt->nd_opt_rdnss_type = ND_OPT_RDNSS; + opt->nd_opt_rdnss_len = opt_len / 8; + opt->nd_opt_rdnss_reserved = 0; + opt->nd_opt_rdnss_lifetime = htonl( + rdnss->lifetime_set + ? rdnss->lifetime + : MAX(1, 0.003 * zif->rtadv.MaxRtrAdvInterval)); + + len += sizeof(struct nd_opt_rdnss); + + IPV6_ADDR_COPY(buf + len, &rdnss->addr); + len += sizeof(struct in6_addr); + } + + /* DNS search list */ + struct rtadv_dnssl *dnssl; + + for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvDNSSLList, node, dnssl)) { + size_t opt_len = sizeof(struct nd_opt_dnssl) + + ((dnssl->encoded_len + 7) & ~7); + + if (len + opt_len > max_len) { + zlog_warn( + "%s(%u): Tx RA: DNSSL option would exceed MTU, omitting it", + ifp->name, ifp->ifindex); + goto no_more_opts; + } + struct nd_opt_dnssl *opt = (struct nd_opt_dnssl *)(buf + len); + + opt->nd_opt_dnssl_type = ND_OPT_DNSSL; + opt->nd_opt_dnssl_len = opt_len / 8; + opt->nd_opt_dnssl_reserved = 0; + opt->nd_opt_dnssl_lifetime = htonl( + dnssl->lifetime_set + ? dnssl->lifetime + : MAX(1, 0.003 * zif->rtadv.MaxRtrAdvInterval)); + + len += sizeof(struct nd_opt_dnssl); + + memcpy(buf + len, dnssl->encoded_name, dnssl->encoded_len); + len += dnssl->encoded_len; + + /* Zero-pad to 8-octet boundary */ + while (len % 8) + buf[len++] = '\0'; + } + +no_more_opts: + msg.msg_name = (void *)&addr; msg.msg_namelen = sizeof(struct sockaddr_in6); msg.msg_iov = &iov; @@ -1533,6 +1608,308 @@ DEFUN (no_ipv6_nd_mtu, return CMD_SUCCESS; } +static struct rtadv_rdnss *rtadv_rdnss_new(void) +{ + return XCALLOC(MTYPE_RTADV_RDNSS, sizeof(struct rtadv_rdnss)); +} + +static void rtadv_rdnss_free(struct rtadv_rdnss *rdnss) +{ + XFREE(MTYPE_RTADV_RDNSS, rdnss); +} + +static struct rtadv_rdnss *rtadv_rdnss_lookup(struct list *list, + struct rtadv_rdnss *rdnss) +{ + struct listnode *node; + struct rtadv_rdnss *p; + + for (ALL_LIST_ELEMENTS_RO(list, node, p)) + if (IPV6_ADDR_SAME(&p->addr, &rdnss->addr)) + return p; + return NULL; +} + +static struct rtadv_rdnss *rtadv_rdnss_get(struct list *list, + struct rtadv_rdnss *rdnss) +{ + struct rtadv_rdnss *p; + + p = rtadv_rdnss_lookup(list, rdnss); + if (p) + return p; + + p = rtadv_rdnss_new(); + memcpy(p, rdnss, sizeof(struct rtadv_rdnss)); + listnode_add(list, p); + + return p; +} + +static void rtadv_rdnss_set(struct zebra_if *zif, struct rtadv_rdnss *rdnss) +{ + struct rtadv_rdnss *p; + + p = rtadv_rdnss_get(zif->rtadv.AdvRDNSSList, rdnss); + p->lifetime = rdnss->lifetime; + p->lifetime_set = rdnss->lifetime_set; +} + +static int rtadv_rdnss_reset(struct zebra_if *zif, struct rtadv_rdnss *rdnss) +{ + struct rtadv_rdnss *p; + + p = rtadv_rdnss_lookup(zif->rtadv.AdvRDNSSList, rdnss); + if (p) { + listnode_delete(zif->rtadv.AdvRDNSSList, p); + rtadv_rdnss_free(p); + return 1; + } + + return 0; +} + +static struct rtadv_dnssl *rtadv_dnssl_new(void) +{ + return XCALLOC(MTYPE_RTADV_DNSSL, sizeof(struct rtadv_dnssl)); +} + +static void rtadv_dnssl_free(struct rtadv_dnssl *dnssl) +{ + XFREE(MTYPE_RTADV_DNSSL, dnssl); +} + +static struct rtadv_dnssl *rtadv_dnssl_lookup(struct list *list, + struct rtadv_dnssl *dnssl) +{ + struct listnode *node; + struct rtadv_dnssl *p; + + for (ALL_LIST_ELEMENTS_RO(list, node, p)) + if (!strcasecmp(p->name, dnssl->name)) + return p; + return NULL; +} + +static struct rtadv_dnssl *rtadv_dnssl_get(struct list *list, + struct rtadv_dnssl *dnssl) +{ + struct rtadv_dnssl *p; + + p = rtadv_dnssl_lookup(list, dnssl); + if (p) + return p; + + p = rtadv_dnssl_new(); + memcpy(p, dnssl, sizeof(struct rtadv_dnssl)); + listnode_add(list, p); + + return p; +} + +static void rtadv_dnssl_set(struct zebra_if *zif, struct rtadv_dnssl *dnssl) +{ + struct rtadv_dnssl *p; + + p = rtadv_dnssl_get(zif->rtadv.AdvDNSSLList, dnssl); + memcpy(p, dnssl, sizeof(struct rtadv_dnssl)); +} + +static int rtadv_dnssl_reset(struct zebra_if *zif, struct rtadv_dnssl *dnssl) +{ + struct rtadv_dnssl *p; + + p = rtadv_dnssl_lookup(zif->rtadv.AdvDNSSLList, dnssl); + if (p) { + listnode_delete(zif->rtadv.AdvDNSSLList, p); + rtadv_dnssl_free(p); + return 1; + } + + return 0; +} + +/* + * Convert dotted domain name (with or without trailing root zone dot) to + * sequence of length-prefixed labels, as described in [RFC1035 3.1]. Write up + * to strlen(in) + 2 octets to out. + * + * Returns the number of octets written to out or -1 if in does not constitute + * a valid domain name. + */ +static int rtadv_dnssl_encode(uint8_t *out, const char *in) +{ + const char *label_start, *label_end; + size_t outp; + + outp = 0; + label_start = in; + + while (*label_start) { + size_t label_len; + + label_end = strchr(label_start, '.'); + if (label_end == NULL) + label_end = label_start + strlen(label_start); + + label_len = label_end - label_start; + if (label_len >= 64) + return -1; /* labels must be 63 octets or less */ + + out[outp++] = (uint8_t)label_len; + memcpy(out + outp, label_start, label_len); + outp += label_len; + label_start += label_len; + if (*label_start == '.') + label_start++; + } + + out[outp++] = '\0'; + return outp; +} + +DEFUN(ipv6_nd_rdnss, + ipv6_nd_rdnss_cmd, + "ipv6 nd rdnss X:X::X:X [<(0-4294967295)|infinite>]", + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Recursive DNS server information\n" + "IPv6 address\n" + "Valid lifetime in seconds\n" + "Infinite valid lifetime\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct zebra_if *zif = ifp->info; + struct rtadv_rdnss rdnss = {}; + + if (inet_pton(AF_INET6, argv[3]->arg, &rdnss.addr) != 1) { + vty_out(vty, "Malformed IPv6 address\n"); + return CMD_WARNING_CONFIG_FAILED; + } + if (argc > 4) { + char *lifetime = argv[4]->type == RANGE_TKN ? argv[4]->arg + : argv[4]->text; + rdnss.lifetime = strmatch(lifetime, "infinite") + ? UINT32_MAX + : strtoll(lifetime, NULL, 10); + rdnss.lifetime_set = 1; + } + + rtadv_rdnss_set(zif, &rdnss); + + return CMD_SUCCESS; +} + +DEFUN(no_ipv6_nd_rdnss, + no_ipv6_nd_rdnss_cmd, + "no ipv6 nd rdnss X:X::X:X [<(0-4294967295)|infinite>]", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Recursive DNS server information\n" + "IPv6 address\n" + "Valid lifetime in seconds\n" + "Infinite valid lifetime\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct zebra_if *zif = ifp->info; + struct rtadv_rdnss rdnss = {}; + + if (inet_pton(AF_INET6, argv[4]->arg, &rdnss.addr) != 1) { + vty_out(vty, "Malformed IPv6 address\n"); + return CMD_WARNING_CONFIG_FAILED; + } + if (rtadv_rdnss_reset(zif, &rdnss) != 1) { + vty_out(vty, "Non-existant RDNSS address\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + return CMD_SUCCESS; +} + +DEFUN(ipv6_nd_dnssl, + ipv6_nd_dnssl_cmd, + "ipv6 nd dnssl SUFFIX [<(0-4294967295)|infinite>]", + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "DNS search list information\n" + "Domain name suffix\n" + "Valid lifetime in seconds\n" + "Infinite valid lifetime\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct zebra_if *zif = ifp->info; + struct rtadv_dnssl dnssl = {}; + size_t len; + int ret; + + len = strlcpy(dnssl.name, argv[3]->arg, sizeof(dnssl.name)); + if (len == 0 || len >= sizeof(dnssl.name)) { + vty_out(vty, "Malformed DNS search domain\n"); + return CMD_WARNING_CONFIG_FAILED; + } + if (dnssl.name[len - 1] == '.') { + /* + * Allow, but don't require, a trailing dot signifying the root + * zone. Canonicalize by cutting it off if present. + */ + dnssl.name[len - 1] = '\0'; + len--; + } + if (argc > 4) { + char *lifetime = argv[4]->type == RANGE_TKN ? argv[4]->arg + : argv[4]->text; + dnssl.lifetime = strmatch(lifetime, "infinite") + ? UINT32_MAX + : strtoll(lifetime, NULL, 10); + dnssl.lifetime_set = 1; + } + + ret = rtadv_dnssl_encode(dnssl.encoded_name, dnssl.name); + if (ret < 0) { + vty_out(vty, "Malformed DNS search domain\n"); + return CMD_WARNING_CONFIG_FAILED; + } + dnssl.encoded_len = ret; + rtadv_dnssl_set(zif, &dnssl); + + return CMD_SUCCESS; +} + +DEFUN(no_ipv6_nd_dnssl, + no_ipv6_nd_dnssl_cmd, + "no ipv6 nd dnssl SUFFIX [<(0-4294967295)|infinite>]", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "DNS search list information\n" + "Domain name suffix\n" + "Valid lifetime in seconds\n" + "Infinite valid lifetime\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct zebra_if *zif = ifp->info; + struct rtadv_dnssl dnssl = {}; + size_t len; + + len = strlcpy(dnssl.name, argv[4]->arg, sizeof(dnssl.name)); + if (len == 0 || len >= sizeof(dnssl.name)) { + vty_out(vty, "Malformed DNS search domain\n"); + return CMD_WARNING_CONFIG_FAILED; + } + if (dnssl.name[len - 1] == '.') { + dnssl.name[len - 1] = '\0'; + len--; + } + if (rtadv_dnssl_reset(zif, &dnssl) != 1) { + vty_out(vty, "Non-existant DNS search domain\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + return CMD_SUCCESS; +} + + /* Dump interface ND information to vty. */ static int nd_dump_vty(struct vty *vty, struct interface *ifp) { @@ -1607,6 +1984,8 @@ static int rtadv_config_write(struct vty *vty, struct interface *ifp) struct zebra_if *zif; struct listnode *node; struct rtadv_prefix *rprefix; + struct rtadv_rdnss *rdnss; + struct rtadv_dnssl *dnssl; char buf[PREFIX_STRLEN]; int interval; @@ -1688,6 +2067,29 @@ static int rtadv_config_write(struct vty *vty, struct interface *ifp) vty_out(vty, " router-address"); vty_out(vty, "\n"); } + for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvRDNSSList, node, rdnss)) { + char buf[INET6_ADDRSTRLEN]; + + vty_out(vty, " ipv6 nd rdnss %s", + inet_ntop(AF_INET6, &rdnss->addr, buf, sizeof(buf))); + if (rdnss->lifetime_set) { + if (rdnss->lifetime == UINT32_MAX) + vty_out(vty, " infinite"); + else + vty_out(vty, " %u", rdnss->lifetime); + } + vty_out(vty, "\n"); + } + for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvDNSSLList, node, dnssl)) { + vty_out(vty, " ipv6 nd dnssl %s", dnssl->name); + if (dnssl->lifetime_set) { + if (dnssl->lifetime == UINT32_MAX) + vty_out(vty, " infinite"); + else + vty_out(vty, " %u", dnssl->lifetime); + } + vty_out(vty, "\n"); + } return 0; } @@ -1782,6 +2184,10 @@ void rtadv_cmd_init(void) install_element(INTERFACE_NODE, &no_ipv6_nd_router_preference_cmd); install_element(INTERFACE_NODE, &ipv6_nd_mtu_cmd); install_element(INTERFACE_NODE, &no_ipv6_nd_mtu_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_rdnss_cmd); + install_element(INTERFACE_NODE, &no_ipv6_nd_rdnss_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_dnssl_cmd); + install_element(INTERFACE_NODE, &no_ipv6_nd_dnssl_cmd); } static int if_join_all_router(int sock, struct interface *ifp) diff --git a/zebra/rtadv.h b/zebra/rtadv.h index 03db13fd69..f7c27ebcb3 100644 --- a/zebra/rtadv.h +++ b/zebra/rtadv.h @@ -91,6 +91,37 @@ struct nd_opt_homeagent_info { /* Home Agent info */ } __attribute__((__packed__)); #endif +#ifndef ND_OPT_RDNSS +#define ND_OPT_RDNSS 25 +#endif +#ifndef ND_OPT_DNSSL +#define ND_OPT_DNSSL 31 +#endif + +#ifndef HAVE_STRUCT_ND_OPT_RDNSS +struct nd_opt_rdnss { /* Recursive DNS server option [RFC8106 5.1] */ + uint8_t nd_opt_rdnss_type; + uint8_t nd_opt_rdnss_len; + uint16_t nd_opt_rdnss_reserved; + uint32_t nd_opt_rdnss_lifetime; + /* Followed by one or more IPv6 addresses */ +} __attribute__((__packed__)); +#endif + +#ifndef HAVE_STRUCT_ND_OPT_DNSSL +struct nd_opt_dnssl { /* DNS search list option [RFC8106 5.2] */ + uint8_t nd_opt_dnssl_type; + uint8_t nd_opt_dnssl_len; + uint16_t nd_opt_dnssl_reserved; + uint32_t nd_opt_dnssl_lifetime; + /* + * Followed by one or more domain names encoded as in [RFC1035 3.1]. + * Multiple domain names are concatenated after encoding. In any case, + * the result is zero-padded to a multiple of 8 octets. + */ +} __attribute__((__packed__)); +#endif + extern const char *rtadv_pref_strs[]; #endif /* HAVE_RTADV */ diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 9b91289dec..4e97c272fb 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -1432,12 +1432,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) case NEXTHOP_TYPE_IPV4_IFINDEX: memset(&vtep_ip, 0, sizeof(struct ipaddr)); - if (CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) { - ifindex = get_l3vni_svi_ifindex(vrf_id); - } else { - ifindex = api_nh->ifindex; - } - + ifindex = api_nh->ifindex; if (IS_ZEBRA_DEBUG_RECV) { char nhbuf[INET6_ADDRSTRLEN] = {0}; @@ -1452,19 +1447,17 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) re, &api_nh->gate.ipv4, NULL, ifindex, api_nh->vrf_id); - /* if this an EVPN route entry, - * program the nh as neigh + /* Special handling for IPv4 routes sourced from EVPN: + * the nexthop and associated MAC need to be installed. */ if (CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) { - SET_FLAG(nexthop->flags, - NEXTHOP_FLAG_EVPN_RVTEP); vtep_ip.ipa_type = IPADDR_V4; memcpy(&(vtep_ip.ipaddr_v4), &(api_nh->gate.ipv4), sizeof(struct in_addr)); zebra_vxlan_evpn_vrf_route_add( - vrf_id, &api_nh->rmac, &vtep_ip, - &api.prefix); + api_nh->vrf_id, &api_nh->rmac, + &vtep_ip, &api.prefix); } break; case NEXTHOP_TYPE_IPV6: @@ -1473,28 +1466,21 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) break; case NEXTHOP_TYPE_IPV6_IFINDEX: memset(&vtep_ip, 0, sizeof(struct ipaddr)); - if (CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) { - ifindex = get_l3vni_svi_ifindex(vrf_id); - } else { - ifindex = api_nh->ifindex; - } - + ifindex = api_nh->ifindex; nexthop = route_entry_nexthop_ipv6_ifindex_add( re, &api_nh->gate.ipv6, ifindex, api_nh->vrf_id); - /* if this an EVPN route entry, - * program the nh as neigh + /* Special handling for IPv6 routes sourced from EVPN: + * the nexthop and associated MAC need to be installed. */ if (CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) { - SET_FLAG(nexthop->flags, - NEXTHOP_FLAG_EVPN_RVTEP); vtep_ip.ipa_type = IPADDR_V6; memcpy(&vtep_ip.ipaddr_v6, &(api_nh->gate.ipv6), sizeof(struct in6_addr)); zebra_vxlan_evpn_vrf_route_add( - vrf_id, &api_nh->rmac, &vtep_ip, - &api.prefix); + api_nh->vrf_id, &api_nh->rmac, + &vtep_ip, &api.prefix); } break; case NEXTHOP_TYPE_BLACKHOLE: diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 928169a862..df26a8534c 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -111,10 +111,13 @@ struct dplane_pw_info { int af; int status; uint32_t flags; - union g_addr nexthop; + union g_addr dest; mpls_label_t local_label; mpls_label_t remote_label; + /* Nexthops */ + struct nexthop_group nhg; + union pw_protocol_fields fields; }; @@ -386,6 +389,15 @@ static void dplane_ctx_free(struct zebra_dplane_ctx **pctx) case DPLANE_OP_PW_INSTALL: case DPLANE_OP_PW_UNINSTALL: + /* Free allocated nexthops */ + if ((*pctx)->u.pw.nhg.nexthop) { + /* This deals with recursive nexthops too */ + nexthops_free((*pctx)->u.pw.nhg.nexthop); + + (*pctx)->u.pw.nhg.nexthop = NULL; + } + break; + case DPLANE_OP_NONE: break; } @@ -520,7 +532,7 @@ const char *dplane_op2str(enum dplane_op_e op) ret = "PW_UNINSTALL"; break; - }; + } return ret; } @@ -539,7 +551,7 @@ const char *dplane_res2str(enum zebra_dplane_result res) case ZEBRA_DPLANE_REQUEST_SUCCESS: ret = "SUCCESS"; break; - }; + } return ret; } @@ -744,14 +756,15 @@ uint32_t dplane_ctx_get_lsp_flags(const struct zebra_dplane_ctx *ctx) return ctx->u.lsp.flags; } -zebra_nhlfe_t *dplane_ctx_get_nhlfe(struct zebra_dplane_ctx *ctx) +const zebra_nhlfe_t *dplane_ctx_get_nhlfe(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); return ctx->u.lsp.nhlfe_list; } -zebra_nhlfe_t *dplane_ctx_get_best_nhlfe(struct zebra_dplane_ctx *ctx) +const zebra_nhlfe_t * +dplane_ctx_get_best_nhlfe(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); @@ -814,12 +827,12 @@ int dplane_ctx_get_pw_status(const struct zebra_dplane_ctx *ctx) return ctx->u.pw.status; } -const union g_addr *dplane_ctx_get_pw_nexthop( +const union g_addr *dplane_ctx_get_pw_dest( const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return &(ctx->u.pw.nexthop); + return &(ctx->u.pw.dest); } const union pw_protocol_fields *dplane_ctx_get_pw_proto( @@ -830,6 +843,14 @@ const union pw_protocol_fields *dplane_ctx_get_pw_proto( return &(ctx->u.pw.fields); } +const struct nexthop_group * +dplane_ctx_get_pw_nhg(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return &(ctx->u.pw.nhg); +} + /* * End of dplane context accessors */ @@ -1039,7 +1060,11 @@ static int dplane_ctx_pw_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, struct zebra_pw *pw) { - int ret = AOK; + struct prefix p; + afi_t afi; + struct route_table *table; + struct route_node *rn; + struct route_entry *re; if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) zlog_debug("init dplane ctx %s: pw '%s', loc %u, rem %u", @@ -1058,6 +1083,7 @@ static int dplane_ctx_pw_init(struct zebra_dplane_ctx *ctx, /* This name appears to be c-string, so we use string copy. */ strlcpy(ctx->u.pw.ifname, pw->ifname, sizeof(ctx->u.pw.ifname)); + ctx->zd_vrf_id = pw->vrf_id; ctx->u.pw.ifindex = pw->ifindex; ctx->u.pw.type = pw->type; @@ -1066,11 +1092,38 @@ static int dplane_ctx_pw_init(struct zebra_dplane_ctx *ctx, ctx->u.pw.remote_label = pw->remote_label; ctx->u.pw.flags = pw->flags; - ctx->u.pw.nexthop = pw->nexthop; + ctx->u.pw.dest = pw->nexthop; ctx->u.pw.fields = pw->data; - return ret; + /* Capture nexthop info for the pw destination. We need to look + * up and use zebra datastructs, but we're running in the zebra + * pthread here so that should be ok. + */ + memcpy(&p.u, &pw->nexthop, sizeof(pw->nexthop)); + p.family = pw->af; + p.prefixlen = ((pw->af == AF_INET) ? + IPV4_MAX_PREFIXLEN : IPV6_MAX_PREFIXLEN); + + afi = (pw->af == AF_INET) ? AFI_IP : AFI_IP6; + table = zebra_vrf_table(afi, SAFI_UNICAST, pw->vrf_id); + if (table) { + rn = route_node_match(table, &p); + if (rn) { + RNODE_FOREACH_RE(rn, re) { + if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) + break; + } + + if (re) + copy_nexthops(&(ctx->u.pw.nhg.nexthop), + re->ng.nexthop, NULL); + + route_unlock_node(rn); + } + } + + return AOK; } /* @@ -1476,10 +1529,6 @@ int dplane_provider_register(const char *name, /* Allocate and init new provider struct */ p = XCALLOC(MTYPE_DP_PROV, sizeof(struct zebra_dplane_provider)); - if (p == NULL) { - ret = ENOMEM; - goto done; - } pthread_mutex_init(&(p->dp_mutex), NULL); TAILQ_INIT(&(p->dp_ctx_in_q)); diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 81226961e8..149ff8dc60 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -203,8 +203,9 @@ const struct nexthop_group *dplane_ctx_get_old_ng( mpls_label_t dplane_ctx_get_in_label(const struct zebra_dplane_ctx *ctx); uint8_t dplane_ctx_get_addr_family(const struct zebra_dplane_ctx *ctx); uint32_t dplane_ctx_get_lsp_flags(const struct zebra_dplane_ctx *ctx); -zebra_nhlfe_t *dplane_ctx_get_nhlfe(struct zebra_dplane_ctx *ctx); -zebra_nhlfe_t *dplane_ctx_get_best_nhlfe(struct zebra_dplane_ctx *ctx); +const zebra_nhlfe_t *dplane_ctx_get_nhlfe(const struct zebra_dplane_ctx *ctx); +const zebra_nhlfe_t *dplane_ctx_get_best_nhlfe( + const struct zebra_dplane_ctx *ctx); uint32_t dplane_ctx_get_lsp_num_ecmp(const struct zebra_dplane_ctx *ctx); /* Accessors for pseudowire information */ @@ -215,10 +216,12 @@ int dplane_ctx_get_pw_type(const struct zebra_dplane_ctx *ctx); int dplane_ctx_get_pw_af(const struct zebra_dplane_ctx *ctx); uint32_t dplane_ctx_get_pw_flags(const struct zebra_dplane_ctx *ctx); int dplane_ctx_get_pw_status(const struct zebra_dplane_ctx *ctx); -const union g_addr *dplane_ctx_get_pw_nexthop( +const union g_addr *dplane_ctx_get_pw_dest( const struct zebra_dplane_ctx *ctx); const union pw_protocol_fields *dplane_ctx_get_pw_proto( const struct zebra_dplane_ctx *ctx); +const struct nexthop_group *dplane_ctx_get_pw_nhg( + const struct zebra_dplane_ctx *ctx); /* Namespace info - esp. for netlink communication */ const struct zebra_dplane_info *dplane_ctx_get_ns( diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index 0aac7d7b12..5c375a6bef 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -85,8 +85,8 @@ static int nhlfe_nexthop_active_ipv6(zebra_nhlfe_t *nhlfe, static int nhlfe_nexthop_active(zebra_nhlfe_t *nhlfe); static void lsp_select_best_nhlfe(zebra_lsp_t *lsp); -static void lsp_uninstall_from_kernel(struct hash_backet *backet, void *ctxt); -static void lsp_schedule(struct hash_backet *backet, void *ctxt); +static void lsp_uninstall_from_kernel(struct hash_bucket *bucket, void *ctxt); +static void lsp_schedule(struct hash_bucket *bucket, void *ctxt); static wq_item_status lsp_process(struct work_queue *wq, void *data); static void lsp_processq_del(struct work_queue *wq, void *data); static void lsp_processq_complete(struct work_queue *wq); @@ -249,8 +249,7 @@ static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label, lsp->ile.in_label, lsp->flags); lsp = hash_release(lsp_table, &lsp->ile); - if (lsp) - XFREE(MTYPE_LSP, lsp); + XFREE(MTYPE_LSP, lsp); } return 0; @@ -313,8 +312,7 @@ static int lsp_uninstall(struct zebra_vrf *zvrf, mpls_label_t label) lsp->ile.in_label, lsp->flags); lsp = hash_release(lsp_table, &lsp->ile); - if (lsp) - XFREE(MTYPE_LSP, lsp); + XFREE(MTYPE_LSP, lsp); } return 0; @@ -853,11 +851,11 @@ static void lsp_select_best_nhlfe(zebra_lsp_t *lsp) * Delete LSP forwarding entry from kernel, if installed. Called upon * process exit. */ -static void lsp_uninstall_from_kernel(struct hash_backet *backet, void *ctxt) +static void lsp_uninstall_from_kernel(struct hash_bucket *bucket, void *ctxt) { zebra_lsp_t *lsp; - lsp = (zebra_lsp_t *)backet->data; + lsp = (zebra_lsp_t *)bucket->data; if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED)) (void)dplane_lsp_delete(lsp); } @@ -866,11 +864,11 @@ static void lsp_uninstall_from_kernel(struct hash_backet *backet, void *ctxt) * Schedule LSP forwarding entry for processing. Called upon changes * that may impact LSPs such as nexthop / connected route changes. */ -static void lsp_schedule(struct hash_backet *backet, void *ctxt) +static void lsp_schedule(struct hash_bucket *bucket, void *ctxt) { zebra_lsp_t *lsp; - lsp = (zebra_lsp_t *)backet->data; + lsp = (zebra_lsp_t *)bucket->data; (void)lsp_processq_add(lsp); } @@ -1048,8 +1046,7 @@ static void lsp_processq_del(struct work_queue *wq, void *data) lsp->ile.in_label, lsp->flags); lsp = hash_release(lsp_table, &lsp->ile); - if (lsp) - XFREE(MTYPE_LSP, lsp); + XFREE(MTYPE_LSP, lsp); } } @@ -1335,8 +1332,7 @@ static int mpls_lsp_uninstall_all(struct hash *lsp_table, zebra_lsp_t *lsp, lsp->ile.in_label, lsp->flags); lsp = hash_release(lsp_table, &lsp->ile); - if (lsp) - XFREE(MTYPE_LSP, lsp); + XFREE(MTYPE_LSP, lsp); } return 0; @@ -1492,7 +1488,7 @@ static json_object *lsp_json(zebra_lsp_t *lsp) static struct list *hash_get_sorted_list(struct hash *hash, void *cmp) { unsigned int i; - struct hash_backet *hb; + struct hash_bucket *hb; struct list *sorted_list = list_new(); sorted_list->cmp = (int (*)(void *, void *))cmp; @@ -1659,8 +1655,7 @@ static int snhlfe_del(zebra_snhlfe_t *snhlfe) slsp->snhlfe_list = snhlfe->next; snhlfe->prev = snhlfe->next = NULL; - if (snhlfe->ifname) - XFREE(MTYPE_SNHLFE_IFNAME, snhlfe->ifname); + XFREE(MTYPE_SNHLFE_IFNAME, snhlfe->ifname); XFREE(MTYPE_SNHLFE, snhlfe); return 0; @@ -1800,9 +1795,10 @@ void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx) break; case DPLANE_OP_LSP_DELETE: - flog_warn(EC_ZEBRA_LSP_DELETE_FAILURE, - "LSP Deletion Failure: in-label %u", - dplane_ctx_get_in_label(ctx)); + if (status != ZEBRA_DPLANE_REQUEST_SUCCESS) + flog_warn(EC_ZEBRA_LSP_DELETE_FAILURE, + "LSP Deletion Failure: in-label %u", + dplane_ctx_get_in_label(ctx)); break; default: @@ -2538,8 +2534,7 @@ int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, lsp->ile.in_label, lsp->flags); lsp = hash_release(lsp_table, &lsp->ile); - if (lsp) - XFREE(MTYPE_LSP, lsp); + XFREE(MTYPE_LSP, lsp); } } return 0; @@ -2549,12 +2544,12 @@ int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, * Uninstall all LDP NHLFEs for a particular LSP forwarding entry. * If no other NHLFEs exist, the entry would be deleted. */ -void mpls_ldp_lsp_uninstall_all(struct hash_backet *backet, void *ctxt) +void mpls_ldp_lsp_uninstall_all(struct hash_bucket *bucket, void *ctxt) { zebra_lsp_t *lsp; struct hash *lsp_table; - lsp = (zebra_lsp_t *)backet->data; + lsp = (zebra_lsp_t *)bucket->data; if (!lsp->nhlfe_list) return; @@ -2783,8 +2778,7 @@ int zebra_mpls_static_lsp_del(struct zebra_vrf *zvrf, mpls_label_t in_label, * above. */ if (!slsp->snhlfe_list) { slsp = hash_release(slsp_table, &tmp_ile); - if (slsp) - XFREE(MTYPE_SLSP, slsp); + XFREE(MTYPE_SLSP, slsp); } return 0; diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h index fb32adde31..39f084ad2f 100644 --- a/zebra/zebra_mpls.h +++ b/zebra/zebra_mpls.h @@ -291,7 +291,7 @@ int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, * Uninstall all LDP NHLFEs for a particular LSP forwarding entry. * If no other NHLFEs exist, the entry would be deleted. */ -void mpls_ldp_lsp_uninstall_all(struct hash_backet *backet, void *ctxt); +void mpls_ldp_lsp_uninstall_all(struct hash_bucket *bucket, void *ctxt); /* * Uninstall all LDP FEC-To-NHLFE (FTN) bindings of the given address-family. @@ -302,7 +302,7 @@ void mpls_ldp_ftn_uninstall_all(struct zebra_vrf *zvrf, int afi); * Uninstall all Segment Routing NHLFEs for a particular LSP forwarding entry. * If no other NHLFEs exist, the entry would be deleted. */ -void mpls_sr_lsp_uninstall_all(struct hash_backet *backet, void *ctxt); +void mpls_sr_lsp_uninstall_all(struct hash_bucket *bucket, void *ctxt); #if defined(HAVE_CUMULUS) /* diff --git a/zebra/zebra_mpls_openbsd.c b/zebra/zebra_mpls_openbsd.c index 72c8f73522..977a8eaf3c 100644 --- a/zebra/zebra_mpls_openbsd.c +++ b/zebra/zebra_mpls_openbsd.c @@ -43,7 +43,7 @@ struct { } kr_state; static int kernel_send_rtmsg_v4(int action, mpls_label_t in_label, - zebra_nhlfe_t *nhlfe) + const zebra_nhlfe_t *nhlfe) { struct iovec iov[5]; struct rt_msghdr hdr; @@ -135,7 +135,7 @@ static int kernel_send_rtmsg_v4(int action, mpls_label_t in_label, #endif static int kernel_send_rtmsg_v6(int action, mpls_label_t in_label, - zebra_nhlfe_t *nhlfe) + const zebra_nhlfe_t *nhlfe) { struct iovec iov[5]; struct rt_msghdr hdr; @@ -238,7 +238,7 @@ static int kernel_send_rtmsg_v6(int action, mpls_label_t in_label, static int kernel_lsp_cmd(struct zebra_dplane_ctx *ctx) { - zebra_nhlfe_t *nhlfe; + const zebra_nhlfe_t *nhlfe; struct nexthop *nexthop = NULL; unsigned int nexthop_num = 0; int action; @@ -342,7 +342,7 @@ static enum zebra_dplane_result kmpw_install(struct zebra_dplane_ctx *ctx) /* pseudowire nexthop */ memset(&ss, 0, sizeof(ss)); - gaddr = dplane_ctx_get_pw_nexthop(ctx); + gaddr = dplane_ctx_get_pw_dest(ctx); switch (dplane_ctx_get_pw_af(ctx)) { case AF_INET: sa_in->sin_family = AF_INET; @@ -415,7 +415,7 @@ enum zebra_dplane_result kernel_pw_update(struct zebra_dplane_ctx *ctx) break; default: break; - }; + } return result; } diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c index 833306bcc4..73db567eac 100644 --- a/zebra/zebra_pbr.c +++ b/zebra/zebra_pbr.c @@ -212,7 +212,7 @@ struct pbr_rule_unique_lookup { vrf_id_t vrf_id; }; -static int pbr_rule_lookup_unique_walker(struct hash_backet *b, void *data) +static int pbr_rule_lookup_unique_walker(struct hash_bucket *b, void *data) { struct pbr_rule_unique_lookup *pul = data; struct zebra_pbr_rule *rule = b->data; @@ -388,7 +388,7 @@ bool zebra_pbr_iptable_hash_equal(const void *arg1, const void *arg2) r2 = (const struct zebra_pbr_iptable *)arg2; if (r1->vrf_id != r2->vrf_id) - return 0; + return false; if (r1->type != r2->type) return false; if (r1->unique != r2->unique) @@ -461,7 +461,7 @@ void zebra_pbr_del_rule(struct zebra_pbr_rule *rule) __PRETTY_FUNCTION__); } -static void zebra_pbr_cleanup_rules(struct hash_backet *b, void *data) +static void zebra_pbr_cleanup_rules(struct hash_bucket *b, void *data) { struct zebra_pbr_rule *rule = b->data; int *sock = data; @@ -473,7 +473,7 @@ static void zebra_pbr_cleanup_rules(struct hash_backet *b, void *data) } } -static void zebra_pbr_cleanup_ipset(struct hash_backet *b, void *data) +static void zebra_pbr_cleanup_ipset(struct hash_bucket *b, void *data) { struct zebra_pbr_ipset *ipset = b->data; int *sock = data; @@ -484,7 +484,7 @@ static void zebra_pbr_cleanup_ipset(struct hash_backet *b, void *data) } } -static void zebra_pbr_cleanup_ipset_entry(struct hash_backet *b, void *data) +static void zebra_pbr_cleanup_ipset_entry(struct hash_bucket *b, void *data) { struct zebra_pbr_ipset_entry *ipset = b->data; int *sock = data; @@ -495,7 +495,7 @@ static void zebra_pbr_cleanup_ipset_entry(struct hash_backet *b, void *data) } } -static void zebra_pbr_cleanup_iptable(struct hash_backet *b, void *data) +static void zebra_pbr_cleanup_iptable(struct hash_bucket *b, void *data) { struct zebra_pbr_iptable *iptable = b->data; int *sock = data; @@ -576,11 +576,11 @@ const char *zebra_pbr_ipset_type2str(uint32_t type) "Unrecognized IPset Type"); } -static int zebra_pbr_ipset_pername_walkcb(struct hash_backet *backet, void *arg) +static int zebra_pbr_ipset_pername_walkcb(struct hash_bucket *bucket, void *arg) { struct pbr_ipset_name_lookup *pinl = (struct pbr_ipset_name_lookup *)arg; - struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)backet->data; + struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)bucket->data; if (!strncmp(pinl->ipset_name, zpi->ipset_name, ZEBRA_IPSET_NAME_SIZE)) { @@ -874,7 +874,7 @@ static void zebra_pbr_display_port(struct vty *vty, uint32_t filter_bm, } } -static int zebra_pbr_show_ipset_entry_walkcb(struct hash_backet *backet, +static int zebra_pbr_show_ipset_entry_walkcb(struct hash_bucket *bucket, void *arg) { struct zebra_pbr_ipset_entry_unique_display *unique = @@ -882,7 +882,7 @@ static int zebra_pbr_show_ipset_entry_walkcb(struct hash_backet *backet, struct zebra_pbr_ipset *zpi = unique->zpi; struct vty *vty = unique->vty; struct zebra_pbr_ipset_entry *zpie = - (struct zebra_pbr_ipset_entry *)backet->data; + (struct zebra_pbr_ipset_entry *)bucket->data; uint64_t pkts = 0, bytes = 0; int ret = 0; @@ -949,11 +949,11 @@ static int zebra_pbr_show_ipset_entry_walkcb(struct hash_backet *backet, return HASHWALK_CONTINUE; } -static int zebra_pbr_show_ipset_walkcb(struct hash_backet *backet, void *arg) +static int zebra_pbr_show_ipset_walkcb(struct hash_bucket *bucket, void *arg) { struct zebra_pbr_env_display *uniqueipset = (struct zebra_pbr_env_display *)arg; - struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)backet->data; + struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)bucket->data; struct zebra_pbr_ipset_entry_unique_display unique; struct vty *vty = uniqueipset->vty; struct zebra_ns *zns = uniqueipset->zns; @@ -1026,12 +1026,12 @@ struct pbr_rule_fwmark_lookup { uint32_t fwmark; }; -static int zebra_pbr_rule_lookup_fwmark_walkcb(struct hash_backet *backet, +static int zebra_pbr_rule_lookup_fwmark_walkcb(struct hash_bucket *bucket, void *arg) { struct pbr_rule_fwmark_lookup *iprule = (struct pbr_rule_fwmark_lookup *)arg; - struct zebra_pbr_rule *zpr = (struct zebra_pbr_rule *)backet->data; + struct zebra_pbr_rule *zpr = (struct zebra_pbr_rule *)bucket->data; if (iprule->fwmark == zpr->rule.filter.fwmark) { iprule->ptr = zpr; @@ -1117,10 +1117,10 @@ static void zebra_pbr_show_iptable_unit(struct zebra_pbr_iptable *iptable, } } -static int zebra_pbr_show_iptable_walkcb(struct hash_backet *backet, void *arg) +static int zebra_pbr_show_iptable_walkcb(struct hash_bucket *bucket, void *arg) { struct zebra_pbr_iptable *iptable = - (struct zebra_pbr_iptable *)backet->data; + (struct zebra_pbr_iptable *)bucket->data; struct zebra_pbr_env_display *env = (struct zebra_pbr_env_display *)arg; struct vty *vty = env->vty; struct zebra_ns *zns = env->zns; diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c index 1e942d6433..bb352dc2ff 100644 --- a/zebra/zebra_ptm.c +++ b/zebra/zebra_ptm.c @@ -328,7 +328,7 @@ DEFUN (zebra_ptm_enable_if, if (!old_ptm_enable && ptm_cb.ptm_enable) { if (!if_is_operative(ifp) && send_linkdown) { if (IS_ZEBRA_DEBUG_EVENT) - zlog_debug("%s: Bringing down interface %s\n", + zlog_debug("%s: Bringing down interface %s", __func__, ifp->name); if_down(ifp); } @@ -354,7 +354,7 @@ DEFUN (no_zebra_ptm_enable_if, ifp->ptm_enable = ZEBRA_IF_PTM_ENABLE_OFF; if (if_is_no_ptm_operative(ifp) && send_linkup) { if (IS_ZEBRA_DEBUG_EVENT) - zlog_debug("%s: Bringing up interface %s\n", + zlog_debug("%s: Bringing up interface %s", __func__, ifp->name); if_up(ifp); } @@ -1215,8 +1215,6 @@ static struct ptm_process *pp_new(pid_t pid, struct zserv *zs) /* Allocate and register new process. */ pp = XCALLOC(MTYPE_ZEBRA_PTM_BFD_PROCESS, sizeof(*pp)); - if (pp == NULL) - return NULL; pp->pp_pid = pid; pp->pp_zs = zs; diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index dcc5a7acb0..5fa51ada45 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -276,10 +276,8 @@ struct nexthop *route_entry_nexthop_ipv4_ifindex_add(struct route_entry *re, /*Pending: need to think if null ifp here is ok during bootup? There was a crash because ifp here was coming to be NULL */ if (ifp) - if (connected_is_unnumbered(ifp) - || CHECK_FLAG(re->flags, ZEBRA_FLAG_EVPN_ROUTE)) { + if (connected_is_unnumbered(ifp)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK); - } route_entry_nexthop_add(re, nexthop); @@ -314,8 +312,6 @@ struct nexthop *route_entry_nexthop_ipv6_ifindex_add(struct route_entry *re, nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX; nexthop->gate.ipv6 = *ipv6; nexthop->ifindex = ifindex; - if (CHECK_FLAG(re->flags, ZEBRA_FLAG_EVPN_ROUTE)) - SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK); route_entry_nexthop_add(re, nexthop); @@ -433,10 +429,6 @@ static int nexthop_active(afi_t afi, struct route_entry *re, re->nexthop_mtu = 0; } - /* Next hops (remote VTEPs) for EVPN routes are fully resolved. */ - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_EVPN_RVTEP)) - return 1; - /* * If the kernel has sent us a route, then * by golly gee whiz it's a good route. @@ -459,6 +451,9 @@ static int nexthop_active(afi_t afi, struct route_entry *re, * Check to see if we should trust the passed in information * for UNNUMBERED interfaces as that we won't find the GW * address in the routing table. + * This check should suffice to handle IPv4 or IPv6 routes + * sourced from EVPN routes which are installed with the + * next hop as the remote VTEP IP. */ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) { ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id); @@ -1089,7 +1084,7 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re, hook_call(rib_update, rn, "installing in kernel"); /* Send add or update */ - if (old && (old != re)) + if (old) ret = dplane_route_update(rn, re, old); else ret = dplane_route_add(rn, re); @@ -1410,7 +1405,7 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, * from ourselves we don't * over write this pointer */ - dest->selected_fib = NULL; + dest->selected_fib = new; } /* If install succeeded or system route, cleanup flags * for prior route. */ @@ -2063,6 +2058,9 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) } done: + if (rn) + route_unlock_node(rn); + /* Return context to dataplane module */ dplane_ctx_fini(&ctx); } @@ -2934,6 +2932,10 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, return; } + /* Special handling for IPv4 or IPv6 routes sourced from + * EVPN - the nexthop (and associated MAC) need to be + * uninstalled if no more refs. + */ if (CHECK_FLAG(flags, ZEBRA_FLAG_EVPN_ROUTE)) { struct nexthop *tmp_nh; @@ -3233,7 +3235,6 @@ void rib_close_table(struct route_table *table) */ static int handle_pw_result(struct zebra_dplane_ctx *ctx) { - int ret = 0; struct zebra_pw *pw; struct zebra_vrf *vrf; @@ -3252,7 +3253,7 @@ static int handle_pw_result(struct zebra_dplane_ctx *ctx) done: - return ret; + return 0; } diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 52637c6062..f601ab7e7b 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -383,7 +383,7 @@ static void zebra_rnh_eval_import_check_entry(vrf_id_t vrfid, afi_t afi, if (state_changed || force) { if (IS_ZEBRA_DEBUG_NHT) { prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN); - zlog_debug("%u:%s: Route import check %s %s\n", vrfid, + zlog_debug("%u:%s: Route import check %s %s", vrfid, bufn, rnh->state ? "passed" : "failed", state_changed ? "(state changed)" : ""); } @@ -775,7 +775,7 @@ void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, struct vty *vty, table = get_rnh_table(vrfid, afi, type); if (!table) { - zlog_debug("print_rnhs: rnh table not found\n"); + zlog_debug("print_rnhs: rnh table not found"); return; } @@ -1025,7 +1025,7 @@ static int zebra_cleanup_rnh_client(vrf_id_t vrf_id, afi_t afi, ntable = get_rnh_table(vrf_id, afi, type); if (!ntable) { - zlog_debug("cleanup_rnh_client: rnh table not found\n"); + zlog_debug("cleanup_rnh_client: rnh table not found"); return -1; } diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index 7d72583dd8..5d1cbbe781 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -127,10 +127,8 @@ static int zebra_route_match_delete(struct vty *vty, const char *command, break; } - if (dep_name) - XFREE(MTYPE_ROUTE_MAP_RULE, dep_name); - if (rmap_name) - XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name); + XFREE(MTYPE_ROUTE_MAP_RULE, dep_name); + XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name); return retval; } diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c index c3b861c242..cabc8be8dd 100644 --- a/zebra/zebra_router.c +++ b/zebra/zebra_router.c @@ -168,10 +168,31 @@ static void zebra_router_free_table(struct zebra_router_table *zrt) table_info = route_table_get_info(zrt->table); route_table_finish(zrt->table); + RB_REMOVE(zebra_router_table_head, &zrouter.tables, zrt); + XFREE(MTYPE_RIB_TABLE_INFO, table_info); XFREE(MTYPE_ZEBRA_NS, zrt); } +void zebra_router_release_table(struct zebra_vrf *zvrf, uint32_t tableid, + afi_t afi, safi_t safi) +{ + struct zebra_router_table finder; + struct zebra_router_table *zrt; + + memset(&finder, 0, sizeof(finder)); + finder.afi = afi; + finder.safi = safi; + finder.tableid = tableid; + finder.ns_id = zvrf->zns->ns_id; + zrt = RB_FIND(zebra_router_table_head, &zrouter.tables, &finder); + + if (!zrt) + return; + + zebra_router_free_table(zrt); +} + uint32_t zebra_router_get_next_sequence(void) { return 1 diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h index fb28495917..e5043f38ae 100644 --- a/zebra/zebra_router.h +++ b/zebra/zebra_router.h @@ -117,6 +117,8 @@ extern struct route_table *zebra_router_find_table(struct zebra_vrf *zvrf, extern struct route_table *zebra_router_get_table(struct zebra_vrf *zvrf, uint32_t tableid, afi_t afi, safi_t safi); +extern void zebra_router_release_table(struct zebra_vrf *zvrf, uint32_t tableid, + afi_t afi, safi_t safi); extern int zebra_router_config_write(struct vty *vty); diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index d18305495b..90f94902f3 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -167,6 +167,11 @@ static int zebra_vrf_disable(struct vrf *vrf) /* Remove all routes. */ for (afi = AFI_IP; afi <= AFI_IP6; afi++) { + route_table_finish(zvrf->rnh_table[afi]); + zvrf->rnh_table[afi] = NULL; + route_table_finish(zvrf->import_check_table[afi]); + zvrf->import_check_table[afi] = NULL; + for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) rib_close_table(zvrf->table[afi][safi]); } @@ -208,13 +213,11 @@ static int zebra_vrf_disable(struct vrf *vrf) * table, see rib_close_table above * we no-longer need this pointer. */ - for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) + for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) { + zebra_router_release_table(zvrf, zvrf->table_id, afi, + safi); zvrf->table[afi][safi] = NULL; - - route_table_finish(zvrf->rnh_table[afi]); - zvrf->rnh_table[afi] = NULL; - route_table_finish(zvrf->import_check_table[afi]); - zvrf->import_check_table[afi] = NULL; + } } return 0; @@ -256,19 +259,19 @@ static int zebra_vrf_delete(struct vrf *vrf) /* release allocated memory */ for (afi = AFI_IP; afi <= AFI_IP6; afi++) { - void *table_info; - for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) { table = zvrf->table[afi][safi]; if (table) { - table_info = route_table_get_info(table); - route_table_finish(table); - XFREE(MTYPE_RIB_TABLE_INFO, table_info); + zebra_router_release_table(zvrf, zvrf->table_id, + afi, safi); + zvrf->table[afi][safi] = NULL; } } - route_table_finish(zvrf->rnh_table[afi]); - route_table_finish(zvrf->import_check_table[afi]); + if (zvrf->rnh_table[afi]) + route_table_finish(zvrf->rnh_table[afi]); + if (zvrf->import_check_table[afi]) + route_table_finish(zvrf->import_check_table[afi]); } /* Cleanup EVPN states for vrf */ @@ -351,8 +354,7 @@ void zebra_rtable_node_cleanup(struct route_table *table, rib_unlink(node, re); } - if (node->info) - XFREE(MTYPE_RIB_DEST, node->info); + XFREE(MTYPE_RIB_DEST, node->info); } static void zebra_rnhtable_node_cleanup(struct route_table *table, diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 537820f7ea..b0884f22cf 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -383,6 +383,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, json_object *json_labels = NULL; time_t uptime; struct tm *tm; + rib_dest_t *dest = rib_dest_from_rnode(rn); uptime = time(NULL); uptime -= re->uptime; @@ -407,6 +408,10 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) json_object_boolean_true_add(json_route, "selected"); + if (dest->selected_fib == re) + json_object_boolean_true_add(json_route, + "destSelected"); + json_object_int_add(json_route, "distance", re->distance); json_object_int_add(json_route, "metric", re->metric); diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 560cd89abd..b44c314d5b 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -65,19 +65,19 @@ DEFINE_MTYPE_STATIC(ZEBRA, NEIGH, "VNI Neighbor"); static int ip_prefix_send_to_client(vrf_id_t vrf_id, struct prefix *p, uint16_t cmd); static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json); -static void zvni_print_neigh_hash(struct hash_backet *backet, void *ctxt); -static void zvni_print_dad_neigh_hash(struct hash_backet *backet, void *ctxt); -static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet, +static void zvni_print_neigh_hash(struct hash_bucket *bucket, void *ctxt); +static void zvni_print_dad_neigh_hash(struct hash_bucket *bucket, void *ctxt); +static void zvni_print_neigh_hash_all_vni(struct hash_bucket *bucket, void **args); static void zl3vni_print_nh(zebra_neigh_t *n, struct vty *vty, json_object *json); static void zl3vni_print_rmac(zebra_mac_t *zrmac, struct vty *vty, json_object *json); static void zvni_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json); -static void zvni_print_mac_hash(struct hash_backet *backet, void *ctxt); -static void zvni_print_mac_hash_all_vni(struct hash_backet *backet, void *ctxt); +static void zvni_print_mac_hash(struct hash_bucket *bucket, void *ctxt); +static void zvni_print_mac_hash_all_vni(struct hash_bucket *bucket, void *ctxt); static void zvni_print(zebra_vni_t *zvni, void **ctxt); -static void zvni_print_hash(struct hash_backet *backet, void *ctxt[]); +static void zvni_print_hash(struct hash_bucket *bucket, void *ctxt[]); static int zvni_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr, struct ipaddr *ip, uint8_t flags, @@ -117,7 +117,7 @@ static int zl3vni_nh_install(zebra_l3vni_t *zl3vni, zebra_neigh_t *n); static int zl3vni_nh_uninstall(zebra_l3vni_t *zl3vni, zebra_neigh_t *n); /* l3-vni rmac related APIs */ -static void zl3vni_print_rmac_hash(struct hash_backet *, void *); +static void zl3vni_print_rmac_hash(struct hash_bucket *, void *); static zebra_mac_t *zl3vni_rmac_lookup(zebra_l3vni_t *zl3vni, struct ethaddr *rmac); static void *zl3vni_rmac_alloc(void *p); @@ -155,7 +155,7 @@ static zebra_vni_t *zvni_map_vlan(struct interface *ifp, struct interface *br_if, vlanid_t vid); static int zvni_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac); static int zvni_mac_uninstall(zebra_vni_t *zvni, zebra_mac_t *mac); -static void zvni_install_mac_hash(struct hash_backet *backet, void *ctxt); +static void zvni_install_mac_hash(struct hash_bucket *bucket, void *ctxt); static unsigned int vni_hash_keymake(void *p); static void *zvni_alloc(void *p); @@ -257,7 +257,7 @@ static uint32_t num_valid_macs(zebra_vni_t *zvni) unsigned int i; uint32_t num_macs = 0; struct hash *hash; - struct hash_backet *hb; + struct hash_bucket *hb; zebra_mac_t *mac; hash = zvni->mac_table; @@ -281,7 +281,7 @@ static uint32_t num_dup_detected_macs(zebra_vni_t *zvni) unsigned int i; uint32_t num_macs = 0; struct hash *hash; - struct hash_backet *hb; + struct hash_bucket *hb; zebra_mac_t *mac; hash = zvni->mac_table; @@ -303,7 +303,7 @@ static uint32_t num_dup_detected_neighs(zebra_vni_t *zvni) unsigned int i; uint32_t num_neighs = 0; struct hash *hash; - struct hash_backet *hb; + struct hash_bucket *hb; zebra_neigh_t *nbr; hash = zvni->neigh_table; @@ -674,14 +674,14 @@ static void zebra_vxlan_dup_addr_detect_for_neigh(struct zebra_vrf *zvrf, * display - just because we're dealing with IPv6 addresses that can * widely vary. */ -static void zvni_find_neigh_addr_width(struct hash_backet *backet, void *ctxt) +static void zvni_find_neigh_addr_width(struct hash_bucket *bucket, void *ctxt) { zebra_neigh_t *n; char buf[INET6_ADDRSTRLEN]; struct neigh_walk_ctx *wctx = ctxt; int width; - n = (zebra_neigh_t *)backet->data; + n = (zebra_neigh_t *)bucket->data; ipaddr2str(&n->ip, buf, sizeof(buf)); width = strlen(buf); @@ -767,8 +767,7 @@ static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json) n->detect_start_time.tv_sec); char tmp_buf[30]; - memset(tmp_buf, 0, 30); - strncpy(tmp_buf, buf, strlen(buf) - 1); + strlcpy(tmp_buf, buf, sizeof(tmp_buf)); vty_out(vty, " Duplicate detection started at %s, detection count %u\n", tmp_buf, n->dad_count); @@ -791,7 +790,7 @@ static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json) /* * Print neighbor hash entry - called for display of all neighbors. */ -static void zvni_print_neigh_hash(struct hash_backet *backet, void *ctxt) +static void zvni_print_neigh_hash(struct hash_bucket *bucket, void *ctxt) { struct vty *vty; json_object *json_vni = NULL, *json_row = NULL; @@ -803,7 +802,7 @@ static void zvni_print_neigh_hash(struct hash_backet *backet, void *ctxt) vty = wctx->vty; json_vni = wctx->json; - n = (zebra_neigh_t *)backet->data; + n = (zebra_neigh_t *)bucket->data; if (json_vni) json_row = json_object_new_object(); @@ -887,7 +886,7 @@ static void zvni_print_neigh_hash(struct hash_backet *backet, void *ctxt) /* * Print neighbor hash entry in detail - called for display of all neighbors. */ -static void zvni_print_neigh_hash_detail(struct hash_backet *backet, void *ctxt) +static void zvni_print_neigh_hash_detail(struct hash_bucket *bucket, void *ctxt) { struct vty *vty; json_object *json_vni = NULL, *json_row = NULL; @@ -897,7 +896,7 @@ static void zvni_print_neigh_hash_detail(struct hash_backet *backet, void *ctxt) vty = wctx->vty; json_vni = wctx->json; - n = (zebra_neigh_t *)backet->data; + n = (zebra_neigh_t *)bucket->data; if (!n) return; @@ -914,7 +913,7 @@ static void zvni_print_neigh_hash_detail(struct hash_backet *backet, void *ctxt) /* * Print neighbors for all VNI. */ -static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet, +static void zvni_print_neigh_hash_all_vni(struct hash_bucket *bucket, void **args) { struct vty *vty; @@ -929,7 +928,7 @@ static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet, json = (json_object *)args[1]; print_dup = (uint32_t)(uintptr_t)args[2]; - zvni = (zebra_vni_t *)backet->data; + zvni = (zebra_vni_t *)bucket->data; num_neigh = hashcount(zvni->neigh_table); @@ -978,35 +977,35 @@ static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet, json_object_object_add(json, vni_str, json_vni); } -static void zvni_print_dad_neigh_hash(struct hash_backet *backet, void *ctxt) +static void zvni_print_dad_neigh_hash(struct hash_bucket *bucket, void *ctxt) { zebra_neigh_t *nbr; - nbr = (zebra_neigh_t *)backet->data; + nbr = (zebra_neigh_t *)bucket->data; if (!nbr) return; if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) - zvni_print_neigh_hash(backet, ctxt); + zvni_print_neigh_hash(bucket, ctxt); } -static void zvni_print_dad_neigh_hash_detail(struct hash_backet *backet, +static void zvni_print_dad_neigh_hash_detail(struct hash_bucket *bucket, void *ctxt) { zebra_neigh_t *nbr; - nbr = (zebra_neigh_t *)backet->data; + nbr = (zebra_neigh_t *)bucket->data; if (!nbr) return; if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) - zvni_print_neigh_hash_detail(backet, ctxt); + zvni_print_neigh_hash_detail(bucket, ctxt); } /* * Print neighbors for all VNIs in detail. */ -static void zvni_print_neigh_hash_all_vni_detail(struct hash_backet *backet, +static void zvni_print_neigh_hash_all_vni_detail(struct hash_bucket *bucket, void **args) { struct vty *vty; @@ -1021,7 +1020,7 @@ static void zvni_print_neigh_hash_all_vni_detail(struct hash_backet *backet, json = (json_object *)args[1]; print_dup = (uint32_t)(uintptr_t)args[2]; - zvni = (zebra_vni_t *)backet->data; + zvni = (zebra_vni_t *)bucket->data; if (!zvni) { if (json) vty_out(vty, "{}\n"); @@ -1148,7 +1147,7 @@ static void zvni_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json) struct vty *vty; zebra_neigh_t *n = NULL; struct listnode *node = NULL; - char buf1[20]; + char buf1[ETHER_ADDR_STRLEN]; char buf2[INET6_ADDRSTRLEN]; struct zebra_vrf *zvrf; struct timeval detect_start_time = {0, 0}; @@ -1289,8 +1288,7 @@ static void zvni_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json) mac->detect_start_time.tv_sec); char tmp_buf[30]; - memset(tmp_buf, 0, 30); - strncpy(tmp_buf, buf, strlen(buf) - 1); + strlcpy(tmp_buf, buf, sizeof(tmp_buf)); vty_out(vty, " Duplicate detection started at %s, detection count %u\n", tmp_buf, mac->dad_count); @@ -1318,17 +1316,17 @@ static void zvni_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json) /* * Print MAC hash entry - called for display of all MACs. */ -static void zvni_print_mac_hash(struct hash_backet *backet, void *ctxt) +static void zvni_print_mac_hash(struct hash_bucket *bucket, void *ctxt) { struct vty *vty; json_object *json_mac_hdr = NULL, *json_mac = NULL; zebra_mac_t *mac; - char buf1[20]; + char buf1[ETHER_ADDR_STRLEN]; struct mac_walk_ctx *wctx = ctxt; vty = wctx->vty; json_mac_hdr = wctx->json; - mac = (zebra_mac_t *)backet->data; + mac = (zebra_mac_t *)bucket->data; prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1)); @@ -1424,32 +1422,32 @@ static void zvni_print_mac_hash(struct hash_backet *backet, void *ctxt) } /* Print Duplicate MAC */ -static void zvni_print_dad_mac_hash(struct hash_backet *backet, void *ctxt) +static void zvni_print_dad_mac_hash(struct hash_bucket *bucket, void *ctxt) { zebra_mac_t *mac; - mac = (zebra_mac_t *)backet->data; + mac = (zebra_mac_t *)bucket->data; if (!mac) return; if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) - zvni_print_mac_hash(backet, ctxt); + zvni_print_mac_hash(bucket, ctxt); } /* * Print MAC hash entry in detail - called for display of all MACs. */ -static void zvni_print_mac_hash_detail(struct hash_backet *backet, void *ctxt) +static void zvni_print_mac_hash_detail(struct hash_bucket *bucket, void *ctxt) { struct vty *vty; json_object *json_mac_hdr = NULL; zebra_mac_t *mac; struct mac_walk_ctx *wctx = ctxt; - char buf1[20]; + char buf1[ETHER_ADDR_STRLEN]; vty = wctx->vty; json_mac_hdr = wctx->json; - mac = (zebra_mac_t *)backet->data; + mac = (zebra_mac_t *)bucket->data; if (!mac) return; @@ -1460,23 +1458,23 @@ static void zvni_print_mac_hash_detail(struct hash_backet *backet, void *ctxt) } /* Print Duplicate MAC in detail */ -static void zvni_print_dad_mac_hash_detail(struct hash_backet *backet, +static void zvni_print_dad_mac_hash_detail(struct hash_bucket *bucket, void *ctxt) { zebra_mac_t *mac; - mac = (zebra_mac_t *)backet->data; + mac = (zebra_mac_t *)bucket->data; if (!mac) return; if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) - zvni_print_mac_hash_detail(backet, ctxt); + zvni_print_mac_hash_detail(bucket, ctxt); } /* * Print MACs for all VNI. */ -static void zvni_print_mac_hash_all_vni(struct hash_backet *backet, void *ctxt) +static void zvni_print_mac_hash_all_vni(struct hash_bucket *bucket, void *ctxt) { struct vty *vty; json_object *json = NULL, *json_vni = NULL; @@ -1489,7 +1487,7 @@ static void zvni_print_mac_hash_all_vni(struct hash_backet *backet, void *ctxt) vty = (struct vty *)wctx->vty; json = (struct json_object *)wctx->json; - zvni = (zebra_vni_t *)backet->data; + zvni = (zebra_vni_t *)bucket->data; wctx->zvni = zvni; /*We are iterating over a new VNI, set the count to 0*/ @@ -1546,7 +1544,7 @@ static void zvni_print_mac_hash_all_vni(struct hash_backet *backet, void *ctxt) /* * Print MACs in detail for all VNI. */ -static void zvni_print_mac_hash_all_vni_detail(struct hash_backet *backet, +static void zvni_print_mac_hash_all_vni_detail(struct hash_bucket *bucket, void *ctxt) { struct vty *vty; @@ -1560,7 +1558,7 @@ static void zvni_print_mac_hash_all_vni_detail(struct hash_backet *backet, vty = (struct vty *)wctx->vty; json = (struct json_object *)wctx->json; - zvni = (zebra_vni_t *)backet->data; + zvni = (zebra_vni_t *)bucket->data; if (!zvni) { if (json) vty_out(vty, "{}\n"); @@ -1609,7 +1607,7 @@ static void zvni_print_mac_hash_all_vni_detail(struct hash_backet *backet, } } -static void zl3vni_print_nh_hash(struct hash_backet *backet, void *ctx) +static void zl3vni_print_nh_hash(struct hash_bucket *bucket, void *ctx) { struct nh_walk_ctx *wctx = NULL; struct vty *vty = NULL; @@ -1624,7 +1622,7 @@ static void zl3vni_print_nh_hash(struct hash_backet *backet, void *ctx) json_vni = wctx->json; if (json_vni) json_nh = json_object_new_object(); - n = (zebra_neigh_t *)backet->data; + n = (zebra_neigh_t *)bucket->data; if (!json_vni) { vty_out(vty, "%-15s %-17s\n", @@ -1642,7 +1640,7 @@ static void zl3vni_print_nh_hash(struct hash_backet *backet, void *ctx) } } -static void zl3vni_print_nh_hash_all_vni(struct hash_backet *backet, +static void zl3vni_print_nh_hash_all_vni(struct hash_bucket *bucket, void **args) { struct vty *vty = NULL; @@ -1656,7 +1654,7 @@ static void zl3vni_print_nh_hash_all_vni(struct hash_backet *backet, vty = (struct vty *)args[0]; json = (struct json_object *)args[1]; - zl3vni = (zebra_l3vni_t *)backet->data; + zl3vni = (zebra_l3vni_t *)bucket->data; num_nh = hashcount(zl3vni->nh_table); if (!num_nh) @@ -1681,7 +1679,7 @@ static void zl3vni_print_nh_hash_all_vni(struct hash_backet *backet, json_object_object_add(json, vni_str, json_vni); } -static void zl3vni_print_rmac_hash_all_vni(struct hash_backet *backet, +static void zl3vni_print_rmac_hash_all_vni(struct hash_bucket *bucket, void **args) { struct vty *vty = NULL; @@ -1695,7 +1693,7 @@ static void zl3vni_print_rmac_hash_all_vni(struct hash_backet *backet, vty = (struct vty *)args[0]; json = (struct json_object *)args[1]; - zl3vni = (zebra_l3vni_t *)backet->data; + zl3vni = (zebra_l3vni_t *)bucket->data; num_rmacs = hashcount(zl3vni->rmac_table); if (!num_rmacs) @@ -1724,7 +1722,7 @@ static void zl3vni_print_rmac_hash_all_vni(struct hash_backet *backet, json_object_object_add(json, vni_str, json_vni); } -static void zl3vni_print_rmac_hash(struct hash_backet *backet, void *ctx) +static void zl3vni_print_rmac_hash(struct hash_bucket *bucket, void *ctx) { zebra_mac_t *zrmac = NULL; struct rmac_walk_ctx *wctx = NULL; @@ -1738,7 +1736,7 @@ static void zl3vni_print_rmac_hash(struct hash_backet *backet, void *ctx) json = wctx->json; if (json) json_rmac = json_object_new_object(); - zrmac = (zebra_mac_t *)backet->data; + zrmac = (zebra_mac_t *)bucket->data; if (!json) { vty_out(vty, "%-17s %-21s\n", @@ -1904,7 +1902,7 @@ static void zvni_print(zebra_vni_t *zvni, void **ctxt) } /* print a L3 VNI hash entry */ -static void zl3vni_print_hash(struct hash_backet *backet, void *ctx[]) +static void zl3vni_print_hash(struct hash_bucket *bucket, void *ctx[]) { struct vty *vty = NULL; json_object *json = NULL; @@ -1914,7 +1912,7 @@ static void zl3vni_print_hash(struct hash_backet *backet, void *ctx[]) vty = (struct vty *)ctx[0]; json = (json_object *)ctx[1]; - zl3vni = (zebra_l3vni_t *)backet->data; + zl3vni = (zebra_l3vni_t *)bucket->data; if (!json) { vty_out(vty, "%-10u %-4s %-21s %-8lu %-8lu %-15s %-37s\n", @@ -1950,7 +1948,7 @@ struct zvni_evpn_show { }; /* print a L3 VNI hash entry in detail*/ -static void zl3vni_print_hash_detail(struct hash_backet *backet, void *data) +static void zl3vni_print_hash_detail(struct hash_bucket *bucket, void *data) { struct vty *vty = NULL; zebra_l3vni_t *zl3vni = NULL; @@ -1964,7 +1962,7 @@ static void zl3vni_print_hash_detail(struct hash_backet *backet, void *data) if (json) use_json = true; - zl3vni = (zebra_l3vni_t *)backet->data; + zl3vni = (zebra_l3vni_t *)bucket->data; zebra_vxlan_print_vni(vty, zes->zvrf, zl3vni->vni, use_json); vty_out(vty, "\n"); @@ -1974,7 +1972,7 @@ static void zl3vni_print_hash_detail(struct hash_backet *backet, void *data) /* * Print a VNI hash entry - called for display of all VNIs. */ -static void zvni_print_hash(struct hash_backet *backet, void *ctxt[]) +static void zvni_print_hash(struct hash_bucket *bucket, void *ctxt[]) { struct vty *vty; zebra_vni_t *zvni; @@ -1990,7 +1988,7 @@ static void zvni_print_hash(struct hash_backet *backet, void *ctxt[]) vty = ctxt[0]; json = ctxt[1]; - zvni = (zebra_vni_t *)backet->data; + zvni = (zebra_vni_t *)bucket->data; zvtep = zvni->vteps; while (zvtep) { @@ -2038,7 +2036,7 @@ static void zvni_print_hash(struct hash_backet *backet, void *ctxt[]) /* * Print a VNI hash entry in detail - called for display of all VNIs. */ -static void zvni_print_hash_detail(struct hash_backet *backet, void *data) +static void zvni_print_hash_detail(struct hash_bucket *bucket, void *data) { struct vty *vty; zebra_vni_t *zvni; @@ -2052,7 +2050,7 @@ static void zvni_print_hash_detail(struct hash_backet *backet, void *data) if (json) use_json = true; - zvni = (zebra_vni_t *)backet->data; + zvni = (zebra_vni_t *)bucket->data; zebra_vxlan_print_vni(vty, zes->zvrf, zvni->vni, use_json); vty_out(vty, "\n"); @@ -2192,6 +2190,7 @@ static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip, memcpy(&n->emac, mac, ETH_ALEN); n->state = ZEBRA_NEIGH_INACTIVE; + n->zvni = zvni; /* Associate the neigh to mac */ zmac = zvni_mac_lookup(zvni, mac); @@ -2215,8 +2214,7 @@ static int zvni_neigh_del(zebra_vni_t *zvni, zebra_neigh_t *n) /* Free the VNI hash entry and allocated memory. */ tmp_n = hash_release(zvni->neigh_table, n); - if (tmp_n) - XFREE(MTYPE_NEIGH, tmp_n); + XFREE(MTYPE_NEIGH, tmp_n); return 0; } @@ -2224,10 +2222,10 @@ static int zvni_neigh_del(zebra_vni_t *zvni, zebra_neigh_t *n) /* * Free neighbor hash entry (callback) */ -static void zvni_neigh_del_hash_entry(struct hash_backet *backet, void *arg) +static void zvni_neigh_del_hash_entry(struct hash_bucket *bucket, void *arg) { struct neigh_walk_ctx *wctx = arg; - zebra_neigh_t *n = backet->data; + zebra_neigh_t *n = bucket->data; if (((wctx->flags & DEL_LOCAL_NEIGH) && (n->flags & ZEBRA_NEIGH_LOCAL)) || ((wctx->flags & DEL_REMOTE_NEIGH) @@ -2557,12 +2555,12 @@ static int zvni_neigh_probe(zebra_vni_t *zvni, zebra_neigh_t *n) /* * Install neighbor hash entry - called upon access VLAN change. */ -static void zvni_install_neigh_hash(struct hash_backet *backet, void *ctxt) +static void zvni_install_neigh_hash(struct hash_bucket *bucket, void *ctxt) { zebra_neigh_t *n; struct neigh_walk_ctx *wctx = ctxt; - n = (zebra_neigh_t *)backet->data; + n = (zebra_neigh_t *)bucket->data; if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) zvni_neigh_install(wctx->zvni, n); @@ -2819,7 +2817,7 @@ static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni, return 0; } -static void zvni_gw_macip_del_for_vni_hash(struct hash_backet *backet, +static void zvni_gw_macip_del_for_vni_hash(struct hash_bucket *bucket, void *ctxt) { zebra_vni_t *zvni = NULL; @@ -2830,7 +2828,7 @@ static void zvni_gw_macip_del_for_vni_hash(struct hash_backet *backet, struct interface *ifp; /* Add primary SVI MAC*/ - zvni = (zebra_vni_t *)backet->data; + zvni = (zebra_vni_t *)bucket->data; ifp = zvni->vxlan_if; if (!ifp) @@ -2859,7 +2857,7 @@ static void zvni_gw_macip_del_for_vni_hash(struct hash_backet *backet, return; } -static void zvni_gw_macip_add_for_vni_hash(struct hash_backet *backet, +static void zvni_gw_macip_add_for_vni_hash(struct hash_bucket *bucket, void *ctxt) { zebra_vni_t *zvni = NULL; @@ -2869,7 +2867,7 @@ static void zvni_gw_macip_add_for_vni_hash(struct hash_backet *backet, struct interface *vrr_if = NULL; struct interface *ifp = NULL; - zvni = (zebra_vni_t *)backet->data; + zvni = (zebra_vni_t *)bucket->data; ifp = zvni->vxlan_if; if (!ifp) @@ -2899,7 +2897,7 @@ static void zvni_gw_macip_add_for_vni_hash(struct hash_backet *backet, return; } -static void zvni_svi_macip_del_for_vni_hash(struct hash_backet *backet, +static void zvni_svi_macip_del_for_vni_hash(struct hash_bucket *bucket, void *ctxt) { zebra_vni_t *zvni = NULL; @@ -2909,7 +2907,7 @@ static void zvni_svi_macip_del_for_vni_hash(struct hash_backet *backet, struct interface *ifp; /* Add primary SVI MAC*/ - zvni = (zebra_vni_t *)backet->data; + zvni = (zebra_vni_t *)bucket->data; if (!zvni) return; @@ -2989,8 +2987,12 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni, } zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); - if (!zvrf) + if (!zvrf) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("\tUnable to find vrf for: %d", + zvni->vxlan_if->vrf_id); return -1; + } /* Check if the neighbor exists. */ n = zvni_neigh_lookup(zvni, ip); @@ -3020,6 +3022,9 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni, cur_is_router = !!CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG); if (!mac_different && is_router == cur_is_router) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "\tIgnoring entry mac is the same and is_router == cur_is_router"); n->ifindex = ifp->ifindex; return 0; } @@ -3048,6 +3053,11 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni, return zvni_neigh_send_add_to_client( zvni->vni, ip, macaddr, n->flags, n->loc_seq); + else { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "\tNeighbor active and frozen"); + } return 0; } @@ -3188,6 +3198,10 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni, if (!neigh_on_hold) return zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, n->flags, n->loc_seq); + else { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("\tNeighbor on hold not sending"); + } return 0; } @@ -3311,8 +3325,7 @@ static int zvni_mac_del(zebra_vni_t *zvni, zebra_mac_t *mac) /* Free the VNI hash entry and allocated memory. */ tmp_mac = hash_release(zvni->mac_table, mac); - if (tmp_mac) - XFREE(MTYPE_MAC, tmp_mac); + XFREE(MTYPE_MAC, tmp_mac); return 0; } @@ -3320,10 +3333,10 @@ static int zvni_mac_del(zebra_vni_t *zvni, zebra_mac_t *mac) /* * Free MAC hash entry (callback) */ -static void zvni_mac_del_hash_entry(struct hash_backet *backet, void *arg) +static void zvni_mac_del_hash_entry(struct hash_bucket *bucket, void *arg) { struct mac_walk_ctx *wctx = arg; - zebra_mac_t *mac = backet->data; + zebra_mac_t *mac = bucket->data; if (((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_LOCAL)) || ((wctx->flags & DEL_REMOTE_MAC) @@ -3664,12 +3677,12 @@ static int zvni_mac_uninstall(zebra_vni_t *zvni, zebra_mac_t *mac) /* * Install MAC hash entry - called upon access VLAN change. */ -static void zvni_install_mac_hash(struct hash_backet *backet, void *ctxt) +static void zvni_install_mac_hash(struct hash_bucket *bucket, void *ctxt) { zebra_mac_t *mac; struct mac_walk_ctx *wctx = ctxt; - mac = (zebra_mac_t *)backet->data; + mac = (zebra_mac_t *)bucket->data; if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) zvni_mac_install(wctx->zvni, mac); @@ -3864,8 +3877,7 @@ static int zvni_del(zebra_vni_t *zvni) /* Free the VNI hash entry and allocated memory. */ tmp_zvni = hash_release(zvrf->vni_table, zvni); - if (tmp_zvni) - XFREE(MTYPE_ZVNI, tmp_zvni); + XFREE(MTYPE_ZVNI, tmp_zvni); return 0; } @@ -4142,13 +4154,13 @@ static int zvni_vtep_uninstall(zebra_vni_t *zvni, struct in_addr *vtep_ip) * Install or uninstall flood entries in the kernel corresponding to * remote VTEPs. This is invoked upon change to BUM handling. */ -static void zvni_handle_flooding_remote_vteps(struct hash_backet *backet, +static void zvni_handle_flooding_remote_vteps(struct hash_bucket *bucket, void *zvrf) { zebra_vni_t *zvni; zebra_vtep_t *zvtep; - zvni = (zebra_vni_t *)backet->data; + zvni = (zebra_vni_t *)bucket->data; if (!zvni) return; @@ -4163,13 +4175,13 @@ static void zvni_handle_flooding_remote_vteps(struct hash_backet *backet, /* * Cleanup VNI/VTEP and update kernel */ -static void zvni_cleanup_all(struct hash_backet *backet, void *arg) +static void zvni_cleanup_all(struct hash_bucket *bucket, void *arg) { zebra_vni_t *zvni = NULL; zebra_l3vni_t *zl3vni = NULL; struct zebra_vrf *zvrf = (struct zebra_vrf *)arg; - zvni = (zebra_vni_t *)backet->data; + zvni = (zebra_vni_t *)bucket->data; /* remove from l3-vni list */ if (zvrf->l3vni) @@ -4189,11 +4201,11 @@ static void zvni_cleanup_all(struct hash_backet *backet, void *arg) } /* cleanup L3VNI */ -static void zl3vni_cleanup_all(struct hash_backet *backet, void *args) +static void zl3vni_cleanup_all(struct hash_bucket *bucket, void *args) { zebra_l3vni_t *zl3vni = NULL; - zl3vni = (zebra_l3vni_t *)backet->data; + zl3vni = (zebra_l3vni_t *)bucket->data; zebra_vxlan_process_l3vni_oper_down(zl3vni); } @@ -4301,8 +4313,7 @@ static int zl3vni_rmac_del(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac) } tmp_rmac = hash_release(zl3vni->rmac_table, zrmac); - if (tmp_rmac) - XFREE(MTYPE_MAC, tmp_rmac); + XFREE(MTYPE_MAC, tmp_rmac); return 0; } @@ -4478,8 +4489,7 @@ static int zl3vni_nh_del(zebra_l3vni_t *zl3vni, zebra_neigh_t *n) } tmp_n = hash_release(zl3vni->nh_table, n); - if (tmp_n) - XFREE(MTYPE_NEIGH, tmp_n); + XFREE(MTYPE_NEIGH, tmp_n); return 0; } @@ -4711,8 +4721,7 @@ static int zl3vni_del(zebra_l3vni_t *zl3vni) /* Free the VNI hash entry and allocated memory. */ tmp_zl3vni = hash_release(zrouter.l3vni_table, zl3vni); - if (tmp_zl3vni) - XFREE(MTYPE_ZL3VNI, tmp_zl3vni); + XFREE(MTYPE_ZL3VNI, tmp_zl3vni); return 0; } @@ -4877,6 +4886,7 @@ static int zl3vni_send_add_to_client(zebra_l3vni_t *zl3vni) stream_put(s, &rmac, sizeof(struct ethaddr)); stream_put_in_addr(s, &zl3vni->local_vtep_ip); stream_put(s, &zl3vni->filter, sizeof(int)); + stream_putl(s, zl3vni->svi_if->ifindex); /* Write packet size. */ stream_putw_at(s, 0, stream_get_endp(s)); @@ -4944,9 +4954,9 @@ static void zebra_vxlan_process_l3vni_oper_down(zebra_l3vni_t *zl3vni) zl3vni_send_del_to_client(zl3vni); } -static void zvni_add_to_l3vni_list(struct hash_backet *backet, void *ctxt) +static void zvni_add_to_l3vni_list(struct hash_bucket *bucket, void *ctxt) { - zebra_vni_t *zvni = (zebra_vni_t *)backet->data; + zebra_vni_t *zvni = (zebra_vni_t *)bucket->data; zebra_l3vni_t *zl3vni = (zebra_l3vni_t *)ctxt; if (zvni->vrf_id == zl3vni_vrf_id(zl3vni)) @@ -5007,24 +5017,24 @@ static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf, vni_t vni, } /* delete and uninstall rmac hash entry */ -static void zl3vni_del_rmac_hash_entry(struct hash_backet *backet, void *ctx) +static void zl3vni_del_rmac_hash_entry(struct hash_bucket *bucket, void *ctx) { zebra_mac_t *zrmac = NULL; zebra_l3vni_t *zl3vni = NULL; - zrmac = (zebra_mac_t *)backet->data; + zrmac = (zebra_mac_t *)bucket->data; zl3vni = (zebra_l3vni_t *)ctx; zl3vni_rmac_uninstall(zl3vni, zrmac); zl3vni_rmac_del(zl3vni, zrmac); } /* delete and uninstall nh hash entry */ -static void zl3vni_del_nh_hash_entry(struct hash_backet *backet, void *ctx) +static void zl3vni_del_nh_hash_entry(struct hash_bucket *bucket, void *ctx) { zebra_neigh_t *n = NULL; zebra_l3vni_t *zl3vni = NULL; - n = (zebra_neigh_t *)backet->data; + n = (zebra_neigh_t *)bucket->data; zl3vni = (zebra_l3vni_t *)ctx; zl3vni_nh_uninstall(zl3vni, n); zl3vni_nh_del(zl3vni, n); @@ -5770,7 +5780,7 @@ void zebra_vxlan_print_rmacs_all_l3vni(struct vty *vty, bool use_json) args[0] = vty; args[1] = json; hash_iterate(zrouter.l3vni_table, - (void (*)(struct hash_backet *, + (void (*)(struct hash_bucket *, void *))zl3vni_print_rmac_hash_all_vni, args); @@ -5887,7 +5897,7 @@ void zebra_vxlan_print_nh_all_l3vni(struct vty *vty, bool use_json) args[0] = vty; args[1] = json; hash_iterate(zrouter.l3vni_table, - (void (*)(struct hash_backet *, + (void (*)(struct hash_bucket *, void *))zl3vni_print_nh_hash_all_vni, args); @@ -6048,7 +6058,7 @@ void zebra_vxlan_print_neigh_all_vni(struct vty *vty, struct zebra_vrf *zvrf, args[2] = (void *)(ptrdiff_t)print_dup; hash_iterate(zvrf->vni_table, - (void (*)(struct hash_backet *, + (void (*)(struct hash_bucket *, void *))zvni_print_neigh_hash_all_vni, args); if (use_json) { @@ -6079,7 +6089,7 @@ void zebra_vxlan_print_neigh_all_vni_detail(struct vty *vty, args[2] = (void *)(ptrdiff_t)print_dup; hash_iterate(zvrf->vni_table, - (void (*)(struct hash_backet *, + (void (*)(struct hash_bucket *, void *))zvni_print_neigh_hash_all_vni_detail, args); if (use_json) { @@ -6641,7 +6651,7 @@ int zebra_vxlan_clear_dup_detect_vni_ip(struct vty *vty, return CMD_SUCCESS; } -static void zvni_clear_dup_mac_hash(struct hash_backet *backet, void *ctxt) +static void zvni_clear_dup_mac_hash(struct hash_bucket *bucket, void *ctxt) { struct mac_walk_ctx *wctx = ctxt; zebra_mac_t *mac; @@ -6649,7 +6659,7 @@ static void zvni_clear_dup_mac_hash(struct hash_backet *backet, void *ctxt) struct listnode *node = NULL; zebra_neigh_t *nbr = NULL; - mac = (zebra_mac_t *)backet->data; + mac = (zebra_mac_t *)bucket->data; if (!mac) return; @@ -6696,14 +6706,14 @@ static void zvni_clear_dup_mac_hash(struct hash_backet *backet, void *ctxt) } } -static void zvni_clear_dup_neigh_hash(struct hash_backet *backet, void *ctxt) +static void zvni_clear_dup_neigh_hash(struct hash_bucket *bucket, void *ctxt) { struct neigh_walk_ctx *wctx = ctxt; zebra_neigh_t *nbr; zebra_vni_t *zvni; char buf[INET6_ADDRSTRLEN]; - nbr = (zebra_neigh_t *)backet->data; + nbr = (zebra_neigh_t *)bucket->data; if (!nbr) return; @@ -6736,7 +6746,7 @@ static void zvni_clear_dup_neigh_hash(struct hash_backet *backet, void *ctxt) } } -static void zvni_clear_dup_detect_hash_vni_all(struct hash_backet *backet, +static void zvni_clear_dup_detect_hash_vni_all(struct hash_bucket *bucket, void **args) { struct vty *vty; @@ -6745,7 +6755,7 @@ static void zvni_clear_dup_detect_hash_vni_all(struct hash_backet *backet, struct mac_walk_ctx m_wctx; struct neigh_walk_ctx n_wctx; - zvni = (zebra_vni_t *)backet->data; + zvni = (zebra_vni_t *)bucket->data; if (!zvni) return; @@ -6783,7 +6793,7 @@ int zebra_vxlan_clear_dup_detect_vni_all(struct vty *vty, args[1] = zvrf; hash_iterate(zvrf->vni_table, - (void (*)(struct hash_backet *, void *)) + (void (*)(struct hash_bucket *, void *)) zvni_clear_dup_detect_hash_vni_all, args); return CMD_SUCCESS; @@ -7009,12 +7019,12 @@ void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf, /* Display all L2-VNIs */ hash_iterate(zvrf->vni_table, - (void (*)(struct hash_backet *, void *))zvni_print_hash, + (void (*)(struct hash_bucket *, void *))zvni_print_hash, args); /* Display all L3-VNIs */ hash_iterate(zrouter.l3vni_table, - (void (*)(struct hash_backet *, void *))zl3vni_print_hash, + (void (*)(struct hash_bucket *, void *))zl3vni_print_hash, args); if (use_json) { @@ -7092,19 +7102,21 @@ void zebra_vxlan_print_vnis_detail(struct vty *vty, struct zebra_vrf *zvrf, zes.zvrf = zvrf; /* Display all L2-VNIs */ - hash_iterate(zvrf->vni_table, (void (*)(struct hash_backet *, - void *))zvni_print_hash_detail, - &zes); + hash_iterate( + zvrf->vni_table, + (void (*)(struct hash_bucket *, void *))zvni_print_hash_detail, + &zes); /* Display all L3-VNIs */ hash_iterate(zrouter.l3vni_table, - (void (*)(struct hash_backet *, + (void (*)(struct hash_bucket *, void *))zl3vni_print_hash_detail, &zes); if (use_json) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); json_object_free(json); } } @@ -7584,7 +7596,7 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp, if (!zvni) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "Add/Update %sMAC %s intf %s(%u) VID %u, could not find VNI", + "\tAdd/Update %sMAC %s intf %s(%u) VID %u, could not find VNI", sticky ? "sticky " : "", prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name, ifp->ifindex, vid); @@ -7592,15 +7604,20 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp, } if (!zvni->vxlan_if) { - zlog_debug( - "VNI %u hash %p doesn't have intf upon local MAC ADD", - zvni->vni, zvni); + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "\tVNI %u hash %p doesn't have intf upon local MAC ADD", + zvni->vni, zvni); return -1; } zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); - if (!zvrf) + if (!zvrf) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("\tNo Vrf found for vrf_id: %d", + zvni->vxlan_if->vrf_id); return -1; + } /* Check if we need to create or update or it is a NO-OP. */ mac = zvni_mac_lookup(zvni, macaddr); @@ -7650,7 +7667,7 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp, && mac->fwd_info.local.vid == vid) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "Add/Update %sMAC %s intf %s(%u) VID %u -> VNI %u, " + "\tAdd/Update %sMAC %s intf %s(%u) VID %u -> VNI %u, " "entry exists and has not changed ", sticky ? "sticky " : "", prefix_mac2str(macaddr, buf, @@ -9162,16 +9179,16 @@ static int zebra_vxlan_dad_ip_auto_recovery_exp(struct thread *t) nbr = THREAD_ARG(t); /* since this is asynchronous we need sanity checks*/ - nbr = zvni_neigh_lookup(zvni, &nbr->ip); - if (!nbr) + zvrf = vrf_info_lookup(nbr->zvni->vrf_id); + if (!zvrf) return 0; zvni = zvni_lookup(nbr->zvni->vni); if (!zvni) return 0; - zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); - if (!zvrf) + nbr = zvni_neigh_lookup(zvni, &nbr->ip); + if (!nbr) return 0; if (IS_ZEBRA_DEBUG_VXLAN) @@ -9212,16 +9229,16 @@ static int zebra_vxlan_dad_mac_auto_recovery_exp(struct thread *t) mac = THREAD_ARG(t); /* since this is asynchronous we need sanity checks*/ - mac = zvni_mac_lookup(zvni, &mac->macaddr); - if (!mac) + zvrf = vrf_info_lookup(mac->zvni->vrf_id); + if (!zvrf) return 0; zvni = zvni_lookup(mac->zvni->vni); if (!zvni) return 0; - zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); - if (!zvrf) + mac = zvni_mac_lookup(zvni, &mac->macaddr); + if (!mac) return 0; if (IS_ZEBRA_DEBUG_VXLAN) |
