diff options
144 files changed, 2149 insertions, 958 deletions
@@ -20,6 +20,7 @@ FRR currently supports the following protocols: * Babel * PBR * OpenFabric +* VRRP * EIGRP (alpha) * NHRP (alpha) diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index b84bc39cd8..0eeb9b2bbb 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -39,9 +39,10 @@ THE SOFTWARE. #include "neighbour.h" #include "route.h" #include "xroute.h" -#include "babel_memory.h" #include "babel_errors.h" +DEFINE_MTYPE_STATIC(BABELD, BABEL_IF, "Babel Interface") + #define IS_ENABLE(ifp) (babel_enable_if_lookup(ifp->name) >= 0) static int babel_enable_if_lookup (const char *ifname); diff --git a/babeld/babel_memory.c b/babeld/babel_memory.c deleted file mode 100644 index a10b7791e7..0000000000 --- a/babeld/babel_memory.c +++ /dev/null @@ -1,30 +0,0 @@ -/* babeld memory type definitions - * - * Copyright (C) 2017 Donald Sharp - * - * This file is part of FRR - * - * FRR is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * FRR is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with FRR; see the file COPYING. If not, write to the Free - * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "babel_memory.h" - -DEFINE_MGROUP(BABELD, "babeld") -DEFINE_MTYPE(BABELD, BABEL, "Babel Structure") -DEFINE_MTYPE(BABELD, BABEL_IF, "Babel Interface") diff --git a/babeld/babel_memory.h b/babeld/babel_memory.h deleted file mode 100644 index 4283498891..0000000000 --- a/babeld/babel_memory.h +++ /dev/null @@ -1,32 +0,0 @@ -/* babel memory type declarations - * - * Copyright (C) 2017 Donald Sharp - * - * This file is part of FRR. - * - * FRR is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * FRR is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with FRR; see the file COPYING. If not, write to the Free - * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#ifndef _FRR_BABEL_MEMORY_H -#define _FRR_BABEL_MEMORY_H - -#include "memory.h" - -DECLARE_MGROUP(BABELD) -DECLARE_MTYPE(BABEL) -DECLARE_MTYPE(BABEL_IF) - -#endif /* _FRR_BABELD_MEMORY_H */ diff --git a/babeld/babeld.c b/babeld/babeld.c index 39451b435a..6ad004a4a4 100644 --- a/babeld/babeld.c +++ b/babeld/babeld.c @@ -43,9 +43,11 @@ THE SOFTWARE. #include "resend.h" #include "babel_filter.h" #include "babel_zebra.h" -#include "babel_memory.h" #include "babel_errors.h" +DEFINE_MGROUP(BABELD, "babeld") +DEFINE_MTYPE_STATIC(BABELD, BABEL, "Babel Structure") + static int babel_init_routing_process(struct thread *thread); static void babel_get_myid(void); static void babel_initial_noise(void); diff --git a/babeld/subdir.am b/babeld/subdir.am index 7081c730aa..dd46675f22 100644 --- a/babeld/subdir.am +++ b/babeld/subdir.am @@ -17,7 +17,6 @@ babeld_libbabel_a_SOURCES = \ babeld/babel_errors.c \ babeld/babel_filter.c \ babeld/babel_interface.c \ - babeld/babel_memory.c \ babeld/babel_zebra.c \ babeld/babeld.c \ babeld/kernel.c \ @@ -36,7 +35,6 @@ noinst_HEADERS += \ babeld/babel_filter.h \ babeld/babel_interface.h \ babeld/babel_main.h \ - babeld/babel_memory.h \ babeld/babel_zebra.h \ babeld/babeld.h \ babeld/kernel.h \ diff --git a/babeld/util.h b/babeld/util.h index 7b836c2e4c..00a025ff93 100644 --- a/babeld/util.h +++ b/babeld/util.h @@ -27,6 +27,9 @@ THE SOFTWARE. #include "babeld.h" #include "babel_main.h" #include "log.h" +#include "memory.h" + +DECLARE_MGROUP(BABELD) #if defined(i386) || defined(__mc68020__) || defined(__x86_64__) #define DO_NTOHS(_d, _s) do{ _d = ntohs(*(const unsigned short*)(_s)); }while(0) diff --git a/bfdd/bfd.c b/bfdd/bfd.c index 4354431820..08a70abc1e 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -31,7 +31,10 @@ #include "bfd.h" -DEFINE_QOBJ_TYPE(bfd_session); +DEFINE_MTYPE_STATIC(BFDD, BFDD_CONFIG, "long-lived configuration memory") +DEFINE_MTYPE_STATIC(BFDD, BFDD_SESSION_OBSERVER, "Session observer") +DEFINE_MTYPE_STATIC(BFDD, BFDD_VRF, "BFD VRF") +DEFINE_QOBJ_TYPE(bfd_session) /* * Prototypes @@ -1552,41 +1555,41 @@ static int bfd_vrf_enable(struct vrf *vrf) } else bvrf = vrf->info; log_debug("VRF enable add %s id %u", vrf->name, vrf->vrf_id); - - /* create sockets if needed */ - if (!bvrf->bg_shop) - bvrf->bg_shop = bp_udp_shop(vrf->vrf_id); - if (!bvrf->bg_mhop) - bvrf->bg_mhop = bp_udp_mhop(vrf->vrf_id); - if (!bvrf->bg_shop6) - bvrf->bg_shop6 = bp_udp6_shop(vrf->vrf_id); - if (!bvrf->bg_mhop6) - bvrf->bg_mhop6 = bp_udp6_mhop(vrf->vrf_id); - if (!bvrf->bg_echo) - bvrf->bg_echo = bp_echo_socket(vrf->vrf_id); - if (!bvrf->bg_echov6) - bvrf->bg_echov6 = bp_echov6_socket(vrf->vrf_id); - - /* Add descriptors to the event loop. */ - if (!bvrf->bg_ev[0]) - thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_shop, - &bvrf->bg_ev[0]); - if (!bvrf->bg_ev[1]) - thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_mhop, - &bvrf->bg_ev[1]); - if (!bvrf->bg_ev[2]) - thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_shop6, - &bvrf->bg_ev[2]); - if (!bvrf->bg_ev[3]) - thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_mhop6, - &bvrf->bg_ev[3]); - if (!bvrf->bg_ev[4]) - thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_echo, - &bvrf->bg_ev[4]); - if (!bvrf->bg_ev[5]) - thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_echov6, - &bvrf->bg_ev[5]); - + if (vrf->vrf_id == VRF_DEFAULT || + vrf_get_backend() == VRF_BACKEND_NETNS) { + if (!bvrf->bg_shop) + bvrf->bg_shop = bp_udp_shop(vrf->vrf_id); + if (!bvrf->bg_mhop) + bvrf->bg_mhop = bp_udp_mhop(vrf->vrf_id); + if (!bvrf->bg_shop6) + bvrf->bg_shop6 = bp_udp6_shop(vrf->vrf_id); + if (!bvrf->bg_mhop6) + bvrf->bg_mhop6 = bp_udp6_mhop(vrf->vrf_id); + if (!bvrf->bg_echo) + bvrf->bg_echo = bp_echo_socket(vrf->vrf_id); + if (!bvrf->bg_echov6) + bvrf->bg_echov6 = bp_echov6_socket(vrf->vrf_id); + + /* Add descriptors to the event loop. */ + if (!bvrf->bg_ev[0]) + thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_shop, + &bvrf->bg_ev[0]); + if (!bvrf->bg_ev[1]) + thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_mhop, + &bvrf->bg_ev[1]); + if (!bvrf->bg_ev[2]) + thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_shop6, + &bvrf->bg_ev[2]); + if (!bvrf->bg_ev[3]) + thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_mhop6, + &bvrf->bg_ev[3]); + if (!bvrf->bg_ev[4]) + thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_echo, + &bvrf->bg_ev[4]); + if (!bvrf->bg_ev[5]) + thread_add_read(master, bfd_recv_cb, bvrf, bvrf->bg_echov6, + &bvrf->bg_ev[5]); + } if (vrf->vrf_id != VRF_DEFAULT) { bfdd_zclient_register(vrf->vrf_id); bfdd_sessions_enable_vrf(vrf); diff --git a/bfdd/bfd.h b/bfdd/bfd.h index 213e905bf0..ec31c8cbc6 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -41,14 +41,9 @@ #define BFDD_JSON_CONV_OPTIONS (0) #endif -DECLARE_MGROUP(BFDD); -DECLARE_MTYPE(BFDD_TMP); -DECLARE_MTYPE(BFDD_CONFIG); -DECLARE_MTYPE(BFDD_LABEL); -DECLARE_MTYPE(BFDD_CONTROL); -DECLARE_MTYPE(BFDD_SESSION_OBSERVER); -DECLARE_MTYPE(BFDD_NOTIFICATION); -DECLARE_MTYPE(BFDD_VRF); +DECLARE_MGROUP(BFDD) +DECLARE_MTYPE(BFDD_CONTROL) +DECLARE_MTYPE(BFDD_NOTIFICATION) struct bfd_timers { uint32_t desired_min_tx; @@ -259,9 +254,9 @@ struct bfd_session { uint64_t refcount; /* number of pointers referencing this. */ /* VTY context data. */ - QOBJ_FIELDS; + QOBJ_FIELDS }; -DECLARE_QOBJ_TYPE(bfd_session); +DECLARE_QOBJ_TYPE(bfd_session) struct peer_label { TAILQ_ENTRY(peer_label) pl_entry; diff --git a/bfdd/bfdd.c b/bfdd/bfdd.c index 06e01abcfa..6c277c98f5 100644 --- a/bfdd/bfdd.c +++ b/bfdd/bfdd.c @@ -29,14 +29,9 @@ /* * FRR related code. */ -DEFINE_MGROUP(BFDD, "Bidirectional Forwarding Detection Daemon"); -DEFINE_MTYPE(BFDD, BFDD_TMP, "short-lived temporary memory"); -DEFINE_MTYPE(BFDD, BFDD_CONFIG, "long-lived configuration memory"); -DEFINE_MTYPE(BFDD, BFDD_LABEL, "long-lived label memory"); -DEFINE_MTYPE(BFDD, BFDD_CONTROL, "long-lived control socket memory"); -DEFINE_MTYPE(BFDD, BFDD_SESSION_OBSERVER, "Session observer"); -DEFINE_MTYPE(BFDD, BFDD_NOTIFICATION, "short-lived control notification data"); -DEFINE_MTYPE(BFDD, BFDD_VRF, "BFD VRF"); +DEFINE_MGROUP(BFDD, "Bidirectional Forwarding Detection Daemon") +DEFINE_MTYPE(BFDD, BFDD_CONTROL, "long-lived control socket memory") +DEFINE_MTYPE(BFDD, BFDD_NOTIFICATION, "short-lived control notification data") /* Master of threads. */ struct thread_master *master; diff --git a/bfdd/config.c b/bfdd/config.c index 74e7d63d0c..0c0bac0aaa 100644 --- a/bfdd/config.c +++ b/bfdd/config.c @@ -30,6 +30,8 @@ #include "bfd.h" +DEFINE_MTYPE_STATIC(BFDD, BFDD_LABEL, "long-lived label memory") + /* * Definitions */ diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c index b9a5784799..ce617fe6b5 100644 --- a/bgpd/bgp_clist.c +++ b/bgpd/bgp_clist.c @@ -695,6 +695,32 @@ int lcommunity_list_match(struct lcommunity *lcom, struct community_list *list) return 0; } + +/* Perform exact matching. In case of expanded large-community-list, do + * same thing as lcommunity_list_match(). + */ +int lcommunity_list_exact_match(struct lcommunity *lcom, + struct community_list *list) +{ + struct community_entry *entry; + + for (entry = list->head; entry; entry = entry->next) { + if (entry->any) + return entry->direct == COMMUNITY_PERMIT ? 1 : 0; + + if (entry->style == LARGE_COMMUNITY_LIST_STANDARD) { + if (lcommunity_cmp(lcom, entry->u.com)) + return entry->direct == COMMUNITY_PERMIT ? 1 + : 0; + } else if (entry->style == LARGE_COMMUNITY_LIST_EXPANDED) { + if (lcommunity_regexp_match(lcom, entry->reg)) + return entry->direct == COMMUNITY_PERMIT ? 1 + : 0; + } + } + return 0; +} + int ecommunity_list_match(struct ecommunity *ecom, struct community_list *list) { struct community_entry *entry; diff --git a/bgpd/bgp_clist.h b/bgpd/bgp_clist.h index 75a31611ba..87b29ac3be 100644 --- a/bgpd/bgp_clist.h +++ b/bgpd/bgp_clist.h @@ -165,6 +165,8 @@ extern int ecommunity_list_match(struct ecommunity *, struct community_list *); extern int lcommunity_list_match(struct lcommunity *, struct community_list *); extern int community_list_exact_match(struct community *, struct community_list *); +extern int lcommunity_list_exact_match(struct lcommunity *lcom, + struct community_list *list); extern struct community *community_list_match_delete(struct community *, struct community_list *); extern struct lcommunity * diff --git a/bgpd/bgp_errors.c b/bgpd/bgp_errors.c index 6e181697d6..d9aba87e35 100644 --- a/bgpd/bgp_errors.c +++ b/bgpd/bgp_errors.c @@ -427,12 +427,6 @@ static struct log_ref ferr_bgp_err[] = { .suggestion = "Most likely a bug. If the problem persists, report the problem for troubleshooting" }, { - .code = EC_BGP_MULTI_INSTANCE, - .title = "BGP config multi-instance issue", - .description = "BGP configuration attempting multiple instances without enabling the feature", - .suggestion = "Correct the configuration so that bgp multiple-instance is enabled if desired" - }, - { .code = EC_BGP_EVPN_AS_MISMATCH, .title = "BGP AS configuration issue", .description = "BGP configuration attempted for a different AS than currently configured", diff --git a/bgpd/bgp_errors.h b/bgpd/bgp_errors.h index 39d043ff13..35c5cc3998 100644 --- a/bgpd/bgp_errors.h +++ b/bgpd/bgp_errors.h @@ -67,7 +67,6 @@ enum bgp_log_refs { EC_BGP_EVPN_ROUTE_INVALID, EC_BGP_EVPN_ROUTE_CREATE, EC_BGP_ES_CREATE, - EC_BGP_MULTI_INSTANCE, EC_BGP_EVPN_AS_MISMATCH, EC_BGP_EVPN_INSTANCE_MISMATCH, EC_BGP_FLOWSPEC_PACKET, diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index c4b2a606c5..94022ec1be 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -5533,10 +5533,6 @@ int bgp_evpn_local_l3vni_add(vni_t l3vni, vrf_id_t vrf_id, struct ethaddr *rmac, vrf_id == VRF_DEFAULT ? BGP_INSTANCE_TYPE_DEFAULT : BGP_INSTANCE_TYPE_VRF); switch (ret) { - case BGP_ERR_MULTIPLE_INSTANCE_NOT_SET: - flog_err(EC_BGP_MULTI_INSTANCE, - "'bgp multiple-instance' not present\n"); - return -1; case BGP_ERR_AS_MISMATCH: flog_err(EC_BGP_EVPN_AS_MISMATCH, "BGP is already running; AS is %u\n", as); diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 67b0079c37..44e9375dc9 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -1060,6 +1060,9 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd, json_object_int_add(json_prefix_info, "prefixLen", rm->p.prefixlen); + + if (rd_header) + json_nroute = json_object_new_object(); } for (pi = bgp_node_get_bgp_path_info(rm); pi; @@ -1132,8 +1135,6 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd, else if (type == RD_TYPE_IP) decode_rd_ip(pnt + 2, &rd_ip); if (use_json) { - json_nroute = - json_object_new_object(); if (type == RD_TYPE_AS || type == RD_TYPE_AS4) sprintf(rd_str, "%u:%d", @@ -1184,6 +1185,7 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd, SAFI_EVPN, json_array); output_count++; } + rd_header = 0; if (use_json) { json_object_object_add(json_prefix_info, "paths", json_array); @@ -2478,6 +2480,8 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type, bgp_evpn_show_route_header(vty, bgp, tbl_ver, json); + vty_out(vty, "%19s Extended Community\n" + , " "); header = 0; } diff --git a/bgpd/bgp_mac.c b/bgpd/bgp_mac.c index f19453fecb..61c7b4080c 100644 --- a/bgpd/bgp_mac.c +++ b/bgpd/bgp_mac.c @@ -29,6 +29,7 @@ #include "bgpd/bgp_memory.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_packet.h" +#include "bgpd/bgp_rd.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_evpn_private.h" @@ -133,11 +134,11 @@ static struct bgp_self_mac *bgp_mac_find_interface_name(const char *ifname) } static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer, - struct bgp_table *table) + struct bgp_table *table, + struct ethaddr *macaddr) { 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; @@ -146,12 +147,21 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer, continue; for (rn = bgp_table_top(sub); rn; rn = bgp_route_next(rn)) { + bool rn_affected; + struct prefix_evpn *pevpn = (struct prefix_evpn *)&rn->p; struct prefix_rd prd; uint32_t num_labels = 0; mpls_label_t *label_pnt = NULL; struct bgp_route_evpn evpn; - count++; + if (pevpn->family == AF_EVPN && + pevpn->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE && + memcmp(&rn->p.u.prefix_evpn.macip_addr.mac, + macaddr, ETH_ALEN) == 0) + rn_affected = true; + else + rn_affected = false; + for (pi = rn->info; pi; pi = pi->next) { if (pi->peer == peer) break; @@ -160,6 +170,14 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer, if (!pi) continue; + /* + * If the mac address is not the same then + * we don't care and since we are looking + */ + if ((memcmp(&pi->attr->rmac, macaddr, ETH_ALEN) != 0) && + !rn_affected) + continue; + if (pi->extra) num_labels = pi->extra->num_labels; if (num_labels) @@ -169,6 +187,23 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer, prd.prefixlen = 64; memcpy(&prd.val, &prn->p.u.val, 8); + if (CHECK_FLAG(pi->flags, BGP_PATH_REMOVED)) { + if (bgp_debug_update(peer, &rn->p, NULL, 1)) { + char pfx_buf[BGP_PRD_PATH_STRLEN]; + + bgp_debug_rdpfxpath2str( + AFI_L2VPN, SAFI_EVPN, &prd, + &rn->p, label_pnt, num_labels, + pi->addpath_rx_id ? 1 : 0, + pi->addpath_rx_id, pfx_buf, + sizeof(pfx_buf)); + zlog_debug( + "%s skip update of %s marked as removed", + peer->host, pfx_buf); + } + continue; + } + memcpy(&evpn, &pi->attr->evpn_overlay, sizeof(evpn)); int32_t ret = bgp_update(peer, &rn->p, pi->addpath_rx_id, @@ -184,7 +219,7 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer, } } -static void bgp_mac_rescan_evpn_table(struct bgp *bgp) +static void bgp_mac_rescan_evpn_table(struct bgp *bgp, struct ethaddr *macaddr) { struct listnode *node; struct peer *peer; @@ -214,12 +249,12 @@ static void bgp_mac_rescan_evpn_table(struct bgp *bgp) 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); + bgp_process_mac_rescan_table(bgp, peer, table, macaddr); } } } -static void bgp_mac_rescan_all_evpn_tables(void) +static void bgp_mac_rescan_all_evpn_tables(struct ethaddr *macaddr) { struct listnode *node; struct bgp *bgp; @@ -228,11 +263,12 @@ static void bgp_mac_rescan_all_evpn_tables(void) struct bgp_table *table = bgp->rib[AFI_L2VPN][SAFI_EVPN]; if (table) - bgp_mac_rescan_evpn_table(bgp); + bgp_mac_rescan_evpn_table(bgp, macaddr); } } -static void bgp_mac_remove_ifp_internal(struct bgp_self_mac *bsm, char *ifname) +static void bgp_mac_remove_ifp_internal(struct bgp_self_mac *bsm, char *ifname, + struct ethaddr *macaddr) { struct listnode *node = NULL; char *name; @@ -252,7 +288,7 @@ static void bgp_mac_remove_ifp_internal(struct bgp_self_mac *bsm, char *ifname) list_delete(&bsm->ifp_list); XFREE(MTYPE_BSM, bsm); - bgp_mac_rescan_all_evpn_tables(); + bgp_mac_rescan_all_evpn_tables(macaddr); } } @@ -276,22 +312,26 @@ void bgp_mac_add_mac_entry(struct interface *ifp) listnode_add(bsm->ifp_list, ifname); if (old_bsm) - bgp_mac_remove_ifp_internal(old_bsm, ifname); + bgp_mac_remove_ifp_internal(old_bsm, ifname, + &old_bsm->macaddr); } else { /* * If old mac address is the same as the new, * then there is nothing to do here */ - if (old_bsm == bsm) + if (old_bsm == bsm) { + XFREE(MTYPE_BSM_STRING, ifname); return; + } if (old_bsm) - bgp_mac_remove_ifp_internal(old_bsm, ifp->name); + bgp_mac_remove_ifp_internal(old_bsm, ifp->name, + &old_bsm->macaddr); listnode_add(bsm->ifp_list, ifname); } - bgp_mac_rescan_all_evpn_tables(); + bgp_mac_rescan_all_evpn_tables(&bsm->macaddr); } void bgp_mac_del_mac_entry(struct interface *ifp) @@ -308,7 +348,7 @@ void bgp_mac_del_mac_entry(struct interface *ifp) * 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); + bgp_mac_remove_ifp_internal(bsm, ifp->name, &bsm->macaddr); } /* This API checks MAC address against any of local diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index ae1821c43a..a3aba447b5 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2311,6 +2311,17 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn, char pfx_buf[PREFIX2STR_BUFFER]; int debug = 0; + if (bgp_flag_check(bgp, BGP_FLAG_DELETE_IN_PROGRESS)) { + if (rn) + debug = bgp_debug_bestpath(&rn->p); + if (debug) { + prefix2str(&rn->p, pfx_buf, sizeof(pfx_buf)); + zlog_debug( + "%s: bgp delete in progress, ignoring event, p=%s", + __func__, pfx_buf); + } + return; + } /* Is it end of initial update? (after startup) */ if (!rn) { quagga_timestamp(3, bgp->update_delay_zebra_resume_time, @@ -6532,28 +6543,38 @@ DEFUN (no_aggregate_address_mask, DEFUN (ipv6_aggregate_address, ipv6_aggregate_address_cmd, - "aggregate-address X:X::X:X/M [summary-only]", + "aggregate-address X:X::X:X/M [<as-set [summary-only]|summary-only [as-set]>]", "Configure BGP aggregate entries\n" "Aggregate prefix\n" - "Filter more specific routes from updates\n") + "Generate AS set path information\n" + "Filter more specific routes from updates\n" + "Filter more specific routes from updates\n" + "Generate AS set path information\n") { int idx = 0; argv_find(argv, argc, "X:X::X:X/M", &idx); char *prefix = argv[idx]->arg; + int as_set = + argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET : 0; + + idx = 0; int sum_only = argv_find(argv, argc, "summary-only", &idx) ? AGGREGATE_SUMMARY_ONLY : 0; return bgp_aggregate_set(vty, prefix, AFI_IP6, SAFI_UNICAST, sum_only, - 0); + as_set); } DEFUN (no_ipv6_aggregate_address, no_ipv6_aggregate_address_cmd, - "no aggregate-address X:X::X:X/M [summary-only]", + "no aggregate-address X:X::X:X/M [<as-set [summary-only]|summary-only [as-set]>]", NO_STR "Configure BGP aggregate entries\n" "Aggregate prefix\n" - "Filter more specific routes from updates\n") + "Generate AS set path information\n" + "Filter more specific routes from updates\n" + "Filter more specific routes from updates\n" + "Generate AS set path information\n") { int idx = 0; argv_find(argv, argc, "X:X::X:X/M", &idx); @@ -6955,6 +6976,7 @@ void route_vty_out(struct vty *vty, struct prefix *p, json_object *json_nexthops = NULL; json_object *json_nexthop_global = NULL; json_object *json_nexthop_ll = NULL; + json_object *json_ext_community = NULL; char vrf_id_str[VRF_NAMSIZ] = {0}; bool nexthop_self = CHECK_FLAG(path->flags, BGP_PATH_ANNC_NH_SELF) ? true : false; @@ -7320,6 +7342,17 @@ void route_vty_out(struct vty *vty, struct prefix *p, vty_out(vty, "%s", bgp_origin_str[attr->origin]); if (json_paths) { + if (safi == SAFI_EVPN && + attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)) { + json_ext_community = json_object_new_object(); + json_object_string_add(json_ext_community, + "string", + attr->ecommunity->str); + json_object_object_add(json_path, + "extendedCommunity", + json_ext_community); + } + if (nexthop_self) json_object_boolean_true_add(json_path, "announceNexthopSelf"); @@ -7353,6 +7386,13 @@ void route_vty_out(struct vty *vty, struct prefix *p, json_object_array_add(json_paths, json_path); } else { vty_out(vty, "\n"); + + if (safi == SAFI_EVPN && + attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)) { + vty_out(vty, "%*s", 20, " "); + vty_out(vty, "%s\n", attr->ecommunity->str); + } + #if ENABLE_BGP_VNC /* prints an additional line, indented, with VNC info, if * present */ @@ -7512,10 +7552,9 @@ void route_vty_out_tmp(struct vty *vty, struct prefix *p, struct attr *attr, json_object_object_add(json_net, "appliedStatusSymbols", json_status); char buf_cut[BUFSIZ]; - json_object_object_add( - json_ar, - inet_ntop(p->family, &p->u.prefix, buf_cut, BUFSIZ), - json_net); + + prefix2str(p, buf_cut, PREFIX_STRLEN); + json_object_object_add(json_ar, buf_cut, json_net); } else vty_out(vty, "\n"); } @@ -9158,6 +9197,15 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, lcom)) continue; } + + if (type == bgp_show_type_lcommunity_exact) { + struct lcommunity *lcom = output_arg; + + if (!pi->attr->lcommunity + || !lcommunity_cmp(pi->attr->lcommunity, + lcom)) + continue; + } if (type == bgp_show_type_lcommunity_list) { struct community_list *list = output_arg; @@ -9165,6 +9213,14 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, list)) continue; } + if (type + == bgp_show_type_lcommunity_list_exact) { + struct community_list *list = output_arg; + + if (!lcommunity_list_exact_match( + pi->attr->lcommunity, list)) + continue; + } if (type == bgp_show_type_lcommunity_all) { if (!pi->attr->lcommunity) continue; @@ -9788,8 +9844,8 @@ static int bgp_show_route(struct vty *vty, struct bgp *bgp, const char *ip_str, } static int bgp_show_lcommunity(struct vty *vty, struct bgp *bgp, int argc, - struct cmd_token **argv, afi_t afi, safi_t safi, - bool uj) + struct cmd_token **argv, bool exact, afi_t afi, + safi_t safi, bool uj) { struct lcommunity *lcom; struct buffer *b; @@ -9820,13 +9876,15 @@ static int bgp_show_lcommunity(struct vty *vty, struct bgp *bgp, int argc, return CMD_WARNING; } - return bgp_show(vty, bgp, afi, safi, bgp_show_type_lcommunity, lcom, - uj); + return bgp_show(vty, bgp, afi, safi, + (exact ? bgp_show_type_lcommunity_exact + : bgp_show_type_lcommunity), + lcom, uj); } static int bgp_show_lcommunity_list(struct vty *vty, struct bgp *bgp, - const char *lcom, afi_t afi, safi_t safi, - bool uj) + const char *lcom, bool exact, afi_t afi, + safi_t safi, bool uj) { struct community_list *list; @@ -9838,13 +9896,15 @@ static int bgp_show_lcommunity_list(struct vty *vty, struct bgp *bgp, return CMD_WARNING; } - return bgp_show(vty, bgp, afi, safi, bgp_show_type_lcommunity_list, + return bgp_show(vty, bgp, afi, safi, + (exact ? bgp_show_type_lcommunity_list_exact + : bgp_show_type_lcommunity_list), list, uj); } DEFUN (show_ip_bgp_large_community_list, show_ip_bgp_large_community_list_cmd, - "show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]] large-community-list <(1-500)|WORD> [json]", + "show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]] large-community-list <(1-500)|WORD> [exact-match] [json]", SHOW_STR IP_STR BGP_STR @@ -9854,12 +9914,14 @@ DEFUN (show_ip_bgp_large_community_list, "Display routes matching the large-community-list\n" "large-community-list number\n" "large-community-list name\n" + "Exact match of the large-communities\n" JSON_STR) { char *vrf = NULL; afi_t afi = AFI_IP6; safi_t safi = SAFI_UNICAST; int idx = 0; + bool exact_match = 0; if (argv_find(argv, argc, "ip", &idx)) afi = AFI_IP; @@ -9883,12 +9945,18 @@ DEFUN (show_ip_bgp_large_community_list, } argv_find(argv, argc, "large-community-list", &idx); - return bgp_show_lcommunity_list(vty, bgp, argv[idx + 1]->arg, afi, safi, - uj); + + const char *clist_number_or_name = argv[++idx]->arg; + + if (++idx < argc && strmatch(argv[idx]->text, "exact-match")) + exact_match = 1; + + return bgp_show_lcommunity_list(vty, bgp, clist_number_or_name, + exact_match, afi, safi, uj); } DEFUN (show_ip_bgp_large_community, show_ip_bgp_large_community_cmd, - "show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]] large-community [AA:BB:CC] [json]", + "show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]] large-community [<AA:BB:CC> [exact-match]] [json]", SHOW_STR IP_STR BGP_STR @@ -9897,12 +9965,14 @@ DEFUN (show_ip_bgp_large_community, BGP_SAFI_WITH_LABEL_HELP_STR "Display routes matching the large-communities\n" "List of large-community numbers\n" + "Exact match of the large-communities\n" JSON_STR) { char *vrf = NULL; afi_t afi = AFI_IP6; safi_t safi = SAFI_UNICAST; int idx = 0; + bool exact_match = 0; if (argv_find(argv, argc, "ip", &idx)) afi = AFI_IP; @@ -9925,9 +9995,12 @@ DEFUN (show_ip_bgp_large_community, return CMD_WARNING; } - if (argv_find(argv, argc, "AA:BB:CC", &idx)) - return bgp_show_lcommunity(vty, bgp, argc, argv, afi, safi, uj); - else + if (argv_find(argv, argc, "AA:BB:CC", &idx)) { + if (argv_find(argv, argc, "exact-match", &idx)) + exact_match = 1; + return bgp_show_lcommunity(vty, bgp, argc, argv, + exact_match, afi, safi, uj); + } else return bgp_show(vty, bgp, afi, safi, bgp_show_type_lcommunity_all, NULL, uj); } diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index f715084450..0f2363dc6f 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -45,7 +45,9 @@ enum bgp_show_type { bgp_show_type_community_list_exact, bgp_show_type_lcommunity_all, bgp_show_type_lcommunity, + bgp_show_type_lcommunity_exact, bgp_show_type_lcommunity_list, + bgp_show_type_lcommunity_list_exact, bgp_show_type_flap_statistics, bgp_show_type_flap_neighbor, bgp_show_type_dampend_paths, diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 28a763ed5e..a212523b19 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -1173,8 +1173,17 @@ static route_map_result_t route_match_lcommunity(void *rule, if (!list) return RMAP_NOMATCH; - if (lcommunity_list_match(path->attr->lcommunity, list)) - return RMAP_MATCH; + if (rcom->exact) { + if (lcommunity_list_exact_match( + path->attr->lcommunity, + list)) + return RMAP_MATCH; + } else { + if (lcommunity_list_match( + path->attr->lcommunity, + list)) + return RMAP_MATCH; + } } return RMAP_NOMATCH; } @@ -1193,6 +1202,7 @@ static void *route_match_lcommunity_compile(const char *arg) len = p - arg; rcom->name = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, len + 1); memcpy(rcom->name, arg, len); + rcom->exact = 1; } else { rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); rcom->exact = 0; @@ -3796,26 +3806,45 @@ DEFUN (no_match_community, DEFUN (match_lcommunity, match_lcommunity_cmd, - "match large-community <(1-99)|(100-500)|WORD>", + "match large-community <(1-99)|(100-500)|WORD> [exact-match]", MATCH_STR "Match BGP large community list\n" "Large Community-list number (standard)\n" "Large Community-list number (expanded)\n" - "Large Community-list name\n") + "Large Community-list name\n" + "Do exact matching of communities\n") { - return bgp_route_match_add(vty, "large-community", argv[2]->arg, + int idx_lcomm_list = 2; + int ret; + char *argstr; + + if (argc == 4) { + argstr = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, + strlen(argv[idx_lcomm_list]->arg) + + strlen("exact-match") + 2); + + sprintf(argstr, "%s exact-match", argv[idx_lcomm_list]->arg); + } else + argstr = argv[idx_lcomm_list]->arg; + + ret = bgp_route_match_add(vty, "large-community", argstr, RMAP_EVENT_LLIST_ADDED); + if (argstr != argv[idx_lcomm_list]->arg) + XFREE(MTYPE_ROUTE_MAP_COMPILED, argstr); + + return ret; } DEFUN (no_match_lcommunity, no_match_lcommunity_cmd, - "no match large-community [<(1-99)|(100-500)|WORD>]", + "no match large-community [<(1-99)|(100-500)|WORD> [exact-match]]", NO_STR MATCH_STR "Match BGP large community list\n" "Large Community-list number (standard)\n" "Large Community-list number (expanded)\n" - "Large Community-list name\n") + "Large Community-list name\n" + "Do exact matching of communities\n") { return bgp_route_match_delete(vty, "large-community", NULL, RMAP_EVENT_LLIST_DELETED); diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c index d0be2471af..82df1905ba 100644 --- a/bgpd/bgp_updgrp.c +++ b/bgpd/bgp_updgrp.c @@ -885,6 +885,9 @@ static void update_subgroup_add_peer(struct update_subgroup *subgrp, bpacket_add_peer(pkt, paf); bpacket_queue_sanity_check(SUBGRP_PKTQ(subgrp)); + if (BGP_DEBUG(update_groups, UPDATE_GROUPS)) + zlog_debug("peer %s added to subgroup s%" PRIu64, + paf->peer->host, subgrp->id); } /* @@ -910,6 +913,10 @@ static void update_subgroup_remove_peer_internal(struct update_subgroup *subgrp, paf->subgroup = NULL; subgrp->peer_count--; + if (BGP_DEBUG(update_groups, UPDATE_GROUPS)) + zlog_debug("peer %s deleted from subgroup s%" + PRIu64 "peer cnt %d", + paf->peer->host, subgrp->id, subgrp->peer_count); SUBGRP_INCR_STAT(subgrp, prune_events); } @@ -1826,9 +1833,9 @@ void peer_af_announce_route(struct peer_af *paf, int combine) */ if (!combine || !all_pending) { update_subgroup_split_peer(paf, NULL); - if (!paf->subgroup) - return; + subgrp = paf->subgroup; + assert(subgrp && subgrp->update_group); if (bgp_debug_update(paf->peer, NULL, subgrp->update_group, 0)) zlog_debug("u%" PRIu64 ":s%" PRIu64 " %s announcing routes", diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index ef7cf89450..6e0e079cd8 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -979,10 +979,6 @@ DEFUN_NOSH (router_bgp, ret = bgp_get(&bgp, &as, name, inst_type); switch (ret) { - case BGP_ERR_MULTIPLE_INSTANCE_NOT_SET: - vty_out(vty, - "Please specify 'bgp multiple-instance' first\n"); - return CMD_WARNING_CONFIG_FAILED; case BGP_ERR_AS_MISMATCH: vty_out(vty, "BGP is already running; AS is %u\n", as); return CMD_WARNING_CONFIG_FAILED; @@ -4830,14 +4826,15 @@ static int peer_default_originate_set_vty(struct vty *vty, const char *peer_str, { int ret; struct peer *peer; - struct route_map *route_map; + struct route_map *route_map = NULL; peer = peer_and_group_lookup_vty(vty, peer_str); if (!peer) return CMD_WARNING_CONFIG_FAILED; if (set) { - route_map = route_map_lookup_warn_noexist(vty, rmap); + if (rmap) + route_map = route_map_lookup_warn_noexist(vty, rmap); ret = peer_default_originate_set(peer, afi, safi, rmap, route_map); } else @@ -7731,14 +7728,6 @@ DEFUN (show_bgp_memory, count * sizeof(struct peer_group))); /* Other */ - if ((count = mtype_stats_alloc(MTYPE_HASH))) - vty_out(vty, "%ld hash tables, using %s of memory\n", count, - mtype_memstr(memstrbuf, sizeof(memstrbuf), - count * sizeof(struct hash))); - if ((count = mtype_stats_alloc(MTYPE_HASH_BACKET))) - vty_out(vty, "%ld hash buckets, using %s of memory\n", count, - mtype_memstr(memstrbuf, sizeof(memstrbuf), - count * sizeof(struct hash_bucket))); if ((count = mtype_stats_alloc(MTYPE_BGP_REGEXP))) vty_out(vty, "%ld compiled regexes, using %s of memory\n", count, mtype_memstr(memstrbuf, sizeof(memstrbuf), @@ -12329,7 +12318,7 @@ ALIAS_HIDDEN( DEFUN (no_bgp_redistribute_ipv4_ospf, no_bgp_redistribute_ipv4_ospf_cmd, - "no redistribute <ospf|table> (1-65535) [metric (0-4294967295)] [route-map WORD]", + "no redistribute <ospf|table> (1-65535) [{metric (0-4294967295)|route-map WORD}]", NO_STR "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" @@ -12357,7 +12346,7 @@ DEFUN (no_bgp_redistribute_ipv4_ospf, ALIAS_HIDDEN( no_bgp_redistribute_ipv4_ospf, no_bgp_redistribute_ipv4_ospf_hidden_cmd, - "no redistribute <ospf|table> (1-65535) [metric (0-4294967295)] [route-map WORD]", + "no redistribute <ospf|table> (1-65535) [{metric (0-4294967295)|route-map WORD}]", NO_STR "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" @@ -12370,7 +12359,7 @@ ALIAS_HIDDEN( DEFUN (no_bgp_redistribute_ipv4, no_bgp_redistribute_ipv4_cmd, - "no redistribute " FRR_IP_REDIST_STR_BGPD " [metric (0-4294967295)] [route-map WORD]", + "no redistribute " FRR_IP_REDIST_STR_BGPD " [{metric (0-4294967295)|route-map WORD}]", NO_STR "Redistribute information from another routing protocol\n" FRR_IP_REDIST_HELP_STR_BGPD @@ -12394,7 +12383,7 @@ DEFUN (no_bgp_redistribute_ipv4, ALIAS_HIDDEN( no_bgp_redistribute_ipv4, no_bgp_redistribute_ipv4_hidden_cmd, "no redistribute " FRR_IP_REDIST_STR_BGPD - " [metric (0-4294967295)] [route-map WORD]", + " [{metric (0-4294967295)|route-map WORD}]", NO_STR "Redistribute information from another routing protocol\n" FRR_IP_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" @@ -12553,7 +12542,7 @@ DEFUN (bgp_redistribute_ipv6_metric_rmap, DEFUN (no_bgp_redistribute_ipv6, no_bgp_redistribute_ipv6_cmd, - "no redistribute " FRR_IP6_REDIST_STR_BGPD " [metric (0-4294967295)] [route-map WORD]", + "no redistribute " FRR_IP6_REDIST_STR_BGPD " [{metric (0-4294967295)|route-map WORD}]", NO_STR "Redistribute information from another routing protocol\n" FRR_IP6_REDIST_HELP_STR_BGPD diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index af90e9841a..3ca209676f 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -3183,7 +3183,7 @@ int bgp_get(struct bgp **bgp_val, as_t *as, const char *name, if (bgp->inst_type != inst_type) return BGP_ERR_INSTANCE_MISMATCH; *bgp_val = bgp; - return 0; + return BGP_SUCCESS; } bgp = bgp_create(as, name, inst_type); @@ -3217,7 +3217,7 @@ int bgp_get(struct bgp **bgp_val, as_t *as, const char *name, bgp_zebra_instance_register(bgp); } - return 0; + return BGP_SUCCESS; } /* diff --git a/bgpd/bgpd.conf.sample b/bgpd/bgpd.conf.sample index cb12a92522..1fb4f1600b 100644 --- a/bgpd/bgpd.conf.sample +++ b/bgpd/bgpd.conf.sample @@ -8,7 +8,6 @@ hostname bgpd password zebra !enable password please-set-at-here ! -!bgp multiple-instance ! router bgp 7675 ! bgp router-id 10.0.0.1 diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 088c6411b4..4bce73898f 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -1453,12 +1453,10 @@ enum bgp_clear_type { #define BGP_ERR_INVALID_AS -3 #define BGP_ERR_INVALID_BGP -4 #define BGP_ERR_PEER_GROUP_MEMBER -5 -#define BGP_ERR_MULTIPLE_INSTANCE_USED -6 #define BGP_ERR_PEER_GROUP_NO_REMOTE_AS -7 #define BGP_ERR_PEER_GROUP_CANT_CHANGE -8 #define BGP_ERR_PEER_GROUP_MISMATCH -9 #define BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT -10 -#define BGP_ERR_MULTIPLE_INSTANCE_NOT_SET -11 #define BGP_ERR_AS_MISMATCH -12 #define BGP_ERR_PEER_FLAG_CONFLICT -13 #define BGP_ERR_PEER_GROUP_SHUTDOWN -14 diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c index 583adcda77..87a05a4f8c 100644 --- a/bgpd/rfapi/rfapi_import.c +++ b/bgpd/rfapi/rfapi_import.c @@ -2402,6 +2402,18 @@ static int rfapiWithdrawTimerVPN(struct thread *t) struct rfapi_monitor_vpn *moved; afi_t afi; + if (bgp == NULL) { + vnc_zlog_debug_verbose( + "%s: NULL BGP pointer, assume shutdown race condition!!!", + __func__); + return 0; + } + if (bgp_flag_check(bgp, BGP_FLAG_DELETE_IN_PROGRESS)) { + vnc_zlog_debug_verbose( + "%s: BGP delete in progress, assume shutdown race condition!!!", + __func__); + return 0; + } assert(wcb->node); assert(bpi); assert(wcb->import_table); diff --git a/doc/developer/building-frr-for-fedora.rst b/doc/developer/building-frr-for-fedora.rst index 0208f1146b..0bfd43e93c 100644 --- a/doc/developer/building-frr-for-fedora.rst +++ b/doc/developer/building-frr-for-fedora.rst @@ -98,6 +98,18 @@ And load the kernel modules on the running system: sudo modprobe mpls-router mpls-iptunnel + +.. note:: + Fedora ships with the ``firewalld`` service enabled. You may run into some + issues with the iptables rules it installs by default. If you wish to just + stop the service and clear `ALL` rules do these commands: + + .. code-block:: console + + sudo systemctl disable firewalld.service + sudo systemctl stop firewalld.service + sudo iptables -F + Install service files ^^^^^^^^^^^^^^^^^^^^^ diff --git a/doc/developer/memtypes.rst b/doc/developer/memtypes.rst index 153131bab9..13f6b43bbf 100644 --- a/doc/developer/memtypes.rst +++ b/doc/developer/memtypes.rst @@ -42,6 +42,16 @@ Example: Definition ---------- +.. c:type:: struct memtype + + This is the (internal) type used for MTYPE definitions. The macros below + should be used to create these, but in some cases it is useful to pass a + ``struct memtype *`` pointer to some helper function. + + The ``MTYPE_name`` created by the macros is declared as an array, i.e. + a function taking a ``struct memtype *`` argument can be called with an + ``MTYPE_name`` argument (as opposed to ``&MTYPE_name``.) + .. c:macro:: DECLARE_MGROUP(name) This macro forward-declares a memory group and should be placed in a diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 1831363e19..f2b1328075 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -267,29 +267,6 @@ An example configuration with multiple autonomous systems might look like this: neighbor 10.0.0.6 remote-as 70 ... -In the past this feature done differently and the following commands were -required to enable the functionality. They are now deprecated. - -.. deprecated:: 5.0 - This command is deprecated and may be safely removed from the config. - -.. index:: bgp multiple-instance -.. clicmd:: bgp multiple-instance - - Enable BGP multiple instance feature. Because this is now the default - configuration this command will not be displayed in the running - configuration. - -.. deprecated:: 5.0 - This command is deprecated and may be safely removed from the config. - -.. index:: no bgp multiple-instance -.. clicmd:: no bgp multiple-instance - - In previous versions of FRR, this command disabled the BGP multiple instance - feature. This functionality is automatically turned on when BGP multiple - instances or views exist so this command no longer does anything. - .. seealso:: :ref:`bgp-vrf-route-leaking` .. seealso:: :ref:`zebra-vrf` @@ -688,6 +665,11 @@ Networks Route Aggregation ----------------- +.. _bgp-route-aggregation-ipv4: + +Route Aggregation-IPv4 Address Family +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + .. index:: aggregate-address A.B.C.D/M .. clicmd:: aggregate-address A.B.C.D/M @@ -707,6 +689,62 @@ Route Aggregation .. index:: no aggregate-address A.B.C.D/M .. clicmd:: no aggregate-address A.B.C.D/M + + This command removes an aggregate address. + + + This configuration example setup the aggregate-address under + ipv4 address-family. + + .. code-block:: frr + + router bgp 1 + address-family ipv4 unicast + aggregate-address 10.0.0.0/8 + aggregate-address 20.0.0.0/8 as-set + aggregate-address 40.0.0.0/8 summary-only + exit-address-family + + +.. _bgp-route-aggregation-ipv6: + +Route Aggregation-IPv6 Address Family +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. index:: aggregate-address X:X::X:X/M +.. clicmd:: aggregate-address X:X::X:X/M + + This command specifies an aggregate address. + +.. index:: aggregate-address X:X::X:X/M as-set +.. clicmd:: aggregate-address X:X::X:X/M as-set + + This command specifies an aggregate address. Resulting routes include + AS set. + +.. index:: aggregate-address X:X::X:X/M summary-only +.. clicmd:: aggregate-address X:X::X:X/M summary-only + + This command specifies an aggregate address. Aggregated routes will + not be announce. + +.. index:: no aggregate-address X:X::X:X/M +.. clicmd:: no aggregate-address X:X::X:X/M + + This command removes an aggregate address. + + + This configuration example setup the aggregate-address under + ipv4 address-family. + + .. code-block:: frr + + router bgp 1 + address-family ipv6 unicast + aggregate-address 10::0/64 + aggregate-address 20::0/64 as-set + aggregate-address 40::0/64 summary-only + exit-address-family .. _bgp-redistribute-to-bgp: @@ -1736,13 +1774,15 @@ Two types of large community lists are supported, namely `standard` and Large Communities in Route Map """""""""""""""""""""""""""""" -.. index:: match large-community LINE -.. clicmd:: match large-community LINE +.. index:: match large-community LINE [exact-match] +.. clicmd:: match large-community LINE [exact-match] Where `line` can be a simple string to match, or a regular expression. It is very important to note that this match occurs on the entire large-community string as a whole, where each large-community is ordered - from lowest to highest. + from lowest to highest. When `exact-match` keyword is specified, match + happen only when BGP updates have completely same large communities value + specified in the large community list. .. index:: set large-community LARGE-COMMUNITY .. clicmd:: set large-community LARGE-COMMUNITY @@ -2235,8 +2275,49 @@ attribute. match the specified community list. When `exact-match` is specified, it displays only routes that have an exact match. +.. _bgp-display-routes-by-lcommunity: + +Displaying Routes by Large Community Attribute +---------------------------------------------- + +The following commands allow displaying routes based on their +large community attribute. + +.. index:: show [ip] bgp <ipv4|ipv6> large-community +.. clicmd:: show [ip] bgp <ipv4|ipv6> large-community + +.. index:: show [ip] bgp <ipv4|ipv6> large-community LARGE-COMMUNITY +.. clicmd:: show [ip] bgp <ipv4|ipv6> large-community LARGE-COMMUNITY + +.. index:: show [ip] bgp <ipv4|ipv6> large-community LARGE-COMMUNITY exact-match +.. clicmd:: show [ip] bgp <ipv4|ipv6> large-community LARGE-COMMUNITY exact-match + +.. index:: show [ip] bgp <ipv4|ipv6> large-community LARGE-COMMUNITY json +.. clicmd:: show [ip] bgp <ipv4|ipv6> large-community LARGE-COMMUNITY json + + These commands display BGP routes which have the large community attribute. + attribute. When ``LARGE-COMMUNITY`` is specified, BGP routes that match that + large community are displayed. When `exact-match` is specified, it display + only routes that have an exact match. When `json` is specified, it display + routes in json format. + +.. index:: show [ip] bgp <ipv4|ipv6> large-community-list WORD +.. clicmd:: show [ip] bgp <ipv4|ipv6> large-community-list WORD + +.. index:: show [ip] bgp <ipv4|ipv6> large-community-list WORD exact-match +.. clicmd:: show [ip] bgp <ipv4|ipv6> large-community-list WORD exact-match + +.. index:: show [ip] bgp <ipv4|ipv6> large-community-list WORD json +.. clicmd:: show [ip] bgp <ipv4|ipv6> large-community-list WORD json + + These commands display BGP routes for the address family specified that + match the specified large community list. When `exact-match` is specified, + it displays only routes that have an exact match. When `json` is specified, + it display routes in json format. + .. _bgp-display-routes-by-as-path: + Displaying Routes by AS Path ---------------------------- @@ -2302,7 +2383,6 @@ different filter for a peer. .. code-block:: frr - bgp multiple-instance ! router bgp 1 view 1 neighbor 10.0.0.1 remote-as 2 diff --git a/doc/user/filter.rst b/doc/user/filter.rst index 9d7361443d..8c86d06087 100644 --- a/doc/user/filter.rst +++ b/doc/user/filter.rst @@ -165,14 +165,8 @@ Showing ip prefix-list Clear counter of ip prefix-list ------------------------------- -.. index:: clear ip prefix-list -.. clicmd:: clear ip prefix-list +.. index:: clear ip prefix-list [NAME [A.B.C.D/M]] +.. clicmd:: clear ip prefix-list [NAME [A.B.C.D/M]] Clears the counters of all IP prefix lists. Clear IP Prefix List can be used - with a specified name and prefix. - -.. index:: clear ip prefix-list NAME -.. clicmd:: clear ip prefix-list NAME - -.. index:: clear ip prefix-list NAME A.B.C.D/M -.. clicmd:: clear ip prefix-list NAME A.B.C.D/M + with a specified NAME or NAME and prefix. diff --git a/doc/user/pim.rst b/doc/user/pim.rst index e8c74f7b87..805d6264a8 100644 --- a/doc/user/pim.rst +++ b/doc/user/pim.rst @@ -151,6 +151,12 @@ Certain signals have special meanings to *pimd*. urib-only Lookup in the Unicast Rib only. +.. index:: ip igmp generate-query-once [version (2-3)] +.. clicmd:: ip igmp generate-query-once [version (2-3)] + + Generate IGMP query (v2/v3) on user requirement. This will not depend on + the existing IGMP general query timer.If no version is provided in the cli, + it will be considered as default v2 query.This is a hidden command. .. _pim-interface-configuration: diff --git a/doc/user/routemap.rst b/doc/user/routemap.rst index ef9ebe8ddc..bac61cbc58 100644 --- a/doc/user/routemap.rst +++ b/doc/user/routemap.rst @@ -85,6 +85,23 @@ deny cont goto next route-map entry +.. _route-map-show-command: + +.. index:: show route-map [WORD] +.. clicmd:: show route-map [WORD] + + Display data about each daemons knowledge of individual route-maps. + If WORD is supplied narrow choice to that particular route-map. + +.. _route-map-clear-counter-command: + +.. index:: clear route-map counter [WORD] +.. clicmd:: clear route-map counter [WORD] + + Clear counters that are being stored about the route-map utilization + so that subsuquent show commands will indicate since the last clear. + If WORD is specified clear just that particular route-map's counters. + .. _route-map-command: Route Map Command @@ -315,6 +332,7 @@ Route Map Exit Action Command Proceed processing the route-map at the first entry whose order is >= N + Route Map Examples ================== diff --git a/doc/user/routeserver.rst b/doc/user/routeserver.rst index e677a3030d..474a68db25 100644 --- a/doc/user/routeserver.rst +++ b/doc/user/routeserver.rst @@ -369,8 +369,6 @@ the policies for client RA): hostname RS password ix ! - bgp multiple-instance - ! router bgp 65000 view RS no bgp default ipv4-unicast neighbor 2001:0DB8::A remote-as 65001 diff --git a/doc/user/vnc.rst b/doc/user/vnc.rst index d0934fe6fa..cb9c74ceea 100644 --- a/doc/user/vnc.rst +++ b/doc/user/vnc.rst @@ -468,8 +468,8 @@ redistributed to VNC as bgp-direct-to-nve-groups routes. These routes are NOT announced via BGP, but they are made available for local RFP lookup in response to queries from NVEs. -A non-main/default BGP instance is configured using the `bgp multiple-instance` -and `router bgp AS view NAME` commands as described elsewhere in this document. +A non-main/default BGP instance is configured using the +`router bgp AS view NAME` command as described elsewhere in this document. In order for a route in the unicast BGP RIB to be made available to a querying NVE, there must already be, available to that NVE, an (interior) VNC route diff --git a/docker/debian/Dockerfile b/docker/debian/Dockerfile index fde29d4911..6ffdd0ccb3 100644 --- a/docker/debian/Dockerfile +++ b/docker/debian/Dockerfile @@ -9,6 +9,5 @@ RUN curl -s https://deb.frrouting.org/frr/keys.asc | apt-key add - RUN echo deb https://deb.frrouting.org/frr $(lsb_release -s -c) frr-stable | tee -a /etc/apt/sources.list.d/frr.list RUN apt-get update RUN apt-get install -y frr frr-pythontools -ADD daemons /etc/frr/daemons ADD docker-start /usr/sbin/docker-start ENTRYPOINT ["/usr/sbin/docker-start"] diff --git a/docker/debian/README.md b/docker/debian/README.md index b10d696a78..3c1209bc97 100644 --- a/docker/debian/README.md +++ b/docker/debian/README.md @@ -1,14 +1,17 @@ -# Debian9 Docker -This is a binary docker container build of debian9. +# Debian 10 Docker + +This is a binary docker container build of Debian 10 (buster) with FRR. # Build + ``` -docker build --rm -t frr:6.0.2 . +docker build -t frr-debian:latest . ``` # Running + ``` -docker run -itd --privileged --name frr frr:latest +docker run -itd --privileged --name frr frr-debian:latest ``` vtysh diff --git a/docker/debian/daemons b/docker/debian/daemons deleted file mode 100644 index ed4d98e1f8..0000000000 --- a/docker/debian/daemons +++ /dev/null @@ -1,65 +0,0 @@ -# This file tells the frr package which daemons to start. -# -# Sample configurations for these daemons can be found in -# /usr/share/doc/frr/examples/. -# -# ATTENTION: -# -# When activation a daemon at the first time, a config file, even if it is -# empty, has to be present *and* be owned by the user and group "frr", else -# the daemon will not be started by /etc/init.d/frr. The permissions should -# be u=rw,g=r,o=. -# When using "vtysh" such a config file is also needed. It should be owned by -# group "frrvty" and set to ug=rw,o= though. Check /etc/pam.d/frr, too. -# -# The watchfrr and zebra daemons are always started. -# -bgpd=yes -ospfd=no -ospf6d=no -ripd=no -ripngd=no -isisd=no -pimd=no -ldpd=no -nhrpd=no -eigrpd=no -babeld=no -sharpd=no -pbrd=no -bfdd=no -fabricd=no - -# -# If this option is set the /etc/init.d/frr script automatically loads -# the config via "vtysh -b" when the servers are started. -# Check /etc/pam.d/frr if you intend to use "vtysh"! -# -vtysh_enable=yes -zebra_options=" -A 127.0.0.1 -s 90000000" -bgpd_options=" -A 127.0.0.1" -ospfd_options=" -A 127.0.0.1" -ospf6d_options=" -A ::1" -ripd_options=" -A 127.0.0.1" -ripngd_options=" -A ::1" -isisd_options=" -A 127.0.0.1" -pimd_options=" -A 127.0.0.1" -ldpd_options=" -A 127.0.0.1" -nhrpd_options=" -A 127.0.0.1" -eigrpd_options=" -A 127.0.0.1" -babeld_options=" -A 127.0.0.1" -sharpd_options=" -A 127.0.0.1" -pbrd_options=" -A 127.0.0.1" -staticd_options="-A 127.0.0.1" -bfdd_options=" -A 127.0.0.1" -fabricd_options="-A 127.0.0.1" - -# The list of daemons to watch is automatically generated by the init script. -watchfrr_options="-r '/usr/lib/frr/watchfrr.sh restart %s' -s '/usr/lib/frr/watchfrr.sh start %s' -k '/usr/lib/frr/watchfrr.sh stop %s'" - -# for debugging purposes, you can specify a "wrap" command to start instead -# of starting the daemon directly, e.g. to use valgrind on ospfd: -# ospfd_wrap="/usr/bin/valgrind" -# or you can use "all_wrap" for all daemons, e.g. to use perf record: -# all_wrap="/usr/bin/perf record --call-graph -" -# the normal daemon command is added to this at the end. diff --git a/lib/command.c b/lib/command.c index 0e16f30a8a..f257c7d0f9 100644 --- a/lib/command.c +++ b/lib/command.c @@ -48,7 +48,7 @@ #include "lib_errors.h" #include "northbound_cli.h" -DEFINE_MTYPE(LIB, HOST, "Host config") +DEFINE_MTYPE_STATIC(LIB, HOST, "Host config") DEFINE_MTYPE(LIB, COMPLETION, "Completion item") #define item(x) \ @@ -84,6 +84,7 @@ const char *node_names[] = { "vrf debug", // VRF_DEBUG_NODE, "northbound debug", // NORTHBOUND_DEBUG_NODE, "vnc debug", // DEBUG_VNC_NODE, + "route-map debug", /* RMAP_DEBUG_NODE */ "aaa", // AAA_NODE, "keychain", // KEYCHAIN_NODE, "keychain key", // KEYCHAIN_KEY_NODE, diff --git a/lib/command.h b/lib/command.h index d6c41e0824..fd8b56d62e 100644 --- a/lib/command.h +++ b/lib/command.h @@ -34,7 +34,6 @@ extern "C" { #endif -DECLARE_MTYPE(HOST) DECLARE_MTYPE(COMPLETION) /* @@ -94,6 +93,7 @@ enum node_type { VRF_DEBUG_NODE, /* Vrf Debug node. */ NORTHBOUND_DEBUG_NODE, /* Northbound Debug node. */ DEBUG_VNC_NODE, /* Debug VNC node. */ + RMAP_DEBUG_NODE, /* Route-map debug node */ AAA_NODE, /* AAA node. */ KEYCHAIN_NODE, /* Key-chain node. */ KEYCHAIN_KEY_NODE, /* Key-chain key node. */ diff --git a/lib/command_parse.y b/lib/command_parse.y index 1b304a98b2..062a4bb30c 100644 --- a/lib/command_parse.y +++ b/lib/command_parse.y @@ -46,6 +46,7 @@ %code requires { #include "config.h" + #include <stdbool.h> #include <stdlib.h> #include <string.h> #include <ctype.h> @@ -140,6 +141,8 @@ static void cleanup (struct parser_ctx *ctx); + static void loopcheck(struct parser_ctx *ctx, struct subgraph *sg); + #define scanner ctx->scanner } @@ -335,6 +338,7 @@ selector: '{' selector_seq_seq '}' varname_token * just use [{a|b}] if neccessary, that will work perfectly fine, and reason * #1 is good enough to keep it this way. */ + loopcheck(ctx, &$$); cmd_token_varname_set ($2.end->data, $4); XFREE (MTYPE_LEX, $4); }; @@ -396,6 +400,38 @@ cmd_graph_parse (struct graph *graph, struct cmd_element *cmd) /* parser helper functions */ +static bool loopcheck_inner(struct graph_node *start, struct graph_node *node, + struct graph_node *end, size_t depth) +{ + size_t i; + bool ret; + + /* safety check */ + if (depth++ == 64) + return true; + + for (i = 0; i < vector_active(node->to); i++) { + struct graph_node *next = vector_slot(node->to, i); + struct cmd_token *tok = next->data; + + if (next == end || next == start) + return true; + if (tok->type < SPECIAL_TKN) + continue; + ret = loopcheck_inner(start, next, end, depth); + if (ret) + return true; + } + return false; +} + +static void loopcheck(struct parser_ctx *ctx, struct subgraph *sg) +{ + if (loopcheck_inner(sg->start, sg->start, sg->end, 0)) + zlog_err("FATAL: '%s': {} contains an empty path! Use [{...}]", + ctx->el->string); +} + void yyerror (CMD_YYLTYPE *loc, struct parser_ctx *ctx, char const *msg) { diff --git a/lib/frr_pthread.c b/lib/frr_pthread.c index 2a18e5cfc6..e588571c01 100644 --- a/lib/frr_pthread.c +++ b/lib/frr_pthread.c @@ -28,8 +28,8 @@ #include "memory.h" #include "linklist.h" -DEFINE_MTYPE(LIB, FRR_PTHREAD, "FRR POSIX Thread"); -DEFINE_MTYPE(LIB, PTHREAD_PRIM, "POSIX synchronization primitives"); +DEFINE_MTYPE_STATIC(LIB, FRR_PTHREAD, "FRR POSIX Thread") +DEFINE_MTYPE_STATIC(LIB, PTHREAD_PRIM, "POSIX sync primitives") /* default frr_pthread start/stop routine prototypes */ static void *fpt_run(void *arg); diff --git a/lib/frr_pthread.h b/lib/frr_pthread.h index 9bc7b94033..3afe7ba966 100644 --- a/lib/frr_pthread.h +++ b/lib/frr_pthread.h @@ -29,9 +29,6 @@ extern "C" { #endif -DECLARE_MTYPE(FRR_PTHREAD); -DECLARE_MTYPE(PTHREAD_PRIM); - #define OS_THREAD_NAMELEN 16 struct frr_pthread; diff --git a/lib/hash.c b/lib/hash.c index fad7de5138..9d9d39702e 100644 --- a/lib/hash.c +++ b/lib/hash.c @@ -29,8 +29,8 @@ #include "command.h" #include "libfrr.h" -DEFINE_MTYPE(LIB, HASH, "Hash") -DEFINE_MTYPE(LIB, HASH_BACKET, "Hash Bucket") +DEFINE_MTYPE_STATIC(LIB, HASH, "Hash") +DEFINE_MTYPE_STATIC(LIB, HASH_BACKET, "Hash Bucket") DEFINE_MTYPE_STATIC(LIB, HASH_INDEX, "Hash Index") static pthread_mutex_t _hashes_mtx = PTHREAD_MUTEX_INITIALIZER; diff --git a/lib/hash.h b/lib/hash.h index c56a98d50c..7b3372d433 100644 --- a/lib/hash.h +++ b/lib/hash.h @@ -28,9 +28,6 @@ extern "C" { #endif -DECLARE_MTYPE(HASH) -DECLARE_MTYPE(HASH_BACKET) - /* Default hash table size. */ #define HASH_INITIAL_SIZE 256 /* Expansion threshold */ @@ -39,7 +39,7 @@ #include "lib/if_clippy.c" #endif -DEFINE_MTYPE(LIB, IF, "Interface") +DEFINE_MTYPE_STATIC(LIB, IF, "Interface") DEFINE_MTYPE_STATIC(LIB, CONNECTED, "Connected") DEFINE_MTYPE_STATIC(LIB, NBR_CONNECTED, "Neighbor Connected") DEFINE_MTYPE(LIB, CONNECTED_LABEL, "Connected interface label") @@ -31,7 +31,6 @@ extern "C" { #endif -DECLARE_MTYPE(IF) DECLARE_MTYPE(CONNECTED_LABEL) /* Interface link-layer type, if known. Derived from: diff --git a/lib/memory.h b/lib/memory.h index 0002ea3349..14cd76f2f5 100644 --- a/lib/memory.h +++ b/lib/memory.h @@ -102,9 +102,14 @@ struct memgroup { } +/* the array is a trick to make the "MTYPE_FOO" name work as a pointer without + * putting a & in front of it, so we can do "XMALLOC(MTYPE_FOO, ...)" instead + * of "XMALLOC(&MTYPE_FOO, ...)". + */ #define DECLARE_MTYPE(name) \ extern struct memtype _mt_##name; \ - static struct memtype *const MTYPE_##name = &_mt_##name; + extern struct memtype MTYPE_##name[1]; \ + /* end */ #define DEFINE_MTYPE_ATTR(group, mname, attr, desc) \ attr struct memtype _mt_##mname \ @@ -130,12 +135,21 @@ struct memgroup { if (_mt_##mname.next) \ _mt_##mname.next->ref = _mt_##mname.ref; \ *_mt_##mname.ref = _mt_##mname.next; \ - } - -#define DEFINE_MTYPE(group, name, desc) DEFINE_MTYPE_ATTR(group, name, , desc) + } \ + /* end */ + +/* can't quite get gcc to emit the alias correctly, so asm-alias it is :/ */ +#define DEFINE_MTYPE(group, name, desc) \ + DEFINE_MTYPE_ATTR(group, name, , desc) \ + __asm__(".equiv MTYPE_" #name ", _mt_" #name "\n\t" \ + ".global MTYPE_" #name "\n"); \ + /* end */ +/* and this one's borked on clang, it drops static on aliases :/, so... asm */ #define DEFINE_MTYPE_STATIC(group, name, desc) \ DEFINE_MTYPE_ATTR(group, name, static, desc) \ - static struct memtype *const MTYPE_##name = &_mt_##name; + extern struct memtype MTYPE_##name[1]; \ + __asm__(".equiv MTYPE_" #name ", _mt_" #name "\n"); \ + /* end */ DECLARE_MGROUP(LIB) DECLARE_MTYPE(TMP) diff --git a/lib/plist.c b/lib/plist.c index 54ea742c66..1ba8982499 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -750,6 +750,7 @@ enum prefix_list_type prefix_list_apply_which_prefix( if (pbest == NULL) return PREFIX_DENY; + pbest->hitcnt++; return pbest->type; } diff --git a/lib/routemap.c b/lib/routemap.c index 9336154b1a..2fee3a479e 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -112,14 +112,14 @@ struct route_map_match_set_hooks { const char *arg, route_map_event_t type); - /* match ip next hop type */ + /* match ip next-hop type */ int (*match_ip_next_hop_type)(struct vty *vty, struct route_map_index *index, const char *command, const char *arg, route_map_event_t type); - /* no match ip next hop type */ + /* no match ip next-hop type */ int (*no_match_ip_next_hop_type)(struct vty *vty, struct route_map_index *index, const char *command, @@ -160,7 +160,7 @@ struct route_map_match_set_hooks { const char *arg, route_map_event_t type); - /* no match ipv6next-hop type */ + /* no match ipv6 next-hop type */ int (*no_match_ipv6_next_hop_type)(struct vty *vty, struct route_map_index *index, const char *command, const char *arg, @@ -303,7 +303,7 @@ void route_map_no_match_ip_next_hop_prefix_list_hook(int (*func)( rmap_match_set_hook.no_match_ip_next_hop_prefix_list = func; } -/* match ip next hop type */ +/* match ip next-hop type */ void route_map_match_ip_next_hop_type_hook(int (*func)( struct vty *vty, struct route_map_index *index, const char *command, const char *arg, route_map_event_t type)) @@ -311,7 +311,7 @@ void route_map_match_ip_next_hop_type_hook(int (*func)( rmap_match_set_hook.match_ip_next_hop_type = func; } -/* no match ip next hop type */ +/* no match ip next-hop type */ void route_map_no_match_ip_next_hop_type_hook(int (*func)( struct vty *vty, struct route_map_index *index, const char *command, const char *arg, route_map_event_t type)) @@ -688,7 +688,7 @@ static unsigned int route_map_dep_hash_make_key(const void *p); static void route_map_clear_all_references(char *rmap_name); static void route_map_rule_delete(struct route_map_rule_list *, struct route_map_rule *); -static int rmap_debug = 0; +static bool rmap_debug; static void route_map_index_delete(struct route_map_index *, int); @@ -739,6 +739,9 @@ static struct route_map *route_map_add(const char *name) (*route_map_master.add_hook)(name); route_map_notify_dependencies(name, RMAP_EVENT_CALL_ADDED); } + + if (rmap_debug) + zlog_debug("Add route-map %s", name); return map; } @@ -757,6 +760,9 @@ static void route_map_free_map(struct route_map *map) while ((index = map->head) != NULL) route_map_index_delete(index, 0); + if (rmap_debug) + zlog_debug("Deleting route-map %s", map->name); + list = &route_map_master; QOBJ_UNREG(map); @@ -921,6 +927,24 @@ static const char *route_map_type_str(enum route_map_type type) return ""; } +static const char *route_map_result_str(route_map_result_t res) +{ + switch (res) { + case RMAP_MATCH: + return "match"; + case RMAP_DENYMATCH: + return "deny"; + case RMAP_NOMATCH: + return "no match"; + case RMAP_ERROR: + return "error"; + case RMAP_OKAY: + return "okay"; + } + + return "invalid"; +} + static int route_map_empty(struct route_map *map) { if (map->head == NULL && map->tail == NULL) @@ -936,12 +960,12 @@ static void vty_show_route_map_entry(struct vty *vty, struct route_map *map) struct route_map_rule *rule; vty_out(vty, "route-map: %s Invoked: %" PRIu64 "\n", - map->name, map->applied); + map->name, map->applied - map->applied_clear); for (index = map->head; index; index = index->next) { vty_out(vty, " %s, sequence %d Invoked %" PRIu64 "\n", route_map_type_str(index->type), index->pref, - index->applied); + index->applied - index->applied_clear); /* Description */ if (index->description) @@ -1066,6 +1090,10 @@ static void route_map_index_delete(struct route_map_index *index, int notify) QOBJ_UNREG(index); + if (rmap_debug) + zlog_debug("Deleting route-map %s sequence %d", + index->map->name, index->pref); + /* Free route match. */ while ((rule = index->match_list.head) != NULL) route_map_rule_delete(&index->match_list, rule); @@ -1152,6 +1180,11 @@ route_map_index_add(struct route_map *map, enum route_map_type type, int pref) (*route_map_master.event_hook)(map->name); route_map_notify_dependencies(map->name, RMAP_EVENT_CALL_ADDED); } + + if (rmap_debug) + zlog_debug("Route-map %s add sequence %d, type: %s", + map->name, pref, route_map_type_str(type)); + return index; } @@ -1612,6 +1645,7 @@ route_map_result_t route_map_apply(struct route_map *map, int ret = 0; struct route_map_index *index; struct route_map_rule *set; + char buf[PREFIX_STRLEN]; if (recursion > RMAP_RECURSION_LIMIT) { flog_warn( @@ -1622,8 +1656,10 @@ route_map_result_t route_map_apply(struct route_map *map, return RMAP_DENYMATCH; } - if (map == NULL) - return RMAP_DENYMATCH; + if (map == NULL) { + ret = RMAP_DENYMATCH; + goto route_map_apply_end; + } map->applied++; for (index = map->head; index; index = index->next) { @@ -1632,6 +1668,13 @@ route_map_result_t route_map_apply(struct route_map *map, ret = route_map_apply_match(&index->match_list, prefix, type, object); + if (rmap_debug) { + zlog_debug("Route-map: %s, sequence: %d, prefix: %s, result: %s", + map->name, index->pref, + prefix2str(prefix, buf, sizeof(buf)), + route_map_result_str(ret)); + } + /* Now we apply the matrix from above */ if (ret == RMAP_NOMATCH) /* 'cont' from matrix - continue to next route-map @@ -1666,12 +1709,12 @@ route_map_result_t route_map_apply(struct route_map *map, /* If nextrm returned 'deny', finish. */ if (ret == RMAP_DENYMATCH) - return ret; + goto route_map_apply_end; } switch (index->exitpolicy) { case RMAP_EXIT: - return ret; + goto route_map_apply_end; case RMAP_NEXT: continue; case RMAP_GOTO: { @@ -1686,19 +1729,30 @@ route_map_result_t route_map_apply(struct route_map *map, } if (next == NULL) { /* No clauses match! */ - return ret; + goto route_map_apply_end; } } } } else if (index->type == RMAP_DENY) /* 'deny' */ { - return RMAP_DENYMATCH; + ret = RMAP_DENYMATCH; + goto route_map_apply_end; } } } /* Finally route-map does not match at all. */ - return RMAP_DENYMATCH; + ret = RMAP_DENYMATCH; + +route_map_apply_end: + if (rmap_debug) { + zlog_debug("Route-map: %s, prefix: %s, result: %s", + (map ? map->name : "null"), + prefix2str(prefix, buf, sizeof(buf)), + route_map_result_str(ret)); + } + + return (ret); } void route_map_add_hook(void (*func)(const char *)) @@ -1835,8 +1889,8 @@ static int route_map_dep_update(struct hash *dephash, const char *dep_name, case RMAP_EVENT_CALL_ADDED: case RMAP_EVENT_FILTER_ADDED: if (rmap_debug) - zlog_debug("%s: Adding dependency for %s in %s", - __FUNCTION__, dep_name, rmap_name); + zlog_debug("Adding dependency for filter %s in route-map %s", + dep_name, rmap_name); dep = (struct route_map_dep *)hash_get( dephash, dname, route_map_dep_hash_alloc); if (!dep) { @@ -1864,8 +1918,8 @@ static int route_map_dep_update(struct hash *dephash, const char *dep_name, case RMAP_EVENT_CALL_DELETED: case RMAP_EVENT_FILTER_DELETED: if (rmap_debug) - zlog_debug("%s: Deleting dependency for %s in %s", - __FUNCTION__, dep_name, rmap_name); + zlog_debug("Deleting dependency for filter %s in route-map %s", + dep_name, rmap_name); dep = (struct route_map_dep *)hash_get(dephash, dname, NULL); if (!dep) { goto out; @@ -1979,8 +2033,7 @@ static void route_map_process_dependency(struct hash_bucket *bucket, void *data) rmap_name = dep_data->rname; if (rmap_debug) - zlog_debug("%s: Notifying %s of dependency", - __FUNCTION__, rmap_name); + zlog_debug("Notifying %s of dependency", rmap_name); if (route_map_master.event_hook) (*route_map_master.event_hook)(rmap_name); } @@ -2027,6 +2080,8 @@ void route_map_notify_dependencies(const char *affected_name, if (!dep->this_hash) dep->this_hash = upd8_hash; + if (rmap_debug) + zlog_debug("Filter %s updated", dep->dep_name); hash_iterate(dep->dep_rmap_hash, route_map_process_dependency, (void *)event); } @@ -2379,7 +2434,7 @@ DEFUN (no_match_ipv6_address_prefix_list, DEFUN(match_ipv6_next_hop_type, match_ipv6_next_hop_type_cmd, "match ipv6 next-hop type <blackhole>", MATCH_STR IPV6_STR - "Match address of route\n" + "Match next-hop address of route\n" "Match entries by type\n" "Blackhole\n") { @@ -2901,6 +2956,46 @@ DEFUN (no_rmap_continue, return no_rmap_onmatch_goto(self, vty, argc, argv); } +static void clear_route_map_helper(struct route_map *map) +{ + struct route_map_index *index; + + map->applied_clear = map->applied; + for (index = map->head; index; index = index->next) + index->applied_clear = index->applied; +} + +DEFUN (rmap_clear_counters, + rmap_clear_counters_cmd, + "clear route-map counters [WORD]", + CLEAR_STR + "route-map information\n" + "counters associated with the specified route-map\n" + "route-map name\n") +{ + int idx_word = 2; + struct route_map *map; + + const char *name = (argc == 3 ) ? argv[idx_word]->arg : NULL; + + if (name) { + map = route_map_lookup_by_name(name); + + if (map) + clear_route_map_helper(map); + else { + vty_out(vty, "%s: 'route-map %s' not found\n", + frr_protonameinst, name); + return CMD_SUCCESS; + } + } else { + for (map = route_map_master.head; map; map = map->next) + clear_route_map_helper(map); + } + + return CMD_SUCCESS; + +} DEFUN (rmap_show_name, rmap_show_name_cmd, @@ -3006,6 +3101,30 @@ DEFUN (no_rmap_description, return CMD_SUCCESS; } +DEFUN (debug_rmap, + debug_rmap_cmd, + "debug route-map", + DEBUG_STR + "Debug option set for route-maps\n") +{ + rmap_debug = true; + return CMD_SUCCESS; +} + +DEFUN (no_debug_rmap, + no_debug_rmap_cmd, + "no debug route-map", + NO_STR + DEBUG_STR + "Debug option set for route-maps\n") +{ + rmap_debug = false; + return CMD_SUCCESS; +} + +/* Debug node. */ +static struct cmd_node rmap_debug_node = {RMAP_DEBUG_NODE, "", 1}; + /* Configuration write function. */ static int route_map_config_write(struct vty *vty) { @@ -3014,8 +3133,15 @@ static int route_map_config_write(struct vty *vty) struct route_map_rule *rule; int first = 1; int write = 0; + struct listnode *ln; + struct list *maplist = list_new(); for (map = route_map_master.head; map; map = map->next) + listnode_add(maplist, map); + + list_sort(maplist, sort_route_map); + + for (ALL_LIST_ELEMENTS_RO(maplist, ln, map)) for (index = map->head; index; index = index->next) { if (!first) vty_out(vty, "!\n"); @@ -3048,6 +3174,20 @@ static int route_map_config_write(struct vty *vty) write++; } + + list_delete(&maplist); + return write; +} + +static int rmap_config_write_debug(struct vty *vty) +{ + int write = 0; + + if (rmap_debug) { + vty_out(vty, "debug route-map\n"); + write++; + } + return write; } @@ -3164,15 +3304,22 @@ void route_map_init(void) cmd_variable_handler_register(rmap_var_handlers); + rmap_debug = false; + /* Install route map top node. */ install_node(&rmap_node, route_map_config_write); + install_node(&rmap_debug_node, rmap_config_write_debug); + /* Install route map commands. */ install_default(RMAP_NODE); install_element(CONFIG_NODE, &route_map_cmd); install_element(CONFIG_NODE, &no_route_map_cmd); install_element(CONFIG_NODE, &no_route_map_all_cmd); + install_element(CONFIG_NODE, &debug_rmap_cmd); + install_element(CONFIG_NODE, &no_debug_rmap_cmd); + /* Install the on-match stuff */ install_element(RMAP_NODE, &route_map_cmd); install_element(RMAP_NODE, &rmap_onmatch_next_cmd); @@ -3193,9 +3340,14 @@ void route_map_init(void) install_element(RMAP_NODE, &no_rmap_description_cmd); /* Install show command */ + install_element(ENABLE_NODE, &rmap_clear_counters_cmd); + install_element(ENABLE_NODE, &rmap_show_name_cmd); install_element(ENABLE_NODE, &rmap_show_unused_cmd); + install_element(ENABLE_NODE, &debug_rmap_cmd); + install_element(ENABLE_NODE, &no_debug_rmap_cmd); + install_element(RMAP_NODE, &match_interface_cmd); install_element(RMAP_NODE, &no_match_interface_cmd); diff --git a/lib/routemap.h b/lib/routemap.h index 3781d227df..90df1048ed 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -153,6 +153,7 @@ struct route_map_index { /* Keep track how many times we've try to apply */ uint64_t applied; + uint64_t applied_clear; QOBJ_FIELDS }; @@ -177,6 +178,7 @@ struct route_map { /* How many times have we applied this route-map */ uint64_t applied; + uint64_t applied_clear; /* Counter to track active usage of this route-map */ uint16_t use_count; diff --git a/lib/table.c b/lib/table.c index 728615c776..1a89a95f4f 100644 --- a/lib/table.c +++ b/lib/table.c @@ -28,7 +28,7 @@ #include "memory.h" #include "sockunion.h" -DEFINE_MTYPE(LIB, ROUTE_TABLE, "Route table") +DEFINE_MTYPE_STATIC(LIB, ROUTE_TABLE, "Route table") DEFINE_MTYPE(LIB, ROUTE_NODE, "Route node") static void route_table_free(struct route_table *); diff --git a/lib/table.h b/lib/table.h index eefd992546..57b65ac4ba 100644 --- a/lib/table.h +++ b/lib/table.h @@ -31,7 +31,6 @@ extern "C" { #endif -DECLARE_MTYPE(ROUTE_TABLE) DECLARE_MTYPE(ROUTE_NODE) /* @@ -1335,7 +1335,6 @@ static int vty_read(struct thread *thread) int vty_sock = THREAD_FD(thread); struct vty *vty = THREAD_ARG(thread); - vty->t_read = NULL; /* Read raw data from socket */ if ((nbytes = read(vty->fd, buf, VTY_READ_BUFSIZ)) <= 0) { @@ -1529,13 +1528,9 @@ static int vty_flush(struct thread *thread) int vty_sock = THREAD_FD(thread); struct vty *vty = THREAD_ARG(thread); - vty->t_write = NULL; - /* Tempolary disable read thread. */ - if ((vty->lines == 0) && vty->t_read) { - thread_cancel(vty->t_read); - vty->t_read = NULL; - } + if (vty->lines == 0) + THREAD_OFF(vty->t_read); /* Function execution continue. */ erase = ((vty->status == VTY_MORE || vty->status == VTY_MORELINE)); @@ -1713,12 +1708,9 @@ void vty_stdio_suspend(void) if (!stdio_vty) return; - if (stdio_vty->t_write) - thread_cancel(stdio_vty->t_write); - if (stdio_vty->t_read) - thread_cancel(stdio_vty->t_read); - if (stdio_vty->t_timeout) - thread_cancel(stdio_vty->t_timeout); + THREAD_OFF(stdio_vty->t_write); + THREAD_OFF(stdio_vty->t_read); + THREAD_OFF(stdio_vty->t_timeout); if (stdio_termios) tcsetattr(0, TCSANOW, &stdio_orig_termios); @@ -2077,7 +2069,6 @@ static int vtysh_read(struct thread *thread) sock = THREAD_FD(thread); vty = THREAD_ARG(thread); - vty->t_read = NULL; if ((nbytes = read(sock, buf, VTY_READ_BUFSIZ)) <= 0) { if (nbytes < 0) { @@ -2157,7 +2148,6 @@ static int vtysh_write(struct thread *thread) { struct vty *vty = THREAD_ARG(thread); - vty->t_write = NULL; vtysh_flush(vty); return 0; } @@ -2193,12 +2183,9 @@ void vty_close(struct vty *vty) bool was_stdio = false; /* Cancel threads.*/ - if (vty->t_read) - thread_cancel(vty->t_read); - if (vty->t_write) - thread_cancel(vty->t_write); - if (vty->t_timeout) - thread_cancel(vty->t_timeout); + THREAD_OFF(vty->t_read); + THREAD_OFF(vty->t_write); + THREAD_OFF(vty->t_timeout); /* Flush buffer. */ buffer_flush_all(vty->obuf, vty->wfd); @@ -2254,7 +2241,6 @@ static int vty_timeout(struct thread *thread) struct vty *vty; vty = THREAD_ARG(thread); - vty->t_timeout = NULL; vty->v_timeout = 0; /* Clear buffer*/ @@ -2651,25 +2637,20 @@ static void vty_event(enum event event, int sock, struct vty *vty) vector_set_index(Vvty_serv_thread, sock, vty_serv_thread); break; case VTYSH_READ: - vty->t_read = NULL; thread_add_read(vty_master, vtysh_read, vty, sock, &vty->t_read); break; case VTYSH_WRITE: - vty->t_write = NULL; thread_add_write(vty_master, vtysh_write, vty, sock, &vty->t_write); break; #endif /* VTYSH */ case VTY_READ: - vty->t_read = NULL; thread_add_read(vty_master, vty_read, vty, sock, &vty->t_read); /* Time out treatment. */ if (vty->v_timeout) { - if (vty->t_timeout) - thread_cancel(vty->t_timeout); - vty->t_timeout = NULL; + THREAD_OFF(vty->t_timeout); thread_add_timer(vty_master, vty_timeout, vty, vty->v_timeout, &vty->t_timeout); } @@ -2679,15 +2660,10 @@ static void vty_event(enum event event, int sock, struct vty *vty) &vty->t_write); break; case VTY_TIMEOUT_RESET: - if (vty->t_timeout) { - thread_cancel(vty->t_timeout); - vty->t_timeout = NULL; - } - if (vty->v_timeout) { - vty->t_timeout = NULL; + THREAD_OFF(vty->t_timeout); + if (vty->v_timeout) thread_add_timer(vty_master, vty_timeout, vty, vty->v_timeout, &vty->t_timeout); - } break; } } @@ -3024,7 +3000,7 @@ void vty_reset(void) for (i = 0; i < vector_active(Vvty_serv_thread); i++) if ((vty_serv_thread = vector_slot(Vvty_serv_thread, i)) != NULL) { - thread_cancel(vty_serv_thread); + THREAD_OFF(vty_serv_thread); vector_slot(Vvty_serv_thread, i) = NULL; close(i); } diff --git a/lib/yang.c b/lib/yang.c index 2f9a9aa5a3..674f3610d6 100644 --- a/lib/yang.c +++ b/lib/yang.c @@ -27,8 +27,8 @@ #include <libyang/user_types.h> -DEFINE_MTYPE(LIB, YANG_MODULE, "YANG module") -DEFINE_MTYPE(LIB, YANG_DATA, "YANG data structure") +DEFINE_MTYPE_STATIC(LIB, YANG_MODULE, "YANG module") +DEFINE_MTYPE_STATIC(LIB, YANG_DATA, "YANG data structure") /* libyang container. */ struct ly_ctx *ly_native_ctx; diff --git a/lib/yang.h b/lib/yang.h index 6f8c84ab64..322c74c76a 100644 --- a/lib/yang.h +++ b/lib/yang.h @@ -33,9 +33,6 @@ extern "C" { #endif -DECLARE_MTYPE(YANG_MODULE) -DECLARE_MTYPE(YANG_DATA) - /* Maximum XPath length. */ #define XPATH_MAXLEN 256 diff --git a/ospfd/ospf_routemap.c b/ospfd/ospf_routemap.c index ab2d5ae584..bb7e97bf7b 100644 --- a/ospfd/ospf_routemap.c +++ b/ospfd/ospf_routemap.c @@ -210,6 +210,40 @@ struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = { route_match_ip_next_hop_prefix_list_compile, route_match_ip_next_hop_prefix_list_free}; +/* `match ip next-hop type <blackhole>' */ + +static route_map_result_t +route_match_ip_next_hop_type(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct external_info *ei = object; + + if (type == RMAP_OSPF && prefix->family == AF_INET) { + ei = (struct external_info *)object; + if (!ei) + return RMAP_DENYMATCH; + + if (ei->nexthop.s_addr == INADDR_ANY && !ei->ifindex) + return RMAP_MATCH; + } + return RMAP_NOMATCH; +} + +static void *route_match_ip_next_hop_type_compile(const char *arg) +{ + return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); +} + +static void route_match_ip_next_hop_type_free(void *rule) +{ + XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); +} + +static struct route_map_rule_cmd route_match_ip_next_hop_type_cmd = { + "ip next-hop type", route_match_ip_next_hop_type, + route_match_ip_next_hop_type_compile, + route_match_ip_next_hop_type_free}; + /* `match ip address IP_ACCESS_LIST' */ /* Match function should return 1 if match is success else return zero. */ @@ -566,6 +600,9 @@ void ospf_route_map_init(void) route_map_match_ip_next_hop_prefix_list_hook(generic_match_add); route_map_no_match_ip_next_hop_prefix_list_hook(generic_match_delete); + route_map_match_ip_next_hop_type_hook(generic_match_add); + route_map_no_match_ip_next_hop_type_hook(generic_match_delete); + route_map_match_tag_hook(generic_match_add); route_map_no_match_tag_hook(generic_match_delete); @@ -579,6 +616,7 @@ void ospf_route_map_init(void) route_map_install_match(&route_match_ip_next_hop_prefix_list_cmd); route_map_install_match(&route_match_ip_address_cmd); route_map_install_match(&route_match_ip_address_prefix_list_cmd); + route_map_install_match(&route_match_ip_next_hop_type_cmd); route_map_install_match(&route_match_interface_cmd); route_map_install_match(&route_match_tag_cmd); diff --git a/pimd/pim_assert.c b/pimd/pim_assert.c index 438a0c9b64..228218e3a3 100644 --- a/pimd/pim_assert.c +++ b/pimd/pim_assert.c @@ -148,12 +148,6 @@ static int dispatch_assert(struct interface *ifp, struct in_addr source_addr, sg.src = source_addr; sg.grp = group_addr; ch = pim_ifchannel_add(ifp, &sg, 0, 0); - if (!ch) { - zlog_warn( - "%s: (S,G)=%s failure creating channel on interface %s", - __PRETTY_FUNCTION__, pim_str_sg_dump(&sg), ifp->name); - return -1; - } switch (ch->ifassert_state) { case PIM_IFASSERT_NOINFO: diff --git a/pimd/pim_bsm.c b/pimd/pim_bsm.c index 266d3ffcf5..9995b5e31f 100644 --- a/pimd/pim_bsm.c +++ b/pimd/pim_bsm.c @@ -152,14 +152,6 @@ static struct bsgrp_node *pim_bsm_new_bsgrp_node(struct route_table *rt, } bsgrp = XCALLOC(MTYPE_PIM_BSGRP_NODE, sizeof(struct bsgrp_node)); - if (!bsgrp) { - if (PIM_DEBUG_BSM) - zlog_debug("%s: bsgrp alloc failed", - __PRETTY_FUNCTION__); - route_unlock_node(rn); - return NULL; - } - rn->info = bsgrp; bsgrp->bsrp_list = pim_alloc_bsrp_list(); bsgrp->partial_bsrp_list = pim_alloc_bsrp_list(); @@ -730,12 +722,6 @@ static bool pim_bsm_frag_send(uint8_t *buf, uint32_t len, struct interface *ifp, pak_start = XCALLOC(MTYPE_PIM_BSM_PKT_VAR_MEM, pim_mtu); - if (!pak_start) { - if (PIM_DEBUG_BSM) - zlog_debug("%s: malloc failed", __PRETTY_FUNCTION__); - return false; - } - pkt = pak_start; /* Fill PIM header later before sending packet to calc checksum */ @@ -1057,13 +1043,6 @@ static bool pim_install_bsm_grp_rp(struct pim_instance *pim, /*memory allocation for bsm_rpinfo */ bsm_rpinfo = XCALLOC(MTYPE_PIM_BSRP_NODE, sizeof(*bsm_rpinfo)); - if (!bsm_rpinfo) { - if (PIM_DEBUG_BSM) - zlog_debug("%s, Memory allocation failed.\r\n", - __PRETTY_FUNCTION__); - return false; - } - bsm_rpinfo->rp_prio = rp->rp_pri; bsm_rpinfo->rp_holdtime = rp->rp_holdtime; memcpy(&bsm_rpinfo->rp_address, &rp->rpaddr.addr, @@ -1387,18 +1366,8 @@ int pim_bsm_process(struct interface *ifp, struct ip *ip_hdr, uint8_t *buf, if (!no_fwd) { pim_bsm_fwd_whole_sz(pim_ifp->pim, buf, buf_size, sz); bsminfo = XCALLOC(MTYPE_PIM_BSM_INFO, sizeof(struct bsm_info)); - if (!bsminfo) { - zlog_warn("%s: bsminfo alloc failed", - __PRETTY_FUNCTION__); - return 0; - } bsminfo->bsm = XCALLOC(MTYPE_PIM_BSM_PKT_VAR_MEM, buf_size); - if (!bsminfo->bsm) { - zlog_warn("%s: bsm alloc failed", __PRETTY_FUNCTION__); - XFREE(MTYPE_PIM_BSM_INFO, bsminfo); - return 0; - } bsminfo->size = buf_size; memcpy(bsminfo->bsm, buf, buf_size); diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index c6617d9d21..72d7916b20 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -6653,13 +6653,7 @@ static int pim_cmd_igmp_start(struct vty *vty, struct interface *ifp) pim_ifp = ifp->info; if (!pim_ifp) { - pim_ifp = pim_if_new(ifp, true, false, false, - false /*vxlan_term*/); - if (!pim_ifp) { - vty_out(vty, "Could not enable IGMP on interface %s\n", - ifp->name); - return CMD_WARNING_CONFIG_FAILED; - } + (void)pim_if_new(ifp, true, false, false, false); need_startup = 1; } else { if (!PIM_IF_TEST_IGMP(pim_ifp->options)) { @@ -7360,19 +7354,40 @@ DEFUN (interface_no_ip_pim_drprio, return CMD_SUCCESS; } +DEFPY_HIDDEN (interface_ip_igmp_query_generate, + interface_ip_igmp_query_generate_cmd, + "ip igmp generate-query-once [version (2-3)]", + IP_STR + IFACE_IGMP_STR + "Generate igmp general query once\n" + "IGMP version\n" + "IGMP version number\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + int igmp_version = 2; + + if (!ifp->info) { + vty_out(vty, "IGMP/PIM is not enabled on the interface %s\n", + ifp->name); + return CMD_WARNING_CONFIG_FAILED; + } + + if (argc > 3) + igmp_version = atoi(argv[4]->arg); + + igmp_send_query_on_intf(ifp, igmp_version); + + return CMD_SUCCESS; +} + static int pim_cmd_interface_add(struct interface *ifp) { struct pim_interface *pim_ifp = ifp->info; - if (!pim_ifp) { - pim_ifp = pim_if_new(ifp, false, true, false, - false /*vxlan_term*/); - if (!pim_ifp) { - return 0; - } - } else { + if (!pim_ifp) + (void)pim_if_new(ifp, false, true, false, false); + else PIM_IF_DO_PIM(pim_ifp->options); - } pim_if_addr_add_all(ifp); pim_if_membership_refresh(ifp); @@ -10289,6 +10304,7 @@ void pim_cmd_init(void) install_element(INTERFACE_NODE, &interface_no_ip_pim_hello_cmd); install_element(INTERFACE_NODE, &interface_ip_pim_boundary_oil_cmd); install_element(INTERFACE_NODE, &interface_no_ip_pim_boundary_oil_cmd); + install_element(INTERFACE_NODE, &interface_ip_igmp_query_generate_cmd); // Static mroutes NEB install_element(INTERFACE_NODE, &interface_ip_mroute_cmd); diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 7b8f045697..0511a1a157 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -1293,11 +1293,7 @@ ferr_r pim_if_igmp_join_add(struct interface *ifp, struct in_addr group_addr, return ferr_ok(); } - ij = igmp_join_new(ifp, group_addr, source_addr); - if (!ij) { - return ferr_cfg_invalid( - "Failure to create new join data structure, see log file for more information"); - } + (void)igmp_join_new(ifp, group_addr, source_addr); if (PIM_DEBUG_IGMP_EVENTS) { char group_str[INET_ADDRSTRLEN]; diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index 9b242e9be5..96c7e8052c 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -133,7 +133,7 @@ void pim_ifchannel_delete(struct pim_ifchannel *ch) if (ch->upstream->channel_oil) { uint32_t mask = PIM_OIF_FLAG_PROTO_PIM; if (ch->upstream->flags & PIM_UPSTREAM_FLAG_MASK_SRC_IGMP) - mask = PIM_OIF_FLAG_PROTO_IGMP; + mask |= PIM_OIF_FLAG_PROTO_IGMP; /* * A S,G RPT channel can have an empty oil, we also @@ -142,13 +142,15 @@ void pim_ifchannel_delete(struct pim_ifchannel *ch) * being inherited. So let's figure out what * needs to be done here */ - if (pim_upstream_evaluate_join_desired_interface( - ch->upstream, ch, ch->parent)) + if ((ch->sg.src.s_addr != INADDR_ANY) && + pim_upstream_evaluate_join_desired_interface( + ch->upstream, ch, ch->parent)) pim_channel_add_oif(ch->upstream->channel_oil, - ch->interface, mask); - else - pim_channel_del_oif(ch->upstream->channel_oil, - ch->interface, mask); + ch->interface, + PIM_OIF_FLAG_PROTO_STAR); + + pim_channel_del_oif(ch->upstream->channel_oil, + ch->interface, mask); /* * Do we have any S,G's that are inheriting? * Nuke from on high too. @@ -227,6 +229,8 @@ void pim_ifchannel_delete_all(struct interface *ifp) while (!RB_EMPTY(pim_ifchannel_rb, &pim_ifp->ifchannel_rb)) { ch = RB_ROOT(pim_ifchannel_rb, &pim_ifp->ifchannel_rb); + pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, + ch, PIM_IFJOIN_NOINFO); pim_ifchannel_delete(ch); } } @@ -613,6 +617,10 @@ static int on_ifjoin_expiry_timer(struct thread *t) ch = THREAD_ARG(t); + if (PIM_DEBUG_TRACE) + zlog_debug("%s: ifchannel %s expiry timer", __PRETTY_FUNCTION__, + ch->sg_str); + ifjoin_to_noinfo(ch, true); /* ch may have been deleted */ @@ -787,8 +795,6 @@ void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr, ch = pim_ifchannel_add(ifp, sg, source_flags, PIM_UPSTREAM_FLAG_MASK_SRC_PIM); - if (!ch) - return; /* RFC 4601: 4.6.1. (S,G) Assert Message State Machine @@ -949,8 +955,6 @@ void pim_ifchannel_prune(struct interface *ifp, struct in_addr upstream, ch = pim_ifchannel_add(ifp, sg, source_flags, PIM_UPSTREAM_FLAG_MASK_SRC_PIM); - if (!ch) - return; pim_ifp = ifp->info; @@ -1078,13 +1082,6 @@ int pim_ifchannel_local_membership_add(struct interface *ifp, } ch = pim_ifchannel_add(ifp, sg, 0, PIM_UPSTREAM_FLAG_MASK_SRC_IGMP); - if (!ch) { - if (PIM_DEBUG_EVENTS) - zlog_debug("%s:%s Unable to add ifchannel", - __PRETTY_FUNCTION__, - pim_str_sg_dump(sg)); - return 0; - } ifmembership_set(ch, PIM_IFMEMBERSHIP_INCLUDE); diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c index 4ae6f69d3e..7dfd26ea65 100644 --- a/pimd/pim_igmp.c +++ b/pimd/pim_igmp.c @@ -305,6 +305,13 @@ static int igmp_recv_query(struct igmp_sock *igmp, int query_version, return -1; } + if (!pim_if_connected_to_source(ifp, from)) { + if (PIM_DEBUG_IGMP_PACKETS) + zlog_debug("Recv IGMP query on interface: %s from a non-connected source: %s", + ifp->name, from_str); + return 0; + } + /* Collecting IGMP Rx stats */ switch (query_version) { case 1: @@ -1180,3 +1187,42 @@ void igmp_send_query(int igmp_version, struct igmp_group *group, int fd, group_addr, query_max_response_time_dsec); } } + +void igmp_send_query_on_intf(struct interface *ifp, int igmp_ver) +{ + struct pim_interface *pim_ifp = ifp->info; + struct listnode *sock_node = NULL; + struct igmp_sock *igmp = NULL; + struct in_addr dst_addr; + struct in_addr group_addr; + int query_buf_size; + + if (!igmp_ver) + igmp_ver = 2; + + if (igmp_ver == 3) + query_buf_size = PIM_IGMP_BUFSIZE_WRITE; + else + query_buf_size = IGMP_V12_MSG_SIZE; + + dst_addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); + group_addr.s_addr = PIM_NET_INADDR_ANY; + + if (PIM_DEBUG_IGMP_TRACE) + zlog_debug("Issuing general query on request on %s", + ifp->name); + + for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { + + char query_buf[query_buf_size]; + + igmp_send_query(igmp_ver, 0 /* igmp_group */, igmp->fd, + igmp->interface->name, query_buf, + sizeof(query_buf), 0 /* num_sources */, + dst_addr, group_addr, + pim_ifp->igmp_query_max_response_time_dsec, + 1 /* s_flag: always set for general queries */, + igmp->querier_robustness_variable, + igmp->querier_query_interval); + } +} diff --git a/pimd/pim_igmp.h b/pimd/pim_igmp.h index 7db568dcfe..9231b0b41f 100644 --- a/pimd/pim_igmp.h +++ b/pimd/pim_igmp.h @@ -198,4 +198,6 @@ void igmp_send_query(int igmp_version, struct igmp_group *group, int fd, uint8_t querier_robustness_variable, uint16_t querier_query_interval); void igmp_group_delete(struct igmp_group *group); + +void igmp_send_query_on_intf(struct interface *ifp, int igmp_ver); #endif /* PIM_IGMP_H */ diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c index bc0460fa03..d9b940bba7 100644 --- a/pimd/pim_igmpv3.c +++ b/pimd/pim_igmpv3.c @@ -332,7 +332,8 @@ void igmp_source_free(struct igmp_source *source) static void source_channel_oil_detach(struct igmp_source *source) { if (source->source_channel_oil) { - pim_channel_oil_del(source->source_channel_oil); + pim_channel_oil_del(source->source_channel_oil, + __PRETTY_FUNCTION__); source->source_channel_oil = NULL; } } diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index ca05824347..b1c55c1f43 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -201,9 +201,14 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp, * Let's blackhole those packets for the moment * As that they will be coming up to the cpu * and causing us to consider them. + * + * This *will* create a dangling channel_oil + * that I see no way to get rid of. Just noting + * this for future reference. */ c_oil = pim_channel_oil_add(pim_ifp->pim, &sg, - pim_ifp->mroute_vif_index); + pim_ifp->mroute_vif_index, + __PRETTY_FUNCTION__); pim_mroute_add(c_oil, __PRETTY_FUNCTION__); return 0; @@ -211,14 +216,6 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp, up = pim_upstream_find_or_add(&sg, ifp, PIM_UPSTREAM_FLAG_MASK_FHR, __PRETTY_FUNCTION__); - if (!up) { - if (PIM_DEBUG_MROUTE) { - zlog_debug( - "%s: Failure to add upstream information for %s", - __PRETTY_FUNCTION__, pim_str_sg_dump(&sg)); - } - return 0; - } /* * I moved this debug till after the actual add because @@ -523,7 +520,8 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, if (!up->channel_oil) up->channel_oil = pim_channel_oil_add( pim_ifp->pim, &sg, - pim_ifp->mroute_vif_index); + pim_ifp->mroute_vif_index, + __PRETTY_FUNCTION__); pim_upstream_inherited_olist(pim_ifp->pim, up); if (!up->channel_oil->installed) pim_mroute_add(up->channel_oil, @@ -548,7 +546,8 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, } pim_ifp = ifp->info; - oil = pim_channel_oil_add(pim_ifp->pim, &sg, pim_ifp->mroute_vif_index); + oil = pim_channel_oil_add(pim_ifp->pim, &sg, pim_ifp->mroute_vif_index, + __PRETTY_FUNCTION__); if (!oil->installed) pim_mroute_add(oil, __PRETTY_FUNCTION__); if (pim_if_connected_to_source(ifp, sg.src)) { diff --git a/pimd/pim_msg.h b/pimd/pim_msg.h index 5f50303967..b6e2cada1f 100644 --- a/pimd/pim_msg.h +++ b/pimd/pim_msg.h @@ -66,9 +66,19 @@ struct pim_encoded_ipv4_unicast { struct in_addr addr; } __attribute__((packed)); +/* + * Encoded Group format. RFC 4601 Sec 4.9.1 + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Addr Family | Encoding Type |B| Reserved |Z| Mask Len | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Group multicast Address + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+... + */ struct pim_encoded_group_ipv4 { - uint8_t ne; uint8_t family; + uint8_t ne; uint8_t bidir : 1; /* Bidir bit */ uint8_t reserved : 6; /* Reserved */ uint8_t sz : 1; /* scope zone bit */ @@ -76,9 +86,20 @@ struct pim_encoded_group_ipv4 { struct in_addr addr; } __attribute__((packed)); + +/* + * Encoded Source format. RFC 4601 Sec 4.9.1 + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Addr Family | Encoding Type | Rsrvd |S|W|R| Mask Len | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Source Address + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-... + */ struct pim_encoded_source_ipv4 { - uint8_t ne; uint8_t family; + uint8_t ne; uint8_t bits; uint8_t mask; struct in_addr addr; diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c index 22045c2d33..d4fc03e20c 100644 --- a/pimd/pim_oil.c +++ b/pimd/pim_oil.c @@ -38,18 +38,22 @@ char *pim_channel_oil_dump(struct channel_oil *c_oil, char *buf, size_t size) { char *out; + struct interface *ifp; struct prefix_sg sg; int i; sg.src = c_oil->oil.mfcc_origin; sg.grp = c_oil->oil.mfcc_mcastgrp; - snprintf(buf, size, "%s IIF: %d, OIFS: ", pim_str_sg_dump(&sg), - c_oil->oil.mfcc_parent); + ifp = pim_if_find_by_vif_index(c_oil->pim, c_oil->oil.mfcc_parent); + snprintf(buf, size, "%s IIF: %s, OIFS: ", pim_str_sg_dump(&sg), + ifp ? ifp->name : "(?)"); out = buf + strlen(buf); for (i = 0; i < MAXVIFS; i++) { if (c_oil->oil.mfcc_ttls[i] != 0) { - snprintf(out, buf + size - out, "%d ", i); + ifp = pim_if_find_by_vif_index(c_oil->pim, i); + snprintf(out, buf + size - out, "%s ", + ifp ? ifp->name : "(?)"); out += strlen(out); } } @@ -144,7 +148,7 @@ struct channel_oil *pim_find_channel_oil(struct pim_instance *pim, struct channel_oil *pim_channel_oil_add(struct pim_instance *pim, struct prefix_sg *sg, - int input_vif_index) + int input_vif_index, const char *name) { struct channel_oil *c_oil; struct interface *ifp; @@ -153,18 +157,23 @@ struct channel_oil *pim_channel_oil_add(struct pim_instance *pim, if (c_oil) { if (c_oil->oil.mfcc_parent != input_vif_index) { c_oil->oil_inherited_rescan = 1; - if (PIM_DEBUG_MROUTE) + if (PIM_DEBUG_MROUTE_DETAIL) zlog_debug( - "%s: Existing channel oil %s points to %d, modifying to point at %d", - __PRETTY_FUNCTION__, - pim_str_sg_dump(sg), + "%s: Existing channel oil %pSG4 points to %d, modifying to point at %d", + __PRETTY_FUNCTION__, sg, c_oil->oil.mfcc_parent, input_vif_index); } c_oil->oil.mfcc_parent = input_vif_index; ++c_oil->oil_ref_count; - c_oil->up = pim_upstream_find( - pim, sg); // channel might be present prior to upstream + /* channel might be present prior to upstream */ + c_oil->up = pim_upstream_find(pim, sg); + + if (PIM_DEBUG_MROUTE) + zlog_debug( + "%s(%s): Existing oil for %pSG4 Ref Count: %d (Post Increment)", + __PRETTY_FUNCTION__, name, sg, + c_oil->oil_ref_count); return c_oil; } @@ -173,9 +182,8 @@ struct channel_oil *pim_channel_oil_add(struct pim_instance *pim, if (!ifp) { /* warning only */ zlog_warn( - "%s: (S,G)=%s could not find input interface for input_vif_index=%d", - __PRETTY_FUNCTION__, pim_str_sg_dump(sg), - input_vif_index); + "%s:%s (S,G)=%pSG4 could not find input interface for input_vif_index=%d", + __PRETTY_FUNCTION__, name, sg, input_vif_index); } } @@ -193,11 +201,23 @@ struct channel_oil *pim_channel_oil_add(struct pim_instance *pim, listnode_add_sort(pim->channel_oil_list, c_oil); + if (PIM_DEBUG_MROUTE) + zlog_debug( + "%s(%s): New oil for %pSG4 vif_index: %d Ref Count: 1 (Post Increment)", + __PRETTY_FUNCTION__, name, sg, input_vif_index); return c_oil; } -void pim_channel_oil_del(struct channel_oil *c_oil) +void pim_channel_oil_del(struct channel_oil *c_oil, const char *name) { + if (PIM_DEBUG_MROUTE) { + struct prefix_sg sg = {.src = c_oil->oil.mfcc_mcastgrp, + .grp = c_oil->oil.mfcc_origin}; + + zlog_debug( + "%s(%s): Del oil for %pSG4, Ref Count: %d (Predecrement)", + __PRETTY_FUNCTION__, name, &sg, c_oil->oil_ref_count); + } --c_oil->oil_ref_count; if (c_oil->oil_ref_count < 1) { @@ -344,10 +364,12 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif, IGMP must be protected against adding looped MFC entries created by both source and receiver attached to the same interface. See TODO T22. + We shall allow igmp to create upstream when it is DR for the intf. + Assume RP reachable via non DR. */ - if (channel_oil->up && - PIM_UPSTREAM_FLAG_TEST_ALLOW_IIF_IN_OIL( - channel_oil->up->flags)) { + if ((channel_oil->up && + PIM_UPSTREAM_FLAG_TEST_ALLOW_IIF_IN_OIL(channel_oil->up->flags)) || + ((proto_mask == PIM_OIF_FLAG_PROTO_IGMP) && PIM_I_am_DR(pim_ifp))) { allow_iif_in_oil = true; } diff --git a/pimd/pim_oil.h b/pimd/pim_oil.h index d097da6b3e..485299196d 100644 --- a/pimd/pim_oil.h +++ b/pimd/pim_oil.h @@ -113,8 +113,8 @@ struct channel_oil *pim_find_channel_oil(struct pim_instance *pim, struct prefix_sg *sg); struct channel_oil *pim_channel_oil_add(struct pim_instance *pim, struct prefix_sg *sg, - int input_vif_index); -void pim_channel_oil_del(struct channel_oil *c_oil); + int input_vif_index, const char *name); +void pim_channel_oil_del(struct channel_oil *c_oil, const char *name); int pim_channel_add_oif(struct channel_oil *c_oil, struct interface *oif, uint32_t proto_mask); diff --git a/pimd/pim_static.c b/pimd/pim_static.c index 442b22e06f..62c3216e86 100644 --- a/pimd/pim_static.c +++ b/pimd/pim_static.c @@ -124,9 +124,6 @@ int pim_static_add(struct pim_instance *pim, struct interface *iif, * back if it fails. */ original_s_route = static_route_alloc(); - if (!original_s_route) { - return -5; - } memcpy(original_s_route, s_route, sizeof(struct static_route)); diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index 50c68c66bd..194fb2cffd 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -146,7 +146,7 @@ static void upstream_channel_oil_detach(struct pim_upstream *up) but upstream would not keep reference of it */ up->channel_oil->up = NULL; - pim_channel_oil_del(up->channel_oil); + pim_channel_oil_del(up->channel_oil, __PRETTY_FUNCTION__); up->channel_oil = NULL; } } @@ -740,13 +740,15 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim, pim_upstream_fill_static_iif(up, incoming); pim_ifp = up->rpf.source_nexthop.interface->info; assert(pim_ifp); - up->channel_oil = pim_channel_oil_add(pim, - &up->sg, pim_ifp->mroute_vif_index); + up->channel_oil = pim_channel_oil_add(pim, &up->sg, + pim_ifp->mroute_vif_index, + __PRETTY_FUNCTION__); } else if (up->upstream_addr.s_addr == INADDR_ANY) { /* Create a dummmy channel oil with incoming ineterface MAXVIFS, * since RP is not configured */ - up->channel_oil = pim_channel_oil_add(pim, &up->sg, MAXVIFS); + up->channel_oil = pim_channel_oil_add(pim, &up->sg, MAXVIFS, + __PRETTY_FUNCTION__); } else { rpf_result = pim_rpf_update(pim, up, NULL); @@ -759,14 +761,27 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim, * MAXVIFS, since RP is not reachable */ up->channel_oil = pim_channel_oil_add( - pim, &up->sg, MAXVIFS); + pim, &up->sg, MAXVIFS, __PRETTY_FUNCTION__); } if (up->rpf.source_nexthop.interface) { pim_ifp = up->rpf.source_nexthop.interface->info; if (pim_ifp) - up->channel_oil = pim_channel_oil_add(pim, - &up->sg, pim_ifp->mroute_vif_index); + up->channel_oil = pim_channel_oil_add( + pim, &up->sg, pim_ifp->mroute_vif_index, + __PRETTY_FUNCTION__); + else { + /* + * Yeah this should not happen + * but let's be sure that we are not + * doing something stupid, all paths + * through upstream creation will + * create a channel oil + */ + up->channel_oil = pim_channel_oil_add( + pim, &up->sg, MAXVIFS, + __PRETTY_FUNCTION__); + } } } @@ -1524,8 +1539,9 @@ int pim_upstream_inherited_olist_decide(struct pim_instance *pim, __PRETTY_FUNCTION__, up->sg_str); } if (pim_ifp && !up->channel_oil) - up->channel_oil = pim_channel_oil_add( - pim, &up->sg, pim_ifp->mroute_vif_index); + up->channel_oil = pim_channel_oil_add(pim, &up->sg, + pim_ifp->mroute_vif_index, + __PRETTY_FUNCTION__); FOR_ALL_INTERFACES (pim->vrf, ifp) { if (!ifp->info) diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index 468cd56ee5..d1935195df 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -70,10 +70,6 @@ int pim_debug_config_write(struct vty *vty) vty_out(vty, "debug igmp trace\n"); ++writes; } - if (PIM_DEBUG_IGMP_TRACE_DETAIL) { - vty_out(vty, "debug igmp trace detail\n"); - ++writes; - } if (PIM_DEBUG_MROUTE) { vty_out(vty, "debug mroute\n"); diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 25ac307ac4..2c814d0fdc 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -974,18 +974,8 @@ void igmp_source_forward_start(struct pim_instance *pim, if (!pim_rp_set_upstream_addr(pim, &vif_source, source->source_addr, sg.grp)) { /*Create a dummy channel oil */ - source->source_channel_oil = - pim_channel_oil_add(pim, &sg, MAXVIFS); - - if (!source->source_channel_oil) { - if (PIM_DEBUG_IGMP_TRACE) { - zlog_debug( - "%s %s: could not create OIL for channel (S,G)=%s", - __FILE__, __PRETTY_FUNCTION__, - pim_str_sg_dump(&sg)); - } - return; - } + source->source_channel_oil = pim_channel_oil_add( + pim, &sg, MAXVIFS, __PRETTY_FUNCTION__); } else { @@ -1035,7 +1025,9 @@ void igmp_source_forward_start(struct pim_instance *pim, source_str); } source->source_channel_oil = - pim_channel_oil_add(pim, &sg, MAXVIFS); + pim_channel_oil_add( + pim, &sg, MAXVIFS, + __PRETTY_FUNCTION__); } else { @@ -1043,10 +1035,12 @@ void igmp_source_forward_start(struct pim_instance *pim, * Protect IGMP against adding looped MFC * entries created by both source and receiver * attached to the same interface. See TODO - * T22. + * T22. Block only when the intf is non DR + * DR must create upstream. */ - if (input_iface_vif_index == - pim_oif->mroute_vif_index) { + if ((input_iface_vif_index == + pim_oif->mroute_vif_index) && + !(PIM_I_am_DR(pim_oif))) { /* ignore request for looped MFC entry */ if (PIM_DEBUG_IGMP_TRACE) { @@ -1065,8 +1059,9 @@ void igmp_source_forward_start(struct pim_instance *pim, } source->source_channel_oil = - pim_channel_oil_add(pim, &sg, - input_iface_vif_index); + pim_channel_oil_add( + pim, &sg, input_iface_vif_index, + __PRETTY_FUNCTION__); if (!source->source_channel_oil) { if (PIM_DEBUG_IGMP_TRACE) { zlog_debug( @@ -1241,22 +1236,14 @@ void pim_forward_start(struct pim_ifchannel *ch) __FILE__, __PRETTY_FUNCTION__, source_str); } - up->channel_oil = pim_channel_oil_add(pim, &up->sg, - MAXVIFS); + up->channel_oil = pim_channel_oil_add( + pim, &up->sg, MAXVIFS, __PRETTY_FUNCTION__); } - else { - up->channel_oil = pim_channel_oil_add(pim, &up->sg, - input_iface_vif_index); - if (!up->channel_oil) { - if (PIM_DEBUG_PIM_TRACE) - zlog_debug( - "%s %s: could not create OIL for channel (S,G)=%s", - __FILE__, __PRETTY_FUNCTION__, - up->sg_str); - return; - } - } + else + up->channel_oil = pim_channel_oil_add( + pim, &up->sg, input_iface_vif_index, + __PRETTY_FUNCTION__); if (PIM_DEBUG_TRACE) { struct interface *in_intf = pim_if_find_by_vif_index( @@ -1268,16 +1255,9 @@ void pim_forward_start(struct pim_ifchannel *ch) input_iface_vif_index, up->sg_str); } - up->channel_oil = pim_channel_oil_add(pim, &up->sg, - input_iface_vif_index); - if (!up->channel_oil) { - if (PIM_DEBUG_PIM_TRACE) - zlog_debug( - "%s %s: could not create OIL for channel (S,G)=%s", - __FILE__, __PRETTY_FUNCTION__, - up->sg_str); - return; - } + up->channel_oil = + pim_channel_oil_add(pim, &up->sg, input_iface_vif_index, + __PRETTY_FUNCTION__); } if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_IGMP) diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c index 634fee0b30..80561f350b 100644 --- a/ripd/rip_interface.c +++ b/ripd/rip_interface.c @@ -43,6 +43,8 @@ #include "ripd/rip_debug.h" #include "ripd/rip_interface.h" +DEFINE_MTYPE_STATIC(RIPD, RIP_INTERFACE, "RIP interface") +DEFINE_MTYPE(RIPD, RIP_INTERFACE_STRING, "RIP Interface String") DEFINE_HOOK(rip_ifaddr_add, (struct connected * ifc), (ifc)) DEFINE_HOOK(rip_ifaddr_del, (struct connected * ifc), (ifc)) diff --git a/ripd/rip_interface.h b/ripd/rip_interface.h index 6befda0e28..715daf2e50 100644 --- a/ripd/rip_interface.h +++ b/ripd/rip_interface.h @@ -20,8 +20,11 @@ #ifndef _QUAGGA_RIP_INTERFACE_H #define _QUAGGA_RIP_INTERFACE_H +#include "memory.h" #include "zclient.h" +DECLARE_MTYPE(RIP_INTERFACE_STRING) + extern int rip_interface_down(int, struct zclient *, zebra_size_t, vrf_id_t); extern int rip_interface_up(int, struct zclient *, zebra_size_t, vrf_id_t); extern int rip_interface_add(int, struct zclient *, zebra_size_t, vrf_id_t); diff --git a/ripd/rip_memory.c b/ripd/rip_memory.c deleted file mode 100644 index 7d703a86db..0000000000 --- a/ripd/rip_memory.c +++ /dev/null @@ -1,36 +0,0 @@ -/* ripd memory type definitions - * - * Copyright (C) 2015 David Lamparter - * - * This file is part of Quagga. - * - * Quagga is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * Quagga 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 - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "rip_memory.h" - -DEFINE_MGROUP(RIPD, "ripd") -DEFINE_MTYPE(RIPD, RIP, "RIP structure") -DEFINE_MTYPE(RIPD, RIP_VRF_NAME, "RIP VRF name") -DEFINE_MTYPE(RIPD, RIP_INFO, "RIP route info") -DEFINE_MTYPE(RIPD, RIP_INTERFACE, "RIP interface") -DEFINE_MTYPE(RIPD, RIP_INTERFACE_STRING, "RIP Interface String") -DEFINE_MTYPE(RIPD, RIP_PEER, "RIP peer") -DEFINE_MTYPE(RIPD, RIP_OFFSET_LIST, "RIP offset list") -DEFINE_MTYPE(RIPD, RIP_DISTANCE, "RIP distance") diff --git a/ripd/rip_memory.h b/ripd/rip_memory.h deleted file mode 100644 index 1f9d8f500f..0000000000 --- a/ripd/rip_memory.h +++ /dev/null @@ -1,37 +0,0 @@ -/* ripd memory type declarations - * - * Copyright (C) 2015 David Lamparter - * - * This file is part of Quagga. - * - * Quagga is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * Quagga 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 _QUAGGA_RIP_MEMORY_H -#define _QUAGGA_RIP_MEMORY_H - -#include "memory.h" - -DECLARE_MGROUP(RIPD) -DECLARE_MTYPE(RIP) -DECLARE_MTYPE(RIP_VRF_NAME) -DECLARE_MTYPE(RIP_INFO) -DECLARE_MTYPE(RIP_INTERFACE) -DECLARE_MTYPE(RIP_INTERFACE_STRING) -DECLARE_MTYPE(RIP_PEER) -DECLARE_MTYPE(RIP_OFFSET_LIST) -DECLARE_MTYPE(RIP_DISTANCE) - -#endif /* _QUAGGA_RIP_MEMORY_H */ diff --git a/ripd/rip_northbound.c b/ripd/rip_northbound.c index f8a7f5dc67..1238d0f0fc 100644 --- a/ripd/rip_northbound.c +++ b/ripd/rip_northbound.c @@ -33,6 +33,7 @@ #include "ripd/ripd.h" #include "ripd/rip_debug.h" #include "ripd/rip_cli.h" +#include "ripd/rip_interface.h" /* * XPath: /frr-ripd:ripd/instance diff --git a/ripd/rip_offset.c b/ripd/rip_offset.c index 8307a95d27..776f121d59 100644 --- a/ripd/rip_offset.c +++ b/ripd/rip_offset.c @@ -29,6 +29,8 @@ #include "ripd/ripd.h" +DEFINE_MTYPE_STATIC(RIPD, RIP_OFFSET_LIST, "RIP offset list") + #define OFFSET_LIST_IN_NAME(O) ((O)->direct[RIP_OFFSET_LIST_IN].alist_name) #define OFFSET_LIST_IN_METRIC(O) ((O)->direct[RIP_OFFSET_LIST_IN].metric) diff --git a/ripd/rip_peer.c b/ripd/rip_peer.c index 08aa61257d..4ad7309c41 100644 --- a/ripd/rip_peer.c +++ b/ripd/rip_peer.c @@ -29,6 +29,8 @@ #include "ripd/ripd.h" +DEFINE_MTYPE_STATIC(RIPD, RIP_PEER, "RIP peer") + static struct rip_peer *rip_peer_new(void) { return XCALLOC(MTYPE_RIP_PEER, sizeof(struct rip_peer)); diff --git a/ripd/rip_routemap.c b/ripd/rip_routemap.c index 3216b8f89f..85d83c61dc 100644 --- a/ripd/rip_routemap.c +++ b/ripd/rip_routemap.c @@ -231,6 +231,40 @@ static struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = { route_match_ip_next_hop_prefix_list_compile, route_match_ip_next_hop_prefix_list_free}; +/* `match ip next-hop type <blackhole>' */ + +static route_map_result_t +route_match_ip_next_hop_type(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct rip_info *rinfo; + + if (type == RMAP_RIP && prefix->family == AF_INET) { + rinfo = (struct rip_info *)object; + if (!rinfo) + return RMAP_DENYMATCH; + + if (rinfo->nh.type == NEXTHOP_TYPE_BLACKHOLE) + return RMAP_MATCH; + } + return RMAP_NOMATCH; +} + +static void *route_match_ip_next_hop_type_compile(const char *arg) +{ + return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); +} + +static void route_match_ip_next_hop_type_free(void *rule) +{ + XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); +} + +static struct route_map_rule_cmd route_match_ip_next_hop_type_cmd = { + "ip next-hop type", route_match_ip_next_hop_type, + route_match_ip_next_hop_type_compile, + route_match_ip_next_hop_type_free}; + /* `match ip address IP_ACCESS_LIST' */ /* Match function should return 1 if match is success else return @@ -537,6 +571,9 @@ void rip_route_map_init(void) route_map_match_ip_next_hop_prefix_list_hook(generic_match_add); route_map_no_match_ip_next_hop_prefix_list_hook(generic_match_delete); + route_map_match_ip_next_hop_type_hook(generic_match_add); + route_map_no_match_ip_next_hop_type_hook(generic_match_delete); + route_map_match_metric_hook(generic_match_add); route_map_no_match_metric_hook(generic_match_delete); @@ -556,6 +593,7 @@ void rip_route_map_init(void) route_map_install_match(&route_match_interface_cmd); route_map_install_match(&route_match_ip_next_hop_cmd); route_map_install_match(&route_match_ip_next_hop_prefix_list_cmd); + route_map_install_match(&route_match_ip_next_hop_type_cmd); route_map_install_match(&route_match_ip_address_cmd); route_map_install_match(&route_match_ip_address_prefix_list_cmd); route_map_install_match(&route_match_tag_cmd); diff --git a/ripd/ripd.c b/ripd/ripd.c index 3a1ffd17a6..e0ff0430f8 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -51,6 +51,12 @@ /* UDP receive buffer size */ #define RIP_UDP_RCV_BUF 41600 +DEFINE_MGROUP(RIPD, "ripd") +DEFINE_MTYPE_STATIC(RIPD, RIP, "RIP structure") +DEFINE_MTYPE_STATIC(RIPD, RIP_VRF_NAME, "RIP VRF name") +DEFINE_MTYPE_STATIC(RIPD, RIP_INFO, "RIP route info") +DEFINE_MTYPE_STATIC(RIPD, RIP_DISTANCE, "RIP distance") + /* Prototypes. */ static void rip_output_process(struct connected *, struct sockaddr_in *, int, uint8_t); diff --git a/ripd/ripd.h b/ripd/ripd.h index 44f5932fb6..7f2c3fd068 100644 --- a/ripd/ripd.h +++ b/ripd/ripd.h @@ -24,7 +24,7 @@ #include "hook.h" #include "nexthop.h" #include "distribute.h" -#include "rip_memory.h" +#include "memory.h" /* RIP version number. */ #define RIPv1 1 @@ -97,6 +97,8 @@ #define RIP_INSTANCE "/frr-ripd:ripd/instance" #define RIP_IFACE "/frr-interface:lib/interface/frr-ripd:rip" +DECLARE_MGROUP(RIPD) + /* RIP structure. */ struct rip { RB_ENTRY(rip) entry; diff --git a/ripd/subdir.am b/ripd/subdir.am index 2a63cc5229..312c1db6af 100644 --- a/ripd/subdir.am +++ b/ripd/subdir.am @@ -23,7 +23,6 @@ ripd_librip_a_SOURCES = \ ripd/rip_debug.c \ ripd/rip_errors.c \ ripd/rip_interface.c \ - ripd/rip_memory.c \ ripd/rip_offset.c \ ripd/rip_northbound.c \ ripd/rip_peer.c \ @@ -40,7 +39,6 @@ noinst_HEADERS += \ ripd/rip_debug.h \ ripd/rip_errors.h \ ripd/rip_interface.h \ - ripd/rip_memory.h \ ripd/ripd.h \ # end diff --git a/ripngd/ripng_interface.c b/ripngd/ripng_interface.c index d83f4d2791..49ed13a2c2 100644 --- a/ripngd/ripng_interface.c +++ b/ripngd/ripng_interface.c @@ -49,6 +49,8 @@ #define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP #endif +DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_IF, "ripng interface") + /* Static utility function. */ static void ripng_enable_apply(struct interface *); static void ripng_passive_interface_apply(struct interface *); @@ -913,7 +915,7 @@ static struct ripng_interface *ri_new(void) { struct ripng_interface *ri; - ri = XCALLOC(MTYPE_IF, sizeof(struct ripng_interface)); + ri = XCALLOC(MTYPE_RIPNG_IF, sizeof(struct ripng_interface)); /* Set default split-horizon behavior. If the interface is Frame Relay or SMDS is enabled, the default value for split-horizon is @@ -950,7 +952,7 @@ static int ripng_if_new_hook(struct interface *ifp) /* Called when interface structure deleted. */ static int ripng_if_delete_hook(struct interface *ifp) { - XFREE(MTYPE_IF, ifp->info); + XFREE(MTYPE_RIPNG_IF, ifp->info); ifp->info = NULL; return 0; } diff --git a/ripngd/ripng_memory.c b/ripngd/ripng_memory.c deleted file mode 100644 index f459566bed..0000000000 --- a/ripngd/ripng_memory.c +++ /dev/null @@ -1,35 +0,0 @@ -/* ripngd memory type definitions - * - * Copyright (C) 2015 David Lamparter - * - * This file is part of Quagga. - * - * Quagga is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * Quagga 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 - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "ripng_memory.h" - -DEFINE_MGROUP(RIPNGD, "ripngd") -DEFINE_MTYPE(RIPNGD, RIPNG, "RIPng structure") -DEFINE_MTYPE(RIPNGD, RIPNG_VRF_NAME, "RIPng VRF name") -DEFINE_MTYPE(RIPNGD, RIPNG_ROUTE, "RIPng route info") -DEFINE_MTYPE(RIPNGD, RIPNG_AGGREGATE, "RIPng aggregate") -DEFINE_MTYPE(RIPNGD, RIPNG_PEER, "RIPng peer") -DEFINE_MTYPE(RIPNGD, RIPNG_OFFSET_LIST, "RIPng offset lst") -DEFINE_MTYPE(RIPNGD, RIPNG_RTE_DATA, "RIPng rte data") diff --git a/ripngd/ripng_memory.h b/ripngd/ripng_memory.h deleted file mode 100644 index 3dfc57b3ff..0000000000 --- a/ripngd/ripng_memory.h +++ /dev/null @@ -1,36 +0,0 @@ -/* ripngd memory type declarations - * - * Copyright (C) 2015 David Lamparter - * - * This file is part of Quagga. - * - * Quagga is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * Quagga 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 _QUAGGA_RIPNG_MEMORY_H -#define _QUAGGA_RIPNG_MEMORY_H - -#include "memory.h" - -DECLARE_MGROUP(RIPNGD) -DECLARE_MTYPE(RIPNG) -DECLARE_MTYPE(RIPNG_VRF_NAME) -DECLARE_MTYPE(RIPNG_ROUTE) -DECLARE_MTYPE(RIPNG_AGGREGATE) -DECLARE_MTYPE(RIPNG_PEER) -DECLARE_MTYPE(RIPNG_OFFSET_LIST) -DECLARE_MTYPE(RIPNG_RTE_DATA) - -#endif /* _QUAGGA_RIPNG_MEMORY_H */ diff --git a/ripngd/ripng_nexthop.c b/ripngd/ripng_nexthop.c index 882c2fbc8c..ba6e52fdda 100644 --- a/ripngd/ripng_nexthop.c +++ b/ripngd/ripng_nexthop.c @@ -39,6 +39,8 @@ #include "ripngd/ripng_debug.h" #include "ripngd/ripng_nexthop.h" +DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_RTE_DATA, "RIPng rte data") + #define DEBUG 1 #define min(a, b) ((a) < (b) ? (a) : (b)) diff --git a/ripngd/ripng_offset.c b/ripngd/ripng_offset.c index fe95ccfc2b..0094c993ad 100644 --- a/ripngd/ripng_offset.c +++ b/ripngd/ripng_offset.c @@ -33,6 +33,8 @@ #include "ripngd/ripngd.h" +DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_OFFSET_LIST, "RIPng offset lst") + #define OFFSET_LIST_IN_NAME(O) ((O)->direct[RIPNG_OFFSET_LIST_IN].alist_name) #define OFFSET_LIST_IN_METRIC(O) ((O)->direct[RIPNG_OFFSET_LIST_IN].metric) diff --git a/ripngd/ripng_peer.c b/ripngd/ripng_peer.c index 5376007747..109524e212 100644 --- a/ripngd/ripng_peer.c +++ b/ripngd/ripng_peer.c @@ -34,6 +34,8 @@ #include "ripngd/ripngd.h" #include "ripngd/ripng_nexthop.h" +DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_PEER, "RIPng peer") + static struct ripng_peer *ripng_peer_new(void) { return XCALLOC(MTYPE_RIPNG_PEER, sizeof(struct ripng_peer)); diff --git a/ripngd/ripng_route.c b/ripngd/ripng_route.c index 1bf1007fec..ed9d77a378 100644 --- a/ripngd/ripng_route.c +++ b/ripngd/ripng_route.c @@ -30,6 +30,8 @@ #include "ripngd/ripngd.h" #include "ripngd/ripng_route.h" +DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_AGGREGATE, "RIPng aggregate") + static struct ripng_aggregate *ripng_aggregate_new(void) { struct ripng_aggregate *new; diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index 71bc43049a..3314892e74 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -43,6 +43,11 @@ #include "ripngd/ripng_debug.h" #include "ripngd/ripng_nexthop.h" +DEFINE_MGROUP(RIPNGD, "ripngd") +DEFINE_MTYPE_STATIC(RIPNGD, RIPNG, "RIPng structure") +DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_VRF_NAME, "RIPng VRF name") +DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_ROUTE, "RIPng route info") + enum { ripng_all_route, ripng_changed_route, }; diff --git a/ripngd/ripngd.h b/ripngd/ripngd.h index a2686304fc..5a0d350a84 100644 --- a/ripngd/ripngd.h +++ b/ripngd/ripngd.h @@ -26,8 +26,7 @@ #include <vty.h> #include <distribute.h> #include <vector.h> - -#include "ripng_memory.h" +#include <memory.h> /* RIPng version and port number. */ #define RIPNG_V1 1 @@ -87,6 +86,8 @@ #define RIPNG_INSTANCE "/frr-ripngd:ripngd/instance" #define RIPNG_IFACE "/frr-interface:lib/interface/frr-ripngd:ripng" +DECLARE_MGROUP(RIPNGD) + /* RIPng structure. */ struct ripng { RB_ENTRY(ripng) entry; diff --git a/ripngd/subdir.am b/ripngd/subdir.am index ea0ccf1482..eac0d67313 100644 --- a/ripngd/subdir.am +++ b/ripngd/subdir.am @@ -17,7 +17,6 @@ ripngd_libripng_a_SOURCES = \ ripngd/ripng_cli.c \ ripngd/ripng_debug.c \ ripngd/ripng_interface.c \ - ripngd/ripng_memory.c \ ripngd/ripng_nexthop.c \ ripngd/ripng_offset.c \ ripngd/ripng_northbound.c \ @@ -34,7 +33,6 @@ ripngd/ripng_cli.$(OBJEXT): ripngd/ripng_cli_clippy.c noinst_HEADERS += \ ripngd/ripng_cli.h \ ripngd/ripng_debug.h \ - ripngd/ripng_memory.h \ ripngd/ripng_nexthop.h \ ripngd/ripng_route.h \ ripngd/ripngd.h \ diff --git a/staticd/static_nht.c b/staticd/static_nht.c index 9af30a587a..2aa0db59f1 100644 --- a/staticd/static_nht.c +++ b/staticd/static_nht.c @@ -37,8 +37,6 @@ static void static_nht_update_safi(struct prefix *p, uint32_t nh_num, struct static_route *si; struct static_vrf *svrf; struct route_node *rn; - bool orig; - bool reinstall; svrf = vrf->info; if (!svrf) @@ -49,7 +47,6 @@ static void static_nht_update_safi(struct prefix *p, uint32_t nh_num, 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; @@ -60,7 +57,6 @@ static void static_nht_update_safi(struct prefix *p, uint32_t nh_num, && si->type != STATIC_IPV6_GATEWAY_IFNAME) continue; - orig = si->nh_valid; if (p->family == AF_INET && p->u.prefix4.s_addr == si->addr.ipv4.s_addr) si->nh_valid = !!nh_num; @@ -69,14 +65,7 @@ static void static_nht_update_safi(struct prefix *p, uint32_t nh_num, && memcmp(&p->u.prefix6, &si->addr.ipv6, 16) == 0) si->nh_valid = !!nh_num; - if (orig != si->nh_valid) - reinstall = true; - - if (reinstall) { - static_zebra_route_add(rn, si, vrf->vrf_id, - safi, true); - reinstall = false; - } + static_zebra_route_add(rn, si, vrf->vrf_id, safi, true); } } } diff --git a/tests/topotests/bgp_instance_del_test/__init__.py b/tests/topotests/bgp_instance_del_test/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_instance_del_test/__init__.py diff --git a/tests/topotests/bgp_instance_del_test/ce1 b/tests/topotests/bgp_instance_del_test/ce1 new file mode 120000 index 0000000000..0924eb5f39 --- /dev/null +++ b/tests/topotests/bgp_instance_del_test/ce1 @@ -0,0 +1 @@ +../bgp_l3vpn_to_bgp_vrf/ce1
\ No newline at end of file diff --git a/tests/topotests/bgp_instance_del_test/ce2 b/tests/topotests/bgp_instance_del_test/ce2 new file mode 120000 index 0000000000..8c7a6777a9 --- /dev/null +++ b/tests/topotests/bgp_instance_del_test/ce2 @@ -0,0 +1 @@ +../bgp_l3vpn_to_bgp_vrf/ce2
\ No newline at end of file diff --git a/tests/topotests/bgp_instance_del_test/ce3 b/tests/topotests/bgp_instance_del_test/ce3 new file mode 120000 index 0000000000..0abb8e55ed --- /dev/null +++ b/tests/topotests/bgp_instance_del_test/ce3 @@ -0,0 +1 @@ +../bgp_l3vpn_to_bgp_vrf/ce3
\ No newline at end of file diff --git a/tests/topotests/bgp_instance_del_test/ce4 b/tests/topotests/bgp_instance_del_test/ce4 new file mode 120000 index 0000000000..ddee1eff9e --- /dev/null +++ b/tests/topotests/bgp_instance_del_test/ce4 @@ -0,0 +1 @@ +../bgp_l3vpn_to_bgp_vrf/ce4
\ No newline at end of file diff --git a/tests/topotests/bgp_instance_del_test/customize.py b/tests/topotests/bgp_instance_del_test/customize.py new file mode 120000 index 0000000000..99fcf39eb5 --- /dev/null +++ b/tests/topotests/bgp_instance_del_test/customize.py @@ -0,0 +1 @@ +../bgp_l3vpn_to_bgp_vrf/customize.py
\ No newline at end of file diff --git a/tests/topotests/bgp_instance_del_test/r1 b/tests/topotests/bgp_instance_del_test/r1 new file mode 120000 index 0000000000..16babfa8d5 --- /dev/null +++ b/tests/topotests/bgp_instance_del_test/r1 @@ -0,0 +1 @@ +../bgp_l3vpn_to_bgp_vrf/r1
\ No newline at end of file diff --git a/tests/topotests/bgp_instance_del_test/r2 b/tests/topotests/bgp_instance_del_test/r2 new file mode 120000 index 0000000000..e25b93276f --- /dev/null +++ b/tests/topotests/bgp_instance_del_test/r2 @@ -0,0 +1 @@ +../bgp_l3vpn_to_bgp_vrf/r2
\ No newline at end of file diff --git a/tests/topotests/bgp_instance_del_test/r3 b/tests/topotests/bgp_instance_del_test/r3 new file mode 120000 index 0000000000..0d7c189c6a --- /dev/null +++ b/tests/topotests/bgp_instance_del_test/r3 @@ -0,0 +1 @@ +../bgp_l3vpn_to_bgp_vrf/r3
\ No newline at end of file diff --git a/tests/topotests/bgp_instance_del_test/r4 b/tests/topotests/bgp_instance_del_test/r4 new file mode 120000 index 0000000000..2d667d37af --- /dev/null +++ b/tests/topotests/bgp_instance_del_test/r4 @@ -0,0 +1 @@ +../bgp_l3vpn_to_bgp_vrf/r4
\ No newline at end of file diff --git a/tests/topotests/bgp_instance_del_test/scripts b/tests/topotests/bgp_instance_del_test/scripts new file mode 120000 index 0000000000..c46bf1f07b --- /dev/null +++ b/tests/topotests/bgp_instance_del_test/scripts @@ -0,0 +1 @@ +../bgp_l3vpn_to_bgp_vrf/scripts
\ No newline at end of file diff --git a/tests/topotests/bgp_instance_del_test/test_bgp_instance_del_test.py b/tests/topotests/bgp_instance_del_test/test_bgp_instance_del_test.py new file mode 100755 index 0000000000..115c7793ad --- /dev/null +++ b/tests/topotests/bgp_instance_del_test/test_bgp_instance_del_test.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python + +# +# Part of NetDEF Topology Tests +# +# Copyright (c) 2018, LabN Consulting, L.L.C. +# Authored by Lou Berger <lberger@labn.net> +# +# 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. +# + +import os +import sys +import pytest + +sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../')) + +from lib.ltemplate import * + +def test_check_linux_vrf(): + CliOnFail = None + # For debugging, uncomment the next line + #CliOnFail = 'tgen.mininet_cli' + CheckFunc = 'ltemplateVersionCheck(\'4.1\', iproute2=\'4.9\')' + #uncomment next line to start cli *before* script is run + #CheckFunc = 'ltemplateVersionCheck(\'4.1\', cli=True, iproute2=\'4.9\')' + ltemplateTest('scripts/check_linux_vrf.py', False, CliOnFail, CheckFunc) + +def test_adjacencies(): + CliOnFail = None + # For debugging, uncomment the next line + #CliOnFail = 'tgen.mininet_cli' + CheckFunc = 'ltemplateVersionCheck(\'4.1\')' + #uncomment next line to start cli *before* script is run + #CheckFunc = 'ltemplateVersionCheck(\'4.1\', cli=True)' + ltemplateTest('scripts/adjacencies.py', False, CliOnFail, CheckFunc) + +def SKIP_test_add_routes(): + CliOnFail = None + # For debugging, uncomment the next line + #CliOnFail = 'tgen.mininet_cli' + CheckFunc = 'ltemplateVersionCheck(\'4.1\')' + #uncomment next line to start cli *before* script is run + #CheckFunc = 'ltemplateVersionCheck(\'4.1\', cli=True)' + ltemplateTest('scripts/add_routes.py', False, CliOnFail, CheckFunc) + +def test_check_routes(): + CliOnFail = None + # For debugging, uncomment the next line + #CliOnFail = 'tgen.mininet_cli' + CheckFunc = 'ltemplateVersionCheck(\'4.1\')' + #uncomment next line to start cli *before* script is run + #CheckFunc = 'ltemplateVersionCheck(\'4.1\', cli=True)' + ltemplateTest('scripts/check_routes.py', False, CliOnFail, CheckFunc) + +#manual data path setup test - remove once have bgp/zebra vrf path working +def test_check_linux_mpls(): + CliOnFail = None + # For debugging, uncomment the next line + #CliOnFail = 'tgen.mininet_cli' + CheckFunc = 'ltemplateVersionCheck(\'4.1\', iproute2=\'4.9\')' + #uncomment next line to start cli *before* script is run + #CheckFunc = 'ltemplateVersionCheck(\'4.1\', cli=True, iproute2=\'4.9\')' + ltemplateTest('scripts/check_linux_mpls.py', False, CliOnFail, CheckFunc) + +def test_del_bgp_instances(): + CliOnFail = None + # For debugging, uncomment the next line + #CliOnFail = 'tgen.mininet_cli' + CheckFunc = 'ltemplateVersionCheck(\'4.1\')' + #uncomment next line to start cli *before* script is run + #CheckFunc = 'ltemplateVersionCheck(\'4.1\', cli=True)' + ltemplateTest('scripts/del_bgp_instances.py', False, CliOnFail, CheckFunc) + +if __name__ == '__main__': + retval = pytest.main(["-s"]) + sys.exit(retval) diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py index ce542413ba..02fba97316 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py @@ -149,7 +149,9 @@ def ltemplatePreRouterStartHook(): krel = platform.release() tgen = get_topogen() logger.info('pre router-start hook, kernel=' + krel) - if topotest.version_cmp(krel, '4.15') == 0: + + if topotest.version_cmp(krel, '4.15') >= 0 and \ + topotest.version_cmp(krel, '4.18') <= 0: l3mdev_accept = 1 else: l3mdev_accept = 0 diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/del_bgp_instances.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/del_bgp_instances.py new file mode 100644 index 0000000000..c25c2d9ec5 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/del_bgp_instances.py @@ -0,0 +1,7 @@ +from lutil import luCommand + +luCommand('r1','/usr/lib/frr/vtysh -c "conf ter" -c "no router bgp 5227 vrf r1-cust1" -c "no router bgp 5226"','.','none','Cleared bgp instances') +luCommand('r2','/usr/lib/frr/vtysh -c "conf ter" -c "no router bgp 5226"','.','none','Cleared bgp instances') +luCommand('r3','/usr/lib/frr/vtysh -c "conf ter" -c "no router bgp 5227 vrf r3-cust1" -c "no router bgp 5226"','.','none','Cleared bgp instances') +luCommand('r4','/usr/lib/frr/vtysh -c "conf ter" -c "no router bgp 5228 vrf r4-cust2" -c "no router bgp 5227 vrf r4-cust1" -c "no router bgp 5226"','.','none','Cleared bgp instances') + diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_down.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_down.py index c17bf1168c..db53c1aacd 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_down.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_down.py @@ -6,14 +6,19 @@ if ret != False and found != None: luCommand('ce3', 'vtysh -c "show bgp sum"', '.', 'pass', 'See %s sharp routes' % num) if num > 0: + rtrs = ['ce1', 'ce2', 'ce3'] + for rtr in rtrs: + luCommand(rtr, 'vtysh -c "show bgp ipv4 uni" | grep Display','.', 'none', 'BGP routes pre remove') + luCommand(rtr, 'ip route show | cat -n | tail','.', 'none', 'Linux routes pre remove') wait = 2*num/500 luCommand('ce1', 'vtysh -c "sharp remove routes 10.0.0.0 {}"'.format(num),'.','none','Removing {} routes'.format(num)) luCommand('ce2', 'vtysh -c "sharp remove routes 10.0.0.0 {}"'.format(num),'.','none','Removing {} routes'.format(num)) - rtrs = ['ce1', 'ce2', 'ce3'] for rtr in rtrs: - luCommand(rtr, 'vtysh -c "show bgp ipv4 uni" | grep -c 10\\.\\*/32','^0$', 'wait', 'BGP routes removed', wait) + luCommand(rtr, 'vtysh -c "show bgp ipv4 uni" | grep Display',' 10 route', 'wait', 'BGP routes removed', wait) + luCommand(rtr, 'vtysh -c "show bgp ipv4 uni"','.', 'none', 'BGP routes post remove') for rtr in rtrs: luCommand(rtr, 'ip route show | grep -c \\^10\\.','^0$', 'wait', 'Linux routes removed', wait) + luCommand(rtr, 'ip route show','.', 'none', 'Linux routes post remove') rtrs = ['r1', 'r3', 'r4'] for rtr in rtrs: luCommand(rtr, 'ip route show vrf {}-cust1 | grep -c \\^10\\.'.format(rtr),'^0$','wait','VRF route removed',wait) diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_up.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_up.py index 7f114d10df..3619cdf84f 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_up.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_up.py @@ -11,14 +11,17 @@ if c > 0: else: d = r wait = 2*num/1000 -mem = {} +mem_z = {} +mem_b = {} rtrs = ['ce1', 'ce2', 'ce3', 'r1', 'r2', 'r3', 'r4'] for rtr in rtrs: - mem[rtr] = {'value': 0, 'units': 'unknown'} - ret = luCommand(rtr, 'vtysh -c "show memory"', 'bgpd: System allocator statistics: Total heap allocated: *(\d*) ([A-Za-z]*)', 'none', 'collect bgpd memory stats') + mem_z[rtr] = {'value': 0, 'units': 'unknown'} + mem_b[rtr] = {'value': 0, 'units': 'unknown'} + ret = luCommand(rtr, 'vtysh -c "show memory"', 'zebra: System allocator statistics: Total heap allocated: *(\d*) ([A-Za-z]*) .*bgpd: System allocator statistics: Total heap allocated: *(\d*) ([A-Za-z]*)', 'none', 'collect bgpd memory stats') found = luLast() if ret != False and found != None: - mem[rtr] = {'value': int(found.group(1)), 'units': found.group(2)} + mem_z[rtr] = {'value': int(found.group(1)), 'units': found.group(2)} + mem_b[rtr] = {'value': int(found.group(3)), 'units': found.group(4)} luCommand('ce1', 'vtysh -c "sharp data nexthop"', 'sharpd is not running', 'none','check if sharpd running') doSharp = True @@ -54,13 +57,20 @@ if doSharp == True: luCommand(rtr, 'ip route show vrf {}-cust1 | grep -c \\^10\\.'.format(rtr), str(num), 'wait','See {} linux routes'.format(num), wait) rtrs = ['ce1', 'ce2', 'ce3', 'r1', 'r2', 'r3', 'r4'] for rtr in rtrs: - ret = luCommand(rtr, 'vtysh -c "show memory"', 'bgpd: System allocator statistics: Total heap allocated: *(\d*) ([A-Za-z]*)', 'none', 'collect bgpd memory stats') + ret = luCommand(rtr, 'vtysh -c "show memory"', 'zebra: System allocator statistics: Total heap allocated: *(\d*) ([A-Za-z]*) .*bgpd: System allocator statistics: Total heap allocated: *(\d*) ([A-Za-z]*)', 'none', 'collect bgpd memory stats') found = luLast() if ret != False and found != None: - val = int(found.group(1)) - if mem[rtr]['units'] != found.group(2): - val *= 1000 - delta = val - int(mem[rtr]['value']) - ave = float(delta)/float(num) - luCommand(rtr, 'vtysh -c "show thread cpu"', '.', 'pass', 'BGPd heap: {0} {1} --> {2} {3} ({4} {1}/route)'.format(mem[rtr]['value'], mem[rtr]['units'], found.group(1), found.group(2), round(ave,4))) + val_z = int(found.group(1)) + if mem_z[rtr]['units'] != found.group(2): + val_z *= 1000 + delta_z = val_z - int(mem_z[rtr]['value']) + ave_z = float(delta_z)/float(num) + + val_b = int(found.group(3)) + if mem_b[rtr]['units'] != found.group(4): + val_b *= 1000 + delta_b = val_b - int(mem_b[rtr]['value']) + ave_b = float(delta_b)/float(num) + luCommand(rtr, 'vtysh -c "show thread cpu"', '.', 'pass', 'BGPd heap: {0} {1} --> {2} {3} ({4} {1}/vpn route)'.format(mem_b[rtr]['value'], mem_b[rtr]['units'], found.group(3), found.group(4), round(ave_b,4))) + luCommand(rtr, 'vtysh -c "show thread cpu"', '.', 'pass', 'Zebra heap: {0} {1} --> {2} {3} ({4} {1}/vpn route)'.format(mem_z[rtr]['value'], mem_z[rtr]['units'], found.group(1), found.group(2), round(ave_z,4))) #done diff --git a/tests/topotests/bgp_multiview_topo1/README.md b/tests/topotests/bgp_multiview_topo1/README.md index b9982d4900..c5e615d252 100644 --- a/tests/topotests/bgp_multiview_topo1/README.md +++ b/tests/topotests/bgp_multiview_topo1/README.md @@ -55,8 +55,6 @@ Simplified `R1` config: ip address 172.16.1.254/24 no link-detect ! - bgp multiple-instance - ! router bgp 100 view 1 bgp router-id 172.30.1.1 network 172.20.0.0/28 route-map local1 diff --git a/tests/topotests/bgp_multiview_topo1/r1/bgpd.conf b/tests/topotests/bgp_multiview_topo1/r1/bgpd.conf index 0c24942f43..71397a9942 100644 --- a/tests/topotests/bgp_multiview_topo1/r1/bgpd.conf +++ b/tests/topotests/bgp_multiview_topo1/r1/bgpd.conf @@ -11,8 +11,6 @@ log file bgpd.log !debug bgp filters !debug bgp zebra ! -bgp multiple-instance -! router bgp 100 view 1 bgp router-id 172.30.1.1 network 172.20.0.0/28 route-map local1 diff --git a/tests/topotests/lib/lutil.py b/tests/topotests/lib/lutil.py index 3ae18018bf..e58b4725eb 100755 --- a/tests/topotests/lib/lutil.py +++ b/tests/topotests/lib/lutil.py @@ -37,7 +37,7 @@ class lUtil: base_log_dir = '.' fout_name = 'output.log' fsum_name = 'summary.txt' - l_level = 9 + l_level = 6 CallOnFail = False l_total = 0 @@ -53,12 +53,12 @@ class lUtil: fsum = '' net = '' - def log(self, str): + def log(self, str, level=6): if self.l_level > 0: if self.fout == '': self.fout = open(self.fout_name, 'w', 0) self.fout.write(str+'\n') - if self.l_level > 5: + if level <= self.l_level: print(str) def summary(self, str): @@ -226,14 +226,16 @@ Total %-4d %-4d %d\n\ ret = success else: ret = search.group() - self.log('found:%s:' % ret) if op != 'fail': success = True + level = 7 else: success = False + level = 5 + self.log('found:%s:' % ret, level) # Experiment: compare matched strings obtained each way if self.l_dotall_experiment and (group_nl_converted != ret): - self.log('DOTALL experiment: strings differ dotall=[%s] orig=[%s]' % (group_nl_converted, ret)) + self.log('DOTALL experiment: strings differ dotall=[%s] orig=[%s]' % (group_nl_converted, ret), 9) if op == 'pass' or op == 'fail': self.result(target, success, result) if js != None: @@ -265,7 +267,7 @@ LUtil=None #entry calls def luStart(baseScriptDir='.', baseLogDir='.', net='', - fout='output.log', fsum='summary.txt', level=9): + fout='output.log', fsum='summary.txt', level=None): global LUtil #init class LUtil=lUtil() @@ -276,7 +278,8 @@ def luStart(baseScriptDir='.', baseLogDir='.', net='', LUtil.fout_name = baseLogDir + '/' + fout if fsum != None: LUtil.fsum_name = baseLogDir + '/' + fsum - LUtil.l_level = level + if level != None: + LUtil.l_level = level LUtil.l_dotall_experiment = False LUtil.l_dotall_experiment = True @@ -289,11 +292,11 @@ def luCommand(target, command, regexp='.', op='none', result='', time=10, return def luLast(usenl=False): if usenl: if LUtil.l_last_nl != None: - LUtil.log('luLast:%s:' % LUtil.l_last_nl.group()) + LUtil.log('luLast:%s:' % LUtil.l_last_nl.group(), 7) return LUtil.l_last_nl else: if LUtil.l_last != None: - LUtil.log('luLast:%s:' % LUtil.l_last.group()) + LUtil.log('luLast:%s:' % LUtil.l_last.group(), 7) return LUtil.l_last def luInclude(filename, CallOnFail=None): diff --git a/vrrpd/subdir.am b/vrrpd/subdir.am index a328f969d6..57eec108cb 100644 --- a/vrrpd/subdir.am +++ b/vrrpd/subdir.am @@ -14,7 +14,6 @@ vrrpd_libvrrp_a_SOURCES = \ vrrpd/vrrp.c \ vrrpd/vrrp_arp.c \ vrrpd/vrrp_debug.c \ - vrrpd/vrrp_memory.c \ vrrpd/vrrp_ndisc.c \ vrrpd/vrrp_packet.c \ vrrpd/vrrp_vty.c \ @@ -25,7 +24,6 @@ noinst_HEADERS += \ vrrpd/vrrp.h \ vrrpd/vrrp_arp.h \ vrrpd/vrrp_debug.h \ - vrrpd/vrrp_memory.h \ vrrpd/vrrp_ndisc.h \ vrrpd/vrrp_packet.h \ vrrpd/vrrp_vty.h \ diff --git a/vrrpd/vrrp.c b/vrrpd/vrrp.c index 3d535cbfba..5213b27d32 100644 --- a/vrrpd/vrrp.c +++ b/vrrpd/vrrp.c @@ -34,13 +34,15 @@ #include "vrrp.h" #include "vrrp_arp.h" #include "vrrp_debug.h" -#include "vrrp_memory.h" #include "vrrp_ndisc.h" #include "vrrp_packet.h" #include "vrrp_zebra.h" #define VRRP_LOGPFX "[CORE] " +DEFINE_MTYPE_STATIC(VRRPD, VRRP_IP, "VRRP IP address") +DEFINE_MTYPE_STATIC(VRRPD, VRRP_RTR, "VRRP Router") + /* statics */ struct hash *vrrp_vrouters_hash; bool vrrp_autoconfig_is_on; @@ -768,7 +770,7 @@ static void vrrp_send_advertisement(struct vrrp_router *r) ssize_t sent = sendto(r->sock_tx, pkt, (size_t)pktsz, 0, &dest.sa, sockunion_sizeof(&dest)); - XFREE(MTYPE_VRRP_PKT, pkt); + vrrp_pkt_free(pkt); if (sent < 0) { zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM diff --git a/vrrpd/vrrp.h b/vrrpd/vrrp.h index fd4901fe22..5d355d04b5 100644 --- a/vrrpd/vrrp.h +++ b/vrrpd/vrrp.h @@ -23,6 +23,7 @@ #include <zebra.h> #include <netinet/ip.h> +#include "lib/memory.h" #include "lib/hash.h" #include "lib/hook.h" #include "lib/if.h" @@ -54,6 +55,8 @@ /* User compatibility constant */ #define CS2MS 10 +DECLARE_MGROUP(VRRPD) + /* Configured defaults */ struct vrrp_defaults { uint8_t priority; diff --git a/vrrpd/vrrp_main.c b/vrrpd/vrrp_main.c index 46a92d936a..6afb418ad0 100644 --- a/vrrpd/vrrp_main.c +++ b/vrrpd/vrrp_main.c @@ -39,6 +39,8 @@ #include "vrrp_vty.h" #include "vrrp_zebra.h" +DEFINE_MGROUP(VRRPD, "vrrpd") + char backup_config_file[256]; zebra_capabilities_t _caps_p[] = { @@ -142,6 +144,7 @@ int main(int argc, char **argv, char **envp) master = frr_init(); + access_list_init(); vrrp_debug_init(); vrrp_zebra_init(); vrrp_vty_init(); diff --git a/vrrpd/vrrp_memory.c b/vrrpd/vrrp_memory.c deleted file mode 100644 index 30eef523cd..0000000000 --- a/vrrpd/vrrp_memory.c +++ /dev/null @@ -1,29 +0,0 @@ -/* - * VRRP memory types. - * Copyright (C) 2018-2019 Cumulus Networks, Inc. - * Quentin Young - * - * 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 "lib/memory.h" - -#include "vrrp_memory.h" - -DEFINE_MGROUP(VRRPD, "vrrpd"); -DEFINE_MTYPE(VRRPD, VRRP_IP, "VRRP IP address"); -DEFINE_MTYPE(VRRPD, VRRP_PKT, "VRRP packet"); -DEFINE_MTYPE(VRRPD, VRRP_RTR, "VRRP Router"); diff --git a/vrrpd/vrrp_memory.h b/vrrpd/vrrp_memory.h deleted file mode 100644 index c3025d1acb..0000000000 --- a/vrrpd/vrrp_memory.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * VRRP memory types. - * Copyright (C) 2018-2019 Cumulus Networks, Inc. - * Quentin Young - * - * 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 __VRRP_MEMORY_H__ -#define __VRRP_MEMORY_H__ - -#include <zebra.h> - -#include "lib/memory.h" - -DECLARE_MGROUP(VRRPD); -DECLARE_MTYPE(VRRP_IP); -DECLARE_MTYPE(VRRP_PKT); -DECLARE_MTYPE(VRRP_RTR); - -#endif /* __VRRP_MEMORY_H__ */ diff --git a/vrrpd/vrrp_packet.c b/vrrpd/vrrp_packet.c index c3f2afba4c..c6b7ac1a7f 100644 --- a/vrrpd/vrrp_packet.c +++ b/vrrpd/vrrp_packet.c @@ -28,9 +28,10 @@ #include "vrrp.h" #include "vrrp_debug.h" -#include "vrrp_memory.h" #include "vrrp_packet.h" +DEFINE_MTYPE_STATIC(VRRPD, VRRP_PKT, "VRRP packet") + /* clang-format off */ const char *vrrp_packet_names[16] = { [0] = "Unknown", @@ -151,6 +152,11 @@ ssize_t vrrp_pkt_adver_build(struct vrrp_pkt **pkt, struct ipaddr *src, return pktsize; } +void vrrp_pkt_free(struct vrrp_pkt *pkt) +{ + XFREE(MTYPE_VRRP_PKT, pkt); +} + size_t vrrp_pkt_adver_dump(char *buf, size_t buflen, struct vrrp_pkt *pkt) { if (buflen < 1) diff --git a/vrrpd/vrrp_packet.h b/vrrpd/vrrp_packet.h index 475e4780d5..c2ce22f008 100644 --- a/vrrpd/vrrp_packet.h +++ b/vrrpd/vrrp_packet.h @@ -135,6 +135,9 @@ ssize_t vrrp_pkt_adver_build(struct vrrp_pkt **pkt, struct ipaddr *src, uint16_t max_adver_int, uint8_t numip, struct ipaddr **ips); +/* free memory allocated by vrrp_pkt_adver_build's pkt arg */ +void vrrp_pkt_free(struct vrrp_pkt *pkt); + /* * Dumps a VRRP ADVERTISEMENT packet to a string. * diff --git a/vrrpd/vrrp_vty.c b/vrrpd/vrrp_vty.c index 48d81b0258..2dc3d3f8a3 100644 --- a/vrrpd/vrrp_vty.c +++ b/vrrpd/vrrp_vty.c @@ -29,7 +29,6 @@ #include "vrrp.h" #include "vrrp_debug.h" -#include "vrrp_memory.h" #include "vrrp_vty.h" #ifndef VTYSH_EXTRACT_PL #include "vrrpd/vrrp_vty_clippy.c" diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index 9c2de0f62b..b8957c2b00 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -373,6 +373,10 @@ void vtysh_config_parse_line(void *arg, const char *line) strlen("debug northbound")) == 0) config = config_get(NORTHBOUND_DEBUG_NODE, line); + else if (strncmp(line, "debug route-map", + strlen("debug route-map")) + == 0) + config = config_get(RMAP_DEBUG_NODE, line); else if (strncmp(line, "debug", strlen("debug")) == 0) config = config_get(DEBUG_NODE, line); else if (strncmp(line, "password", strlen("password")) == 0 @@ -418,7 +422,8 @@ void vtysh_config_parse_line(void *arg, const char *line) || (I) == ACCESS_IPV6_NODE || (I) == ACCESS_MAC_NODE \ || (I) == PREFIX_IPV6_NODE || (I) == FORWARDING_NODE \ || (I) == DEBUG_NODE || (I) == AAA_NODE || (I) == VRF_DEBUG_NODE \ - || (I) == NORTHBOUND_DEBUG_NODE || (I) == MPLS_NODE) + || (I) == NORTHBOUND_DEBUG_NODE || (I) == RMAP_DEBUG_NODE \ + || (I) == MPLS_NODE) /* Display configuration to file pointer. */ void vtysh_config_dump(void) diff --git a/vtysh/vtysh_user.c b/vtysh/vtysh_user.c index aaf70ab08b..17e5a7331c 100644 --- a/vtysh/vtysh_user.c +++ b/vtysh/vtysh_user.c @@ -62,35 +62,20 @@ static int vtysh_pam(const char *user) /* Start PAM. */ ret = pam_start(FRR_PAM_NAME, user, &conv, &pamh); - /* printf ("ret %d\n", ret); */ /* Is user really user? */ if (ret == PAM_SUCCESS) ret = pam_authenticate(pamh, 0); -/* printf ("ret %d\n", ret); */ -#if 0 - /* Permitted access? */ - if (ret == PAM_SUCCESS) - ret = pam_acct_mgmt (pamh, 0); - printf ("ret %d\n", ret); - - if (ret == PAM_AUTHINFO_UNAVAIL) - ret = PAM_SUCCESS; -#endif /* 0 */ - -/* This is where we have been authorized or not. */ -#ifdef DEBUG - if (ret == PAM_SUCCESS) - printf("Authenticated\n"); - else - printf("Not Authenticated\n"); -#endif /* DEBUG */ + if (ret != PAM_SUCCESS) + fprintf(stderr, "vtysh_pam: Failure to initialize pam: %s(%d)", + pam_strerror(pamh, ret), ret); /* close Linux-PAM */ if (pam_end(pamh, ret) != PAM_SUCCESS) { pamh = NULL; - fprintf(stderr, "vtysh_pam: failed to release authenticator\n"); + fprintf(stderr, "vtysh_pam: failed to release authenticator: %s(%d)\n", + pam_strerror(pamh, ret), ret); exit(1); } diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 4971994346..2c306434a3 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -129,8 +129,18 @@ static const struct message family_str[] = {{AF_INET, "ipv4"}, {RTNL_FAMILY_IP6MR, "ipv6MR"}, {0}}; -static const struct message rttype_str[] = {{RTN_UNICAST, "unicast"}, +static const struct message rttype_str[] = {{RTN_UNSPEC, "none"}, + {RTN_UNICAST, "unicast"}, + {RTN_LOCAL, "local"}, + {RTN_BROADCAST, "broadcast"}, + {RTN_ANYCAST, "anycast"}, {RTN_MULTICAST, "multicast"}, + {RTN_BLACKHOLE, "blackhole"}, + {RTN_UNREACHABLE, "unreachable"}, + {RTN_PROHIBIT, "prohibited"}, + {RTN_THROW, "throw"}, + {RTN_NAT, "nat"}, + {RTN_XRESOLVE, "resolver"}, {0}}; extern struct thread_master *master; diff --git a/zebra/main.c b/zebra/main.c index 5797a5846a..1947106750 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -55,6 +55,7 @@ #include "zebra/zebra_netns_notify.h" #include "zebra/zebra_rnh.h" #include "zebra/zebra_pbr.h" +#include "zebra/zebra_vxlan.h" #if defined(HANDLE_NETLINK_FUZZING) #include "zebra/kernel_netlink.h" @@ -455,6 +456,9 @@ int main(int argc, char **argv) /* RNH init */ zebra_rnh_init(); + /* Config handler Init */ + zebra_evpn_init(); + /* Error init */ zebra_error_init(); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 92c78a4cbb..b05d037f96 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -330,6 +330,10 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, bh_type = BLACKHOLE_ADMINPROHIB; break; default: + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("Route rtm_type: %s(%d) intentionally ignoring", + nl_rttype_to_str(rtm->rtm_type), + rtm->rtm_type); return 0; } @@ -2344,7 +2348,8 @@ static int netlink_macfdb_update(struct interface *ifp, vlanid_t vid, * 5549 support, re-install them. */ static void netlink_handle_5549(struct ndmsg *ndm, struct zebra_if *zif, - struct interface *ifp, struct ipaddr *ip) + struct interface *ifp, struct ipaddr *ip, + bool handle_failed) { if (ndm->ndm_family != AF_INET) return; @@ -2355,6 +2360,12 @@ static void netlink_handle_5549(struct ndmsg *ndm, struct zebra_if *zif, if (ipv4_ll.s_addr != ip->ip._v4_addr.s_addr) return; + if (handle_failed && ndm->ndm_state & NUD_FAILED) { + zlog_info("Neighbor Entry for %s has entered a failed state, not reinstalling", + ifp->name); + return; + } + if_nbr_ipv6ll_to_ipv4ll_neigh_update(ifp, &zif->v6_2_v4_ll_addr6, true); } @@ -2405,7 +2416,7 @@ 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); + netlink_handle_5549(ndm, zif, ifp, &ip, false); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( "\tNeighbor Entry Received is a 5549 entry, finished"); @@ -2414,7 +2425,7 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) /* if kernel marks our rfc5549 neighbor entry invalid, re-install it */ if (h->nlmsg_type == RTM_NEWNEIGH && !(ndm->ndm_state & NUD_VALID)) - netlink_handle_5549(ndm, zif, ifp, &ip); + netlink_handle_5549(ndm, zif, ifp, &ip, true); /* The neighbor is present on an SVI. From this, we locate the * underlying diff --git a/zebra/rtadv.c b/zebra/rtadv.c index e181b495b8..5841c44b03 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -50,6 +50,8 @@ extern struct zebra_privs_t zserv_privs; #if defined(HAVE_RTADV) +DEFINE_MTYPE_STATIC(ZEBRA, RTADV_PREFIX, "Router Advertisement Prefix") + #ifdef OPEN_BSD #include <netinet/icmp6.h> #endif diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index abe1879c26..f93562b31b 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -36,8 +36,8 @@ #include "zebra/debug.h" /* Memory type for context blocks */ -DEFINE_MTYPE(ZEBRA, DP_CTX, "Zebra DPlane Ctx") -DEFINE_MTYPE(ZEBRA, DP_PROV, "Zebra DPlane Provider") +DEFINE_MTYPE_STATIC(ZEBRA, DP_CTX, "Zebra DPlane Ctx") +DEFINE_MTYPE_STATIC(ZEBRA, DP_PROV, "Zebra DPlane Provider") #ifndef AOK # define AOK 0 diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c index 35a5d69ee3..32b9763c56 100644 --- a/zebra/zebra_fpm.c +++ b/zebra/zebra_fpm.c @@ -30,15 +30,21 @@ #include "network.h" #include "command.h" #include "version.h" +#include "jhash.h" #include "zebra/rib.h" #include "zebra/zserv.h" #include "zebra/zebra_ns.h" #include "zebra/zebra_vrf.h" #include "zebra/zebra_errors.h" +#include "zebra/zebra_memory.h" #include "fpm/fpm.h" #include "zebra_fpm_private.h" +#include "zebra/zebra_router.h" +#include "zebra_vxlan_private.h" + +DEFINE_MTYPE_STATIC(ZEBRA, FPM_MAC_INFO, "FPM_MAC_INFO"); /* * Interval at which we attempt to connect to the FPM. @@ -62,6 +68,9 @@ * Interval over which we collect statistics. */ #define ZFPM_STATS_IVL_SECS 10 +#define FPM_MAX_MAC_MSG_LEN 512 + +static void zfpm_iterate_rmac_table(struct hash_backet *backet, void *args); /* * Structure that holds state for iterating over all route_node @@ -179,6 +188,25 @@ typedef struct zfpm_glob_t_ { TAILQ_HEAD(zfpm_dest_q, rib_dest_t_) dest_q; /* + * List of fpm_mac_info structures to be processed + */ + TAILQ_HEAD(zfpm_mac_q, fpm_mac_info_t) mac_q; + + /* + * Hash table of fpm_mac_info_t entries + * + * While adding fpm_mac_info_t for a MAC to the mac_q, + * it is possible that another fpm_mac_info_t node for the this MAC + * is already present in the queue. + * This is possible in the case of consecutive add->delete operations. + * To avoid such duplicate insertions in the mac_q, + * define a hash table for fpm_mac_info_t which can be looked up + * to see if an fpm_mac_info_t node for a MAC is already present + * in the mac_q. + */ + struct hash *fpm_mac_info_table; + + /* * Stream socket to the FPM. */ int sock; @@ -259,6 +287,7 @@ static int zfpm_write_cb(struct thread *thread); static void zfpm_set_state(zfpm_state_t state, const char *reason); static void zfpm_start_connect_timer(const char *reason); static void zfpm_start_stats_timer(void); +static void zfpm_mac_info_del(struct fpm_mac_info_t *fpm_mac); /* * zfpm_thread_should_yield @@ -492,6 +521,9 @@ static int zfpm_conn_up_thread_cb(struct thread *thread) goto done; } + /* Enqueue FPM updates for all the RMAC entries */ + hash_iterate(zrouter.l3vni_table, zfpm_iterate_rmac_table, NULL); + while ((rnode = zfpm_rnodes_iter_next(iter))) { dest = rib_dest_from_rnode(rnode); @@ -591,9 +623,17 @@ static int zfpm_conn_down_thread_cb(struct thread *thread) struct route_node *rnode; zfpm_rnodes_iter_t *iter; rib_dest_t *dest; + struct fpm_mac_info_t *mac = NULL; assert(zfpm_g->state == ZFPM_STATE_IDLE); + /* + * Delink and free all fpm_mac_info_t nodes + * in the mac_q and fpm_mac_info_hash + */ + while ((mac = TAILQ_FIRST(&zfpm_g->mac_q)) != NULL) + zfpm_mac_info_del(mac); + zfpm_g->t_conn_down = NULL; iter = &zfpm_g->t_conn_down_state.iter; @@ -778,6 +818,14 @@ done: return 0; } +static bool zfpm_updates_pending(void) +{ + if (!(TAILQ_EMPTY(&zfpm_g->dest_q)) || !(TAILQ_EMPTY(&zfpm_g->mac_q))) + return true; + + return false; +} + /* * zfpm_writes_pending * @@ -794,9 +842,9 @@ static int zfpm_writes_pending(void) return 1; /* - * Check if there are any prefixes on the outbound queue. + * Check if there are any updates scheduled on the outbound queues. */ - if (!TAILQ_EMPTY(&zfpm_g->dest_q)) + if (zfpm_updates_pending()) return 1; return 0; @@ -861,12 +909,29 @@ struct route_entry *zfpm_route_for_update(rib_dest_t *dest) } /* - * zfpm_build_updates + * Define an enum for return codes for queue processing functions * - * Process the outgoing queue and write messages to the outbound - * buffer. + * FPM_WRITE_STOP: This return code indicates that the write buffer is full. + * Stop processing all the queues and empty the buffer by writing its content + * to the socket. + * + * FPM_GOTO_NEXT_Q: This return code indicates that either this queue is + * empty or we have processed enough updates from this queue. + * So, move on to the next queue. */ -static void zfpm_build_updates(void) +enum { + FPM_WRITE_STOP = 0, + FPM_GOTO_NEXT_Q = 1 +}; + +#define FPM_QUEUE_PROCESS_LIMIT 10000 + +/* + * zfpm_build_route_updates + * + * Process the dest_q queue and write FPM messages to the outbound buffer. + */ +static int zfpm_build_route_updates(void) { struct stream *s; rib_dest_t *dest; @@ -877,25 +942,27 @@ static void zfpm_build_updates(void) struct route_entry *re; int is_add, write_msg; fpm_msg_type_e msg_type; + uint16_t q_limit; - s = zfpm_g->obuf; + if (TAILQ_EMPTY(&zfpm_g->dest_q)) + return FPM_GOTO_NEXT_Q; - assert(stream_empty(s)); - - do { + s = zfpm_g->obuf; + q_limit = FPM_QUEUE_PROCESS_LIMIT; + do { /* * Make sure there is enough space to write another message. */ if (STREAM_WRITEABLE(s) < FPM_MAX_MSG_LEN) - break; + return FPM_WRITE_STOP; buf = STREAM_DATA(s) + stream_get_endp(s); buf_end = buf + STREAM_WRITEABLE(s); dest = TAILQ_FIRST(&zfpm_g->dest_q); if (!dest) - break; + return FPM_GOTO_NEXT_Q; assert(CHECK_FLAG(dest->flags, RIB_DEST_UPDATE_FPM)); @@ -955,10 +1022,136 @@ static void zfpm_build_updates(void) if (rib_gc_dest(dest->rnode)) zfpm_g->stats.dests_del_after_update++; + q_limit--; + if (q_limit == 0) { + /* + * We have processed enough updates in this queue. + * Now yield for other queues. + */ + return FPM_GOTO_NEXT_Q; + } + } while (true); +} + +/* + * zfpm_encode_mac + * + * Encode a message to FPM with information about the given MAC. + * + * Returns the number of bytes written to the buffer. + */ +static inline int zfpm_encode_mac(struct fpm_mac_info_t *mac, char *in_buf, + size_t in_buf_len, fpm_msg_type_e *msg_type) +{ + size_t len = 0; + + *msg_type = FPM_MSG_TYPE_NONE; + + switch (zfpm_g->message_format) { + + case ZFPM_MSG_FORMAT_NONE: + break; + case ZFPM_MSG_FORMAT_NETLINK: +#ifdef HAVE_NETLINK + len = zfpm_netlink_encode_mac(mac, in_buf, in_buf_len); + assert(fpm_msg_align(len) == len); + *msg_type = FPM_MSG_TYPE_NETLINK; +#endif /* HAVE_NETLINK */ + break; + case ZFPM_MSG_FORMAT_PROTOBUF: + break; + } + return len; +} + +static int zfpm_build_mac_updates(void) +{ + struct stream *s; + struct fpm_mac_info_t *mac; + unsigned char *buf, *data, *buf_end; + fpm_msg_hdr_t *hdr; + size_t data_len, msg_len; + fpm_msg_type_e msg_type; + uint16_t q_limit; + + if (TAILQ_EMPTY(&zfpm_g->mac_q)) + return FPM_GOTO_NEXT_Q; + + s = zfpm_g->obuf; + q_limit = FPM_QUEUE_PROCESS_LIMIT; + + do { + /* Make sure there is enough space to write another message. */ + if (STREAM_WRITEABLE(s) < FPM_MAX_MAC_MSG_LEN) + return FPM_WRITE_STOP; + + buf = STREAM_DATA(s) + stream_get_endp(s); + buf_end = buf + STREAM_WRITEABLE(s); + + mac = TAILQ_FIRST(&zfpm_g->mac_q); + if (!mac) + return FPM_GOTO_NEXT_Q; + + /* Check for no-op */ + if (!CHECK_FLAG(mac->fpm_flags, ZEBRA_MAC_UPDATE_FPM)) { + zfpm_g->stats.nop_deletes_skipped++; + zfpm_mac_info_del(mac); + continue; + } + + hdr = (fpm_msg_hdr_t *)buf; + hdr->version = FPM_PROTO_VERSION; + + data = fpm_msg_data(hdr); + data_len = zfpm_encode_mac(mac, (char *)data, buf_end - data, + &msg_type); + assert(data_len); + + hdr->msg_type = msg_type; + msg_len = fpm_data_len_to_msg_len(data_len); + hdr->msg_len = htons(msg_len); + stream_forward_endp(s, msg_len); + + /* Remove the MAC from the queue, and delete it. */ + zfpm_mac_info_del(mac); + + q_limit--; + if (q_limit == 0) { + /* + * We have processed enough updates in this queue. + * Now yield for other queues. + */ + return FPM_GOTO_NEXT_Q; + } } while (1); } /* + * zfpm_build_updates + * + * Process the outgoing queues and write messages to the outbound + * buffer. + */ +static void zfpm_build_updates(void) +{ + struct stream *s; + + s = zfpm_g->obuf; + assert(stream_empty(s)); + + do { + /* + * Stop processing the queues if zfpm_g->obuf is full + * or we do not have more updates to process + */ + if (zfpm_build_mac_updates() == FPM_WRITE_STOP) + break; + if (zfpm_build_route_updates() == FPM_WRITE_STOP) + break; + } while (zfpm_updates_pending()); +} + +/* * zfpm_write_cb */ static int zfpm_write_cb(struct thread *thread) @@ -1277,6 +1470,207 @@ static int zfpm_trigger_update(struct route_node *rn, const char *reason) } /* + * Generate Key for FPM MAC info hash entry + * Key is generated using MAC address and VNI id which should be sufficient + * to provide uniqueness + */ +static unsigned int zfpm_mac_info_hash_keymake(const void *p) +{ + struct fpm_mac_info_t *fpm_mac = (struct fpm_mac_info_t *)p; + uint32_t mac_key; + + mac_key = jhash(fpm_mac->macaddr.octet, ETH_ALEN, 0xa5a5a55a); + + return jhash_2words(mac_key, fpm_mac->vni, 0); +} + +/* + * Compare function for FPM MAC info hash lookup + */ +static bool zfpm_mac_info_cmp(const void *p1, const void *p2) +{ + const struct fpm_mac_info_t *fpm_mac1 = p1; + const struct fpm_mac_info_t *fpm_mac2 = p2; + + if (memcmp(fpm_mac1->macaddr.octet, fpm_mac2->macaddr.octet, ETH_ALEN) + != 0) + return false; + if (fpm_mac1->r_vtep_ip.s_addr != fpm_mac2->r_vtep_ip.s_addr) + return false; + if (fpm_mac1->vni != fpm_mac2->vni) + return false; + + return true; +} + +/* + * Lookup FPM MAC info hash entry. + */ +static struct fpm_mac_info_t *zfpm_mac_info_lookup(struct fpm_mac_info_t *key) +{ + return hash_lookup(zfpm_g->fpm_mac_info_table, key); +} + +/* + * Callback to allocate fpm_mac_info_t structure. + */ +static void *zfpm_mac_info_alloc(void *p) +{ + const struct fpm_mac_info_t *key = p; + struct fpm_mac_info_t *fpm_mac; + + fpm_mac = XCALLOC(MTYPE_FPM_MAC_INFO, sizeof(struct fpm_mac_info_t)); + + memcpy(&fpm_mac->macaddr, &key->macaddr, ETH_ALEN); + memcpy(&fpm_mac->r_vtep_ip, &key->r_vtep_ip, sizeof(struct in_addr)); + fpm_mac->vni = key->vni; + + return (void *)fpm_mac; +} + +/* + * Delink and free fpm_mac_info_t. + */ +static void zfpm_mac_info_del(struct fpm_mac_info_t *fpm_mac) +{ + hash_release(zfpm_g->fpm_mac_info_table, fpm_mac); + TAILQ_REMOVE(&zfpm_g->mac_q, fpm_mac, fpm_mac_q_entries); + XFREE(MTYPE_FPM_MAC_INFO, fpm_mac); +} + +/* + * zfpm_trigger_rmac_update + * + * Zebra code invokes this function to indicate that we should + * send an update to FPM for given MAC entry. + * + * This function checks if we already have enqueued an update for this RMAC, + * If yes, update the same fpm_mac_info_t. Else, create and enqueue an update. + */ +static int zfpm_trigger_rmac_update(zebra_mac_t *rmac, zebra_l3vni_t *zl3vni, + bool delete, const char *reason) +{ + char buf[ETHER_ADDR_STRLEN]; + struct fpm_mac_info_t *fpm_mac, key; + struct interface *vxlan_if, *svi_if; + + /* + * Ignore if the connection is down. We will update the FPM about + * all destinations once the connection comes up. + */ + if (!zfpm_conn_is_up()) + return 0; + + if (reason) { + zfpm_debug("triggering update to FPM - Reason: %s - %s", + reason, + prefix_mac2str(&rmac->macaddr, buf, sizeof(buf))); + } + + vxlan_if = zl3vni_map_to_vxlan_if(zl3vni); + svi_if = zl3vni_map_to_svi_if(zl3vni); + + memset(&key, 0, sizeof(struct fpm_mac_info_t)); + + memcpy(&key.macaddr, &rmac->macaddr, ETH_ALEN); + key.r_vtep_ip.s_addr = rmac->fwd_info.r_vtep_ip.s_addr; + key.vni = zl3vni->vni; + + /* Check if this MAC is already present in the queue. */ + fpm_mac = zfpm_mac_info_lookup(&key); + + if (fpm_mac) { + if (!!CHECK_FLAG(fpm_mac->fpm_flags, ZEBRA_MAC_DELETE_FPM) + == delete) { + /* + * MAC is already present in the queue + * with the same op as this one. Do nothing + */ + zfpm_g->stats.redundant_triggers++; + return 0; + } + + /* + * A new op for an already existing fpm_mac_info_t node. + * Update the existing node for the new op. + */ + if (!delete) { + /* + * New op is "add". Previous op is "delete". + * Update the fpm_mac_info_t for the new add. + */ + fpm_mac->zebra_flags = rmac->flags; + + fpm_mac->vxlan_if = vxlan_if ? vxlan_if->ifindex : 0; + fpm_mac->svi_if = svi_if ? svi_if->ifindex : 0; + + UNSET_FLAG(fpm_mac->fpm_flags, ZEBRA_MAC_DELETE_FPM); + SET_FLAG(fpm_mac->fpm_flags, ZEBRA_MAC_UPDATE_FPM); + } else { + /* + * New op is "delete". Previous op is "add". + * Thus, no-op. Unset ZEBRA_MAC_UPDATE_FPM flag. + */ + SET_FLAG(fpm_mac->fpm_flags, ZEBRA_MAC_DELETE_FPM); + UNSET_FLAG(fpm_mac->fpm_flags, ZEBRA_MAC_UPDATE_FPM); + } + + return 0; + } + + fpm_mac = hash_get(zfpm_g->fpm_mac_info_table, &key, + zfpm_mac_info_alloc); + if (!fpm_mac) + return 0; + + fpm_mac->zebra_flags = rmac->flags; + fpm_mac->vxlan_if = vxlan_if ? vxlan_if->ifindex : 0; + fpm_mac->svi_if = svi_if ? svi_if->ifindex : 0; + + SET_FLAG(fpm_mac->fpm_flags, ZEBRA_MAC_UPDATE_FPM); + if (delete) + SET_FLAG(fpm_mac->fpm_flags, ZEBRA_MAC_DELETE_FPM); + + TAILQ_INSERT_TAIL(&zfpm_g->mac_q, fpm_mac, fpm_mac_q_entries); + + zfpm_g->stats.updates_triggered++; + + /* If writes are already enabled, return. */ + if (zfpm_g->t_write) + return 0; + + zfpm_write_on(); + return 0; +} + +/* + * This function is called when the FPM connections is established. + * Iterate over all the RMAC entries for the given L3VNI + * and enqueue the RMAC for FPM processing. + */ +static void zfpm_trigger_rmac_update_wrapper(struct hash_backet *backet, + void *args) +{ + zebra_mac_t *zrmac = (zebra_mac_t *)backet->data; + zebra_l3vni_t *zl3vni = (zebra_l3vni_t *)args; + + zfpm_trigger_rmac_update(zrmac, zl3vni, false, "RMAC added"); +} + +/* + * This function is called when the FPM connections is established. + * This function iterates over all the L3VNIs to trigger + * FPM updates for RMACs currently available. + */ +static void zfpm_iterate_rmac_table(struct hash_backet *backet, void *args) +{ + zebra_l3vni_t *zl3vni = (zebra_l3vni_t *)backet->data; + + hash_iterate(zl3vni->rmac_table, zfpm_trigger_rmac_update_wrapper, + (void *)zl3vni); +} + +/* * zfpm_stats_timer_cb */ static int zfpm_stats_timer_cb(struct thread *t) @@ -1589,6 +1983,13 @@ static int zfpm_init(struct thread_master *master) memset(zfpm_g, 0, sizeof(*zfpm_g)); zfpm_g->master = master; TAILQ_INIT(&zfpm_g->dest_q); + TAILQ_INIT(&zfpm_g->mac_q); + + /* Create hash table for fpm_mac_info_t enties */ + zfpm_g->fpm_mac_info_table = hash_create(zfpm_mac_info_hash_keymake, + zfpm_mac_info_cmp, + "FPM MAC info hash table"); + zfpm_g->sock = -1; zfpm_g->state = ZFPM_STATE_IDLE; @@ -1631,6 +2032,7 @@ static int zfpm_init(struct thread_master *master) static int zebra_fpm_module_init(void) { hook_register(rib_update, zfpm_trigger_update); + hook_register(zebra_rmac_update, zfpm_trigger_rmac_update); hook_register(frr_late_init, zfpm_init); return 0; } diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c index 2ac79b100c..d5479bc627 100644 --- a/zebra/zebra_fpm_netlink.c +++ b/zebra/zebra_fpm_netlink.c @@ -580,4 +580,67 @@ int zfpm_netlink_encode_route(int cmd, rib_dest_t *dest, struct route_entry *re, return netlink_route_info_encode(ri, in_buf, in_buf_len); } +/* + * zfpm_netlink_encode_mac + * + * Create a netlink message corresponding to the given MAC. + * + * Returns the number of bytes written to the buffer. 0 or a negative + * value indicates an error. + */ +int zfpm_netlink_encode_mac(struct fpm_mac_info_t *mac, char *in_buf, + size_t in_buf_len) +{ + char buf1[ETHER_ADDR_STRLEN]; + size_t buf_offset; + + struct macmsg { + struct nlmsghdr hdr; + struct ndmsg ndm; + char buf[0]; + } *req; + req = (void *)in_buf; + + buf_offset = offsetof(struct macmsg, buf); + if (in_buf_len < buf_offset) + return 0; + memset(req, 0, buf_offset); + + /* Construct nlmsg header */ + req->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); + req->hdr.nlmsg_type = CHECK_FLAG(mac->fpm_flags, ZEBRA_MAC_DELETE_FPM) ? + RTM_DELNEIGH : RTM_NEWNEIGH; + req->hdr.nlmsg_flags = NLM_F_REQUEST; + if (req->hdr.nlmsg_type == RTM_NEWNEIGH) + req->hdr.nlmsg_flags |= (NLM_F_CREATE | NLM_F_REPLACE); + + /* Construct ndmsg */ + req->ndm.ndm_family = AF_BRIDGE; + req->ndm.ndm_ifindex = mac->vxlan_if; + + req->ndm.ndm_state = NUD_REACHABLE; + req->ndm.ndm_flags |= NTF_SELF | NTF_MASTER; + if (CHECK_FLAG(mac->zebra_flags, + (ZEBRA_MAC_STICKY | ZEBRA_MAC_REMOTE_DEF_GW))) + req->ndm.ndm_state |= NUD_NOARP; + else + req->ndm.ndm_flags |= NTF_EXT_LEARNED; + + /* Add attributes */ + addattr_l(&req->hdr, in_buf_len, NDA_LLADDR, &mac->macaddr, 6); + addattr_l(&req->hdr, in_buf_len, NDA_DST, &mac->r_vtep_ip, 4); + addattr32(&req->hdr, in_buf_len, NDA_MASTER, mac->svi_if); + addattr32(&req->hdr, in_buf_len, NDA_VNI, mac->vni); + + assert(req->hdr.nlmsg_len < in_buf_len); + + zfpm_debug("Tx %s family %s ifindex %u MAC %s DEST %s", + nl_msg_type_to_str(req->hdr.nlmsg_type), + nl_family_to_str(req->ndm.ndm_family), req->ndm.ndm_ifindex, + prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1)), + inet_ntoa(mac->r_vtep_ip)); + + return req->hdr.nlmsg_len; +} + #endif /* HAVE_NETLINK */ diff --git a/zebra/zebra_fpm_private.h b/zebra/zebra_fpm_private.h index 943aad9864..c169ee8c22 100644 --- a/zebra/zebra_fpm_private.h +++ b/zebra/zebra_fpm_private.h @@ -53,6 +53,34 @@ static inline void zfpm_debug(const char *format, ...) } #endif +/* This structure contains the MAC addresses enqueued for FPM processing. */ +struct fpm_mac_info_t { + struct ethaddr macaddr; + uint32_t zebra_flags; /* Could be used to build FPM messages */ + vni_t vni; + ifindex_t vxlan_if; + ifindex_t svi_if; /* L2 or L3 Bridge interface */ + struct in_addr r_vtep_ip; /* Remote VTEP IP */ + + /* Linkage to put MAC on the FPM processing queue. */ + TAILQ_ENTRY(fpm_mac_info_t) fpm_mac_q_entries; + + uint8_t fpm_flags; + +#define ZEBRA_MAC_UPDATE_FPM 0x1 /* This flag indicates if we want to upadte + * data plane for this MAC. If a MAC is added + * and then deleted immediately, we do not want + * to update data plane for such operation. + * Unset the ZEBRA_MAC_UPDATE_FPM flag in this + * case. FPM thread while processing the queue + * node will check this flag and dequeue the + * node silently without sending any update to + * the data plane. + */ +#define ZEBRA_MAC_DELETE_FPM 0x2 /* This flag is set if it is a delete operation + * for the MAC. + */ +}; /* * Externs @@ -64,6 +92,9 @@ extern int zfpm_netlink_encode_route(int cmd, rib_dest_t *dest, extern int zfpm_protobuf_encode_route(rib_dest_t *dest, struct route_entry *re, uint8_t *in_buf, size_t in_buf_len); +extern int zfpm_netlink_encode_mac(struct fpm_mac_info_t *mac, char *in_buf, + size_t in_buf_len); + extern struct route_entry *zfpm_route_for_update(rib_dest_t *dest); #ifdef __cplusplus diff --git a/zebra/zebra_memory.c b/zebra/zebra_memory.c index ee041b1c3d..a9c2c5fe58 100644 --- a/zebra/zebra_memory.c +++ b/zebra/zebra_memory.c @@ -26,11 +26,5 @@ #include "zebra_memory.h" DEFINE_MGROUP(ZEBRA, "zebra") -DEFINE_MTYPE(ZEBRA, RTADV_PREFIX, "Router Advertisement Prefix") -DEFINE_MTYPE(ZEBRA, ZEBRA_VRF, "ZEBRA VRF") DEFINE_MTYPE(ZEBRA, RE, "Route Entry") -DEFINE_MTYPE(ZEBRA, RIB_QUEUE, "RIB process work queue") -DEFINE_MTYPE(ZEBRA, STATIC_ROUTE, "Static route") DEFINE_MTYPE(ZEBRA, RIB_DEST, "RIB destination") -DEFINE_MTYPE(ZEBRA, RIB_TABLE_INFO, "RIB table info") -DEFINE_MTYPE(ZEBRA, RNH, "Nexthop tracking object") diff --git a/zebra/zebra_memory.h b/zebra/zebra_memory.h index 667c73b227..e15f972493 100644 --- a/zebra/zebra_memory.h +++ b/zebra/zebra_memory.h @@ -29,17 +29,9 @@ extern "C" { #endif DECLARE_MGROUP(ZEBRA) -DECLARE_MTYPE(RTADV_PREFIX) DECLARE_MTYPE(ZEBRA_NS) -DECLARE_MTYPE(ZEBRA_VRF) DECLARE_MTYPE(RE) -DECLARE_MTYPE(RIB_QUEUE) -DECLARE_MTYPE(STATIC_ROUTE) DECLARE_MTYPE(RIB_DEST) -DECLARE_MTYPE(RIB_TABLE_INFO) -DECLARE_MTYPE(RNH) -DECLARE_MTYPE(DP_CTX) -DECLARE_MTYPE(DP_PROV) #ifdef __cplusplus } diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index cc614abac5..2df24f75c5 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -744,9 +744,10 @@ void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq) if (IS_ZEBRA_DEBUG_NHT_DETAILED) { char buf[PREFIX_STRLEN]; - zlog_debug("%s: %s Being examined for Nexthop Tracking", + zlog_debug("%s: %s Being examined for Nexthop Tracking Count: %zd", __PRETTY_FUNCTION__, - srcdest_rnode2str(rn, buf, sizeof(buf))); + srcdest_rnode2str(rn, buf, sizeof(buf)), + dest ? rnh_list_count(&dest->nht) : 0); } if (!dest) { rn = rn->parent; @@ -760,7 +761,7 @@ void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq) * nht resolution and as such we need to call the * nexthop tracking evaluation code */ - frr_each (rnh_list, &dest->nht, rnh) { + frr_each_safe(rnh_list, &dest->nht, rnh) { struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(rnh->vrf_id); struct prefix *p = &rnh->node->p; @@ -769,11 +770,12 @@ void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq) char buf1[PREFIX_STRLEN]; char buf2[PREFIX_STRLEN]; - zlog_debug("%u:%s has Nexthop(%s) depending on it, evaluating %u:%u", + zlog_debug("%u:%s has Nexthop(%s) Type: %s depending on it, evaluating %u:%u", zvrf->vrf->vrf_id, srcdest_rnode2str(rn, buf1, sizeof(buf1)), prefix2str(p, buf2, sizeof(buf2)), + rnh_type2str(rnh->type), seq, rnh->seqno); } @@ -2442,6 +2444,7 @@ void _route_entry_dump(const char *func, union prefixconstptr pp, bool is_srcdst = src_p && src_p->prefixlen; char straddr[PREFIX_STRLEN]; char srcaddr[PREFIX_STRLEN]; + char nhname[PREFIX_STRLEN]; struct nexthop *nexthop; zlog_debug("%s: dumping RE entry %p for %s%s%s vrf %u", func, @@ -2451,12 +2454,12 @@ void _route_entry_dump(const char *func, union prefixconstptr pp, : "", re->vrf_id); zlog_debug("%s: uptime == %lu, type == %u, instance == %d, table == %d", - func, (unsigned long)re->uptime, re->type, re->instance, + straddr, (unsigned long)re->uptime, re->type, re->instance, re->table); zlog_debug( "%s: metric == %u, mtu == %u, distance == %u, flags == %u, status == %u", - func, re->metric, re->mtu, re->distance, re->flags, re->status); - zlog_debug("%s: nexthop_num == %u, nexthop_active_num == %u", func, + straddr, re->metric, re->mtu, re->distance, re->flags, re->status); + zlog_debug("%s: nexthop_num == %u, nexthop_active_num == %u", straddr, re->nexthop_num, re->nexthop_active_num); for (ALL_NEXTHOPS(re->ng, nexthop)) { @@ -2465,27 +2468,27 @@ void _route_entry_dump(const char *func, union prefixconstptr pp, switch (nexthop->type) { case NEXTHOP_TYPE_BLACKHOLE: - sprintf(straddr, "Blackhole"); + sprintf(nhname, "Blackhole"); break; case NEXTHOP_TYPE_IFINDEX: ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id); - sprintf(straddr, "%s", ifp ? ifp->name : "Unknown"); + sprintf(nhname, "%s", ifp ? ifp->name : "Unknown"); break; case NEXTHOP_TYPE_IPV4: /* fallthrough */ case NEXTHOP_TYPE_IPV4_IFINDEX: - inet_ntop(AF_INET, &nexthop->gate, straddr, + inet_ntop(AF_INET, &nexthop->gate, nhname, INET6_ADDRSTRLEN); break; case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6_IFINDEX: - inet_ntop(AF_INET6, &nexthop->gate, straddr, + inet_ntop(AF_INET6, &nexthop->gate, nhname, INET6_ADDRSTRLEN); break; } zlog_debug("%s: %s %s[%u] vrf %s(%u) with flags %s%s%s%s%s%s", - func, (nexthop->rparent ? " NH" : "NH"), straddr, + straddr, (nexthop->rparent ? " NH" : "NH"), nhname, nexthop->ifindex, vrf ? vrf->name : "Unknown", nexthop->vrf_id, (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) @@ -2507,7 +2510,7 @@ void _route_entry_dump(const char *func, union prefixconstptr pp, ? "DUPLICATE " : "")); } - zlog_debug("%s: dump complete", func); + zlog_debug("%s: dump complete", straddr); } /* This is an exported helper to rtm_read() to dump the strange diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 1024f3a052..6f65f8ab7a 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -50,6 +50,8 @@ #include "zebra/zebra_memory.h" #include "zebra/zebra_errors.h" +DEFINE_MTYPE_STATIC(ZEBRA, RNH, "Nexthop tracking object") + static void free_state(vrf_id_t vrf_id, struct route_entry *re, struct route_node *rn); static void copy_state(struct rnh *rnh, struct route_entry *re, @@ -160,14 +162,15 @@ struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type, if (IS_ZEBRA_DEBUG_NHT) { prefix2str(p, buf, sizeof(buf)); - zlog_debug("%u: Add RNH %s type %d", vrfid, buf, type); + zlog_debug("%u: Add RNH %s type %s", vrfid, buf, + rnh_type2str(type)); } table = get_rnh_table(vrfid, afi, type); if (!table) { prefix2str(p, buf, sizeof(buf)); flog_warn(EC_ZEBRA_RNH_NO_TABLE, - "%u: Add RNH %s type %d - table not found", vrfid, - buf, type); + "%u: Add RNH %s type %s - table not found", vrfid, + buf, rnh_type2str(type)); exists = false; return NULL; } @@ -271,8 +274,8 @@ static void zebra_delete_rnh(struct rnh *rnh, rnh_type_t type) if (IS_ZEBRA_DEBUG_NHT) { char buf[PREFIX2STR_BUFFER]; - zlog_debug("%u: Del RNH %s type %d", rnh->vrf_id, - rnh_str(rnh, buf, sizeof(buf)), type); + zlog_debug("%u: Del RNH %s type %s", rnh->vrf_id, + rnh_str(rnh, buf, sizeof(buf)), rnh_type2str(type)); } zebra_free_rnh(rnh); @@ -293,9 +296,9 @@ void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client, { if (IS_ZEBRA_DEBUG_NHT) { char buf[PREFIX2STR_BUFFER]; - zlog_debug("%u: Client %s registers for RNH %s type %d", vrf_id, + zlog_debug("%u: Client %s registers for RNH %s type %s", vrf_id, zebra_route_string(client->proto), - rnh_str(rnh, buf, sizeof(buf)), type); + rnh_str(rnh, buf, sizeof(buf)), rnh_type2str(type)); } if (!listnode_lookup(rnh->client_list, client)) listnode_add(rnh->client_list, client); @@ -312,9 +315,9 @@ void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client, { if (IS_ZEBRA_DEBUG_NHT) { char buf[PREFIX2STR_BUFFER]; - zlog_debug("Client %s unregisters for RNH %s type %d", + zlog_debug("Client %s unregisters for RNH %s type %s", zebra_route_string(client->proto), - rnh_str(rnh, buf, sizeof(buf)), type); + rnh_str(rnh, buf, sizeof(buf)), rnh_type2str(type)); } listnode_delete(rnh->client_list, client); zebra_delete_rnh(rnh, type); @@ -756,7 +759,7 @@ static void zebra_rnh_eval_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi, * change. */ zebra_rnh_remove_from_routing_table(rnh); - if (!prefix_same(&rnh->resolved_route, prn ? NULL : &prn->p)) { + if (!prefix_same(&rnh->resolved_route, prn ? &prn->p : NULL)) { if (prn) prefix_copy(&rnh->resolved_route, &prn->p); else { @@ -803,8 +806,8 @@ static void zebra_rnh_evaluate_entry(struct zebra_vrf *zvrf, afi_t afi, if (IS_ZEBRA_DEBUG_NHT) { prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN); - zlog_debug("%u:%s: Evaluate RNH, type %d %s", zvrf->vrf->vrf_id, - bufn, type, force ? "(force)" : ""); + zlog_debug("%u:%s: Evaluate RNH, type %s %s", zvrf->vrf->vrf_id, + bufn, rnh_type2str(type), force ? "(force)" : ""); } rnh = nrn->info; @@ -962,7 +965,6 @@ static void copy_state(struct rnh *rnh, struct route_entry *re, static int compare_state(struct route_entry *r1, struct route_entry *r2) { - if (!r1 && !r2) return 0; @@ -978,8 +980,7 @@ static int compare_state(struct route_entry *r1, struct route_entry *r2) if (r1->nexthop_num != r2->nexthop_num) return 1; - if (CHECK_FLAG(r1->status, ROUTE_ENTRY_NEXTHOPS_CHANGED) - || CHECK_FLAG(r1->status, ROUTE_ENTRY_LABELS_CHANGED)) + if (nexthop_group_hash(&r1->ng) != nexthop_group_hash(&r2->ng)) return 1; return 0; @@ -1156,9 +1157,9 @@ static int zebra_cleanup_rnh_client(vrf_id_t vrf_id, afi_t afi, struct rnh *rnh; if (IS_ZEBRA_DEBUG_NHT) - zlog_debug("%u: Client %s RNH cleanup for family %s type %d", + zlog_debug("%u: Client %s RNH cleanup for family %s type %s", vrf_id, zebra_route_string(client->proto), - afi2str(afi), type); + afi2str(afi), rnh_type2str(type)); ntable = get_rnh_table(vrf_id, afi, type); if (!ntable) { diff --git a/zebra/zebra_rnh.h b/zebra/zebra_rnh.h index 95a3941181..c7d2c0d298 100644 --- a/zebra/zebra_rnh.h +++ b/zebra/zebra_rnh.h @@ -43,6 +43,18 @@ static inline int rnh_resolve_via_default(int family) return 0; } +static inline const char *rnh_type2str(rnh_type_t type) +{ + switch (type) { + case RNH_NEXTHOP_TYPE: + return "Nexthop"; + case RNH_IMPORT_CHECK_TYPE: + return "Import"; + } + + return "ERROR"; +} + extern struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type, bool *exists); extern struct rnh *zebra_lookup_rnh(struct prefix *p, vrf_id_t vrfid, diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index dbfe695a00..2f7d50541e 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -1254,6 +1254,40 @@ static struct route_map_rule_cmd route_match_ipv6_address_prefix_list_cmd = { route_match_address_prefix_list_compile, route_match_address_prefix_list_free}; +/* `match ipv6 next-hop type <TYPE>' */ + +static route_map_result_t +route_match_ipv6_next_hop_type(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct nh_rmap_obj *nh_data; + + if (type == RMAP_ZEBRA && prefix->family == AF_INET6) { + nh_data = (struct nh_rmap_obj *)object; + if (!nh_data) + return RMAP_DENYMATCH; + + if (nh_data->nexthop->type == NEXTHOP_TYPE_BLACKHOLE) + return RMAP_MATCH; + } + return RMAP_NOMATCH; +} + +static void *route_match_ipv6_next_hop_type_compile(const char *arg) +{ + return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); +} + +static void route_match_ipv6_next_hop_type_free(void *rule) +{ + XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_ipv6_next_hop_type_cmd = { + "ipv6 next-hop type", route_match_ipv6_next_hop_type, + route_match_ipv6_next_hop_type_compile, + route_match_ipv6_next_hop_type_free}; + /* `match ip address prefix-len PREFIXLEN' */ static route_map_result_t @@ -1345,6 +1379,40 @@ static struct route_map_rule_cmd route_match_ip_nexthop_prefix_len_cmd = { route_match_address_prefix_len_free /* reuse */ }; +/* `match ip next-hop type <blackhole>' */ + +static route_map_result_t +route_match_ip_next_hop_type(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct nh_rmap_obj *nh_data; + + if (type == RMAP_ZEBRA && prefix->family == AF_INET) { + nh_data = (struct nh_rmap_obj *)object; + if (!nh_data) + return RMAP_DENYMATCH; + + if (nh_data->nexthop->type == NEXTHOP_TYPE_BLACKHOLE) + return RMAP_MATCH; + } + return RMAP_NOMATCH; +} + +static void *route_match_ip_next_hop_type_compile(const char *arg) +{ + return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); +} + +static void route_match_ip_next_hop_type_free(void *rule) +{ + XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); +} + +static struct route_map_rule_cmd route_match_ip_next_hop_type_cmd = { + "ip next-hop type", route_match_ip_next_hop_type, + route_match_ip_next_hop_type_compile, + route_match_ip_next_hop_type_free}; + /* `match source-protocol PROTOCOL' */ static route_map_result_t route_match_source_protocol(void *rule, @@ -1927,6 +1995,9 @@ void zebra_route_map_init(void) route_map_match_ip_next_hop_prefix_list_hook(generic_match_add); route_map_no_match_ip_next_hop_prefix_list_hook(generic_match_delete); + route_map_match_ip_next_hop_type_hook(generic_match_add); + route_map_no_match_ip_next_hop_type_hook(generic_match_delete); + route_map_match_tag_hook(generic_match_add); route_map_no_match_tag_hook(generic_match_delete); @@ -1936,6 +2007,9 @@ void zebra_route_map_init(void) route_map_match_ipv6_address_prefix_list_hook(generic_match_add); route_map_no_match_ipv6_address_prefix_list_hook(generic_match_delete); + route_map_match_ipv6_next_hop_type_hook(generic_match_add); + route_map_no_match_ipv6_next_hop_type_hook(generic_match_delete); + route_map_install_match(&route_match_tag_cmd); route_map_install_match(&route_match_interface_cmd); route_map_install_match(&route_match_ip_next_hop_cmd); @@ -1947,6 +2021,8 @@ void zebra_route_map_init(void) route_map_install_match(&route_match_ip_address_prefix_len_cmd); route_map_install_match(&route_match_ipv6_address_prefix_len_cmd); route_map_install_match(&route_match_ip_nexthop_prefix_len_cmd); + route_map_install_match(&route_match_ip_next_hop_type_cmd); + route_map_install_match(&route_match_ipv6_next_hop_type_cmd); route_map_install_match(&route_match_source_protocol_cmd); route_map_install_match(&route_match_source_instance_cmd); diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c index 4352d688a1..1e9f9e4ec7 100644 --- a/zebra/zebra_router.c +++ b/zebra/zebra_router.c @@ -32,6 +32,8 @@ #include "zebra_nhg.h" #include "debug.h" +DEFINE_MTYPE_STATIC(ZEBRA, RIB_TABLE_INFO, "RIB table info") + struct zebra_router zrouter = { .multipath_num = MULTIPATH_NUM, .ipv4_multicast_mode = MCAST_NO_CONFIG, diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index fdf0cbc693..fcc94a7be9 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -48,7 +48,8 @@ static void zebra_vrf_table_create(struct zebra_vrf *zvrf, afi_t afi, static void zebra_rnhtable_node_cleanup(struct route_table *table, struct route_node *node); -DEFINE_MTYPE_STATIC(ZEBRA, OTHER_TABLE, "Other Table"); +DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_VRF, "ZEBRA VRF") +DEFINE_MTYPE_STATIC(ZEBRA, OTHER_TABLE, "Other Table") /* VRF information update. */ static void zebra_vrf_add_update(struct zebra_vrf *zvrf) diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 077c1ff8f0..a3a630d53e 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -60,6 +60,9 @@ DEFINE_MTYPE_STATIC(ZEBRA, MAC, "VNI MAC"); DEFINE_MTYPE_STATIC(ZEBRA, NEIGH, "VNI Neighbor"); DEFINE_MTYPE_STATIC(ZEBRA, ZVXLAN_SG, "zebra VxLAN multicast group"); +DEFINE_HOOK(zebra_rmac_update, (zebra_mac_t *rmac, zebra_l3vni_t *zl3vni, + bool delete, const char *reason), (rmac, zl3vni, delete, reason)) + /* definitions */ /* PMSI strings. */ #define VXLAN_FLOOD_STR_NO_INFO "-" @@ -143,8 +146,6 @@ static zebra_l3vni_t *zl3vni_lookup(vni_t vni); static void *zl3vni_alloc(void *p); static zebra_l3vni_t *zl3vni_add(vni_t vni, vrf_id_t vrf_id); static int zl3vni_del(zebra_l3vni_t *zl3vni); -static struct interface *zl3vni_map_to_svi_if(zebra_l3vni_t *zl3vni); -static struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni); static void zebra_vxlan_process_l3vni_oper_up(zebra_l3vni_t *zl3vni); static void zebra_vxlan_process_l3vni_oper_down(zebra_l3vni_t *zl3vni); @@ -224,6 +225,9 @@ static void zebra_vxlan_sg_ref(struct in_addr local_vtep_ip, struct in_addr mcast_grp); static void zebra_vxlan_sg_cleanup(struct hash_backet *backet, void *arg); +static void zvni_send_mac_to_client(zebra_vni_t *zvn); +static void zvni_send_neigh_to_client(zebra_vni_t *zvni); + /* Private functions */ static int host_rb_entry_compare(const struct host_rb_entry *hle1, const struct host_rb_entry *hle2) @@ -871,10 +875,10 @@ static void zvni_print_neigh_hash(struct hash_bucket *bucket, void *ctxt) if (json_vni == NULL) { if ((wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP) && (wctx->count == 0)) - vty_out(vty, - "%*s %-6s %-8s %-17s %-21s\n", + vty_out(vty, "%*s %-6s %-8s %-17s %-21s %s\n", -wctx->addr_width, "Neighbor", "Type", - "State", "MAC", "Remote VTEP"); + "State", "MAC", "Remote VTEP", + "Seq #'s"); vty_out(vty, "%*s %-6s %-8s %-17s %-21s %u/%u\n", -wctx->addr_width, buf2, "remote", state_str, buf1, inet_ntoa(n->r_vtep_ip), n->loc_seq, n->rem_seq); @@ -1386,8 +1390,11 @@ static void zvni_print_mac_hash(struct hash_bucket *bucket, void *ctxt) vty_out(vty, " %-5u", vid); else json_object_int_add(json_mac, "vlan", vid); - } + } else /* No vid? fill out the space */ + if (json_mac_hdr == NULL) + vty_out(vty, " %-5s", ""); if (json_mac_hdr == NULL) { + vty_out(vty, " %u/%u", mac->loc_seq, mac->rem_seq); vty_out(vty, "\n"); } else { json_object_int_add(json_mac, "localSequence", @@ -1418,11 +1425,13 @@ static void zvni_print_mac_hash(struct hash_bucket *bucket, void *ctxt) if ((wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP) && (wctx->count == 0)) { vty_out(vty, "\nVNI %u\n\n", wctx->zvni->vni); - vty_out(vty, "%-17s %-6s %-21s %-5s\n", "MAC", - "Type", "Intf/Remote VTEP", "VLAN"); + vty_out(vty, "%-17s %-6s %-21s %-5s %s\n", + "MAC", "Type", "Intf/Remote VTEP", + "VLAN", "Seq #'s"); } - vty_out(vty, "%-17s %-6s %-21s\n", buf1, "remote", - inet_ntoa(mac->fwd_info.r_vtep_ip)); + vty_out(vty, "%-17s %-6s %-21s %-5s %u/%u\n", buf1, + "remote", inet_ntoa(mac->fwd_info.r_vtep_ip), + "", mac->loc_seq, mac->rem_seq); } else { json_object_string_add(json_mac, "type", "remote"); json_object_string_add(json_mac, "remoteVtep", @@ -1536,8 +1545,8 @@ static void zvni_print_mac_hash_all_vni(struct hash_bucket *bucket, void *ctxt) if (json == NULL) { vty_out(vty, "\nVNI %u #MACs (local and remote) %u\n\n", zvni->vni, num_macs); - vty_out(vty, "%-17s %-6s %-21s %-5s\n", "MAC", "Type", - "Intf/Remote VTEP", "VLAN"); + vty_out(vty, "%-17s %-6s %-21s %-5s %s\n", "MAC", + "Type", "Intf/Remote VTEP", "VLAN", "Seq #'s"); } else json_object_int_add(json_vni, "numMacs", num_macs); } @@ -2869,6 +2878,16 @@ static void zvni_gw_macip_del_for_vni_hash(struct hash_bucket *bucket, /* Add primary SVI MAC*/ zvni = (zebra_vni_t *)bucket->data; + /* Global (Zvrf) advertise-default-gw is disabled, + * but zvni advertise-default-gw is enabled + */ + if (zvni->advertise_gw_macip) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("VNI: %u GW-MACIP enabled, retain gw-macip", + zvni->vni); + return; + } + ifp = zvni->vxlan_if; if (!ifp) return; @@ -2950,6 +2969,16 @@ static void zvni_svi_macip_del_for_vni_hash(struct hash_bucket *bucket, if (!zvni) return; + /* Global(vrf) advertise-svi-ip disabled, but zvni advertise-svi-ip + * enabled + */ + if (zvni->advertise_svi_macip) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("VNI: %u SVI-MACIP enabled, retain svi-macip", + zvni->vni); + return; + } + ifp = zvni->vxlan_if; if (!ifp) return; @@ -4056,46 +4085,67 @@ static void zvni_build_hash_table(void) ifp->name, ifp->ifindex, vni, inet_ntoa(vxl->vtep_ip)); - /* VNI hash entry is not expected to exist. */ + /* VNI hash entry is expected to exist, if the BGP process is killed */ zvni = zvni_lookup(vni); if (zvni) { zlog_debug( "VNI hash already present for IF %s(%u) L2-VNI %u", ifp->name, ifp->ifindex, vni); - continue; - } - zvni = zvni_add(vni); - if (!zvni) { - zlog_debug( - "Failed to add VNI hash, IF %s(%u) L2-VNI %u", - ifp->name, ifp->ifindex, vni); - return; - } + /* + * Inform BGP if intf is up and mapped to + * bridge. + */ + if (if_is_operative(ifp) && + zif->brslave_info.br_if) + zvni_send_add_to_client(zvni); - if (zvni->local_vtep_ip.s_addr != vxl->vtep_ip.s_addr || - zvni->mcast_grp.s_addr != vxl->mcast_grp.s_addr) { - zebra_vxlan_sg_deref(zvni->local_vtep_ip, - zvni->mcast_grp); - zebra_vxlan_sg_ref(vxl->vtep_ip, - vxl->mcast_grp); - zvni->local_vtep_ip = vxl->vtep_ip; - zvni->mcast_grp = vxl->mcast_grp; - } - zvni->vxlan_if = ifp; - vlan_if = zvni_map_to_svi(vxl->access_vlan, - zif->brslave_info.br_if); - if (vlan_if) { - zvni->vrf_id = vlan_if->vrf_id; - zl3vni = zl3vni_from_vrf(vlan_if->vrf_id); - if (zl3vni) - listnode_add_sort(zl3vni->l2vnis, zvni); - } + /* Send Local MAC-entries to client */ + zvni_send_mac_to_client(zvni); + /* Send Loval Neighbor entries to client */ + zvni_send_neigh_to_client(zvni); + } else { + zvni = zvni_add(vni); + if (!zvni) { + zlog_debug( + "Failed to add VNI hash, IF %s(%u) L2-VNI %u", + ifp->name, ifp->ifindex, vni); + return; + } + + if (zvni->local_vtep_ip.s_addr != + vxl->vtep_ip.s_addr || + zvni->mcast_grp.s_addr != + vxl->mcast_grp.s_addr) { + zebra_vxlan_sg_deref( + zvni->local_vtep_ip, + zvni->mcast_grp); + zebra_vxlan_sg_ref(vxl->vtep_ip, + vxl->mcast_grp); + zvni->local_vtep_ip = vxl->vtep_ip; + zvni->mcast_grp = vxl->mcast_grp; + } + zvni->vxlan_if = ifp; + vlan_if = zvni_map_to_svi(vxl->access_vlan, + zif->brslave_info.br_if); + if (vlan_if) { + zvni->vrf_id = vlan_if->vrf_id; + zl3vni = zl3vni_from_vrf( + vlan_if->vrf_id); + if (zl3vni) + listnode_add_sort( + zl3vni->l2vnis, zvni); + } - /* Inform BGP if intf is up and mapped to bridge. */ - if (if_is_operative(ifp) && zif->brslave_info.br_if) - zvni_send_add_to_client(zvni); + /* + * Inform BGP if intf is up and mapped to + * bridge. + */ + if (if_is_operative(ifp) && + zif->brslave_info.br_if) + zvni_send_add_to_client(zvni); + } } } } @@ -4459,6 +4509,10 @@ static int zl3vni_remote_rmac_add(zebra_l3vni_t *zl3vni, struct ethaddr *rmac, memset(&zrmac->fwd_info, 0, sizeof(zrmac->fwd_info)); zrmac->fwd_info.r_vtep_ip = vtep_ip->ipaddr_v4; + /* Send RMAC for FPM processing */ + hook_call(zebra_rmac_update, zrmac, zl3vni, false, + "new RMAC added"); + /* install rmac in kernel */ zl3vni_rmac_install(zl3vni, zrmac); } @@ -4479,6 +4533,10 @@ static void zl3vni_remote_rmac_del(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac, /* uninstall from kernel */ zl3vni_rmac_uninstall(zl3vni, zrmac); + /* Send RMAC for FPM processing */ + hook_call(zebra_rmac_update, zrmac, zl3vni, true, + "RMAC deleted"); + /* del the rmac entry */ zl3vni_rmac_del(zl3vni, zrmac); } @@ -4790,7 +4848,7 @@ static int zl3vni_del(zebra_l3vni_t *zl3vni) return 0; } -static struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni) +struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni) { struct zebra_ns *zns = NULL; struct route_node *rn = NULL; @@ -4821,7 +4879,7 @@ static struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni) return NULL; } -static struct interface *zl3vni_map_to_svi_if(zebra_l3vni_t *zl3vni) +struct interface *zl3vni_map_to_svi_if(zebra_l3vni_t *zl3vni) { struct zebra_if *zif = NULL; /* zebra_if for vxlan_if */ struct zebra_l2info_vxlan *vxl = NULL; /* l2 info for vxlan_if */ @@ -5089,6 +5147,10 @@ static void zl3vni_del_rmac_hash_entry(struct hash_bucket *bucket, void *ctx) zrmac = (zebra_mac_t *)bucket->data; zl3vni = (zebra_l3vni_t *)ctx; zl3vni_rmac_uninstall(zl3vni, zrmac); + + /* Send RMAC for FPM processing */ + hook_call(zebra_rmac_update, zrmac, zl3vni, true, "RMAC deleted"); + zl3vni_rmac_del(zl3vni, zrmac); } @@ -6089,9 +6151,8 @@ void zebra_vxlan_print_neigh_vni(struct vty *vty, struct zebra_vrf *zvrf, vty_out(vty, "Number of ARPs (local and remote) known for this VNI: %u\n", num_neigh); - vty_out(vty, "%*s %-6s %-8s %-17s %-21s\n", - -wctx.addr_width, "IP", "Type", - "State", "MAC", "Remote VTEP"); + vty_out(vty, "%*s %-6s %-8s %-17s %-21s %s\n", -wctx.addr_width, + "IP", "Type", "State", "MAC", "Remote VTEP", "Seq #'s"); } else json_object_int_add(json, "numArpNd", num_neigh); @@ -6353,8 +6414,8 @@ void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf, vty_out(vty, "Number of MACs (local and remote) known for this VNI: %u\n", num_macs); - vty_out(vty, "%-17s %-6s %-21s %-5s\n", "MAC", "Type", - "Intf/Remote VTEP", "VLAN"); + vty_out(vty, "%-17s %-6s %-21s %-5s %s\n", "MAC", "Type", + "Intf/Remote VTEP", "VLAN", "Seq #'s"); } else json_object_int_add(json, "numMacs", num_macs); @@ -8916,7 +8977,7 @@ void zebra_vxlan_advertise_svi_macip(ZAPI_HANDLER_ARGS) struct interface *ifp = NULL; if (!EVPN_ENABLED(zvrf)) { - zlog_debug("EVPN GW-MACIP Adv for non-EVPN VRF %u", + zlog_debug("EVPN SVI-MACIP Adv for non-EVPN VRF %u", zvrf_id(zvrf)); return; } @@ -8927,7 +8988,7 @@ void zebra_vxlan_advertise_svi_macip(ZAPI_HANDLER_ARGS) if (!vni) { if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("EVPN gateway macip Adv %s, currently %s", + zlog_debug("EVPN SVI-MACIP Adv %s, currently %s", advertise ? "enabled" : "disabled", advertise_gw_macip_enabled(NULL) ? "enabled" @@ -9637,3 +9698,120 @@ static void zebra_vxlan_sg_cleanup(struct hash_backet *backet, void *arg) zebra_vxlan_sg_del(vxlan_sg); } + +/************************** EVPN BGP config management ************************/ +/* Notify Local MACs to the clienti, skips GW MAC */ +static void zvni_send_mac_hash_entry_to_client(struct hash_bucket *bucket, + void *arg) +{ + struct mac_walk_ctx *wctx = arg; + zebra_mac_t *zmac = bucket->data; + + if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_DEF_GW)) + return; + + if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL)) + zvni_mac_send_add_to_client(wctx->zvni->vni, &zmac->macaddr, + zmac->flags, zmac->loc_seq); +} + +/* Iterator to Notify Local MACs of a L2VNI */ +static void zvni_send_mac_to_client(zebra_vni_t *zvni) +{ + struct mac_walk_ctx wctx; + + if (!zvni->mac_table) + return; + + memset(&wctx, 0, sizeof(struct mac_walk_ctx)); + wctx.zvni = zvni; + + hash_iterate(zvni->mac_table, zvni_send_mac_hash_entry_to_client, + &wctx); +} + +/* Notify Neighbor entries to the Client, skips the GW entry */ +static void zvni_send_neigh_hash_entry_to_client(struct hash_bucket *bucket, + void *arg) +{ + struct mac_walk_ctx *wctx = arg; + zebra_neigh_t *zn = bucket->data; + zebra_mac_t *zmac = NULL; + + if (CHECK_FLAG(zn->flags, ZEBRA_NEIGH_DEF_GW)) + return; + + if (CHECK_FLAG(zn->flags, ZEBRA_NEIGH_LOCAL) && + IS_ZEBRA_NEIGH_ACTIVE(zn)) { + zmac = zvni_mac_lookup(wctx->zvni, &zn->emac); + if (!zmac) + return; + + zvni_neigh_send_add_to_client(wctx->zvni->vni, &zn->ip, + &zn->emac, zn->flags, + zn->loc_seq); + } +} + +/* Iterator of a specific L2VNI */ +static void zvni_send_neigh_to_client(zebra_vni_t *zvni) +{ + struct neigh_walk_ctx wctx; + + memset(&wctx, 0, sizeof(struct neigh_walk_ctx)); + wctx.zvni = zvni; + + hash_iterate(zvni->neigh_table, zvni_send_neigh_hash_entry_to_client, + &wctx); +} + +static void zvni_evpn_cfg_cleanup(struct hash_bucket *bucket, void *ctxt) +{ + zebra_vni_t *zvni = NULL; + + zvni = (zebra_vni_t *)bucket->data; + zvni->advertise_gw_macip = 0; + zvni->advertise_svi_macip = 0; + zvni->advertise_subnet = 0; + + zvni_neigh_del_all(zvni, 0, 0, + DEL_REMOTE_NEIGH | DEL_REMOTE_NEIGH_FROM_VTEP); + zvni_mac_del_all(zvni, 0, 0, + DEL_REMOTE_MAC | DEL_REMOTE_MAC_FROM_VTEP); + zvni_vtep_del_all(zvni, 0); +} + +/* Cleanup EVPN configuration of a specific VRF */ +static void zebra_evpn_vrf_cfg_cleanup(struct zebra_vrf *zvrf) +{ + zvrf->advertise_all_vni = 0; + zvrf->advertise_gw_macip = 0; + zvrf->advertise_svi_macip = 0; + zvrf->vxlan_flood_ctrl = VXLAN_FLOOD_HEAD_END_REPL; + + hash_iterate(zvrf->vni_table, zvni_evpn_cfg_cleanup, NULL); +} + +/* Cleanup BGP EVPN configuration upon client disconnect */ +static int zebra_evpn_cfg_clean_up(struct zserv *client) +{ + struct vrf *vrf; + struct zebra_vrf *zvrf; + + if (client->proto != ZEBRA_ROUTE_BGP) + return 0; + + RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { + zvrf = vrf->info; + if (zvrf) + zebra_evpn_vrf_cfg_cleanup(zvrf); + } + + return 0; +} + +/* Cleanup BGP EVPN configuration upon client disconnect */ +extern void zebra_evpn_init(void) +{ + hook_register(zserv_client_close, zebra_evpn_cfg_clean_up); +} diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h index f752bdd690..6117567bc1 100644 --- a/zebra/zebra_vxlan.h +++ b/zebra/zebra_vxlan.h @@ -212,6 +212,7 @@ extern int zebra_vxlan_clear_dup_detect_vni_all(struct vty *vty, extern int zebra_vxlan_clear_dup_detect_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni); +extern void zebra_evpn_init(void); #ifdef __cplusplus } diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h index 1dd42b7083..8e78042646 100644 --- a/zebra/zebra_vxlan_private.h +++ b/zebra/zebra_vxlan_private.h @@ -431,6 +431,12 @@ struct nh_walk_ctx { }; extern zebra_l3vni_t *zl3vni_from_vrf(vrf_id_t vrf_id); +extern struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni); +extern struct interface *zl3vni_map_to_svi_if(zebra_l3vni_t *zl3vni); + +DECLARE_HOOK(zebra_rmac_update, (zebra_mac_t *rmac, zebra_l3vni_t *zl3vni, + bool delete, const char *reason), (rmac, zl3vni, delete, reason)) + #ifdef __cplusplus } |
