--- /dev/null
+dist: focal
+os: linux
+language: c
+services:
+ - docker
+jobs:
+ include:
+ - script:
+ - docker/centos-7/build.sh
+ - docker images
+ name: centos7
+ - script:
+ - docker/centos-8/build.sh
+ - docker images
+ name: centos8
+ - script:
+ - sudo apt install -y linux-modules-extra-$(uname -r)
+ - docker build -t frr-ubuntu18:latest -f docker/ubuntu18-ci/Dockerfile .
+ - docker images
+ - uname -a
+ - docker run -d --privileged --name frr-ubuntu18 --mount type=bind,source=/lib/modules,target=/lib/modules frr-ubuntu18:latest
+ - docker ps
+ - docker exec frr-ubuntu18 bash -c 'cd ~/frr ; make check'
+ - docker exec frr-ubuntu18 bash -c 'ps agxu ; lsmod | grep mpls || true'
+ - docker exec frr-ubuntu18 bash -c 'cd ~/frr/tests/topotests/ospf-topo1 ; sudo pytest test_ospf_topo1.py'
+ - docker exec frr-ubuntu18 bash -c 'cd ~/frr/tests/topotests/bgp_l3vpn_to_bgp_vrf ; sudo pytest test_bgp_l3vpn_to_bgp_vrf.py'
+ name: ubuntu18+minimalCI
+ - script:
+ - sudo apt install -y linux-modules-extra-$(uname -r)
+ - docker build -t frr-ubuntu20:latest -f docker/ubuntu20-ci/Dockerfile .
+ - docker images
+ - uname -a
+ - docker run -d --privileged --name frr-ubuntu20 --mount type=bind,source=/lib/modules,target=/lib/modules frr-ubuntu20:latest
+ - docker ps
+ - docker exec frr-ubuntu20 bash -c 'cd ~/frr ; make check'
+ - docker exec frr-ubuntu20 bash -c 'ps agxu ; lsmod | grep mpls || true'
+ - docker exec frr-ubuntu20 bash -c 'cd ~/frr/tests/topotests/ospf-topo1 ; sudo pytest test_ospf_topo1.py'
+ - docker exec frr-ubuntu20 bash -c 'cd ~/frr/tests/topotests/bgp_l3vpn_to_bgp_vrf ; sudo pytest test_bgp_l3vpn_to_bgp_vrf.py'
+ name: ubuntu20+minimalCI
+
ncurses-libs ncurses-terminfo ncurses-terminfo-base patch pax-utils pcre
perl pkgconf python3 python3-dev readline readline-dev sqlite-libs
squashfs-tools sudo tar texinfo xorriso xz-libs py-pip rtrlib rtrlib-dev
- py3-sphinx"
+ py3-sphinx elfutils elfutils-dev"
checkdepends="pytest py-setuptools"
install="$pkgname.pre-install $pkgname.pre-deinstall $pkgname.post-deinstall"
subpackages="$pkgname-dev $pkgname-doc $pkgname-dbg"
!LICENCE
!Makefile
!subdir.am
-!babeld.conf.sample
!.gitignore
+++ /dev/null
-debug babel common
-!debug babel kernel
-!debug babel filter
-!debug babel timeout
-!debug babel interface
-!debug babel route
-!debug babel all
-
-router babel
-! network wlan0
-! network eth0
-! redistribute ipv4 kernel
-! no redistribute ipv6 static
-
-! The defaults are fine for a wireless interface
-
-!interface wlan0
-
-! A few optimisation tweaks are optional but recommended on a wired interface
-! Disable link quality estimation, enable split horizon processing, and
-! increase the hello and update intervals.
-
-!interface eth0
-! babel wired
-! babel split-horizon
-! babel hello-interval 12000
-! babel update-interval 36000
-
-! log file /var/log/quagga/babeld.log
-log stdout
if BABELD
noinst_LIBRARIES += babeld/libbabel.a
sbin_PROGRAMS += babeld/babeld
-dist_examples_DATA += babeld/babeld.conf.sample
vtysh_scan += \
babeld/babel_interface.c \
babeld/babel_zebra.c \
+++ /dev/null
-password zebra
-!
-log stdout
-!
-line vty
void bfd_cli_show_shutdown(struct vty *vty, struct lyd_node *dnode,
bool show_defaults)
{
- if (show_defaults)
- vty_out(vty, " no shutdown\n");
- else
- vty_out(vty, " %sshutdown\n",
- yang_dnode_get_bool(dnode, NULL) ? "" : "no ");
+ vty_out(vty, " %sshutdown\n",
+ yang_dnode_get_bool(dnode, NULL) ? "" : "no ");
}
DEFPY_YANG(
void bfd_cli_show_passive(struct vty *vty, struct lyd_node *dnode,
bool show_defaults)
{
- if (show_defaults)
- vty_out(vty, " no passive-mode\n");
- else
- vty_out(vty, " %spassive-mode\n",
- yang_dnode_get_bool(dnode, NULL) ? "" : "no ");
+ vty_out(vty, " %spassive-mode\n",
+ yang_dnode_get_bool(dnode, NULL) ? "" : "no ");
}
DEFPY_YANG(
void bfd_cli_show_minimum_ttl(struct vty *vty, struct lyd_node *dnode,
bool show_defaults)
{
- if (show_defaults)
- vty_out(vty, " minimum-ttl 254\n");
- else
- vty_out(vty, " minimum-ttl %s\n",
- yang_dnode_get_string(dnode, NULL));
+ vty_out(vty, " minimum-ttl %s\n", yang_dnode_get_string(dnode, NULL));
}
DEFPY_YANG(
void bfd_cli_show_mult(struct vty *vty, struct lyd_node *dnode,
bool show_defaults)
{
- if (show_defaults)
- vty_out(vty, " detect-multiplier %d\n",
- BFD_DEFDETECTMULT);
- else
- vty_out(vty, " detect-multiplier %s\n",
- yang_dnode_get_string(dnode, NULL));
+ vty_out(vty, " detect-multiplier %s\n",
+ yang_dnode_get_string(dnode, NULL));
}
DEFPY_YANG(
void bfd_cli_show_rx(struct vty *vty, struct lyd_node *dnode,
bool show_defaults)
{
- uint32_t value;
+ uint32_t value = yang_dnode_get_uint32(dnode, NULL);
- if (show_defaults)
- vty_out(vty, " receive-interval %d\n",
- BFD_DEFREQUIREDMINRX);
- else {
- value = yang_dnode_get_uint32(dnode, NULL);
- vty_out(vty, " receive-interval %u\n", value / 1000);
- }
+ vty_out(vty, " receive-interval %u\n", value / 1000);
}
DEFPY_YANG(
void bfd_cli_show_tx(struct vty *vty, struct lyd_node *dnode,
bool show_defaults)
{
- uint32_t value;
+ uint32_t value = yang_dnode_get_uint32(dnode, NULL);
- if (show_defaults)
- vty_out(vty, " transmit-interval %d\n",
- BFD_DEFDESIREDMINTX);
- else {
- value = yang_dnode_get_uint32(dnode, NULL);
- vty_out(vty, " transmit-interval %u\n", value / 1000);
- }
+ vty_out(vty, " transmit-interval %u\n", value / 1000);
}
DEFPY_YANG(
void bfd_cli_show_echo(struct vty *vty, struct lyd_node *dnode,
bool show_defaults)
{
- if (show_defaults)
- vty_out(vty, " no echo-mode\n");
- else
- vty_out(vty, " %secho-mode\n",
- yang_dnode_get_bool(dnode, NULL) ? "" : "no ");
+ vty_out(vty, " %secho-mode\n",
+ yang_dnode_get_bool(dnode, NULL) ? "" : "no ");
}
DEFPY_YANG(
void bfd_cli_show_desired_echo_transmission_interval(struct vty *vty,
struct lyd_node *dnode, bool show_defaults)
{
- uint32_t value;
+ uint32_t value = yang_dnode_get_uint32(dnode, NULL);
- if (show_defaults)
- vty_out(vty, " echo transmit-interval %d\n",
- BFD_DEF_DES_MIN_ECHO_TX);
- else {
- value = yang_dnode_get_uint32(dnode, NULL);
- vty_out(vty, " echo transmit-interval %u\n", value / 1000);
- }
+ vty_out(vty, " echo transmit-interval %u\n", value / 1000);
}
DEFPY_YANG(
void bfd_cli_show_required_echo_receive_interval(struct vty *vty,
struct lyd_node *dnode, bool show_defaults)
{
- uint32_t value;
-
- if (show_defaults)
- vty_out(vty, " echo receive-interval %d\n",
- BFD_DEF_REQ_MIN_ECHO_RX);
- else {
- value = yang_dnode_get_uint32(dnode, NULL);
- if (value)
- vty_out(vty, " echo receive-interval %u\n",
- value / 1000);
- else
- vty_out(vty, " echo receive-interval disabled\n");
- }
+ uint32_t value = yang_dnode_get_uint32(dnode, NULL);
+
+ if (value)
+ vty_out(vty, " echo receive-interval %u\n", value / 1000);
+ else
+ vty_out(vty, " echo receive-interval disabled\n");
}
/*
if BFDD
noinst_LIBRARIES += bfdd/libbfd.a
sbin_PROGRAMS += bfdd/bfdd
-dist_examples_DATA += bfdd/bfdd.conf.sample
vtysh_scan += bfdd/bfdd_vty.c
vtysh_scan += bfdd/bfdd_cli.c
vtysh_daemons += bfdd
if (!CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE))
continue;
+ /* Don't overrun the zapi buffer. */
+ if (api_nhg.nexthop_num == MULTIPATH_NUM)
+ break;
+
/* overwrite the gw */
if (v4_nhg)
nh.gate.ipv4 = es_vtep->vtep_ip;
if (!api_nhg.nexthop_num)
return;
- if (api_nhg.nexthop_num > MULTIPATH_NUM)
- return;
-
zclient_nhg_send(zclient, ZEBRA_NHG_ADD, &api_nhg);
}
static int bgp_start(struct peer *);
/* Register peer with NHT */
-static int bgp_peer_reg_with_nht(struct peer *peer)
+int bgp_peer_reg_with_nht(struct peer *peer)
{
int connected = 0;
* needed, even on a passive connection.
*/
bgp_peer_reg_with_nht(peer);
+ if (from_peer)
+ bgp_replace_nexthop_by_peer(from_peer, peer);
bgp_reads_on(peer);
bgp_writes_on(peer);
const char *print_peer_gr_cmd(enum peer_gr_command pr_gr_cmd);
const char *print_global_gr_mode(enum global_mode gl_mode);
const char *print_global_gr_cmd(enum global_gr_command gl_gr_cmd);
+int bgp_peer_reg_with_nht(struct peer *peer);
#endif /* _QUAGGA_BGP_FSM_H */
bool more = true; // whether we got more data
bool fatal = false; // whether fatal error occurred
bool added_pkt = false; // whether we pushed onto ->ibuf
+ int code = 0; // FSM code if error occurred
/* clang-format on */
- int code;
peer = THREAD_ARG(thread);
/*
* Reads a chunk of data from peer->fd into peer->ibuf_work.
*
+ * code_p
+ * Pointer to location to store FSM event code in case of fatal error.
+ *
* @return status flag (see top-of-file)
*/
static uint16_t bgp_read(struct peer *peer, int *code_p)
peer1->doppelganger = peer;
peer->fd = bgp_sock;
vrf_bind(peer->bgp->vrf_id, bgp_sock, bgp_get_bound_name(peer));
+ bgp_peer_reg_with_nht(peer);
bgp_fsm_change_status(peer, Active);
BGP_TIMER_OFF(peer->t_start); /* created in peer_create() */
bgp_unlink_nexthop_check(bnc);
}
+void bgp_replace_nexthop_by_peer(struct peer *from, struct peer *to)
+{
+ struct prefix pp;
+ struct prefix pt;
+ struct bgp_nexthop_cache *bncp, *bnct;
+ afi_t afi;
+
+ if (!sockunion2hostprefix(&from->su, &pp))
+ return;
+
+ afi = family2afi(pp.family);
+ bncp = bnc_find(&from->bgp->nexthop_cache_table[afi], &pp, 0);
+
+ if (!sockunion2hostprefix(&to->su, &pt))
+ return;
+
+ bnct = bnc_find(&to->bgp->nexthop_cache_table[afi], &pt, 0);
+
+ if (bnct != bncp)
+ return;
+
+ if (bnct)
+ bnct->nht_info = to;
+}
+
void bgp_unlink_nexthop_by_peer(struct peer *peer)
{
struct prefix p;
(bgp_path_info_extra_get(pi))->igpmetric = bnc->metric;
else if (pi->extra)
pi->extra->igpmetric = 0;
- } else if (peer)
- bnc->nht_info = (void *)peer; /* NHT peer reference */
+ } else if (peer) {
+ /*
+ * Let's not accidently save the peer data for a peer
+ * we are going to throw away in a second or so.
+ * When we come back around we'll fix up this
+ * data properly in replace_nexthop_by_peer
+ */
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
+ bnc->nht_info = (void *)peer; /* NHT peer reference */
+ }
/*
* We are cheating here. Views have no associated underlying
*/
extern void bgp_unlink_nexthop(struct bgp_path_info *p);
void bgp_unlink_nexthop_by_peer(struct peer *peer);
-
+void bgp_replace_nexthop_by_peer(struct peer *from, struct peer *to);
/**
* bgp_delete_connected_nexthop() - Reset the 'peer' pointer for a connected
* nexthop entry. If no paths reference the nexthop, it will be unregistered
}
/* Static function to display route. */
-static void route_vty_out_route(const struct prefix *p, struct vty *vty,
- json_object *json, bool wide)
+static void route_vty_out_route(struct bgp_dest *dest, const struct prefix *p,
+ struct vty *vty, json_object *json, bool wide)
{
int len = 0;
char buf[BUFSIZ];
json_object_int_add(json, "prefixLen", p->prefixlen);
prefix2str(p, buf2, PREFIX_STRLEN);
json_object_string_add(json, "network", buf2);
+ json_object_int_add(json, "version", dest->version);
}
} else if (p->family == AF_ETHERNET) {
len = vty_out(vty, "%pFX", p);
json_object_int_add(json, "prefixLen", p->prefixlen);
prefix2str(p, buf2, PREFIX_STRLEN);
json_object_string_add(json, "network", buf2);
+ json_object_int_add(json, "version", dest->version);
}
}
/* Print the short form route status for a bgp_path_info */
static void route_vty_short_status_out(struct vty *vty,
struct bgp_path_info *path,
+ const struct prefix *p,
json_object *json_path)
{
+ enum rpki_states rpki_state = RPKI_NOT_BEING_USED;
+
if (json_path) {
/* Route status display. */
return;
}
+ /* RPKI validation state */
+ rpki_state =
+ hook_call(bgp_rpki_prefix_status, path->peer, path->attr, p);
+
+ if (rpki_state == RPKI_VALID)
+ vty_out(vty, "V");
+ else if (rpki_state == RPKI_INVALID)
+ vty_out(vty, "I");
+ else if (rpki_state == RPKI_NOTFOUND)
+ vty_out(vty, "N");
+
/* Route status display. */
if (CHECK_FLAG(path->flags, BGP_PATH_REMOVED))
vty_out(vty, "R");
json_path = json_object_new_object();
/* short status lead text */
- route_vty_short_status_out(vty, path, json_path);
+ route_vty_short_status_out(vty, path, p, json_path);
if (!json_paths) {
/* print prefix and mask */
if (!display)
- route_vty_out_route(p, vty, json_path, wide);
+ route_vty_out_route(path->net, p, vty, json_path, wide);
else
vty_out(vty, "%*s", (wide ? 45 : 17), " ");
} else {
- route_vty_out_route(p, vty, json_path, wide);
+ route_vty_out_route(path->net, p, vty, json_path, wide);
}
/*
}
/* called from terminal list command */
-void route_vty_out_tmp(struct vty *vty, const struct prefix *p,
- struct attr *attr, safi_t safi, bool use_json,
- json_object *json_ar, bool wide)
+void route_vty_out_tmp(struct vty *vty, struct bgp_dest *dest,
+ const struct prefix *p, struct attr *attr, safi_t safi,
+ bool use_json, json_object *json_ar, bool wide)
{
json_object *json_status = NULL;
json_object *json_net = NULL;
json_object_string_add(json_net, "network", buff);
}
} else
- route_vty_out_route(p, vty, NULL, wide);
+ route_vty_out_route(dest, p, vty, NULL, wide);
/* Print attribute */
if (attr) {
json_out = json_object_new_object();
/* short status lead text */
- route_vty_short_status_out(vty, path, json_out);
+ route_vty_short_status_out(vty, path, p, json_out);
/* print prefix and mask */
if (json == NULL) {
if (!display)
- route_vty_out_route(p, vty, NULL, false);
+ route_vty_out_route(path->net, p, vty, NULL, false);
else
vty_out(vty, "%*s", 17, " ");
}
}
/* short status lead text */
- route_vty_short_status_out(vty, path, json_path);
+ route_vty_short_status_out(vty, path, p, json_path);
/* print prefix and mask */
if (!display)
- route_vty_out_route(p, vty, json_path, false);
+ route_vty_out_route(path->net, p, vty, json_path, false);
else
vty_out(vty, "%*s", 17, " ");
char timebuf[BGP_UPTIME_LEN];
/* short status lead text */
- route_vty_short_status_out(vty, path, json);
+ route_vty_short_status_out(vty, path, p, json);
/* print prefix and mask */
if (!use_json) {
if (!display)
- route_vty_out_route(p, vty, NULL, false);
+ route_vty_out_route(path->net, p, vty, NULL, false);
else
vty_out(vty, "%*s", 17, " ");
}
bdi = path->extra->damp_info;
/* short status lead text */
- route_vty_short_status_out(vty, path, json);
+ route_vty_short_status_out(vty, path, p, json);
/* print prefix and mask */
if (!use_json) {
if (!display)
- route_vty_out_route(p, vty, NULL, false);
+ route_vty_out_route(path->net, p, vty, NULL, false);
else
vty_out(vty, "%*s", 17, " ");
}
vty_out(vty, ", valid");
}
+ if (json_paths)
+ json_object_int_add(json_path, "version", bn->version);
+
if (path->peer != bgp->peer_self) {
if (path->peer->as == path->peer->local_as) {
if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) {
vty_out(vty, "\n");
/* Line 4 display Community */
- if (attr->community) {
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES)) {
if (json_paths) {
if (!attr->community->json)
community_str(attr->community, true);
for (; pi; pi = pi->next) {
total_count++;
+ if (type == bgp_show_type_prefix_version) {
+ uint32_t version =
+ strtoul(output_arg, NULL, 10);
+ if (dest->version < version)
+ continue;
+ }
+
if (type == bgp_show_type_rpki) {
if (dest_p->family == AF_INET
|| dest_p->family == AF_INET6)
vty_out(vty, BGP_SHOW_SCODE_HEADER);
vty_out(vty, BGP_SHOW_NCODE_HEADER);
vty_out(vty, BGP_SHOW_OCODE_HEADER);
+ vty_out(vty, BGP_SHOW_RPKI_HEADER);
if (type == bgp_show_type_dampend_paths
|| type == bgp_show_type_damp_neighbor)
vty_out(vty, BGP_SHOW_DAMP_HEADER);
flap_route_vty_out(vty, dest_p, pi, display,
AFI_IP, safi, use_json,
json_paths);
- else
- route_vty_out(vty, dest_p, pi, display, safi,
- json_paths, wide);
+ else {
+ if (CHECK_FLAG(show_flags, BGP_SHOW_OPT_DETAIL))
+ route_vty_out_detail(
+ vty, bgp, dest, pi,
+ family2afi(dest_p->family),
+ safi, RPKI_NOT_BEING_USED,
+ json_paths);
+ else
+ route_vty_out(vty, dest_p, pi, display,
+ safi, json_paths, wide);
+ }
display++;
}
}
} else {
if (!json) {
- vty_out(vty, "BGP routing table entry for %s%s%pFX\n",
+ vty_out(vty,
+ "BGP routing table entry for %s%s%pFX, version %" PRIu64
+ "\n",
((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)
? prefix_rd2str(prd, buf1,
sizeof(buf1))
: ""),
- safi == SAFI_MPLS_VPN ? ":" : "", p);
+ safi == SAFI_MPLS_VPN ? ":" : "", p,
+ dest->version);
- } else
+ } else {
json_object_string_add(json, "prefix",
prefix2str(p, prefix_str, sizeof(prefix_str)));
+ json_object_int_add(json, "version", dest->version);
+
+ }
}
if (has_valid_label) {
struct bgp *bgp = NULL;
bool uj = use_json(argc, argv);
- if (uj)
- argc--;
+ if (uj)
+ argc--;
- bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
- &bgp, uj);
- if (!idx)
- return CMD_WARNING;
+ bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
+ &bgp, uj);
+ if (!idx)
+ return CMD_WARNING;
argv_find(argv, argc, "large-community-list", &idx);
|route-filter-v4|route-filter-translated-v6\
|route-filter-translated-v4] [exact-match]\
|rpki <invalid|valid|notfound>\
- ] [json$uj | wide$wide]",
+ |version (1-4294967295)\
+ ] [json$uj [detail$detail] | wide$wide]",
SHOW_STR
IP_STR
BGP_STR
"A valid path as determined by rpki\n"
"A invalid path as determined by rpki\n"
"A path that has no rpki data\n"
+ "Display prefixes with matching version numbers\n"
+ "Version number and above\n"
JSON_STR
+ "Display detailed version of JSON output\n"
"Increase table width for longer prefixes\n")
{
afi_t afi = AFI_IP6;
int idx = 0;
int exact_match = 0;
char *community = NULL;
+ char *prefix_version = NULL;
bool first = true;
uint8_t show_flags = 0;
enum rpki_states rpki_target_state = RPKI_NOT_BEING_USED;
SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
}
+ if (detail)
+ SET_FLAG(show_flags, BGP_SHOW_OPT_DETAIL);
+
/* [<ipv4|ipv6> [all]] */
if (all) {
SET_FLAG(show_flags, BGP_SHOW_OPT_AFI_ALL);
rpki_target_state = RPKI_INVALID;
}
+ /* Display prefixes with matching version numbers */
+ if (argv_find(argv, argc, "version", &idx)) {
+ sh_type = bgp_show_type_prefix_version;
+ prefix_version = argv[idx + 1]->arg;
+ }
+
if (!all) {
/* show bgp: AFI_IP6, show ip bgp: AFI_IP */
if (community)
return bgp_show_community(vty, bgp, community,
exact_match, afi, safi,
show_flags);
+ else if (prefix_version)
+ return bgp_show(vty, bgp, afi, safi, sh_type,
+ prefix_version, show_flags,
+ rpki_target_state);
else
return bgp_show(vty, bgp, afi, safi, sh_type, NULL,
show_flags, rpki_target_state);
bgp_show_community(vty, bgp, community,
exact_match, afi,
safi, show_flags);
+ else if (prefix_version)
+ return bgp_show(vty, bgp, afi, safi,
+ sh_type, prefix_version,
+ show_flags,
+ rpki_target_state);
else
bgp_show(vty, bgp, afi, safi, sh_type,
NULL, show_flags,
bgp_show_community(vty, bgp, community,
exact_match, afi,
safi, show_flags);
+ else if (prefix_version)
+ return bgp_show(vty, bgp, afi, safi,
+ sh_type, prefix_version,
+ show_flags,
+ rpki_target_state);
else
bgp_show(vty, bgp, afi, safi, sh_type,
NULL, show_flags,
vty_out(vty, BGP_SHOW_SCODE_HEADER);
vty_out(vty, BGP_SHOW_NCODE_HEADER);
vty_out(vty, BGP_SHOW_OCODE_HEADER);
+ vty_out(vty, BGP_SHOW_RPKI_HEADER);
}
*header1 = 0;
}
vty_out(vty, BGP_SHOW_SCODE_HEADER);
vty_out(vty, BGP_SHOW_NCODE_HEADER);
vty_out(vty, BGP_SHOW_OCODE_HEADER);
+ vty_out(vty, BGP_SHOW_RPKI_HEADER);
vty_out(vty, "Originating default network %s\n\n",
(afi == AFI_IP) ? "0.0.0.0/0" : "::/0");
&& (route_filtered || ret == RMAP_DENY))
(*filtered_count)++;
- route_vty_out_tmp(vty, rn_p, &attr, safi,
+ route_vty_out_tmp(vty, dest, rn_p, &attr, safi,
use_json, json_ar, wide);
bgp_attr_undup(&attr, ain->attr);
(*output_count)++;
}
}
route_vty_out_tmp(
- vty, rn_p, &attr, safi,
- use_json, json_ar,
+ vty, dest, rn_p, &attr,
+ safi, use_json, json_ar,
wide);
(*output_count)++;
} else {
if (!CHECK_FLAG(pi->flags, BGP_PATH_SELECTED))
continue;
- route_vty_out_tmp(vty,
+ route_vty_out_tmp(vty, dest,
bgp_dest_get_prefix(dest),
pi->attr, safi, use_json,
json_ar, wide);
bgp_show_type_damp_neighbor,
bgp_show_type_detail,
bgp_show_type_rpki,
+ bgp_show_type_prefix_version,
};
enum bgp_show_adj_route_type {
"Status codes: s suppressed, d damped, " \
"h history, * valid, > best, = multipath,\n" \
" i internal, r RIB-failure, S Stale, R Removed\n"
-#define BGP_SHOW_OCODE_HEADER "Origin codes: i - IGP, e - EGP, ? - incomplete\n\n"
+#define BGP_SHOW_OCODE_HEADER \
+ "Origin codes: i - IGP, e - EGP, ? - incomplete\n"
#define BGP_SHOW_NCODE_HEADER "Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self\n"
+#define BGP_SHOW_RPKI_HEADER \
+ "RPKI validation codes: V valid, I invalid, N Not found\n\n"
#define BGP_SHOW_HEADER " Network Next Hop Metric LocPrf Weight Path\n"
#define BGP_SHOW_HEADER_WIDE " Network Next Hop Metric LocPrf Weight Path\n"
#define BGP_SHOW_OPT_AFI_IP6 (1 << 4)
#define BGP_SHOW_OPT_ESTABLISHED (1 << 5)
#define BGP_SHOW_OPT_FAILED (1 << 6)
+#define BGP_SHOW_OPT_DETAIL (1 << 7)
/* Prototypes. */
extern void bgp_rib_remove(struct bgp_dest *dest, struct bgp_path_info *pi,
extern void route_vty_out_tag(struct vty *vty, const struct prefix *p,
struct bgp_path_info *path, int display,
safi_t safi, json_object *json);
-extern void route_vty_out_tmp(struct vty *vty, const struct prefix *p,
- struct attr *attr, safi_t safi, bool use_json,
- json_object *json_ar, bool wide);
+extern void route_vty_out_tmp(struct vty *vty, struct bgp_dest *dest,
+ const struct prefix *p, struct attr *attr,
+ safi_t safi, bool use_json, json_object *json_ar,
+ bool wide);
extern void route_vty_out_overlay(struct vty *vty, const struct prefix *p,
struct bgp_path_info *path, int display,
json_object *json);
}
if ((flags & UPDWALK_FLAGS_ADVQUEUE) && adj->adv
&& adj->adv->baa) {
- route_vty_out_tmp(vty, dest_p,
+ route_vty_out_tmp(vty, dest, dest_p,
adj->adv->baa->attr,
SUBGRP_SAFI(subgrp),
0, NULL, false);
}
if ((flags & UPDWALK_FLAGS_ADVERTISED)
&& adj->attr) {
- route_vty_out_tmp(vty, dest_p,
+ route_vty_out_tmp(vty, dest, dest_p,
adj->attr,
SUBGRP_SAFI(subgrp),
0, NULL, false);
}
rd_header = 0;
}
- route_vty_out_tmp(vty, bgp_dest_get_prefix(rm), attr,
- safi, use_json, json_routes, false);
+ route_vty_out_tmp(vty, rm, bgp_dest_get_prefix(rm),
+ attr, safi, use_json, json_routes,
+ false);
output_count++;
}
NB_OP_MODIFY, "true");
}
- nb_cli_pending_commit_check(vty);
ret = nb_cli_apply_changes(vty, base_xpath);
if (ret == CMD_SUCCESS) {
VTY_PUSH_XPATH(BGP_NODE, base_xpath);
* For backward compatibility with old commands we still
* need to use the qobj infrastructure.
*/
+ nb_cli_pending_commit_check(vty);
bgp = bgp_lookup(as, name);
if (bgp)
VTY_PUSH_CONTEXT(BGP_NODE, bgp);
+++ /dev/null
-! -*- bgp -*-
-!
-! BGPd sample configuration file
-!
-! $Id: bgpd.conf.sample,v 1.1 2002/12/13 20:15:29 paul Exp $
-!
-hostname bgpd
-password zebra
-!enable password please-set-at-here
-!
-!
-router bgp 7675
-! bgp router-id 10.0.0.1
-! network 10.0.0.0/8
-! neighbor 10.0.0.2 remote-as 7675
-! neighbor 10.0.0.2 ebgp-multihop
-!
-! address-family ipv4 unicast
-! neighbor 10.0.0.2 route-map set-nexthop out
-! neighbor 10.0.0.2 next-hop-self
-! exit-address-family
-!
-! access-list all permit any
-!
-!route-map set-nexthop permit 10
-! match ip address all
-! set ip next-hop 10.0.0.1
-!
-!log file bgpd.log
-!
-log stdout
+++ /dev/null
-hostname H192.1.1.1
-password zebra
-#enable password zebra
-log stdout notifications
-log monitor notifications
-#debug bgp
-
-line vty
-exec-timeout 1000
-exit
-
-
-router bgp 64512
-
- # Must set a router-id if no zebra (default 0.0.0.0)
- bgp router-id 192.1.1.1
-
- neighbor 192.1.1.2 remote-as 64512
- neighbor 192.1.1.2 description H192.1.1.2
- neighbor 192.1.1.2 update-source 192.1.1.1
- neighbor 192.1.1.2 advertisement-interval 1
-
- neighbor 192.1.1.3 remote-as 64512
- neighbor 192.1.1.3 description H192.1.1.3
- neighbor 192.1.1.3 update-source 192.1.1.1
- neighbor 192.1.1.3 advertisement-interval 1
-
- address-family ipv4 unicast
- no neighbor 192.1.1.2 activate
- no neighbor 192.1.1.3 activate
-
- address-family vpnv4
- neighbor 192.1.1.2 activate
- neighbor 192.1.1.3 activate
- exit-address-family
-
- address-family vpnv6
- neighbor 192.1.1.2 activate
- neighbor 192.1.1.3 activate
- exit-address-family
-
- vnc defaults
- rd auto:vn:5226
- response-lifetime 45
- rt both 1000:1 1000:2
- exit-vnc
-
- vnc nve-group group1
- prefix vn 172.16.0.0/16
- exit-vnc
-
- vnc nve-group red
- prefix vn 10.0.0.0/8
- rd auto:vn:10
- rt both 1000:10
- exit-vnc
-
- vnc nve-group blue
- prefix vn 20.0.0.0/8
- rd auto:vn:20
- rt both 1000:20
- exit-vnc
-
- vnc nve-group green
- prefix vn 30.0.0.0/8
- rd auto:vn:20
- rt both 1000:30
- exit-vnc
-
- vnc nve-group rfc4291v6c
- prefix vn ::ac10:0/112
- rd auto:vn:5227
- rt both 2000:1
- exit-vnc
-
- vnc nve-group rfc4291v6m
- prefix vn ::ffff:ac10:0/112
- rd auto:vn:5528
- rt both 3000:1
- exit-vnc
-
- vnc nve-group rfc6052v6
- prefix vn 64:ff9b::ac10:0/112
- rd auto:vn:5529
- rt both 4000:1
- exit-vnc
-
-exit
-
-
-
noinst_LIBRARIES += bgpd/libbgp.a
sbin_PROGRAMS += bgpd/bgpd
noinst_PROGRAMS += bgpd/bgp_btoa
-dist_examples_DATA += \
- bgpd/bgpd.conf.sample \
- bgpd/bgpd.conf.sample2 \
- bgpd/bgpd.conf.vnc.sample \
- # end
vtysh_scan += \
bgpd/bgp_bfd.c \
bgpd/bgp_debug.c \
etc/iproute2/rt_protos.d/
etc/logrotate.d/
usr/share/doc/frr/
-usr/share/doc/frr/examples/
usr/share/lintian/overrides/
usr/share/yang/
var/log/frr/
debian/frr.conf usr/lib/tmpfiles.d
etc/
+tools/etc/frr/frr.conf etc/frr/
tools/frr-reload usr/lib/frr/
usr/bin/mtracebis
usr/bin/vtysh
usr/lib/frr/*d
usr/lib/frr/watchfrr
usr/lib/frr/zebra
-usr/share/doc/frr/examples
usr/share/man/
usr/share/yang/
override_dh_auto_configure:
$(shell dpkg-buildflags --export=sh); \
dh_auto_configure -- \
- --enable-exampledir=/usr/share/doc/frr/examples/ \
--localstatedir=/var/run/frr \
--sbindir=/usr/lib/frr \
--sysconfdir=/etc/frr \
cp -r tools/etc/* debian/tmp/etc/
-rm debian/tmp/etc/frr/daemons.conf
- sed -e 's#^!log file #!log file /var/log/frr/#' -i debian/tmp/usr/share/doc/frr/examples/*sample*
-
# drop dev-only files
find debian/tmp -name '*.la' -o -name '*.a' -o -name 'lib*.so' | xargs rm -f
rm -rf debian/tmp/usr/include
* Centos 7
* Centos 8
+The following platform images are used to support Travis CI and can also
+be used to reproduce topotest failures when the docker host is Ubuntu
+(tested on 18.04 and 20.04):
+
+* Ubuntu 18.04
+* Ubuntu 20.04
+
The following platform images may also be built, but these simply install a
binary package from an existing repository and do not perform source builds:
No script, multi-arch (ex. amd64, arm64)::
docker buildx build --platform linux/amd64,linux/arm64 -f docker/centos-8/Dockerfile -t frr-centos8:latest .
+
+
+
+Building Ubuntu 18.04 Image
+---------------------------
+
+Build image (from project root directory)::
+
+ docker build -t frr-ubuntu18:latest -f docker/ubuntu18-ci/Dockerfile .
+
+Start the container::
+
+ docker run -d --privileged --name frr-ubuntu18 --mount type=bind,source=/lib/modules,target=/lib/modules frr-ubuntu18:latest
+
+Running a topotest (when the docker host is Ubuntu)::
+
+ docker exec frr-ubuntu18 bash -c 'cd ~/frr/tests/topotests/ospf-topo1 ; sudo pytest test_ospf_topo1.py'
+
+Starting an interactive bash session::
+
+ docker exec -it frr-ubuntu18 bash
+
+Stopping an removing a container::
+
+ docker stop frr-ubuntu18 ; docker rm frr-ubuntu18
+
+Removing the built image::
+
+ docker rmi frr-ubuntu18:latest
+
+
+Building Ubuntu 20.04 Image
+---------------------------
+
+Build image (from project root directory)::
+
+ docker build -t frr-ubuntu20:latest -f docker/ubuntu20-ci/Dockerfile .
+
+Start the container::
+
+ docker run -d --privileged --name frr-ubuntu20 --mount type=bind,source=/lib/modules,target=/lib/modules frr-ubuntu20:latest
+
+Running a topotest (when the docker host is Ubuntu)::
+
+ docker exec frr-ubuntu20 bash -c 'cd ~/frr/tests/topotests/ospf-topo1 ; sudo pytest test_ospf_topo1.py'
+
+Starting an interactive bash session::
+
+ docker exec -it frr-ubuntu20 bash
+
+Stopping an removing a container::
+
+ docker stop frr-ubuntu20 ; docker rm frr-ubuntu20
+
+Removing the built image::
+
+ docker rmi frr-ubuntu20:latest
docker exec -it frr /bin/sh
vi /etc/frr/daemons
- cp /etc/frr/zebra.conf.sample /etc/frr/zebra.conf
- vi /etc/frr/zebra.conf
/etc/init.d/frr start
Or, to configure the daemons using /etc/frr from a host volume, put the
When executing cli that does not invoke a vtysh shell, if an error ocurrs ignore it for purposes of return codes from vtysh.
+.. option:: -H, --histfile
+
+ Override the history file for vtysh commands. You can set ``vtysh -H /dev/null`` to turn logging of at all.
+
.. option:: -u, --user
Restrict access to configuration commands by preventing use of the "enable" command. This option provides the same limited "security" as password-protected telnet access. *This security should not be relied on in production environments.*
VTYSH_PAGER
This should be the name of the pager to use. Default is more.
+VTYSH_HISTFILE
+ Override the history file for vtysh commands. Logging can be turned off using ``VTYSH_HISTFILE=/dev/null vtysh``.
+ Environment is prefered way to override the history file path over command line argument (-H/--histfile).
+
FILES
=====
|INSTALL_PREFIX_SBIN|/vtysh
.. note::
If you have compiled with the ``NO_DEBUG`` flag, then these commands aren't
available.
+
+
+Babel sample configuration file
+===============================
+
+.. code-block:: frr
+
+ debug babel common
+ !debug babel kernel
+ !debug babel filter
+ !debug babel timeout
+ !debug babel interface
+ !debug babel route
+ !debug babel all
+
+ router babel
+ ! network wlan0
+ ! network eth0
+ ! redistribute ipv4 kernel
+ ! no redistribute ipv6 static
+
+ ! The defaults are fine for a wireless interface
+
+ !interface wlan0
+
+ ! A few optimisation tweaks are optional but recommended on a wired interface
+ ! Disable link quality estimation, enable split horizon processing, and
+ ! increase the hello and update intervals.
+
+ !interface eth0
+ ! babel wired
+ ! babel split-horizon
+ ! babel hello-interval 12000
+ ! babel update-interval 36000
+
+ ! log file /var/log/quagga/babeld.log
+ log stdout
+
Send a message to all logging destinations that are enabled for messages of
the given severity.
-.. clicmd:: find COMMAND...
+.. clicmd:: find REGEX...
- This command performs a simple substring search across all defined commands
- in all modes. As an example, suppose you're in enable mode and can't
- remember where the command to turn OSPF segment routing on is:
+ This command performs a regex search across all defined commands in all
+ modes. As an example, suppose you're in enable mode and can't remember where
+ the command to turn OSPF segment routing on is:
::
frr# find segment-routing on
(ospf) segment-routing on
+ (isis) segment-routing on
+
The CLI mode is displayed next to each command. In this example,
:clicmd:`segment-routing on` is under the `router ospf` mode.
- Similarly, suppose you want a listing of all commands that contain "l2vpn":
+ Similarly, suppose you want a listing of all commands that contain "l2vpn"
+ and "neighbor":
::
- frr# find l2vpn
- (view) show [ip] bgp l2vpn evpn [json]
- (view) show [ip] bgp l2vpn evpn all <A.B.C.D|A.B.C.D/M> [json]
- (view) show [ip] bgp l2vpn evpn all neighbors A.B.C.D advertised-routes [json]
- (view) show [ip] bgp l2vpn evpn all neighbors A.B.C.D routes [json]
- (view) show [ip] bgp l2vpn evpn all overlay
+ frr# find l2vpn.*neighbor
+ (view) show [ip] bgp l2vpn evpn neighbors <A.B.C.D|X:X::X:X|WORD> advertised-routes [json]
+ (view) show [ip] bgp l2vpn evpn neighbors <A.B.C.D|X:X::X:X|WORD> routes [json]
+ (view) show [ip] bgp l2vpn evpn rd ASN:NN_OR_IP-ADDRESS:NN neighbors <A.B.C.D|X:X::X:X|WORD> advertised-routes [json]
+ (view) show [ip] bgp l2vpn evpn rd ASN:NN_OR_IP-ADDRESS:NN neighbors <A.B.C.D|X:X::X:X|WORD> routes [json]
...
+
+ Note that when entering spaces as part of a regex specification, repeated
+ spaces will be compressed into a single space for matching purposes. This is
+ a consequence of spaces being used to delimit CLI tokens. If you need to
+ match more than one space, use the ``\s`` escape.
+
+ POSIX Extended Regular Expressions are supported.
+
+
.. _common-show-commands:
.. clicmd:: show thread cpu [r|w|t|e|x]
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
+ RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
*> 0.0.0.0/0 10.10.10.1 0 0 1 i
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
+ RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
*> 0.0.0.0/0 0.0.0.0 0 1 i
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
+ RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
*> 10.139.224.0/20 10.10.10.1 0 0 1 ?
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
+ RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
*> 10.139.224.0/20 0.0.0.0 0 1 ?
has been done to keep old format with IPv4 routing table, while new format
displays IPv6 routing table.
-.. clicmd:: show ip bgp [all] [wide|json]
+.. clicmd:: show ip bgp [all] [wide|json [detail]]
.. clicmd:: show ip bgp A.B.C.D [json]
-.. clicmd:: show bgp [all] [wide|json]
+.. clicmd:: show bgp [all] [wide|json [detail]]
.. clicmd:: show bgp X:X::X:X [json]
If ``json`` option is specified, output is displayed in JSON format.
+ If ``detail`` option is specified after ``json``, more verbose JSON output
+ will be displayed.
+
Some other commands provide additional options for filtering the output.
.. clicmd:: show [ip] bgp regexp LINE
Display flap statistics of routes of the selected afi and safi selected.
+.. clicmd:: show bgp [afi] [safi] [all] version (1-4294967295) [wide|json]
+
+ Display prefixes with matching version numbers. The version number and
+ above having prefixes will be listed here.
+
+ It helps to identify which prefixes were installed at some point.
+
+ Here is an example of how to check what prefixes were installed starting
+ with an arbitrary version::
+
+ .. code-block:: frr
+
+ ~# vtysh -c 'show bgp ipv4 unicast json' | jq '.tableVersion'
+ 9
+ ~# vtysh -c 'show ip bgp version 9 json' | jq -r '.routes | keys[]'
+ 192.168.3.0/24
+ ~# vtysh -c 'show ip bgp version 8 json' | jq -r '.routes | keys[]'
+ 192.168.2.0/24
+ 192.168.3.0/24
+
.. clicmd:: show bgp [afi] [safi] statistics
Display statistics of routes of the selected afi and safi.
``show debugging eigrp`` will show all information currently set for eigrpd
debug.
+
+Sample configuration
+====================
+
+.. code-block:: frr
+
+ hostname eigrpd
+ password zebra
+ enable password please-set-at-here
+ !
+ router eigrp 4453
+ network 192.168.1.0/24
+ !
+ log stdout
+
.. clicmd:: set-overload-bit
-
Set overload bit to avoid any transit traffic.
.. clicmd:: purge-originator
Print which OpenFabric debug levels are active.
-
-OpenFabric configuration example
-================================
+Sample configuration
+====================
A simple example:
!
router openfabric 1
net 49.0000.0000.0001.00
+
+
+Alternative example:
+
+.. code-block:: frr
+
+ hostname fabricd
+
+ router openfabric DEAD
+ net 47.0023.0000.0003.0300.0100.0102.0304.0506.00
+ lsp-lifetime 65535
+
+ hostname isisd-router
+ domain-password foobar
+
+ interface eth0
+ ip router openfabric DEAD
+ openfabric hello-interval 5
+ openfabric lsp-interval 1000
+
+ ! -- optional
+ openfabric retransmit-interval 10
+ openfabric retransmit-throttle-interval
description to the prefix list.
-.. _ip-prefix-list-sequential-number-control:
-
-ip prefix-list sequential number control
-----------------------------------------
-
-.. clicmd:: ip prefix-list sequence-number
-
- With this command, the IP prefix list sequential number is displayed.
- This is the default behavior.
-
-
.. _showing-ip-prefix-list:
Showing ip prefix-list
- ``messages``
- ``zebra``
-LDP Example Configuration
-=========================
+
+Sample configuration
+====================
Below configuration gives a typical MPLS configuration of a device located in a
MPLS backbone. LDP is enabled on two interfaces and will attempt to peer with
O>* 10.200.0.0/24 [110/210] via 10.115.0.1, eth2, label 17, 00:00:15
north-vm#
+
+Additional example demonstrating use of some miscellaneous config options:
+
+.. code-block:: frr
+
+ interface eth0
+ !
+ interface eth1
+ !
+ interface lo
+ !
+ mpls ldp
+ dual-stack cisco-interop
+ neighbor 10.0.1.5 password opensourcerouting
+ neighbor 172.16.0.1 password opensourcerouting
+ !
+ address-family ipv4
+ discovery transport-address 10.0.1.1
+ label local advertise explicit-null
+ !
+ interface eth0
+ !
+ interface eth1
+ !
+ !
+ address-family ipv6
+ discovery transport-address 2001:db8::1
+ !
+ interface eth1
+ !
+ !
+ !
+ l2vpn ENG type vpls
+ bridge br0
+ member interface eth2
+ !
+ member pseudowire mpw0
+ neighbor lsr-id 1.1.1.1
+ pw-id 100
+ !
+ !
+
Actively maintained patches are also available at:
https://gitlab.alpinelinux.org/alpine/aports/-/tree/master/main/strongswan
+.. _multicast-functionality:
+
+Multicast Functionality
+=======================
+
+nhrpd can be configured to forward multicast packets, allowing routing
+protocols that use multicast (such as OSPF) to be supported in the DMVPN
+network.
+
+This support requires an iptables NFLOG rule to allow nhrpd to intercept
+multicast packets. A second iptables rule is also usually used to drop the
+original multicast packet.
+
+ .. code-block:: shell
+
+ iptables -A OUTPUT -d 224.0.0.0/24 -o gre1 -j NFLOG --nflog-group 2
+ iptables -A OUTPUT -d 224.0.0.0/24 -o gre1 -j DROP
+
+.. index:: nhrp multicast-nflog-group (1-65535)
+.. clicmd:: nhrp multicast-nflog-group (1-65535)
+
+ Sets the nflog group that nhrpd will listen on for multicast packets. This
+ value must match the nflog-group value set in the iptables rule.
+
+.. index:: ip nhrp map multicast A.B.C.D|X:X::X:X A.B.C.D|dynamic
+.. clicmd:: ip nhrp map multicast A.B.C.D|X:X::X:X A.B.C.D|dynamic
+
+ Sends multicast packets to the specified NBMA address. If dynamic is
+ specified then destination NBMA address (or addresses) are learnt
+ dynamically.
+
.. _nhrp-events:
NHRP Events
JSON object, with each router having "cost", "isLeafNode" and "children" as
arguments.
-OSPF6 Configuration Examples
-============================
+
+Sample configuration
+====================
Example of ospf6d configured on one interface and area:
area 0.0.0.0 range 2001:770:105:2::/64
interface eth0 area 0.0.0.0
!
+
+
+Larger example with policy and various options set:
+
+
+.. code-block:: frr
+
+ debug ospf6 neighbor state
+ !
+ interface fxp0
+ ipv6 ospf6 cost 1
+ ipv6 ospf6 hello-interval 10
+ ipv6 ospf6 dead-interval 40
+ ipv6 ospf6 retransmit-interval 5
+ ipv6 ospf6 priority 0
+ ipv6 ospf6 transmit-delay 1
+ ipv6 ospf6 instance-id 0
+ !
+ interface lo0
+ ipv6 ospf6 cost 1
+ ipv6 ospf6 hello-interval 10
+ ipv6 ospf6 dead-interval 40
+ ipv6 ospf6 retransmit-interval 5
+ ipv6 ospf6 priority 1
+ ipv6 ospf6 transmit-delay 1
+ ipv6 ospf6 instance-id 0
+ !
+ router ospf6
+ router-id 255.1.1.1
+ redistribute static route-map static-ospf6
+ interface fxp0 area 0.0.0.0
+ !
+ access-list access4 permit 127.0.0.1/32
+ !
+ ipv6 access-list access6 permit 3ffe:501::/32
+ ipv6 access-list access6 permit 2001:200::/48
+ ipv6 access-list access6 permit ::1/128
+ !
+ ipv6 prefix-list test-prefix seq 1000 deny any
+ !
+ route-map static-ospf6 permit 10
+ match ipv6 address prefix-list test-prefix
+ set metric-type type-2
+ set metric 2000
+ !
+ line vty
+ access-class access4
+ ipv6 access-class access6
+ exec-timeout 0 0
+ !
This command enables or disables sending ARP requests to update neighbor
table entries. It speeds up convergence for /32 networks on a P2P
- connection.
+ connection.
This feature is enabled by default.
command can be used when the neighbor state get stuck at some state and
this can be used to recover it from that state.
-.. index:: maximum-paths " CMD_RANGE_STR(1, MULTIPATH_NUM)
-.. clicmd:: maximum-paths " CMD_RANGE_STR(1, MULTIPATH_NUM)
+.. clicmd:: maximum-paths (1-64)
-.. index:: maximum-paths " CMD_RANGE_STR(1, MULTIPATH_NUM)
-.. clicmd:: no maximum-paths
-
- CLI to control maximum number of equal cost paths to reach a specific
- destination.(ECMP)
- Reset CLI, resets the maximum supported multi path to the default value.
+ Use this command to control the maximum number of equal cost paths to reach
+ a specific destination. The upper limit may differ if you change the value
+ of MULTIPATH_NUM during compilation. The default is MULTIPATH_NUM (64).
.. _ospf-area:
:clicmd:`ip ospf dead-interval minimal hello-multiplier (2-20)` is also
specified for the interface.
-.. clicmd:: ip ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point)
+.. clicmd:: ip ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point [dmvpn])
When configuring a point-to-point network on an interface and the interface
has a /32 address associated with then OSPF will treat the interface
net.ipv4.conf.<interface name>.rp_filter value to 0. In order for
the ospf multicast packets to be delivered by the kernel.
+ When used in a DMVPN network at a spoke, this OSPF will be configured in
+ point-to-point, but the HUB will be a point-to-multipoint. To make this
+ topology work, specify the optional 'dmvpn' parameter at the spoke.
Set explicitly network type for specified interface.
Debug commnd to enable/disable external route summarisation specific debugs.
-OSPF Configuration Examples
-===========================
+
+Sample Configuration
+====================
A simple example, with MD5 authentication enabled:
!
In this case, the SR Policy with color `1` and endpoint `1.1.1.1` is selected.
+
+
+Sample configuration
+====================
+
+.. code-block:: frr
+
+ ! Default pathd configuration sample
+ !
+ password frr
+ log stdout
+
+ segment-routing
+ traffic-eng
+ segment-list test1
+ index 10 mpls label 123
+ index 20 mpls label 456
+ !
+ segment-list test2
+ index 10 mpls label 321
+ index 20 mpls label 654
+ !
+ policy color 1 endpoint 1.1.1.1
+ name one
+ binding-sid 100
+ candidate-path preference 100 name test1 explicit segment-list test1
+ candidate-path preference 200 name test2 explicit segment-list test2
+ !
+ policy color 2 endpoint 2.2.2.2
+ name two
+ binding-sid 101
+ candidate-path preference 100 name def explicit segment-list test2
+ candidate-path preference 200 name dyn dynamic
+ bandwidth 12345
+ metric bound abc 16 required
+ metric te 10
+ !
+ !
+ pcep
+ pcc-peer PCE1
+ address ip 127.0.0.1
+ sr-draft07
+ !
+ pcc
+ peer PCE1
+ !
+ !
+ !
+
The creation of a nexthop or nexthop-group is translated to a default route in a
table with the nexthops specified as the nexthops for the default route.
+
+Sample configuration
+====================
+
+.. code-block:: frr
+
+ nexthop-group TEST
+ nexthop 4.5.6.7
+ nexthop 5.6.7.8
+ !
+ pbr-map BLUE seq 100
+ match dst-ip 9.9.9.0/24
+ match src-ip 10.10.10.0/24
+ set nexthop-group TEST
+ !
+ int swp1
+ pbr-policy BLUE
+
+
- Enable pim on the underlay L3 interface via the "ip pim" command.
- Configure RPs for the BUM multicast group range.
- Ensure the PIM is enabled on the lo of the VTEPs and the RP.
+
+
+Sample configuration
+====================
+
+.. code-block:: frr
+
+ debug igmp
+ debug pim
+ debug pim zebra
+
+ ! You may want to enable ssmpingd for troubleshooting
+ ! See http://www.venaas.no/multicast/ssmping/
+ !
+ ip ssmpingd 1.1.1.1
+ ip ssmpingd 2.2.2.2
+
+ ! HINTS:
+ ! - Enable "ip pim ssm" on the interface directly attached to the
+ ! multicast source host (if this is the first-hop router)
+ ! - Enable "ip pim ssm" on pim-routers-facing interfaces
+ ! - Enable "ip igmp" on IGMPv3-hosts-facing interfaces
+ ! - In order to inject IGMPv3 local membership information in the
+ ! PIM protocol state, enable both "ip pim ssm" and "ip igmp" on
+ ! the same interface; otherwise PIM won't advertise
+ ! IGMPv3-learned membership to other PIM routers
+
+ interface eth0
+ ip pim ssm
+ ip igmp
+
Shows all information currently set for ripd debug.
+
+Sample configuration
+====================
+
+.. code-block:: frr
+
+
+ debug rip events
+ debug rip packet
+
+ router rip
+ network 11.0.0.0/8
+ network eth0
+ route 10.0.0.0/8
+ distribute-list private-only in eth0
+
+ access-list private-only permit 10.0.0.0/8
+ access-list private-only deny any
distribute-list local-only out sit1
+
+Sample configuration
+====================
+
+.. code-block:: frr
+
+ debug ripng events
+ debug ripng packet
+
+ router ripng
+ network sit1
+ route 3ffe:506::0/32
+ distribute-list local-only out sit1
+
+ ipv6 access-list local-only permit 3ffe:506::0/32
+ ipv6 access-list local-only deny any
Route Map Optimization Command
==============================
-.. clicmd:: route-map optimization
+.. clicmd:: route-map ROUTE-MAP-NAME optimization
- Enable route-map processing optimization. The optimization is
- enabled by default.
+ Enable route-map processing optimization for `route-map-name`.
+ The optimization is enabled by default.
Instead of sequentially passing through all the route-map indexes
until a match is found, the search for the best-match index will be
based on a look-up in a prefix-tree. A per-route-map prefix-tree
# This stage builds a dist tarball from the source
-FROM alpine:latest as source-builder
+FROM alpine:3.13 as source-builder
RUN mkdir -p /src/alpine
COPY alpine/APKBUILD.in /src/alpine
&& make dist
# This stage builds an apk from the dist tarball
-FROM alpine:latest as alpine-builder
+FROM alpine:3.13 as alpine-builder
# Don't use nocache here so that abuild can use the cache
RUN apk add \
--update-cache \
&& abuild -r -P /pkgs/apk
# This stage installs frr from the apk
-FROM alpine:latest
+FROM alpine:3.13
RUN mkdir -p /pkgs/apk
COPY --from=alpine-builder /pkgs/apk/ /pkgs/apk/
RUN apk add \
--- /dev/null
+FROM ubuntu:18.04
+
+ARG DEBIAN_FRONTEND=noninteractive
+ENV APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn
+# Update Ubuntu Software repository
+RUN apt update && \
+ apt-get install -y \
+ git autoconf automake libtool make libreadline-dev texinfo \
+ pkg-config libpam0g-dev libjson-c-dev bison flex python3-pytest \
+ libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \
+ install-info build-essential libsystemd-dev libsnmp-dev perl libcap-dev \
+ libelf-dev \
+ sudo gdb iputils-ping time \
+ mininet python-pip iproute2 iperf && \
+ pip install ipaddr && \
+ pip install "pytest<5" && \
+ pip install "scapy>=2.4.2" && \
+ pip install exabgp==3.4.17
+
+RUN groupadd -r -g 92 frr && \
+ groupadd -r -g 85 frrvty && \
+ adduser --system --ingroup frr --home /home/frr \
+ --gecos "FRR suite" --shell /bin/bash frr && \
+ usermod -a -G frrvty frr && \
+ useradd -d /var/run/exabgp/ -s /bin/false exabgp && \
+ echo 'frr ALL = NOPASSWD: ALL' | tee /etc/sudoers.d/frr && \
+ mkdir -p /home/frr && chown frr.frr /home/frr
+
+#for libyang 1
+RUN apt-get install -y cmake libpcre3-dev
+
+USER frr:frr
+
+# build and install libyang1
+RUN cd && pwd && ls -al && \
+ git clone https://github.com/CESNET/libyang.git && \
+ cd libyang && \
+ git checkout v1.0.225 && \
+ mkdir build; cd build && \
+ cmake -DENABLE_LYD_PRIV=ON -DCMAKE_INSTALL_PREFIX:PATH=/usr \
+ -D CMAKE_BUILD_TYPE:String="Release" .. && \
+ make -j $(nproc) && \
+ sudo make install
+
+COPY --chown=frr:frr . /home/frr/frr/
+
+RUN cd && ls -al && ls -al frr
+
+RUN cd ~/frr && \
+ ./bootstrap.sh && \
+ ./configure \
+ --prefix=/usr \
+ --localstatedir=/var/run/frr \
+ --sbindir=/usr/lib/frr \
+ --sysconfdir=/etc/frr \
+ --enable-vtysh \
+ --enable-pimd \
+ --enable-sharpd \
+ --enable-multipath=64 \
+ --enable-user=frr \
+ --enable-group=frr \
+ --enable-vty-group=frrvty \
+ --enable-snmp=agentx \
+ --with-pkg-extra-version=-my-manual-build && \
+ make -j $(nproc) && \
+ sudo make install
+
+RUN cd ~/frr && make check || true
+
+COPY docker/ubuntu18-ci/docker-start /usr/sbin/docker-start
+ENTRYPOINT ["/usr/sbin/docker-start"]
--- /dev/null
+# Ubuntu 18.04
+
+This builds an ubuntu 18.04 container for dev / test
+
+# Build
+
+```
+docker build -t frr-ubuntu18:latest -f docker/ubuntu18-ci/Dockerfile .
+```
+
+# Running
+
+```
+docker run -d --privileged --name frr-ubuntu18 --mount type=bind,source=/lib/modules,target=/lib/modules frr-ubuntu18:latest
+```
+
+# make check
+
+```
+docker exec frr-ubuntu18 bash -c 'cd ~/frr ; make check'
+```
+
+# interactive bash
+```
+docker exec -it frr-ubuntu18 bash
+```
+
+# topotest -- when Host O/S is Ubuntu only
+
+```
+docker exec frr-ubuntu18 bash -c 'cd ~/frr/tests/topotests/ospf-topo1 ; sudo pytest test_ospf_topo1.py'
+```
+
+# stop & remove container
+
+```
+docker stop frr-ubuntu18 ; docker rm frr-ubuntu18
+```
+
+# remove image
+
+```
+docker rmi frr-ubuntu18:latest
+```
--- /dev/null
+#!/bin/bash
+
+if [ $(uname -a | grep -ci Ubuntu) -ge 1 ]; then
+ #for topotests under ubuntu host
+ sudo modprobe mpls-router mpls-iptunnel
+ sudo /etc/init.d/openvswitch-switch start
+fi
+while true ; do sleep 365d ; done
--- /dev/null
+FROM ubuntu:20.04
+
+ARG DEBIAN_FRONTEND=noninteractive
+ENV APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn
+# Update Ubuntu Software repository
+RUN apt update && \
+ apt-get install -y \
+ git autoconf automake libtool make libreadline-dev texinfo \
+ pkg-config libpam0g-dev libjson-c-dev bison flex python3-pytest \
+ libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \
+ install-info build-essential libsystemd-dev libsnmp-dev perl \
+ libcap-dev python2 libelf-dev \
+ sudo gdb curl iputils-ping time \
+ mininet iproute2 iperf && \
+ curl https://bootstrap.pypa.io/pip/2.7/get-pip.py --output /tmp/get-pip.py && \
+ python2 /tmp/get-pip.py && \
+ rm -f /tmp/get-pip.py && \
+ pip2 install ipaddr && \
+ pip2 install "pytest<5" && \
+ pip2 install "scapy>=2.4.2" && \
+ pip2 install exabgp==3.4.17
+
+RUN groupadd -r -g 92 frr && \
+ groupadd -r -g 85 frrvty && \
+ adduser --system --ingroup frr --home /home/frr \
+ --gecos "FRR suite" --shell /bin/bash frr && \
+ usermod -a -G frrvty frr && \
+ useradd -d /var/run/exabgp/ -s /bin/false exabgp && \
+ echo 'frr ALL = NOPASSWD: ALL' | tee /etc/sudoers.d/frr && \
+ mkdir -p /home/frr && chown frr.frr /home/frr
+
+#for libyang 1
+RUN apt-get install -y cmake libpcre3-dev
+
+USER frr:frr
+
+# build and install libyang1
+RUN cd && pwd && ls -al && \
+ git clone https://github.com/CESNET/libyang.git && \
+ cd libyang && \
+ git checkout v1.0.225 && \
+ mkdir build; cd build && \
+ cmake -DENABLE_LYD_PRIV=ON -DCMAKE_INSTALL_PREFIX:PATH=/usr \
+ -D CMAKE_BUILD_TYPE:String="Release" .. && \
+ make -j $(nproc) && \
+ sudo make install
+
+COPY --chown=frr:frr . /home/frr/frr/
+
+RUN cd && ls -al && ls -al frr
+
+RUN cd ~/frr && \
+ ./bootstrap.sh && \
+ ./configure \
+ --prefix=/usr \
+ --localstatedir=/var/run/frr \
+ --sbindir=/usr/lib/frr \
+ --sysconfdir=/etc/frr \
+ --enable-vtysh \
+ --enable-pimd \
+ --enable-sharpd \
+ --enable-multipath=64 \
+ --enable-user=frr \
+ --enable-group=frr \
+ --enable-vty-group=frrvty \
+ --enable-snmp=agentx \
+ --with-pkg-extra-version=-my-manual-build && \
+ make -j $(nproc) && \
+ sudo make install
+
+RUN cd ~/frr && make check || true
+
+COPY docker/ubuntu20-ci/docker-start /usr/sbin/docker-start
+ENTRYPOINT ["/usr/sbin/docker-start"]
--- /dev/null
+# Ubuntu 20.04
+
+This builds an ubuntu 20.04 container for dev / test
+
+# Build
+
+```
+docker build -t frr-ubuntu20:latest -f docker/ubuntu20-ci/Dockerfile .
+```
+
+# Running
+
+```
+docker run -d --privileged --name frr-ubuntu20 --mount type=bind,source=/lib/modules,target=/lib/modules frr-ubuntu20:latest
+```
+
+# make check
+
+```
+docker exec frr-ubuntu20 bash -c 'cd ~/frr ; make check'
+```
+
+# interactive bash
+
+```
+docker exec -it frr-ubuntu20 bash
+```
+
+# topotest -- when Host O/S is Ubuntu only
+
+```
+docker exec frr-ubuntu20 bash -c 'cd ~/frr/tests/topotests/ospf-topo1 ; sudo pytest test_ospf_topo1.py'
+```
+
+# stop & remove container
+
+```
+docker stop frr-ubuntu20 ; docker rm frr-ubuntu18
+```
+
+# remove image
+
+```
+docker rmi frr-ubuntu20:latest
+```
--- /dev/null
+#!/bin/bash
+
+if [ $(uname -a | grep -ci Ubuntu) -ge 1 ]; then
+ #for topotests under ubuntu host
+ sudo modprobe mpls-router mpls-iptunnel
+ sudo /etc/init.d/openvswitch-switch start
+fi
+while true ; do sleep 365d ; done
+++ /dev/null
-! -*- eigrpd -*-
-!
-! EIGRPDd sample configuration file
-!
-!
-hostname eigrpd
-password zebra
-!enable password please-set-at-here
-!
-!router eigrp 4453
-! network 192.168.1.0/24
-!
-log stdout
if EIGRPD
noinst_LIBRARIES += eigrpd/libeigrp.a
sbin_PROGRAMS += eigrpd/eigrpd
-dist_examples_DATA += eigrpd/eigrpd.conf.sample
vtysh_scan += \
eigrpd/eigrp_cli.c \
eigrpd/eigrp_dump.c \
+++ /dev/null
-! -*- openfabric -*-
-!
-! fabricd sample configuration file
-!
-hostname fabricd
-password foo
-enable password foo
-log stdout
-!log file /tmp/fabricd.log
-!
-!
-router openfabric DEAD
- net 47.0023.0000.0003.0300.0100.0102.0304.0506.00
-! lsp-lifetime 65535
-
-! hostname isisd-router
-! domain-password foobar
-
-interface eth0
- ip router openfabric DEAD
-! openfabric hello-interval 5
-! openfabric lsp-interval 1000
-
-! -- optional
-! openfabric retransmit-interval 10
-! openfabric retransmit-throttle-interval
-!
+++ /dev/null
-! -*- isis -*-
-!
-! ISISd sample configuration file
-!
-hostname isisd
-password foo
-enable password foo
-log stdout
-!log file /tmp/isisd.log
-!
-!
-router isis DEAD
- net 47.0023.0000.0003.0300.0100.0102.0304.0506.00
-! is-type level-1
-
-! -- set the lifetime either for level-1, level-2 or both
-! lsp-lifetime level-1 65535
-! lsp-lifetime level-2 65535
-! lsp-lifetime 65535
-
-! hostname isisd-router
-! area-password foobar
-! domain-password foobar
-
-interface eth0
- ip router isis DEAD
-! isis hello-interval 5
-! isis lsp-interval 1000
-
-! -- optional
-! isis circuit-type level-1
-! isis password lallaa level-1
-! isis metric 1 level-1
-! isis csnp-interval 5 level-1
-! isis retransmit-interval 10
-! isis retransmit-throttle-interval
-! isis hello-multiplier 2 level-1
-! isis priority 64
-!
if ISISD
noinst_LIBRARIES += isisd/libisis.a
sbin_PROGRAMS += isisd/isisd
-dist_examples_DATA += isisd/isisd.conf.sample
vtysh_scan += \
isisd/isis_cli.c \
isisd/isis_ldp_sync.c \
if FABRICD
noinst_LIBRARIES += isisd/libfabric.a
sbin_PROGRAMS += isisd/fabricd
-dist_examples_DATA += isisd/fabricd.conf.sample
if !ISISD
vtysh_scan += \
isisd/isis_cli.c \
+++ /dev/null
-! -*- ldp -*-
-!
-! LDPd sample configuration file
-!
-hostname ldpd
-password zebra
-log stdout
-!
-interface eth0
-!
-interface eth1
-!
-interface lo
-!
-mpls ldp
- dual-stack cisco-interop
- neighbor 10.0.1.5 password opensourcerouting
- neighbor 172.16.0.1 password opensourcerouting
- !
- address-family ipv4
- discovery transport-address 10.0.1.1
- label local advertise explicit-null
- !
- interface eth0
- !
- interface eth1
- !
- !
- address-family ipv6
- discovery transport-address 2001:db8::1
- !
- interface eth1
- !
- !
-!
-l2vpn ENG type vpls
- bridge br0
- member interface eth2
- !
- member pseudowire mpw0
- neighbor lsr-id 1.1.1.1
- pw-id 100
- !
-!
-line vty
-!
if LDPD
noinst_LIBRARIES += ldpd/libldp.a
sbin_PROGRAMS += ldpd/ldpd
-dist_examples_DATA += ldpd/ldpd.conf.sample
vtysh_scan += ldpd/ldp_vty_cmds.c
vtysh_daemons += ldpd
man8 += $(MANBUILD)/frr-ldpd.8
memset(sp, 0, sizeof(*sp));
/* Get interface index. */
- ifindex = stream_getl(s);
+ STREAM_GETL(s, ifindex);
/* Lookup index. */
if (ifindex != 0) {
}
/* Fetch destination address. */
- dp->family = stream_getc(s);
+ STREAM_GETC(s, dp->family);
plen = prefix_blen(dp);
- stream_get(&dp->u.prefix, s, plen);
- dp->prefixlen = stream_getc(s);
+ STREAM_GET(&dp->u.prefix, s, plen);
+ STREAM_GETC(s, dp->prefixlen);
/* Get BFD status. */
- *status = stream_getl(s);
+ STREAM_GETL(s, (*status));
- sp->family = stream_getc(s);
+ STREAM_GETC(s, sp->family);
plen = prefix_blen(sp);
- stream_get(&sp->u.prefix, s, plen);
- sp->prefixlen = stream_getc(s);
+ STREAM_GET(&sp->u.prefix, s, plen);
+ STREAM_GETC(s, sp->prefixlen);
- local_remote_cbit = stream_getc(s);
+ STREAM_GETC(s, local_remote_cbit);
if (remote_cbit)
*remote_cbit = local_remote_cbit;
return ifp;
+
+stream_failure:
+ return NULL;
}
/*
ifp = bfd_get_peer_info(zclient->ibuf, &dp, &sp, &state, &remote_cbit,
vrf_id);
+ /*
+ * When interface lookup fails or an invalid stream is read, we must
+ * not proceed otherwise it will trigger an assertion while checking
+ * family type below.
+ */
+ if (dp.family == 0 || sp.family == 0)
+ return 0;
if (bsglobal.debugging) {
ifstr[0] = 0;
DEFUN(find,
find_cmd,
- "find REGEX",
+ "find REGEX...",
"Find CLI command matching a regular expression\n"
"Search pattern (POSIX regex)\n")
{
- char *pattern = argv[1]->arg;
const struct cmd_node *node;
const struct cmd_element *cli;
vector clis;
regex_t exp = {};
+ char *pattern = argv_concat(argv, argc, 1);
int cr = regcomp(&exp, pattern, REG_NOSUB | REG_EXTENDED);
+ XFREE(MTYPE_TMP, pattern);
if (cr != 0) {
switch (cr) {
else
list->head = access->next;
+ route_map_notify_dependencies(access->name, RMAP_EVENT_FILTER_DELETED);
+
+ if (master->delete_hook)
+ master->delete_hook(access);
+
XFREE(MTYPE_ACCESS_LIST_STR, access->name);
XFREE(MTYPE_TMP, access->remark);
host A single host address
*/
-struct filter *filter_lookup_cisco(struct access_list *access,
- struct filter *mnew)
-{
- struct filter *mfilter;
- struct filter_cisco *filter;
- struct filter_cisco *new;
-
- new = &mnew->u.cfilter;
-
- for (mfilter = access->head; mfilter; mfilter = mfilter->next) {
- filter = &mfilter->u.cfilter;
-
- if (filter->extended) {
- if (mfilter->type == mnew->type
- && filter->addr.s_addr == new->addr.s_addr
- && filter->addr_mask.s_addr == new->addr_mask.s_addr
- && filter->mask.s_addr == new->mask.s_addr
- && filter->mask_mask.s_addr
- == new->mask_mask.s_addr)
- return mfilter;
- } else {
- if (mfilter->type == mnew->type
- && filter->addr.s_addr == new->addr.s_addr
- && filter->addr_mask.s_addr
- == new->addr_mask.s_addr)
- return mfilter;
- }
- }
-
- return NULL;
-}
-
-struct filter *filter_lookup_zebra(struct access_list *access,
- struct filter *mnew)
-{
- struct filter *mfilter;
- struct filter_zebra *filter;
- struct filter_zebra *new;
-
- new = &mnew->u.zfilter;
-
- for (mfilter = access->head; mfilter; mfilter = mfilter->next) {
- filter = &mfilter->u.zfilter;
-
- if (filter->exact == new->exact
- && mfilter->type == mnew->type) {
- if (prefix_same(&filter->prefix, &new->prefix))
- return mfilter;
- }
- }
- return NULL;
-}
-
static void config_write_access_zebra(struct vty *, struct filter *);
static void config_write_access_cisco(struct vty *, struct filter *);
void access_list_filter_delete(struct access_list *access,
struct filter *filter);
int64_t filter_new_seq_get(struct access_list *access);
-struct filter *filter_lookup_cisco(struct access_list *access,
- struct filter *mnew);
-struct filter *filter_lookup_zebra(struct access_list *access,
- struct filter *mnew);
extern const struct frr_yang_module_info frr_filter_info;
/** Duplicated entry found in list? */
bool ada_found;
+ /** Sequence number of the found entry */
+ int64_t ada_seq;
+
/** (Optional) Already existing `dnode`. */
const struct lyd_node *ada_entry_dnode;
};
/** Duplicated entry found in list? */
bool pda_found;
+ /** Sequence number of the found entry */
+ int64_t pda_seq;
+
/** (Optional) Already existing `dnode`. */
const struct lyd_node *pda_entry_dnode;
};
#define PREFIX_LIST_NAME_STR "Prefix list entry name\n"
-/*
- * Helper function to locate filter data structures for Cisco-style ACLs.
- */
-static int64_t acl_cisco_get_seq(struct access_list *acl, const char *action,
- const char *src, const char *src_mask,
- const char *dst, const char *dst_mask)
-{
- struct filter_cisco *fc;
- struct filter f, *fn;
-
- memset(&f, 0, sizeof(f));
- f.cisco = 1;
- if (strcmp(action, "permit") == 0)
- f.type = FILTER_PERMIT;
- else
- f.type = FILTER_DENY;
-
- fc = &f.u.cfilter;
- inet_pton(AF_INET, src, &fc->addr);
- inet_pton(AF_INET, src_mask, &fc->addr_mask);
- fc->addr.s_addr &= ~fc->addr_mask.s_addr;
- if (dst != NULL) {
- fc->extended = 1;
- inet_pton(AF_INET, dst, &fc->mask);
- inet_pton(AF_INET, dst_mask, &fc->mask_mask);
- fc->mask.s_addr &= ~fc->mask_mask.s_addr;
- }
-
- fn = filter_lookup_cisco(acl, &f);
- if (fn == NULL)
- return -1;
-
- return fn->seq;
-}
-
-/*
- * Helper function to locate filter data structures for zebra-style ACLs.
- */
-static int64_t acl_zebra_get_seq(struct access_list *acl, const char *action,
- const struct prefix *p, bool exact)
-{
- struct filter_zebra *fz;
- struct filter f, *fn;
-
- memset(&f, 0, sizeof(f));
- memset(&fz, 0, sizeof(fz));
- if (strcmp(action, "permit") == 0)
- f.type = FILTER_PERMIT;
- else
- f.type = FILTER_DENY;
-
- fz = &f.u.zfilter;
- if (p->family)
- prefix_copy(&fz->prefix, p);
- fz->exact = exact;
-
- fn = filter_lookup_zebra(acl, &f);
- if (fn == NULL)
- return -1;
-
- return fn->seq;
-}
-
/*
* Helper function to generate a sequence number for legacy commands.
*/
return seq + 5;
}
+static int acl_remove_if_empty(struct vty *vty, const char *iptype,
+ const char *name)
+{
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/access-list[type='%s'][name='%s']/remark",
+ iptype, name);
+ /* List is not empty if there is a remark, check that: */
+ if (yang_dnode_exists(vty->candidate_config->dnode, xpath))
+ return CMD_SUCCESS;
+
+ /* Check if we have any entries: */
+ snprintf(xpath, sizeof(xpath),
+ "/frr-filter:lib/access-list[type='%s'][name='%s']", iptype,
+ name);
+ /*
+ * NOTE: if the list is empty it will return the first sequence
+ * number: 5.
+ */
+ if (acl_get_seq(vty, xpath) != 5)
+ return CMD_SUCCESS;
+
+ /* Nobody is using this list, lets remove it. */
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+static int acl_remove(struct vty *vty, const char *iptype, const char *name,
+ int64_t sseq)
+{
+ char xpath[XPATH_MAXLEN];
+ int rv;
+
+ snprintfrr(
+ xpath, sizeof(xpath),
+ "/frr-filter:lib/access-list[type='%s'][name='%s']/entry[sequence='%" PRId64 "']",
+ iptype, name, sseq);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ rv = nb_cli_apply_changes(vty, NULL);
+ if (rv == CMD_SUCCESS)
+ return acl_remove_if_empty(vty, iptype, name);
+
+ return rv;
+}
+
/*
* Cisco (legacy) access lists.
*/
ada.ada_value[1] = mask_str;
} else {
ada.ada_xpath[0] = "./source-any";
- ada.ada_value[0] = "true";
+ ada.ada_value[0] = "";
}
/* Duplicated entry without sequence, just quit. */
"Address to match\n"
"Wildcard bits\n")
{
- struct access_list *acl;
- struct lyd_node *dnode;
int64_t sseq;
- char xpath[XPATH_MAXLEN];
- char xpath_entry[XPATH_MAXLEN + 32];
+ struct acl_dup_args ada = {};
/* If the user provided sequence number, then just go for it. */
- if (seq_str != NULL) {
- snprintf(
- xpath, sizeof(xpath),
- "/frr-filter:lib/access-list[type='ipv4'][name='%s']/entry[sequence='%s']",
- name, seq_str);
- nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
- return nb_cli_apply_changes(vty, NULL);
- }
+ if (seq_str != NULL)
+ return acl_remove(vty, "ipv4", name, seq);
/* Otherwise, to keep compatibility, we need to figure it out. */
- snprintf(xpath, sizeof(xpath),
- "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name);
-
- /* Access-list must exist before entries. */
- if (yang_dnode_exists(running_config->dnode, xpath) == false)
- return CMD_WARNING_CONFIG_FAILED;
+ ada.ada_type = "ipv4";
+ ada.ada_name = name;
+ ada.ada_action = action;
+ if (host_str && mask_str == NULL) {
+ ada.ada_xpath[0] = "./host";
+ ada.ada_value[0] = host_str;
+ } else if (host_str && mask_str) {
+ ada.ada_xpath[0] = "./network/address";
+ ada.ada_value[0] = host_str;
+ ada.ada_xpath[1] = "./network/mask";
+ ada.ada_value[1] = mask_str;
+ } else {
+ ada.ada_xpath[0] = "./source-any";
+ ada.ada_value[0] = "";
+ }
- /* Use access-list data structure to fetch sequence. */
- dnode = yang_dnode_get(running_config->dnode, xpath);
- acl = nb_running_get_entry(dnode, NULL, true);
- sseq = acl_cisco_get_seq(acl, action, host_str,
- mask_str ? mask_str : CISCO_HOST_WILDCARD_MASK,
- NULL, NULL);
- if (sseq == -1)
+ if (acl_is_dup(vty->candidate_config->dnode, &ada))
+ sseq = ada.ada_seq;
+ else
return CMD_WARNING_CONFIG_FAILED;
- snprintfrr(xpath_entry, sizeof(xpath_entry),
- "%s/entry[sequence='%" PRId64 "']", xpath, sseq);
- nb_cli_enqueue_change(vty, xpath_entry, NB_OP_DESTROY, NULL);
-
- return nb_cli_apply_changes(vty, NULL);
+ return acl_remove(vty, "ipv4", name, sseq);
}
DEFPY_YANG(
idx++;
} else {
ada.ada_xpath[idx] = "./source-any";
- ada.ada_value[idx] = "true";
+ ada.ada_value[idx] = "";
idx++;
}
idx++;
} else {
ada.ada_xpath[idx] = "./destination-any";
- ada.ada_value[idx] = "true";
+ ada.ada_value[idx] = "";
idx++;
}
"Destination address to match\n"
"Any destination host\n")
{
- struct access_list *acl;
- struct lyd_node *dnode;
+ int idx = 0;
int64_t sseq;
- char xpath[XPATH_MAXLEN];
- char xpath_entry[XPATH_MAXLEN + 32];
+ struct acl_dup_args ada = {};
/* If the user provided sequence number, then just go for it. */
- if (seq_str != NULL) {
- snprintfrr(
- xpath, sizeof(xpath),
- "/frr-filter:lib/access-list[type='ipv4'][name='%s']/entry[sequence='%s']",
- name, seq_str);
- nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
- return nb_cli_apply_changes(vty, NULL);
- }
+ if (seq_str != NULL)
+ return acl_remove(vty, "ipv4", name, seq);
/* Otherwise, to keep compatibility, we need to figure it out. */
- snprintf(xpath, sizeof(xpath),
- "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name);
-
- /* Access-list must exist before entries. */
- if (yang_dnode_exists(running_config->dnode, xpath) == false)
- return CMD_WARNING_CONFIG_FAILED;
+ ada.ada_type = "ipv4";
+ ada.ada_name = name;
+ ada.ada_action = action;
+ if (src_str && src_mask_str == NULL) {
+ ada.ada_xpath[idx] = "./host";
+ ada.ada_value[idx] = src_str;
+ idx++;
+ } else if (src_str && src_mask_str) {
+ ada.ada_xpath[idx] = "./network/address";
+ ada.ada_value[idx] = src_str;
+ idx++;
+ ada.ada_xpath[idx] = "./network/mask";
+ ada.ada_value[idx] = src_mask_str;
+ idx++;
+ } else {
+ ada.ada_xpath[idx] = "./source-any";
+ ada.ada_value[idx] = "";
+ idx++;
+ }
- /* Use access-list data structure to fetch sequence. */
- dnode = yang_dnode_get(running_config->dnode, xpath);
- acl = nb_running_get_entry(dnode, NULL, true);
- if (src_str != NULL) {
- if (dst_str != NULL)
- sseq = acl_cisco_get_seq(
- acl, action, src_str,
- src_mask_str ? src_mask_str
- : CISCO_HOST_WILDCARD_MASK,
- dst_str,
- dst_mask_str ? dst_mask_str
- : CISCO_HOST_WILDCARD_MASK);
- else
- sseq = acl_cisco_get_seq(
- acl, action, src_str,
- src_mask_str ? src_mask_str
- : CISCO_HOST_WILDCARD_MASK,
- "0.0.0.0", CISCO_ANY_WILDCARD_MASK);
+ if (dst_str && dst_mask_str == NULL) {
+ ada.ada_xpath[idx] = "./destination-host";
+ ada.ada_value[idx] = dst_str;
+ idx++;
+ } else if (dst_str && dst_mask_str) {
+ ada.ada_xpath[idx] = "./destination-network/address";
+ ada.ada_value[idx] = dst_str;
+ idx++;
+ ada.ada_xpath[idx] = "./destination-network/mask";
+ ada.ada_value[idx] = dst_mask_str;
+ idx++;
} else {
- if (dst_str != NULL)
- sseq = acl_cisco_get_seq(
- acl, action, "0.0.0.0", CISCO_ANY_WILDCARD_MASK,
- dst_str,
- dst_mask_str ? dst_mask_str
- : CISCO_HOST_WILDCARD_MASK);
- else
- sseq = acl_cisco_get_seq(
- acl, action, "0.0.0.0", CISCO_ANY_WILDCARD_MASK,
- "0.0.0.0", CISCO_ANY_WILDCARD_MASK);
+ ada.ada_xpath[idx] = "./destination-any";
+ ada.ada_value[idx] = "";
+ idx++;
}
- if (sseq == -1)
- return CMD_WARNING_CONFIG_FAILED;
- snprintfrr(xpath_entry, sizeof(xpath_entry),
- "%s/entry[sequence='%" PRId64 "']", xpath, sseq);
- nb_cli_enqueue_change(vty, xpath_entry, NB_OP_DESTROY, NULL);
+ if (acl_is_dup(vty->candidate_config->dnode, &ada))
+ sseq = ada.ada_seq;
+ else
+ return CMD_WARNING_CONFIG_FAILED;
- return nb_cli_apply_changes(vty, NULL);
+ return acl_remove(vty, "ipv4", name, sseq);
}
/*
}
} else {
ada.ada_xpath[0] = "./any";
- ada.ada_value[0] = "true";
+ ada.ada_value[0] = "";
}
/* Duplicated entry without sequence, just quit. */
"Exact match of the prefixes\n"
"Match any IPv4\n")
{
- struct access_list *acl;
- struct lyd_node *dnode;
int64_t sseq;
- struct prefix pany;
- char xpath[XPATH_MAXLEN];
- char xpath_entry[XPATH_MAXLEN + 32];
+ struct acl_dup_args ada = {};
/* If the user provided sequence number, then just go for it. */
- if (seq_str != NULL) {
- snprintf(
- xpath, sizeof(xpath),
- "/frr-filter:lib/access-list[type='ipv4'][name='%s']/entry[sequence='%s']",
- name, seq_str);
- nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
- return nb_cli_apply_changes(vty, NULL);
- }
+ if (seq_str != NULL)
+ return acl_remove(vty, "ipv4", name, seq);
/* Otherwise, to keep compatibility, we need to figure it out. */
- snprintf(xpath, sizeof(xpath),
- "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name);
-
- /* Access-list must exist before entries. */
- if (yang_dnode_exists(running_config->dnode, xpath) == false)
- return CMD_WARNING_CONFIG_FAILED;
+ ada.ada_type = "ipv4";
+ ada.ada_name = name;
+ ada.ada_action = action;
+
+ if (prefix_str) {
+ ada.ada_xpath[0] = "./ipv4-prefix";
+ ada.ada_value[0] = prefix_str;
+ if (exact) {
+ ada.ada_xpath[1] = "./ipv4-exact-match";
+ ada.ada_value[1] = "true";
+ }
+ } else {
+ ada.ada_xpath[0] = "./any";
+ ada.ada_value[0] = "";
+ }
- /* Use access-list data structure to fetch sequence. */
- dnode = yang_dnode_get(running_config->dnode, xpath);
- acl = nb_running_get_entry(dnode, NULL, true);
- if (prefix_str == NULL) {
- memset(&pany, 0, sizeof(pany));
- pany.family = AF_INET;
- sseq = acl_zebra_get_seq(acl, action, &pany, exact);
- } else
- sseq = acl_zebra_get_seq(acl, action, (struct prefix *)prefix,
- exact);
- if (sseq == -1)
+ if (acl_is_dup(vty->candidate_config->dnode, &ada))
+ sseq = ada.ada_seq;
+ else
return CMD_WARNING_CONFIG_FAILED;
- snprintfrr(xpath_entry, sizeof(xpath_entry),
- "%s/entry[sequence='%" PRId64 "']", xpath, sseq);
- nb_cli_enqueue_change(vty, xpath_entry, NB_OP_DESTROY, NULL);
-
- return nb_cli_apply_changes(vty, NULL);
+ return acl_remove(vty, "ipv4", name, sseq);
}
DEFPY_YANG(
ACCESS_LIST_REMARK_STR)
{
char xpath[XPATH_MAXLEN];
+ int rv;
snprintf(xpath, sizeof(xpath),
"/frr-filter:lib/access-list[type='ipv4'][name='%s']/remark",
name);
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
- return nb_cli_apply_changes(vty, NULL);
+ rv = nb_cli_apply_changes(vty, NULL);
+ if (rv == CMD_SUCCESS)
+ return acl_remove_if_empty(vty, "ipv4", name);
+
+ return rv;
}
ALIAS(
}
} else {
ada.ada_xpath[0] = "./any";
- ada.ada_value[0] = "true";
+ ada.ada_value[0] = "";
}
/* Duplicated entry without sequence, just quit. */
"Exact match of the prefixes\n"
"Match any IPv6\n")
{
- struct access_list *acl;
- struct lyd_node *dnode;
int64_t sseq;
- struct prefix pany;
- char xpath[XPATH_MAXLEN];
- char xpath_entry[XPATH_MAXLEN + 32];
+ struct acl_dup_args ada = {};
/* If the user provided sequence number, then just go for it. */
- if (seq_str != NULL) {
- snprintf(
- xpath, sizeof(xpath),
- "/frr-filter:lib/access-list[type='ipv6'][name='%s']/entry[sequence='%s']",
- name, seq_str);
- nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
- return nb_cli_apply_changes(vty, NULL);
- }
+ if (seq_str != NULL)
+ return acl_remove(vty, "ipv6", name, seq);
/* Otherwise, to keep compatibility, we need to figure it out. */
- snprintf(xpath, sizeof(xpath),
- "/frr-filter:lib/access-list[type='ipv6'][name='%s']", name);
-
- /* Access-list must exist before entries. */
- if (yang_dnode_exists(running_config->dnode, xpath) == false)
- return CMD_WARNING_CONFIG_FAILED;
+ ada.ada_type = "ipv6";
+ ada.ada_name = name;
+ ada.ada_action = action;
+
+ if (prefix_str) {
+ ada.ada_xpath[0] = "./ipv6-prefix";
+ ada.ada_value[0] = prefix_str;
+ if (exact) {
+ ada.ada_xpath[1] = "./ipv6-exact-match";
+ ada.ada_value[1] = "true";
+ }
+ } else {
+ ada.ada_xpath[0] = "./any";
+ ada.ada_value[0] = "";
+ }
- /* Use access-list data structure to fetch sequence. */
- dnode = yang_dnode_get(running_config->dnode, xpath);
- acl = nb_running_get_entry(dnode, NULL, true);
- if (prefix == NULL) {
- memset(&pany, 0, sizeof(pany));
- pany.family = AF_INET6;
- sseq = acl_zebra_get_seq(acl, action, &pany, exact);
- } else
- sseq = acl_zebra_get_seq(acl, action, (struct prefix *)prefix,
- exact);
- if (sseq == -1)
+ if (acl_is_dup(vty->candidate_config->dnode, &ada))
+ sseq = ada.ada_seq;
+ else
return CMD_WARNING_CONFIG_FAILED;
- snprintfrr(xpath_entry, sizeof(xpath_entry),
- "%s/entry[sequence='%" PRId64 "']", xpath, sseq);
- nb_cli_enqueue_change(vty, xpath_entry, NB_OP_DESTROY, NULL);
-
- return nb_cli_apply_changes(vty, NULL);
+ return acl_remove(vty, "ipv6", name, sseq);
}
DEFPY_YANG(
ACCESS_LIST_REMARK_STR)
{
char xpath[XPATH_MAXLEN];
+ int rv;
snprintf(xpath, sizeof(xpath),
"/frr-filter:lib/access-list[type='ipv6'][name='%s']/remark",
name);
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
- return nb_cli_apply_changes(vty, NULL);
+ rv = nb_cli_apply_changes(vty, NULL);
+ if (rv == CMD_SUCCESS)
+ return acl_remove_if_empty(vty, "ipv6", name);
+
+ return rv;
}
ALIAS(
ada.ada_value[0] = mac_str;
} else {
ada.ada_xpath[0] = "./any";
- ada.ada_value[0] = "true";
+ ada.ada_value[0] = "";
}
/* Duplicated entry without sequence, just quit. */
DEFPY_YANG(
no_mac_access_list, no_mac_access_list_cmd,
- "no mac access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$prefix|any>",
+ "no mac access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$mac|any>",
NO_STR
MAC_STR
ACCESS_LIST_STR
"MAC address\n"
"Match any MAC address\n")
{
- struct access_list *acl;
- struct lyd_node *dnode;
int64_t sseq;
- struct prefix pany;
- char xpath[XPATH_MAXLEN];
- char xpath_entry[XPATH_MAXLEN + 32];
+ struct acl_dup_args ada = {};
/* If the user provided sequence number, then just go for it. */
- if (seq_str != NULL) {
- snprintf(
- xpath, sizeof(xpath),
- "/frr-filter:lib/access-list[type='mac'][name='%s']/entry[sequence='%s']",
- name, seq_str);
- nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
- return nb_cli_apply_changes(vty, NULL);
- }
+ if (seq_str != NULL)
+ return acl_remove(vty, "mac", name, seq);
/* Otherwise, to keep compatibility, we need to figure it out. */
- snprintf(xpath, sizeof(xpath),
- "/frr-filter:lib/access-list[type='mac'][name='%s']", name);
+ ada.ada_type = "mac";
+ ada.ada_name = name;
+ ada.ada_action = action;
- /* Access-list must exist before entries. */
- if (yang_dnode_exists(running_config->dnode, xpath) == false)
- return CMD_WARNING_CONFIG_FAILED;
+ if (mac_str) {
+ ada.ada_xpath[0] = "./mac";
+ ada.ada_value[0] = mac_str;
+ } else {
+ ada.ada_xpath[0] = "./any";
+ ada.ada_value[0] = "";
+ }
- /* Use access-list data structure to fetch sequence. */
- dnode = yang_dnode_get(running_config->dnode, xpath);
- acl = nb_running_get_entry(dnode, NULL, true);
- if (prefix == NULL) {
- memset(&pany, 0, sizeof(pany));
- pany.family = AF_ETHERNET;
- sseq = acl_zebra_get_seq(acl, action, &pany, false);
- } else
- sseq = acl_zebra_get_seq(acl, action, (struct prefix *)prefix,
- false);
- if (sseq == -1)
+ if (acl_is_dup(vty->candidate_config->dnode, &ada))
+ sseq = ada.ada_seq;
+ else
return CMD_WARNING_CONFIG_FAILED;
- snprintfrr(xpath_entry, sizeof(xpath_entry),
- "%s/entry[sequence='%" PRId64 "']", xpath, sseq);
- nb_cli_enqueue_change(vty, xpath_entry, NB_OP_DESTROY, NULL);
-
- return nb_cli_apply_changes(vty, NULL);
+ return acl_remove(vty, "mac", name, sseq);
}
DEFPY_YANG(
ACCESS_LIST_REMARK_STR)
{
char xpath[XPATH_MAXLEN];
+ int rv;
snprintf(xpath, sizeof(xpath),
"/frr-filter:lib/access-list[type='mac'][name='%s']/remark",
name);
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
- return nb_cli_apply_changes(vty, NULL);
+ rv = nb_cli_apply_changes(vty, NULL);
+ if (rv == CMD_SUCCESS)
+ return acl_remove_if_empty(vty, "mac", name);
+
+ return rv;
}
ALIAS(
}
static int plist_remove(struct vty *vty, const char *iptype, const char *name,
- const char *seq, const char *action, struct prefix *p,
- long ge, long le)
+ const char *seq, const char *action,
+ const char *prefix_str, const char *ge_str,
+ const char *le_str)
{
- struct prefix_list_entry *pentry;
- enum prefix_list_type plt;
- struct prefix_list *pl;
- struct lyd_node *dnode;
+ int64_t sseq;
+ int arg_idx = 0;
+ struct plist_dup_args pda = {};
char xpath[XPATH_MAXLEN];
char xpath_entry[XPATH_MAXLEN + 32];
int rv;
}
/* Otherwise, to keep compatibility, we need to figure it out. */
- snprintf(xpath, sizeof(xpath),
- "/frr-filter:lib/prefix-list[type='%s'][name='%s']", iptype,
- name);
-
- /* Access-list must exist before entries. */
- if (yang_dnode_exists(running_config->dnode, xpath) == false)
- return CMD_WARNING_CONFIG_FAILED;
+ pda.pda_type = iptype;
+ pda.pda_name = name;
+ pda.pda_action = action;
+ if (prefix_str) {
+ if (strmatch(iptype, "ipv4")) {
+ pda.pda_xpath[arg_idx] = "./ipv4-prefix";
+ pda.pda_value[arg_idx] = prefix_str;
+ arg_idx++;
+ if (ge_str) {
+ pda.pda_xpath[arg_idx] =
+ "./ipv4-prefix-length-greater-or-equal";
+ pda.pda_value[arg_idx] = ge_str;
+ arg_idx++;
+ }
+ if (le_str) {
+ pda.pda_xpath[arg_idx] =
+ "./ipv4-prefix-length-lesser-or-equal";
+ pda.pda_value[arg_idx] = le_str;
+ arg_idx++;
+ }
+ } else {
+ pda.pda_xpath[arg_idx] = "./ipv6-prefix";
+ pda.pda_value[arg_idx] = prefix_str;
+ arg_idx++;
+ if (ge_str) {
+ pda.pda_xpath[arg_idx] =
+ "./ipv6-prefix-length-greater-or-equal";
+ pda.pda_value[arg_idx] = ge_str;
+ arg_idx++;
+ }
+ if (le_str) {
+ pda.pda_xpath[arg_idx] =
+ "./ipv6-prefix-length-lesser-or-equal";
+ pda.pda_value[arg_idx] = le_str;
+ arg_idx++;
+ }
+ }
+ } else {
+ pda.pda_xpath[0] = "./any";
+ pda.pda_value[0] = "";
+ }
- /* Use access-list data structure to fetch sequence. */
- assert(action != NULL);
- if (strcmp(action, "permit") == 0)
- plt = PREFIX_PERMIT;
+ if (plist_is_dup(vty->candidate_config->dnode, &pda))
+ sseq = pda.pda_seq;
else
- plt = PREFIX_DENY;
-
- dnode = yang_dnode_get(running_config->dnode, xpath);
- pl = nb_running_get_entry(dnode, NULL, true);
- pentry = prefix_list_entry_lookup(pl, p, plt, -1, le, ge);
- if (pentry == NULL)
return CMD_WARNING_CONFIG_FAILED;
- snprintfrr(xpath_entry, sizeof(xpath_entry),
- "%s/entry[sequence='%" PRId64 "']", xpath, pentry->seq);
+ snprintfrr(
+ xpath_entry, sizeof(xpath_entry),
+ "/frr-filter:lib/prefix-list[type='%s'][name='%s']/entry[sequence='%" PRId64 "']",
+ iptype, name, sseq);
nb_cli_enqueue_change(vty, xpath_entry, NB_OP_DESTROY, NULL);
rv = nb_cli_apply_changes(vty, NULL);
"Maximum prefix length to be matched\n"
"Maximum prefix length\n")
{
- return plist_remove(vty, "ipv4", name, seq_str, action,
- (struct prefix *)prefix, ge, le);
+ return plist_remove(vty, "ipv4", name, seq_str, action, prefix_str,
+ ge_str, le_str);
}
DEFPY_YANG(
PREFIX_LIST_NAME_STR
ACCESS_LIST_SEQ_STR)
{
- return plist_remove(vty, "ipv4", name, seq_str, NULL, NULL, 0, 0);
+ return plist_remove(vty, "ipv4", name, seq_str, NULL, NULL, NULL, NULL);
}
DEFPY_YANG(
ACCESS_LIST_REMARK_STR)
{
char xpath[XPATH_MAXLEN];
+ int rv;
snprintf(xpath, sizeof(xpath),
"/frr-filter:lib/prefix-list[type='ipv4'][name='%s']/remark",
name);
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
- return nb_cli_apply_changes(vty, NULL);
+ rv = nb_cli_apply_changes(vty, NULL);
+ if (rv == CMD_SUCCESS)
+ return plist_remove_if_empty(vty, "ipv4", name);
+
+ return rv;
}
ALIAS(
"Minimum prefix length to be matched\n"
"Minimum prefix length\n")
{
- return plist_remove(vty, "ipv6", name, seq_str, action,
- (struct prefix *)prefix, ge, le);
+ return plist_remove(vty, "ipv6", name, seq_str, action, prefix_str,
+ ge_str, le_str);
}
DEFPY_YANG(
PREFIX_LIST_NAME_STR
ACCESS_LIST_SEQ_STR)
{
- return plist_remove(vty, "ipv6", name, seq_str, NULL, NULL, 0, 0);
+ return plist_remove(vty, "ipv6", name, seq_str, NULL, NULL, NULL, NULL);
}
DEFPY_YANG(
ACCESS_LIST_REMARK_STR)
{
char xpath[XPATH_MAXLEN];
+ int rv;
snprintf(xpath, sizeof(xpath),
"/frr-filter:lib/prefix-list[type='ipv6'][name='%s']/remark",
name);
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
- return nb_cli_apply_changes(vty, NULL);
+ rv = nb_cli_apply_changes(vty, NULL);
+ if (rv == CMD_SUCCESS)
+ return plist_remove_if_empty(vty, "ipv6", name);
+
+ return rv;
}
ALIAS(
}
ada->ada_found = true;
+ ada->ada_seq = yang_dnode_get_uint32(dnode, "sequence");
return YANG_ITER_STOP;
}
}
pda->pda_found = true;
+ pda->pda_seq = yang_dnode_get_uint32(dnode, "sequence");
return YANG_ITER_STOP;
}
static int lib_access_list_destroy(struct nb_cb_destroy_args *args)
{
- struct access_master *am;
struct access_list *acl;
if (args->event != NB_EV_APPLY)
return NB_OK;
acl = nb_running_unset_entry(args->dnode);
- am = acl->master;
- if (am->delete_hook)
- am->delete_hook(acl);
-
access_list_delete(acl);
return NB_OK;
void if_terminate(struct vrf *vrf)
{
struct interface *ifp;
+ bool delete;
+
+ /*
+ * If the default VRF is being terminated or has
+ * already been terminated it means that
+ * the program is shutting down and we need to
+ * delete all the interfaces. Otherwise, we only
+ * need to move VRF's interfaces to the default VRF.
+ */
+ delete = vrf_is_backend_netns() || vrf->vrf_id == VRF_DEFAULT
+ || !vrf_lookup_by_id(VRF_DEFAULT);
while (!RB_EMPTY(if_name_head, &vrf->ifaces_by_name)) {
ifp = RB_ROOT(if_name_head, &vrf->ifaces_by_name);
- if (ifp->node) {
- ifp->node->info = NULL;
- route_unlock_node(ifp->node);
+ if (delete) {
+ if (ifp->node) {
+ ifp->node->info = NULL;
+ route_unlock_node(ifp->node);
+ }
+ if_delete(&ifp);
+ } else {
+ if_update_to_new_vrf(ifp, VRF_DEFAULT);
}
- if_delete(&ifp);
}
}
.suggestion = "Gather log data and open an Issue. restart FRR",
},
{
- .code = EC_LIB_SLOW_THREAD,
- .title = "The Event subsystem has detected a slow process",
- .description = "The Event subsystem has detected a slow process, this typically indicates that FRR is having trouble completing work in a timely manner. This can be either a misconfiguration, bug, or some combination therof.",
+ .code = EC_LIB_SLOW_THREAD_CPU,
+ .title = "The Event subsystem has detected a slow cpu time process",
+ .description = "The Event subsystem has detected a slow process, this typically indicates that FRR is having trouble completing work in a timely manner. This can be either a misconfiguration, bug, or some combination therof. In this case total CPU time was over 5 seconds. Which indicates that FRR is very busy doing some work and should be addressed",
+ .suggestion = "Gather log data and open an Issue",
+ },
+ {
+ .code = EC_LIB_SLOW_THREAD_WALL,
+ .title = "The Event subsystem has detected a slow wall time process",
+ .description = "The Event subsystem has detected a slow process, this typically indicates that FRR is having trouble completing work in a timely manner. This can be either a misconfiguration, bug or some combination therof. In this case total WALL time was over 5 seconds. Which indicates that FRR might be having trouble being scheduled or some system call is delaying",
.suggestion = "Gather log data and open an Issue",
},
{
EC_LIB_SNMP,
EC_LIB_STREAM,
EC_LIB_LINUX_NS,
- EC_LIB_SLOW_THREAD,
+ EC_LIB_SLOW_THREAD_CPU,
+ EC_LIB_SLOW_THREAD_WALL,
EC_LIB_NO_THREAD,
EC_LIB_RMAP_RECURSION_LIMIT,
EC_LIB_BACKUP_CONFIG,
DESC_ENTRY(ZEBRA_ROUTE_NOTIFY_REQUEST),
DESC_ENTRY(ZEBRA_CLIENT_CLOSE_NOTIFY),
DESC_ENTRY(ZEBRA_EVPN_REMOTE_NH_ADD),
- DESC_ENTRY(ZEBRA_EVPN_REMOTE_NH_DEL)};
+ DESC_ENTRY(ZEBRA_EVPN_REMOTE_NH_DEL),
+ DESC_ENTRY(ZEBRA_NHRP_NEIGH_ADDED),
+ DESC_ENTRY(ZEBRA_NHRP_NEIGH_REMOVED),
+ DESC_ENTRY(ZEBRA_NHRP_NEIGH_GET),
+ DESC_ENTRY(ZEBRA_NHRP_NEIGH_REGISTER),
+ DESC_ENTRY(ZEBRA_NHRP_NEIGH_UNREGISTER),
+ DESC_ENTRY(ZEBRA_NEIGH_IP_ADD),
+ DESC_ENTRY(ZEBRA_NEIGH_IP_DEL),
+ DESC_ENTRY(ZEBRA_CONFIGURE_ARP)};
#undef DESC_ENTRY
static const struct zebra_desc_table unknown = {0, "unknown", '?'};
zlog_progname);
}
-DEFUN (show_logging,
- show_logging_cmd,
- "show logging",
- SHOW_STR
- "Show current logging configuration\n")
+DEFUN_NOSH (show_logging,
+ show_logging_cmd,
+ "show logging",
+ SHOW_STR
+ "Show current logging configuration\n")
{
log_show_syslog(vty);
/* List of prefix_list which name is string. */
struct prefix_list_list str;
- /* Whether sequential number is used. */
- bool seqnum;
-
/* The latest update. */
struct prefix_list *recent;
/* Static structure of IPv4 prefix_list's master. */
static struct prefix_master prefix_master_ipv4 = {
- {NULL, NULL}, {NULL, NULL}, 1, NULL, NULL, NULL, PLC_MAXLEVELV4,
+ {NULL, NULL}, {NULL, NULL}, NULL, NULL, NULL, PLC_MAXLEVELV4,
};
/* Static structure of IPv6 prefix-list's master. */
static struct prefix_master prefix_master_ipv6 = {
- {NULL, NULL}, {NULL, NULL}, 1, NULL, NULL, NULL, PLC_MAXLEVELV6,
+ {NULL, NULL}, {NULL, NULL}, NULL, NULL, NULL, PLC_MAXLEVELV6,
};
/* Static structure of BGP ORF prefix_list's master. */
static struct prefix_master prefix_master_orf_v4 = {
- {NULL, NULL}, {NULL, NULL}, 1, NULL, NULL, NULL, PLC_MAXLEVELV4,
+ {NULL, NULL}, {NULL, NULL}, NULL, NULL, NULL, PLC_MAXLEVELV4,
};
/* Static structure of BGP ORF prefix_list's master. */
static struct prefix_master prefix_master_orf_v6 = {
- {NULL, NULL}, {NULL, NULL}, 1, NULL, NULL, NULL, PLC_MAXLEVELV6,
+ {NULL, NULL}, {NULL, NULL}, NULL, NULL, NULL, PLC_MAXLEVELV6,
};
static struct prefix_master *prefix_master_get(afi_t afi, int orf)
vty_out(vty, " ");
- if (master->seqnum)
- vty_out(vty, "seq %" PRId64 " ", pentry->seq);
+ vty_out(vty, "seq %" PRId64 " ", pentry->seq);
vty_out(vty, "%s ", prefix_list_type_str(pentry));
#include "lib/plist_clippy.c"
#endif
-DEFPY (ip_prefix_list_sequence_number,
- ip_prefix_list_sequence_number_cmd,
- "[no] ip prefix-list sequence-number",
- NO_STR
- IP_STR
- PREFIX_LIST_STR
- "Include/exclude sequence numbers in NVGEN\n")
-{
- prefix_master_ipv4.seqnum = no ? false : true;
- return CMD_SUCCESS;
-}
-
-
DEFPY (show_ip_prefix_list,
show_ip_prefix_list_cmd,
"show ip prefix-list [WORD [seq$dseq (1-4294967295)$arg]]",
return vty_clear_prefix_list(vty, AFI_IP, prefix_list, prefix_str);
}
-DEFPY (ipv6_prefix_list_sequence_number,
- ipv6_prefix_list_sequence_number_cmd,
- "[no] ipv6 prefix-list sequence-number",
- NO_STR
- IPV6_STR
- PREFIX_LIST_STR
- "Include/exclude sequence numbers in NVGEN\n")
-{
- prefix_master_ipv6.seqnum = no ? false : true;
- return CMD_SUCCESS;
-}
-
DEFPY (show_ipv6_prefix_list,
show_ipv6_prefix_list_cmd,
"show ipv6 prefix-list [WORD [seq$dseq (1-4294967295)$arg]]",
assert(master->str.head == NULL);
assert(master->str.tail == NULL);
- master->seqnum = true;
master->recent = NULL;
}
{
install_node(&prefix_node);
- install_element(CONFIG_NODE, &ip_prefix_list_sequence_number_cmd);
-
install_element(VIEW_NODE, &show_ip_prefix_list_cmd);
install_element(VIEW_NODE, &show_ip_prefix_list_prefix_cmd);
install_element(VIEW_NODE, &show_ip_prefix_list_summary_cmd);
{
install_node(&prefix_ipv6_node);
- install_element(CONFIG_NODE, &ipv6_prefix_list_sequence_number_cmd);
-
install_element(VIEW_NODE, &show_ipv6_prefix_list_cmd);
install_element(VIEW_NODE, &show_ipv6_prefix_list_prefix_cmd);
install_element(VIEW_NODE, &show_ipv6_prefix_list_summary_cmd);
}
/* VTY related functions. */
-DEFUN(no_routemap_optimization, no_routemap_optimization_cmd,
- "no route-map optimization",
- NO_STR
- "route-map\n"
- "optimization\n")
-{
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- index->map->optimization_disabled = true;
- return CMD_SUCCESS;
-}
-
-DEFUN(routemap_optimization, routemap_optimization_cmd,
- "route-map optimization",
- "route-map\n"
- "optimization\n")
-{
- VTY_DECLVAR_CONTEXT(route_map_index, index);
-
- index->map->optimization_disabled = false;
- return CMD_SUCCESS;
-}
-
static void clear_route_map_helper(struct route_map *map)
{
struct route_map_index *index;
install_element(ENABLE_NODE, &debug_rmap_cmd);
install_element(ENABLE_NODE, &no_debug_rmap_cmd);
- install_element(RMAP_NODE, &routemap_optimization_cmd);
- install_element(RMAP_NODE, &no_routemap_optimization_cmd);
-
install_element(ENABLE_NODE, &show_route_map_pfx_tbl_cmd);
}
extern void route_map_description_show(struct vty *vty,
struct lyd_node *dnode,
bool show_defaults);
+extern void route_map_optimization_disabled_show(struct vty *vty,
+ struct lyd_node *dnode,
+ bool show_defaults);
extern void route_map_cli_init(void);
#ifdef __cplusplus
vty_out(vty, " description %s\n", yang_dnode_get_string(dnode, NULL));
}
+DEFPY_YANG(
+ route_map_optimization, route_map_optimization_cmd,
+ "[no] route-map WORD$name optimization",
+ NO_STR
+ ROUTE_MAP_CMD_STR
+ "Configure route-map optimization\n")
+{
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath),
+ "/frr-route-map:lib/route-map[name='%s']", name);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+
+ snprintf(
+ xpath, sizeof(xpath),
+ "/frr-route-map:lib/route-map[name='%s']/optimization-disabled",
+ name);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, no ? "true" : "false");
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void route_map_optimization_disabled_show(struct vty *vty,
+ struct lyd_node *dnode,
+ bool show_defaults)
+{
+ const char *name = yang_dnode_get_string(dnode, "../name");
+ const bool disabled = yang_dnode_get_bool(dnode, NULL);
+
+ vty_out(vty, "%sroute-map %s optimization\n", disabled ? "no " : "",
+ name);
+}
+
+#if CONFDATE > 20220409
+CPP_NOTICE("Time to remove old route-map optimization command")
+#endif
+
+DEFPY_HIDDEN(
+ routemap_optimization, routemap_optimization_cmd,
+ "[no] route-map optimization",
+ NO_STR
+ "route-map\n"
+ "optimization\n")
+{
+ const struct lyd_node *rmi_dnode;
+ const char *rm_name;
+ char xpath[XPATH_MAXLEN];
+
+ vty_out(vty,
+ "%% This command is deprecated. Please, use `route-map NAME optimization` from the config node.\n");
+
+ rmi_dnode =
+ yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
+ if (!rmi_dnode) {
+ vty_out(vty, "%% Failed to get RMI dnode in candidate DB\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ rm_name = yang_dnode_get_string(rmi_dnode, "../name");
+
+ snprintf(
+ xpath, sizeof(xpath),
+ "/frr-route-map:lib/route-map[name='%s']/optimization-disabled",
+ rm_name);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, no ? "true" : "false");
+ return nb_cli_apply_changes(vty, NULL);
+}
+
static int route_map_config_write(struct vty *vty)
{
struct lyd_node *dnode;
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, &route_map_optimization_cmd);
/* Install the on-match stuff */
install_element(RMAP_NODE, &rmap_onmatch_next_cmd);
install_element(RMAP_NODE, &set_srte_color_cmd);
install_element(RMAP_NODE, &no_set_srte_color_cmd);
+
+ install_element(RMAP_NODE, &routemap_optimization_cmd);
}
return NB_OK;
}
+/*
+ * XPath: /frr-route-map:lib/route-map/optimization-disabled
+ */
+static int
+lib_route_map_optimization_disabled_modify(struct nb_cb_modify_args *args)
+{
+ struct route_map *rm;
+ bool disabled = yang_dnode_get_bool(args->dnode, NULL);
+
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ rm = nb_running_get_entry(args->dnode, NULL, true);
+ rm->optimization_disabled = disabled;
+ break;
+ }
+
+ return NB_OK;
+}
+
/*
* XPath: /frr-route-map:lib/route-map/entry
*/
.destroy = lib_route_map_destroy,
}
},
+ {
+ .xpath = "/frr-route-map:lib/route-map/optimization-disabled",
+ .cbs = {
+ .modify = lib_route_map_optimization_disabled_modify,
+ .cli_show = route_map_optimization_disabled_show,
+ }
+ },
{
.xpath = "/frr-route-map:lib/route-map/entry",
.cbs = {
/* make sure we don't hang in here. default for SIGALRM is terminate.
* - if we're in backtrace for more than a second, abort. */
struct sigaction sa_default = {.sa_handler = SIG_DFL};
+
sigaction(SIGALRM, &sa_default, NULL);
+ sigaction(signo, &sa_default, NULL);
sigset_t sigset;
+
sigemptyset(&sigset);
sigaddset(&sigset, SIGALRM);
sigprocmask(SIG_UNBLOCK, &sigset, NULL);
log_memstats(stderr, "core_handler");
zlog_tls_buffer_fini();
- abort();
+
+ /* give the kernel a chance to generate a coredump */
+ sigaddset(&sigset, signo);
+ sigprocmask(SIG_UNBLOCK, &sigset, NULL);
+ raise(signo);
+
+ /* only chance to end up here is if the default action for signo is
+ * something other than kill or coredump the process
+ */
+ _exit(128 + signo);
}
static void trap_default_signals(void)
lib/if_rmap.c \
lib/keychain.c \
lib/lib_vty.c \
+ lib/log_vty.c \
lib/nexthop_group.c \
lib/plist.c \
+ lib/resolver.c \
lib/routemap.c \
lib/routemap_cli.c \
+ lib/spf_backoff.c \
+ lib/thread.c \
lib/vrf.c \
lib/vty.c \
# end
static void vty_out_cpu_thread_history(struct vty *vty,
struct cpu_thread_history *a)
{
- vty_out(vty, "%5zu %10zu.%03zu %9zu %8zu %9zu %8zu %9zu",
+ vty_out(vty, "%5zu %10zu.%03zu %9zu %8zu %9zu %8zu %9zu %9zu %9zu",
a->total_active, a->cpu.total / 1000, a->cpu.total % 1000,
- a->total_calls, (a->cpu.total / a->total_calls), a->cpu.max,
- (a->real.total / a->total_calls), a->real.max);
- vty_out(vty, " %c%c%c%c%c %s\n",
+ a->total_calls, (a->cpu.total / a->total_calls), a->cpu.max,
+ (a->real.total / a->total_calls), a->real.max,
+ a->total_cpu_warn, a->total_wall_warn);
+ vty_out(vty, " %c%c%c%c%c %s\n",
a->types & (1 << THREAD_READ) ? 'R' : ' ',
a->types & (1 << THREAD_WRITE) ? 'W' : ' ',
a->types & (1 << THREAD_TIMER) ? 'T' : ' ',
atomic_load_explicit(&a->total_active, memory_order_seq_cst);
copy.total_calls =
atomic_load_explicit(&a->total_calls, memory_order_seq_cst);
+ copy.total_cpu_warn =
+ atomic_load_explicit(&a->total_cpu_warn, memory_order_seq_cst);
+ copy.total_wall_warn =
+ atomic_load_explicit(&a->total_wall_warn, memory_order_seq_cst);
copy.cpu.total =
atomic_load_explicit(&a->cpu.total, memory_order_seq_cst);
copy.cpu.max = atomic_load_explicit(&a->cpu.max, memory_order_seq_cst);
vty_out_cpu_thread_history(vty, ©);
totals->total_active += copy.total_active;
totals->total_calls += copy.total_calls;
+ totals->total_cpu_warn += copy.total_cpu_warn;
+ totals->total_wall_warn += copy.total_wall_warn;
totals->real.total += copy.real.total;
if (totals->real.max < copy.real.max)
totals->real.max = copy.real.max;
vty_out(vty,
"Active Runtime(ms) Invoked Avg uSec Max uSecs");
vty_out(vty, " Avg uSec Max uSecs");
- vty_out(vty, " Type Thread\n");
+ vty_out(vty, " CPU_Warn Wall_Warn Type Thread\n");
if (m->cpu_record->count)
hash_iterate(
vty_out(vty, "%30s %18s %18s\n", "",
"CPU (user+system):", "Real (wall-clock):");
vty_out(vty, "Active Runtime(ms) Invoked Avg uSec Max uSecs");
- vty_out(vty, " Avg uSec Max uSecs");
+ vty_out(vty, " Avg uSec Max uSecs CPU_Warn Wall_Warn");
vty_out(vty, " Type Thread\n");
if (tmp.total_calls > 0)
}
#ifndef EXCLUDE_CPU_TIME
-DEFUN (show_thread_cpu,
- show_thread_cpu_cmd,
- "show thread cpu [FILTER]",
- SHOW_STR
- "Thread information\n"
- "Thread CPU usage\n"
- "Display filter (rwtex)\n")
+DEFUN_NOSH (show_thread_cpu,
+ show_thread_cpu_cmd,
+ "show thread cpu [FILTER]",
+ SHOW_STR
+ "Thread information\n"
+ "Thread CPU usage\n"
+ "Display filter (rwtex)\n")
{
uint8_t filter = (uint8_t)-1U;
int idx = 0;
}
}
-DEFUN (show_thread_poll,
- show_thread_poll_cmd,
- "show thread poll",
- SHOW_STR
- "Thread information\n"
- "Show poll FD's and information\n")
+DEFUN_NOSH (show_thread_poll,
+ show_thread_poll_cmd,
+ "show thread poll",
+ SHOW_STR
+ "Thread information\n"
+ "Show poll FD's and information\n")
{
struct listnode *node;
struct thread_master *m;
memory_order_seq_cst);
#ifdef CONSUMED_TIME_CHECK
- if (realtime > CONSUMED_TIME_CHECK) {
+ if (cputime > CONSUMED_TIME_CHECK) {
/*
- * We have a CPU Hog on our hands.
+ * We have a CPU Hog on our hands. The time FRR
+ * has spent doing actual work ( not sleeping )
+ * is greater than 5 seconds.
* Whinge about it now, so we're aware this is yet another task
* to fix.
*/
+ atomic_fetch_add_explicit(&thread->hist->total_cpu_warn,
+ 1, memory_order_seq_cst);
+ flog_warn(
+ EC_LIB_SLOW_THREAD_CPU,
+ "CPU HOG: task %s (%lx) ran for %lums (cpu time %lums)",
+ thread->xref->funcname, (unsigned long)thread->func,
+ realtime / 1000, cputime / 1000);
+ } else if (realtime > CONSUMED_TIME_CHECK) {
+ /*
+ * The runtime for a task is greater than 5 seconds, but
+ * the cpu time is under 5 seconds. Let's whine
+ * about this because this could imply some sort of
+ * scheduling issue.
+ */
+ atomic_fetch_add_explicit(&thread->hist->total_wall_warn,
+ 1, memory_order_seq_cst);
flog_warn(
- EC_LIB_SLOW_THREAD,
- "SLOW THREAD: task %s (%lx) ran for %lums (cpu time %lums)",
+ EC_LIB_SLOW_THREAD_WALL,
+ "STARVATION: task %s (%lx) ran for %lums (cpu time %lums)",
thread->xref->funcname, (unsigned long)thread->func,
realtime / 1000, cputime / 1000);
}
struct cpu_thread_history {
int (*func)(struct thread *);
+ atomic_size_t total_cpu_warn;
+ atomic_size_t total_wall_warn;
atomic_size_t total_calls;
atomic_size_t total_active;
struct time_stats {
#ifdef CONSUMED_TIME_CHECK
GETRUSAGE(&after);
- if ((realtime = thread_consumed_time(&after, &before, &cputime))
- > CONSUMED_TIME_CHECK)
+ realtime = thread_consumed_time(&after, &before, &cputime);
+ if (cputime > CONSUMED_TIME_CHECK) {
/* Warn about CPU hog that must be fixed. */
flog_warn(
- EC_LIB_SLOW_THREAD,
- "SLOW COMMAND: command took %lums (cpu time %lums): %s",
+ EC_LIB_SLOW_THREAD_CPU,
+ "CPU HOG: command took %lums (cpu time %lums): %s",
realtime / 1000, cputime / 1000, buf);
+ } else if (realtime > CONSUMED_TIME_CHECK) {
+ flog_warn(
+ EC_LIB_SLOW_THREAD_WALL,
+ "STARVATION: command took %lums (cpu time %lums): %s",
+ realtime / 1000, cputime / 1000, buf);
+ }
}
#endif /* CONSUMED_TIME_CHECK */
extern const struct xref * const __start_xref_array[1] DSO_LOCAL;
extern const struct xref * const __stop_xref_array[1] DSO_LOCAL;
+#if defined(__has_feature)
+#if __has_feature(address_sanitizer)
+/* no redzone around each of the xref_p please, we're building an array out
+ * of variables here. kinda breaks things if there's redzones between each
+ * array item.
+ */
+#define xref_array_attr used, section("xref_array"), no_sanitize("address")
+#endif
+#endif
+#ifndef xref_array_attr
+#define xref_array_attr used, section("xref_array")
+#endif
+
/* this macro is invoked once for each standalone DSO through
* FRR_MODULE_SETUP \
* }-> FRR_COREMOD_SETUP -> XREF_SETUP
/* .func = */ "dummy", \
}; \
static const struct xref * const _dummy_xref_p \
- __attribute__((used, section("xref_array"))) \
- = &_dummy_xref; \
+ __attribute__((xref_array_attr)) = &_dummy_xref; \
static void __attribute__((used, _CONSTRUCTOR(1100))) \
_xref_init(void) { \
static struct xref_block _xref_block = { \
#if defined(__clang__) || !defined(__cplusplus)
#define XREF_LINK(dst) \
static const struct xref * const NAMECTR(xref_p_) \
- __attribute__((used, section("xref_array"))) \
+ __attribute__((xref_array_attr)) \
= &(dst) \
/* end */
(*zclient->zebra_client_close_notify)(command, zclient,
length, vrf_id);
break;
+ case ZEBRA_NHRP_NEIGH_ADDED:
+ if (zclient->neighbor_added)
+ (*zclient->neighbor_added)(command, zclient, length,
+ vrf_id);
+ break;
+ case ZEBRA_NHRP_NEIGH_REMOVED:
+ if (zclient->neighbor_removed)
+ (*zclient->neighbor_removed)(command, zclient, length,
+ vrf_id);
+ break;
+ case ZEBRA_NHRP_NEIGH_GET:
+ if (zclient->neighbor_get)
+ (*zclient->neighbor_get)(command, zclient, length,
+ vrf_id);
+ break;
default:
break;
}
return buf;
}
+
+static int zclient_neigh_ip_read_entry(struct stream *s, struct ipaddr *add)
+{
+ uint8_t family;
+
+ STREAM_GETC(s, family);
+ if (family != AF_INET && family != AF_INET6)
+ return -1;
+
+ STREAM_GET(&add->ip.addr, s, family2addrsize(family));
+ add->ipa_type = family;
+ return 0;
+ stream_failure:
+ return -1;
+}
+
+int zclient_neigh_ip_encode(struct stream *s,
+ uint16_t cmd,
+ union sockunion *in,
+ union sockunion *out,
+ struct interface *ifp)
+{
+ int ret = 0;
+
+ zclient_create_header(s, cmd, ifp->vrf_id);
+ stream_putc(s, sockunion_family(in));
+ stream_write(s, sockunion_get_addr(in), sockunion_get_addrlen(in));
+ if (out && sockunion_family(out) != AF_UNSPEC) {
+ stream_putc(s, sockunion_family(out));
+ stream_write(s, sockunion_get_addr(out),
+ sockunion_get_addrlen(out));
+ } else
+ stream_putc(s, AF_UNSPEC);
+ stream_putl(s, ifp->ifindex);
+ if (out)
+ stream_putl(s, ZEBRA_NEIGH_STATE_REACHABLE);
+ else
+ stream_putl(s, ZEBRA_NEIGH_STATE_FAILED);
+ return ret;
+}
+
+int zclient_neigh_ip_decode(struct stream *s, struct zapi_neigh_ip *api)
+{
+ int ret;
+
+ ret = zclient_neigh_ip_read_entry(s, &api->ip_in);
+ if (ret < 0)
+ return -1;
+ zclient_neigh_ip_read_entry(s, &api->ip_out);
+
+ STREAM_GETL(s, api->index);
+ STREAM_GETL(s, api->ndm_state);
+ return 0;
+ stream_failure:
+ return -1;
+}
/* For struct zapi_route. */
#include "prefix.h"
+#include "ipaddr.h"
/* For struct interface and struct connected. */
#include "if.h"
ZEBRA_NEIGH_DISCOVER,
ZEBRA_ROUTE_NOTIFY_REQUEST,
ZEBRA_CLIENT_CLOSE_NOTIFY,
+ ZEBRA_NHRP_NEIGH_ADDED,
+ ZEBRA_NHRP_NEIGH_REMOVED,
+ ZEBRA_NHRP_NEIGH_GET,
+ ZEBRA_NHRP_NEIGH_REGISTER,
+ ZEBRA_NHRP_NEIGH_UNREGISTER,
+ ZEBRA_NEIGH_IP_ADD,
+ ZEBRA_NEIGH_IP_DEL,
+ ZEBRA_CONFIGURE_ARP,
} zebra_message_types_t;
enum zebra_error_types {
int (*opaque_unregister_handler)(ZAPI_CALLBACK_ARGS);
int (*sr_policy_notify_status)(ZAPI_CALLBACK_ARGS);
int (*zebra_client_close_notify)(ZAPI_CALLBACK_ARGS);
+ void (*neighbor_added)(ZAPI_CALLBACK_ARGS);
+ void (*neighbor_removed)(ZAPI_CALLBACK_ARGS);
+ void (*neighbor_get)(ZAPI_CALLBACK_ARGS);
};
/* Zebra API message flag. */
extern struct zclient_options zclient_options_default;
+/* link layer representation for GRE like interfaces
+ * ip_in is the underlay IP, ip_out is the tunnel dest
+ * index stands for the index of the interface
+ * ndm state stands for the NDM value in netlink
+ */
+#define ZEBRA_NEIGH_STATE_REACHABLE (0x02)
+#define ZEBRA_NEIGH_STATE_FAILED (0x20)
+struct zapi_neigh_ip {
+ int cmd;
+ struct ipaddr ip_in;
+ struct ipaddr ip_out;
+ ifindex_t index;
+ uint32_t ndm_state;
+};
+int zclient_neigh_ip_decode(struct stream *s, struct zapi_neigh_ip *api);
+int zclient_neigh_ip_encode(struct stream *s,
+ uint16_t cmd,
+ union sockunion *in,
+ union sockunion *out,
+ struct interface *ifp);
+
/*
* We reserve the top 4 bits for l2-NHG, everything else
* is for zebra/proto l3-NHG.
struct zlog_tls {
char *mmbuf;
size_t bufpos;
+ bool do_unlink;
size_t nmsgs;
struct zlog_msg msgs[TLS_LOG_MAXMSG];
mmpath, strerror(errno));
goto out_anon_unlink;
}
+ zlog_tls->do_unlink = true;
close(mmfd);
zlog_tls_set(zlog_tls);
return;
out_anon_unlink:
- unlink(mmpath);
+ unlinkat(zlog_tmpdirfd, mmpath, 0);
close(mmfd);
out_anon:
void zlog_tls_buffer_fini(void)
{
char mmpath[MAXPATHLEN];
+ struct zlog_tls *zlog_tls = zlog_tls_get();
+ bool do_unlink = zlog_tls ? zlog_tls->do_unlink : false;
zlog_tls_buffer_flush();
- zlog_tls_free(zlog_tls_get());
+ zlog_tls_free(zlog_tls);
zlog_tls_set(NULL);
snprintfrr(mmpath, sizeof(mmpath), "logbuf.%ld", zlog_gettid());
- if (unlinkat(zlog_tmpdirfd, mmpath, 0))
+ if (do_unlink && unlinkat(zlog_tmpdirfd, mmpath, 0))
zlog_err("unlink logbuf: %s (%d)", strerror(errno), errno);
}
#include <stdio.h>
#include <unistd.h>
#include <string.h>
+#include <errno.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include "os.h"
#include "netlink.h"
+#ifndef HAVE_STRLCPY
+size_t strlcpy(char *__restrict dest,
+ const char *__restrict src, size_t destsize);
+#endif
+
static int nhrp_socket_fd = -1;
int os_socket(void)
}
int os_sendmsg(const uint8_t *buf, size_t len, int ifindex, const uint8_t *addr,
- size_t addrlen)
+ size_t addrlen, uint16_t protocol)
{
struct sockaddr_ll lladdr;
struct iovec iov = {
.msg_iov = &iov,
.msg_iovlen = 1,
};
- int status;
+ int status, fd;
if (addrlen > sizeof(lladdr.sll_addr))
return -1;
memset(&lladdr, 0, sizeof(lladdr));
lladdr.sll_family = AF_PACKET;
- lladdr.sll_protocol = htons(ETH_P_NHRP);
+ lladdr.sll_protocol = htons(protocol);
lladdr.sll_ifindex = ifindex;
lladdr.sll_halen = addrlen;
memcpy(lladdr.sll_addr, addr, addrlen);
- status = sendmsg(nhrp_socket_fd, &msg, 0);
- if (status < 0)
+ fd = os_socket();
+ if (fd < 0)
return -1;
- return 0;
+ status = sendmsg(fd, &msg, 0);
+ if (status < 0)
+ return -errno;
+
+ return status;
}
int os_recvmsg(uint8_t *buf, size_t *len, int *ifindex, uint8_t *addr,
{
struct ifreq ifr;
- strncpy(ifr.ifr_name, iface, IFNAMSIZ - 1);
+ strlcpy(ifr.ifr_name, iface, IFNAMSIZ);
if (ioctl(nhrp_socket_fd, SIOCGIFFLAGS, &ifr))
return -1;
break;
}
ret |= linux_configure_arp(ifname, 1);
- ret |= netlink_configure_arp(ifindex, af);
return ret;
}
struct interface;
extern int netlink_nflog_group;
+extern int netlink_mcast_nflog_group;
extern int netlink_req_fd;
void netlink_init(void);
#include <linux/netfilter/nfnetlink_log.h>
#include "thread.h"
+#include "stream.h"
+#include "prefix.h"
#include "nhrpd.h"
#include "netlink.h"
#include "znl.h"
int netlink_nflog_group;
static int netlink_log_fd = -1;
static struct thread *netlink_log_thread;
-static int netlink_listen_fd = -1;
-
-typedef void (*netlink_dispatch_f)(struct nlmsghdr *msg, struct zbuf *zb);
void netlink_update_binding(struct interface *ifp, union sockunion *proto,
union sockunion *nbma)
{
- struct nlmsghdr *n;
- struct ndmsg *ndm;
- struct zbuf *zb = zbuf_alloc(512);
-
- n = znl_nlmsg_push(zb, nbma ? RTM_NEWNEIGH : RTM_DELNEIGH,
- NLM_F_REQUEST | NLM_F_REPLACE | NLM_F_CREATE);
- ndm = znl_push(zb, sizeof(*ndm));
- *ndm = (struct ndmsg){
- .ndm_family = sockunion_family(proto),
- .ndm_ifindex = ifp->ifindex,
- .ndm_type = RTN_UNICAST,
- .ndm_state = nbma ? NUD_REACHABLE : NUD_FAILED,
- };
- znl_rta_push(zb, NDA_DST, sockunion_get_addr(proto),
- family2addrsize(sockunion_family(proto)));
- if (nbma)
- znl_rta_push(zb, NDA_LLADDR, sockunion_get_addr(nbma),
- family2addrsize(sockunion_family(nbma)));
- znl_nlmsg_complete(zb, n);
- zbuf_send(zb, netlink_req_fd);
- zbuf_recv(zb, netlink_req_fd);
- zbuf_free(zb);
-}
-
-static void netlink_neigh_msg(struct nlmsghdr *msg, struct zbuf *zb)
-{
- struct ndmsg *ndm;
- struct rtattr *rta;
- struct nhrp_cache *c;
- struct interface *ifp;
- struct zbuf payload;
- union sockunion addr, lladdr;
- size_t len;
- int state;
-
- memset(&lladdr, 0, sizeof(lladdr));
- ndm = znl_pull(zb, sizeof(*ndm));
- if (!ndm)
- return;
-
- sockunion_family(&addr) = AF_UNSPEC;
- while ((rta = znl_rta_pull(zb, &payload)) != NULL) {
- len = zbuf_used(&payload);
- switch (rta->rta_type) {
- case NDA_DST:
- sockunion_set(&addr, ndm->ndm_family,
- zbuf_pulln(&payload, len), len);
- break;
- case NDA_LLADDR:
- sockunion_set(&lladdr, ndm->ndm_family,
- zbuf_pulln(&payload, len), len);
- break;
- }
- }
-
- ifp = if_lookup_by_index(ndm->ndm_ifindex, VRF_DEFAULT);
- if (!ifp || sockunion_family(&addr) == AF_UNSPEC)
- return;
-
- c = nhrp_cache_get(ifp, &addr, 0);
- if (!c)
- return;
-
- debugf(NHRP_DEBUG_KERNEL,
- "Netlink: %s %pSU dev %s lladdr %pSU nud 0x%x cache used %u type %u",
- (msg->nlmsg_type == RTM_GETNEIGH)
- ? "who-has"
- : (msg->nlmsg_type == RTM_NEWNEIGH) ? "new-neigh"
- : "del-neigh",
- &addr, ifp->name, &lladdr, ndm->ndm_state, c->used, c->cur.type);
-
- if (msg->nlmsg_type == RTM_GETNEIGH) {
- if (c->cur.type >= NHRP_CACHE_CACHED) {
- nhrp_cache_set_used(c, 1);
- debugf(NHRP_DEBUG_KERNEL,
- "Netlink: update binding for %pSU dev %s from c %pSU peer.vc.nbma %pSU to lladdr %pSU",
- &addr, ifp->name, &c->cur.remote_nbma_natoa,
- &c->cur.peer->vc->remote.nbma, &lladdr);
- /* In case of shortcuts, nbma is given by lladdr, not
- * vc->remote.nbma.
- */
- netlink_update_binding(ifp, &addr, &lladdr);
- }
- } else {
- state = (msg->nlmsg_type == RTM_NEWNEIGH) ? ndm->ndm_state
- : NUD_FAILED;
- nhrp_cache_set_used(c, state == NUD_REACHABLE);
- }
-}
-
-static int netlink_route_recv(struct thread *t)
-{
- uint8_t buf[ZNL_BUFFER_SIZE];
- int fd = THREAD_FD(t);
- struct zbuf payload, zb;
- struct nlmsghdr *n;
-
- zbuf_init(&zb, buf, sizeof(buf), 0);
- while (zbuf_recv(&zb, fd) > 0) {
- while ((n = znl_nlmsg_pull(&zb, &payload)) != NULL) {
- debugf(NHRP_DEBUG_KERNEL,
- "Netlink: Received msg_type %u, msg_flags %u",
- n->nlmsg_type, n->nlmsg_flags);
- switch (n->nlmsg_type) {
- case RTM_GETNEIGH:
- case RTM_NEWNEIGH:
- case RTM_DELNEIGH:
- netlink_neigh_msg(n, &payload);
- break;
- }
- }
- }
-
- thread_add_read(master, netlink_route_recv, 0, fd, NULL);
-
- return 0;
+ nhrp_send_zebra_nbr(proto, nbma, ifp);
}
static void netlink_log_register(int fd, int group)
}
}
-void netlink_init(void)
+void nhrp_neighbor_operation(ZAPI_CALLBACK_ARGS)
{
- netlink_req_fd = znl_open(NETLINK_ROUTE, 0);
- if (netlink_req_fd < 0)
- return;
+ union sockunion addr = {}, lladdr = {};
+ struct interface *ifp;
+ int state, ndm_state;
+ struct nhrp_cache *c;
+ struct zapi_neigh_ip api = {};
- netlink_listen_fd = znl_open(NETLINK_ROUTE, RTMGRP_NEIGH);
- if (netlink_listen_fd < 0)
+ zclient_neigh_ip_decode(zclient->ibuf, &api);
+ if (api.ip_in.ipa_type == AF_UNSPEC)
return;
+ sockunion_family(&addr) = api.ip_in.ipa_type;
+ memcpy((uint8_t *)sockunion_get_addr(&addr), &api.ip_in.ip.addr,
+ family2addrsize(api.ip_in.ipa_type));
- thread_add_read(master, netlink_route_recv, 0, netlink_listen_fd, NULL);
-}
+ sockunion_family(&lladdr) = api.ip_out.ipa_type;
+ if (api.ip_out.ipa_type != AF_UNSPEC)
+ memcpy((uint8_t *)sockunion_get_addr(&lladdr),
+ &api.ip_out.ip.addr,
+ family2addrsize(api.ip_out.ipa_type));
-int netlink_configure_arp(unsigned int ifindex, int pf)
-{
- struct nlmsghdr *n;
- struct ndtmsg *ndtm;
- struct rtattr *rta;
- struct zbuf *zb = zbuf_alloc(512);
- int r;
-
- n = znl_nlmsg_push(zb, RTM_SETNEIGHTBL, NLM_F_REQUEST | NLM_F_REPLACE);
- ndtm = znl_push(zb, sizeof(*ndtm));
- *ndtm = (struct ndtmsg){
- .ndtm_family = pf,
- };
+ ifp = if_lookup_by_index(api.index, vrf_id);
+ ndm_state = api.ndm_state;
- znl_rta_push(zb, NDTA_NAME, pf == AF_INET ? "arp_cache" : "ndisc_cache",
- 10);
-
- rta = znl_rta_nested_push(zb, NDTA_PARMS);
- znl_rta_push_u32(zb, NDTPA_IFINDEX, ifindex);
- znl_rta_push_u32(zb, NDTPA_APP_PROBES, 1);
- znl_rta_push_u32(zb, NDTPA_MCAST_PROBES, 0);
- znl_rta_push_u32(zb, NDTPA_UCAST_PROBES, 0);
- znl_rta_nested_complete(zb, rta);
-
- znl_nlmsg_complete(zb, n);
- r = zbuf_send(zb, netlink_req_fd);
- zbuf_recv(zb, netlink_req_fd);
- zbuf_free(zb);
+ if (!ifp)
+ return;
+ c = nhrp_cache_get(ifp, &addr, 0);
+ if (!c)
+ return;
+ debugf(NHRP_DEBUG_KERNEL,
+ "Netlink: %s %pSU dev %s lladdr %pSU nud 0x%x cache used %u type %u",
+ (cmd == ZEBRA_NHRP_NEIGH_GET)
+ ? "who-has"
+ : (cmd == ZEBRA_NHRP_NEIGH_ADDED) ? "new-neigh"
+ : "del-neigh",
+ &addr, ifp->name, &lladdr, ndm_state, c->used, c->cur.type);
+ if (cmd == ZEBRA_NHRP_NEIGH_GET) {
+ if (c->cur.type >= NHRP_CACHE_CACHED) {
+ nhrp_cache_set_used(c, 1);
+ debugf(NHRP_DEBUG_KERNEL,
+ "Netlink: update binding for %pSU dev %s from c %pSU peer.vc.nbma %pSU to lladdr %pSU",
+ &addr, ifp->name, &c->cur.remote_nbma_natoa,
+ &c->cur.peer->vc->remote.nbma, &lladdr);
+ /* In case of shortcuts, nbma is given by lladdr, not
+ * vc->remote.nbma.
+ */
+ netlink_update_binding(ifp, &addr, &lladdr);
+ }
+ } else {
+ state = (cmd == ZEBRA_NHRP_NEIGH_ADDED) ? ndm_state
+ : ZEBRA_NEIGH_STATE_FAILED;
+ nhrp_cache_set_used(c, state == ZEBRA_NEIGH_STATE_REACHABLE);
+ }
+}
- return r;
+void netlink_init(void)
+{
+ netlink_req_fd = znl_open(NETLINK_ROUTE, 0);
+ if (netlink_req_fd < 0)
+ return;
}
struct nhrp_afi_data *ad = &nifp->afi[afi];
ad->holdtime = NHRPD_DEFAULT_HOLDTIME;
list_init(&ad->nhslist_head);
+ list_init(&ad->mcastlist_head);
}
return 0;
nhrp_cache_interface_del(ifp);
nhrp_nhs_interface_del(ifp);
+ nhrp_multicast_interface_del(ifp);
nhrp_peer_interface_del(ifp);
if (nifp->ipsec_profile)
if (!if_ad->configured) {
os_configure_dmvpn(ifp->ifindex, ifp->name,
afi2family(afi));
+ nhrp_send_zebra_configure_arp(ifp, afi2family(afi));
if_ad->configured = 1;
nhrp_interface_update_address(ifp, afi, 1);
}
--- /dev/null
+/* NHRP Multicast Support
+ * Copyright (c) 2020-2021 4RF Limited
+ *
+ * This file is free software: you may copy, redistribute 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <fcntl.h>
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <netinet/if_ether.h>
+#include <linux/netlink.h>
+#include <linux/neighbour.h>
+#include <linux/netfilter/nfnetlink_log.h>
+#include <linux/if_packet.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "thread.h"
+#include "nhrpd.h"
+#include "netlink.h"
+#include "znl.h"
+#include "os.h"
+
+DEFINE_MTYPE_STATIC(NHRPD, NHRP_MULTICAST, "NHRP Multicast");
+
+int netlink_mcast_nflog_group;
+static int netlink_mcast_log_fd = -1;
+static struct thread *netlink_mcast_log_thread;
+
+struct mcast_ctx {
+ struct interface *ifp;
+ struct zbuf *pkt;
+};
+
+static void nhrp_multicast_send(struct nhrp_peer *p, struct zbuf *zb)
+{
+ size_t addrlen;
+ int ret;
+
+ addrlen = sockunion_get_addrlen(&p->vc->remote.nbma);
+ ret = os_sendmsg(zb->head, zbuf_used(zb), p->ifp->ifindex,
+ sockunion_get_addr(&p->vc->remote.nbma), addrlen,
+ addrlen == 4 ? ETH_P_IP : ETH_P_IPV6);
+
+ debugf(NHRP_DEBUG_COMMON,
+ "Multicast Packet: %pSU -> %pSU, ret = %d, size = %zu, addrlen = %zu",
+ &p->vc->local.nbma, &p->vc->remote.nbma, ret, zbuf_used(zb),
+ addrlen);
+}
+
+static void nhrp_multicast_forward_nbma(union sockunion *nbma_addr,
+ struct interface *ifp, struct zbuf *pkt)
+{
+ struct nhrp_peer *p = nhrp_peer_get(ifp, nbma_addr);
+
+ if (p && p->online) {
+ /* Send packet */
+ nhrp_multicast_send(p, pkt);
+ }
+ nhrp_peer_unref(p);
+}
+
+static void nhrp_multicast_forward_cache(struct nhrp_cache *c, void *pctx)
+{
+ struct mcast_ctx *ctx = (struct mcast_ctx *)pctx;
+
+ if (c->cur.type == NHRP_CACHE_DYNAMIC && c->cur.peer)
+ nhrp_multicast_forward_nbma(&c->cur.peer->vc->remote.nbma,
+ ctx->ifp, ctx->pkt);
+}
+
+static void nhrp_multicast_forward(struct nhrp_multicast *mcast, void *pctx)
+{
+ struct mcast_ctx *ctx = (struct mcast_ctx *)pctx;
+ struct nhrp_interface *nifp = ctx->ifp->info;
+
+ if (!nifp->enabled)
+ return;
+
+ /* dynamic */
+ if (sockunion_family(&mcast->nbma_addr) == AF_UNSPEC) {
+ nhrp_cache_foreach(ctx->ifp, nhrp_multicast_forward_cache,
+ pctx);
+ return;
+ }
+
+ /* Fixed IP Address */
+ nhrp_multicast_forward_nbma(&mcast->nbma_addr, ctx->ifp, ctx->pkt);
+}
+
+static void netlink_mcast_log_handler(struct nlmsghdr *msg, struct zbuf *zb)
+{
+ struct nfgenmsg *nf;
+ struct rtattr *rta;
+ struct zbuf rtapl;
+ uint32_t *out_ndx = NULL;
+ afi_t afi;
+ struct mcast_ctx ctx;
+
+ nf = znl_pull(zb, sizeof(*nf));
+ if (!nf)
+ return;
+
+ ctx.pkt = NULL;
+ while ((rta = znl_rta_pull(zb, &rtapl)) != NULL) {
+ switch (rta->rta_type) {
+ case NFULA_IFINDEX_OUTDEV:
+ out_ndx = znl_pull(&rtapl, sizeof(*out_ndx));
+ break;
+ case NFULA_PAYLOAD:
+ ctx.pkt = &rtapl;
+ break;
+ /* NFULA_HWHDR exists and is supposed to contain source
+ * hardware address. However, for ip_gre it seems to be
+ * the nexthop destination address if the packet matches
+ * route.
+ */
+ }
+ }
+
+ if (!out_ndx || !ctx.pkt)
+ return;
+
+ ctx.ifp = if_lookup_by_index(htonl(*out_ndx), VRF_DEFAULT);
+ if (!ctx.ifp)
+ return;
+
+ debugf(NHRP_DEBUG_COMMON,
+ "Intercepted multicast packet leaving %s len %zu",
+ ctx.ifp->name, zbuf_used(ctx.pkt));
+
+ for (afi = 0; afi < AFI_MAX; afi++) {
+ nhrp_multicast_foreach(ctx.ifp, afi, nhrp_multicast_forward,
+ (void *)&ctx);
+ }
+}
+
+static int netlink_mcast_log_recv(struct thread *t)
+{
+ uint8_t buf[65535]; /* Max OSPF Packet size */
+ int fd = THREAD_FD(t);
+ struct zbuf payload, zb;
+ struct nlmsghdr *n;
+
+ netlink_mcast_log_thread = NULL;
+
+ zbuf_init(&zb, buf, sizeof(buf), 0);
+ while (zbuf_recv(&zb, fd) > 0) {
+ while ((n = znl_nlmsg_pull(&zb, &payload)) != NULL) {
+ debugf(NHRP_DEBUG_COMMON,
+ "Netlink-mcast-log: Received msg_type %u, msg_flags %u",
+ n->nlmsg_type, n->nlmsg_flags);
+ switch (n->nlmsg_type) {
+ case (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_PACKET:
+ netlink_mcast_log_handler(n, &payload);
+ break;
+ }
+ }
+ }
+
+ thread_add_read(master, netlink_mcast_log_recv, 0, netlink_mcast_log_fd,
+ &netlink_mcast_log_thread);
+
+ return 0;
+}
+
+static void netlink_mcast_log_register(int fd, int group)
+{
+ struct nlmsghdr *n;
+ struct nfgenmsg *nf;
+ struct nfulnl_msg_config_cmd cmd;
+ struct zbuf *zb = zbuf_alloc(512);
+
+ n = znl_nlmsg_push(zb, (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG,
+ NLM_F_REQUEST | NLM_F_ACK);
+ nf = znl_push(zb, sizeof(*nf));
+ *nf = (struct nfgenmsg){
+ .nfgen_family = AF_UNSPEC,
+ .version = NFNETLINK_V0,
+ .res_id = htons(group),
+ };
+ cmd.command = NFULNL_CFG_CMD_BIND;
+ znl_rta_push(zb, NFULA_CFG_CMD, &cmd, sizeof(cmd));
+ znl_nlmsg_complete(zb, n);
+
+ zbuf_send(zb, fd);
+ zbuf_free(zb);
+}
+
+void netlink_mcast_set_nflog_group(int nlgroup)
+{
+ if (netlink_mcast_log_fd >= 0) {
+ THREAD_OFF(netlink_mcast_log_thread);
+ close(netlink_mcast_log_fd);
+ netlink_mcast_log_fd = -1;
+ debugf(NHRP_DEBUG_COMMON, "De-register nflog group");
+ }
+ netlink_mcast_nflog_group = nlgroup;
+ if (nlgroup) {
+ netlink_mcast_log_fd = znl_open(NETLINK_NETFILTER, 0);
+ if (netlink_mcast_log_fd < 0)
+ return;
+
+ netlink_mcast_log_register(netlink_mcast_log_fd, nlgroup);
+ thread_add_read(master, netlink_mcast_log_recv, 0,
+ netlink_mcast_log_fd,
+ &netlink_mcast_log_thread);
+ debugf(NHRP_DEBUG_COMMON, "Register nflog group: %d",
+ netlink_mcast_nflog_group);
+ }
+}
+
+static int nhrp_multicast_free(struct interface *ifp,
+ struct nhrp_multicast *mcast)
+{
+ list_del(&mcast->list_entry);
+ XFREE(MTYPE_NHRP_MULTICAST, mcast);
+ return 0;
+}
+
+int nhrp_multicast_add(struct interface *ifp, afi_t afi,
+ union sockunion *nbma_addr)
+{
+ struct nhrp_interface *nifp = ifp->info;
+ struct nhrp_multicast *mcast;
+
+ list_for_each_entry(mcast, &nifp->afi[afi].mcastlist_head, list_entry)
+ {
+ if (sockunion_same(&mcast->nbma_addr, nbma_addr))
+ return NHRP_ERR_ENTRY_EXISTS;
+ }
+
+ mcast = XMALLOC(MTYPE_NHRP_MULTICAST, sizeof(struct nhrp_multicast));
+
+ *mcast = (struct nhrp_multicast){
+ .afi = afi, .ifp = ifp, .nbma_addr = *nbma_addr,
+ };
+ list_add_tail(&mcast->list_entry, &nifp->afi[afi].mcastlist_head);
+
+ debugf(NHRP_DEBUG_COMMON, "Adding multicast entry (%pSU)", nbma_addr);
+
+ return NHRP_OK;
+}
+
+int nhrp_multicast_del(struct interface *ifp, afi_t afi,
+ union sockunion *nbma_addr)
+{
+ struct nhrp_interface *nifp = ifp->info;
+ struct nhrp_multicast *mcast, *tmp;
+
+ list_for_each_entry_safe(mcast, tmp, &nifp->afi[afi].mcastlist_head,
+ list_entry)
+ {
+ if (!sockunion_same(&mcast->nbma_addr, nbma_addr))
+ continue;
+
+ debugf(NHRP_DEBUG_COMMON, "Deleting multicast entry (%pSU)",
+ nbma_addr);
+
+ nhrp_multicast_free(ifp, mcast);
+
+ return NHRP_OK;
+ }
+
+ return NHRP_ERR_ENTRY_NOT_FOUND;
+}
+
+void nhrp_multicast_interface_del(struct interface *ifp)
+{
+ struct nhrp_interface *nifp = ifp->info;
+ struct nhrp_multicast *mcast, *tmp;
+ afi_t afi;
+
+ for (afi = 0; afi < AFI_MAX; afi++) {
+ debugf(NHRP_DEBUG_COMMON,
+ "Cleaning up multicast entries (%d)",
+ !list_empty(&nifp->afi[afi].mcastlist_head));
+
+ list_for_each_entry_safe(
+ mcast, tmp, &nifp->afi[afi].mcastlist_head, list_entry)
+ {
+ nhrp_multicast_free(ifp, mcast);
+ }
+ }
+}
+
+void nhrp_multicast_foreach(struct interface *ifp, afi_t afi,
+ void (*cb)(struct nhrp_multicast *, void *),
+ void *ctx)
+{
+ struct nhrp_interface *nifp = ifp->info;
+ struct nhrp_multicast *mcast;
+
+ list_for_each_entry(mcast, &nifp->afi[afi].mcastlist_head, list_entry)
+ {
+ cb(mcast, ctx);
+ }
+}
return p;
}
-static void do_peer_hash_free(struct hash_bucket *hb,
- void *arg __attribute__((__unused__)))
+static void do_peer_hash_free(void *hb_data)
{
- struct nhrp_peer *p = hb->data;
+ struct nhrp_peer *p = (struct nhrp_peer *)hb_data;
+
nhrp_peer_check_delete(p);
}
nifp->peer_hash ? nifp->peer_hash->count : 0);
if (nifp->peer_hash) {
- hash_iterate(nifp->peer_hash, do_peer_hash_free, NULL);
+ hash_clean(nifp->peer_hash, do_peer_hash_free);
assert(nifp->peer_hash->count == 0);
hash_free(nifp->peer_hash);
+ nifp->peer_hash = NULL;
}
}
os_sendmsg(zb->head, zbuf_used(zb), p->ifp->ifindex,
sockunion_get_addr(&p->vc->remote.nbma),
- sockunion_get_addrlen(&p->vc->remote.nbma));
+ sockunion_get_addrlen(&p->vc->remote.nbma), ETH_P_NHRP);
zbuf_reset(zb);
}
}
}
+static void nhrp_zebra_register_neigh(vrf_id_t vrf_id, afi_t afi, bool reg)
+{
+ struct stream *s;
+
+ if (!zclient || zclient->sock < 0)
+ return;
+
+ s = zclient->obuf;
+ stream_reset(s);
+
+ zclient_create_header(s, reg ? ZEBRA_NHRP_NEIGH_REGISTER :
+ ZEBRA_NHRP_NEIGH_UNREGISTER,
+ vrf_id);
+ stream_putw(s, afi);
+ stream_putw_at(s, 0, stream_get_endp(s));
+ zclient_send_message(zclient);
+}
+
void nhrp_route_update_nhrp(const struct prefix *p, struct interface *ifp)
{
struct route_node *rn;
ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT);
zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6,
ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT);
+ nhrp_zebra_register_neigh(VRF_DEFAULT, AFI_IP, true);
+ nhrp_zebra_register_neigh(VRF_DEFAULT, AFI_IP6, true);
}
void nhrp_zebra_init(void)
zclient->interface_address_delete = nhrp_interface_address_delete;
zclient->redistribute_route_add = nhrp_route_read;
zclient->redistribute_route_del = nhrp_route_read;
-
+ zclient->neighbor_added = nhrp_neighbor_operation;
+ zclient->neighbor_removed = nhrp_neighbor_operation;
+ zclient->neighbor_get = nhrp_neighbor_operation;
zclient_init(zclient, ZEBRA_ROUTE_NHRP, 0, &nhrpd_privs);
}
XFREE(MTYPE_NHRP_ROUTE, node->info);
}
+void nhrp_send_zebra_configure_arp(struct interface *ifp, int family)
+{
+ struct stream *s;
+
+ if (!zclient || zclient->sock < 0) {
+ debugf(NHRP_DEBUG_COMMON, "%s() : zclient not ready",
+ __func__);
+ return;
+ }
+ s = zclient->obuf;
+ stream_reset(s);
+ zclient_create_header(s,
+ ZEBRA_CONFIGURE_ARP,
+ ifp->vrf_id);
+ stream_putc(s, family);
+ stream_putl(s, ifp->ifindex);
+ stream_putw_at(s, 0, stream_get_endp(s));
+ zclient_send_message(zclient);
+}
+
+void nhrp_send_zebra_nbr(union sockunion *in,
+ union sockunion *out,
+ struct interface *ifp)
+{
+ struct stream *s;
+
+ if (!zclient || zclient->sock < 0)
+ return;
+ s = zclient->obuf;
+ stream_reset(s);
+ zclient_neigh_ip_encode(s, out ? ZEBRA_NEIGH_IP_ADD :
+ ZEBRA_NEIGH_IP_DEL, in, out,
+ ifp);
+ stream_putw_at(s, 0, stream_get_endp(s));
+ zclient_send_message(zclient);
+}
+
void nhrp_zebra_terminate(void)
{
+ nhrp_zebra_register_neigh(VRF_DEFAULT, AFI_IP, false);
+ nhrp_zebra_register_neigh(VRF_DEFAULT, AFI_IP6, false);
zclient_stop(zclient);
zclient_free(zclient);
if (netlink_nflog_group) {
vty_out(vty, "nhrp nflog-group %d\n", netlink_nflog_group);
}
+ if (netlink_mcast_nflog_group)
+ vty_out(vty, "nhrp multicast-nflog-group %d\n",
+ netlink_mcast_nflog_group);
return 0;
}
return CMD_SUCCESS;
}
+DEFUN(nhrp_multicast_nflog_group, nhrp_multicast_nflog_group_cmd,
+ "nhrp multicast-nflog-group (1-65535)",
+ NHRP_STR
+ "Specify NFLOG group number for Multicast Packets\n"
+ "NFLOG group number\n")
+{
+ uint32_t nfgroup;
+
+ nfgroup = strtoul(argv[2]->arg, NULL, 10);
+ netlink_mcast_set_nflog_group(nfgroup);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(no_nhrp_multicast_nflog_group, no_nhrp_multicast_nflog_group_cmd,
+ "no nhrp multicast-nflog-group [(1-65535)]",
+ NO_STR
+ NHRP_STR
+ "Specify NFLOG group number\n"
+ "NFLOG group number\n")
+{
+ netlink_mcast_set_nflog_group(0);
+ return CMD_SUCCESS;
+}
+
DEFUN(tunnel_protection, tunnel_protection_cmd,
"tunnel protection vici profile PROFILE [fallback-profile FALLBACK]",
"NHRP/GRE integration\n"
return CMD_SUCCESS;
}
+DEFUN(if_nhrp_map_multicast, if_nhrp_map_multicast_cmd,
+ AFI_CMD " nhrp map multicast <A.B.C.D|X:X::X:X|dynamic>",
+ AFI_STR
+ NHRP_STR
+ "Multicast NBMA Configuration\n"
+ "Use this NBMA mapping for multicasts\n"
+ "IPv4 NBMA address\n"
+ "IPv6 NBMA address\n"
+ "Dynamically learn destinations from client registrations on hub\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ afi_t afi = cmd_to_afi(argv[0]);
+ union sockunion nbma_addr;
+ int ret;
+
+ if (str2sockunion(argv[4]->arg, &nbma_addr) < 0)
+ sockunion_family(&nbma_addr) = AF_UNSPEC;
+
+ ret = nhrp_multicast_add(ifp, afi, &nbma_addr);
+
+ return nhrp_vty_return(vty, ret);
+}
+
+DEFUN(if_no_nhrp_map_multicast, if_no_nhrp_map_multicast_cmd,
+ "no " AFI_CMD " nhrp map multicast <A.B.C.D|X:X::X:X|dynamic>",
+ NO_STR
+ AFI_STR
+ NHRP_STR
+ "Multicast NBMA Configuration\n"
+ "Use this NBMA mapping for multicasts\n"
+ "IPv4 NBMA address\n"
+ "IPv6 NBMA address\n"
+ "Dynamically learn destinations from client registrations on hub\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ afi_t afi = cmd_to_afi(argv[1]);
+ union sockunion nbma_addr;
+ int ret;
+
+ if (str2sockunion(argv[5]->arg, &nbma_addr) < 0)
+ sockunion_family(&nbma_addr) = AF_UNSPEC;
+
+ ret = nhrp_multicast_del(ifp, afi, &nbma_addr);
+
+ return nhrp_vty_return(vty, ret);
+}
+
DEFUN(if_nhrp_nhs, if_nhrp_nhs_cmd,
AFI_CMD " nhrp nhs <A.B.C.D|X:X::X:X|dynamic> nbma <A.B.C.D|FQDN>",
AFI_STR
ctx->count++;
if (reg && reg->peer)
- sockunion2str(®->peer->vc->remote.nbma,
- buf[0], sizeof(buf[0]));
+ sockunion2str(®->peer->vc->remote.nbma, buf[0],
+ sizeof(buf[0]));
else
snprintf(buf[0], sizeof(buf[0]), "-");
sockunion2str(reg ? ®->proto_addr : &n->proto_addr, buf[1],
const char *aficmd;
};
-static void interface_config_write_nhrp_map(struct nhrp_cache_config *c, void *data)
+static void interface_config_write_nhrp_map(struct nhrp_cache_config *c,
+ void *data)
{
struct write_map_ctx *ctx = data;
struct vty *vty = ctx->vty;
- char buf[2][SU_ADDRSTRLEN];
if (sockunion_family(&c->remote_addr) != ctx->family)
return;
- vty_out(vty, " %s nhrp map %s %s\n", ctx->aficmd,
- sockunion2str(&c->remote_addr, buf[0], sizeof(buf[0])),
- c->type == NHRP_CACHE_LOCAL
- ? "local" : sockunion2str(&c->nbma, buf[1], sizeof(buf[1])));
+ vty_out(vty, " %s nhrp map %pSU ", ctx->aficmd, &c->remote_addr);
+ if (c->type == NHRP_CACHE_LOCAL)
+ vty_out(vty, "local\n");
+ else
+ vty_out(vty, "%pSU\n", &c->nbma);
}
static int interface_config_write(struct vty *vty)
struct interface *ifp;
struct nhrp_interface *nifp;
struct nhrp_nhs *nhs;
+ struct nhrp_multicast *mcast;
const char *aficmd;
afi_t afi;
- char buf[SU_ADDRSTRLEN];
int i;
FOR_ALL_INTERFACES (vrf, ifp) {
.family = afi2family(afi),
.aficmd = aficmd,
};
- nhrp_cache_config_foreach(ifp, interface_config_write_nhrp_map,
- &mapctx);
+ nhrp_cache_config_foreach(
+ ifp, interface_config_write_nhrp_map, &mapctx);
list_for_each_entry(nhs, &ad->nhslist_head,
nhslist_entry)
{
- vty_out(vty, " %s nhrp nhs %s nbma %s\n",
- aficmd,
- sockunion_family(&nhs->proto_addr)
- == AF_UNSPEC
- ? "dynamic"
- : sockunion2str(
- &nhs->proto_addr, buf,
- sizeof(buf)),
- nhs->nbma_fqdn);
+ vty_out(vty, " %s nhrp nhs ", aficmd);
+ if (sockunion_family(&nhs->proto_addr)
+ == AF_UNSPEC)
+ vty_out(vty, "dynamic");
+ else
+ vty_out(vty, "%pSU", &nhs->proto_addr);
+ vty_out(vty, "nbma %s\n", nhs->nbma_fqdn);
+ }
+
+ list_for_each_entry(mcast, &ad->mcastlist_head,
+ list_entry)
+ {
+ vty_out(vty, " %s nhrp map multicast ", aficmd);
+ if (sockunion_family(&mcast->nbma_addr)
+ == AF_UNSPEC)
+ vty_out(vty, "dynamic\n");
+ else
+ vty_out(vty, "%pSU\n",
+ &mcast->nbma_addr);
}
}
install_element(CONFIG_NODE, &no_nhrp_event_socket_cmd);
install_element(CONFIG_NODE, &nhrp_nflog_group_cmd);
install_element(CONFIG_NODE, &no_nhrp_nflog_group_cmd);
+ install_element(CONFIG_NODE, &nhrp_multicast_nflog_group_cmd);
+ install_element(CONFIG_NODE, &no_nhrp_multicast_nflog_group_cmd);
/* interface specific commands */
install_node(&nhrp_interface_node);
install_element(INTERFACE_NODE, &if_no_nhrp_reg_flags_cmd);
install_element(INTERFACE_NODE, &if_nhrp_map_cmd);
install_element(INTERFACE_NODE, &if_no_nhrp_map_cmd);
+ install_element(INTERFACE_NODE, &if_nhrp_map_multicast_cmd);
+ install_element(INTERFACE_NODE, &if_no_nhrp_map_multicast_cmd);
install_element(INTERFACE_NODE, &if_nhrp_nhs_cmd);
install_element(INTERFACE_NODE, &if_no_nhrp_nhs_cmd);
}
void nhrp_zebra_init(void);
void nhrp_zebra_terminate(void);
-
+void nhrp_send_zebra_configure_arp(struct interface *ifp, int family);
+void nhrp_send_zebra_nbr(union sockunion *in,
+ union sockunion *out,
+ struct interface *ifp);
+void nhrp_send_zebra_configure_arp(struct interface *ifp,
+ int family);
struct zbuf;
struct nhrp_vc;
struct nhrp_cache;
struct list_head reglist_head;
};
+struct nhrp_multicast {
+ struct interface *ifp;
+ struct list_head list_entry;
+ afi_t afi;
+ union sockunion nbma_addr; /* IP-address */
+};
+
struct nhrp_registration {
struct list_head reglist_entry;
struct thread *t_register;
unsigned short mtu;
unsigned int holdtime;
struct list_head nhslist_head;
+ struct list_head mcastlist_head;
} afi[AFI_MAX];
};
int nhrp_interface_down(ZAPI_CALLBACK_ARGS);
int nhrp_interface_address_add(ZAPI_CALLBACK_ARGS);
int nhrp_interface_address_delete(ZAPI_CALLBACK_ARGS);
+void nhrp_neighbor_operation(ZAPI_CALLBACK_ARGS);
void nhrp_interface_notify_add(struct interface *ifp, struct notifier_block *n,
notifier_fn_t fn);
void *ctx);
void nhrp_nhs_interface_del(struct interface *ifp);
+int nhrp_multicast_add(struct interface *ifp, afi_t afi,
+ union sockunion *nbma_addr);
+int nhrp_multicast_del(struct interface *ifp, afi_t afi,
+ union sockunion *nbma_addr);
+void nhrp_multicast_interface_del(struct interface *ifp);
+void nhrp_multicast_foreach(struct interface *ifp, afi_t afi,
+ void (*cb)(struct nhrp_multicast *, void *),
+ void *ctx);
+void netlink_mcast_set_nflog_group(int nlgroup);
+
void nhrp_route_update_nhrp(const struct prefix *p, struct interface *ifp);
void nhrp_route_announce(int add, enum nhrp_cache_type type,
const struct prefix *p, struct interface *ifp,
int os_socket(void);
int os_sendmsg(const uint8_t *buf, size_t len, int ifindex, const uint8_t *addr,
- size_t addrlen);
+ size_t addrlen, uint16_t protocol);
int os_recvmsg(uint8_t *buf, size_t *len, int *ifindex, uint8_t *addr,
size_t *addrlen);
int os_configure_dmvpn(unsigned int ifindex, const char *ifname, int af);
nhrpd/nhrp_nhs.c \
nhrpd/nhrp_packet.c \
nhrpd/nhrp_peer.c \
+ nhrpd/nhrp_multicast.c \
nhrpd/nhrp_route.c \
nhrpd/nhrp_shortcut.c \
nhrpd/nhrp_vc.c \
vici_submit(vici, obuf);
}
+static bool vici_charon_filepath_done;
+static bool vici_charon_not_found;
+
+static char *vici_get_charon_filepath(void)
+{
+ static char buff[1200];
+ FILE *fp;
+ char *ptr;
+ char line[1024];
+
+ if (vici_charon_filepath_done)
+ return (char *)buff;
+ fp = popen("ipsec --piddir", "r");
+ if (!fp) {
+ if (!vici_charon_not_found) {
+ flog_err(EC_NHRP_SWAN,
+ "VICI: Failed to retrieve charon file path");
+ vici_charon_not_found = true;
+ }
+ return NULL;
+ }
+ /* last line of output is used to get vici path */
+ while (fgets(line, sizeof(line), fp) != NULL) {
+ ptr = strchr(line, '\n');
+ if (ptr)
+ *ptr = '\0';
+ snprintf(buff, sizeof(buff), "%s/charon.vici", line);
+ }
+ pclose(fp);
+ vici_charon_filepath_done = true;
+ return buff;
+}
+
static int vici_reconnect(struct thread *t)
{
struct vici_conn *vici = THREAD_ARG(t);
int fd;
+ char *file_path;
vici->t_reconnect = NULL;
if (vici->fd >= 0)
return 0;
fd = sock_open_unix(VICI_SOCKET);
+ if (fd < 0) {
+ file_path = vici_get_charon_filepath();
+ if (file_path)
+ fd = sock_open_unix(file_path);
+ }
if (fd < 0) {
debugf(NHRP_DEBUG_VICI,
"%s: failure connecting VICI socket: %s", __func__,
{
struct zbuf *zb;
- zb = XMALLOC(MTYPE_ZBUF_DATA, sizeof(*zb) + size);
+ zb = XCALLOC(MTYPE_ZBUF_DATA, sizeof(*zb) + size);
zbuf_init(zb, zb + 1, size, 0);
zb->allocated = 1;
/* Verify Area */
if (oi->area == NULL) {
vty_out(vty, "%s not attached to area %s\n",
- oi->interface->name, oi->area->name);
+ oi->interface->name, argv[idx_ipv4]->arg);
return CMD_SUCCESS;
}
+++ /dev/null
-!
-! Zebra configuration saved from vty
-! 2003/11/28 00:49:49
-!
-hostname ospf6d@plant
-password zebra
-log stdout
-service advanced-vty
-!
-debug ospf6 neighbor state
-!
-interface fxp0
- ipv6 ospf6 cost 1
- ipv6 ospf6 hello-interval 10
- ipv6 ospf6 dead-interval 40
- ipv6 ospf6 retransmit-interval 5
- ipv6 ospf6 priority 0
- ipv6 ospf6 transmit-delay 1
- ipv6 ospf6 instance-id 0
-!
-interface lo0
- ipv6 ospf6 cost 1
- ipv6 ospf6 hello-interval 10
- ipv6 ospf6 dead-interval 40
- ipv6 ospf6 retransmit-interval 5
- ipv6 ospf6 priority 1
- ipv6 ospf6 transmit-delay 1
- ipv6 ospf6 instance-id 0
-!
-router ospf6
- router-id 255.1.1.1
- redistribute static route-map static-ospf6
- interface fxp0 area 0.0.0.0
-!
-access-list access4 permit 127.0.0.1/32
-!
-ipv6 access-list access6 permit 3ffe:501::/32
-ipv6 access-list access6 permit 2001:200::/48
-ipv6 access-list access6 permit ::1/128
-!
-ipv6 prefix-list test-prefix seq 1000 deny any
-!
-route-map static-ospf6 permit 10
- match ipv6 address prefix-list test-prefix
- set metric-type type-2
- set metric 2000
-!
-line vty
- access-class access4
- ipv6 access-class access6
- exec-timeout 0 0
-!
if OSPF6D
noinst_LIBRARIES += ospf6d/libospf6.a
sbin_PROGRAMS += ospf6d/ospf6d
-dist_examples_DATA += ospf6d/ospf6d.conf.sample
vtysh_scan += \
ospf6d/ospf6_abr.c \
ospf6d/ospf6_asbr.c \
/* Making formatted timer strings. */
#define MINUTE_IN_SECONDS 60
#define HOUR_IN_SECONDS (60*MINUTE_IN_SECONDS)
-#define DAY_IN_SECONDS (24*HOUR_IN_SECONDS)
-#define WEEK_IN_SECONDS (7*DAY_IN_SECONDS)
+
unsigned long w, d, h, m, ms, us;
if (!t)
ms %= 1000;
}
- if (t->tv_sec > WEEK_IN_SECONDS) {
- w = t->tv_sec / WEEK_IN_SECONDS;
- t->tv_sec -= w * WEEK_IN_SECONDS;
+ if (t->tv_sec > ONE_WEEK_SECOND) {
+ w = t->tv_sec / ONE_WEEK_SECOND;
+ t->tv_sec -= w * ONE_WEEK_SECOND;
}
- if (t->tv_sec > DAY_IN_SECONDS) {
- d = t->tv_sec / DAY_IN_SECONDS;
- t->tv_sec -= d * DAY_IN_SECONDS;
+ if (t->tv_sec > ONE_DAY_SECOND) {
+ d = t->tv_sec / ONE_DAY_SECOND;
+ t->tv_sec -= d * ONE_DAY_SECOND;
}
if (t->tv_sec >= HOUR_IN_SECONDS) {
snprintf(buf, size, "%luh%02lum%02lds", h, m, (long)t->tv_sec);
else if (m)
snprintf(buf, size, "%lum%02lds", m, (long)t->tv_sec);
- else if (ms)
+ else if (t->tv_sec > 0 || ms > 0)
snprintf(buf, size, "%ld.%03lus", (long)t->tv_sec, ms);
else
snprintf(buf, size, "%ld usecs", (long)t->tv_usec);
oip->network_lsa_seqnum = htonl(OSPF_INITIAL_SEQUENCE_NUMBER);
oip->is_v_wait_set = false;
+ oip->ptp_dmvpn = 0;
+
return oip;
}
/* MPLS LDP-IGP Sync configuration */
struct ldp_sync_info *ldp_sync_info;
+
+ /* point-to-point DMVPN configuration */
+ uint8_t ptp_dmvpn;
};
enum { MEMBER_ALLROUTERS = 0,
/* OSPF Network Type. */
uint8_t type;
+ /* point-to-point DMVPN configuration */
+ uint8_t ptp_dmvpn;
+
/* State of Interface State Machine. */
uint8_t state;
}
/* Describe Point-to-Point link (Section 12.4.1.1). */
+
+/* Note: If the interface is configured as point-to-point dmvpn then the other
+ * end of link is dmvpn hub with point-to-multipoint ospf network type. The
+ * hub then expects this router to populate the stub network and also Link Data
+ * Field set to IP Address and not MIB-II ifIndex
+ */
static int lsa_link_ptop_set(struct stream **s, struct ospf_interface *oi)
{
int links = 0;
if ((nbr = ospf_nbr_lookup_ptop(oi)))
if (nbr->state == NSM_Full) {
if (CHECK_FLAG(oi->connected->flags,
- ZEBRA_IFA_UNNUMBERED)) {
+ ZEBRA_IFA_UNNUMBERED)
+ && !oi->ptp_dmvpn) {
/* For unnumbered point-to-point networks, the
Link Data field
should specify the interface's MIB-II ifIndex
}
/* no need for a stub link for unnumbered interfaces */
- if (!CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED)) {
+ if (oi->ptp_dmvpn
+ || !CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED)) {
/* Regardless of the state of the neighboring router, we must
add a Type 3 link (stub network).
N.B. Options 1 & 2 share basically the same logic. */
&iph.ip_dst, iph.ip_id, iph.ip_off,
iph.ip_len, oi->ifp->name, oi->ifp->mtu);
- if (ret < 0)
+ /* sendmsg will return EPERM if firewall is blocking sending.
+ * This is a normal situation when 'ip nhrp map multicast xxx'
+ * is being used to send multicast packets to DMVPN peers. In
+ * that case the original message is blocked with iptables rule
+ * causing the EPERM result
+ */
+ if (ret < 0 && errno != EPERM)
flog_err(
EC_LIB_SOCKET,
"*** sendmsg in ospf_write failed to %pI4, id %d, off %d, len %d, interface %s, mtu %u: %s",
/* Compare network mask. */
/* Checking is ignored for Point-to-Point and Virtual link. */
+ /* Checking is also ignored for Point-to-Multipoint with /32 prefix */
if (oi->type != OSPF_IFTYPE_POINTOPOINT
- && oi->type != OSPF_IFTYPE_VIRTUALLINK)
+ && oi->type != OSPF_IFTYPE_VIRTUALLINK
+ && !(oi->type == OSPF_IFTYPE_POINTOMULTIPOINT
+ && oi->address->prefixlen == IPV4_MAX_BITLEN))
if (oi->address->prefixlen != p.prefixlen) {
flog_warn(
EC_OSPF_PACKET,
|| oi->type == OSPF_IFTYPE_VIRTUALLINK)
return 1;
+ /* Ignore mask check for max prefix length (32) */
+ if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT
+ && oi->address->prefixlen == IPV4_MAX_BITLEN)
+ return 1;
+
masklen2ip(oi->address->prefixlen, &mask);
me.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr;
* somehow.
*/
if (area->ospf->ti_lfa_enabled
- || (oi && oi->type == OSPF_IFTYPE_POINTOPOINT)) {
+ || (oi && oi->type == OSPF_IFTYPE_POINTOPOINT)
+ || (oi && oi->type == OSPF_IFTYPE_POINTOMULTIPOINT
+ && oi->address->prefixlen == IPV4_MAX_BITLEN)) {
struct ospf_neighbor *nbr_w = NULL;
/* Calculating node is root node, link
continue;
oi->type = IF_DEF_PARAMS(ifp)->type;
+ oi->ptp_dmvpn = IF_DEF_PARAMS(ifp)->ptp_dmvpn;
if (oi->state > ISM_Down) {
OSPF_ISM_EVENT_EXECUTE(oi, ISM_InterfaceDown);
return no_ip_ospf_hello_interval(self, vty, argc, argv);
}
-DEFUN (ip_ospf_network,
- ip_ospf_network_cmd,
- "ip ospf network <broadcast|non-broadcast|point-to-multipoint|point-to-point>",
- "IP Information\n"
- "OSPF interface commands\n"
- "Network type\n"
- "Specify OSPF broadcast multi-access network\n"
- "Specify OSPF NBMA network\n"
- "Specify OSPF point-to-multipoint network\n"
- "Specify OSPF point-to-point network\n")
+DEFUN(ip_ospf_network, ip_ospf_network_cmd,
+ "ip ospf network <broadcast|non-broadcast|point-to-multipoint|point-to-point [dmvpn]>",
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Network type\n"
+ "Specify OSPF broadcast multi-access network\n"
+ "Specify OSPF NBMA network\n"
+ "Specify OSPF point-to-multipoint network\n"
+ "Specify OSPF point-to-point network\n"
+ "Specify OSPF point-to-point DMVPN network\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
int idx = 0;
int old_type = IF_DEF_PARAMS(ifp)->type;
+ uint8_t old_ptp_dmvpn = IF_DEF_PARAMS(ifp)->ptp_dmvpn;
struct route_node *rn;
if (old_type == OSPF_IFTYPE_LOOPBACK) {
return CMD_WARNING_CONFIG_FAILED;
}
+ IF_DEF_PARAMS(ifp)->ptp_dmvpn = 0;
+
if (argv_find(argv, argc, "broadcast", &idx))
IF_DEF_PARAMS(ifp)->type = OSPF_IFTYPE_BROADCAST;
else if (argv_find(argv, argc, "non-broadcast", &idx))
IF_DEF_PARAMS(ifp)->type = OSPF_IFTYPE_NBMA;
else if (argv_find(argv, argc, "point-to-multipoint", &idx))
IF_DEF_PARAMS(ifp)->type = OSPF_IFTYPE_POINTOMULTIPOINT;
- else if (argv_find(argv, argc, "point-to-point", &idx))
+ else if (argv_find(argv, argc, "point-to-point", &idx)) {
IF_DEF_PARAMS(ifp)->type = OSPF_IFTYPE_POINTOPOINT;
+ if (argv_find(argv, argc, "dmvpn", &idx))
+ IF_DEF_PARAMS(ifp)->ptp_dmvpn = 1;
+ }
- if (IF_DEF_PARAMS(ifp)->type == old_type)
+ if (IF_DEF_PARAMS(ifp)->type == old_type
+ && IF_DEF_PARAMS(ifp)->ptp_dmvpn == old_ptp_dmvpn)
return CMD_SUCCESS;
SET_IF_PARAM(IF_DEF_PARAMS(ifp), type);
struct route_node *rn;
IF_DEF_PARAMS(ifp)->type = ospf_default_iftype(ifp);
+ IF_DEF_PARAMS(ifp)->ptp_dmvpn = 0;
if (IF_DEF_PARAMS(ifp)->type == old_type)
return CMD_SUCCESS;
vty_out(vty, " ip ospf network %s",
ospf_int_type_str
[params->type]);
+ if (params->type
+ == OSPF_IFTYPE_POINTOPOINT
+ && params->ptp_dmvpn)
+ vty_out(vty, " dmvpn");
if (params != IF_DEF_PARAMS(ifp) && rn)
vty_out(vty, " %pI4",
&rn->p.u.prefix4);
/* Router Dead Interval print. */
if (OSPF_IF_PARAM_CONFIGURED(params, v_wait)
+ && params->is_v_wait_set
&& params->v_wait
!= OSPF_ROUTER_DEAD_INTERVAL_DEFAULT) {
vty_out(vty, " ip ospf dead-interval ");
/* If network type is specified previously,
skip network type setting. */
oi->type = IF_DEF_PARAMS(co->ifp)->type;
+ oi->ptp_dmvpn = IF_DEF_PARAMS(co->ifp)->ptp_dmvpn;
/* Add pseudo neighbor. */
ospf_nbr_self_reset(oi, oi->ospf->router_id);
+++ /dev/null
-! -*- ospf -*-
-!
-! OSPFd sample configuration file
-!
-!
-hostname ospfd
-password zebra
-!enable password please-set-at-here
-!
-!router ospf
-! network 192.168.1.0/24 area 0
-!
-log stdout
if OSPFD
noinst_LIBRARIES += ospfd/libfrrospf.a
sbin_PROGRAMS += ospfd/ospfd
-dist_examples_DATA += ospfd/ospfd.conf.sample
vtysh_scan += \
ospfd/ospf_bfd.c \
ospfd/ospf_dump.c \
+++ /dev/null
-! Default pathd configuration sample
-!
-password frr
-log stdout
-
-segment-routing
- traffic-eng
- segment-list test1
- index 10 mpls label 123
- index 20 mpls label 456
- !
- segment-list test2
- index 10 mpls label 321
- index 20 mpls label 654
- !
- policy color 1 endpoint 1.1.1.1
- name one
- binding-sid 100
- candidate-path preference 100 name test1 explicit segment-list test1
- candidate-path preference 200 name test2 explicit segment-list test2
- !
- policy color 2 endpoint 2.2.2.2
- name two
- binding-sid 101
- candidate-path preference 100 name def explicit segment-list test2
- candidate-path preference 200 name dyn dynamic
- bandwidth 12345
- metric bound abc 16 required
- metric te 10
- !
- !
- pcep
- pcc-peer PCE1
- address ip 127.0.0.1
- sr-draft07
- !
- pcc
- peer PCE1
- !
- !
-!
if PATHD
noinst_LIBRARIES += pathd/libpath.a
sbin_PROGRAMS += pathd/pathd
-dist_examples_DATA += pathd/pathd.conf.sample
-vtysh_scan += $(top_srcdir)/pathd/path_cli.c
+vtysh_scan += pathd/path_cli.c
vtysh_daemons += pathd
# TODO add man page
#man8 += $(MANBUILD)/pathd.8
if PATHD_PCEP
-vtysh_scan += $(top_srcdir)/pathd/path_pcep_cli.c
+vtysh_scan += pathd/path_pcep_cli.c
module_LTLIBRARIES += pathd/pathd_pcep.la
endif
+++ /dev/null
-! Sample pbrd configuration file
-!
-! A quick example of what a pbr configuration might look like
-!
-!
-log stdout
-!
-! nexthop-group TEST
-! nexthop 4.5.6.7
-! nexthop 5.6.7.8
-! !
-! pbr-map BLUE seq 100
-! match dst-ip 9.9.9.0/24
-! match src-ip 10.10.10.0/24
-! set nexthop-group TEST
-! !
-! int swp1
-! pbr-policy BLUE
-!
if PBRD
noinst_LIBRARIES += pbrd/libpbr.a
sbin_PROGRAMS += pbrd/pbrd
-dist_examples_DATA += pbrd/pbrd.conf.sample
vtysh_scan += \
pbrd/pbr_vty.c \
pbrd/pbr_debug.c \
+++ /dev/null
-!
-! pimd sample configuration file
-!
-hostname quagga-pimd-router
-password zebra
-!enable password zebra
-!
-!log file pimd.log
-log stdout
-!
-line vty
- exec-timeout 60
-!
-!debug igmp
-!debug pim
-!debug pim zebra
-!
-ip multicast-routing
-!
-! ! You may want to enable ssmpingd for troubleshooting
-! ! See http://www.venaas.no/multicast/ssmping/
-! !
-! ip ssmpingd 1.1.1.1
-! ip ssmpingd 2.2.2.2
-!
-! ! HINTS:
-! ! - Enable "ip pim ssm" on the interface directly attached to the
-! ! multicast source host (if this is the first-hop router)
-! ! - Enable "ip pim ssm" on pim-routers-facing interfaces
-! ! - Enable "ip igmp" on IGMPv3-hosts-facing interfaces
-! ! - In order to inject IGMPv3 local membership information in the
-! ! PIM protocol state, enable both "ip pim ssm" and "ip igmp" on
-! ! the same interface; otherwise PIM won't advertise
-! ! IGMPv3-learned membership to other PIM routers
-!
-interface eth0
- ip pim ssm
- ip igmp
-
-! -x-
sbin_PROGRAMS += pimd/pimd
bin_PROGRAMS += pimd/mtracebis
noinst_PROGRAMS += pimd/test_igmpv3_join
-dist_examples_DATA += pimd/pimd.conf.sample
vtysh_scan += pimd/pim_cmd.c
vtysh_daemons += pimd
man8 += $(MANBUILD)/frr-pimd.8
--- /dev/null
+#!/usr/bin/env python3
+#
+# Quick demo program that checks whether files define commands that aren't
+# in vtysh. Execute after building.
+#
+# This is free and unencumbered software released into the public domain.
+#
+# Anyone is free to copy, modify, publish, use, compile, sell, or
+# distribute this software, either in source code form or as a compiled
+# binary, for any purpose, commercial or non-commercial, and by any
+# means.
+#
+# In jurisdictions that recognize copyright laws, the author or authors
+# of this software dedicate any and all copyright interest in the
+# software to the public domain. We make this dedication for the benefit
+# of the public at large and to the detriment of our heirs and
+# successors. We intend this dedication to be an overt act of
+# relinquishment in perpetuity of all present and future rights to this
+# software under copyright law.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+# For more information, please refer to <http://unlicense.org/>
+
+import os
+import json
+import subprocess
+
+os.chdir(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+
+with open("frr.xref", "r") as fd:
+ data = json.load(fd)
+
+vtysh_scan, _ = subprocess.Popen(
+ ["make", "var-vtysh_scan"], stdout=subprocess.PIPE
+).communicate()
+vtysh_scan = set(vtysh_scan.decode("US-ASCII").split())
+
+check = set()
+vtysh = {}
+
+for cmd, defs in data["cli"].items():
+ for binary, clidef in defs.items():
+ if clidef["defun"]["file"].startswith("vtysh/"):
+ vtysh[clidef["string"]] = clidef
+
+for cmd, defs in data["cli"].items():
+ for binary, clidef in defs.items():
+ if clidef["defun"]["file"].startswith("vtysh/"):
+ continue
+
+ if clidef["defun"]["file"] not in vtysh_scan:
+ vtysh_def = vtysh.get(clidef["string"])
+ if vtysh_def is not None:
+ print(
+ "\033[33m%s defines %s, has a custom define in vtysh %s\033[m"
+ % (clidef["defun"]["file"], cmd, vtysh_def["defun"]["file"])
+ )
+ else:
+ print(
+ "\033[31m%s defines %s, not in vtysh_scan\033[m"
+ % (clidef["defun"]["file"], cmd)
+ )
+ check.add(clidef["defun"]["file"])
+
+print("\nfiles to check:\n\t" + " ".join(sorted(check)))
%endif
install %{zeb_src}/tools/etc/frr/daemons %{buildroot}%{_sysconfdir}/frr
+install %{zeb_src}/tools/etc/frr/frr.conf %{buildroot}%{_sysconfdir}/frr
install -m644 %{zeb_rh_src}/frr.pam %{buildroot}%{_sysconfdir}/pam.d/frr
install -m644 %{zeb_rh_src}/frr.logrotate %{buildroot}%{_sysconfdir}/logrotate.d/frr
install -d -m750 %{buildroot}%{rundir}
%files
-%doc */*.sample* COPYING
+%doc COPYING
%doc doc/mpls
%doc README.md
/usr/share/yang/*.yang
%dir %attr(750,root,root) %{_localstatedir}/log/frr
%dir %attr(750,root,root) %{rundir}
%endif
-%if 0%{?vty_group:1}
- %attr(750,%{frr_user},%{vty_group}) %{configdir}/vtysh.conf.sample
-%endif
%{_infodir}/frr.info.gz
%{_mandir}/man*/*
%{_sbindir}/zebra
+++ /dev/null
-! -*- rip -*-
-!
-! RIPd sample configuration file
-!
-hostname ripd
-password zebra
-!
-! debug rip events
-! debug rip packet
-!
-router rip
-! network 11.0.0.0/8
-! network eth0
-! route 10.0.0.0/8
-! distribute-list private-only in eth0
-!
-!access-list private-only permit 10.0.0.0/8
-!access-list private-only deny any
-!
-!log file ripd.log
-!
-log stdout
if RIPD
noinst_LIBRARIES += ripd/librip.a
sbin_PROGRAMS += ripd/ripd
-dist_examples_DATA += ripd/ripd.conf.sample
vtysh_scan += \
ripd/rip_cli.c \
ripd/rip_debug.c \
+++ /dev/null
-! -*- rip -*-
-!
-! RIPngd sample configuration file
-!
-hostname ripngd
-password zebra
-!
-! debug ripng events
-! debug ripng packet
-!
-!
-router ripng
-! network sit1
-! route 3ffe:506::0/32
-! distribute-list local-only out sit1
-!
-!ipv6 access-list local-only permit 3ffe:506::0/32
-!ipv6 access-list local-only deny any
-!
-log stdout
nodist_ripngd_ripngd_SOURCES = \
yang/frr-ripngd.yang.c \
# end
-
-dist_examples_DATA += ripngd/ripngd.conf.sample
+++ /dev/null
-! Default sharpd configuration sample
-!
-! There are no `default` configuration commands for sharpd
-! all commands are at the view or enable level.
-!
-log stdout
if SHARPD
noinst_LIBRARIES += sharpd/libsharp.a
sbin_PROGRAMS += sharpd/sharpd
-dist_examples_DATA += sharpd/sharpd.conf.sample
vtysh_scan += sharpd/sharp_vty.c
vtysh_daemons += sharpd
man8 += $(MANBUILD)/frr-sharpd.8
+++ /dev/null
-! Default staticd configuration sample
-!
-log stdout
-!
-! ip route 4.5.6.7/32 10.10.10.10
if STATICD
noinst_LIBRARIES += staticd/libstatic.a
sbin_PROGRAMS += staticd/staticd
-dist_examples_DATA += staticd/staticd.conf.sample
vtysh_scan += staticd/static_vty.c
vtysh_daemons += staticd
man8 += $(MANBUILD)/frr-staticd.8
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
+RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
*> 192.168.0.0 0.0.0.0 0 32768 i
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
+RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
*> 192.168.0.0/24 0.0.0.0 0 32768 i
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
+RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
*> 192.168.0.0/24 0.0.0.0 0 32768 i
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
+RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
*> fc00::/64 :: 0 32768 i
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
+RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
*> fc00::/64 :: 0 32768 i
return next_hop
-def test_BGP_GR_TC_46_p1(request):
- """
- Test Objective : transition from Peer-level helper to Global Restarting
- Global Mode : GR Restarting
- PerPeer Mode : GR Helper
- GR Mode effective : GR Helper
-
- """
-
- tgen = get_topogen()
- tc_name = request.node.name
- write_test_header(tc_name)
-
- # Check router status
- check_router_status(tgen)
-
- # Don't run this test if we have any failure.
- if tgen.routers_have_failure():
- pytest.skip(tgen.errors)
-
- # Creating configuration from JSON
- reset_config_on_routers(tgen)
-
- step(
- "Configure R1 and R2 as GR restarting node in global"
- " and helper in per-Peer-level"
- )
-
- input_dict = {
- "r1": {
- "bgp": {
- "graceful-restart": {
- "graceful-restart": True,
- },
- "address_family": {
- "ipv4": {
- "unicast": {
- "neighbor": {
- "r2": {
- "dest_link": {
- "r1-link1": {"graceful-restart-helper": True}
- }
- }
- }
- }
- },
- "ipv6": {
- "unicast": {
- "neighbor": {
- "r2": {
- "dest_link": {
- "r1-link1": {"graceful-restart-helper": True}
- }
- }
- }
- }
- },
- },
- }
- },
- "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}},
- }
-
- configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2")
-
- step("Verify on R2 that R1 advertises GR capabilities as a restarting node")
-
- for addr_type in ADDR_TYPES:
- result = verify_graceful_restart(
- tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
- )
- assert result is True, "Testcase {} : Failed \n Error {}".format(
- tc_name, result
- )
-
- for addr_type in ADDR_TYPES:
- protocol = "bgp"
- next_hop = next_hop_per_address_family(
- tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1
- )
- input_topo = {"r1": topo["routers"]["r1"]}
- result = verify_rib(tgen, addr_type, "r2", input_topo, next_hop, protocol)
- assert result is True, "Testcase {} : Failed \n Error {}".format(
- tc_name, result
- )
-
- for addr_type in ADDR_TYPES:
- next_hop = next_hop_per_address_family(
- tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2
- )
- input_topo = {"r2": topo["routers"]["r2"]}
- result = verify_bgp_rib(tgen, addr_type, "r1", input_topo, next_hop)
- assert result is True, "Testcase {} : Failed \n Error {}".format(
- tc_name, result
- )
-
- result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol)
- assert result is True, "Testcase {} : Failed \n Error {}".format(
- tc_name, result
- )
-
- step("Kill BGP on R2")
-
- kill_router_daemons(tgen, "r2", ["bgpd"])
-
- step(
- "Verify that R1 keeps the stale entries in RIB & FIB and R2 keeps stale entries in FIB using"
- )
-
- for addr_type in ADDR_TYPES:
- protocol = "bgp"
- next_hop = next_hop_per_address_family(
- tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1
- )
- input_topo = {"r1": topo["routers"]["r1"]}
- result = verify_rib(tgen, addr_type, "r2", input_topo, next_hop, protocol)
- assert result is True, "Testcase {} : Failed \n Error {}".format(
- tc_name, result
- )
-
- for addr_type in ADDR_TYPES:
- next_hop = next_hop_per_address_family(
- tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2
- )
- input_topo = {"r2": topo["routers"]["r2"]}
- result = verify_bgp_rib(tgen, addr_type, "r1", input_topo, next_hop)
- assert result is True, "Testcase {} : Failed \n Error {}".format(
- tc_name, result
- )
-
- result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol)
- assert result is True, "Testcase {} : Failed \n Error {}".format(
- tc_name, result
- )
-
- step(
- "Bring up BGP on R1 and remove Peer-level GR config"
- " from R1 following by a session reset"
- )
-
- start_router_daemons(tgen, "r2", ["bgpd"])
-
- input_dict = {
- "r1": {
- "bgp": {
- "address_family": {
- "ipv4": {
- "unicast": {
- "neighbor": {
- "r2": {
- "dest_link": {
- "r1-link1": {"graceful-restart-helper": False}
- }
- }
- }
- }
- },
- "ipv6": {
- "unicast": {
- "neighbor": {
- "r2": {
- "dest_link": {
- "r1-link1": {"graceful-restart-helper": False}
- }
- }
- }
- }
- },
- }
- }
- }
- }
-
- result = create_router_bgp(tgen, topo, input_dict)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
-
- step("Verify on R2 that R1 advertises GR capabilities as a restarting node")
-
- input_dict = {
- "r1": {"bgp": {"graceful-restart": {"graceful-restart": True}}},
- "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}},
- }
-
- for addr_type in ADDR_TYPES:
- result = verify_graceful_restart(
- tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
- )
- assert result is True, "Testcase {} : Failed \n Error {}".format(
- tc_name, result
- )
-
- for addr_type in ADDR_TYPES:
- protocol = "bgp"
- next_hop = next_hop_per_address_family(
- tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2
- )
- input_topo = {"r2": topo["routers"]["r2"]}
- result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol)
- assert (
- result is True
- ), "Testcase {} : Failed \n Routes are still present \n Error {}".format(
- tc_name, result
- )
-
- for addr_type in ADDR_TYPES:
- next_hop = next_hop_per_address_family(
- tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1
- )
- input_topo = {"r1": topo["routers"]["r1"]}
- result = verify_bgp_rib(tgen, addr_type, "r2", input_topo, next_hop)
- assert result is True, "Testcase {} : Failed \n Error {}".format(
- tc_name, result
- )
-
- result = verify_rib(tgen, addr_type, "r2", input_topo, next_hop, protocol)
- assert (
- result is True
- ), "Testcase {} : Failed \n Routes are still present \n Error {}".format(
- tc_name, result
- )
-
- step("Kill BGP on R1")
-
- kill_router_daemons(tgen, "r1", ["bgpd"])
-
- step(
- "Verify that R1 keeps the stale entries in FIB command and R2 keeps stale entries in RIB & FIB"
- )
-
- for addr_type in ADDR_TYPES:
- protocol = "bgp"
- next_hop = next_hop_per_address_family(
- tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2
- )
- input_topo = {"r2": topo["routers"]["r2"]}
- result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol)
- assert (
- result is True
- ), "Testcase {} : Failed \n Routes are still present \n Error {}".format(
- tc_name, result
- )
-
- for addr_type in ADDR_TYPES:
- next_hop = next_hop_per_address_family(
- tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1
- )
- input_topo = {"r1": topo["routers"]["r1"]}
- result = verify_bgp_rib(tgen, addr_type, "r2", input_topo, next_hop)
- assert result is True, "Testcase {} : Failed \n Error {}".format(
- tc_name, result
- )
-
- result = verify_rib(tgen, addr_type, "r2", input_topo, next_hop, protocol)
- assert (
- result is True
- ), "Testcase {} : Failed \n Routes are still present \n Error {}".format(
- tc_name, result
- )
-
- step("Start BGP on R1")
-
- start_router_daemons(tgen, "r1", ["bgpd"])
-
- write_test_footer(tc_name)
-
-
def BGP_GR_TC_50_p1(request):
"""
Test Objective : Transition from Peer-level helper to Global inherit helper
write_test_footer(tc_name)
-def test_BGP_GR_TC_17_p1(request):
- """
- Test Objective : Verify that only GR helper routers keep the stale
- route entries, not any GR disabled router.
- """
-
- tgen = get_topogen()
- tc_name = request.node.name
- write_test_header(tc_name)
-
- # Check router status
- check_router_status(tgen)
-
- # Don't run this test if we have any failure.
- if tgen.routers_have_failure():
- pytest.skip(tgen.errors)
-
- # Creating configuration from JSON
- reset_config_on_routers(tgen)
-
- logger.info("[Phase 1] : Test Setup [Disable]R1-----R2[Restart] initialized ")
-
- # Configure graceful-restart
- input_dict = {
- "r1": {
- "bgp": {
- "graceful-restart": {
- "graceful-restart": True,
- "preserve-fw-state": True,
- },
- "address_family": {
- "ipv4": {
- "unicast": {
- "neighbor": {
- "r2": {
- "dest_link": {
- "r1-link1": {"graceful-restart-disable": True}
- }
- }
- }
- }
- },
- "ipv6": {
- "unicast": {
- "neighbor": {
- "r2": {
- "dest_link": {
- "r1-link1": {"graceful-restart-disable": True}
- }
- }
- }
- }
- },
- },
- }
- },
- "r2": {
- "bgp": {
- "address_family": {
- "ipv4": {
- "unicast": {
- "neighbor": {
- "r1": {
- "dest_link": {
- "r2-link1": {"graceful-restart": True}
- }
- }
- }
- }
- },
- "ipv6": {
- "unicast": {
- "neighbor": {
- "r1": {
- "dest_link": {
- "r2-link1": {"graceful-restart": True}
- }
- }
- }
- }
- },
- }
- }
- },
- }
-
- configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2")
-
- for addr_type in ADDR_TYPES:
- result = verify_graceful_restart(
- tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
- )
- assert result is True, "Testcase {} : Failed \n Error {}".format(
- tc_name, result
- )
-
- # Verifying BGP RIB routes
- dut = "r1"
- peer = "r2"
- next_hop = next_hop_per_address_family(
- tgen, dut, peer, addr_type, NEXT_HOP_IP_2
- )
- input_topo = {key: topo["routers"][key] for key in ["r2"]}
- result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop)
- assert result is True, "Testcase {} : Failed \n Error {}".format(
- tc_name, result
- )
-
- # Verifying RIB routes
- protocol = "bgp"
- result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
- assert result is True, "Testcase {} : Failed \n Error {}".format(
- tc_name, result
- )
-
- logger.info("[Phase 2] : R2 goes for reload ")
-
- kill_router_daemons(tgen, "r2", ["bgpd"])
-
- logger.info(
- "[Phase 3] : R2 is still down, restart time 120 sec."
- " So time verify the routes are present in BGP RIB and ZEBRA "
- )
-
- for addr_type in ADDR_TYPES:
- # Verifying BGP RIB routes
- next_hop = next_hop_per_address_family(
- tgen, dut, peer, addr_type, NEXT_HOP_IP_2
- )
- input_topo = {key: topo["routers"][key] for key in ["r2"]}
- result = verify_bgp_rib(
- tgen, addr_type, dut, input_topo, next_hop, expected=False
- )
- assert result is not True, (
- "Testcase {} : Failed \n "
- "r1: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
- )
- logger.info(" Expected behavior: {}".format(result))
-
- # Verifying RIB routes
- result = verify_rib(
- tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False
- )
- assert result is not True, (
- "Testcase {} : Failed \n "
- "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
- )
- logger.info(" Expected behavior: {}".format(result))
-
- logger.info("[Phase 5] : R2 is about to come up now ")
- start_router_daemons(tgen, "r2", ["bgpd"])
-
- logger.info("[Phase 4] : R2 is UP now, so time to collect GR stats ")
-
- for addr_type in ADDR_TYPES:
- result = verify_graceful_restart(
- tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
- )
- assert result is True, "Testcase {} : Failed \n Error {}".format(
- tc_name, result
- )
-
- result = verify_r_bit(
- tgen, topo, addr_type, input_dict, dut="r1", peer="r2", expected=False
- )
- assert (
- result is not True
- ), "Testcase {} : Failed \n " "r1: R-bit is set to True\n Error: {}".format(
- tc_name, result
- )
-
- # Verifying BGP RIB routes
- next_hop = next_hop_per_address_family(
- tgen, dut, peer, addr_type, NEXT_HOP_IP_2
- )
- input_topo = {key: topo["routers"][key] for key in ["r2"]}
- result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop)
- assert result is True, "Testcase {} : Failed \n Error {}".format(
- tc_name, result
- )
-
- # Verifying RIB routes
- result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
- assert result is True, "Testcase {} : Failed \n Error {}".format(
- tc_name, result
- )
-
- write_test_footer(tc_name)
-
-
def test_BGP_GR_TC_19_p1(request):
"""
Test Objective : Verify that GR helper routers keeps all the routes received
test_func = partial(
topotest.router_json_cmp,
router,
- "show ip route json".format(router.name),
+ "show ip route json",
expected,
)
_, result = topotest.run_and_expect(test_func, None, count=160, wait=0.5)
test_func = partial(
topotest.router_json_cmp,
router,
- "show ipv6 route json".format(router.name),
+ "show ipv6 route json",
expected,
)
_, result = topotest.run_and_expect(test_func, None, count=160, wait=0.5)
result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False)
assert (
result is not True
- ), "Testcase {} : Failed \n Expected Behaviour: Routes are rejected because"
- " nexthop-self config is deleted \n Error {}".format(tc_name, result)
+ ), "Testcase {} : Failed \n Expected Behaviour: Routes are rejected because nexthop-self config is deleted \n Error {}".format(tc_name, result)
result = verify_rib(tgen, addr_type, dut, input_dict_2, expected=False)
assert (
result is not True
- ), "Testcase {} : Failed \n Expected Behaviour: Routes are rejected because"
- " nexthop-self config is deleted \n Error {}".format(tc_name, result)
+ ), "Testcase {} : Failed \n Expected Behaviour: Routes are rejected because nexthop-self config is deleted \n Error {}".format(tc_name, result)
write_test_footer(tc_name)
result = verify_rib(tgen, addr_type, dut, denied_routes, expected=False)
assert result is not True, "Testcase {} : Failed \n"
- "Expected behaviour: Routes are denied by prefix-list \n"
- "Error {}".format(tc_name, result)
+ "{}:Expected behaviour: Routes are denied by prefix-list \nError {}".format(tc_name, result)
step(
"On router R1, configure prefix-lists to permit 2 "
)
result = verify_rib(tgen, addr_type, dut, denied_routes, expected=False)
- assert result is not True, "Testcase {} : Failed \n"
- "Expected behaviour: Routes are denied by prefix-list \n"
- "Error {}".format(tc_name, result)
+ assert result is not True, "Testcase {} : Failed \nExpected behaviour: Routes are denied by prefix-list \nError {}".format(tc_name, result)
write_test_footer(tc_name)
result = verify_rib(tgen, addr_type, dut, input_dict_2, expected=False)
assert (
result is not True
- ), "Testcase {} : Failed \n Expected Behavior: Routes are denied \n"
- "Error {}".format(tc_name, result)
+ ), "Testcase {} : Failed \n Expected Behavior: Routes are denied \nError {}".format(tc_name, result)
write_test_footer(tc_name)
result = verify_rib(tgen, addr_type, dut, input_dict_2, expected=False)
assert (
result is not True
- ), "Testcase {} : Failed \n Expected Behavior: Routes are denied \n"
- "Error {}".format(tc_name, result)
+ ), "Testcase {} : Failed \n Expected Behavior: Routes are denied \nError {}".format(tc_name, result)
write_test_footer(tc_name)
sleep(HOLDDOWNTIMER + 1)
result = verify_bgp_convergence(tgen, topo, expected=False)
- assert result is not True, "Testcase {} : Failed \n "
- "Expected Behaviour: BGP will not be converged \n "
- "Error {}".format(tc_name, result)
+ assert result is not True, "Testcase {} : Failed \nExpected Behaviour: BGP will not be converged \nError {}".format(tc_name, result)
for addr_type in ADDR_TYPES:
dut = "r2"
}
result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False)
- assert result is not True, "Testcase {} : Failed \n "
- " Expected Behaviour: Routes are flushed out \n "
- "Error {}".format(tc_name, result)
+ assert result is not True, "Testcase {} : Failed \nExpected Behaviour: Routes are flushed out \nError {}".format(tc_name, result)
result = verify_rib(tgen, addr_type, dut, input_dict_2, expected=False)
- assert result is not True, "Testcase {} : Failed \n "
- " Expected Behaviour: Routes are flushed out \n "
- "Error {}".format(tc_name, result)
+ assert result is not True, "Testcase {} : Failed \nExpected Behaviour: Routes are flushed out \nError {}".format(tc_name, result)
step("Bring up connecting interface between R1<<>>R2 on R1.")
for intf in interfaces:
result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False)
assert (
result is not True
- ), "Testcase {} : Failed \n Expected Behaviour: Routes are"
- " cleaned \n Error {}".format(tc_name, result)
+ ), "Testcase {} : Failed \n Expected Behaviour: Routes are cleaned \n Error {}".format(tc_name, result)
step("Add/reconfigure the same VRF instance again")
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
result = verify_bgp_convergence(tgen, topo)
- assert result is True, "Testcase () :Failed\n Error {}".format(tc_name, result)
+ assert result is True, "Testcase {} :Failed\n Error {}".format(tc_name, result)
step("Kill BGPd daemon on R1.")
kill_router_daemons(tgen, "r1", ["bgpd"])
result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False)
assert (
result is not True
- ), "Testcase {} :Failed \n Expected Behaviour: Routes are not"
- " present \n Error {}".format(tc_name, result)
+ ), "Testcase {} :Failed \n Expected Behaviour: Routes are not present \n Error {}".format(tc_name, result)
result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False)
assert (
result is not True
- ), "Testcase {} :Failed \n Expected Behaviour: Routes are not"
- " present \n Error {}".format(tc_name, result)
+ ), "Testcase {} :Failed \n Expected Behaviour: Routes are not present \n Error {}".format(tc_name, result)
for addr_type in ADDR_TYPES:
dut = "blue2"
result = verify_rib(tgen, addr_type, dut, input_dict_2, expected=False)
assert result is not True, (
- "Testcase {} :Failed \n Expected Behaviour: Routes are not"
- " present \n Error {}".format(tc_name, result)
+ "Testcase {} :Failed \n Expected Behaviour: Routes are not present \n Error {}".format(tc_name, result)
)
result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2, expected=False)
assert result is not True, (
- "Testcase {} :Failed \n Expected Behaviour: Routes are not"
- " present \n Error {}".format(tc_name, result)
+ "Testcase {} :Failed \n Expected Behaviour: Routes are not present \n Error {}".format(tc_name, result)
)
step("Create 2 new VRFs PINK_A and GREY_A IN R3")
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
+RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
* 10.0.1.0/24 172.16.1.5 0 65005 i
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
+RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
* 10.0.1.0/24 172.16.1.5 0 65005 i
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
+RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
* 10.0.1.0/24 172.16.1.4 0 65004 i
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
+RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
* 10.0.1.0/24 172.16.1.4 0 65004 i
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
+RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
* 10.0.1.0/24 172.16.1.8 0 65008 i
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
+RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
* 10.0.1.0/24 172.16.1.8 0 65008 i
"""
+ tc_name = request.node.name
logger.info("Remove prefer-global rmap applied on neighbors")
input_dict = {
"r1": {
command = "show bgp"
- sleep(5)
for net in network:
if vrf:
cmd = "{} vrf {} {} {} json".format(command, vrf, addr_type, net)
--- /dev/null
+{
+ "attr":{
+ "entriesCount":2
+ },
+ "table":[
+ {
+ "interface":"r1-gre0",
+ "type":"nhs",
+ "protocol":"10.255.255.2",
+ "nbma":"10.2.1.2",
+ "claimed_nbma":"10.2.1.2",
+ "used":false,
+ "timeout":true,
+ "auth":false,
+ "identity":""
+ },
+ {
+ "interface":"r1-gre0",
+ "type":"local",
+ "protocol":"10.255.255.1",
+ "nbma":"10.1.1.1",
+ "claimed_nbma":"10.1.1.1",
+ "used":false,
+ "timeout":false,
+ "auth":false,
+ "identity":"-"
+ }
+ ]
+}
--- /dev/null
+{
+ "10.255.255.2\/32":[
+ {
+ "prefix":"10.255.255.2\/32",
+ "protocol":"nhrp",
+ "vrfId":0,
+ "vrfName":"default",
+ "selected":true,
+ "destSelected":true,
+ "distance":10,
+ "metric":0,
+ "installed":true,
+ "internalNextHopNum":1,
+ "internalNextHopActiveNum":1,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"r1-gre0",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+log stdout debugging
+debug nhrp all
+interface r1-gre0
+ ip nhrp holdtime 500
+ ip nhrp shortcut
+ ip nhrp network-id 42
+ ip nhrp nhs dynamic nbma 10.2.1.2
+ ip nhrp registration no-unique
+ tunnel source r1-eth0
+exit
--- /dev/null
+interface r1-eth0
+ ip address 10.1.1.1/24
+!
+ip route 10.2.1.0/24 10.1.1.3
+interface r1-gre0
+ ip address 10.255.255.1/32
+ no link-detect
+ ipv6 nd suppress-ra
+exit
+interface r1-eth1
+ ip address 192.168.1.1/24
+!
--- /dev/null
+{
+ "attr":{
+ "entriesCount":2
+ },
+ "table":[
+ {
+ "interface":"r2-gre0",
+ "type":"local",
+ "protocol":"10.255.255.2",
+ "nbma":"10.2.1.2",
+ "claimed_nbma":"10.2.1.2",
+ "used":false,
+ "timeout":false,
+ "auth":false,
+ "identity":"-"
+ },
+ {
+ "interface":"r2-gre0",
+ "type":"dynamic",
+ "protocol":"10.255.255.1",
+ "nbma":"10.1.1.1",
+ "claimed_nbma":"10.1.1.1",
+ "used":false,
+ "timeout":true,
+ "auth":false,
+ "identity":""
+ }
+ ]
+}
--- /dev/null
+{
+ "10.255.255.1\/32":[
+ {
+ "prefix":"10.255.255.1\/32",
+ "protocol":"nhrp",
+ "vrfId":0,
+ "vrfName":"default",
+ "selected":true,
+ "destSelected":true,
+ "distance":10,
+ "metric":0,
+ "installed":true,
+ "internalNextHopNum":1,
+ "internalNextHopActiveNum":1,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"r2-gre0",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+debug nhrp all
+log stdout debugging
+nhrp nflog-group 1
+interface r2-gre0
+ ip nhrp holdtime 500
+ ip nhrp redirect
+ ip nhrp network-id 42
+ ip nhrp registration no-unique
+ tunnel source r2-eth0
+exit
--- /dev/null
+interface r2-eth0
+ ip address 10.2.1.2/24
+!
+ip route 10.1.1.0/24 10.2.1.3
+interface r2-gre0
+ ip address 10.255.255.2/32
+ no link-detect
+ ipv6 nd suppress-ra
+!
+interface r2-eth1
+ ip address 192.168.2.2/24
+!
--- /dev/null
+debug zebra kernel
+debug zebra rib
+debug zebra events
+debug zebra packet
+ip forwarding
+interface r3-eth0
+ ip address 10.1.1.3/24
+!
+interface r3-eth1
+ ip address 10.2.1.3/24
+exit
--- /dev/null
+## Color coding:
+#########################
+## Main FRR: #f08080 red
+## Switches: #d0e0d0 gray
+## RIP: #19e3d9 Cyan
+## RIPng: #fcb314 dark yellow
+## OSPFv2: #32b835 Green
+## OSPFv3: #19e3d9 Cyan
+## ISIS IPv4 #fcb314 dark yellow
+## ISIS IPv6 #9a81ec purple
+## BGP IPv4 #eee3d3 beige
+## BGP IPv6 #fdff00 yellow
+##### Colors (see http://www.color-hex.com/)
+
+graph template {
+ label="bfd-topo2";
+
+ # Routers
+ r1 [
+ shape=doubleoctagon,
+ label="r1",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r2 [
+ shape=doubleoctagon
+ label="r2",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r3 [
+ shape=doubleoctagon
+ label="r3",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r4 [
+ shape=doubleoctagon
+ label="r4",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+
+ # Switches
+ sw1 [
+ shape=oval,
+ label="sw1\n2001:db8:1::/64",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ sw2 [
+ shape=oval,
+ label="sw2\n10.0.3.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ sw3 [
+ shape=oval,
+ label="sw3\n2001:db8:4::/64",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+
+ # Connections
+ r1 -- sw1 [label="eth0"];
+ r2 -- sw1 [label="eth0"];
+
+ r2 -- sw2 [label="eth1"];
+ r3 -- sw2 [label="eth0"];
+
+ r2 -- sw3 [label="eth2"];
+ r4 -- sw3 [label="eth0"];
+}
--- /dev/null
+#!/usr/bin/env python
+
+#
+# test_nhrp_topo.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2019 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_nhrp_topo.py: Test the FRR/Quagga NHRP daemon
+"""
+
+import os
+import sys
+import json
+from functools import partial
+import pytest
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../'))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+# Required to instantiate the topology builder class.
+from mininet.topo import Topo
+
+
+class NHRPTopo(Topo):
+ "Test topology builder"
+ def build(self, *_args, **_opts):
+ "Build function"
+ tgen = get_topogen(self)
+
+ # Create 3 routers.
+ for routern in range(1, 4):
+ tgen.add_router('r{}'.format(routern))
+
+ switch = tgen.add_switch('s1')
+ switch.add_link(tgen.gears['r1'])
+ switch.add_link(tgen.gears['r3'])
+ switch = tgen.add_switch('s2')
+ switch.add_link(tgen.gears['r2'])
+ switch.add_link(tgen.gears['r3'])
+ switch = tgen.add_switch('s3')
+ switch.add_link(tgen.gears['r2'])
+ switch = tgen.add_switch('s4')
+ switch.add_link(tgen.gears['r1'])
+
+
+def _populate_iface():
+ tgen = get_topogen()
+ cmds_tot_hub = ['ip tunnel add {0}-gre0 mode gre ttl 64 key 42 dev {0}-eth0 local 10.2.1.{1} remote 0.0.0.0',
+ 'ip link set dev {0}-gre0 up',
+ 'echo 0 > /proc/sys/net/ipv4/ip_forward_use_pmtu',
+ 'echo 1 > /proc/sys/net/ipv6/conf/{0}-eth0/disable_ipv6',
+ 'echo 1 > /proc/sys/net/ipv6/conf/{0}-gre0/disable_ipv6']
+
+ cmds_tot = ['ip tunnel add {0}-gre0 mode gre ttl 64 key 42 dev {0}-eth0 local 10.1.1.{1} remote 0.0.0.0',
+ 'ip link set dev {0}-gre0 up',
+ 'echo 0 > /proc/sys/net/ipv4/ip_forward_use_pmtu',
+ 'echo 1 > /proc/sys/net/ipv6/conf/{0}-eth0/disable_ipv6',
+ 'echo 1 > /proc/sys/net/ipv6/conf/{0}-gre0/disable_ipv6']
+
+ for cmd in cmds_tot_hub:
+ input = cmd.format('r2', '2')
+ logger.info('input: '+cmd)
+ output = tgen.net['r2'].cmd(cmd.format('r2', '2'))
+ logger.info('output: '+output);
+
+ for cmd in cmds_tot:
+ input = cmd.format('r1', '1')
+ logger.info('input: '+cmd)
+ output = tgen.net['r1'].cmd(cmd.format('r1', '1'))
+ logger.info('output: '+output);
+
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+ tgen = Topogen(NHRPTopo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+ _populate_iface()
+
+ for rname, router in router_list.iteritems():
+ router.load_config(
+ TopoRouter.RD_ZEBRA,
+ os.path.join(CWD, '{}/zebra.conf'.format(rname)),
+ )
+ if rname in ('r1', 'r2'):
+ router.load_config(
+ TopoRouter.RD_NHRP,
+ os.path.join(CWD, '{}/nhrpd.conf'.format(rname))
+ )
+
+ # Initialize all routers.
+ logger.info('Launching BGP, NHRP')
+ for name in router_list:
+ router = tgen.gears[name]
+ router.start()
+
+
+def teardown_module(_mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_protocols_convergence():
+ """
+ Assert that all protocols have converged before checking for the NHRP
+ statuses as they depend on it.
+ """
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Check IPv4 routing tables.
+ logger.info("Checking NHRP cache and IPv4 routes for convergence")
+ router_list = tgen.routers()
+
+ for rname, router in router_list.iteritems():
+ if rname == 'r3':
+ continue
+
+ json_file = '{}/{}/nhrp4_cache.json'.format(CWD, router.name)
+ if not os.path.isfile(json_file):
+ logger.info('skipping file {}'.format(json_file))
+ continue
+
+ expected = json.loads(open(json_file).read())
+ test_func = partial(topotest.router_json_cmp,
+ router, 'show ip nhrp cache json', expected)
+ _, result = topotest.run_and_expect(test_func, None, count=40,
+ wait=0.5)
+
+ output = router.vtysh_cmd('show ip nhrp cache')
+ logger.info(output)
+
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert result is None, assertmsg
+
+ for rname, router in router_list.iteritems():
+ if rname == 'r3':
+ continue
+
+ json_file = '{}/{}/nhrp_route4.json'.format(CWD, router.name)
+ if not os.path.isfile(json_file):
+ logger.info('skipping file {}'.format(json_file))
+ continue
+
+ expected = json.loads(open(json_file).read())
+ test_func = partial(topotest.router_json_cmp,
+ router, 'show ip route nhrp json', expected)
+ _, result = topotest.run_and_expect(test_func, None, count=40,
+ wait=0.5)
+
+ output = router.vtysh_cmd('show ip route nhrp')
+ logger.info(output)
+
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert result is None, assertmsg
+
+ for rname, router in router_list.iteritems():
+ if rname == 'r3':
+ continue
+ logger.info('Dump neighbor information on {}-gre0'.format(rname))
+ output = router.run('ip neigh show')
+ logger.info(output)
+
+
+def test_nhrp_connection():
+ "Assert that the NHRP peers can find themselves."
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ pingrouter = tgen.gears['r1']
+ logger.info('Check Ping IPv4 from R1 to R2 = 10.255.255.2)')
+ output = pingrouter.run('ping 10.255.255.2 -f -c 1000')
+ logger.info(output)
+ if '1000 packets transmitted, 1000 received' not in output:
+ assertmsg = 'expected ping IPv4 from R1 to R2 should be ok'
+ assert 0, assertmsg
+ else:
+ logger.info('Check Ping IPv4 from R1 to R2 OK')
+
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip('Memory leak test/report is disabled')
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == '__main__':
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
-# default to using syslog. /etc/rsyslog.d/45-frr.conf places the log
-# in /var/log/frr/frr.log
+# default to using syslog. /etc/rsyslog.d/45-frr.conf places the log in
+# /var/log/frr/frr.log
+#
+# Note:
+# FRR's configuration shell, vtysh, dynamically edits the live, in-memory
+# configuration while FRR is running. When instructed, vtysh will persist the
+# live configuration to this file, overwriting its contents. If you want to
+# avoid this, you can edit this file manually before starting FRR, or instruct
+# vtysh to write configuration to a different file.
log syslog informational
if VRRPD
noinst_LIBRARIES += vrrpd/libvrrp.a
sbin_PROGRAMS += vrrpd/vrrpd
-# dist_examples_DATA += staticd/staticd.conf.sample
vtysh_scan += vrrpd/vrrp_vty.c
vtysh_daemons += vrrpd
man8 += $(MANBUILD)/frr-vrrpd.8
elsif ($file =~ /lib\/(filter|filter_cli)\.c$/) {
$protocol = "VTYSH_ACL";
}
- elsif ($file =~ /lib\/lib_vty\.c$/) {
+ elsif ($file =~ /lib\/(lib|log)_vty\.c$/) {
$protocol = "VTYSH_ALL";
}
elsif ($file =~ /lib\/agentx\.c$/) {
$protocol = "VTYSH_RIPD";
}
}
- elsif ($file =~ /lib\/vty\.c$/) {
+ elsif ($file =~ /lib\/resolver\.c$/) {
+ $protocol = "VTYSH_NHRPD|VTYSH_BGPD";
+ }
+ elsif ($file =~ /lib\/spf_backoff\.c$/) {
+ $protocol = "VTYSH_ISISD";
+ }
+ elsif ($file =~ /lib\/(vty|thread)\.c$/) {
$protocol = "VTYSH_ALL";
}
elsif ($file =~ /librfp\/.*\.c$/ || $file =~ /rfapi\/.*\.c$/) {
foreach (sort keys %odefun) {
my ($node, $str) = (split (/,/));
$cmd = $ocmd{$_};
- $cmd =~ s/_cmd/_cmd_vtysh/;
+ $cmd =~ s/_cmd$/_cmd_vtysh/;
printf " install_element ($node, &$cmd);\n";
}
if VTYSH
bin_PROGRAMS += vtysh/vtysh
-dist_examples_DATA += vtysh/vtysh.conf.sample
man1 += $(MANBUILD)/vtysh.1
endif
"Logging configuration for %s:\n");
}
-DEFUNSH(VTYSH_ALL, vtysh_log_stdout, vtysh_log_stdout_cmd, "log stdout",
- "Logging control\n"
- "Set stdout logging level\n")
-{
- return CMD_SUCCESS;
-}
-
-DEFUNSH(VTYSH_ALL, vtysh_log_stdout_level, vtysh_log_stdout_level_cmd,
- "log stdout <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>",
- "Logging control\n"
- "Set stdout logging level\n" LOG_LEVEL_DESC)
-{
- return CMD_SUCCESS;
-}
-
-DEFUNSH(VTYSH_ALL, no_vtysh_log_stdout, no_vtysh_log_stdout_cmd,
- "no log stdout [LEVEL]", NO_STR
- "Logging control\n"
- "Cancel logging to stdout\n"
- "Logging level\n")
-{
- return CMD_SUCCESS;
-}
-
-DEFUNSH(VTYSH_ALL, vtysh_log_file, vtysh_log_file_cmd, "log file FILENAME",
- "Logging control\n"
- "Logging to file\n"
- "Logging filename\n")
-{
- return CMD_SUCCESS;
-}
-
-DEFUNSH(VTYSH_ALL, vtysh_log_file_level, vtysh_log_file_level_cmd,
- "log file FILENAME <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>",
- "Logging control\n"
- "Logging to file\n"
- "Logging filename\n" LOG_LEVEL_DESC)
-{
- return CMD_SUCCESS;
-}
-
-DEFUNSH(VTYSH_ALL, no_vtysh_log_file, no_vtysh_log_file_cmd,
- "no log file [FILENAME [LEVEL]]", NO_STR
- "Logging control\n"
- "Cancel logging to file\n"
- "Logging file name\n"
- "Logging level\n")
-{
- return CMD_SUCCESS;
-}
-
-DEFUNSH(VTYSH_ALL, vtysh_log_monitor, vtysh_log_monitor_cmd,
- "log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
- "Logging control\n"
- "Set terminal line (monitor) logging level\n" LOG_LEVEL_DESC)
-{
- return CMD_SUCCESS;
-}
-
-DEFUNSH(VTYSH_ALL, no_vtysh_log_monitor, no_vtysh_log_monitor_cmd,
- "no log monitor [LEVEL]", NO_STR
- "Logging control\n"
- "Disable terminal line (monitor) logging\n"
- "Logging level\n")
-{
- return CMD_SUCCESS;
-}
-
-DEFUNSH(VTYSH_ALL, vtysh_log_syslog, vtysh_log_syslog_cmd,
- "log syslog [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
- "Logging control\n"
- "Set syslog logging level\n" LOG_LEVEL_DESC)
-{
- return CMD_SUCCESS;
-}
-
-DEFUNSH(VTYSH_ALL, no_vtysh_log_syslog, no_vtysh_log_syslog_cmd,
- "no log syslog [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
- NO_STR
- "Logging control\n"
- "Cancel logging to syslog\n"
- LOG_LEVEL_DESC)
-{
- return CMD_SUCCESS;
-}
-
-DEFUNSH(VTYSH_ALL, vtysh_log_facility, vtysh_log_facility_cmd,
- "log facility <kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>",
- "Logging control\n"
- "Facility parameter for syslog messages\n" LOG_FACILITY_DESC)
-{
- return CMD_SUCCESS;
-}
-
-DEFUNSH(VTYSH_ALL, no_vtysh_log_facility, no_vtysh_log_facility_cmd,
- "no log facility [<kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>]",
- NO_STR
- "Logging control\n"
- "Reset syslog facility to default (daemon)\n"
- LOG_FACILITY_DESC)
-{
- return CMD_SUCCESS;
-}
-
-DEFUNSH(VTYSH_ALL, vtysh_log_record_priority, vtysh_log_record_priority_cmd,
- "log record-priority",
- "Logging control\n"
- "Log the priority of the message within the message\n")
-{
- return CMD_SUCCESS;
-}
-
-DEFUNSH(VTYSH_ALL, no_vtysh_log_record_priority,
- no_vtysh_log_record_priority_cmd, "no log record-priority", NO_STR
- "Logging control\n"
- "Do not log the priority of the message within the message\n")
-{
- return CMD_SUCCESS;
-}
-
-DEFUNSH(VTYSH_ALL, vtysh_log_timestamp_precision,
- vtysh_log_timestamp_precision_cmd, "log timestamp precision (0-6)",
- "Logging control\n"
- "Timestamp configuration\n"
- "Set the timestamp precision\n"
- "Number of subsecond digits\n")
-{
- return CMD_SUCCESS;
-}
-
DEFUNSH(VTYSH_ALL, vtysh_debug_memstats,
vtysh_debug_memstats_cmd, "[no] debug memstats-at-exit",
NO_STR
return CMD_SUCCESS;
}
-DEFUNSH(VTYSH_ALL, no_vtysh_log_timestamp_precision,
- no_vtysh_log_timestamp_precision_cmd, "no log timestamp precision",
- NO_STR
- "Logging control\n"
- "Timestamp configuration\n"
- "Reset the timestamp precision to the default value of 0\n")
-{
- return CMD_SUCCESS;
-}
-
DEFUNSH(VTYSH_ALL, vtysh_service_password_encrypt,
vtysh_service_password_encrypt_cmd, "service password-encryption",
"Set up miscellaneous service\n"
DEFUN(find,
find_cmd,
- "find REGEX",
+ "find REGEX...",
"Find CLI command matching a regular expression\n"
"Search pattern (POSIX regex)\n")
{
- char *pattern = argv[1]->arg;
const struct cmd_node *node;
const struct cmd_element *cli;
vector clis;
-
regex_t exp = {};
-
+ char *pattern = argv_concat(argv, argc, 1);
int cr = regcomp(&exp, pattern, REG_NOSUB | REG_EXTENDED);
+ XFREE(MTYPE_TMP, pattern);
+
if (cr != 0) {
switch (cr) {
case REG_BADBR:
/* Logging */
install_element(VIEW_NODE, &vtysh_show_logging_cmd);
- install_element(CONFIG_NODE, &vtysh_log_stdout_cmd);
- install_element(CONFIG_NODE, &vtysh_log_stdout_level_cmd);
- install_element(CONFIG_NODE, &no_vtysh_log_stdout_cmd);
- install_element(CONFIG_NODE, &vtysh_log_file_cmd);
- install_element(CONFIG_NODE, &vtysh_log_file_level_cmd);
- install_element(CONFIG_NODE, &no_vtysh_log_file_cmd);
- install_element(CONFIG_NODE, &vtysh_log_monitor_cmd);
- install_element(CONFIG_NODE, &no_vtysh_log_monitor_cmd);
- install_element(CONFIG_NODE, &vtysh_log_syslog_cmd);
- install_element(CONFIG_NODE, &no_vtysh_log_syslog_cmd);
- install_element(CONFIG_NODE, &vtysh_log_facility_cmd);
- install_element(CONFIG_NODE, &no_vtysh_log_facility_cmd);
- install_element(CONFIG_NODE, &vtysh_log_record_priority_cmd);
- install_element(CONFIG_NODE, &no_vtysh_log_record_priority_cmd);
- install_element(CONFIG_NODE, &vtysh_log_timestamp_precision_cmd);
- install_element(CONFIG_NODE, &no_vtysh_log_timestamp_precision_cmd);
install_element(CONFIG_NODE, &vtysh_service_password_encrypt_cmd);
install_element(CONFIG_NODE, &no_vtysh_service_password_encrypt_cmd);
+++ /dev/null
-!
-! Sample configuration file for vtysh.
-!
-!service integrated-vtysh-config
-!hostname quagga-router
-!username root nopassword
-!
config = config_get(OPENFABRIC_NODE, line);
else if (strncmp(line, "route-map", strlen("route-map")) == 0)
config = config_get(RMAP_NODE, line);
+ else if (strncmp(line, "no route-map", strlen("no route-map"))
+ == 0)
+ config = config_get(RMAP_NODE, line);
else if (strncmp(line, "pbr-map", strlen("pbr-map")) == 0)
config = config_get(PBRMAP_NODE, line);
else if (strncmp(line, "access-list", strlen("access-list"))
progname);
else
printf("Usage : %s [OPTION...]\n\n"
- "Integrated shell for FRR (version " FRR_VERSION "). \n"
- "Configured with:\n " FRR_CONFIG_ARGS "\n\n"
+ "Integrated shell for FRR (version " FRR_VERSION
+ "). \n"
+ "Configured with:\n " FRR_CONFIG_ARGS
+ "\n\n"
"-b, --boot Execute boot startup configuration\n"
"-c, --command Execute argument as command\n"
"-d, --daemon Connect only to the specified daemon\n"
"-N --pathspace Insert prefix into config & socket paths\n"
"-u --user Run as an unprivileged user\n"
"-w, --writeconfig Write integrated config (frr.conf) and exit\n"
+ "-H, --histfile Override history file\n"
"-h, --help Display this help and exit\n\n"
"Note that multiple commands may be executed from the command\n"
"line by passing multiple -c args, or by embedding linefeed\n"
{"vty_socket", required_argument, NULL, OPTION_VTYSOCK},
{"config_dir", required_argument, NULL, OPTION_CONFDIR},
{"inputfile", required_argument, NULL, 'f'},
+ {"histfile", required_argument, NULL, 'H'},
{"echo", no_argument, NULL, 'E'},
{"dryrun", no_argument, NULL, 'C'},
{"help", no_argument, NULL, 'h'},
char sysconfdir[MAXPATHLEN];
const char *pathspace_arg = NULL;
char pathspace[MAXPATHLEN] = "";
+ const char *histfile = NULL;
/* SUID: drop down to calling user & go back up when needed */
elevuid = geteuid();
/* Option handling. */
while (1) {
- opt = getopt_long(argc, argv, "be:c:d:nf:mEhCwN:u",
- longopts, 0);
+ opt = getopt_long(argc, argv, "be:c:d:nf:H:mEhCwN:u", longopts,
+ 0);
if (opt == EOF)
break;
case 'h':
usage(0);
break;
+ case 'H':
+ histfile = optarg;
+ break;
default:
usage(1);
break;
/*
* Setup history file for use by both -c and regular input
* If we can't find the home directory, then don't store
- * the history information
+ * the history information.
+ * VTYSH_HISTFILE is prefered over command line
+ * argument (-H/--histfile).
*/
- homedir = vtysh_get_home();
- if (homedir) {
- snprintf(history_file, sizeof(history_file), "%s/.history_frr",
- homedir);
+ if (getenv("VTYSH_HISTFILE")) {
+ const char *file = getenv("VTYSH_HISTFILE");
+
+ strlcpy(history_file, file, sizeof(history_file));
+ } else if (histfile) {
+ strlcpy(history_file, histfile, sizeof(history_file));
+ } else {
+ homedir = vtysh_get_home();
+ if (homedir)
+ snprintf(history_file, sizeof(history_file),
+ "%s/.history_frr", homedir);
+ }
+
+ if (strlen(history_file) > 0) {
if (read_history(history_file) != 0) {
int fp;
description
"Route map instance name";
}
+ leaf optimization-disabled {
+ type boolean;
+ default false;
+ description "Disables or enables the optimization";
+ }
list entry {
key "sequence";
else if (IS_ZEBRA_IF_VXLAN(ifp))
zebra_l2_vxlanif_del(ifp);
- if (!IS_ZEBRA_IF_VRF(ifp))
- if_delete_update(ifp);
+ if_delete_update(ifp);
}
return 0;
* Remove and re-add any existing neighbor entry for this address,
* since Netlink doesn't currently offer update message types.
*/
- kernel_neigh_update(0, ifp->ifindex, ipv4_ll.s_addr, mac, 6, ns_id);
+ kernel_neigh_update(0, ifp->ifindex, (void *)&ipv4_ll.s_addr, mac, 6,
+ ns_id, AF_INET, true);
/* Add new neighbor entry.
*
* they'll be useless to us.
*/
if (add)
- kernel_neigh_update(add, ifp->ifindex, ipv4_ll.s_addr, mac, 6,
- ns_id);
+ kernel_neigh_update(add, ifp->ifindex, (void *)&ipv4_ll.s_addr,
+ mac, 6, ns_id, AF_INET, true);
memcpy(&zif->neigh_mac[0], &mac[0], 6);
case DPLANE_OP_VTEP_ADD:
case DPLANE_OP_VTEP_DELETE:
case DPLANE_OP_NEIGH_DISCOVER:
+ case DPLANE_OP_NEIGH_IP_INSTALL:
+ case DPLANE_OP_NEIGH_IP_DELETE:
+ case DPLANE_OP_NEIGH_TABLE_UPDATE:
return netlink_put_neigh_update_msg(bth, ctx);
case DPLANE_OP_RULE_ADD:
#endif /* !HAVE_NETLINK */
-extern int kernel_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla,
- int llalen, ns_id_t ns_id);
+extern int kernel_neigh_update(int cmd, int ifindex, void *addr, char *lla,
+ int llalen, ns_id_t ns_id, uint8_t family,
+ bool permanent);
+extern int kernel_neigh_register(vrf_id_t vrf_id, struct zserv *client,
+ bool reg);
extern int kernel_interface_set_master(struct interface *master,
struct interface *slave);
extern uint32_t kernel_get_speed(struct interface *ifp, int *error);
extern int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *mroute);
+extern int kernel_configure_if_link(struct interface *ifp,
+ struct interface *link_ifp, ns_id_t ns_id);
+
/*
* Southbound Initialization routines to get initial starting
* state.
state |= NUD_PROBE;
if (dplane_state & DPLANE_NUD_INCOMPLETE)
state |= NUD_INCOMPLETE;
+ if (dplane_state & DPLANE_NUD_PERMANENT)
+ state |= NUD_PERMANENT;
+ if (dplane_state & DPLANE_NUD_FAILED)
+ state |= NUD_FAILED;
return state;
}
routedesc, nl_msg_type_to_str(cmd), label);
}
-static int netlink_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla,
- int llalen, ns_id_t ns_id)
+static int netlink_neigh_update(int cmd, int ifindex, void *addr, char *lla,
+ int llalen, ns_id_t ns_id, uint8_t family,
+ bool permanent, uint8_t protocol)
{
- uint8_t protocol = RTPROT_ZEBRA;
struct {
struct nlmsghdr n;
struct ndmsg ndm;
req.n.nlmsg_type = cmd; // RTM_NEWNEIGH or RTM_DELNEIGH
req.n.nlmsg_pid = zns->netlink_cmd.snl.nl_pid;
- req.ndm.ndm_family = AF_INET;
- req.ndm.ndm_state = NUD_PERMANENT;
+ req.ndm.ndm_family = family;
req.ndm.ndm_ifindex = ifindex;
req.ndm.ndm_type = RTN_UNICAST;
+ if (cmd == RTM_NEWNEIGH) {
+ if (!permanent)
+ req.ndm.ndm_state = NUD_REACHABLE;
+ else
+ req.ndm.ndm_state = NUD_PERMANENT;
+ } else
+ req.ndm.ndm_state = NUD_FAILED;
nl_attr_put(&req.n, sizeof(req), NDA_PROTOCOL, &protocol,
sizeof(protocol));
- nl_attr_put32(&req.n, sizeof(req), NDA_DST, addr);
- nl_attr_put(&req.n, sizeof(req), NDA_LLADDR, lla, llalen);
+ req.ndm.ndm_type = RTN_UNICAST;
+ nl_attr_put(&req.n, sizeof(req), NDA_DST, addr,
+ family2addrsize(family));
+ if (lla)
+ nl_attr_put(&req.n, sizeof(req), NDA_LLADDR, lla, llalen);
return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
0);
}
-int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla,
- int llalen, ns_id_t ns_id)
+int kernel_neigh_update(int add, int ifindex, void *addr, char *lla, int llalen,
+ ns_id_t ns_id, uint8_t family, bool permanent)
{
return netlink_neigh_update(add ? RTM_NEWNEIGH : RTM_DELNEIGH, ifindex,
- addr, lla, llalen, ns_id);
+ addr, lla, llalen, ns_id, family, permanent,
+ RTPROT_ZEBRA);
}
/**
* entry.
* @ctx: Dataplane context
* @cmd: Netlink command (RTM_NEWNEIGH or RTM_DELNEIGH)
- * @mac: A neighbor cache link layer address
+ * @lla: A pointer to neighbor cache link layer address
+ * @llalen: Length of the pointer to neighbor cache link layer
+ * address
* @ip: A neighbor cache n/w layer destination address
* In the case of bridge FDB, this represnts the remote
* VTEP IP.
* @state: NUD_* states
* @data: data buffer pointer
* @datalen: total amount of data buffer space
+ * @protocol: protocol information
*
* Return: 0 when the msg doesn't fit entirely in the buffer
* otherwise the number of bytes written to buf.
*/
static ssize_t netlink_neigh_update_msg_encode(
- const struct zebra_dplane_ctx *ctx, int cmd, const struct ethaddr *mac,
- const struct ipaddr *ip, bool replace_obj, uint8_t family, uint8_t type,
- uint8_t flags, uint16_t state, uint32_t nhg_id, bool nfy,
+ const struct zebra_dplane_ctx *ctx, int cmd, const void *lla,
+ int llalen, const struct ipaddr *ip, bool replace_obj, uint8_t family,
+ uint8_t type, uint8_t flags, uint16_t state, uint32_t nhg_id, bool nfy,
uint8_t nfy_flags, bool ext, uint32_t ext_flags, void *data,
- size_t datalen)
+ size_t datalen, uint8_t protocol)
{
- uint8_t protocol = RTPROT_ZEBRA;
struct {
struct nlmsghdr n;
struct ndmsg ndm;
sizeof(protocol)))
return 0;
- if (mac) {
- if (!nl_attr_put(&req->n, datalen, NDA_LLADDR, mac, 6))
+ if (lla) {
+ if (!nl_attr_put(&req->n, datalen, NDA_LLADDR, lla, llalen))
return 0;
}
void *buf, size_t buflen)
{
struct ethaddr dst_mac = {.octet = {0}};
+ int proto = RTPROT_ZEBRA;
+
+ if (dplane_ctx_get_type(ctx) != 0)
+ proto = zebra2proto(dplane_ctx_get_type(ctx));
return netlink_neigh_update_msg_encode(
- ctx, cmd, &dst_mac, dplane_ctx_neigh_get_ipaddr(ctx), false,
- PF_BRIDGE, 0, NTF_SELF, (NUD_NOARP | NUD_PERMANENT), 0 /*nhg*/,
- false /*nfy*/, 0 /*nfy_flags*/, false /*ext*/, 0 /*ext_flags*/,
- buf, buflen);
+ ctx, cmd, (const void *)&dst_mac, ETH_ALEN,
+ dplane_ctx_neigh_get_ipaddr(ctx), false, PF_BRIDGE, 0, NTF_SELF,
+ (NUD_NOARP | NUD_PERMANENT), 0 /*nhg*/, false /*nfy*/,
+ 0 /*nfy_flags*/, false /*ext*/, 0 /*ext_flags*/, buf, buflen,
+ proto);
}
#ifndef NDA_RTA
uint32_t update_flags;
bool nfy = false;
uint8_t nfy_flags = 0;
+ int proto = RTPROT_ZEBRA;
+
+ if (dplane_ctx_get_type(ctx) != 0)
+ proto = zebra2proto(dplane_ctx_get_type(ctx));
cmd = dplane_ctx_get_op(ctx) == DPLANE_OP_MAC_INSTALL
? RTM_NEWNEIGH : RTM_DELNEIGH;
}
total = netlink_neigh_update_msg_encode(
- ctx, cmd, dplane_ctx_mac_get_addr(ctx), &vtep_ip, true,
- AF_BRIDGE, 0, flags, state, nhg_id, nfy, nfy_flags,
- false /*ext*/, 0 /*ext_flags*/, data, datalen);
+ ctx, cmd, (const void *)dplane_ctx_mac_get_addr(ctx), ETH_ALEN,
+ &vtep_ip, true, AF_BRIDGE, 0, flags, state, nhg_id, nfy,
+ nfy_flags, false /*ext*/, 0 /*ext_flags*/, data, datalen,
+ proto);
return total;
}
bool local_inactive;
uint32_t ext_flags = 0;
bool dp_static = false;
+ int l2_len = 0;
+ int cmd;
ndm = NLMSG_DATA(h);
if (h->nlmsg_type == RTM_NEWNEIGH && !(ndm->ndm_state & NUD_VALID))
netlink_handle_5549(ndm, zif, ifp, &ip, true);
+ /* we send link layer information to client:
+ * - nlmsg_type = RTM_DELNEIGH|NEWNEIGH|GETNEIGH
+ * - struct ipaddr ( for DEL and GET)
+ * - struct ethaddr mac; (for NEW)
+ */
+ if (h->nlmsg_type == RTM_NEWNEIGH)
+ cmd = ZEBRA_NHRP_NEIGH_ADDED;
+ else if (h->nlmsg_type == RTM_GETNEIGH)
+ cmd = ZEBRA_NHRP_NEIGH_GET;
+ else if (h->nlmsg_type == RTM_DELNEIGH)
+ cmd = ZEBRA_NHRP_NEIGH_REMOVED;
+ else {
+ zlog_debug("%s(): unknown nlmsg type %u", __func__,
+ h->nlmsg_type);
+ return 0;
+ }
+ if (tb[NDA_LLADDR]) {
+ /* copy LLADDR information */
+ l2_len = RTA_PAYLOAD(tb[NDA_LLADDR]);
+ memcpy(&mac, RTA_DATA(tb[NDA_LLADDR]), l2_len);
+ }
+ if (l2_len == IPV4_MAX_BYTELEN || l2_len == 0) {
+ union sockunion link_layer_ipv4;
+
+ if (l2_len) {
+ sockunion_family(&link_layer_ipv4) = AF_INET;
+ memcpy((void *)sockunion_get_addr(&link_layer_ipv4),
+ &mac, l2_len);
+ } else
+ sockunion_family(&link_layer_ipv4) = AF_UNSPEC;
+ zsend_nhrp_neighbor_notify(cmd, ifp, &ip, ndm->ndm_state,
+ &link_layer_ipv4);
+ }
+
+ if (h->nlmsg_type == RTM_GETNEIGH)
+ return 0;
+
/* The neighbor is present on an SVI. From this, we locate the
* underlying
* bridge because we're only interested in neighbors on a VxLAN bridge.
int len;
struct ndmsg *ndm;
- if (!(h->nlmsg_type == RTM_NEWNEIGH || h->nlmsg_type == RTM_DELNEIGH))
+ if (!(h->nlmsg_type == RTM_NEWNEIGH || h->nlmsg_type == RTM_DELNEIGH
+ || h->nlmsg_type == RTM_GETNEIGH))
return 0;
/* Length validity. */
int cmd, void *buf, size_t buflen)
{
const struct ipaddr *ip;
- const struct ethaddr *mac;
+ const struct ethaddr *mac = NULL;
+ const struct ipaddr *link_ip = NULL;
+ const void *link_ptr = NULL;
+ char buf2[ETHER_ADDR_STRLEN];
+
+ int llalen;
uint8_t flags;
uint16_t state;
uint8_t family;
uint32_t update_flags;
uint32_t ext_flags = 0;
bool ext = false;
+ int proto = RTPROT_ZEBRA;
+
+ if (dplane_ctx_get_type(ctx) != 0)
+ proto = zebra2proto(dplane_ctx_get_type(ctx));
ip = dplane_ctx_neigh_get_ipaddr(ctx);
- mac = dplane_ctx_neigh_get_mac(ctx);
- if (is_zero_mac(mac))
- mac = NULL;
+ if (dplane_ctx_get_op(ctx) == DPLANE_OP_NEIGH_IP_INSTALL
+ || dplane_ctx_get_op(ctx) == DPLANE_OP_NEIGH_IP_DELETE) {
+ link_ip = dplane_ctx_neigh_get_link_ip(ctx);
+ llalen = IPADDRSZ(link_ip);
+ link_ptr = (const void *)&(link_ip->ip.addr);
+ ipaddr2str(link_ip, buf2, sizeof(buf2));
+ } else {
+ mac = dplane_ctx_neigh_get_mac(ctx);
+ llalen = ETH_ALEN;
+ link_ptr = (const void *)mac;
+ if (is_zero_mac(mac))
+ mac = NULL;
+ if (mac)
+ prefix_mac2str(mac, buf2, sizeof(buf2));
+ else
+ snprintf(buf2, sizeof(buf2), "null");
+ }
update_flags = dplane_ctx_neigh_get_update_flags(ctx);
flags = neigh_flags_to_netlink(dplane_ctx_neigh_get_flags(ctx));
state = neigh_state_to_netlink(dplane_ctx_neigh_get_state(ctx));
*/
if (update_flags & DPLANE_NEIGH_WAS_STATIC)
ext = true;
- } else {
+ } else if (!(update_flags & DPLANE_NEIGH_NO_EXTENSION)) {
ext = true;
/* local neigh */
if (update_flags & DPLANE_NEIGH_SET_STATIC)
}
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
- "Tx %s family %s IF %s(%u) Neigh %pIA MAC %pEA flags 0x%x state 0x%x %sext_flags 0x%x",
+ "Tx %s family %s IF %s(%u) Neigh %pIA %s %s flags 0x%x state 0x%x %sext_flags 0x%x",
nl_msg_type_to_str(cmd), nl_family_to_str(family),
dplane_ctx_get_ifname(ctx), dplane_ctx_get_ifindex(ctx),
- ip, mac, flags, state, ext ? "ext " : "", ext_flags);
+ ip, link_ip ? "Link " : "MAC ", buf2, flags, state,
+ ext ? "ext " : "", ext_flags);
return netlink_neigh_update_msg_encode(
- ctx, cmd, mac, ip, true, family, RTN_UNICAST, flags, state,
- 0 /*nhg*/, false /*nfy*/, 0 /*nfy_flags*/, ext, ext_flags, buf,
- buflen);
+ ctx, cmd, link_ptr, llalen, ip, true, family, RTN_UNICAST,
+ flags, state, 0 /*nhg*/, false /*nfy*/, 0 /*nfy_flags*/, ext,
+ ext_flags, buf, buflen, proto);
+}
+
+static int netlink_neigh_table_update_ctx(const struct zebra_dplane_ctx *ctx,
+ void *data, size_t datalen)
+{
+ struct {
+ struct nlmsghdr n;
+ struct ndtmsg ndtm;
+ char buf[];
+ } *req = data;
+ struct rtattr *nest;
+ uint8_t family;
+ ifindex_t idx;
+ uint32_t val;
+
+ if (datalen < sizeof(*req))
+ return 0;
+ memset(req, 0, sizeof(*req));
+ family = dplane_ctx_neightable_get_family(ctx);
+ idx = dplane_ctx_get_ifindex(ctx);
+
+ req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndtmsg));
+ req->n.nlmsg_flags = NLM_F_REQUEST | NLM_F_REPLACE;
+ req->n.nlmsg_type = RTM_SETNEIGHTBL;
+ req->ndtm.ndtm_family = family;
+
+ nl_attr_put(&req->n, datalen, NDTA_NAME,
+ family == AF_INET ? "arp_cache" : "ndisc_cache", 10);
+ nest = nl_attr_nest(&req->n, datalen, NDTA_PARMS);
+ if (nest == NULL)
+ return 0;
+ if (!nl_attr_put(&req->n, datalen, NDTPA_IFINDEX, &idx, sizeof(idx)))
+ return 0;
+ val = dplane_ctx_neightable_get_app_probes(ctx);
+ if (!nl_attr_put(&req->n, datalen, NDTPA_APP_PROBES, &val, sizeof(val)))
+ return 0;
+ val = dplane_ctx_neightable_get_mcast_probes(ctx);
+ if (!nl_attr_put(&req->n, datalen, NDTPA_MCAST_PROBES, &val,
+ sizeof(val)))
+ return 0;
+ val = dplane_ctx_neightable_get_ucast_probes(ctx);
+ if (!nl_attr_put(&req->n, datalen, NDTPA_UCAST_PROBES, &val,
+ sizeof(val)))
+ return 0;
+ nl_attr_nest_end(&req->n, nest);
+
+ return NLMSG_ALIGN(req->n.nlmsg_len);
}
static ssize_t netlink_neigh_msg_encoder(struct zebra_dplane_ctx *ctx,
case DPLANE_OP_NEIGH_INSTALL:
case DPLANE_OP_NEIGH_UPDATE:
case DPLANE_OP_NEIGH_DISCOVER:
+ case DPLANE_OP_NEIGH_IP_INSTALL:
ret = netlink_neigh_update_ctx(ctx, RTM_NEWNEIGH, buf, buflen);
break;
case DPLANE_OP_NEIGH_DELETE:
+ case DPLANE_OP_NEIGH_IP_DELETE:
ret = netlink_neigh_update_ctx(ctx, RTM_DELNEIGH, buf, buflen);
break;
case DPLANE_OP_VTEP_ADD:
ret = netlink_vxlan_flood_update_ctx(ctx, RTM_DELNEIGH, buf,
buflen);
break;
+ case DPLANE_OP_NEIGH_TABLE_UPDATE:
+ ret = netlink_neigh_table_update_ctx(ctx, buf, buflen);
+ break;
default:
ret = -1;
}
return ZEBRA_DPLANE_REQUEST_SUCCESS;
}
-int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla,
- int llalen, ns_id_t ns_id)
+int kernel_neigh_register(vrf_id_t vrf_id, struct zserv *client, bool reg)
+{
+ /* TODO */
+ return 0;
+}
+
+int kernel_neigh_update(int add, int ifindex, void *addr, char *lla, int llalen,
+ ns_id_t ns_id, uint8_t family, bool permanent)
{
/* TODO */
return 0;
return ZEBRA_DPLANE_REQUEST_SUCCESS;
}
+int kernel_configure_if_link(struct interface *ifp, struct interface *link_ifp,
+ ns_id_t ns_id)
+{
+ return 0;
+}
+
extern int kernel_interface_set_master(struct interface *master,
struct interface *slave)
{
if ZEBRA
sbin_PROGRAMS += zebra/zebra
-dist_examples_DATA += zebra/zebra.conf.sample
vtysh_scan += \
zebra/debug.c \
zebra/interface.c \
zebra_dplane_fpm_nl_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
zebra_dplane_fpm_nl_la_LIBADD =
-vtysh_scan += $(top_srcdir)/zebra/dplane_fpm_nl.c
+vtysh_scan += zebra/dplane_fpm_nl.c
endif
if NETLINK_DEBUG
zserv_send_message(client, s);
}
+void zsend_nhrp_neighbor_notify(int cmd, struct interface *ifp,
+ struct ipaddr *ipaddr, int ndm_state,
+ union sockunion *link_layer_ipv4)
+{
+ struct stream *s;
+ struct listnode *node, *nnode;
+ struct zserv *client;
+ afi_t afi;
+ union sockunion ip;
+
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: Notifying Neighbor entry (%u)",
+ __PRETTY_FUNCTION__, cmd);
+
+ sockunion_family(&ip) = ipaddr_family(ipaddr);
+ afi = family2afi(sockunion_family(&ip));
+ memcpy((char *)sockunion_get_addr(&ip), &ipaddr->ip.addr,
+ family2addrsize(sockunion_family(&ip)));
+
+ for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
+ if (!vrf_bitmap_check(client->nhrp_neighinfo[afi], ifp->vrf_id))
+ continue;
+
+ s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+ zclient_neigh_ip_encode(s, cmd, &ip, link_layer_ipv4, ifp);
+ stream_putw_at(s, 0, stream_get_endp(s));
+ zserv_send_message(client, s);
+ }
+}
+
+
/* Router-id is updated. Send ZEBRA_ROUTER_ID_UPDATE to client. */
int zsend_router_id_update(struct zserv *client, afi_t afi, struct prefix *p,
vrf_id_t vrf_id)
vrf_bitmap_unset(client->redist[afi][i], zvrf_id(zvrf));
vrf_bitmap_unset(client->redist_default[afi], zvrf_id(zvrf));
vrf_bitmap_unset(client->ridinfo[afi], zvrf_id(zvrf));
+ vrf_bitmap_unset(client->nhrp_neighinfo[afi], zvrf_id(zvrf));
}
}
return;
}
+
+static inline void zebra_neigh_register(ZAPI_HANDLER_ARGS)
+{
+ afi_t afi;
+
+ STREAM_GETW(msg, afi);
+ if (afi <= AFI_UNSPEC || afi >= AFI_MAX) {
+ zlog_warn(
+ "Invalid AFI %u while registering for neighbors notifications",
+ afi);
+ goto stream_failure;
+ }
+ vrf_bitmap_set(client->nhrp_neighinfo[afi], zvrf_id(zvrf));
+stream_failure:
+ return;
+}
+
+static inline void zebra_neigh_unregister(ZAPI_HANDLER_ARGS)
+{
+ afi_t afi;
+
+ STREAM_GETW(msg, afi);
+ if (afi <= AFI_UNSPEC || afi >= AFI_MAX) {
+ zlog_warn(
+ "Invalid AFI %u while unregistering from neighbor notifications",
+ afi);
+ goto stream_failure;
+ }
+ vrf_bitmap_unset(client->nhrp_neighinfo[afi], zvrf_id(zvrf));
+stream_failure:
+ return;
+}
+
+static inline void zebra_configure_arp(ZAPI_HANDLER_ARGS)
+{
+ struct stream *s;
+ uint8_t fam;
+ ifindex_t idx;
+ struct interface *ifp;
+
+ s = msg;
+ STREAM_GETC(s, fam);
+ if (fam != AF_INET && fam != AF_INET6)
+ return;
+ STREAM_GETL(s, idx);
+ ifp = if_lookup_by_index_per_ns(zvrf->zns, idx);
+ if (!ifp)
+ return;
+ dplane_neigh_table_update(ifp, fam, 1, 0, 0);
+stream_failure:
+ return;
+}
+
+static inline void zebra_neigh_ip_add(ZAPI_HANDLER_ARGS)
+{
+ struct stream *s;
+ struct zapi_neigh_ip api = {};
+ int ret;
+ const struct interface *ifp;
+
+ s = msg;
+ ret = zclient_neigh_ip_decode(s, &api);
+ if (ret < 0)
+ return;
+ ifp = if_lookup_by_index(api.index, zvrf_id(zvrf));
+ if (!ifp)
+ return;
+ dplane_neigh_ip_update(DPLANE_OP_NEIGH_IP_INSTALL, ifp, &api.ip_out,
+ &api.ip_in, api.ndm_state, client->proto);
+}
+
+
+static inline void zebra_neigh_ip_del(ZAPI_HANDLER_ARGS)
+{
+ struct stream *s;
+ struct zapi_neigh_ip api = {};
+ int ret;
+ struct interface *ifp;
+
+ s = msg;
+ ret = zclient_neigh_ip_decode(s, &api);
+ if (ret < 0)
+ return;
+ ifp = if_lookup_by_index(api.index, zvrf_id(zvrf));
+ if (!ifp)
+ return;
+ dplane_neigh_ip_update(DPLANE_OP_NEIGH_IP_DELETE, ifp, &api.ip_out,
+ &api.ip_in, api.ndm_state, client->proto);
+}
+
+
static inline void zread_iptable(ZAPI_HANDLER_ARGS)
{
struct zebra_pbr_iptable *zpi =
[ZEBRA_ROUTE_NOTIFY_REQUEST] = zread_route_notify_request,
[ZEBRA_EVPN_REMOTE_NH_ADD] = zebra_evpn_proc_remote_nh,
[ZEBRA_EVPN_REMOTE_NH_DEL] = zebra_evpn_proc_remote_nh,
+ [ZEBRA_NEIGH_IP_ADD] = zebra_neigh_ip_add,
+ [ZEBRA_NEIGH_IP_DEL] = zebra_neigh_ip_del,
+ [ZEBRA_NHRP_NEIGH_REGISTER] = zebra_neigh_register,
+ [ZEBRA_NHRP_NEIGH_UNREGISTER] = zebra_neigh_unregister,
+ [ZEBRA_CONFIGURE_ARP] = zebra_configure_arp,
};
/*
extern int zsend_sr_policy_notify_status(uint32_t color,
struct ipaddr *endpoint, char *name,
int status);
+extern void zsend_nhrp_neighbor_notify(int cmd, struct interface *ifp,
+ struct ipaddr *ipaddr, int ndm_state,
+ union sockunion *link_layer_ipv4);
extern int zsend_client_close_notify(struct zserv *client,
struct zserv *closed_client);
+++ /dev/null
-! -*- zebra -*-
-!
-! zebra sample configuration file
-!
-hostname Router
-password zebra
-enable password zebra
-!
-! Interface's description.
-!
-!interface lo
-! description test of desc.
-!
-!interface sit0
-! multicast
-
-!
-! Static default route sample.
-!
-!ip route 0.0.0.0/0 203.181.89.241
-!
-
-!log file zebra.log
*/
struct dplane_neigh_info {
struct ipaddr ip_addr;
- struct ethaddr mac;
+ union {
+ struct ethaddr mac;
+ struct ipaddr ip_addr;
+ } link;
uint32_t flags;
uint16_t state;
uint32_t update_flags;
};
+/*
+ * Neighbor Table
+ */
+struct dplane_neigh_table {
+ uint8_t family;
+ uint32_t app_probes;
+ uint32_t ucast_probes;
+ uint32_t mcast_probes;
+};
+
/*
* Policy based routing rule info for the dataplane
*/
struct zebra_pbr_ipset_entry entry;
struct zebra_pbr_ipset_info info;
} ipset_entry;
+ struct dplane_neigh_table neightable;
} u;
/* Namespace info, used especially for netlink kernel communication */
_Atomic uint32_t dg_ipset_entry_in;
_Atomic uint32_t dg_ipset_entry_errors;
+ _Atomic uint32_t dg_neightable_in;
+ _Atomic uint32_t dg_neightable_errors;
+
/* Dataplane pthread */
struct frr_pthread *dg_pthread;
vlanid_t vid, const struct ethaddr *mac,
struct in_addr vtep_ip, bool sticky, uint32_t nhg_id,
uint32_t update_flags);
-static enum zebra_dplane_result neigh_update_internal(
- enum dplane_op_e op,
- const struct interface *ifp,
- const struct ethaddr *mac,
- const struct ipaddr *ip,
- uint32_t flags, uint16_t state, uint32_t update_flags);
+static enum zebra_dplane_result
+neigh_update_internal(enum dplane_op_e op, const struct interface *ifp,
+ const void *link, int link_family,
+ const struct ipaddr *ip, uint32_t flags, uint16_t state,
+ uint32_t update_flags, int protocol);
/*
* Public APIs
case DPLANE_OP_RULE_UPDATE:
case DPLANE_OP_NEIGH_DISCOVER:
case DPLANE_OP_BR_PORT_UPDATE:
+ case DPLANE_OP_NEIGH_IP_INSTALL:
+ case DPLANE_OP_NEIGH_IP_DELETE:
case DPLANE_OP_NONE:
case DPLANE_OP_IPSET_ADD:
case DPLANE_OP_IPSET_DELETE:
case DPLANE_OP_IPSET_ENTRY_ADD:
case DPLANE_OP_IPSET_ENTRY_DELETE:
break;
+ case DPLANE_OP_NEIGH_TABLE_UPDATE:
+ break;
case DPLANE_OP_IPTABLE_ADD:
case DPLANE_OP_IPTABLE_DELETE:
if (ctx->u.iptable.interface_name_list) {
case DPLANE_OP_IPSET_ENTRY_DELETE:
ret = "IPSET_ENTRY_DELETE";
break;
+ case DPLANE_OP_NEIGH_IP_INSTALL:
+ ret = "NEIGH_IP_INSTALL";
+ break;
+ case DPLANE_OP_NEIGH_IP_DELETE:
+ ret = "NEIGH_IP_DELETE";
+ break;
+ case DPLANE_OP_NEIGH_TABLE_UPDATE:
+ ret = "NEIGH_TABLE_UPDATE";
+ break;
}
return ret;
return &(ctx->u.neigh.ip_addr);
}
+const struct ipaddr *
+dplane_ctx_neigh_get_link_ip(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+ return &(ctx->u.neigh.link.ip_addr);
+}
+
const struct ethaddr *dplane_ctx_neigh_get_mac(
const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
- return &(ctx->u.neigh.mac);
+ return &(ctx->u.neigh.link.mac);
}
uint32_t dplane_ctx_neigh_get_flags(const struct zebra_dplane_ctx *ctx)
return ptr->status;
}
+uint8_t dplane_ctx_neightable_get_family(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.neightable.family;
+}
+
+uint32_t
+dplane_ctx_neightable_get_app_probes(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.neightable.app_probes;
+}
+
+uint32_t
+dplane_ctx_neightable_get_ucast_probes(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.neightable.ucast_probes;
+}
+
+uint32_t
+dplane_ctx_neightable_get_mcast_probes(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.neightable.mcast_probes;
+}
+
/*
* End of interface extra info accessors
*/
return result;
}
+/*
+ * API to configure link local with either MAC address or IP information
+ */
+enum zebra_dplane_result dplane_neigh_ip_update(enum dplane_op_e op,
+ const struct interface *ifp,
+ struct ipaddr *link_ip,
+ struct ipaddr *ip,
+ uint32_t ndm_state, int protocol)
+{
+ enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
+ uint16_t state = 0;
+ uint32_t update_flags;
+
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
+ char buf1[PREFIX_STRLEN], buf2[PREFIX_STRLEN];
+
+ ipaddr2str(link_ip, buf1, sizeof(buf1));
+ ipaddr2str(ip, buf2, sizeof(buf2));
+ zlog_debug("init link ctx %s: ifp %s, ip %s link %s",
+ dplane_op2str(op), ifp->name, buf1, buf2);
+ }
+ if (ndm_state == ZEBRA_NEIGH_STATE_REACHABLE)
+ state = DPLANE_NUD_REACHABLE;
+ else if (ndm_state == ZEBRA_NEIGH_STATE_FAILED)
+ state = DPLANE_NUD_FAILED;
+
+ update_flags = DPLANE_NEIGH_NO_EXTENSION;
+
+ result = neigh_update_internal(op, ifp, (const void *)link_ip,
+ ipaddr_family(link_ip), ip, 0, state,
+ update_flags, protocol);
+
+ return result;
+}
+
/*
* Enqueue local mac add (or update).
*/
if (was_static)
update_flags |= DPLANE_NEIGH_WAS_STATIC;
- result = neigh_update_internal(DPLANE_OP_NEIGH_INSTALL,
- ifp, mac, ip, flags, DPLANE_NUD_NOARP,
- update_flags);
+ result = neigh_update_internal(
+ DPLANE_OP_NEIGH_INSTALL, ifp, (const void *)mac, AF_ETHERNET,
+ ip, flags, DPLANE_NUD_NOARP, update_flags, 0);
return result;
}
if (set_router)
ntf |= DPLANE_NTF_ROUTER;
- result = neigh_update_internal(DPLANE_OP_NEIGH_INSTALL,
- ifp, mac, ip, ntf,
- state, update_flags);
+ result = neigh_update_internal(DPLANE_OP_NEIGH_INSTALL, ifp,
+ (const void *)mac, AF_ETHERNET, ip, ntf,
+ state, update_flags, 0);
return result;
}
update_flags |= DPLANE_NEIGH_REMOTE;
- result = neigh_update_internal(DPLANE_OP_NEIGH_DELETE,
- ifp, NULL, ip, 0, 0, update_flags);
+ result = neigh_update_internal(DPLANE_OP_NEIGH_DELETE, ifp, NULL,
+ AF_ETHERNET, ip, 0, 0, update_flags, 0);
return result;
}
SET_IPADDR_V4(&addr);
addr.ipaddr_v4 = *ip;
- result = neigh_update_internal(DPLANE_OP_VTEP_ADD,
- ifp, &mac, &addr, 0, 0, 0);
+ result = neigh_update_internal(DPLANE_OP_VTEP_ADD, ifp, &mac,
+ AF_ETHERNET, &addr, 0, 0, 0, 0);
return result;
}
SET_IPADDR_V4(&addr);
addr.ipaddr_v4 = *ip;
- result = neigh_update_internal(DPLANE_OP_VTEP_DELETE,
- ifp, &mac, &addr, 0, 0, 0);
+ result = neigh_update_internal(DPLANE_OP_VTEP_DELETE, ifp,
+ (const void *)&mac, AF_ETHERNET, &addr,
+ 0, 0, 0, 0);
return result;
}
{
enum zebra_dplane_result result;
- result = neigh_update_internal(DPLANE_OP_NEIGH_DISCOVER, ifp, NULL, ip,
- DPLANE_NTF_USE, DPLANE_NUD_INCOMPLETE, 0);
+ result = neigh_update_internal(DPLANE_OP_NEIGH_DISCOVER, ifp, NULL,
+ AF_ETHERNET, ip, DPLANE_NTF_USE,
+ DPLANE_NUD_INCOMPLETE, 0, 0);
+
+ return result;
+}
+
+enum zebra_dplane_result dplane_neigh_table_update(const struct interface *ifp,
+ const uint8_t family,
+ const uint32_t app_probes,
+ const uint32_t ucast_probes,
+ const uint32_t mcast_probes)
+{
+ enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
+ int ret;
+ struct zebra_dplane_ctx *ctx = NULL;
+ struct zebra_ns *zns;
+ enum dplane_op_e op = DPLANE_OP_NEIGH_TABLE_UPDATE;
+
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
+ zlog_debug("set neigh ctx %s: ifp %s, family %s",
+ dplane_op2str(op), ifp->name, family2str(family));
+ }
+
+ ctx = dplane_ctx_alloc();
+
+ ctx->zd_op = op;
+ ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
+ ctx->zd_vrf_id = ifp->vrf_id;
+
+ zns = zebra_ns_lookup(ifp->vrf_id);
+ dplane_ctx_ns_init(ctx, zns, false);
+
+ strlcpy(ctx->zd_ifname, ifp->name, sizeof(ctx->zd_ifname));
+ ctx->zd_ifindex = ifp->ifindex;
+
+ /* Init the neighbor-specific data area */
+ memset(&ctx->u.neightable, 0, sizeof(ctx->u.neightable));
+
+ ctx->u.neightable.family = family;
+ ctx->u.neightable.app_probes = app_probes;
+ ctx->u.neightable.ucast_probes = ucast_probes;
+ ctx->u.neightable.mcast_probes = mcast_probes;
+
+ /* Enqueue for processing on the dplane pthread */
+ ret = dplane_update_enqueue(ctx);
+
+ /* Increment counter */
+ atomic_fetch_add_explicit(&zdplane_info.dg_neightable_in, 1,
+ memory_order_relaxed);
+
+ if (ret == AOK)
+ result = ZEBRA_DPLANE_REQUEST_QUEUED;
+ else {
+ /* Error counter */
+ atomic_fetch_add_explicit(&zdplane_info.dg_neightable_errors, 1,
+ memory_order_relaxed);
+ dplane_ctx_free(&ctx);
+ }
return result;
}
* Common helper api for neighbor updates
*/
static enum zebra_dplane_result
-neigh_update_internal(enum dplane_op_e op,
- const struct interface *ifp,
- const struct ethaddr *mac,
- const struct ipaddr *ip,
- uint32_t flags, uint16_t state,
- uint32_t update_flags)
+neigh_update_internal(enum dplane_op_e op, const struct interface *ifp,
+ const void *link, const int link_family,
+ const struct ipaddr *ip, uint32_t flags, uint16_t state,
+ uint32_t update_flags, int protocol)
{
enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
int ret;
struct zebra_dplane_ctx *ctx = NULL;
struct zebra_ns *zns;
+ const struct ethaddr *mac = NULL;
+ const struct ipaddr *link_ip = NULL;
- if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
- zlog_debug("init neigh ctx %s: ifp %s, mac %pEA, ip %pIA",
- dplane_op2str(op), ifp->name, mac, ip);
+ if (link_family == AF_ETHERNET)
+ mac = (const struct ethaddr *)link;
+ else
+ link_ip = (const struct ipaddr *)link;
+
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
+ char buf1[PREFIX_STRLEN];
+
+ buf1[0] = '\0';
+ if (link_family == AF_ETHERNET)
+ prefix_mac2str(mac, buf1, sizeof(buf1));
+ else
+ ipaddr2str(link_ip, buf1, sizeof(buf1));
+ zlog_debug("init neigh ctx %s: ifp %s, %s %s, ip %pIA",
+ dplane_op2str(op), ifp->name,
+ link_family == AF_ETHERNET ? "mac " : "link ",
+ buf1, ip);
+ }
ctx = dplane_ctx_alloc();
ctx->zd_op = op;
ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
ctx->zd_vrf_id = ifp->vrf_id;
+ dplane_ctx_set_type(ctx, protocol);
zns = zebra_ns_lookup(ifp->vrf_id);
dplane_ctx_ns_init(ctx, zns, false);
ctx->u.neigh.ip_addr = *ip;
if (mac)
- ctx->u.neigh.mac = *mac;
+ ctx->u.neigh.link.mac = *mac;
+ else if (link_ip)
+ ctx->u.neigh.link.ip_addr = *link_ip;
+
ctx->u.neigh.flags = flags;
ctx->u.neigh.state = state;
ctx->u.neigh.update_flags = update_flags;
memory_order_relaxed);
vty_out(vty, "IPset entry updates: %" PRIu64 "\n", incoming);
vty_out(vty, "IPset entry errors: %" PRIu64 "\n", errs);
+
+ incoming = atomic_load_explicit(&zdplane_info.dg_neightable_in,
+ memory_order_relaxed);
+ errs = atomic_load_explicit(&zdplane_info.dg_neightable_errors,
+ memory_order_relaxed);
+ vty_out(vty, "Neighbor Table updates: %"PRIu64"\n", incoming);
+ vty_out(vty, "Neighbor Table errors: %"PRIu64"\n", errs);
return CMD_SUCCESS;
}
case DPLANE_OP_VTEP_ADD:
case DPLANE_OP_VTEP_DELETE:
case DPLANE_OP_NEIGH_DISCOVER:
+ case DPLANE_OP_NEIGH_IP_INSTALL:
+ case DPLANE_OP_NEIGH_IP_DELETE:
ipaddr2str(dplane_ctx_neigh_get_ipaddr(ctx), buf,
sizeof(buf));
dplane_op2str(dplane_ctx_get_op(ctx)),
ipent.unique, ctx);
} break;
+
+ case DPLANE_OP_NEIGH_TABLE_UPDATE:
+ zlog_debug("Dplane neigh table op %s, ifp %s, family %s",
+ dplane_op2str(dplane_ctx_get_op(ctx)),
+ dplane_ctx_get_ifname(ctx),
+ family2str(dplane_ctx_neightable_get_family(ctx)));
+ break;
}
}
case DPLANE_OP_VTEP_ADD:
case DPLANE_OP_VTEP_DELETE:
case DPLANE_OP_NEIGH_DISCOVER:
+ case DPLANE_OP_NEIGH_IP_INSTALL:
+ case DPLANE_OP_NEIGH_IP_DELETE:
if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
atomic_fetch_add_explicit(&zdplane_info.dg_neigh_errors,
1, memory_order_relaxed);
memory_order_relaxed);
break;
+ case DPLANE_OP_NEIGH_TABLE_UPDATE:
+ if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
+ atomic_fetch_add_explicit(
+ &zdplane_info.dg_neightable_errors, 1,
+ memory_order_relaxed);
+ break;
+
/* Ignore 'notifications' - no-op */
case DPLANE_OP_SYS_ROUTE_ADD:
case DPLANE_OP_SYS_ROUTE_DELETE:
DPLANE_OP_IPSET_DELETE,
DPLANE_OP_IPSET_ENTRY_ADD,
DPLANE_OP_IPSET_ENTRY_DELETE,
+
+ /* LINK LAYER IP address update */
+ DPLANE_OP_NEIGH_IP_INSTALL,
+ DPLANE_OP_NEIGH_IP_DELETE,
+
+ DPLANE_OP_NEIGH_TABLE_UPDATE,
};
/*
#define DPLANE_NUD_NOARP 0x04
#define DPLANE_NUD_PROBE 0x08
#define DPLANE_NUD_INCOMPLETE 0x10
+#define DPLANE_NUD_PERMANENT 0x20
+#define DPLANE_NUD_FAILED 0x40
/* MAC update flags - dplane_mac_info.update_flags */
#define DPLANE_MAC_REMOTE (1 << 0)
#define DPLANE_NEIGH_WAS_STATIC (1 << 1)
#define DPLANE_NEIGH_SET_STATIC (1 << 2)
#define DPLANE_NEIGH_SET_INACTIVE (1 << 3)
+#define DPLANE_NEIGH_NO_EXTENSION (1 << 4)
#define DPLANE_BR_PORT_NON_DF (1 << 0)
const struct zebra_dplane_ctx *ctx);
const struct ethaddr *dplane_ctx_neigh_get_mac(
const struct zebra_dplane_ctx *ctx);
+const struct ipaddr *
+dplane_ctx_neigh_get_link_ip(const struct zebra_dplane_ctx *ctx);
uint32_t dplane_ctx_neigh_get_flags(const struct zebra_dplane_ctx *ctx);
uint16_t dplane_ctx_neigh_get_state(const struct zebra_dplane_ctx *ctx);
uint32_t dplane_ctx_neigh_get_update_flags(const struct zebra_dplane_ctx *ctx);
uint32_t
dplane_ctx_get_br_port_backup_nhg_id(const struct zebra_dplane_ctx *ctx);
+/* Accessors for neighbor table information */
+uint8_t dplane_ctx_neightable_get_family(const struct zebra_dplane_ctx *ctx);
+uint32_t
+dplane_ctx_neightable_get_app_probes(const struct zebra_dplane_ctx *ctx);
+uint32_t
+dplane_ctx_neightable_get_mcast_probes(const struct zebra_dplane_ctx *ctx);
+uint32_t
+dplane_ctx_neightable_get_ucast_probes(const struct zebra_dplane_ctx *ctx);
+
/* Namespace info - esp. for netlink communication */
const struct zebra_dplane_info *dplane_ctx_get_ns(
const struct zebra_dplane_ctx *ctx);
enum zebra_dplane_result dplane_intf_addr_unset(const struct interface *ifp,
const struct connected *ifc);
+/*
+ * Link layer operations for the dataplane.
+ */
+enum zebra_dplane_result dplane_neigh_ip_update(enum dplane_op_e op,
+ const struct interface *ifp,
+ struct ipaddr *link_ip,
+ struct ipaddr *ip,
+ uint32_t ndm_state,
+ int protocol);
+
/*
* Enqueue evpn mac operations for the dataplane.
*/
enum zebra_dplane_result dplane_neigh_discover(const struct interface *ifp,
const struct ipaddr *ip);
+/*
+ * Enqueue a neighbor table parameter set
+ */
+enum zebra_dplane_result dplane_neigh_table_update(const struct interface *ifp,
+ const uint8_t family,
+ const uint32_t app_probes,
+ const uint32_t ucast_probes,
+ const uint32_t mcast_probes);
+
/* Forward ref of zebra_pbr_rule */
struct zebra_pbr_rule;
case DPLANE_OP_NEIGH_INSTALL:
case DPLANE_OP_NEIGH_UPDATE:
case DPLANE_OP_NEIGH_DELETE:
+ case DPLANE_OP_NEIGH_IP_INSTALL:
+ case DPLANE_OP_NEIGH_IP_DELETE:
case DPLANE_OP_VTEP_ADD:
case DPLANE_OP_VTEP_DELETE:
case DPLANE_OP_RULE_ADD:
case DPLANE_OP_IPSET_DELETE:
case DPLANE_OP_IPSET_ENTRY_ADD:
case DPLANE_OP_IPSET_ENTRY_DELETE:
+ case DPLANE_OP_NEIGH_TABLE_UPDATE:
break;
}
case DPLANE_OP_NEIGH_INSTALL:
case DPLANE_OP_NEIGH_UPDATE:
case DPLANE_OP_NEIGH_DELETE:
+ case DPLANE_OP_NEIGH_IP_INSTALL:
+ case DPLANE_OP_NEIGH_IP_DELETE:
case DPLANE_OP_VTEP_ADD:
case DPLANE_OP_VTEP_DELETE:
case DPLANE_OP_NEIGH_DISCOVER:
case DPLANE_OP_BR_PORT_UPDATE:
+ case DPLANE_OP_NEIGH_TABLE_UPDATE:
case DPLANE_OP_NONE:
/* Don't expect this: just return the struct? */
dplane_ctx_fini(&ctx);
vrf_bitmap_free(client->redist_default[afi]);
vrf_bitmap_free(client->ridinfo[afi]);
+ vrf_bitmap_free(client->nhrp_neighinfo[afi]);
}
/*
client->redist[afi][i] = vrf_bitmap_init();
client->redist_default[afi] = vrf_bitmap_init();
client->ridinfo[afi] = vrf_bitmap_init();
+ client->nhrp_neighinfo[afi] = vrf_bitmap_init();
}
/* Add this client to linked list. */
/* Router-id information. */
vrf_bitmap_t ridinfo[AFI_MAX];
+ /* Router-id information. */
+ vrf_bitmap_t nhrp_neighinfo[AFI_MAX];
+
bool notify_owner;
/* Indicates if client is synchronous. */