* Babel
* PBR
* OpenFabric
+* VRRP
* EIGRP (alpha)
* NHRP (alpha)
#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);
+++ /dev/null
-/* 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")
+++ /dev/null
-/* 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 */
#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);
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 \
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 \
#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)
#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
} 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);
#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;
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;
/*
* 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;
#include "bfd.h"
+DEFINE_MTYPE_STATIC(BFDD, BFDD_LABEL, "long-lived label memory")
+
/*
* Definitions
*/
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;
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 *
.description = "BGP attempted to create an EVPN ES entry and failed",
.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",
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,
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);
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;
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",
SAFI_EVPN, json_array);
output_count++;
}
+ rd_header = 0;
if (use_json) {
json_object_object_add(json_prefix_info,
"paths", json_array);
bgp_evpn_show_route_header(vty, bgp,
tbl_ver,
json);
+ vty_out(vty, "%19s Extended Community\n"
+ , " ");
header = 0;
}
#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"
}
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;
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;
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)
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,
}
}
-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;
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;
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;
list_delete(&bsm->ifp_list);
XFREE(MTYPE_BSM, bsm);
- bgp_mac_rescan_all_evpn_tables();
+ bgp_mac_rescan_all_evpn_tables(macaddr);
}
}
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)
* 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
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,
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);
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;
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");
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 */
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");
}
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;
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;
}
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;
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;
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
"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;
}
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
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;
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);
}
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,
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;
}
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;
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);
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);
}
/*
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);
}
*/
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",
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;
{
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
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),
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"
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"
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
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"
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
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);
bgp_zebra_instance_register(bgp);
}
- return 0;
+ return BGP_SUCCESS;
}
/*
password zebra
!enable password please-set-at-here
!
-!bgp multiple-instance
!
router bgp 7675
! bgp router-id 10.0.0.1
#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
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);
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
^^^^^^^^^^^^^^^^^^^^^
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
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`
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
.. 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:
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
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
----------------------------
.. code-block:: frr
- bgp multiple-instance
!
router bgp 1 view 1
neighbor 10.0.0.1 remote-as 2
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.
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:
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
Proceed processing the route-map at the first entry whose order is >= N
+
Route Map Examples
==================
hostname RS
password ix
!
- bgp multiple-instance
- !
router bgp 65000 view RS
no bgp default ipv4-unicast
neighbor 2001:0DB8::A remote-as 65001
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
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"]
-# 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
+++ /dev/null
-# 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.
#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) \
"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,
extern "C" {
#endif
-DECLARE_MTYPE(HOST)
DECLARE_MTYPE(COMPLETION)
/*
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. */
%code requires {
#include "config.h"
+ #include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
static void
cleanup (struct parser_ctx *ctx);
+ static void loopcheck(struct parser_ctx *ctx, struct subgraph *sg);
+
#define scanner ctx->scanner
}
* 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);
};
/* 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)
{
#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);
extern "C" {
#endif
-DECLARE_MTYPE(FRR_PTHREAD);
-DECLARE_MTYPE(PTHREAD_PRIM);
-
#define OS_THREAD_NAMELEN 16
struct frr_pthread;
#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;
extern "C" {
#endif
-DECLARE_MTYPE(HASH)
-DECLARE_MTYPE(HASH_BACKET)
-
/* Default hash table size. */
#define HASH_INITIAL_SIZE 256
/* Expansion threshold */
#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")
extern "C" {
#endif
-DECLARE_MTYPE(IF)
DECLARE_MTYPE(CONNECTED_LABEL)
/* Interface link-layer type, if known. Derived from:
}
+/* 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 \
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)
if (pbest == NULL)
return PREFIX_DENY;
+ pbest->hitcnt++;
return pbest->type;
}
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,
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,
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))
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))
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);
(*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;
}
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);
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)
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)
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);
(*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;
}
int ret = 0;
struct route_map_index *index;
struct route_map_rule *set;
+ char buf[PREFIX_STRLEN];
if (recursion > RMAP_RECURSION_LIMIT) {
flog_warn(
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) {
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
/* 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: {
}
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 *))
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) {
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;
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);
}
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);
}
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")
{
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,
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)
{
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");
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;
}
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);
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);
/* Keep track how many times we've try to apply */
uint64_t applied;
+ uint64_t applied_clear;
QOBJ_FIELDS
};
/* 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;
#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 *);
extern "C" {
#endif
-DECLARE_MTYPE(ROUTE_TABLE)
DECLARE_MTYPE(ROUTE_NODE)
/*
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) {
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));
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);
sock = THREAD_FD(thread);
vty = THREAD_ARG(thread);
- vty->t_read = NULL;
if ((nbytes = read(sock, buf, VTY_READ_BUFSIZ)) <= 0) {
if (nbytes < 0) {
{
struct vty *vty = THREAD_ARG(thread);
- vty->t_write = NULL;
vtysh_flush(vty);
return 0;
}
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);
struct vty *vty;
vty = THREAD_ARG(thread);
- vty->t_timeout = NULL;
vty->v_timeout = 0;
/* Clear buffer*/
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);
}
&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;
}
}
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);
}
#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;
extern "C" {
#endif
-DECLARE_MTYPE(YANG_MODULE)
-DECLARE_MTYPE(YANG_DATA)
-
/* Maximum XPath length. */
#define XPATH_MAXLEN 256
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. */
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);
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);
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:
}
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();
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 */
/*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,
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);
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)) {
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);
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);
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];
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
* 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.
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);
}
}
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 */
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
ch = pim_ifchannel_add(ifp, sg, source_flags,
PIM_UPSTREAM_FLAG_MASK_SRC_PIM);
- if (!ch)
- return;
pim_ifp = ifp->info;
}
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);
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:
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);
+ }
+}
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 */
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;
}
}
* 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;
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
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,
}
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)) {
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 */
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;
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);
}
}
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;
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;
}
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);
}
}
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) {
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;
}
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);
* 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));
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;
}
}
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);
* 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__);
+ }
}
}
__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)
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");
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 {
source_str);
}
source->source_channel_oil =
- pim_channel_oil_add(pim, &sg, MAXVIFS);
+ pim_channel_oil_add(
+ pim, &sg, MAXVIFS,
+ __PRETTY_FUNCTION__);
}
else {
* 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) {
}
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(
__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(
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)
#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))
#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);
+++ /dev/null
-/* 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")
+++ /dev/null
-/* 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 */
#include "ripd/ripd.h"
#include "ripd/rip_debug.h"
#include "ripd/rip_cli.h"
+#include "ripd/rip_interface.h"
/*
* XPath: /frr-ripd:ripd/instance
#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)
#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));
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
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);
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);
/* 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);
#include "hook.h"
#include "nexthop.h"
#include "distribute.h"
-#include "rip_memory.h"
+#include "memory.h"
/* RIP version number. */
#define RIPv1 1
#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;
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 \
ripd/rip_debug.h \
ripd/rip_errors.h \
ripd/rip_interface.h \
- ripd/rip_memory.h \
ripd/ripd.h \
# end
#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 *);
{
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
/* 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;
}
+++ /dev/null
-/* 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")
+++ /dev/null
-/* 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 */
#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))
#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)
#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));
#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;
#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,
};
#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
#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;
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 \
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 \
struct static_route *si;
struct static_vrf *svrf;
struct route_node *rn;
- bool orig;
- bool reinstall;
svrf = vrf->info;
if (!svrf)
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;
&& 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;
&& 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);
}
}
}
--- /dev/null
+../bgp_l3vpn_to_bgp_vrf/ce1
\ No newline at end of file
--- /dev/null
+../bgp_l3vpn_to_bgp_vrf/ce2
\ No newline at end of file
--- /dev/null
+../bgp_l3vpn_to_bgp_vrf/ce3
\ No newline at end of file
--- /dev/null
+../bgp_l3vpn_to_bgp_vrf/ce4
\ No newline at end of file
--- /dev/null
+../bgp_l3vpn_to_bgp_vrf/customize.py
\ No newline at end of file
--- /dev/null
+../bgp_l3vpn_to_bgp_vrf/r1
\ No newline at end of file
--- /dev/null
+../bgp_l3vpn_to_bgp_vrf/r2
\ No newline at end of file
--- /dev/null
+../bgp_l3vpn_to_bgp_vrf/r3
\ No newline at end of file
--- /dev/null
+../bgp_l3vpn_to_bgp_vrf/r4
\ No newline at end of file
--- /dev/null
+../bgp_l3vpn_to_bgp_vrf/scripts
\ No newline at end of file
--- /dev/null
+#!/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)
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
--- /dev/null
+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')
+
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)
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
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
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
!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
base_log_dir = '.'
fout_name = 'output.log'
fsum_name = 'summary.txt'
- l_level = 9
+ l_level = 6
CallOnFail = False
l_total = 0
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):
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:
#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()
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
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):
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 \
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 \
#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;
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
#include <zebra.h>
#include <netinet/ip.h>
+#include "lib/memory.h"
#include "lib/hash.h"
#include "lib/hook.h"
#include "lib/if.h"
/* User compatibility constant */
#define CS2MS 10
+DECLARE_MGROUP(VRRPD)
+
/* Configured defaults */
struct vrrp_defaults {
uint8_t priority;
#include "vrrp_vty.h"
#include "vrrp_zebra.h"
+DEFINE_MGROUP(VRRPD, "vrrpd")
+
char backup_config_file[256];
zebra_capabilities_t _caps_p[] = {
master = frr_init();
+ access_list_init();
vrrp_debug_init();
vrrp_zebra_init();
vrrp_vty_init();
+++ /dev/null
-/*
- * 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");
+++ /dev/null
-/*
- * 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__ */
#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",
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)
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.
*
#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"
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
|| (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)
/* 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);
}
{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;
#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"
/* RNH init */
zebra_rnh_init();
+ /* Config handler Init */
+ zebra_evpn_init();
+
/* Error init */
zebra_error_init();
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;
}
* 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;
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);
}
/* 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");
/* 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
#if defined(HAVE_RTADV)
+DEFINE_MTYPE_STATIC(ZEBRA, RTADV_PREFIX, "Router Advertisement Prefix")
+
#ifdef OPEN_BSD
#include <netinet/icmp6.h>
#endif
#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
#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.
* 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
*/
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.
*/
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
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);
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;
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
*
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;
}
/*
- * 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;
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));
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
*/
return 0;
}
+/*
+ * 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
*/
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;
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;
}
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 */
}
#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
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
#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")
#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
}
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;
* 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;
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);
}
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,
: "",
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)) {
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)
? "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
#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,
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;
}
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);
{
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);
{
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);
* 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 {
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;
static int compare_state(struct route_entry *r1, struct route_entry *r2)
{
-
if (!r1 && !r2)
return 0;
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;
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) {
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,
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
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,
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);
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);
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);
#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,
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)
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 "-"
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);
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)
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);
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",
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",
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);
}
/* 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;
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;
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);
+ }
}
}
}
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);
}
/* 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);
}
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;
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 */
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);
}
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);
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);
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;
}
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"
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);
+}
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
}
};
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
}