struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc)
{
struct bfd_session *bfd, *l_bfd;
+ struct interface *ifp = NULL;
int psock;
/* check to see if this needs a new session */
return NULL;
}
+ /*
+ * No session found, we have to allocate a new one.
+ *
+ * First a few critical checks:
+ *
+ * * Check that the specified interface exists.
+ * * Attempt to create the UDP socket (might fail if we exceed
+ * our limits).
+ */
+ if (bpc->bpc_has_localif) {
+ ifp = if_lookup_by_name(bpc->bpc_localif, VRF_DEFAULT);
+ if (ifp == NULL) {
+ log_error(
+ "session-new: specified interface doesn't exists.");
+ return NULL;
+ }
+ }
+
/*
* Get socket for transmitting control packets. Note that if we
* could use the destination port (3784) for the source
return NULL;
}
- if (bpc->bpc_has_localif && !bpc->bpc_mhop) {
- bfd->ifindex = ptm_bfd_fetch_ifindex(bpc->bpc_localif);
- ptm_bfd_fetch_local_mac(bpc->bpc_localif, bfd->local_mac);
- }
+ if (bpc->bpc_has_localif && !bpc->bpc_mhop)
+ bfd->ifp = ifp;
if (bpc->bpc_ipv4 == false) {
BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6);
/* Set the IPv6 scope id for link-local addresses. */
if (IN6_IS_ADDR_LINKLOCAL(&bpc->bpc_local.sa_sin6.sin6_addr))
- bpc->bpc_local.sa_sin6.sin6_scope_id = bfd->ifindex;
+ bpc->bpc_local.sa_sin6.sin6_scope_id =
+ bfd->ifp != NULL ? bfd->ifp->ifindex
+ : IFINDEX_INTERNAL;
if (IN6_IS_ADDR_LINKLOCAL(&bpc->bpc_peer.sa_sin6.sin6_addr))
- bpc->bpc_peer.sa_sin6.sin6_scope_id = bfd->ifindex;
+ bpc->bpc_peer.sa_sin6.sin6_scope_id =
+ bfd->ifp != NULL ? bfd->ifp->ifindex
+ : IFINDEX_INTERNAL;
}
/* Initialize the session */
#include "lib/libfrr.h"
#include "lib/qobj.h"
#include "lib/queue.h"
+#include "lib/vrf.h"
#include "bfdctl.h"
struct sockaddr_any local_address;
struct sockaddr_any local_ip;
- int ifindex;
+ struct interface *ifp;
uint8_t local_mac[ETHERNET_ADDRESS_LENGTH];
uint8_t peer_mac[ETHERNET_ADDRESS_LENGTH];
int ptm_bfd_ses_del(struct bfd_peer_cfg *bpc);
void ptm_bfd_ses_dn(struct bfd_session *bfd, uint8_t diag);
void ptm_bfd_ses_up(struct bfd_session *bfd);
-void fetch_portname_from_ifindex(int ifindex, char *ifname, size_t ifnamelen);
void ptm_bfd_echo_stop(struct bfd_session *bfd, int polling);
void ptm_bfd_echo_start(struct bfd_session *bfd);
void ptm_bfd_xmt_TO(struct bfd_session *bfd, int fbit);
int ptm_bfd_notify(struct bfd_session *bs);
-
-/*
- * OS compatibility functions.
- */
-#if defined(BFD_LINUX) || defined(BFD_BSD)
-int ptm_bfd_fetch_ifindex(const char *ifname);
-void ptm_bfd_fetch_local_mac(const char *ifname, uint8_t *mac);
-void fetch_portname_from_ifindex(int ifindex, char *ifname, size_t ifnamelen);
-#endif /* BFD_LINUX || BFD_BSD */
-
-#ifdef BFD_BSD
-ssize_t bsd_echo_sock_read(int sd, uint8_t *buf, ssize_t *buflen,
- struct sockaddr_storage *ss, socklen_t *sslen,
- uint8_t *ttl, uint32_t *id);
-#endif /* BFD_BSD */
-
#endif /* _BFD_H_ */
size_t vrfnamelen, struct sockaddr_any *local,
struct sockaddr_any *peer)
{
+ struct interface *ifp;
struct cmsghdr *cm;
int ifindex;
ssize_t mlen;
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
local->sa_sin.sin_len = sizeof(local->sa_sin);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
- fetch_portname_from_ifindex(pi->ipi_ifindex, port,
- portlen);
+
+ ifp = if_lookup_by_index(pi->ipi_ifindex, VRF_DEFAULT);
+ if (ifp == NULL)
+ break;
+
+ if (strlcpy(port, ifp->name, portlen) >= portlen)
+ log_debug(
+ "ipv4-recv: interface name truncated");
break;
}
#endif /* BFD_LINUX */
/* OS agnostic way of getting interface name. */
if (port[0] == 0) {
ifindex = getsockopt_ifindex(AF_INET, &msghdr);
- if (ifindex > 0)
- fetch_portname_from_ifindex(ifindex, port, portlen);
+ if (ifindex <= 0)
+ return mlen;
+
+ ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
+ if (ifp == NULL)
+ return mlen;
+
+ if (strlcpy(port, ifp->name, portlen) >= portlen)
+ log_debug("ipv4-recv: interface name truncated");
}
return mlen;
size_t vrfnamelen, struct sockaddr_any *local,
struct sockaddr_any *peer)
{
+ struct interface *ifp;
struct cmsghdr *cm;
struct in6_pktinfo *pi6 = NULL;
int ifindex = 0;
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
local->sa_sin6.sin6_len = sizeof(local->sa_sin6);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
- fetch_portname_from_ifindex(pi6->ipi6_ifindex,
- port, portlen);
+
ifindex = pi6->ipi6_ifindex;
+ ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
+ if (ifp == NULL)
+ break;
+
+ if (strlcpy(port, ifp->name, portlen)
+ >= portlen)
+ log_debug(
+ "ipv6-recv: interface name truncated");
}
}
}
* If no interface was detected, save the interface where the
* packet came in.
*/
- if (bfd->ifindex == 0)
- bfd->ifindex = ptm_bfd_fetch_ifindex(port);
+ if (bfd->ifp == NULL)
+ bfd->ifp = if_lookup_by_name(port, VRF_DEFAULT);
/* Log remote discriminator changes. */
if ((bfd->discrs.remote_discr != 0)
int bp_peer_socketv6(struct bfd_peer_cfg *bpc)
{
- int sd, pcount, ifindex;
+ struct interface *ifp;
+ int sd, pcount;
struct sockaddr_in6 sin6;
static int srcPort = BFD_SRCPORTINIT;
sin6.sin6_len = sizeof(sin6);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
sin6 = bpc->bpc_local.sa_sin6;
- ifindex = ptm_bfd_fetch_ifindex(bpc->bpc_localif);
- if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr))
- sin6.sin6_scope_id = ifindex;
+ if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr)) {
+ ifp = if_lookup_by_name(bpc->bpc_localif, VRF_DEFAULT);
+ sin6.sin6_scope_id =
+ (ifp != NULL) ? ifp->ifindex : IFINDEX_INTERNAL;
+ }
if (bpc->bpc_has_localif) {
if (bp_bind_dev(sd, bpc->bpc_localif) != 0) {
/*
* Definitions.
*/
-int ptm_bfd_fetch_ifindex(const char *ifname)
-{
- return if_nametoindex(ifname);
-}
-
-void ptm_bfd_fetch_local_mac(const char *ifname, uint8_t *mac)
-{
- struct ifaddrs *ifap, *ifa;
- struct if_data *ifi;
- struct sockaddr_dl *sdl;
- size_t maclen;
-
- /* Always clean the target, zeroed macs mean failure. */
- memset(mac, 0, ETHERNET_ADDRESS_LENGTH);
-
- if (getifaddrs(&ifap) != 0)
- return;
-
- for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
- /* Find interface with that name. */
- if (strcmp(ifa->ifa_name, ifname) != 0)
- continue;
- /* Skip non link addresses. We want the MAC address. */
- if (ifa->ifa_addr->sa_family != AF_LINK)
- continue;
-
- sdl = (struct sockaddr_dl *)ifa->ifa_addr;
- ifi = (struct if_data *)ifa->ifa_data;
- /* Skip non ethernet related data. */
- if (ifi->ifi_type != IFT_ETHER)
- continue;
-
- if (sdl->sdl_alen != ETHERNET_ADDRESS_LENGTH)
- log_warning("%s:%d mac address length %d (expected %d)",
- __func__, __LINE__, sdl->sdl_alen,
- ETHERNET_ADDRESS_LENGTH);
-
- maclen = (sdl->sdl_alen > ETHERNET_ADDRESS_LENGTH)
- ? ETHERNET_ADDRESS_LENGTH
- : sdl->sdl_alen;
- memcpy(mac, LLADDR(sdl), maclen);
- break;
- }
-
- freeifaddrs(ifap);
-}
-
-
-/* Was _fetch_portname_from_ifindex() */
-void fetch_portname_from_ifindex(int ifindex, char *ifname, size_t ifnamelen)
-{
- char ifname_tmp[IF_NAMESIZE];
-
- /* Set ifname to empty to signalize failures. */
- memset(ifname, 0, ifnamelen);
-
- if (if_indextoname(ifindex, ifname_tmp) == NULL)
- return;
-
- if (strlcpy(ifname, ifname_tmp, ifnamelen) > ifnamelen)
- log_warning("%s:%d interface name truncated", __func__,
- __LINE__);
-}
-
int bp_bind_dev(int sd, const char *dev)
{
/*
/*
* Definitions.
*/
-int ptm_bfd_fetch_ifindex(const char *ifname)
-{
- struct ifreq ifr;
-
- if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name))
- > sizeof(ifr.ifr_name))
- log_error("interface-to-index: name truncated ('%s' -> '%s')",
- ifr.ifr_name, ifname);
-
- if (ioctl(bglobal.bg_shop, SIOCGIFINDEX, &ifr) == -1) {
- log_error("interface-to-index: %s translation failed: %s",
- ifname, strerror(errno));
- return -1;
- }
-
- return ifr.ifr_ifindex;
-}
-
-void ptm_bfd_fetch_local_mac(const char *ifname, uint8_t *mac)
-{
- struct ifreq ifr;
-
- if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name))
- > sizeof(ifr.ifr_name))
- log_error("interface-mac: name truncated ('%s' -> '%s')",
- ifr.ifr_name, ifname);
-
- if (ioctl(bglobal.bg_shop, SIOCGIFHWADDR, &ifr) == -1) {
- log_error("interface-mac: %s MAC retrieval failed: %s", ifname,
- strerror(errno));
- return;
- }
-
- memcpy(mac, ifr.ifr_hwaddr.sa_data, ETHERNET_ADDRESS_LENGTH);
-}
-
-
-/* Was _fetch_portname_from_ifindex() */
-void fetch_portname_from_ifindex(int ifindex, char *ifname, size_t ifnamelen)
-{
- struct ifreq ifr;
-
- ifname[0] = 0;
-
- memset(&ifr, 0, sizeof(ifr));
- ifr.ifr_ifindex = ifindex;
-
- if (ioctl(bglobal.bg_shop, SIOCGIFNAME, &ifr) == -1) {
- log_error("index-to-interface: index %d failure: %s", ifindex,
- strerror(errno));
- return;
- }
-
- if (strlcpy(ifname, ifr.ifr_name, ifnamelen) >= ifnamelen)
- log_debug("index-to-interface: name truncated '%s' -> '%s'",
- ifr.ifr_name, ifname);
-}
-
int bp_bind_dev(int sd __attribute__((__unused__)),
const char *dev __attribute__((__unused__)))
{
stream_putl(msg, ZEBRA_INTERFACE_BFD_DEST_UPDATE);
/* NOTE: Interface is a shortcut to avoid comparing source address. */
- stream_putl(msg, bs->ifindex);
+ if (bs->ifp != NULL)
+ stream_putl(msg, bs->ifp->ifindex);
+ else
+ stream_putl(msg, IFINDEX_INTERNAL);
/* BFD destination prefix information. */
if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
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;
*/
if (bpc->bpc_ipv4 == false
&& IN6_IS_ADDR_LINKLOCAL(
- &bpc->bpc_peer.sa_sin6.sin6_addr))
+ &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 =
- ptm_bfd_fetch_ifindex(bpc->bpc_localif);
+ ifp->ifindex;
+ }
}
}
stream_putl(msg, ZEBRA_BFD_DEST_REPLAY);
stream_putw_at(msg, 0, stream_get_endp(msg));
+ /* Ask for interfaces information. */
+ zclient_create_header(msg, ZEBRA_INTERFACE_ADD, VRF_DEFAULT);
+
+ /* Send requests. */
zclient_send_message(zclient);
}
+static int bfdd_interface_update(int cmd, struct zclient *zc, uint16_t len,
+ vrf_id_t vrfid)
+{
+ /*
+ * `zebra_interface_add_read` will handle the interface creation
+ * on `lib/if.c`. We'll use that data structure instead of
+ * rolling our own.
+ */
+ if (cmd == ZEBRA_INTERFACE_ADD) {
+ zebra_interface_add_read(zc->ibuf, vrfid);
+ return 0;
+ }
+
+ /* Update interface information. */
+ zebra_interface_state_read(zc->ibuf, vrfid);
+
+ /* TODO: stop all sessions using this interface. */
+
+ return 0;
+}
+
void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv)
{
zclient = zclient_new(master, &zclient_options_default);
/* Send replay request on zebra connect. */
zclient->zebra_connected = bfdd_zebra_connected;
+
+ /* Learn interfaces from zebra instead of the OS. */
+ zclient->interface_add = bfdd_interface_update;
+ zclient->interface_delete = bfdd_interface_update;
}
void bfdd_zclient_stop(void)
if (!a1 && !a2)
return true;
return !memcmp(&(a1->evpn_overlay), &(a2->evpn_overlay),
- sizeof(struct overlay_index));
+ sizeof(struct bgp_route_evpn));
}
/* Unknown transit attribute. */
#endif
-/* Overlay Index Info */
-struct overlay_index {
- struct eth_segment_id eth_s_id;
- union gw_addr gw_ip;
-};
-
enum pta_type {
PMSI_TNLTYPE_NO_INFO = 0,
PMSI_TNLTYPE_RSVP_TE_P2MP,
struct bgp_attr_encap_subtlv *vnc_subtlvs; /* VNC-specific */
#endif
/* EVPN */
- struct overlay_index evpn_overlay;
+ struct bgp_route_evpn evpn_overlay;
/* EVPN MAC Mobility sequence number, if any. */
uint32_t mm_seqnum;
pthread_cond_init(peerhash_cond, &attrs);
pthread_condattr_destroy(&attrs);
- frr_pthread_set_name(fpt, NULL, "bgpd_ka");
+ /*
+ * We are not using normal FRR pthread mechanics and are
+ * not using fpt_run
+ */
+ frr_pthread_set_name(fpt);
/* initialize peer hashtable */
peerhash = hash_create_size(2048, peer_hash_key, peer_hash_cmp, NULL);
--- /dev/null
+/*
+ * BGPd - Mac hash code
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <zebra.h>
+
+#include <jhash.h>
+#include <hash.h>
+#include <prefix.h>
+#include <memory.h>
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_mac.h"
+#include "bgpd/bgp_memory.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_packet.h"
+#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_evpn_private.h"
+
+DEFINE_MTYPE_STATIC(BGPD, BSM, "Mac Hash Entry");
+DEFINE_MTYPE_STATIC(BGPD, BSM_STRING, "Mac Hash Entry Interface String");
+
+struct bgp_self_mac {
+ struct ethaddr macaddr;
+ struct list *ifp_list;
+};
+
+static unsigned int bgp_mac_hash_key_make(void *data)
+{
+ struct bgp_self_mac *bsm = data;
+
+ return jhash(&bsm->macaddr, ETH_ALEN, 0xa5a5dead);
+}
+
+static bool bgp_mac_hash_cmp(const void *d1, const void *d2)
+{
+ const struct bgp_self_mac *bsm1 = d1;
+ const struct bgp_self_mac *bsm2 = d2;
+
+ if (memcmp(&bsm1->macaddr, &bsm2->macaddr, ETH_ALEN) == 0)
+ return true;
+
+ return false;
+}
+
+void bgp_mac_init(void)
+{
+ bm->self_mac_hash = hash_create(bgp_mac_hash_key_make, bgp_mac_hash_cmp,
+ "BGP MAC Hash");
+}
+
+static void bgp_mac_hash_free(void *data)
+{
+ struct bgp_self_mac *bsm = data;
+
+ if (bsm->ifp_list)
+ list_delete(&bsm->ifp_list);
+
+ XFREE(MTYPE_BSM, bsm);
+}
+
+void bgp_mac_finish(void)
+{
+ hash_clean(bm->self_mac_hash, bgp_mac_hash_free);
+ hash_free(bm->self_mac_hash);
+}
+
+static void bgp_mac_hash_interface_string_del(void *val)
+{
+ char *data = val;
+
+ XFREE(MTYPE_BSM_STRING, data);
+}
+
+static void *bgp_mac_hash_alloc(void *p)
+{
+ const struct bgp_self_mac *orig = p;
+ struct bgp_self_mac *bsm;
+
+ bsm = XCALLOC(MTYPE_BSM, sizeof(struct bgp_self_mac));
+ memcpy(&bsm->macaddr, &orig->macaddr, ETH_ALEN);
+
+ bsm->ifp_list = list_new();
+ bsm->ifp_list->del = bgp_mac_hash_interface_string_del;
+
+ return bsm;
+}
+
+struct bgp_mac_find_internal {
+ struct bgp_self_mac *bsm;
+ const char *ifname;
+};
+
+static void bgp_mac_find_ifp_internal(struct hash_backet *backet, void *arg)
+{
+ struct bgp_mac_find_internal *bmfi = arg;
+ struct bgp_self_mac *bsm = backet->data;
+ struct listnode *node;
+ char *name;
+
+ for (ALL_LIST_ELEMENTS_RO(bsm->ifp_list, node, name)) {
+ if (strcmp(name, bmfi->ifname) == 0) {
+ bmfi->bsm = bsm;
+ return;
+ }
+ }
+}
+
+static struct bgp_self_mac *bgp_mac_find_interface_name(const char *ifname)
+{
+ struct bgp_mac_find_internal bmfi;
+
+ bmfi.bsm = NULL;
+ bmfi.ifname = ifname;
+ hash_iterate(bm->self_mac_hash, bgp_mac_find_ifp_internal, &bmfi);
+
+ return bmfi.bsm;
+}
+
+static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer,
+ struct bgp_table *table)
+{
+ struct bgp_node *prn, *rn;
+ struct bgp_path_info *pi;
+ uint32_t count = 0;
+
+ for (prn = bgp_table_top(table); prn; prn = bgp_route_next(prn)) {
+ struct bgp_table *sub = prn->info;
+
+ if (!sub)
+ continue;
+
+ for (rn = bgp_table_top(sub); rn; rn = bgp_route_next(rn)) {
+ struct prefix_rd prd;
+ uint32_t num_labels = 0;
+ mpls_label_t *label_pnt = NULL;
+ struct bgp_route_evpn evpn;
+
+ count++;
+ for (pi = rn->info; pi; pi = pi->next) {
+ if (pi->peer == peer)
+ break;
+ }
+
+ if (!pi)
+ continue;
+
+ if (pi->extra)
+ num_labels = pi->extra->num_labels;
+ if (num_labels)
+ label_pnt = &pi->extra->label[0];
+
+ prd.family = AF_UNSPEC;
+ prd.prefixlen = 64;
+ memcpy(&prd.val, &prn->p.u.val, 8);
+
+ memcpy(&evpn, &pi->attr->evpn_overlay, sizeof(evpn));
+ int32_t ret = bgp_update(peer, &rn->p,
+ pi->addpath_rx_id,
+ pi->attr, AFI_L2VPN, SAFI_EVPN,
+ ZEBRA_ROUTE_BGP,
+ BGP_ROUTE_NORMAL, &prd,
+ label_pnt, num_labels,
+ 1, &evpn);
+
+ if (ret < 0)
+ bgp_unlock_node(rn);
+ }
+ }
+}
+
+static void bgp_mac_rescan_evpn_table(struct bgp *bgp)
+{
+ struct listnode *node;
+ struct peer *peer;
+ safi_t safi;
+ afi_t afi;
+
+ afi = AFI_L2VPN;
+ safi = SAFI_EVPN;
+ for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) {
+
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+ continue;
+
+ if (peer->status != Established)
+ continue;
+
+ if (CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_SOFT_RECONFIG)) {
+ if (bgp_debug_update(peer, NULL, NULL, 1))
+ zlog_debug("Processing EVPN MAC interface change on peer %s (inbound, soft-reconfig)",
+ peer->host);
+
+ bgp_soft_reconfig_in(peer, afi, safi);
+ } else {
+ struct bgp_table *table = bgp->rib[afi][safi];
+
+ if (bgp_debug_update(peer, NULL, NULL, 1))
+ zlog_debug("Processing EVPN MAC interface change on peer %s",
+ peer->host);
+ bgp_process_mac_rescan_table(bgp, peer, table);
+ }
+ }
+}
+
+static void bgp_mac_rescan_all_evpn_tables(void)
+{
+ struct listnode *node;
+ struct bgp *bgp;
+
+ for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) {
+ struct bgp_table *table = bgp->rib[AFI_L2VPN][SAFI_EVPN];
+
+ if (table)
+ bgp_mac_rescan_evpn_table(bgp);
+ }
+}
+
+static void bgp_mac_remove_ifp_internal(struct bgp_self_mac *bsm, char *ifname)
+{
+ struct listnode *node = NULL;
+ char *name;
+
+ for (ALL_LIST_ELEMENTS_RO(bsm->ifp_list, node, name)) {
+ if (strcmp(name, ifname) == 0)
+ break;
+ }
+
+ if (node) {
+ list_delete_node(bsm->ifp_list, node);
+ XFREE(MTYPE_BSM_STRING, name);
+ }
+
+ if (bsm->ifp_list->count == 0) {
+ hash_release(bm->self_mac_hash, bsm);
+ list_delete(&bsm->ifp_list);
+ XFREE(MTYPE_BSM, bsm);
+
+ bgp_mac_rescan_all_evpn_tables();
+ }
+}
+
+void bgp_mac_add_mac_entry(struct interface *ifp)
+{
+ struct bgp_self_mac lookup;
+ struct bgp_self_mac *bsm;
+ struct bgp_self_mac *old_bsm;
+ char *ifname;
+
+ memcpy(&lookup.macaddr, &ifp->hw_addr, ETH_ALEN);
+ bsm = hash_get(bm->self_mac_hash, &lookup, bgp_mac_hash_alloc);
+
+ /*
+ * Does this happen to be a move
+ */
+ old_bsm = bgp_mac_find_interface_name(ifp->name);
+ ifname = XSTRDUP(MTYPE_BSM_STRING, ifp->name);
+
+ if (bsm->ifp_list->count == 0) {
+
+ listnode_add(bsm->ifp_list, ifname);
+ if (old_bsm)
+ bgp_mac_remove_ifp_internal(old_bsm, ifname);
+ } else {
+ /*
+ * If old mac address is the same as the new,
+ * then there is nothing to do here
+ */
+ if (old_bsm == bsm)
+ return;
+
+ if (old_bsm)
+ bgp_mac_remove_ifp_internal(old_bsm, ifp->name);
+
+ listnode_add(bsm->ifp_list, ifname);
+ }
+
+ bgp_mac_rescan_all_evpn_tables();
+}
+
+void bgp_mac_del_mac_entry(struct interface *ifp)
+{
+ struct bgp_self_mac lookup;
+ struct bgp_self_mac *bsm;
+
+ memcpy(&lookup.macaddr, &ifp->hw_addr, ETH_ALEN);
+ bsm = hash_lookup(bm->self_mac_hash, &lookup);
+ if (!bsm)
+ return;
+
+ /*
+ * Write code to allow old mac address to no-longer
+ * win if we happen to have received it from a peer.
+ */
+ bgp_mac_remove_ifp_internal(bsm, ifp->name);
+}
+
+bool bgp_mac_entry_exists(struct prefix *p)
+{
+ struct prefix_evpn *pevpn = (struct prefix_evpn *)p;
+ struct bgp_self_mac lookup;
+ struct bgp_self_mac *bsm;
+
+ if (pevpn->family != AF_EVPN)
+ return false;
+
+ 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 true;
+}
+
+static void bgp_mac_show_mac_entry(struct hash_backet *backet, void *arg)
+{
+ struct vty *vty = arg;
+ struct bgp_self_mac *bsm = backet->data;
+ struct listnode *node;
+ char *name;
+ char buf_mac[ETHER_ADDR_STRLEN];
+
+ vty_out(vty, "Mac Address: %s ",
+ prefix_mac2str(&bsm->macaddr, buf_mac, sizeof(buf_mac)));
+
+ for (ALL_LIST_ELEMENTS_RO(bsm->ifp_list, node, name))
+ vty_out(vty, "%s ", name);
+
+ vty_out(vty, "\n");
+}
+
+void bgp_mac_dump_table(struct vty *vty)
+{
+ hash_iterate(bm->self_mac_hash, bgp_mac_show_mac_entry, vty);
+}
--- /dev/null
+/*
+ * BGPd - Mac hash header
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef __BGP_MAC_H__
+#define __BGP_MAC_H__
+
+void bgp_mac_init(void);
+void bgp_mac_finish(void);
+
+/*
+ * Functions to add/delete the mac entry from the appropriate
+ * bgp hash's. Additionally to do some additional processing
+ * to allow the win/loss to be processed.
+ */
+void bgp_mac_add_mac_entry(struct interface *ifp);
+void bgp_mac_del_mac_entry(struct interface *ifp);
+
+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);
+
+#endif
bgp->vrf_id);
}
+ if (label == BGP_PREVENT_VRF_2_VRF_LEAK)
+ label = MPLS_LABEL_NONE;
zclient_send_vrf_label(zclient, bgp->vrf_id, afi, label, ZEBRA_LSP_BGP);
bgp->vpn_policy[afi].tovpn_zebra_vrf_label_last_sent = label;
}
bgp->name_pretty, bgp->vrf_id);
}
+ if (label == BGP_PREVENT_VRF_2_VRF_LEAK)
+ label = MPLS_LABEL_NONE;
+
zclient_send_vrf_label(zclient, bgp->vrf_id, afi, label, ZEBRA_LSP_BGP);
bgp->vpn_policy[afi].tovpn_zebra_vrf_label_last_sent = label;
}
#include "bgpd/bgp_updgrp.h"
#include "bgpd/bgp_label.h"
#include "bgpd/bgp_addpath.h"
+#include "bgpd/bgp_mac.h"
#if ENABLE_BGP_VNC
#include "bgpd/rfapi/rfapi_backend.h"
goto filtered;
}
+ if (bgp_mac_entry_exists(p)) {
+ reason = "self mac;";
+ goto filtered;
+ }
+
attr_new = bgp_attr_intern(&new_attr);
/* If the update is implicit withdraw. */
bgp_node_get_bgp_path_info(rn);
uint32_t num_labels = 0;
mpls_label_t *label_pnt = NULL;
+ struct bgp_route_evpn evpn;
if (pi && pi->extra)
num_labels = pi->extra->num_labels;
if (num_labels)
label_pnt = &pi->extra->label[0];
+ if (pi)
+ memcpy(&evpn, &pi->attr->evpn_overlay,
+ sizeof(evpn));
+ else
+ memset(&evpn, 0, sizeof(evpn));
ret = bgp_update(peer, &rn->p, ain->addpath_rx_id,
ain->attr, afi, safi, ZEBRA_ROUTE_BGP,
BGP_ROUTE_NORMAL, prd, label_pnt,
- num_labels, 1, NULL);
+ num_labels, 1, &evpn);
if (ret < 0) {
bgp_unlock_node(rn);
#include "frrstr.h"
#include "bgpd/bgpd.h"
+#include "bgpd/bgp_attr_evpn.h"
#include "bgpd/bgp_advertise.h"
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_io.h"
#include "bgpd/bgp_evpn.h"
#include "bgpd/bgp_addpath.h"
+#include "bgpd/bgp_mac.h"
static struct peer_group *listen_range_exists(struct bgp *bgp,
struct prefix *range, int exact);
/* one clear bgp command to rule them all */
DEFUN (clear_ip_bgp_all,
clear_ip_bgp_all_cmd,
- "clear [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]] <*|A.B.C.D|X:X::X:X|WORD|(1-4294967295)|external|peer-group WORD> [<soft [<in|out>]|in [prefix-filter]|out>]",
+ "clear [ip] bgp [<view|vrf> VIEWVRFNAME] [<ipv4|ipv6|l2vpn> [<unicast|multicast|vpn|labeled-unicast|flowspec|evpn>]] <*|A.B.C.D|X:X::X:X|WORD|(1-4294967295)|external|peer-group WORD> [<soft [<in|out>]|in [prefix-filter]|out>]",
CLEAR_STR
IP_STR
BGP_STR
BGP_INSTANCE_HELP_STR
BGP_AFI_HELP_STR
+ "Address Family\n"
BGP_SAFI_WITH_LABEL_HELP_STR
+ "Address Family modifier\n"
"Clear all peers\n"
"BGP neighbor address to clear\n"
"BGP IPv6 neighbor to clear\n"
return CMD_SUCCESS;
}
+DEFUN (show_bgp_mac_hash,
+ show_bgp_mac_hash_cmd,
+ "show bgp mac hash",
+ SHOW_STR
+ BGP_STR
+ "Mac Address\n"
+ "Mac Address database\n")
+{
+ bgp_mac_dump_table(vty);
+
+ return CMD_SUCCESS;
+}
static void show_tip_entry(struct hash_backet *backet, void *args)
{
&neighbor_soft_reconfiguration_cmd);
install_element(BGP_FLOWSPECV6_NODE,
&no_neighbor_soft_reconfiguration_cmd);
+ install_element(BGP_EVPN_NODE, &neighbor_soft_reconfiguration_cmd);
+ install_element(BGP_EVPN_NODE, &no_neighbor_soft_reconfiguration_cmd);
/* "neighbor attribute-unchanged" commands. */
install_element(BGP_NODE, &neighbor_attr_unchanged_hidden_cmd);
/* "show bgp martian next-hop" */
install_element(VIEW_NODE, &show_bgp_martian_nexthop_db_cmd);
+ install_element(VIEW_NODE, &show_bgp_mac_hash_cmd);
+
/* "show [ip] bgp views" commands. */
install_element(VIEW_NODE, &show_bgp_views_cmd);
#include "bgpd/bgp_labelpool.h"
#include "bgpd/bgp_pbr.h"
#include "bgpd/bgp_evpn_private.h"
+#include "bgpd/bgp_mac.h"
/* All information about zebra. */
struct zclient *zclient = NULL;
if (!bgp)
return 0;
+ bgp_mac_add_mac_entry(ifp);
+
bgp_update_interface_nbrs(bgp, ifp, ifp);
return 0;
}
if (bgp)
bgp_update_interface_nbrs(bgp, ifp, NULL);
+ bgp_mac_del_mac_entry(ifp);
+
if_set_index(ifp, IFINDEX_INTERNAL);
return 0;
}
if (!ifp)
return 0;
+ bgp_mac_add_mac_entry(ifp);
+
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("Rx Intf up VRF %u IF %s", vrf_id, ifp->name);
if (!ifp)
return 0;
+ bgp_mac_del_mac_entry(ifp);
+
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("Rx Intf down VRF %u IF %s", vrf_id, ifp->name);
#include "bgpd/bgp_pbr.h"
#include "bgpd/bgp_addpath.h"
#include "bgpd/bgp_evpn_private.h"
+#include "bgpd/bgp_mac.h"
DEFINE_MTYPE_STATIC(BGPD, PEER_TX_SHUTDOWN_MSG, "Peer shutdown message (TX)");
DEFINE_MTYPE_STATIC(BGPD, BGP_EVPN_INFO, "BGP EVPN instance information");
bgp_process_queue_init();
+ bgp_mac_init();
/* init the rd id space.
assign 0th index in the bitfield,
so that we start with id 1
if (bm->t_rmap_update)
BGP_TIMER_OFF(bm->t_rmap_update);
+ bgp_mac_finish();
}
/* Listener address */
char *address;
+ /* The Mac table */
+ struct hash *self_mac_hash;
+
/* BGP start time. */
time_t start_time;
bgpd/bgp_label.c \
bgpd/bgp_labelpool.c \
bgpd/bgp_lcommunity.c \
+ bgpd/bgp_mac.c \
bgpd/bgp_memory.c \
bgpd/bgp_mpath.c \
bgpd/bgp_mplsvpn.c \
bgpd/bgp_label.h \
bgpd/bgp_labelpool.h \
bgpd/bgp_lcommunity.h \
+ bgpd/bgp_mac.h \
bgpd/bgp_memory.h \
bgpd/bgp_mpath.h \
bgpd/bgp_mplsvpn.h \
fpt->name = XSTRDUP(MTYPE_FRR_PTHREAD, name);
if (os_name)
snprintf(fpt->os_name, OS_THREAD_NAMELEN, "%s", os_name);
+ else
+ snprintf(fpt->os_name, OS_THREAD_NAMELEN, "%s", name);
/* initialize startup synchronization primitives */
fpt->running_cond_mtx = XCALLOC(
MTYPE_PTHREAD_PRIM, sizeof(pthread_mutex_t));
XFREE(MTYPE_FRR_PTHREAD, fpt);
}
-int frr_pthread_set_name(struct frr_pthread *fpt, const char *name,
- const char *os_name)
+int frr_pthread_set_name(struct frr_pthread *fpt)
{
int ret = 0;
- if (name) {
- pthread_mutex_lock(&fpt->mtx);
- {
- if (fpt->name)
- XFREE(MTYPE_FRR_PTHREAD, fpt->name);
- fpt->name = XSTRDUP(MTYPE_FRR_PTHREAD, name);
- }
- pthread_mutex_unlock(&fpt->mtx);
- thread_master_set_name(fpt->master, name);
- }
-
- if (os_name) {
- pthread_mutex_lock(&fpt->mtx);
- snprintf(fpt->os_name, OS_THREAD_NAMELEN, "%s", os_name);
- pthread_mutex_unlock(&fpt->mtx);
#ifdef HAVE_PTHREAD_SETNAME_NP
# ifdef GNU_LINUX
- ret = pthread_setname_np(fpt->thread, fpt->os_name);
+ ret = pthread_setname_np(fpt->thread, fpt->os_name);
# else /* NetBSD */
- ret = pthread_setname_np(fpt->thread, fpt->os_name, NULL);
+ ret = pthread_setname_np(fpt->thread, fpt->os_name, NULL);
# endif
#elif defined(HAVE_PTHREAD_SET_NAME_NP)
- pthread_set_name_np(fpt->thread, fpt->os_name);
+ pthread_set_name_np(fpt->thread, fpt->os_name);
#endif
- }
return ret;
}
fpt->master->handle_signals = false;
- if (fpt->os_name[0])
- frr_pthread_set_name(fpt, NULL, fpt->os_name);
+ frr_pthread_set_name(fpt);
frr_pthread_notify_running(fpt);
const char *name, const char *os_name);
/*
- * Changes the name of the frr_pthread.
+ * Changes the name of the frr_pthread as reported by the operating
+ * system.
*
* @param fpt - the frr_pthread to operate on
- * @param name - Human-readable name
- * @param os_name - 16 characters thread name , including the null
- * terminator ('\0') to set in os.
* @return - on success returns 0 otherwise nonzero error number.
*/
-int frr_pthread_set_name(struct frr_pthread *fpt, const char *name,
- const char *os_name);
+int frr_pthread_set_name(struct frr_pthread *fpt);
/*
* Destroys an frr_pthread.
} lp;
struct ethaddr prefix_eth; /* AF_ETHERNET */
uint8_t val[16];
+ uint32_t val32[4];
uintptr_t ptr;
struct evpn_addr prefix_evpn; /* AF_EVPN */
struct flowspec_prefix prefix_flowspec; /* AF_FLOWSPEC */
void thread_getrusage(RUSAGE_T *r)
{
+#if defined RUSAGE_THREAD
+#define FRR_RUSAGE RUSAGE_THREAD
+#else
+#define FRR_RUSAGE RUSAGE_SELF
+#endif
monotime(&r->real);
- getrusage(RUSAGE_SELF, &(r->cpu));
+ getrusage(FRR_RUSAGE, &(r->cpu));
}
/*
DEFPY (install_routes,
install_routes_cmd,
- "sharp install routes A.B.C.D$start <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 <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"
- "Address to start /32 generation at\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"
"V4 Nexthop address to use\n"
"V6 Nexthop address to use\n"
memset(&nhop, 0, sizeof(nhop));
memset(&nhop_group, 0, sizeof(nhop_group));
- prefix.family = AF_INET;
- prefix.prefixlen = 32;
- prefix.u.prefix4 = start;
+ if (start4.s_addr != 0) {
+ prefix.family = AF_INET;
+ prefix.prefixlen = 32;
+ prefix.u.prefix4 = start4;
+ } else {
+ prefix.family = AF_INET6;
+ prefix.prefixlen = 128;
+ prefix.u.prefix6 = start6;
+ }
orig_prefix = prefix;
if (nexthop_group) {
DEFPY (remove_routes,
remove_routes_cmd,
- "sharp remove routes A.B.C.D$start (1-1000000)$routes [instance (0-255)$instance]",
+ "sharp remove routes <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"
- "Starting spot\n"
- "Routes to uniinstall\n"
+ "v4 Starting spot\n"
+ "v6 Starting spot\n"
+ "Routes to uninstall\n"
"instance to use\n"
"Value of instance\n")
{
memset(&prefix, 0, sizeof(prefix));
- prefix.family = AF_INET;
- prefix.prefixlen = 32;
- prefix.u.prefix4 = start;
+ if (start4.s_addr != 0) {
+ prefix.family = AF_INET;
+ prefix.prefixlen = 32;
+ prefix.u.prefix4 = start4;
+ } else {
+ prefix.family = AF_INET6;
+ prefix.prefixlen = 128;
+ prefix.u.prefix6 = start6;
+ }
inst = instance;
rts = routes;
return 0;
}
+static struct timeval t_start;
+static struct timeval t_end;
extern uint32_t total_routes;
extern uint32_t installed_routes;
extern uint32_t removed_routes;
uint32_t routes)
{
uint32_t temp, i;
+ bool v4 = false;
zlog_debug("Inserting %u routes", routes);
- temp = ntohl(p->u.prefix4.s_addr);
+ if (p->family == AF_INET) {
+ v4 = true;
+ temp = ntohl(p->u.prefix4.s_addr);
+ } else
+ temp = ntohl(p->u.val32[3]);
+
+ monotime(&t_start);
for (i = 0; i < routes; i++) {
route_add(p, (uint8_t)instance, nhg);
- p->u.prefix4.s_addr = htonl(++temp);
+ if (v4)
+ p->u.prefix4.s_addr = htonl(++temp);
+ else
+ p->u.val32[3] = htonl(++temp);
}
}
uint32_t routes)
{
uint32_t temp, i;
+ bool v4 = false;
zlog_debug("Removing %u routes", routes);
- temp = ntohl(p->u.prefix4.s_addr);
+ if (p->family == AF_INET) {
+ v4 = true;
+ temp = ntohl(p->u.prefix4.s_addr);
+ } else
+ temp = ntohl(p->u.val32[3]);
+
+ monotime(&t_start);
for (i = 0; i < routes; i++) {
route_delete(p, (uint8_t)instance);
- p->u.prefix4.s_addr = htonl(++temp);
+ if (v4)
+ p->u.prefix4.s_addr = htonl(++temp);
+ else
+ p->u.val32[3] = htonl(++temp);
}
}
static int route_notify_owner(int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
+ struct timeval r;
struct prefix p;
enum zapi_route_notify_owner note;
uint32_t table;
case ZAPI_ROUTE_INSTALLED:
installed_routes++;
if (total_routes == installed_routes) {
- zlog_debug("Installed All Items");
+ monotime(&t_end);
+ timersub(&t_end, &t_start, &r);
+ zlog_debug("Installed All Items %ld.%ld", r.tv_sec,
+ r.tv_usec);
handle_repeated(true);
}
break;
case ZAPI_ROUTE_REMOVED:
removed_routes++;
if (total_routes == removed_routes) {
- zlog_debug("Removed all Items");
+ monotime(&t_end);
+ timersub(&t_end, &t_start, &r);
+ zlog_debug("Removed all Items %ld.%ld", r.tv_sec,
+ r.tv_usec);
handle_repeated(false);
}
break;
#include "static_zebra.h"
#include "static_nht.h"
-void static_nht_update(struct prefix *p, uint32_t nh_num, afi_t afi,
- vrf_id_t nh_vrf_id)
+static void static_nht_update_safi(struct prefix *p, uint32_t nh_num,
+ afi_t afi, safi_t safi, struct vrf *vrf,
+ vrf_id_t nh_vrf_id)
{
struct route_table *stable;
struct static_route *si;
struct static_vrf *svrf;
struct route_node *rn;
- struct vrf *vrf;
bool orig;
bool reinstall;
- RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
- svrf = vrf->info;
- if (!svrf)
- continue;
+ svrf = vrf->info;
+ if (!svrf)
+ return;
- stable = static_vrf_static_table(afi, SAFI_UNICAST, svrf);
- if (!stable)
- continue;
+ stable = static_vrf_static_table(afi, safi, svrf);
+ if (!stable)
+ return;
- for (rn = route_top(stable); rn; rn = route_next(rn)) {
- reinstall = false;
- for (si = rn->info; si; si = si->next) {
- if (si->nh_vrf_id != nh_vrf_id)
- continue;
+ for (rn = route_top(stable); rn; rn = route_next(rn)) {
+ reinstall = false;
+ for (si = rn->info; si; si = si->next) {
+ if (si->nh_vrf_id != nh_vrf_id)
+ return;
- if (si->type != STATIC_IPV4_GATEWAY
- && si->type != STATIC_IPV4_GATEWAY_IFNAME
- && si->type != STATIC_IPV6_GATEWAY
- && si->type != STATIC_IPV6_GATEWAY_IFNAME)
- continue;
+ if (si->type != STATIC_IPV4_GATEWAY
+ && si->type != STATIC_IPV4_GATEWAY_IFNAME
+ && si->type != STATIC_IPV6_GATEWAY
+ && si->type != STATIC_IPV6_GATEWAY_IFNAME)
+ return;
- orig = si->nh_valid;
- if (p->family == AF_INET
- && p->u.prefix4.s_addr
- == si->addr.ipv4.s_addr)
- si->nh_valid = !!nh_num;
+ orig = si->nh_valid;
+ if (p->family == AF_INET
+ && p->u.prefix4.s_addr == si->addr.ipv4.s_addr)
+ si->nh_valid = !!nh_num;
- if (p->family == AF_INET6
- && memcmp(&p->u.prefix6, &si->addr.ipv6, 16)
- == 0)
- si->nh_valid = !!nh_num;
+ if (p->family == AF_INET6
+ && memcmp(&p->u.prefix6, &si->addr.ipv6, 16) == 0)
+ si->nh_valid = !!nh_num;
- if (orig != si->nh_valid)
- reinstall = true;
+ if (orig != si->nh_valid)
+ reinstall = true;
- if (reinstall) {
- static_zebra_route_add(
- rn, si, vrf->vrf_id,
- SAFI_UNICAST, true);
- reinstall = false;
- }
+ if (reinstall) {
+ static_zebra_route_add(rn, si, vrf->vrf_id,
+ safi, true);
+ reinstall = false;
}
}
}
}
+
+void static_nht_update(struct prefix *p, uint32_t nh_num, afi_t afi,
+ vrf_id_t nh_vrf_id)
+{
+
+ struct vrf *vrf;
+
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ static_nht_update_safi(p, nh_num, afi, SAFI_UNICAST,
+ vrf, nh_vrf_id);
+ static_nht_update_safi(p, nh_num, afi, SAFI_MULTICAST,
+ vrf, nh_vrf_id);
+ }
+}
uint32_t flags;
/* RIB internal status */
- uint8_t status;
+ uint32_t status;
#define ROUTE_ENTRY_REMOVED 0x1
/* to simplify NHT logic when NHs change, instead of doing a NH by NH cmp */
#define ROUTE_ENTRY_NEXTHOPS_CHANGED 0x2
+/* The Route Entry has changed */
#define ROUTE_ENTRY_CHANGED 0x4
+/* The Label has changed on the Route entry */
#define ROUTE_ENTRY_LABELS_CHANGED 0x8
+/* Route is queued for Installation into the Data Plane */
+#define ROUTE_ENTRY_QUEUED 0x10
+/* Route is installed into the Data Plane */
+#define ROUTE_ENTRY_INSTALLED 0x20
+/* Route has Failed installation into the Data Plane in some manner */
+#define ROUTE_ENTRY_FAILED 0x40
/* Nexthop information. */
uint8_t nexthop_num;
/* Flags */
int dp_flags;
- dplane_provider_process_fp dp_fp;
+ int (*dp_fp)(struct zebra_dplane_provider *prov);
- dplane_provider_fini_fp dp_fini;
+ int (*dp_fini)(struct zebra_dplane_provider *prov, bool early_p);
_Atomic uint32_t dp_in_counter;
_Atomic uint32_t dp_in_queued;
pthread_mutex_t dg_mutex;
/* Results callback registered by zebra 'core' */
- dplane_results_fp dg_results_cb;
+ int (*dg_results_cb)(struct dplane_ctx_q *ctxlist);
/* Sentinel for beginning of shutdown */
volatile bool dg_is_shutdown;
int dplane_provider_register(const char *name,
enum dplane_provider_prio prio,
int flags,
- dplane_provider_process_fp fp,
- dplane_provider_fini_fp fini_fp,
- void *data)
+ int (*fp)(struct zebra_dplane_provider *),
+ int (*fini_fp)(struct zebra_dplane_provider *,
+ bool early),
+ void *data,
+ struct zebra_dplane_provider **prov_p)
{
int ret = 0;
- struct zebra_dplane_provider *p, *last;
+ struct zebra_dplane_provider *p = NULL, *last;
/* Validate */
if (fp == NULL) {
p->dp_name, p->dp_id, p->dp_priority);
done:
+ if (prov_p)
+ *prov_p = p;
+
return ret;
}
return AOK;
}
-/*
- * Zebra registers a results callback with the dataplane system
- */
-int dplane_results_register(dplane_results_fp fp)
-{
- zdplane_info.dg_results_cb = fp;
- return AOK;
-}
-
/*
* Kernel dataplane provider
*/
DPLANE_PROV_FLAGS_DEFAULT,
kernel_dplane_process_func,
NULL,
- NULL);
+ NULL, NULL);
if (ret != AOK)
zlog_err("Unable to register kernel dplane provider: %d",
DPLANE_PROV_FLAGS_DEFAULT,
test_dplane_process_func,
test_dplane_shutdown_func,
- NULL /* data */);
+ NULL /* data */, NULL);
if (ret != AOK)
zlog_err("Unable to register test dplane provider: %d",
counter, error_counter);
/*
- * TODO -- I'd rather hand lists through the api to zebra main,
+ * Hand lists through the api to zebra main,
* to reduce the number of lock/unlock cycles
*/
- for (ctx = TAILQ_FIRST(&error_list); ctx; ) {
- TAILQ_REMOVE(&error_list, ctx, zd_q_entries);
-
- /* Call through to zebra main */
- (*zdplane_info.dg_results_cb)(ctx);
- ctx = TAILQ_FIRST(&error_list);
- }
+ /* Call through to zebra main */
+ (zdplane_info.dg_results_cb)(&error_list);
+ TAILQ_INIT(&error_list);
- for (ctx = TAILQ_FIRST(&work_list); ctx; ) {
- TAILQ_REMOVE(&work_list, ctx, zd_q_entries);
- /* Call through to zebra main */
- (*zdplane_info.dg_results_cb)(ctx);
+ /* Call through to zebra main */
+ (zdplane_info.dg_results_cb)(&work_list);
- ctx = TAILQ_FIRST(&work_list);
- }
+ TAILQ_INIT(&work_list);
done:
return 0;
/*
* Initialize the dataplane module at startup; called by zebra rib_init()
*/
-void zebra_dplane_init(void)
+void zebra_dplane_init(int (*results_fp)(struct dplane_ctx_q *))
{
zebra_dplane_init_internal(&zebrad);
+ zdplane_info.dg_results_cb = results_fp;
}
DPLANE_PRIO_LAST
};
-/* Provider's entry-point for incoming work, called in the context of the
- * dataplane pthread. The dataplane pthread enqueues any new work to the
- * provider's 'inbound' queue, then calls the callback. The dataplane
- * then checks the provider's outbound queue.
- */
-typedef int (*dplane_provider_process_fp)(struct zebra_dplane_provider *prov);
-
-/* Provider's entry-point for shutdown and cleanup. Called with 'early'
- * during shutdown, to indicate that the dataplane subsystem is allowing
- * work to move through the providers and finish. When called without 'early',
- * the provider should release all resources (if it has any allocated).
- */
-typedef int (*dplane_provider_fini_fp)(struct zebra_dplane_provider *prov,
- bool early);
-
/* Flags values used during provider registration. */
#define DPLANE_PROV_FLAGS_DEFAULT 0x0
/* Provider registration: ordering or priority value, callbacks, and optional
- * opaque data value.
+ * opaque data value. If 'prov_p', return the newly-allocated provider object
+ * on success.
+ */
+
+/* Providers offer an entry-point for incoming work, called in the context of
+ * the dataplane pthread. The dataplane pthread enqueues any new work to the
+ * provider's 'inbound' queue, then calls the callback. The dataplane
+ * then checks the provider's outbound queue for completed work.
+ */
+
+/* Providers offer an entry-point for shutdown and cleanup. This is called
+ * with 'early' during shutdown, to indicate that the dataplane subsystem
+ * is allowing work to move through the providers and finish.
+ * When called without 'early', the provider should release
+ * all resources (if it has any allocated).
*/
int dplane_provider_register(const char *name,
enum dplane_provider_prio prio,
int flags,
- dplane_provider_process_fp fp,
- dplane_provider_fini_fp fini_fp,
- void *data);
+ int (*fp)(struct zebra_dplane_provider *),
+ int (*fini_fp)(struct zebra_dplane_provider *,
+ bool early),
+ void *data,
+ struct zebra_dplane_provider **prov_p);
/* Accessors for provider attributes */
const char *dplane_provider_get_name(const struct zebra_dplane_provider *prov);
void dplane_provider_enqueue_out_ctx(struct zebra_dplane_provider *prov,
struct zebra_dplane_ctx *ctx);
-/*
- * Zebra registers a results callback with the dataplane. The callback is
- * called in the dataplane pthread context, so the expectation is that the
- * context is queued for the zebra main pthread or that processing
- * is very limited.
- */
-typedef int (*dplane_results_fp)(struct zebra_dplane_ctx *ctx);
-
-int dplane_results_register(dplane_results_fp fp);
-
/*
* Initialize the dataplane modules at zebra startup. This is currently called
- * by the rib module.
+ * by the rib module. Zebra registers a results callback with the dataplane.
+ * The callback is called in the dataplane pthread context,
+ * so the expectation is that the contexts are queued for the zebra
+ * main pthread.
*/
-void zebra_dplane_init(void);
+void zebra_dplane_init(int (*) (struct dplane_ctx_q *));
/*
* Start the dataplane pthread. This step needs to be run later than the
break;
}
- if (event->mask & IN_DELETE)
- return zebra_ns_delete(event->name);
-
+ if (event->mask & IN_DELETE) {
+ zebra_ns_delete(event->name);
+ continue;
+ }
netnspath = ns_netns_pathname(NULL, event->name);
if (!netnspath)
continue;
dplane_ctx_get_vrf(ctx), dest_str, ctx,
dplane_op2str(op), dplane_res2str(status));
- if (op == DPLANE_OP_ROUTE_DELETE) {
- /*
- * In the delete case, the zebra core datastructs were
- * updated (or removed) at the time the delete was issued,
- * so we're just notifying the route owner.
- */
- if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
- zsend_route_notify_owner_ctx(ctx, ZAPI_ROUTE_REMOVED);
-
- if (zvrf)
- zvrf->removals++;
- } else {
- zsend_route_notify_owner_ctx(ctx,
- ZAPI_ROUTE_REMOVE_FAIL);
-
- zlog_warn("%u:%s: Route Deletion failure",
- dplane_ctx_get_vrf(ctx),
- prefix2str(dest_pfx,
- dest_str, sizeof(dest_str)));
- }
-
- /* Nothing more to do in delete case */
- goto done;
- }
-
/*
* Update is a bit of a special case, where we may have both old and new
* routes to post-process.
goto done;
}
- if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
- /* Update zebra nexthop FIB flag for each
- * nexthop that was installed.
- */
- for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), ctx_nexthop)) {
+ switch (op) {
+ case DPLANE_OP_NONE:
+ break;
+ case DPLANE_OP_ROUTE_INSTALL:
+ case DPLANE_OP_ROUTE_UPDATE:
+ if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
+ /* Update zebra nexthop FIB flag for each
+ * nexthop that was installed.
+ */
+ for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx),
+ ctx_nexthop)) {
- for (ALL_NEXTHOPS(re->ng, nexthop)) {
- if (nexthop_same(ctx_nexthop, nexthop))
- break;
+ for (ALL_NEXTHOPS(re->ng, nexthop)) {
+ if (nexthop_same(ctx_nexthop, nexthop))
+ break;
+ }
+
+ if (nexthop == NULL)
+ continue;
+
+ if (CHECK_FLAG(nexthop->flags,
+ NEXTHOP_FLAG_RECURSIVE))
+ continue;
+
+ if (CHECK_FLAG(ctx_nexthop->flags,
+ NEXTHOP_FLAG_FIB))
+ SET_FLAG(nexthop->flags,
+ NEXTHOP_FLAG_FIB);
+ else
+ UNSET_FLAG(nexthop->flags,
+ NEXTHOP_FLAG_FIB);
}
- if (nexthop == NULL)
- continue;
+ if (zvrf) {
+ zvrf->installs++;
+ /* Set flag for nexthop tracking processing */
+ zvrf->flags |= ZEBRA_VRF_RIB_SCHEDULED;
+ }
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
- continue;
+ /* Redistribute */
+ /*
+ * TODO -- still calling the redist api using the
+ * route_entries, and there's a corner-case here:
+ * if there's no client for the 'new' route, a redist
+ * deleting the 'old' route will be sent. But if the
+ * 'old' context info was stale, 'old_re' will be
+ * NULL here and that delete will not be sent.
+ */
+ redistribute_update(dest_pfx, src_pfx, re, old_re);
- if (CHECK_FLAG(ctx_nexthop->flags,
- NEXTHOP_FLAG_FIB))
- SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
- else
- UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
- }
+ /* Notify route owner */
+ zsend_route_notify_owner(re, dest_pfx,
+ ZAPI_ROUTE_INSTALLED);
- if (zvrf) {
- zvrf->installs++;
- /* Set flag for nexthop tracking processing */
- zvrf->flags |= ZEBRA_VRF_RIB_SCHEDULED;
- }
+ } else {
+ zsend_route_notify_owner(re, dest_pfx,
+ ZAPI_ROUTE_FAIL_INSTALL);
- /* Redistribute */
- /* TODO -- still calling the redist api using the route_entries,
- * and there's a corner-case here: if there's no client
- * for the 'new' route, a redist deleting the 'old' route
- * will be sent. But if the 'old' context info was stale,
- * 'old_re' will be NULL here and that delete will not be sent.
+ zlog_warn("%u:%s: Route install failed",
+ dplane_ctx_get_vrf(ctx),
+ prefix2str(dest_pfx,
+ dest_str, sizeof(dest_str)));
+ }
+ break;
+ case DPLANE_OP_ROUTE_DELETE:
+ /*
+ * In the delete case, the zebra core datastructs were
+ * updated (or removed) at the time the delete was issued,
+ * so we're just notifying the route owner.
*/
- redistribute_update(dest_pfx, src_pfx, re, old_re);
-
- /* Notify route owner */
- zsend_route_notify_owner(re,
- dest_pfx, ZAPI_ROUTE_INSTALLED);
+ if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
+ zsend_route_notify_owner_ctx(ctx, ZAPI_ROUTE_REMOVED);
- } else {
- zsend_route_notify_owner(re, dest_pfx,
- ZAPI_ROUTE_FAIL_INSTALL);
+ if (zvrf)
+ zvrf->removals++;
+ } else {
+ zsend_route_notify_owner_ctx(ctx,
+ ZAPI_ROUTE_REMOVE_FAIL);
- zlog_warn("%u:%s: Route install failed",
- dplane_ctx_get_vrf(ctx),
- prefix2str(dest_pfx,
- dest_str, sizeof(dest_str)));
+ zlog_warn("%u:%s: Route Deletion failure",
+ dplane_ctx_get_vrf(ctx),
+ prefix2str(dest_pfx,
+ dest_str, sizeof(dest_str)));
+ }
+ break;
}
-
done:
/* Return context to dataplane module */
return mq->size ? WQ_REQUEUE : WQ_SUCCESS;
}
-/* Look into the RN and queue it into one or more priority queues,
- * increasing the size for each data push done.
+
+/*
+ * Look into the RN and queue it into the highest priority queue
+ * at this point in time for processing.
+ *
+ * We will enqueue a route node only once per invocation.
+ *
+ * There are two possibilities here that should be kept in mind.
+ * If the original invocation has not been pulled off for processing
+ * yet, A subsuquent invocation can have a route entry with a better
+ * meta queue index value and we can have a situation where
+ * we might have the same node enqueued 2 times. Not necessarily
+ * an optimal situation but it should be ok.
+ *
+ * The other possibility is that the original invocation has not
+ * been pulled off for processing yet, A subsusquent invocation
+ * doesn't have a route_entry with a better meta-queue and the
+ * original metaqueue index value will win and we'll end up with
+ * the route node enqueued once.
*/
static void rib_meta_queue_add(struct meta_queue *mq, struct route_node *rn)
{
- struct route_entry *re;
+ struct route_entry *re = NULL, *curr_re = NULL;
+ uint8_t qindex = MQ_SIZE, curr_qindex = MQ_SIZE;
+ struct zebra_vrf *zvrf;
- RNODE_FOREACH_RE (rn, re) {
- uint8_t qindex = route_info[re->type].meta_q_map;
- struct zebra_vrf *zvrf;
+ RNODE_FOREACH_RE (rn, curr_re) {
+ curr_qindex = route_info[curr_re->type].meta_q_map;
- /* Invariant: at this point we always have rn->info set. */
- if (CHECK_FLAG(rib_dest_from_rnode(rn)->flags,
- RIB_ROUTE_QUEUED(qindex))) {
- if (IS_ZEBRA_DEBUG_RIB_DETAILED)
- rnode_debug(
- rn, re->vrf_id,
- "rn %p is already queued in sub-queue %u",
- (void *)rn, qindex);
- continue;
+ if (curr_qindex <= qindex) {
+ re = curr_re;
+ qindex = curr_qindex;
}
+ }
- SET_FLAG(rib_dest_from_rnode(rn)->flags,
- RIB_ROUTE_QUEUED(qindex));
- listnode_add(mq->subq[qindex], rn);
- route_lock_node(rn);
- mq->size++;
+ if (!re)
+ return;
+ /* Invariant: at this point we always have rn->info set. */
+ if (CHECK_FLAG(rib_dest_from_rnode(rn)->flags,
+ RIB_ROUTE_QUEUED(qindex))) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
rnode_debug(rn, re->vrf_id,
- "queued rn %p into sub-queue %u",
+ "rn %p is already queued in sub-queue %u",
(void *)rn, qindex);
-
- zvrf = zebra_vrf_lookup_by_id(re->vrf_id);
- if (zvrf)
- zvrf->flags |= ZEBRA_VRF_RIB_SCHEDULED;
+ return;
}
+
+ SET_FLAG(rib_dest_from_rnode(rn)->flags, RIB_ROUTE_QUEUED(qindex));
+ listnode_add(mq->subq[qindex], rn);
+ route_lock_node(rn);
+ mq->size++;
+
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+ rnode_debug(rn, re->vrf_id, "queued rn %p into sub-queue %u",
+ (void *)rn, qindex);
+
+ zvrf = zebra_vrf_lookup_by_id(re->vrf_id);
+ if (zvrf)
+ zvrf->flags |= ZEBRA_VRF_RIB_SCHEDULED;
}
/* Add route_node to work queue and schedule processing */
static int rib_process_dplane_results(struct thread *thread)
{
struct zebra_dplane_ctx *ctx;
+ struct dplane_ctx_q ctxlist;
+
+ /* Dequeue a list of completed updates with one lock/unlock cycle */
do {
+ TAILQ_INIT(&ctxlist);
+
/* Take lock controlling queue of results */
pthread_mutex_lock(&dplane_mutex);
{
/* Dequeue context block */
- ctx = dplane_ctx_dequeue(&rib_dplane_q);
+ dplane_ctx_list_append(&ctxlist, &rib_dplane_q);
}
pthread_mutex_unlock(&dplane_mutex);
- if (ctx)
- rib_process_after(ctx);
- else
+ /* Dequeue context block */
+ ctx = dplane_ctx_dequeue(&ctxlist);
+
+ /* If we've emptied the results queue, we're done */
+ if (ctx == NULL)
break;
+ while (ctx) {
+ rib_process_after(ctx);
+
+ ctx = dplane_ctx_dequeue(&ctxlist);
+ }
+
} while (1);
/* Check for nexthop tracking processing after finishing with results */
* the dataplane pthread. We enqueue the results here for processing by
* the main thread later.
*/
-static int rib_dplane_results(struct zebra_dplane_ctx *ctx)
+static int rib_dplane_results(struct dplane_ctx_q *ctxlist)
{
/* Take lock controlling queue of results */
pthread_mutex_lock(&dplane_mutex);
{
- /* Enqueue context block */
- dplane_ctx_enqueue_tail(&rib_dplane_q, ctx);
+ /* Enqueue context blocks */
+ dplane_ctx_list_append(&rib_dplane_q, ctxlist);
}
pthread_mutex_unlock(&dplane_mutex);
- /* Ensure event is signalled to zebra main thread */
+ /* Ensure event is signalled to zebra main pthread */
thread_add_event(zebrad.master, rib_process_dplane_results, NULL, 0,
&t_dplane);
/* Init dataplane, and register for results */
pthread_mutex_init(&dplane_mutex, NULL);
TAILQ_INIT(&rib_dplane_q);
- zebra_dplane_init();
- dplane_results_register(rib_dplane_results);
+ zebra_dplane_init(rib_dplane_results);
}
/*
info = XCALLOC(MTYPE_RIB_TABLE_INFO, sizeof(*info));
info->zvrf = zvrf;
info->afi = afi;
- info->safi = SAFI_UNICAST;
+ info->safi = safi;
route_table_set_info(zrt->table, info);
zrt->table->cleanup = zebra_rtable_node_cleanup;
return cnt;
}
+void zebra_router_show_table_summary(struct vty *vty)
+{
+ struct zebra_router_table *zrt;
+
+ vty_out(vty,
+ "VRF NS ID VRF ID AFI SAFI Table Count\n");
+ vty_out(vty,
+ "---------------------------------------------------------------------------\n");
+ RB_FOREACH (zrt, zebra_router_table_head, &zrouter.tables) {
+ rib_table_info_t *info = route_table_get_info(zrt->table);
+
+ vty_out(vty, "%-16s%5d %9d %7s %15s %8d %10lu\n", info->zvrf->vrf->name,
+ zrt->ns_id, info->zvrf->vrf->vrf_id,
+ afi2str(zrt->afi), safi2str(zrt->safi),
+ zrt->tableid,
+ zrt->table->count);
+ }
+}
+
void zebra_router_sweep_route(void)
{
struct zebra_router_table *zrt;
extern unsigned long zebra_router_score_proto(uint8_t proto,
unsigned short instance);
extern void zebra_router_sweep_route(void);
+
+extern void zebra_router_show_table_summary(struct vty *vty);
#endif
static void zebra_vrf_table_create(struct zebra_vrf *zvrf, afi_t afi,
safi_t safi)
{
- rib_table_info_t *info;
- struct route_table *table;
-
assert(!zvrf->table[afi][safi]);
- table = zebra_router_get_table(zvrf, zvrf->table_id, afi, safi);
-
- table->cleanup = zebra_rtable_node_cleanup;
- zvrf->table[afi][safi] = table;
-
- XFREE(MTYPE_RIB_TABLE_INFO, table->info);
- info = XCALLOC(MTYPE_RIB_TABLE_INFO, sizeof(*info));
- info->zvrf = zvrf;
- info->afi = afi;
- info->safi = safi;
- route_table_set_info(table, info);
+ zvrf->table[afi][safi] =
+ zebra_router_get_table(zvrf, zvrf->table_id, afi, safi);
}
/* Allocate new zebra VRF. */
return CMD_SUCCESS;
}
+DEFUN (zebra_show_routing_tables_summary,
+ zebra_show_routing_tables_summary_cmd,
+ "show zebra router table summary",
+ SHOW_STR
+ ZEBRA_STR
+ "The Zebra Router Information\n"
+ "Table Information about this Zebra Router\n"
+ "Summary Information\n")
+{
+ zebra_router_show_table_summary(vty);
+
+ return CMD_SUCCESS;
+}
+
/* Table configuration write function. */
static int config_write_table(struct vty *vty)
{
install_element(VIEW_NODE, &show_dataplane_providers_cmd);
install_element(CONFIG_NODE, &zebra_dplane_queue_limit_cmd);
install_element(CONFIG_NODE, &no_zebra_dplane_queue_limit_cmd);
+
+ install_element(VIEW_NODE, &zebra_show_routing_tables_summary_cmd);
}
struct zebra_vrf *zvrf = NULL;
struct timeval detect_start_time = {0, 0};
- zvrf = zebra_vrf_lookup_by_id(n->zvni->vrf_id);
+ zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
if (!zvrf)
return;
+ zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
ipaddr2str(&n->ip, buf2, sizeof(buf2));
prefix_mac2str(&n->emac, buf1, sizeof(buf1));
type_str = CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL) ?
struct zebra_vrf *zvrf;
struct timeval detect_start_time = {0, 0};
- zvrf = zebra_vrf_lookup_by_id(mac->zvni->vrf_id);
+ zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
vty = (struct vty *)ctxt;
prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1));
struct zebra_vrf *zvrf = NULL;
char buf[ETHER_ADDR_STRLEN];
- zvrf = vrf_info_lookup(zvni->vrf_id);
+ zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug("Processing neighbors on local MAC %s %s, VNI %u",
}
}
- zvrf = vrf_info_lookup(zvni->vrf_id);
+ zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
if (!zvrf)
return -1;
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "%s: duplicate detect %s max_moves %u timeout %u freeze %s freeze_time %u",
- __PRETTY_FUNCTION__,
+ "VRF %s duplicate detect %s max_moves %u timeout %u freeze %s freeze_time %u",
+ vrf_id_to_name(zvrf->vrf->vrf_id),
zvrf->dup_addr_detect ? "enable" : "disable",
zvrf->dad_max_moves,
zvrf->dad_time,
nbr = THREAD_ARG(t);
/* since this is asynchronous we need sanity checks*/
- zvrf = vrf_info_lookup(nbr->zvni->vrf_id);
- if (!zvrf)
+ nbr = zvni_neigh_lookup(zvni, &nbr->ip);
+ if (!nbr)
return 0;
zvni = zvni_lookup(nbr->zvni->vni);
if (!zvni)
return 0;
- nbr = zvni_neigh_lookup(zvni, &nbr->ip);
- if (!nbr)
+ zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
+ if (!zvrf)
return 0;
if (IS_ZEBRA_DEBUG_VXLAN)
mac = THREAD_ARG(t);
/* since this is asynchronous we need sanity checks*/
- zvrf = vrf_info_lookup(mac->zvni->vrf_id);
- if (!zvrf)
+ mac = zvni_mac_lookup(zvni, &mac->macaddr);
+ if (!mac)
return 0;
zvni = zvni_lookup(mac->zvni->vni);
if (!zvni)
return 0;
- mac = zvni_mac_lookup(zvni, &mac->macaddr);
- if (!mac)
+ zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
+ if (!zvrf)
return 0;
if (IS_ZEBRA_DEBUG_VXLAN)