diff options
220 files changed, 5824 insertions, 1753 deletions
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/bfd.c b/bfdd/bfd.c index afd5d814a0..c8adf82a83 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -36,7 +36,9 @@ DEFINE_QOBJ_TYPE(bfd_session); /* * Prototypes */ -static struct bfd_session *bs_peer_waiting_find(struct bfd_peer_cfg *bpc); +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); @@ -52,66 +54,47 @@ 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 */ -static struct bfd_session *bs_peer_waiting_find(struct bfd_peer_cfg *bpc) +void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer, + struct sockaddr_any *local, bool mhop, const char *ifname, + const char *vrfname) { - struct bfd_session_observer *bso; - struct bfd_session *bs = NULL; - bool is_shop, is_ipv4; - - TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) { - bs = bso->bso_bs; - - is_shop = !BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH); - is_ipv4 = !BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6); - /* Quick checks first. */ - if (is_shop != (!bpc->bpc_mhop)) - continue; - if (is_ipv4 != bpc->bpc_ipv4) - continue; - - /* - * Slow lookup without hash because we don't have all - * information yet. - */ - if (is_shop) { - if (strcmp(bs->ifname, bpc->bpc_localif)) - continue; - if (memcmp(&bs->shop.peer, &bpc->bpc_peer, - sizeof(bs->shop.peer))) - continue; - - break; - } - - if (strcmp(bs->vrfname, bpc->bpc_vrfname)) - continue; - if (memcmp(&bs->mhop.peer, &bpc->bpc_peer, - sizeof(bs->mhop.peer))) - continue; - if (memcmp(&bs->mhop.local, &bpc->bpc_local, - sizeof(bs->mhop.local))) - continue; + 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; } - if (bso == NULL) - bs = NULL; - return bs; + 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 interface *ifp; - struct vrf *vrf; - struct bfd_mhop_key mhop; - struct bfd_shop_key shop; + struct bfd_key key; /* Try to find label first. */ if (bpc->bpc_has_label) { @@ -123,38 +106,10 @@ 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) { - vrf = vrf_lookup_by_name(bpc->bpc_vrfname); - if (vrf == NULL) - return NULL; - - mhop.vrfid = vrf->vrf_id; - } + gen_bfd_key(&key, &bpc->bpc_peer, &bpc->bpc_local, bpc->bpc_mhop, + bpc->bpc_localif, bpc->bpc_vrfname); - bs = bfd_mhop_lookup(mhop); - } else { - memset(&shop, 0, sizeof(shop)); - shop.peer = bpc->bpc_peer; - if (bpc->bpc_has_localif) { - ifp = if_lookup_by_name_all_vrf(bpc->bpc_localif); - if (ifp == NULL) - return NULL; - - shop.ifindex = ifp->ifindex; - } - - bs = bfd_shop_lookup(shop); - } - - if (bs != NULL) - return bs; - - /* Search for entries that are incomplete. */ - return bs_peer_waiting_find(bpc); + return bfd_key_lookup(key); } /* @@ -165,7 +120,6 @@ struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc) */ int bfd_session_enable(struct bfd_session *bs) { - struct sockaddr_in6 *sin6; struct interface *ifp = NULL; struct vrf *vrf = NULL; int psock; @@ -174,8 +128,8 @@ int bfd_session_enable(struct bfd_session *bs) * If the interface or VRF doesn't exist, then we must register * the session but delay its start. */ - if (bs->ifname[0] != 0) { - ifp = if_lookup_by_name_all_vrf(bs->ifname); + 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."); @@ -184,15 +138,17 @@ int bfd_session_enable(struct bfd_session *bs) vrf = vrf_lookup_by_id(ifp->vrf_id); if (vrf == NULL) { - log_error("session-enable: specified VRF doesn't exists."); + log_error( + "session-enable: specified VRF doesn't exists."); return 0; } } - if (bs->vrfname[0] != 0) { - vrf = vrf_lookup_by_name(bs->vrfname); + 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."); + log_error( + "session-enable: specified VRF doesn't exists."); return 0; } } @@ -202,26 +158,15 @@ int bfd_session_enable(struct bfd_session *bs) if (bs->vrf == NULL) bs->vrf = vrf_lookup_by_id(VRF_DEFAULT); - if (bs->ifname[0] != 0 && - BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0) + if (bs->key.ifname[0] + && BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0) bs->ifp = ifp; - /* Set the IPv6 scope id for link-local addresses. */ - if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6)) { - sin6 = &bs->mhop.peer.sa_sin6; - if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) - sin6->sin6_scope_id = bs->ifp != NULL - ? bs->ifp->ifindex - : IFINDEX_INTERNAL; - - sin6 = &bs->mhop.local.sa_sin6; - if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) - sin6->sin6_scope_id = bs->ifp != NULL - ? bs->ifp->ifindex - : IFINDEX_INTERNAL; - - bs->local_ip.sa_sin6 = *sin6; - bs->local_address.sa_sin6 = *sin6; + /* Sanity check: don't leak open sockets. */ + if (bs->sock != -1) { + zlog_debug("session-enable: previous socket open"); + close(bs->sock); + bs->sock = -1; } /* @@ -232,11 +177,11 @@ int bfd_session_enable(struct bfd_session *bs) if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6) == 0) { psock = bp_peer_socket(bs); if (psock == -1) - return -1; + return 0; } else { psock = bp_peer_socketv6(bs); if (psock == -1) - return -1; + return 0; } /* @@ -247,25 +192,6 @@ int bfd_session_enable(struct bfd_session *bs) bfd_recvtimer_update(bs); ptm_bfd_start_xmt_timer(bs, false); - /* Registrate session into data structures. */ - bs->discrs.my_discr = ptm_bfd_gen_ID(); - bfd_id_insert(bs); - if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) { - if (vrf != NULL) - bs->mhop.vrfid = vrf->vrf_id; - else - bs->mhop.vrfid = VRF_DEFAULT; - - bfd_mhop_insert(bs); - } else { - if (ifp != NULL) - bs->shop.ifindex = ifp->ifindex; - else - bs->shop.ifindex = IFINDEX_INTERNAL; - - bfd_shop_insert(bs); - } - return 0; } @@ -288,13 +214,6 @@ void bfd_session_disable(struct bfd_session *bs) bfd_echo_recvtimer_delete(bs); bfd_xmttimer_delete(bs); bfd_echo_xmttimer_delete(bs); - - /* Unregister session from hashes to avoid unwanted activation. */ - 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); } static uint32_t ptm_bfd_gen_ID(void) @@ -438,21 +357,20 @@ 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, @@ -461,32 +379,30 @@ struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp, 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; + 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; - mhop.vrfid = vrfid; - - l_bfd = bfd_mhop_lookup(mhop); - } else { - memset(&shop, 0, sizeof(shop)); - shop.peer = *peer; - shop.ifindex = ifindex; + 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_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) @@ -551,8 +467,6 @@ 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); @@ -703,6 +617,9 @@ static void bfd_session_free(struct bfd_session *bs) bfd_session_disable(bs); + bfd_key_delete(bs->key); + bfd_id_delete(bs->discrs.my_discr); + /* Remove observer if any. */ TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) { if (bso->bso_bs != bs) @@ -745,29 +662,47 @@ struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc) * start. See `bfd_session_enable` for more information. */ if (bpc->bpc_has_localif) - strlcpy(bfd->ifname, bpc->bpc_localif, sizeof(bfd->ifname)); + strlcpy(bfd->key.ifname, bpc->bpc_localif, + sizeof(bfd->key.ifname)); if (bpc->bpc_has_vrfname) - strlcpy(bfd->vrfname, bpc->bpc_vrfname, sizeof(bfd->vrfname)); - - /* Add observer if we have moving parts. */ - if (bfd->ifname[0] || bfd->vrfname[0]) - bs_observer_add(bfd); + strlcpy(bfd->key.vrfname, bpc->bpc_vrfname, + sizeof(bfd->key.vrfname)); /* Copy remaining data. */ if (bpc->bpc_ipv4 == false) BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6); - 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; - } else { - bfd->shop.peer = bpc->bpc_peer; + 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; + + 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; + + default: + assert(1); + break; } - bfd->local_ip = bpc->bpc_local; - bfd->local_address = bpc->bpc_local; + if (bpc->bpc_mhop) + BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_MH); + + bfd->key.mhop = bpc->bpc_mhop; + + /* Registrate session into data structures. */ + bfd_key_insert(bfd); + bfd->discrs.my_discr = ptm_bfd_gen_ID(); + bfd_id_insert(bfd); /* Try to enable session and schedule for packet receive/send. */ if (bfd_session_enable(bfd) == -1) { @@ -776,6 +711,10 @@ struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc) return NULL; } + /* Add observer if we have moving parts. */ + if (bfd->key.ifname[0] || bfd->key.vrfname[0] || bfd->sock == -1) + bs_observer_add(bfd); + /* Apply other configurations. */ _bfd_session_update(bfd, bpc); @@ -1221,35 +1160,26 @@ 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.vrfid != VRF_DEFAULT) - snprintf(buf + pos, sizeof(buf) - pos, " vrf:%u", - bs->mhop.vrfid); - } else { - pos += snprintf(buf + pos, sizeof(buf) - pos, " peer:%s", - satostr(&bs->shop.peer)); - - if (bs->local_address.sa_sin.sin_family) - pos += snprintf(buf + pos, sizeof(buf) - pos, - " local:%s", - satostr(&bs->local_address)); - - if (bs->shop.ifindex) - snprintf(buf + pos, sizeof(buf) - pos, " ifindex:%u", - bs->shop.ifindex); - } - + 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; } @@ -1261,12 +1191,20 @@ int bs_observer_add(struct bfd_session *bs) 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->ifname, + strlcpy(bso->bso_entryname, bs->key.ifname, sizeof(bso->bso_entryname)); else - strlcpy(bso->bso_entryname, bs->vrfname, + 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)); + } + TAILQ_INSERT_TAIL(&bglobal.bg_obslist, bso, bso_entry); return 0; @@ -1278,21 +1216,59 @@ void bs_observer_del(struct bfd_session_observer *bso) 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.peer, + 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.peer, + 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)); + } +} + /* * 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_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 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 unsigned int bfd_key_hash_do(void *p); static void _bfd_free(struct hash_bucket *hb, void *arg __attribute__((__unused__))); @@ -1313,73 +1289,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; } -/* 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); - bs->shop.ifindex = IFINDEX_INTERNAL; -} - -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; - } -} /* * Hash public interface / exported functions. @@ -1395,32 +1318,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.ifindex != 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; + /* 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); - _mhop_key(&bs, &mhop); + /* 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_mhop_hash, &bs); + return bsp; } /* @@ -1442,31 +1366,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.ifindex != 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); + return hash_release(bfd_key_hash, bsp); } /* Iteration functions. */ @@ -1475,14 +1386,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) -{ - hash_iterate(bfd_shop_hash, hif, arg); -} - -void bfd_mhop_iterate(hash_iter_func hif, void *arg) +void bfd_key_iterate(hash_iter_func hif, void *arg) { - hash_iterate(bfd_mhop_hash, hif, arg); + hash_iterate(bfd_key_hash, hif, arg); } /* @@ -1496,24 +1402,17 @@ 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) -{ - return (hash_get(bfd_shop_hash, bs, hash_alloc_intern) == bs); -} - -bool bfd_mhop_insert(struct bfd_session *bs) +bool bfd_key_insert(struct bfd_session *bs) { - return (hash_get(bfd_mhop_hash, bs, hash_alloc_intern) == bs); + 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 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_bucket *hb, @@ -1534,11 +1433,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); + 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_key_hash); } diff --git a/bfdd/bfd.h b/bfdd/bfd.h index 7451ca82a3..a69ff9a1a7 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -173,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; - ifindex_t ifindex; -}; - -struct bfd_mhop_key { - struct sockaddr_any peer; - struct sockaddr_any local; - vrf_id_t vrfid; +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 { @@ -227,19 +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; struct vrf *vrf; - char ifname[MAXNAMELEN]; - char vrfname[MAXNAMELEN]; + + int sock; /* BFD session flags */ enum bfd_session_flags flags; @@ -281,7 +274,11 @@ struct bfd_state_str_list { struct bfd_session_observer { struct bfd_session *bso_bs; bool bso_isinterface; - char bso_entryname[MAXNAMELEN]; + bool bso_isaddress; + union { + char bso_entryname[MAXNAMELEN]; + struct prefix bso_addr; + }; TAILQ_ENTRY(bfd_session_observer) bso_entry; }; @@ -531,38 +528,28 @@ 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_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; @@ -572,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 45c5f5dbdc..69d27ed698 100644 --- a/bfdd/bfd_packet.c +++ b/bfdd/bfd_packet.c @@ -79,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)) @@ -92,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)) @@ -120,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; @@ -135,31 +138,34 @@ 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)); + 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)); + 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; @@ -544,7 +550,7 @@ int bfd_recv_cb(struct thread *t) } /* Validate packet TTL. */ - if ((is_mhop == false) && (ttl != BFD_TTL_VAL)) { + 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; @@ -602,8 +608,8 @@ int bfd_recv_cb(struct thread *t) 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; } /* @@ -917,25 +923,26 @@ int bp_peer_socket(const struct bfd_session *bs) return -1; } - if (bs->shop.ifindex != IFINDEX_INTERNAL) { - if (bp_bind_dev(sd, bs->ifp->name) != 0) { + if (bs->key.ifname[0]) { + if (bp_bind_dev(sd, bs->key.ifname) != 0) { close(sd); return -1; } - } else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) && - bs->mhop.vrfid != VRF_DEFAULT) { - if (bp_bind_dev(sd, bs->vrf->name) != 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; } } /* Find an available source port in the proper range */ - sin = bs->local_ip.sa_sin; + memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN sin.sin_len = sizeof(sin); #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ + 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; @@ -987,20 +994,23 @@ int bp_peer_socketv6(const struct bfd_session *bs) } /* Find an available source port in the proper range */ - sin6 = bs->local_ip.sa_sin6; + memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN sin6.sin6_len = sizeof(sin6); #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ + 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 (bs->shop.ifindex != IFINDEX_INTERNAL) { - if (bp_bind_dev(sd, bs->ifp->name) != 0) { + if (bs->key.ifname[0]) { + if (bp_bind_dev(sd, bs->key.ifname) != 0) { close(sd); return -1; } - } else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) && - bs->mhop.vrfid != VRF_DEFAULT) { - if (bp_bind_dev(sd, bs->vrf->name) != 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_vty.c b/bfdd/bfdd_vty.c index 0041f9cc2e..c139492076 100644 --- a/bfdd/bfdd_vty.c +++ b/bfdd/bfdd_vty.c @@ -79,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. */ @@ -369,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->vrfname[0]) - vty_out(vty, " vrf %s", bs->vrfname); - 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->ifname[0]) - vty_out(vty, " interface %s", bs->ifname); - 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); @@ -453,22 +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->vrfname[0]) - json_object_string_add(jo, "vrf", bs->vrfname); - } 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->ifname[0]) - json_object_string_add(jo, "interface", bs->ifname); - } + + 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); @@ -564,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; @@ -647,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; @@ -916,25 +921,29 @@ static int bfdd_write_config(struct vty *vty) static void _bfdd_peer_write_config(struct vty *vty, struct bfd_session *bs) { - if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) { - vty_out(vty, " peer %s", satostr(&bs->mhop.peer)); + char addr_buf[INET6_ADDRSTRLEN]; + + vty_out(vty, " peer %s", + inet_ntop(bs->key.family, &bs->key.peer, addr_buf, + sizeof(addr_buf))); + + if (bs->key.mhop) vty_out(vty, " multihop"); - vty_out(vty, " local-address %s", satostr(&bs->mhop.local)); - if (bs->vrfname[0]) - vty_out(vty, " vrf %s", bs->vrfname); - 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->ifname[0]) - vty_out(vty, " interface %s", bs->ifname); - 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 or interface doesn't exist\n"); + 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); @@ -980,16 +989,7 @@ static void _bfdd_peer_write_config_iter(struct hash_bucket *hb, void *arg) static int bfdd_peer_write_config(struct vty *vty) { - struct bfd_session_observer *bso; - bfd_id_iterate(_bfdd_peer_write_config_iter, vty); - TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) { - /* Only print disabled sessions here. */ - if (bso->bso_bs->sock != -1) - continue; - - _bfdd_peer_write_config(vty, bso->bso_bs); - } return 1; } diff --git a/bfdd/config.c b/bfdd/config.c index d1342eff1e..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.vrfid != VRF_DEFAULT) { - bpc->bpc_has_vrfname = true; - strlcpy(bpc->bpc_vrfname, pl->pl_bs->vrf->name, - sizeof(bpc->bpc_vrfname)); - } - } else { - bpc->bpc_peer = pl->pl_bs->shop.peer; - if (pl->pl_bs->ifname[0]) { - bpc->bpc_has_localif = true; - strlcpy(bpc->bpc_localif, pl->pl_bs->ifname, - sizeof(bpc->bpc_localif)); - } - } + bs_to_bpc(pl->pl_bs, bpc); return 0; } @@ -519,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"); @@ -528,21 +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 (bs->vrfname[0]) - json_object_string_add(jo, "vrf-name", bs->vrfname); + 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 (bs->ifname[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->ifname); + 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 40f4f4d3be..c308d647d8 100644 --- a/bfdd/control.c +++ b/bfdd/control.c @@ -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); @@ -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/ptm_adapter.c b/bfdd/ptm_adapter.c index 3f1512d8e7..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; - } } } @@ -608,7 +551,7 @@ static void bfdd_sessions_enable_interface(struct interface *ifp) /* Interface name mismatch. */ bs = bso->bso_bs; - if (strcmp(ifp->name, bs->ifname)) + if (strcmp(ifp->name, bs->key.ifname)) continue; /* Skip enabled sessions. */ if (bs->sock != -1) @@ -630,7 +573,7 @@ static void bfdd_sessions_disable_interface(struct interface *ifp) /* Interface name mismatch. */ bs = bso->bso_bs; - if (strcmp(ifp->name, bs->ifname)) + if (strcmp(ifp->name, bs->key.ifname)) continue; /* Skip disabled sessions. */ if (bs->sock == -1) @@ -691,6 +634,48 @@ static int bfdd_interface_vrf_update(int command __attribute__((__unused__)), 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; +} + void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv) { zclient = zclient_new(master, &zclient_options_default); @@ -713,6 +698,10 @@ void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv) /* 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) @@ -752,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); @@ -799,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_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 51833394d9..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); @@ -2096,3 +2099,110 @@ void aspath_print_all_vty(struct vty *vty) 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 e731af754c..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); } @@ -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; } 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 361df826fa..19cda453f5 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -184,8 +184,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 +294,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 +964,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; @@ -3941,7 +3935,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; @@ -4027,7 +4021,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); @@ -4882,8 +4876,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", @@ -5108,8 +5103,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; @@ -5189,8 +5182,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)); @@ -5405,7 +5396,8 @@ static void link_l2vni_hash_to_l3vni(struct hash_bucket *bucket, } 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 */ @@ -5453,14 +5445,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) diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index dfe141c40e..22fb0939c9 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -173,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 8437c4024e..fb2d9da533 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -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; } 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_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 4a408df858..49b5854020 100644 --- a/bgpd/bgp_mac.c +++ b/bgpd/bgp_mac.c @@ -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,10 +347,7 @@ 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; } 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_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 2d3ff8b695..35634c9ec1 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -1094,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; @@ -1115,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 */ diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c index 4c51db8e14..c0be36ed3f 100644 --- a/bgpd/bgp_pbr.c +++ b/bgpd/bgp_pbr.c @@ -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." 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 0b6c536f5a..eca632dd44 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -3096,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; } @@ -3285,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)) @@ -3457,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)) @@ -4469,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); } @@ -5034,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 = @@ -5046,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; @@ -5066,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 = @@ -5352,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); @@ -5461,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; @@ -5488,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; @@ -5585,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)); @@ -5737,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; @@ -5746,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; @@ -5781,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; @@ -5814,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; @@ -5824,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, @@ -5986,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. */ @@ -5995,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) { @@ -6021,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); @@ -6052,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); @@ -6096,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); @@ -6149,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; } @@ -11259,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); @@ -11847,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 1527571278..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)) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 17109281bc..c276f5ef7b 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -197,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; @@ -324,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); } @@ -837,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') { @@ -998,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; } @@ -1555,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); } @@ -2046,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; } @@ -2141,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; } @@ -3105,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; } @@ -3399,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); } @@ -4351,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; } @@ -4450,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; } 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 b74dc33ea4..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); 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 2aa4e3ecd4..3e100f2f0a 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -2841,18 +2841,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; @@ -3251,7 +3256,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; } @@ -7163,7 +7168,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, @@ -8031,7 +8036,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)); @@ -8071,7 +8076,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( @@ -8522,7 +8527,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, @@ -10945,6 +10950,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)) @@ -10973,17 +10986,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) { @@ -11049,7 +11099,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, @@ -11058,7 +11109,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); @@ -11151,6 +11202,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); @@ -11166,13 +11218,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); } @@ -11267,8 +11335,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; @@ -11277,13 +11346,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) { @@ -11354,11 +11420,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(); @@ -11422,6 +11489,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, @@ -11441,6 +11556,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)) { @@ -11470,7 +11586,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, @@ -14456,8 +14578,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); @@ -14508,8 +14629,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..5f0b20e029 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; @@ -2486,6 +2496,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 +2506,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/bgpd.c b/bgpd/bgpd.c index a920cfeeec..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) { @@ -3404,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); @@ -3435,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); } @@ -4368,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); @@ -4378,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; @@ -5125,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; } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index dde1501d30..7a77c8b3ee 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]; @@ -517,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) diff --git a/bgpd/rfapi/bgp_rfapi_cfg.c b/bgpd/rfapi/bgp_rfapi_cfg.c index d621d58e48..2220f0ed9a 100644 --- a/bgpd/rfapi/bgp_rfapi_cfg.c +++ b/bgpd/rfapi/bgp_rfapi_cfg.c @@ -3457,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); @@ -3815,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(); @@ -3878,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/configure.ac b/configure.ac index fcfc4bd2fb..9ae196fcb1 100755 --- a/configure.ac +++ b/configure.ac @@ -765,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) diff --git a/doc/user/installation.rst b/doc/user/installation.rst index 4e1582ccd8..e191ebd035 100644 --- a/doc/user/installation.rst +++ b/doc/user/installation.rst @@ -275,7 +275,8 @@ options from the list below. For backwards compatability 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/eigrpd/eigrp_fsm.c b/eigrpd/eigrp_fsm.c index 374114cf55..22f5a5ddb1 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"; } diff --git a/eigrpd/eigrp_hello.c b/eigrpd/eigrp_hello.c index b4d850be08..dacd5caeb5 100644 --- a/eigrpd/eigrp_hello.c +++ b/eigrpd/eigrp_hello.c @@ -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_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_vty.c b/eigrpd/eigrp_vty.c index a9b103de47..fc5bdbdbc5 100644 --- a/eigrpd/eigrp_vty.c +++ b/eigrpd/eigrp_vty.c @@ -1499,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 */ @@ -1525,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/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/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_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_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 3364a9f0be..2d1d6f5927 100644 --- a/isisd/isis_northbound.c +++ b/isisd/isis_northbound.c @@ -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; } diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 330da9b216..107de47f3d 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -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_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/command.c b/lib/command.c index b46241ac87..559457c119 100644 --- a/lib/command.c +++ b/lib/command.c @@ -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_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/distribute.c b/lib/distribute.c index 7cc10a230d..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. */ 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/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/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_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/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/hash.c b/lib/hash.c index 9f9fc31d37..c02b81814c 100644 --- a/lib/hash.c +++ b/lib/hash.c @@ -95,8 +95,6 @@ static void hash_expand(struct hash *hash) new_index = XCALLOC(MTYPE_HASH_INDEX, sizeof(struct hash_bucket *) * new_size); - if (new_index == NULL) - return; hash->stats.empty = new_size; @@ -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); @@ -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); } @@ -708,8 +707,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); } @@ -1349,8 +1347,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); @@ -1366,8 +1363,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; } diff --git a/lib/if_rmap.c b/lib/if_rmap.c index 7ac5368171..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_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 8dded2cb48..dfc7298823 100644 --- a/lib/if_rmap.h +++ b/lib/if_rmap.h @@ -34,12 +34,33 @@ 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 } 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/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/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/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]; @@ -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); 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/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/nexthop.h b/lib/nexthop.h index c79ec590a8..fd27ca207b 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -83,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)) diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index 23ea96f75c..f940418d83 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -205,11 +205,9 @@ 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); XFREE(MTYPE_TMP, nh); } diff --git a/lib/northbound.c b/lib/northbound.c index 15139aa8d0..edf7e0eca6 100644 --- a/lib/northbound.c +++ b/lib/northbound.c @@ -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_DESTROY; + 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); diff --git a/lib/northbound_confd.c b/lib/northbound_confd.c index a8e0017819..a499d48c12 100644 --- a/lib/northbound_confd.c +++ b/lib/northbound_confd.c @@ -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/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/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/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/privs.c b/lib/privs.c index 2932800070..3ce8e0d57a 100644 --- a/lib/privs.c +++ b/lib/privs.c @@ -706,6 +706,14 @@ struct zebra_privs_t *_zprivs_raise(struct zebra_privs_t *privs, if (!privs) return NULL; + /* If we're already elevated, just return */ + pthread_mutex_lock(&(privs->mutex)); + if (++privs->refcount > 1) { + pthread_mutex_unlock(&(privs->mutex)); + return privs; + } + pthread_mutex_unlock(&(privs->mutex)); + errno = 0; if (privs->change(ZPRIVS_RAISE)) { zlog_err("%s: Failed to raise privileges (%s)", @@ -723,6 +731,14 @@ void _zprivs_lower(struct zebra_privs_t **privs) if (!*privs) return; + /* Don't lower privs if there's another caller */ + pthread_mutex_lock(&(*privs)->mutex); + if (--((*privs)->refcount) > 0) { + pthread_mutex_unlock(&(*privs)->mutex); + return; + } + pthread_mutex_unlock(&(*privs)->mutex); + errno = 0; if ((*privs)->change(ZPRIVS_LOWER)) { zlog_err("%s: Failed to lower privileges (%s)", @@ -743,6 +759,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. */ diff --git a/lib/privs.h b/lib/privs.h index 1fee423a95..01ddba4622 100644 --- a/lib/privs.h +++ b/lib/privs.h @@ -23,6 +23,8 @@ #ifndef _ZEBRA_PRIVS_H #define _ZEBRA_PRIVS_H +#include <pthread.h> + #ifdef __cplusplus extern "C" { #endif @@ -59,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 */ diff --git a/lib/routemap.c b/lib/routemap.c index 7c1ee2353c..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; @@ -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); diff --git a/lib/thread.c b/lib/thread.c index 055587434c..19ab409439 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -414,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); @@ -484,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); @@ -649,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); @@ -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(); 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/yang_translator.c b/lib/yang_translator.c index 6d6f92836f..76a6cc5fd1 100644 --- a/lib/yang_translator.c +++ b/lib/yang_translator.c @@ -511,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, 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/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/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 83b9001fea..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(); 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_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_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..d4f6f6f4ae 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) { @@ -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_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_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_snmp.c b/ospfd/ospf_snmp.c index 755634a2f1..f068efc8db 100644 --- a/ospfd/ospf_snmp.c +++ b/ospfd/ospf_snmp.c @@ -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_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/pbrd/pbr_map.c b/pbrd/pbr_map.c index 8f8b6aeed1..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); } diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c index 2cba657f65..6a025fd724 100644 --- a/pbrd/pbr_nht.c +++ b/pbrd/pbr_nht.c @@ -740,7 +740,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; } diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index eaec002a73..012c3b4f1d 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); @@ -5159,16 +5159,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 +6351,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 +6377,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; 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_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_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_register.c b/pimd/pim_register.c index b9908ae22b..4b402de634 100644 --- a/pimd/pim_register.c +++ b/pimd/pim_register.c @@ -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..308d5a5e06 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -65,8 +65,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); } 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/ripd/rip_cli.c b/ripd/rip_cli.c index 6fbcdc059b..62aaad5d97 100644 --- a/ripd/rip_cli.c +++ b/ripd/rip_cli.c @@ -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_DESTROY : NB_OP_CREATE, ifname); - nb_cli_enqueue_change(vty, "./non-passive-interface", - no ? NB_OP_CREATE : NB_OP_DESTROY, 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); } 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 1e5f86eff8..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)); 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/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/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 9018cfb359..fbcbbe3fdc 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -39,17 +39,28 @@ #endif DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd, - "sharp watch <nexthop$n|import$import> 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; @@ -63,23 +74,36 @@ DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd, p.family = AF_INET6; sharp_nh_tracker_get(&p); - sharp_zebra_nexthop_watch(&p, type_import, 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$n|import$import> 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) @@ -92,7 +116,8 @@ DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd, p.family = AF_INET; sharp_nh_tracker_get(&p); - sharp_zebra_nexthop_watch(&p, type_import, true, !!connected); + sharp_zebra_nexthop_watch(&p, vrf->vrf_id, type_import, + true, !!connected); return CMD_SUCCESS; } @@ -132,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" @@ -149,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; @@ -176,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) { @@ -195,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; } @@ -237,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; @@ -265,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 4682dbc73a..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,7 +323,7 @@ void route_delete(struct prefix *p, uint8_t instance) return; } -void sharp_zebra_nexthop_watch(struct prefix *p, bool import, +void sharp_zebra_nexthop_watch(struct prefix *p, vrf_id_t vrf_id, bool import, bool watch, bool connected) { int command; @@ -337,7 +340,7 @@ void sharp_zebra_nexthop_watch(struct prefix *p, bool import, command = ZEBRA_IMPORT_ROUTE_UNREGISTER; } - if (zclient_send_rnh(zclient, command, p, connected, VRF_DEFAULT) < 0) + if (zclient_send_rnh(zclient, command, p, connected, vrf_id) < 0) zlog_warn("%s: Failure to send nexthop to zebra", __PRETTY_FUNCTION__); } diff --git a/sharpd/sharp_zebra.h b/sharpd/sharp_zebra.h index b219022f02..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 import, - 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/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/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 5c0e171778..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)); } 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/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/bfd-topo2/__init__.py b/tests/topotests/bfd-topo2/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ 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/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/vtysh/vtysh.c b/vtysh/vtysh.c index 9ff869e503..1f1152d364 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -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]", @@ -3735,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); 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/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_netlink.c b/zebra/if_netlink.c index 3583d63d31..b2f470bc8d 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -1194,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); } diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 3868412b20..c56e2f316d 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -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/zapi_msg.c b/zebra/zapi_msg.c index ef9917d4e6..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,12 +1447,10 @@ 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), @@ -1473,22 +1466,15 @@ 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)); 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 a06e15d90d..5c375a6bef 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -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; @@ -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; @@ -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; @@ -2539,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; @@ -2784,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_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 348bdeb9fc..73db567eac 100644 --- a/zebra/zebra_pbr.c +++ b/zebra/zebra_pbr.c @@ -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) diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c index 1e942d6433..cc5e38e690 100644 --- a/zebra/zebra_ptm.c +++ b/zebra/zebra_ptm.c @@ -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 5f9210109d..2014aa3bed 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); @@ -2937,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; @@ -3236,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; @@ -3255,7 +3253,7 @@ static int handle_pw_result(struct zebra_dplane_ctx *ctx) done: - return ret; + return 0; } 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..1300ca24f3 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -208,8 +208,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; @@ -256,14 +259,12 @@ 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; } } @@ -351,8 +352,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 7d4d5db6b0..00fc230851 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -2213,8 +2213,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; } @@ -2987,8 +2986,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); @@ -3018,6 +3021,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; } @@ -3046,6 +3052,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; } @@ -3186,6 +3197,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; } @@ -3309,8 +3324,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; } @@ -3862,8 +3876,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; } @@ -4299,8 +4312,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; } @@ -4476,8 +4488,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; } @@ -4709,8 +4720,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; } @@ -4875,6 +4885,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)); @@ -7090,9 +7101,10 @@ 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_bucket *, - 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, @@ -7101,8 +7113,9 @@ void zebra_vxlan_print_vnis_detail(struct vty *vty, struct zebra_vrf *zvrf, &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); } } @@ -7582,7 +7595,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); @@ -7590,15 +7603,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); @@ -7648,7 +7666,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, @@ -9160,16 +9178,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) @@ -9210,16 +9228,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) |
