--- /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
+
## Process this file with automake to produce Makefile.in.
AUTOMAKE_OPTIONS = subdir-objects 1.12
-ACLOCAL_AMFLAGS = -I m4
+ACLOCAL_AMFLAGS = -I m4 -Wall,no-override
AM_CFLAGS = \
+ $(AC_CFLAGS) \
$(LIBYANG_CFLAGS) \
$(SQLITE3_CFLAGS) \
$(UNWIND_CFLAGS) \
$(SAN_FLAGS) \
$(WERROR) \
# end
-AM_CPPFLAGS = \
+
+# CPPFLAGS_BASE does not contain the include path for overriding assert.h,
+# therefore should be used in tools that do *not* link libfrr or do not want
+# assert() overridden
+CPPFLAGS_BASE = \
-I$(top_srcdir) -I$(top_srcdir)/include -I$(top_srcdir)/lib \
- -I$(top_builddir) -I$(top_builddir)/include -I$(top_builddir)/lib \
+ -I$(top_builddir) \
$(LUA_INCLUDE) \
# end
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/lib/assert \
+ $(CPPFLAGS_BASE) \
+ # end
AM_LDFLAGS = \
-export-dynamic \
$(AC_LDFLAGS) \
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"
#include "thread.h"
#include "privs.h"
#include "sigevent.h"
-#include "version.h"
+#include "lib/version.h"
#include "command.h"
#include "vty.h"
#include "memory.h"
return CMD_SUCCESS;
}
+DEFUN (babel_distribute_list,
+ babel_distribute_list_cmd,
+ "distribute-list [prefix] WORD <in|out> [WORD]",
+ "Filter networks in routing updates\n"
+ "Specify a prefix\n"
+ "Access-list name\n"
+ "Filter incoming routing updates\n"
+ "Filter outgoing routing updates\n"
+ "Interface name\n")
+{
+ const char *ifname = NULL;
+ int prefix = (argv[1]->type == WORD_TKN) ? 1 : 0;
+
+ if (argv[argc - 1]->type == VARIABLE_TKN)
+ ifname = argv[argc - 1]->arg;
+
+ return distribute_list_parser(prefix, true, argv[2 + prefix]->text,
+ argv[1 + prefix]->arg, ifname);
+}
+
+DEFUN (babel_no_distribute_list,
+ babel_no_distribute_list_cmd,
+ "no distribute-list [prefix] WORD <in|out> [WORD]",
+ NO_STR
+ "Filter networks in routing updates\n"
+ "Specify a prefix\n"
+ "Access-list name\n"
+ "Filter incoming routing updates\n"
+ "Filter outgoing routing updates\n"
+ "Interface name\n")
+{
+ const char *ifname = NULL;
+ int prefix = (argv[2]->type == WORD_TKN) ? 1 : 0;
+
+ if (argv[argc - 1]->type == VARIABLE_TKN)
+ ifname = argv[argc - 1]->arg;
+
+ return distribute_list_no_parser(vty, prefix, true,
+ argv[3 + prefix]->text,
+ argv[2 + prefix]->arg, ifname);
+}
+
+DEFUN (babel_ipv6_distribute_list,
+ babel_ipv6_distribute_list_cmd,
+ "ipv6 distribute-list [prefix] WORD <in|out> [WORD]",
+ "IPv6\n"
+ "Filter networks in routing updates\n"
+ "Specify a prefix\n"
+ "Access-list name\n"
+ "Filter incoming routing updates\n"
+ "Filter outgoing routing updates\n"
+ "Interface name\n")
+{
+ const char *ifname = NULL;
+ int prefix = (argv[2]->type == WORD_TKN) ? 1 : 0;
+
+ if (argv[argc - 1]->type == VARIABLE_TKN)
+ ifname = argv[argc - 1]->arg;
+
+ return distribute_list_parser(prefix, false, argv[3 + prefix]->text,
+ argv[2 + prefix]->arg, ifname);
+}
+
+DEFUN (babel_no_ipv6_distribute_list,
+ babel_no_ipv6_distribute_list_cmd,
+ "no ipv6 distribute-list [prefix] WORD <in|out> [WORD]",
+ NO_STR
+ "IPv6\n"
+ "Filter networks in routing updates\n"
+ "Specify a prefix\n"
+ "Access-list name\n"
+ "Filter incoming routing updates\n"
+ "Filter outgoing routing updates\n"
+ "Interface name\n")
+{
+ const char *ifname = NULL;
+ int prefix = (argv[3]->type == WORD_TKN) ? 1 : 0;
+
+ if (argv[argc - 1]->type == VARIABLE_TKN)
+ ifname = argv[argc - 1]->arg;
+
+ return distribute_list_no_parser(vty, prefix, false,
+ argv[4 + prefix]->text,
+ argv[3 + prefix]->arg, ifname);
+}
+
void
babeld_quagga_init(void)
{
install_element(BABEL_NODE, &babel_set_resend_delay_cmd);
install_element(BABEL_NODE, &babel_set_smoothing_half_life_cmd);
+ install_element(BABEL_NODE, &babel_distribute_list_cmd);
+ install_element(BABEL_NODE, &babel_no_distribute_list_cmd);
+ install_element(BABEL_NODE, &babel_ipv6_distribute_list_cmd);
+ install_element(BABEL_NODE, &babel_no_ipv6_distribute_list_cmd);
+
babel_if_init();
/* Access list install. */
prefix_list_init ();
prefix_list_add_hook (babel_distribute_update_all);
prefix_list_delete_hook (babel_distribute_update_all);
-
- /* Distribute list install. */
- distribute_list_init(BABEL_NODE);
}
/* Stubs to adapt Babel's filtering calls to Quagga's infrastructure. */
if (p->nexthop.ifp)
bfd_sess_set_interface(p->bfd_config->session,
p->nexthop.ifp->name);
-
- bfd_sess_enable(p->bfd_config->session, true);
}
static void bgp_peer_remove_bfd(struct peer *p)
#include "lib_errors.h"
#include "stream.h"
#include "libfrr.h"
-#include "version.h"
+#include "lib/version.h"
#include "jhash.h"
#include "termtable.h"
}
if (str) {
- if (!lcommunity_list_valid(str, style))
- return COMMUNITY_LIST_ERR_MALFORMED_VAL;
-
if (style == LARGE_COMMUNITY_LIST_STANDARD)
lcom = lcommunity_str2com(str);
else
#include "bgpd/bgp_memory.h"
#include "bgpd/bgp_community.h"
+#include "bgpd/bgp_community_alias.h"
/* Hash of community attribute. */
static struct hash *comhash;
len += strlen(" no-peer");
break;
default:
- len += strlen(" 65536:65535");
+ len = BUFSIZ;
break;
}
}
val = comval & 0xFFFF;
char buf[32];
snprintf(buf, sizeof(buf), "%u:%d", as, val);
- strlcat(str, buf, len);
+ strlcat(str, bgp_community2alias(buf), len);
if (make_json) {
json_string = json_object_new_string(buf);
json_object_array_add(json_community_list,
--- /dev/null
+/* BGP community, large-community aliasing.
+ *
+ * Copyright (C) 2021 Donatas Abraitis <donatas.abraitis@gmail.com>
+ *
+ * This file is part of FRRouting (FRR).
+ *
+ * FRR is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2, or (at your option) any later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "memory.h"
+#include "lib/jhash.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_community_alias.h"
+
+static struct hash *bgp_ca_alias_hash;
+static struct hash *bgp_ca_community_hash;
+
+static unsigned int bgp_ca_community_hash_key(const void *p)
+{
+ const struct community_alias *ca = p;
+
+ return jhash(ca->community, sizeof(ca->community), 0);
+}
+
+static bool bgp_ca_community_hash_cmp(const void *p1, const void *p2)
+{
+ const struct community_alias *ca1 = p1;
+ const struct community_alias *ca2 = p2;
+
+ return (strncmp(ca1->community, ca2->community,
+ sizeof(struct community_alias))
+ == 0);
+}
+
+static unsigned int bgp_ca_alias_hash_key(const void *p)
+{
+ const struct community_alias *ca = p;
+
+ return jhash(ca->alias, sizeof(ca->alias), 0);
+}
+
+static bool bgp_ca_alias_hash_cmp(const void *p1, const void *p2)
+{
+ const struct community_alias *ca1 = p1;
+ const struct community_alias *ca2 = p2;
+
+ return (strncmp(ca1->alias, ca2->alias, sizeof(struct community_alias))
+ == 0);
+}
+
+static void *bgp_community_alias_alloc(void *p)
+{
+ const struct community_alias *ca = p;
+ struct communtiy_alias *new;
+
+ new = XCALLOC(MTYPE_COMMUNITY_ALIAS, sizeof(struct community_alias));
+ memcpy(new, ca, sizeof(struct community_alias));
+
+ return new;
+}
+
+void bgp_community_alias_init(void)
+{
+ bgp_ca_community_hash = hash_create(bgp_ca_community_hash_key,
+ bgp_ca_community_hash_cmp,
+ "BGP community alias (community)");
+ bgp_ca_alias_hash =
+ hash_create(bgp_ca_alias_hash_key, bgp_ca_alias_hash_cmp,
+ "BGP community alias (alias)");
+}
+
+void bgp_community_alias_finish(void)
+{
+ hash_free(bgp_ca_community_hash);
+ hash_free(bgp_ca_alias_hash);
+}
+
+static void bgp_community_alias_show_iterator(struct hash_bucket *hb,
+ struct vty *vty)
+{
+ struct community_alias *ca = hb->data;
+
+ vty_out(vty, "bgp community alias %s %s\n", ca->community, ca->alias);
+}
+
+int bgp_community_alias_write(struct vty *vty)
+{
+ hash_iterate(bgp_ca_community_hash,
+ (void (*)(struct hash_bucket *,
+ void *))bgp_community_alias_show_iterator,
+ vty);
+ return 1;
+}
+
+void bgp_ca_community_insert(struct community_alias *ca)
+{
+ hash_get(bgp_ca_community_hash, ca, bgp_community_alias_alloc);
+}
+
+void bgp_ca_alias_insert(struct community_alias *ca)
+{
+ hash_get(bgp_ca_alias_hash, ca, bgp_community_alias_alloc);
+}
+
+void bgp_ca_community_delete(struct community_alias *ca)
+{
+ struct community_alias *data = hash_release(bgp_ca_community_hash, ca);
+
+ XFREE(MTYPE_COMMUNITY_ALIAS, data);
+}
+
+void bgp_ca_alias_delete(struct community_alias *ca)
+{
+ struct community_alias *data = hash_release(bgp_ca_alias_hash, ca);
+
+ XFREE(MTYPE_COMMUNITY_ALIAS, data);
+}
+
+struct community_alias *bgp_ca_community_lookup(struct community_alias *ca)
+{
+ return hash_lookup(bgp_ca_community_hash, ca);
+}
+
+struct community_alias *bgp_ca_alias_lookup(struct community_alias *ca)
+{
+ return hash_lookup(bgp_ca_alias_hash, ca);
+}
+
+const char *bgp_community2alias(char *community)
+{
+ struct community_alias ca;
+ struct community_alias *find;
+
+ memset(&ca, 0, sizeof(ca));
+ strlcpy(ca.community, community, sizeof(ca.community));
+
+ find = bgp_ca_community_lookup(&ca);
+ if (find)
+ return find->alias;
+
+ return community;
+}
--- /dev/null
+/* BGP community, large-community aliasing.
+ *
+ * Copyright (C) 2021 Donatas Abraitis <donatas.abraitis@gmail.com>
+ *
+ * This file is part of FRRouting (FRR).
+ *
+ * FRR is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2, or (at your option) any later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "bgpd/bgp_lcommunity.h"
+
+#ifndef FRR_BGP_COMMUNITY_ALIAS_H
+#define FRR_BGP_COMMUNITY_ALIAS_H
+
+struct community_alias {
+ /* Human readable community string */
+ char community[LCOMMUNITY_SIZE * 3];
+
+ /* Human readable community alias */
+ char alias[BUFSIZ];
+};
+
+extern void bgp_community_alias_init(void);
+extern void bgp_community_alias_finish(void);
+extern struct community_alias *bgp_ca_alias_lookup(struct community_alias *ca);
+extern struct community_alias *
+bgp_ca_community_lookup(struct community_alias *ca);
+extern void bgp_ca_community_insert(struct community_alias *ca);
+extern void bgp_ca_alias_insert(struct community_alias *ca);
+extern void bgp_ca_community_delete(struct community_alias *ca);
+extern void bgp_ca_alias_delete(struct community_alias *ca);
+extern int bgp_community_alias_write(struct vty *vty);
+extern const char *bgp_community2alias(char *community);
+
+#endif /* FRR_BGP_COMMUNITY_ALIAS_H */
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <zebra.h>
+
#include "bgpd/bgp_conditional_adv.h"
#include "bgpd/bgp_vty.h"
bgp_dump_routes_attr(obuf, path->attr, p);
cur_endp = stream_get_endp(obuf);
- if (cur_endp > BGP_MAX_PACKET_SIZE + BGP_DUMP_MSG_HEADER
+ if (cur_endp > BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE
+ + BGP_DUMP_MSG_HEADER
+ BGP_DUMP_HEADER_SIZE) {
stream_set_endp(obuf, endp);
break;
memset(&bgp_dump_routes, 0, sizeof(struct bgp_dump));
bgp_dump_obuf =
- stream_new((BGP_MAX_PACKET_SIZE << 1) + BGP_DUMP_MSG_HEADER
- + BGP_DUMP_HEADER_SIZE);
+ stream_new((BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE * 2)
+ + BGP_DUMP_MSG_HEADER + BGP_DUMP_HEADER_SIZE);
install_node(&bgp_dump_node);
/* Delete the selected value */
ecom->size--;
- p = XMALLOC(MTYPE_ECOMMUNITY_VAL, ecom->size * ecom->unit_size);
- if (c != 0)
- memcpy(p, ecom->val, c * ecom->unit_size);
- if ((ecom->size - c) != 0)
- memcpy(p + (c)*ecom->unit_size,
- ecom->val + (c + 1) * ecom->unit_size,
- (ecom->size - c) * ecom->unit_size);
- XFREE(MTYPE_ECOMMUNITY_VAL, ecom->val);
- ecom->val = p;
+ if (ecom->size) {
+ p = XMALLOC(MTYPE_ECOMMUNITY_VAL, ecom->size * ecom->unit_size);
+ if (c != 0)
+ memcpy(p, ecom->val, c * ecom->unit_size);
+ if ((ecom->size - c) != 0)
+ memcpy(p + (c)*ecom->unit_size,
+ ecom->val + (c + 1) * ecom->unit_size,
+ (ecom->size - c) * ecom->unit_size);
+ XFREE(MTYPE_ECOMMUNITY_VAL, ecom->val);
+ ecom->val = p;
+ } else
+ ecom->val = NULL;
+
return true;
}
uint8_t flags, uint32_t seq, esi_t *esi)
{
struct stream *s;
- int ipa_len;
+ uint16_t ipa_len;
static struct in_addr zero_remote_vtep_ip;
/* Check socket. */
stream_put(s, &p->prefix.macip_addr.mac.octet, ETH_ALEN); /* Mac Addr */
/* IP address length and IP address, if any. */
if (is_evpn_prefix_ipaddr_none(p))
- stream_putl(s, 0);
+ stream_putw(s, 0);
else {
ipa_len = is_evpn_prefix_ipaddr_v4(p) ? IPV4_MAX_BYTELEN
: IPV6_MAX_BYTELEN;
- stream_putl(s, ipa_len);
+ stream_putw(s, ipa_len);
stream_put(s, &p->prefix.macip_addr.ip.ip.addr, ipa_len);
}
/* If the ESI is valid that becomes the nexthop; tape out the
{
return p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE
&& (is_evpn_prefix_ipaddr_v4(p)
- || !IN6_IS_ADDR_LINKLOCAL(
- &p->prefix.macip_addr.ip.ipaddr_v6))
+ || (is_evpn_prefix_ipaddr_v6(p)
+ && !IN6_IS_ADDR_LINKLOCAL(
+ &p->prefix.macip_addr.ip.ipaddr_v6)))
&& CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS)
&& bgpevpn_get_l3vni(vpn) && bgp_evpn_es_add_l3_ecomm_ok(esi);
}
switch (ret) {
case BGP_ERR_AS_MISMATCH:
flog_err(EC_BGP_EVPN_AS_MISMATCH,
- "BGP is already running; AS is %u", as);
+ "BGP instance is already running; AS is %u",
+ as);
return -1;
case BGP_ERR_INSTANCE_MISMATCH:
flog_err(EC_BGP_EVPN_INSTANCE_MISMATCH,
- "BGP instance name and AS number mismatch");
+ "BGP instance type mismatch");
return -1;
}
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);
}
/* AS path filter master. */
struct as_list_master {
- /* List of access_list which name is number. */
- struct as_list_list num;
-
/* List of access_list which name is string. */
struct as_list_list str;
struct as_list {
char *name;
- enum access_type type;
-
struct as_list *next;
struct as_list *prev;
/* as-path access-list 10 permit AS1. */
static struct as_list_master as_list_master = {{NULL, NULL},
- {NULL, NULL},
NULL,
NULL};
if (name == NULL)
return NULL;
- for (aslist = as_list_master.num.head; aslist; aslist = aslist->next)
- if (strcmp(aslist->name, name) == 0)
- return aslist;
-
for (aslist = as_list_master.str.head; aslist; aslist = aslist->next)
if (strcmp(aslist->name, name) == 0)
return aslist;
the name. */
static struct as_list *as_list_insert(const char *name)
{
- size_t i;
- long number;
struct as_list *aslist;
struct as_list *point;
struct as_list_list *list;
aslist->name = XSTRDUP(MTYPE_AS_STR, name);
assert(aslist->name);
- /* If name is made by all digit character. We treat it as
- number. */
- for (number = 0, i = 0; i < strlen(name); i++) {
- if (isdigit((unsigned char)name[i]))
- number = (number * 10) + (name[i] - '0');
- else
- break;
- }
-
- /* In case of name is all digit character */
- if (i == strlen(name)) {
- aslist->type = ACCESS_TYPE_NUMBER;
-
- /* Set access_list to number list. */
- list = &as_list_master.num;
-
- for (point = list->head; point; point = point->next)
- if (atol(point->name) >= number)
- break;
- } else {
- aslist->type = ACCESS_TYPE_STRING;
-
- /* Set access_list to string list. */
- list = &as_list_master.str;
+ /* Set access_list to string list. */
+ list = &as_list_master.str;
- /* Set point to insertion point. */
- for (point = list->head; point; point = point->next)
- if (strcmp(point->name, name) >= 0)
- break;
- }
+ /* Set point to insertion point. */
+ for (point = list->head; point; point = point->next)
+ if (strcmp(point->name, name) >= 0)
+ break;
/* In case of this is the first element of master. */
if (list->head == NULL) {
as_filter_free(filter);
}
- if (aslist->type == ACCESS_TYPE_NUMBER)
- list = &as_list_master.num;
- else
- list = &as_list_master.str;
+ list = &as_list_master.str;
if (aslist->next)
aslist->next->prev = aslist->prev;
struct as_list *aslist;
struct as_filter *asfilter;
- for (aslist = as_list_master.num.head; aslist; aslist = aslist->next) {
- vty_out(vty, "AS path access list %s\n", aslist->name);
-
- for (asfilter = aslist->head; asfilter;
- asfilter = asfilter->next) {
- vty_out(vty, " %s %s\n",
- filter_type_str(asfilter->type),
- asfilter->reg_str);
- }
- }
-
for (aslist = as_list_master.str.head; aslist; aslist = aslist->next) {
vty_out(vty, "AS path access list %s\n", aslist->name);
struct as_filter *asfilter;
int write = 0;
- for (aslist = as_list_master.num.head; aslist; aslist = aslist->next)
- for (asfilter = aslist->head; asfilter;
- asfilter = asfilter->next) {
- vty_out(vty,
- "bgp as-path access-list %s seq %" PRId64
- " %s %s\n",
- aslist->name, asfilter->seq,
- filter_type_str(asfilter->type),
- asfilter->reg_str);
- write++;
- }
-
for (aslist = as_list_master.str.head; aslist; aslist = aslist->next)
for (asfilter = aslist->head; asfilter;
asfilter = asfilter->next) {
struct as_list *aslist;
struct as_list *next;
- for (aslist = as_list_master.num.head; aslist; aslist = next) {
- next = aslist->next;
- as_list_delete(aslist);
- }
-
for (aslist = as_list_master.str.head; aslist; aslist = next) {
next = aslist->next;
as_list_delete(aslist);
}
- assert(as_list_master.num.head == NULL);
- assert(as_list_master.num.tail == NULL);
-
assert(as_list_master.str.head == NULL);
assert(as_list_master.str.tail == NULL);
}
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;
}
FOREACH_AFI_SAFI (afi, safi) {
- peer->af_flags[afi][safi] = from_peer->af_flags[afi][safi];
peer->af_sflags[afi][safi] = from_peer->af_sflags[afi][safi];
peer->af_cap[afi][safi] = from_peer->af_cap[afi][safi];
peer->afc_nego[afi][safi] = from_peer->afc_nego[afi][safi];
* 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 */
#include "stream.h" // for stream_get_endp, stream_getw_from, str...
#include "ringbuf.h" // for ringbuf_remain, ringbuf_peek, ringbuf_...
#include "thread.h" // for THREAD_OFF, THREAD_ARG, thread...
-#include "zassert.h" // for assert
#include "bgpd/bgp_io.h"
#include "bgpd/bgp_debug.h" // for bgp_debug_neighbor_events, bgp_type_str
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)
{
+ size_t readsize; // how many bytes we want to read
ssize_t nbytes; // how many bytes we actually read
uint16_t status = 0;
- nbytes = ringbuf_read(peer->ibuf_work, peer->fd);
+ readsize =
+ MIN(ringbuf_space(peer->ibuf_work), sizeof(peer->ibuf_scratch));
+ nbytes = read(peer->fd, peer->ibuf_scratch, readsize);
/* EAGAIN or EWOULDBLOCK; come back later */
if (nbytes < 0 && ERRNO_IO_RETRY(errno)) {
*code_p = TCP_connection_closed;
SET_FLAG(status, BGP_IO_FATAL_ERR);
+ } else {
+ assert(ringbuf_put(peer->ibuf_work, peer->ibuf_scratch, nbytes)
+ == (size_t)nbytes);
}
return status;
#include "bgpd/bgpd.h"
#include "bgpd/bgp_lcommunity.h"
+#include "bgpd/bgp_community_alias.h"
#include "bgpd/bgp_aspath.h"
/* Hash of community attribute. */
}
/* 1 space + lcom->size lcom strings + null terminator */
- size_t str_buf_sz = (LCOMMUNITY_STRLEN * lcom->size) + 2;
+ size_t str_buf_sz = BUFSIZ;
str_buf = XCALLOC(MTYPE_LCOMMUNITY_STR, str_buf_sz);
for (i = 0; i < lcom->size; i++) {
snprintf(lcsb, sizeof(lcsb), "%u:%u:%u", global, local1,
local2);
- len = strlcat(str_buf, lcsb, str_buf_sz);
+ len = strlcat(str_buf, bgp_community2alias(lcsb), str_buf_sz);
assert((unsigned int)len < str_buf_sz);
if (make_json) {
#include "bgpd/bgp_evpn_mh.h"
#include "bgpd/bgp_nht.h"
#include "bgpd/bgp_routemap_nb.h"
+#include "bgpd/bgp_community_alias.h"
#ifdef ENABLE_BGP_VNC
#include "bgpd/rfapi/rfapi_backend.h"
/* reverse bgp_dump_init */
bgp_dump_finish();
+ /* BGP community aliases */
+ bgp_community_alias_finish();
+
/* reverse bgp_route_init */
bgp_route_finish();
DEFINE_MTYPE(BGPD, AS_FILTER, "BGP AS filter");
DEFINE_MTYPE(BGPD, AS_FILTER_STR, "BGP AS filter str");
+DEFINE_MTYPE(BGPD, COMMUNITY_ALIAS, "community");
+
DEFINE_MTYPE(BGPD, COMMUNITY, "community");
DEFINE_MTYPE(BGPD, COMMUNITY_VAL, "community val");
DEFINE_MTYPE(BGPD, COMMUNITY_STR, "community str");
DECLARE_MTYPE(AS_FILTER);
DECLARE_MTYPE(AS_FILTER_STR);
+DECLARE_MTYPE(COMMUNITY_ALIAS);
+
DECLARE_MTYPE(COMMUNITY);
DECLARE_MTYPE(COMMUNITY_VAL);
DECLARE_MTYPE(COMMUNITY_STR);
if (bpi) {
bool labelssame = labels_same(bpi, label, num_labels);
+ if (CHECK_FLAG(source_bpi->flags, BGP_PATH_REMOVED)
+ && CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) {
+ if (debug) {
+ zlog_debug(
+ "%s: ->%s(s_flags: 0x%x b_flags: 0x%x): %pFX: Found route, being removed, not leaking",
+ __func__, bgp->name_pretty,
+ source_bpi->flags, bpi->flags, p);
+ }
+ return NULL;
+ }
+
if (attrhash_cmp(bpi->attr, new_attr) && labelssame
&& !CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) {
return bpi;
}
+ if (CHECK_FLAG(source_bpi->flags, BGP_PATH_REMOVED)) {
+ if (debug) {
+ zlog_debug(
+ "%s: ->%s(s_flags: 0x%x): %pFX: New route, being removed, not leaking",
+ __func__, bgp->name_pretty,
+ source_bpi->flags, p);
+ }
+ return NULL;
+ }
+
new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_IMPORTED, 0,
bgp->peer_self, new_attr, bn);
if (debug)
zlog_debug("%s: deleting it",
__func__);
+ /* withdraw from leak-to vrfs as well */
+ vpn_leak_to_vrf_withdraw(bgp_vpn, bpi);
bgp_aggregate_decrement(
bgp_vpn,
bgp_dest_get_prefix(bn), bpi,
if (!ecom_intersect(
bgp_vrf->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_FROMVPN],
path_vpn->attr->ecommunity)) {
-
+ if (debug)
+ zlog_debug(
+ "from vpn to vrf %s, skipping after no intersection of route targets",
+ bgp_vrf->name_pretty);
return;
}
bool is_config)
{
afi_t afi;
- int debug;
+ int debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF)
+ | BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF));
char *vname;
const char *export_name;
char buf[RD_ADDRSTRLEN];
struct ecommunity *ecom;
vpn_policy_direction_t idir, edir;
+ /*
+ * Router-id change that is not explicitly configured
+ * (a change from zebra, frr restart for example)
+ * should not replace a configured vpn RD/RT.
+ */
+ if (!is_config) {
+ if (debug)
+ zlog_debug("%s: skipping non explicit router-id change",
+ __func__);
+ return;
+ }
+
if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT
&& bgp->inst_type != BGP_INSTANCE_TYPE_VRF)
return;
export_name = bgp->name ? bgp->name : VRF_DEFAULT_NAME;
- debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) |
- BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF));
-
idir = BGP_VPN_POLICY_DIR_FROMVPN;
edir = BGP_VPN_POLICY_DIR_TOVPN;
if (!bgp_import)
continue;
- ecommunity_del_val(bgp_import->vpn_policy[afi].
- rtlist[idir],
+ ecommunity_del_val(
+ bgp_import->vpn_policy[afi]
+ .rtlist[idir],
(struct ecommunity_val *)ecom->val);
-
}
} else {
- /*
- * Router-id changes that are not explicit config
- * changes should not replace configured RD/RT.
- */
- if (!is_config) {
- if (CHECK_FLAG(bgp->vpn_policy[afi].flags,
- BGP_VPN_POLICY_TOVPN_RD_SET)) {
- if (debug)
- zlog_debug("%s: auto router-id change skipped",
- __func__);
- goto postchange;
- }
- }
-
/* New router-id derive auto RD and RT and export
* to VPN
*/
else
bgp_import->vpn_policy[afi].rtlist[idir]
= ecommunity_dup(ecom);
-
}
-postchange:
/* Update routes to VPN */
vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN,
afi, bgp_get_default(),
#include "filter.h"
#include "hook.h"
#include "libfrr.h"
-#include "version.h"
+#include "lib/version.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_route.h"
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <zebra.h>
+
#include "northbound.h"
#include "libfrr.h"
#include "bgpd/bgp_nb.h"
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <zebra.h>
+
#include "northbound.h"
#include "libfrr.h"
#include "log.h"
if (inst_type == BGP_INSTANCE_TYPE_DEFAULT)
is_new_bgp = (bgp_lookup(as, name) == NULL);
+ else
+ is_new_bgp = (bgp_lookup_by_name(name) == NULL);
ret = bgp_get_vty(&bgp, &as, name, inst_type);
- if (ret == BGP_ERR_INSTANCE_MISMATCH) {
- snprintf(
- args->errmsg, args->errmsg_len,
- "BGP instance name and AS number mismatch\nBGP instance is already running; AS is %u, input-as %u",
- bgp->as, as);
-
+ switch (ret) {
+ case BGP_ERR_AS_MISMATCH:
+ snprintf(args->errmsg, args->errmsg_len,
+ "BGP instance is already running; AS is %u",
+ as);
+ return NB_ERR_INCONSISTENCY;
+ case BGP_ERR_INSTANCE_MISMATCH:
+ snprintf(args->errmsg, args->errmsg_len,
+ "BGP instance type mismatch");
return NB_ERR_INCONSISTENCY;
}
+
/*
* If we just instantiated the default instance, complete
* any pending VRF-VPN leaking that was configured via
if (is_new_bgp && inst_type == BGP_INSTANCE_TYPE_DEFAULT)
vpn_leak_postchange_all();
- if (inst_type == BGP_INSTANCE_TYPE_VRF)
+ /*
+ * Check if we need to export to other VRF(s).
+ * Leak the routes to importing bgp vrf instances,
+ * only when new bgp vrf instance is configured.
+ */
+ if (is_new_bgp)
bgp_vpn_leak_export(bgp);
UNSET_FLAG(bgp->vrf_flags, BGP_VRF_AUTO);
inst_type = BGP_INSTANCE_TYPE_VIEW;
ret = bgp_lookup_by_as_name_type(&bgp, &as, name, inst_type);
- if (ret == BGP_ERR_INSTANCE_MISMATCH) {
- snprintf(
- args->errmsg, args->errmsg_len,
- "BGP instance name and AS number mismatch\nBGP instance is already running; input-as %u",
- as);
-
+ switch (ret) {
+ case BGP_ERR_AS_MISMATCH:
+ snprintf(args->errmsg, args->errmsg_len,
+ "BGP instance is already running; AS is %u",
+ as);
+ return NB_ERR_VALIDATION;
+ case BGP_ERR_INSTANCE_MISMATCH:
+ snprintf(args->errmsg, args->errmsg_len,
+ "BGP instance type mismatch");
return NB_ERR_VALIDATION;
}
-
break;
case NB_EV_PREPARE:
case NB_EV_ABORT:
accept_sock);
return -1;
}
- listener->thread = NULL;
thread_add_read(bm->master, bgp_accept, listener, accept_sock,
&listener->thread);
if (peer1) {
/* Dynamic neighbor has been created, let it proceed */
peer1->fd = bgp_sock;
+
+ /* Set the user configured MSS to TCP socket */
+ if (CHECK_FLAG(peer1->flags, PEER_FLAG_TCP_MSS))
+ sockopt_tcp_mss_set(bgp_sock, peer1->tcp_mss);
+
bgp_fsm_change_status(peer1, Active);
BGP_TIMER_OFF(
peer1->t_start); /* created in peer_create() */
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() */
set_nonblocking(peer->fd);
+ /* Set the user configured MSS to TCP socket */
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_TCP_MSS))
+ sockopt_tcp_mss_set(peer->fd, peer->tcp_mss);
+
bgp_socket_set_buffer_size(peer->fd);
if (bgp_set_socket_ttl(peer, peer->fd) < 0)
listener->bgp = bgp;
memcpy(&listener->su, sa, salen);
- listener->thread = NULL;
thread_add_read(bm->master, bgp_accept, listener, sock,
&listener->thread);
listnode_add(bm->listen_sockets, listener);
static int bgp_isvalid_nexthop(struct bgp_nexthop_cache *bnc)
{
return (bgp_zebra_num_connects() == 0
- || (bnc && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)));
+ || (bnc && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)
+ && bnc->nexthop_num > 0));
}
static int bgp_isvalid_labeled_nexthop(struct bgp_nexthop_cache *bnc)
{
return (bgp_zebra_num_connects() == 0
- || (bnc && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID)));
+ || (bnc && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID)
+ && bnc->nexthop_num > 0));
}
static void bgp_unlink_nexthop_check(struct bgp_nexthop_cache *bnc)
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
bnc->nexthop = nhlist_head;
} else {
bnc->flags &= ~BGP_NEXTHOP_VALID;
+ bnc->flags &= ~BGP_NEXTHOP_LABELED_VALID;
bnc->nexthop_num = nhr->nexthop_num;
/* notify bgp fsm if nbr ip goes from valid->invalid */
*/
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
{
int ret = 0;
uint8_t *error;
- uint8_t error_data[BGP_MAX_PACKET_SIZE];
+ uint8_t error_data[BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE];
struct stream *s = BGP_INPUT(peer);
size_t end = stream_get_getp(s) + length;
/* Extended Message Support */
peer->max_packet_size =
CHECK_FLAG(peer->cap, PEER_CAP_EXTENDED_MESSAGE_RCV)
- ? BGP_MAX_EXTENDED_MESSAGE_PACKET_SIZE
- : BGP_MAX_PACKET_SIZE;
+ ? BGP_EXTENDED_MESSAGE_MAX_PACKET_SIZE
+ : BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE;
/* Check there are no common AFI/SAFIs and send Unsupported Capability
error. */
{
struct stream *s;
- s = stream_new(BGP_MAX_PACKET_SIZE);
+ s = stream_new(BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE);
/* Make keepalive packet. */
bgp_packet_set_marker(s, BGP_MSG_KEEPALIVE);
else
local_as = peer->local_as;
- s = stream_new(BGP_MAX_PACKET_SIZE);
+ s = stream_new(BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE);
/* Make open packet. */
bgp_packet_set_marker(s, BGP_MSG_OPEN);
*/
if (peer->curr) {
size_t packetsize = stream_get_endp(peer->curr);
- assert(packetsize <= sizeof(peer->last_reset_cause));
+ assert(packetsize <= peer->max_packet_size);
memcpy(peer->last_reset_cause, peer->curr->data, packetsize);
peer->last_reset_cause_size = packetsize;
}
{
struct peer *peer;
- /* Upon receipt of an OPEN message, the local system must examine
- all of its connections that are in the OpenConfirm state. A BGP
- speaker may also examine connections in an OpenSent state if it
- knows the BGP Identifier of the peer by means outside of the
- protocol. If among these connections there is a connection to a
- remote BGP speaker whose BGP Identifier equals the one in the
- OPEN message, then the local system performs the following
- collision resolution procedure: */
-
- if ((peer = new->doppelganger) != NULL) {
- /* Do not accept the new connection in Established or Clearing
- * states.
- * Note that a peer GR is handled by closing the existing
- * connection
- * upon receipt of new one.
+ /*
+ * Upon receipt of an OPEN message, the local system must examine
+ * all of its connections that are in the OpenConfirm state. A BGP
+ * speaker may also examine connections in an OpenSent state if it
+ * knows the BGP Identifier of the peer by means outside of the
+ * protocol. If among these connections there is a connection to a
+ * remote BGP speaker whose BGP Identifier equals the one in the
+ * OPEN message, then the local system performs the following
+ * collision resolution procedure:
+ */
+ peer = new->doppelganger;
+ if (peer == NULL)
+ return 0;
+
+ /*
+ * Do not accept the new connection in Established or Clearing
+ * states. Note that a peer GR is handled by closing the existing
+ * connection upon receipt of new one.
+ */
+ if (peer->status == Established || peer->status == Clearing) {
+ bgp_notify_send(new, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_COLLISION_RESOLUTION);
+ return -1;
+ }
+
+ if ((peer->status != OpenConfirm) && (peer->status != OpenSent))
+ return 0;
+
+ /*
+ * 1. The BGP Identifier of the local system is
+ * compared to the BGP Identifier of the remote
+ * system (as specified in the OPEN message).
+ *
+ * If the BGP Identifiers of the peers
+ * involved in the connection collision
+ * are identical, then the connection
+ * initiated by the BGP speaker with the
+ * larger AS number is preserved.
+ */
+ if (ntohl(peer->local_id.s_addr) < ntohl(remote_id.s_addr)
+ || (ntohl(peer->local_id.s_addr) == ntohl(remote_id.s_addr)
+ && peer->local_as < peer->as))
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER)) {
+ /*
+ * 2. If the value of the local BGP
+ * Identifier is less than the remote one,
+ * the local system closes BGP connection
+ * that already exists (the one that is
+ * already in the OpenConfirm state),
+ * and accepts BGP connection initiated by
+ * the remote system.
+ */
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_COLLISION_RESOLUTION);
+ return 1;
+ } else {
+ bgp_notify_send(new, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_COLLISION_RESOLUTION);
+ return -1;
+ }
+ else {
+ if (ntohl(peer->local_id.s_addr) == ntohl(remote_id.s_addr)
+ && peer->local_as == peer->as)
+ flog_err(EC_BGP_ROUTER_ID_SAME,
+ "Peer's router-id %pI4 is the same as ours",
+ &remote_id);
+
+ /*
+ * 3. Otherwise, the local system closes newly
+ * created BGP connection (the one associated with the
+ * newly received OPEN message), and continues to use
+ * the existing one (the one that is already in the
+ * OpenConfirm state).
*/
- if (peer->status == Established || peer->status == Clearing) {
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER)) {
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_COLLISION_RESOLUTION);
+ return 1;
+ } else {
bgp_notify_send(new, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_COLLISION_RESOLUTION);
return -1;
- } else if ((peer->status == OpenConfirm)
- || (peer->status == OpenSent)) {
- /* 1. The BGP Identifier of the local system is
- * compared to the BGP Identifier of the remote
- * system (as specified in the OPEN message).
- *
- * If the BGP Identifiers of the peers
- * involved in the connection collision
- * are identical, then the connection
- * initiated by the BGP speaker with the
- * larger AS number is preserved.
- */
- if (ntohl(peer->local_id.s_addr)
- < ntohl(remote_id.s_addr)
- || (ntohl(peer->local_id.s_addr)
- == ntohl(remote_id.s_addr)
- && peer->local_as < peer->as))
- if (!CHECK_FLAG(peer->sflags,
- PEER_STATUS_ACCEPT_PEER)) {
- /* 2. If the value of the local BGP
- Identifier is less
- than the remote one, the local system
- closes BGP
- connection that already exists (the
- one that is
- already in the OpenConfirm state),
- and accepts BGP
- connection initiated by the remote
- system. */
- bgp_notify_send(
- peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_COLLISION_RESOLUTION);
- return 1;
- } else {
- bgp_notify_send(
- new, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_COLLISION_RESOLUTION);
- return -1;
- }
- else {
- if (ntohl(peer->local_id.s_addr)
- == ntohl(remote_id.s_addr)
- && peer->local_as == peer->as)
- flog_err(
- EC_BGP_ROUTER_ID_SAME,
- "Peer's router-id %pI4 is the same as ours",
- &remote_id);
-
- /* 3. Otherwise, the local system closes newly
- created
- BGP connection (the one associated with the
- newly
- received OPEN message), and continues to use
- the
- existing one (the one that is already in the
- OpenConfirm state). */
- if (CHECK_FLAG(peer->sflags,
- PEER_STATUS_ACCEPT_PEER)) {
- bgp_notify_send(
- peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_COLLISION_RESOLUTION);
- return 1;
- } else {
- bgp_notify_send(
- new, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_COLLISION_RESOLUTION);
- return -1;
- }
- }
}
}
- return 0;
}
/* Packet processing routines ---------------------------------------------- */
return BGP_Stop;
}
- /* Set remote router-id */
- peer->remote_id = remote_id;
-
/* Peer BGP version check. */
if (version != BGP_VERSION_4) {
uint16_t maxver = htons(BGP_VERSION_4);
return BGP_Stop;
}
+ /*
+ * When collision is detected and this peer is closed.
+ * Return immediately.
+ */
+ ret = bgp_collision_detect(peer, remote_id);
+ if (ret < 0)
+ return BGP_Stop;
+
+ /* Get sockname. */
+ if (bgp_getsockname(peer) < 0) {
+ flog_err_sys(EC_LIB_SOCKET,
+ "%s: bgp_getsockname() failed for peer: %s",
+ __func__, peer->host);
+ return BGP_Stop;
+ }
+
+ /* Set remote router-id */
+ peer->remote_id = remote_id;
+
/* From the rfc: Upon receipt of an OPEN message, a BGP speaker MUST
calculate the value of the Hold Timer by using the smaller of its
configured Hold Time and the Hold Time received in the OPEN message.
peer->afc[AFI_IP6][SAFI_FLOWSPEC];
}
- /* When collision is detected and this peer is closed.
- * Return immediately.
- */
- ret = bgp_collision_detect(peer, remote_id);
- if (ret < 0)
- return BGP_Stop;
-
- /* Get sockname. */
- if (bgp_getsockname(peer) < 0) {
- flog_err_sys(EC_LIB_SOCKET,
- "%s: bgp_getsockname() failed for peer: %s",
- __func__, peer->host);
- return BGP_Stop;
- }
-
/* Verify valid local address present based on negotiated
* address-families. */
if (peer->afc_nego[AFI_IP][SAFI_UNICAST]
return;
if (bpf->protocol != IPPROTO_ICMP)
return;
+
+ memset(&srcp, 0, sizeof(srcp));
+ memset(&dstp, 0, sizeof(dstp));
bpf->src_port = &srcp;
bpf->dst_port = &dstp;
/* parse icmp type and lookup appropriate icmp code
struct bgp_pbr_or_filter bpof;
struct bgp_pbr_val_mask bpvm;
+ memset(&range, 0, sizeof(range));
memset(&nh, 0, sizeof(struct nexthop));
memset(&bpf, 0, sizeof(struct bgp_pbr_filter));
memset(&bpof, 0, sizeof(struct bgp_pbr_or_filter));
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_regex.h"
#include "bgpd/bgp_community.h"
+#include "bgpd/bgp_community_alias.h"
#include "bgpd/bgp_ecommunity.h"
#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_clist.h"
/* 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 */
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) {
}
/* 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)
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) {
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) {
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);
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++;
}
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-translated-v4] [exact-match]\
|rpki <invalid|valid|notfound>\
|version (1-4294967295)\
- ] [json$uj | wide$wide]",
+ ] [json$uj [detail$detail] | wide$wide]",
SHOW_STR
IP_STR
BGP_STR
"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;
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);
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");
"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,
*/
+#include <zebra.h>
+
#include "lib/command.h"
#include "lib/log.h"
#include "lib/northbound.h"
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <zebra.h>
+
#include "lib/command.h"
#include "lib/log.h"
#include "lib/northbound.h"
#endif
#include "hook.h"
#include "libfrr.h"
-#include "version.h"
+#include "lib/version.h"
#ifndef VTYSH_EXTRACT_PL
#include "bgpd/bgp_rpki_clippy.c"
#include "filter.h"
#include "hook.h"
#include "libfrr.h"
-#include "version.h"
+#include "lib/version.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_table.h"
#define TRACEPOINT_CREATE_PROBES
#define TRACEPOINT_DEFINE
+#include <zebra.h>
+
#include "bgp_trace.h"
#include "command.h"
#include "lib/json.h"
+#include "lib/sockopt.h"
#include "lib_errors.h"
#include "lib/zclient.h"
#include "lib/printfrr.h"
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_community.h"
+#include "bgpd/bgp_community_alias.h"
#include "bgpd/bgp_ecommunity.h"
#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_damp.h"
(bgp, vty));
DEFINE_HOOK(bgp_snmp_update_last_changed, (struct bgp *bgp), (bgp));
-#define GR_NO_OPER \
- "The Graceful Restart No Operation was executed as cmd same as previous one."
-#define GR_INVALID \
- "The Graceful Restart command used is not valid at this moment."
static struct peer_group *listen_range_exists(struct bgp *bgp,
struct prefix *range, int exact);
case BGP_ERR_GR_OPERATION_FAILED:
str = "The Graceful Restart Operation failed due to an err.";
break;
- case BGP_GR_NO_OPERATION:
- str = GR_NO_OPER;
- break;
case BGP_ERR_PEER_GROUP_MEMBER:
str = "Peer-group member cannot override remote-as of peer-group";
break;
case BGP_ERR_GR_OPERATION_FAILED:
str = "The Graceful Restart Operation failed due to an err.";
break;
- case BGP_GR_NO_OPERATION:
- str = GR_NO_OPER;
- break;
}
if (str) {
vty_out(vty, "%% %s\n", str);
vty_out(vty, " bgp router-id %s\n", yang_dnode_get_string(dnode, NULL));
}
+DEFPY(bgp_community_alias, bgp_community_alias_cmd,
+ "[no$no] bgp community alias WORD$community WORD$alias",
+ NO_STR BGP_STR
+ "Add community specific parameters\n"
+ "Create an alias for a community\n"
+ "Community (AA:BB or AA:BB:CC)\n"
+ "Alias name\n")
+{
+ struct community_alias ca1;
+ struct community_alias ca2;
+ struct community_alias *lookup_community;
+ struct community_alias *lookup_alias;
+
+ if (!community_str2com(community) && !lcommunity_str2com(community)) {
+ vty_out(vty, "Invalid community format\n");
+ return CMD_WARNING;
+ }
+
+ memset(&ca1, 0, sizeof(ca1));
+ memset(&ca2, 0, sizeof(ca2));
+ strlcpy(ca1.community, community, sizeof(ca1.community));
+ strlcpy(ca1.alias, alias, sizeof(ca1.alias));
+
+ lookup_community = bgp_ca_community_lookup(&ca1);
+ lookup_alias = bgp_ca_alias_lookup(&ca1);
+
+ if (no) {
+ bgp_ca_alias_delete(&ca1);
+ bgp_ca_community_delete(&ca1);
+ } else {
+ if (lookup_alias) {
+ /* Lookup if community hash table has an item
+ * with the same alias name.
+ */
+ strlcpy(ca2.community, lookup_alias->community,
+ sizeof(ca2.community));
+ if (bgp_ca_community_lookup(&ca2)) {
+ vty_out(vty,
+ "community (%s) already has this alias (%s)\n",
+ lookup_alias->community,
+ lookup_alias->alias);
+ return CMD_WARNING;
+ }
+ bgp_ca_alias_delete(&ca1);
+ }
+
+ if (lookup_community)
+ bgp_ca_community_delete(&ca1);
+
+ bgp_ca_alias_insert(&ca1);
+ bgp_ca_community_insert(&ca1);
+ }
+
+ return CMD_SUCCESS;
+}
+
DEFPY (bgp_global_suppress_fib_pending,
bgp_global_suppress_fib_pending_cmd,
"[no] bgp suppress-fib-pending",
uint8_t *msg;
json_object *json_neigh = NULL;
time_t epoch_tbuf;
+ uint32_t sync_tcp_mss;
bgp = p->bgp;
p->v_delayopen * 1000);
}
+ /* Configured and Synced tcp-mss value for peer */
+ if (CHECK_FLAG(p->flags, PEER_FLAG_TCP_MSS)) {
+ sync_tcp_mss = sockopt_tcp_mss_get(p->fd);
+ json_object_int_add(json_neigh, "bgpTcpMssConfigured",
+ p->tcp_mss);
+ json_object_int_add(json_neigh, "bgpTcpMssSynced",
+ sync_tcp_mss);
+ }
+
if (CHECK_FLAG(p->flags, PEER_FLAG_TIMER)) {
json_object_int_add(json_neigh,
"bgpTimerConfiguredHoldTimeMsecs",
vty_out(vty,
" Configured DelayOpenTime is %d seconds\n",
p->delayopen);
+
+ /* Configured and synced tcp-mss value for peer */
+ if (CHECK_FLAG(p->flags, PEER_FLAG_TCP_MSS)) {
+ sync_tcp_mss = sockopt_tcp_mss_get(p->fd);
+ vty_out(vty, " Configured tcp-mss is %d", p->tcp_mss);
+ vty_out(vty, ", synced tcp-mss is %d\n", sync_tcp_mss);
+ }
}
/* Capability. */
if (p->status == Established) {
vty_out(vty, "\n");
}
+/* Neighbor update tcp-mss. */
+static int peer_tcp_mss_vty(struct vty *vty, const char *peer_str,
+ const char *tcp_mss_str)
+{
+ struct peer *peer;
+ uint32_t tcp_mss_val = 0;
+
+ peer = peer_and_group_lookup_vty(vty, peer_str);
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ if (tcp_mss_str) {
+ tcp_mss_val = strtoul(tcp_mss_str, NULL, 10);
+ peer_tcp_mss_set(peer, tcp_mss_val);
+ } else {
+ peer_tcp_mss_unset(peer);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(neighbor_tcp_mss, neighbor_tcp_mss_cmd,
+ "neighbor <A.B.C.D|X:X::X:X|WORD> tcp-mss (1-65535)",
+ NEIGHBOR_STR NEIGHBOR_ADDR_STR2
+ "TCP max segment size\n"
+ "TCP MSS value\n")
+{
+ int peer_index = 1;
+ int mss_index = 3;
+
+ vty_out(vty,
+ " Warning: Reset BGP session for tcp-mss value to take effect\n");
+ return peer_tcp_mss_vty(vty, argv[peer_index]->arg,
+ argv[mss_index]->arg);
+}
+
+DEFUN(no_neighbor_tcp_mss, no_neighbor_tcp_mss_cmd,
+ "no neighbor <A.B.C.D|X:X::X:X|WORD> tcp-mss [(1-65535)]",
+ NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
+ "TCP max segment size\n"
+ "TCP MSS value\n")
+{
+ int peer_index = 2;
+
+ vty_out(vty,
+ " Warning: Reset BGP session for tcp-mss value to take effect\n");
+ return peer_tcp_mss_vty(vty, argv[peer_index]->arg, NULL);
+}
+
static void bgp_config_write_redistribute(struct vty *vty, struct bgp *bgp,
afi_t afi, safi_t safi)
{
vty_out(vty, " neighbor %s interface %s\n", addr, peer->ifname);
}
+ /* TCP max segment size */
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_TCP_MSS))
+ vty_out(vty, " neighbor %s tcp-mss %d\n", addr, peer->tcp_mss);
+
/* passive */
if (peergroup_flag_check(peer, PEER_FLAG_PASSIVE))
vty_out(vty, " neighbor %s passive\n", addr);
: "");
}
}
+
+ if (peer_af_flag_check(peer, afi, safi, PEER_FLAG_CONFIG_DAMPENING))
+ bgp_config_write_peer_damp(vty, peer, afi, safi);
}
/* Address family based peer configuration display. */
/* BGP flag dampening. */
if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
bgp_config_write_damp(vty, bgp, afi, safi);
- for (ALL_LIST_ELEMENTS_RO(bgp->group, node, group))
- if (peer_af_flag_check(group->conf, afi, safi,
- PEER_FLAG_CONFIG_DAMPENING))
- bgp_config_write_peer_damp(vty, group->conf, afi, safi);
- for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer))
- if (peer_af_flag_check(peer, afi, safi,
- PEER_FLAG_CONFIG_DAMPENING))
- bgp_config_write_peer_damp(vty, peer, afi, safi);
for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group))
bgp_config_write_peer_af(vty, bgp, group->conf, afi, safi);
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
- /* Skip dynamic neighbors. */
- if (peer_dynamic_neighbor(peer))
- continue;
-
/* Do not display doppelganger peers */
if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
bgp_config_write_peer_af(vty, bgp, peer, afi, safi);
/* Community-list. */
community_list_vty();
+ community_alias_vty();
+
/* vpn-policy commands */
install_element(BGP_IPV4_NODE, &af_rd_vpn_export_cmd);
install_element(BGP_IPV6_NODE, &af_rd_vpn_export_cmd);
install_element(BGP_IPV6_NODE, &af_no_route_map_vpn_imexport_cmd);
install_element(BGP_IPV4_NODE, &af_no_import_vrf_route_map_cmd);
install_element(BGP_IPV6_NODE, &af_no_import_vrf_route_map_cmd);
+
+ /* tcp-mss command */
+ install_element(BGP_NODE, &neighbor_tcp_mss_cmd);
+ install_element(BGP_NODE, &no_neighbor_tcp_mss_cmd);
}
#include "memory.h"
install_element(VIEW_NODE, &show_bgp_lcommunity_list_cmd);
install_element(VIEW_NODE, &show_bgp_lcommunity_list_arg_cmd);
}
+
+static struct cmd_node community_alias_node = {
+ .name = "community alias",
+ .node = COMMUNITY_ALIAS_NODE,
+ .prompt = "",
+ .config_write = bgp_community_alias_write,
+};
+
+void community_alias_vty(void)
+{
+ install_node(&community_alias_node);
+
+ /* Community-list. */
+ install_element(CONFIG_NODE, &bgp_community_alias_cmd);
+}
} while (0)
extern void bgp_vty_init(void);
+extern void community_alias_vty(void);
extern const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json);
extern int bgp_get_vty(struct bgp **bgp, as_t *as, const char *name,
enum bgp_instance_type inst_type);
redist_add_instance(&zclient->mi_redist[afi][type], instance);
} else {
- if (vrf_bitmap_check(zclient->redist[afi][type], bgp->vrf_id))
- return CMD_WARNING;
-
#ifdef ENABLE_BGP_VNC
if (EVPN_ENABLED(bgp) && type == ZEBRA_ROUTE_VNC_DIRECT) {
vnc_export_bgp_enable(
void bgp_zebra_initiate_radv(struct bgp *bgp, struct peer *peer)
{
- int ra_interval = BGP_UNNUM_DEFAULT_RA_INTERVAL;
+ uint32_t ra_interval = BGP_UNNUM_DEFAULT_RA_INTERVAL;
/* Don't try to initiate if we're not connected to Zebra */
if (zclient->sock < 0)
#include "jhash.h"
#include "table.h"
#include "lib/json.h"
+#include "lib/sockopt.h"
#include "frr_pthread.h"
#include "bitfield.h"
#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_errors.h"
#include "bgpd/bgp_community.h"
+#include "bgpd/bgp_community_alias.h"
#include "bgpd/bgp_conditional_adv.h"
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_regex.h"
peer->bgp = bgp_lock(bgp);
peer = peer_lock(peer); /* initial reference */
peer->password = NULL;
- peer->max_packet_size = BGP_MAX_EXTENDED_MESSAGE_PACKET_SIZE;
+ peer->max_packet_size = BGP_MAX_PACKET_SIZE;
/* Set default flags. */
FOREACH_AFI_SAFI (afi, safi) {
/* We use a larger buffer for peer->obuf_work in the event that:
* - We RX a BGP_UPDATE where the attributes alone are just
- * under BGP_MAX_EXTENDED_MESSAGE_PACKET_SIZE.
+ * under BGP_EXTENDED_MESSAGE_MAX_PACKET_SIZE.
* - The user configures an outbound route-map that does many as-path
* prepends or adds many communities. At most they can have
* CMD_ARGC_MAX args in a route-map so there is a finite limit on how
* bounds checking for every single attribute as we construct an
* UPDATE.
*/
- peer->obuf_work = stream_new(BGP_MAX_EXTENDED_MESSAGE_PACKET_SIZE
- + BGP_MAX_PACKET_SIZE_OVERFLOW);
- peer->ibuf_work = ringbuf_new(BGP_MAX_EXTENDED_MESSAGE_PACKET_SIZE
- * BGP_READ_PACKET_MAX);
+ peer->obuf_work =
+ stream_new(BGP_MAX_PACKET_SIZE + BGP_MAX_PACKET_SIZE_OVERFLOW);
+ peer->ibuf_work =
+ ringbuf_new(BGP_MAX_PACKET_SIZE * BGP_READ_PACKET_MAX);
- peer->scratch = stream_new(BGP_MAX_EXTENDED_MESSAGE_PACKET_SIZE);
+ peer->scratch = stream_new(BGP_MAX_PACKET_SIZE);
bgp_sync_init(peer);
peer_dst->local_as = peer_src->local_as;
peer_dst->port = peer_src->port;
+ /* copy tcp_mss value */
+ peer_dst->tcp_mss = peer_src->tcp_mss;
(void)peer_sort(peer_dst);
peer_dst->rmap_type = peer_src->rmap_type;
if (bgp) {
if (bgp->as != *as) {
*as = bgp->as;
- return BGP_ERR_INSTANCE_MISMATCH;
+ return BGP_ERR_AS_MISMATCH;
}
if (bgp->inst_type != inst_type)
return BGP_ERR_INSTANCE_MISMATCH;
int ret = 0;
ret = bgp_lookup_by_as_name_type(bgp_val, as, name, inst_type);
- switch (ret) {
- case BGP_ERR_INSTANCE_MISMATCH:
+ if (ret || *bgp_val)
return ret;
- case BGP_SUCCESS:
- if (*bgp_val)
- return ret;
- }
bgp = bgp_create(as, name, inst_type);
if (bgp_option_check(BGP_OPT_NO_ZEBRA) && name)
peer->port = BGP_PORT_DEFAULT;
}
+/* Set the TCP-MSS value in the peer structure,
+ * This gets applied only after connection reset
+ * So this value will be used in bgp_connect.
+ */
+void peer_tcp_mss_set(struct peer *peer, uint32_t tcp_mss)
+{
+ peer->tcp_mss = tcp_mss;
+ SET_FLAG(peer->flags, PEER_FLAG_TCP_MSS);
+}
+
+/* Reset the TCP-MSS value in the peer structure,
+ * This gets applied only after connection reset
+ * So this value will be used in bgp_connect.
+ */
+void peer_tcp_mss_unset(struct peer *peer)
+{
+ UNSET_FLAG(peer->flags, PEER_FLAG_TCP_MSS);
+ peer->tcp_mss = 0;
+}
+
/*
* Helper function that is called after the name of the policy
* being used by a peer has changed (AF specific). Automatically
/* BGP inits. */
bgp_attr_init();
bgp_debug_init();
+ bgp_community_alias_init();
bgp_dump_init();
bgp_route_init();
bgp_route_map_init();
#include "bgp_addpath_types.h"
#include "bgp_nexthop.h"
#include "bgp_damp.h"
+#include "bgp_io.h"
#include "lib/bfd.h"
/* BGP message header and packet size. */
#define BGP_MARKER_SIZE 16
#define BGP_HEADER_SIZE 19
-#define BGP_MAX_PACKET_SIZE 4096
-#define BGP_MAX_EXTENDED_MESSAGE_PACKET_SIZE 65535
+#define BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE 4096
+#define BGP_EXTENDED_MESSAGE_MAX_PACKET_SIZE 65535
+#define BGP_MAX_PACKET_SIZE BGP_EXTENDED_MESSAGE_MAX_PACKET_SIZE
#define BGP_MAX_PACKET_SIZE_OVERFLOW 1024
/*
struct stream_fifo *ibuf; // packets waiting to be processed
struct stream_fifo *obuf; // packets waiting to be written
+ /* used as a block to deposit raw wire data to */
+ uint8_t ibuf_scratch[BGP_EXTENDED_MESSAGE_MAX_PACKET_SIZE
+ * BGP_READ_PACKET_MAX];
struct ringbuf *ibuf_work; // WiP buffer used by bgp_read() only
struct stream *obuf_work; // WiP buffer used to construct packets
#define PEER_FLAG_GRACEFUL_RESTART (1U << 24) /* Graceful Restart */
#define PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT (1U << 25) /* Global-Inherit */
#define PEER_FLAG_RTT_SHUTDOWN (1U << 26) /* shutdown rtt */
+#define PEER_FLAG_TIMER_DELAYOPEN (1U << 27) /* delayopen timer */
+#define PEER_FLAG_TCP_MSS (1U << 28) /* tcp-mss */
/*
*GR-Disabled mode means unset PEER_FLAG_GRACEFUL_RESTART
*and PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT
*/
-#define PEER_FLAG_TIMER_DELAYOPEN (1 << 27) /* delayopen timer */
-
struct bgp_peer_gr PEER_GR_FSM[BGP_PEER_GR_MODE][BGP_PEER_GR_EVENT_CMD];
enum peer_mode peer_gr_present_state;
/* Non stop forwarding afi-safi count for BGP gr feature*/
bool advmap_config_change[AFI_MAX][SAFI_MAX];
bool advmap_table_change;
+ /* set TCP max segment size */
+ uint32_t tcp_mss;
+
QOBJ_FIELDS;
};
DECLARE_QOBJ_TYPE(peer);
void peer_nsf_stop(struct peer *peer);
+void peer_tcp_mss_set(struct peer *peer, uint32_t tcp_mss);
+void peer_tcp_mss_unset(struct peer *peer);
#endif /* _QUAGGA_BGPD_H */
noinst_PROGRAMS += bgpd/rfp-example/rfptest/rfptest
endif
-bgpd_rfp_example_rfptest_rfptest_CFLAGS = -I$(top_srcdir)/bgpd/rfapi
+bgpd_rfp_example_rfptest_rfptest_CFLAGS = \
+ $(AM_CFLAGS) \
+ -I$(top_srcdir)/bgpd/rfapi \
+ # end
bgpd_rfp_example_rfptest_rfptest_SOURCES = \
bgpd/rfp-example/rfptest/rfptest.c \
# end
bgpd/bgp_bfd.c \
bgpd/bgp_clist.c \
bgpd/bgp_community.c \
+ bgpd/bgp_community_alias.c \
bgpd/bgp_conditional_adv.c \
bgpd/bgp_damp.c \
bgpd/bgp_debug.c \
bgpd/bgp_bfd.h \
bgpd/bgp_clist.h \
bgpd/bgp_community.h \
+ bgpd/bgp_community_alias.h \
bgpd/bgp_conditional_adv.h \
bgpd/bgp_damp.h \
bgpd/bgp_debug.h \
bgpd_bgpd_SOURCES = bgpd/bgp_main.c
bgpd_bgp_btoa_SOURCES = bgpd/bgp_btoa.c
-bgpd_bgpd_CFLAGS = $(AM_CFLAGS)
-bgpd_bgp_btoa_CFLAGS = $(AM_CFLAGS)
-
# RFPLDADD is set in bgpd/rfp-example/librfp/subdir.am
bgpd_bgpd_LDADD = bgpd/libbgp.a $(RFPLDADD) lib/libfrr.la $(LIBCAP) $(LIBM) $(UST_LIBS)
bgpd_bgp_btoa_LDADD = bgpd/libbgp.a $(RFPLDADD) lib/libfrr.la $(LIBCAP) $(LIBM) $(UST_LIBS)
bgpd_bgpd_snmp_la_SOURCES = bgpd/bgp_snmp.c bgpd/bgp_mplsvpn_snmp.c
-bgpd_bgpd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11
+bgpd_bgpd_snmp_la_CFLAGS = $(AM_CFLAGS) $(SNMP_CFLAGS) -std=gnu11
bgpd_bgpd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
bgpd_bgpd_snmp_la_LIBADD = lib/libfrrsnmp.la
bgpd_bgpd_rpki_la_SOURCES = bgpd/bgp_rpki.c
-bgpd_bgpd_rpki_la_CFLAGS = $(WERROR) $(RTRLIB_CFLAGS)
+bgpd_bgpd_rpki_la_CFLAGS = $(AM_CFLAGS) $(RTRLIB_CFLAGS)
bgpd_bgpd_rpki_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
bgpd_bgpd_rpki_la_LIBADD = $(RTRLIB_LIBS)
+++ /dev/null
-{
- <zlog_keep_working_at_exit>
- Memcheck:Leak
- match-leak-kinds: reachable
- fun:calloc
- fun:qcalloc
- fun:zlog_target_clone
-}
-{
- <libyang1_1.0.184>
- Memcheck:Leak
- match-leak-kinds: reachable
- fun:calloc
- fun:_dlerror_run
- fun:dlopen@@GLIBC_2.2.5
- obj:/usr/lib/x86_64-linux-gnu/libyang.so.1.9.2
- fun:ly_load_plugins
-}
# and so that those used to the presence of bootstrap.sh or autogen.sh
# will have an eaiser time.
-autoreconf -i
+exec autoreconf -is -Wall,no-override
## Copyright (c) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
## Portions Copyright (c) 2003 Paul Jakma <paul@dishone.st>
##
-AC_PREREQ([2.60])
+AC_PREREQ([2.69])
AC_INIT([frr], [7.7-dev], [https://github.com/frrouting/frr/issues])
PACKAGE_URL="https://frrouting.org/"
AC_CONFIG_SRCDIR([lib/zebra.h])
AC_CONFIG_MACRO_DIR([m4])
+AC_CONFIG_AUX_DIR([m4/ac])
dnl -----------------------------------
dnl Get hostname and other information.
dnl try and enable CFLAGS that are useful for FRR
dnl - specifically, options to control warnings
+AC_SUBST([AC_CFLAGS])
AC_USE_SYSTEM_EXTENSIONS
AC_DEFUN([AC_C_FLAG], [{
m4_pushdef([cachename],[m4_translit([frr_cv_$1],[ =-+/{}$],[________])])
AC_LANG_POP([C])
])
if test "$cachename" = "yes"; then
- m4_if([$3], [], [CFLAGS="$CFLAGS $1"], [$3])
+ m4_if([$3], [], [AC_CFLAGS="$AC_CFLAGS $1"], [$3])
else
:
$2
AC_C_FLAG([-O0])
fi
- LDFLAGS="${LDFLAGS} -lgcov"
+ AC_LDFLAGS="${AC_LDFLAGS} -lgcov"
fi
if test "$enable_clang_coverage" = "yes"; then
])
fi
+dnl the following flags go in CFLAGS rather than AC_CFLAGS since they make
+dnl sense to be overridden by the user
if test "$enable_dev_build" = "yes"; then
AC_DEFINE([DEV_BUILD], [1], [Build for development])
if test "$orig_cflags" = ""; then
- AC_C_FLAG([-g3])
- AC_C_FLAG([-O0])
- AC_C_FLAG([-ggdb3])
+ AC_C_FLAG([-O0],,[CFLAGS="$CFLAGS -O0"])
+ AC_C_FLAG([-g3],,[CFLAGS="$CFLAGS -g3"])
+ AC_C_FLAG([-ggdb3],,[CFLAGS="$CFLAGS -ggdb3"])
fi
else
if test "$orig_cflags" = ""; then
- AC_C_FLAG([-g])
- AC_C_FLAG([-O2])
+ AC_C_FLAG([-g],,[CFLAGS="$CFLAGS -g"])
+ AC_C_FLAG([-O2],,[CFLAGS="$CFLAGS -O2"])
fi
fi
AX_PTHREAD([
CC="$PTHREAD_CC"
- CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ AC_CFLAGS="$AC_CFLAGS $PTHREAD_CFLAGS"
LIBS="$PTHREAD_LIBS $LIBS"
], [
AC_MSG_FAILURE([This FRR version needs pthreads])
])
+orig_cflags="$CFLAGS"
+CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
AC_SEARCH_LIBS([pthread_condattr_setclock], [],
[frr_cv_pthread_condattr_setclock=yes],
[frr_cv_pthread_condattr_setclock=no])
AC_DEFINE([HAVE_PTHREAD_CONDATTR_SETCLOCK], [1], [Have pthread.h pthread_condattr_setclock])
fi
+AC_CHECK_HEADERS([pthread_np.h],,, [
+#include <pthread.h>
+])
+AC_CHECK_FUNCS([pthread_setname_np pthread_set_name_np pthread_getthreadid_np])
+
+CFLAGS="$orig_cflags"
+
dnl --------------
dnl Check programs
dnl --------------
dnl Check other header files.
dnl -------------------------
AC_CHECK_HEADERS([stropts.h sys/ksym.h \
- linux/version.h asm/types.h])
+ linux/version.h asm/types.h endian.h sys/endian.h])
ac_stdatomic_ok=false
AC_DEFINE([FRR_AUTOCONF_ATOMIC], [1], [did autoconf checks for atomic funcs])
])
])
-AC_CHECK_HEADERS([pthread_np.h],,, [
-#include <pthread.h>
-])
-AC_CHECK_FUNCS([pthread_setname_np pthread_set_name_np pthread_getthreadid_np])
-
needsync=true
AS_IF([$needsync], [
esac
fi
-dnl -------------------------------
-dnl Endian-ness check
-dnl -------------------------------
-AC_WORDS_BIGENDIAN
-
dnl ---------------
dnl other functions
dnl ---------------
#endif
])dnl
-AC_MSG_CHECKING([for BSD struct ip_mreq hack])
-AC_TRY_COMPILE([#include <sys/param.h>],
-[#if (defined(__FreeBSD__) && ((__FreeBSD_version >= 500022 && __FreeBSD_version < 700000) || (__FreeBSD_version < 500000 && __FreeBSD_version >= 440000))) || (defined(__NetBSD__) && defined(__NetBSD_Version__) && __NetBSD_Version__ >= 106010000) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__DragonFly__) || defined(__sun)
- return (0);
-#else
- #error No support for BSD struct ip_mreq hack detected
-#endif],[AC_MSG_RESULT([yes])
-AC_DEFINE([HAVE_BSD_STRUCT_IP_MREQ_HACK], [1], [Can pass ifindex in struct ip_mreq])],
-AC_MSG_RESULT([no]))
-
AC_MSG_CHECKING([for RFC3678 protocol-independed API])
-AC_TRY_COMPILE([
-#include <sys/types.h>
-#include <netinet/in.h>
-], [struct group_req gr; int sock; setsockopt(sock, IPPROTO_IP, MCAST_JOIN_GROUP, (void*)&gr, sizeof(gr));
-], [AC_MSG_RESULT([yes])
-AC_DEFINE([HAVE_RFC3678], [1], [Have RFC3678 protocol-independed API])],
-AC_MSG_RESULT([no]))
+AC_COMPILE_IFELSE(
+[ AC_LANG_PROGRAM([[
+ #include <sys/types.h>
+ #include <netinet/in.h>
+ ]], [[
+ struct group_req gr;
+ int sock;
+ setsockopt(sock, IPPROTO_IP, MCAST_JOIN_GROUP, (void*)&gr, sizeof(gr));
+ ]])
+],[
+ AC_MSG_RESULT([yes])
+ AC_DEFINE([HAVE_RFC3678], [1], [Have RFC3678 protocol-independed API])
+],[
+ AC_MSG_RESULT(no)
+])
dnl ---------------------------------------------------------------
dnl figure out how to check link-state
dnl ---------------
dnl libyang
dnl ---------------
-PKG_CHECK_MODULES([LIBYANG], [libyang >= 1.0.184], , [
+PKG_CHECK_MODULES([LIBYANG], [libyang >= 1.0.184 libyang < 2.0], , [
AC_MSG_ERROR([libyang (>= 1.0.184) was not found on your system.])
])
ac_cflags_save="$CFLAGS"
dnl checking for IP_PKTINFO
dnl -----------------------
AC_MSG_CHECKING([for IP_PKTINFO])
-AC_TRY_COMPILE([#include <netdb.h>], [
- int opt = IP_PKTINFO;
-], [
+AC_COMPILE_IFELSE(
+[ AC_LANG_PROGRAM([[
+ #include <netdb.h>
+ ]], [[
+ int opt = IP_PKTINFO;
+ ]])
+],[
AC_MSG_RESULT([yes])
AC_DEFINE([HAVE_IP_PKTINFO], [1], [Have IP_PKTINFO])
-], [
+],[
AC_MSG_RESULT([no])
])
dnl checking for IP_RECVDSTADDR
dnl ---------------------------
AC_MSG_CHECKING([for IP_RECVDSTADDR])
-AC_TRY_COMPILE([#include <netinet/in.h>], [
- int opt = IP_RECVDSTADDR;
-], [
+AC_COMPILE_IFELSE(
+[ AC_LANG_PROGRAM([[
+ #include <netinet/in.h>
+ ]], [[
+ int opt = IP_RECVDSTADDR;
+ ]])
+],[
AC_MSG_RESULT([yes])
AC_DEFINE([HAVE_IP_RECVDSTADDR], [1], [Have IP_RECVDSTADDR])
-], [
+],[
AC_MSG_RESULT([no])
])
dnl checking for IP_RECVIF
dnl ----------------------
AC_MSG_CHECKING([for IP_RECVIF])
-AC_TRY_COMPILE([#include <netinet/in.h>], [
- int opt = IP_RECVIF;
-], [
+AC_COMPILE_IFELSE(
+[ AC_LANG_PROGRAM([[
+ #include <netinet/in.h>
+ ]], [[
+ int opt = IP_RECVIF;
+ ]])
+],[
AC_MSG_RESULT([yes])
AC_DEFINE([HAVE_IP_RECVIF], [1], [Have IP_RECVIF])
-], [
+],[
AC_MSG_RESULT([no])
])
dnl checking for SO_BINDANY
dnl ----------------------
AC_MSG_CHECKING([for SO_BINDANY])
-AC_TRY_COMPILE([#include <sys/socket.h>], [
- int opt = SO_BINDANY;
-], [
+AC_COMPILE_IFELSE(
+[ AC_LANG_PROGRAM([[
+ #include <sys/socket.h>
+ ]], [[
+ int opt = SO_BINDANY;
+ ]])
+],[
AC_MSG_RESULT([yes])
AC_DEFINE([HAVE_SO_BINDANY], [1], [Have SO_BINDANY])
-], [
+],[
AC_MSG_RESULT([no])
])
dnl checking for IP_FREEBIND
dnl ----------------------
AC_MSG_CHECKING([for IP_FREEBIND])
-AC_TRY_COMPILE([#include <netinet/in.h>], [
- int opt = IP_FREEBIND;
-], [
+AC_COMPILE_IFELSE(
+[ AC_LANG_PROGRAM([[
+ #include <netinet/in.h>
+ ]], [[
+ int opt = IP_FREEBIND;
+ ]])
+],[
AC_MSG_RESULT([yes])
AC_DEFINE([HAVE_IP_FREEBIND], [1], [Have IP_FREEBIND])
-], [
+],[
AC_MSG_RESULT([no])
])
dnl --------------------------------------
dnl checking for be32dec existence or not
dnl --------------------------------------
-AC_CHECK_DECLS([be32enc, be32dec], [], [],
- [#include <sys/endian.h>])
+AC_CHECK_DECLS([be32enc, be32dec], [], [], [
+ #ifdef HAVE_SYS_ENDIAN_H
+ #include <sys/endian.h>
+ #endif
+ #ifdef HAVE_ENDIAN_H
+ #include <endian.h>
+ #endif
+])
dnl --------------------------------------
dnl checking for clock_time monotonic struct and call
dnl -------------------
if test "$enable_capabilities" != "no"; then
AC_MSG_CHECKING([whether prctl PR_SET_KEEPCAPS is available])
- AC_TRY_COMPILE([#include <sys/prctl.h>], [prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);],
- [AC_MSG_RESULT([yes])
+ AC_COMPILE_IFELSE(
+ [ AC_LANG_PROGRAM([[
+ #include <sys/prctl.h>
+ ]], [[
+ prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
+ ]])
+ ],[AC_MSG_RESULT([yes])
AC_DEFINE([HAVE_PR_SET_KEEPCAPS], [1], [prctl])
- frr_ac_keepcaps="yes"],
- AC_MSG_RESULT([no])
- )
+ frr_ac_keepcaps="yes"
+ ],[AC_MSG_RESULT(no)
+ ])
if test "$frr_ac_keepcaps" = "yes"; then
AC_CHECK_HEADERS([sys/capability.h])
fi
host operating system : ${host_os}
source code location : ${srcdir}
compiler : ${CC}
-compiler flags : ${CFLAGS} ${SAN_FLAGS}
+compiler flags : ${CFLAGS} ${AC_CFLAGS} ${SAN_FLAGS}
make : ${MAKE-make}
linker flags : ${LDFLAGS} ${SAN_FLAGS} ${LIBS} ${LIBCAP} ${LIBREADLINE} ${LIBM}
state file directory : ${frr_statedir}
* 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
::
+ pkg_add clang libcares python3
pkg_add git autoconf-2.69p2 automake-1.15.1 libtool bison
pkg_add gmake json-c py-test py-sphinx libexecinfo
(You may prefer different options on configure statement. These are just
an example)
+.. warning::
+
+ In openbsd the proper links for the libyang library may not have been created.
+
+::
+
+ ln -s /usr/lib/libyang.so.1.10.17 /usr/lib/libyang.so
+
+.. warning::
+
+ ``openbsd`` since version 6.2 has ``clang`` as the default compiler so to
+ build frr, clang must be used (the included gcc version is very old).
+
::
git clone https://github.com/frrouting/frr.git frr
--enable-logfile-mask=0640 \
--enable-fpm \
--with-pkg-git-version \
- --with-pkg-extra-version=-MyOwnFRRVersion
+ --with-pkg-extra-version=-MyOwnFRRVersion \
+ CC=clang
gmake
gmake check
doas gmake install
| _first, _next, _next_safe, | yes | yes | yes | yes | yes |
| _const_first, _const_next | | | | | |
+------------------------------------+------+------+------+---------+------------+
+| _swap_all | yes | yes | yes | yes | yes |
++------------------------------------+------+------+------+---------+------------+
| _add_head, _add_tail, _add_after | yes | -- | -- | -- | -- |
+------------------------------------+------+------+------+---------+------------+
| _add | -- | yes | yes | yes | yes |
return ``item``. The function may also call ``assert()`` (but most
don't.)
+.. c:function:: itemtype *Z_swap_all(struct Z_head *, struct Z_head *)
+
+ Swap the contents of 2 containers (of identical type). This exchanges the
+ contents of the two head structures and updates pointers if necessary for
+ the particular data structure. Fast for all structures.
+
+ (Not currently available on atomic containers.)
+
.. todo::
``Z_del_after()`` / ``Z_del_hint()``?
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
# Keep ipv6 permanent addresses on an admin down
net.ipv6.conf.all.keep_addr_on_down=1
+net.ipv6.route.skip_notify_on_dev_down=1
# igmp
net.ipv4.igmp_max_memberships=1000
This command clears all current filters in the log-filter table. Can be
daemon independent.
+
+.. clicmd:: log immediate-mode
+
+ Use unbuffered output for log and debug messages; normally there is
+ some internal buffering.
+
.. clicmd:: service password-encryption
Encrypt password.
The following commands are available inside the interface configuration node.
-.. clicmd:: ipv6 ospf6 bfd
+.. clicmd:: ipv6 ospf6 bfd [profile BFDPROF]
Listen for BFD events on peers created on the interface. Every time
a new neighbor is found a BFD peer is created to monitor the link
status for fast convergence.
+ Optionally uses the BFD profile ``BFDPROF`` in the created sessions under
+ that interface.
+
.. _bfd-pim-peer-config:
The following commands are available inside the interface configuration node.
-.. clicmd:: ip pim bfd
+.. clicmd:: ip pim bfd [profile BFDPROF]
Listen for BFD events on peers created on the interface. Every time
a new neighbor is found a BFD peer is created to monitor the link
status for fast convergence.
+ Optionally uses the BFD profile ``BFDPROF`` in the created sessions under
+ that interface.
+
.. _bfd-configuration:
attribute in BGP updates. The expanded community is only used to filter,
not `set` actions.
+.. clicmd:: bgp community alias NAME ALIAS
+
+ This command creates an alias name for a community that will be used
+ later in various CLI outputs in a human-readable format.
+
+ .. code-block:: frr
+
+ ~# show ip bgp 172.16.16.1/32
+ BGP routing table entry for 172.16.16.1/32, version 21
+ Paths: (2 available, best #2, table default)
+ Advertised to non peer-group peers:
+ 65030
+ 192.168.0.2 from 192.168.0.2 (172.16.16.1)
+ Origin incomplete, metric 0, valid, external, best (Neighbor IP)
+ Community: 65001:12 65001:13 community-1 65001:65534
+ Large Community: lcommunity-1 65001:123:2
+ Last update: Fri Apr 16 12:51:27 2021
+
.. deprecated:: 5.0
It is recommended to use the more explicit versions of this command.
Ethernet Virtual Network - EVPN
-------------------------------
+Note: When using EVPN features and if you have a large number of hosts, make
+sure to adjust the size of the arp neighbor cache to avoid neighbor table
+overflow and/or excessive garbage collection. On Linux, the size of the table
+and garbage collection frequency can be controlled via the following
+sysctl configurations:
+
+.. code-block:: shell
+
+ net.ipv4.neigh.default.gc_thresh1
+ net.ipv4.neigh.default.gc_thresh2
+ net.ipv4.neigh.default.gc_thresh3
+
+ net.ipv6.neigh.default.gc_thresh1
+ net.ipv6.neigh.default.gc_thresh2
+ net.ipv6.neigh.default.gc_thresh3
+
+For more information, see ``man 7 arp``.
+
.. _bgp-evpn-advertise-pip:
EVPN advertise-PIP
To support this feature there needs to have ability to co-exist a
(system-MAC, system-IP) pair with a (anycast-MAC, anycast-IP) pair with the
ability to terminate VxLAN-encapsulated packets received for either pair on
-the same L3VNI (i.e associated VLAN). This capability is need per tenant
+the same L3VNI (i.e associated VLAN). This capability is needed per tenant
VRF instance.
-To derive the system-MAC and the anycast MAC, there needs to have a
+To derive the system-MAC and the anycast MAC, there must be a
separate/additional MAC-VLAN interface corresponding to L3VNI’s SVI.
The SVI interface’s MAC address can be interpreted as system-MAC
and MAC-VLAN interface's MAC as anycast MAC.
auto derived value is not preferred.
Note: By default, advertise-pip feature is enabled and user has an option to
-disable the feature via configuration CLI. Once the feature is disable under
+disable the feature via configuration CLI. Once the feature is disabled under
bgp vrf instance or MAC-VLAN interface is not configured, all the routes follow
the same behavior of using same next-hop and RMAC values.
Enables or disables advertise-pip feature, specifiy system-IP and/or system-MAC
parameters.
+EVPN advertise-svi-ip
+^^^^^^^^^^^^^^^^^^^^^
+Typically, the SVI IP address is reused on VTEPs across multiple racks. However,
+if you have unique SVI IP addresses that you want to be reachable you can use the
+advertise-svi-ip option. This option advertises the SVI IP/MAC address as a type-2
+route and eliminates the need for any flooding over VXLAN to reach the IP from a
+remote VTEP.
+
+.. clicmd:: advertise-svi-ip
+
+Note that you should not enable both the advertise-svi-ip and the advertise-default-gw
+at the same time.
+
EVPN Multihoming
^^^^^^^^^^^^^^^^
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
log file bgpd.log
!
+.. _bgp-tcp-mss:
+
+BGP tcp-mss support
+===================
+TCP provides a mechanism for the user to specify the max segment size.
+setsockopt API is used to set the max segment size for TCP session. We
+can configure this as part of BGP neighbor configuration.
+
+This document explains how to avoid ICMP vulnerability issues by limiting
+TCP max segment size when you are using MTU discovery. Using MTU discovery
+on TCP paths is one method of avoiding BGP packet fragmentation.
+
+TCP negotiates a maximum segment size (MSS) value during session connection
+establishment between two peers. The MSS value negotiated is primarily based
+on the maximum transmission unit (MTU) of the interfaces to which the
+communicating peers are directly connected. However, due to variations in
+link MTU on the path taken by the TCP packets, some packets in the network
+that are well within the MSS value might be fragmented when the packet size
+exceeds the link's MTU.
+
+This feature is supported with TCP over IPv4 and TCP over IPv6.
+
+CLI Configuration:
+------------------
+Below configuration can be done in router bgp mode and allows the user to
+configure the tcp-mss value per neighbor. The configuration gets applied
+only after hard reset is performed on that neighbor. If we configure tcp-mss
+on both the neighbors then both neighbors need to be reset.
+
+The configuration takes effect based on below rules, so there is a configured
+tcp-mss and a synced tcp-mss value per TCP session.
+
+By default if the configuration is not done then the TCP max segment size is
+set to the Maximum Transmission unit (MTU) – (IP/IP6 header size + TCP header
+size + ethernet header). For IPv4 its MTU – (20 bytes IP header + 20 bytes TCP
+header + 12 bytes ethernet header) and for IPv6 its MTU – (40 bytes IPv6 header
++ 20 bytes TCP header + 12 bytes ethernet header).
+
+If the config is done then it reduces 12-14 bytes for the ether header and
+uses it after synchronizing in TCP handshake.
+
+.. clicmd:: neighbor <A.B.C.D|X:X::X:X|WORD> tcp-mss (1-65535)
+
+When tcp-mss is configured kernel reduces 12-14 bytes for ethernet header.
+E.g. if tcp-mss is configured as 150 the synced value will be 138.
+
+Note: configured and synced value is different since TCP module will reduce
+12 bytes for ethernet header.
+
+Running config:
+---------------
+
+.. code-block:: frr
+
+ frr# show running-config
+ Building configuration...
+
+ Current configuration:
+ !
+ router bgp 100
+ bgp router-id 192.0.2.1
+ neighbor 198.51.100.2 remote-as 100
+ neighbor 198.51.100.2 tcp-mss 150 => new entry
+ neighbor 2001:DB8::2 remote-as 100
+ neighbor 2001:DB8::2 tcp-mss 400 => new entry
+
+Show command:
+-------------
+
+.. code-block:: frr
+
+ frr# show bgp neighbors 198.51.100.2
+ BGP neighbor is 198.51.100.2, remote AS 100, local AS 100, internal link
+ Hostname: frr
+ BGP version 4, remote router ID 192.0.2.2, local router ID 192.0.2.1
+ BGP state = Established, up for 02:15:28
+ Last read 00:00:28, Last write 00:00:28
+ Hold time is 180, keepalive interval is 60 seconds
+ Configured tcp-mss is 150, synced tcp-mss is 138 => new display
+
+.. code-block:: frr
+
+ frr# show bgp neighbors 2001:DB8::2
+ BGP neighbor is 2001:DB8::2, remote AS 100, local AS 100, internal link
+ Hostname: frr
+ BGP version 4, remote router ID 192.0.2.2, local router ID 192.0.2.1
+ BGP state = Established, up for 02:16:34
+ Last read 00:00:34, Last write 00:00:34
+ Hold time is 180, keepalive interval is 60 seconds
+ Configured tcp-mss is 400, synced tcp-mss is 388 => new display
+
+Show command json output:
+-------------------------
+
+.. code-block:: frr
+
+ frr# show bgp neighbors 2001:DB8::2 json
+ {
+ "2001:DB8::2":{
+ "remoteAs":100,
+ "localAs":100,
+ "nbrInternalLink":true,
+ "hostname":"frr",
+ "bgpVersion":4,
+ "remoteRouterId":"192.0.2.2",
+ "localRouterId":"192.0.2.1",
+ "bgpState":"Established",
+ "bgpTimerUpMsec":8349000,
+ "bgpTimerUpString":"02:19:09",
+ "bgpTimerUpEstablishedEpoch":1613054251,
+ "bgpTimerLastRead":9000,
+ "bgpTimerLastWrite":9000,
+ "bgpInUpdateElapsedTimeMsecs":8347000,
+ "bgpTimerHoldTimeMsecs":180000,
+ "bgpTimerKeepAliveIntervalMsecs":60000,
+ "bgpTcpMssConfigured":400, => new entry
+ "bgpTcpMssSynced":388, => new entry
+
+.. code-block:: frr
+
+ frr# show bgp neighbors 198.51.100.2 json
+ {
+ "198.51.100.2":{
+ "remoteAs":100,
+ "localAs":100,
+ "nbrInternalLink":true,
+ "hostname":"frr",
+ "bgpVersion":4,
+ "remoteRouterId":"192.0.2.2",
+ "localRouterId":"192.0.2.1",
+ "bgpState":"Established",
+ "bgpTimerUpMsec":8370000,
+ "bgpTimerUpString":"02:19:30",
+ "bgpTimerUpEstablishedEpoch":1613054251,
+ "bgpTimerLastRead":30000,
+ "bgpTimerLastWrite":30000,
+ "bgpInUpdateElapsedTimeMsecs":8368000,
+ "bgpTimerHoldTimeMsecs":180000,
+ "bgpTimerKeepAliveIntervalMsecs":60000,
+ "bgpTcpMssConfigured":150, => new entry
+ "bgpTcpMssSynced":138, => new entry
.. include:: routeserver.rst
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
- transition
Send and accept both styles of TLVs during transition
- wide
- Use new style of TLVs to carry wider metric
+ Use new style of TLVs to carry wider metric. FRR uses this as a default value
.. clicmd:: set-overload-bit
.. _ip-router-isis-word:
-.. clicmd:: <ip|ipv6> router isis WORD [vrf NAME]
+.. clicmd:: <ip|ipv6> router isis WORD
Activate ISIS adjacency on this interface. Note that the name of ISIS
instance must be the same as the one used to configure the ISIS process (see
Limit Remote LFA PQ node selection within the specified metric.
-.. clicmd:: isis fast-reroute ti-lfa [level-1|level-2] [node-protection]
+.. clicmd:: isis fast-reroute ti-lfa [level-1|level-2] [node-protection [link-fallback]]
Enable per-prefix TI-LFA fast reroute link or node protection.
-
+ When node protection is used, option link-fallback enables the computation and use of
+ link-protecting LFAs for destinations unprotected by node protection.
.. _showing-isis-information:
There are several different methods for reading kernel routing table
information, updating kernel routing tables, and for looking up interfaces.
+FRR relies heavily on the Netlink (``man 7 netlink``) interface to
+communicate with the Kernel. However, other interfaces are still used
+in some parts of the code.
- ioctl
This method is a very traditional way for reading or writing kernel
kernel information.
- routing socket / Netlink
- On recent Linux kernels (2.0.x and 2.2.x), there is a kernel/user
- communication support called `Netlink`. It makes asynchronous communication
- between kernel and FRR possible, similar to a routing socket on BSD systems.
-
- Before you use this feature, be sure to select (in kernel configuration) the
- kernel/Netlink support option 'Kernel/User network link driver' and 'Routing
- messages'.
-
- Today, the :file:`/dev/route` special device file is obsolete. Netlink
- communication is done by reading/writing over Netlink socket.
-
- After the kernel configuration, please reconfigure and rebuild FRR. You can
- use Netlink as a dynamic routing update channel between FRR and the kernel.
+ Netlink first appeard in Linux kernel 2.0. It makes asynchronous
+ communication between the kernel and FRR possible, similar to a routing
+ socket on BSD systems. Netlink communication is done by reading/writing
+ over Netlink socket.
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
OSPF6 router
============
-.. clicmd:: router ospf6
+.. clicmd:: router ospf6 [vrf NAME]
.. clicmd:: ospf6 router-id A.B.C.D
Showing OSPF6 information
=========================
-.. clicmd:: show ipv6 ospf6 [INSTANCE_ID] [json]
+.. clicmd:: show ipv6 ospf6 [vrf <NAME|all>] [json]
- INSTANCE_ID is an optional OSPF instance ID. To see router ID and OSPF
- instance ID, simply type "show ipv6 ospf6 <cr>". JSON output can be
- obtained by appending 'json' to the end of command.
+ Show information on a variety of general OSPFv3 and area state and
+ configuration information. JSON output can be obtained by appending 'json'
+ to the end of command.
-.. clicmd:: show ipv6 ospf6 database [<detail|dump|internal>] [json]
+.. clicmd:: show ipv6 ospf6 [vrf <NAME|all>] database [<detail|dump|internal>] [json]
This command shows LSAs present in the LSDB. There are three view options.
These options helps in viewing all the parameters of the LSAs. JSON output
can be obtained by appending 'json' to the end of command. JSON option is
not applicable with 'dump' option.
-.. clicmd:: show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> [json]
+.. clicmd:: show ipv6 ospf6 [vrf <NAME|all>] database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> [json]
These options filters out the LSA based on its type. The three views options
works here as well. JSON output can be obtained by appending 'json' to the
end of command.
-.. clicmd:: show ipv6 ospf6 database adv-router A.B.C.D linkstate-id A.B.C.D [json]
+.. clicmd:: show ipv6 ospf6 [vrf <NAME|all>] database adv-router A.B.C.D linkstate-id A.B.C.D [json]
The LSAs additinally can also be filtered with the linkstate-id and
advertising-router fields. We can use the LSA type filter and views with
this command as well and visa-versa. JSON output can be obtained by
appending 'json' to the end of command.
-.. clicmd:: show ipv6 ospf6 database self-originated [json]
+.. clicmd:: show ipv6 ospf6 [vrf <NAME|all>] database self-originated [json]
This command is used to filter the LSAs which are originated by the present
router. All the other filters are applicable here as well.
-.. clicmd:: show ipv6 ospf6 interface [json]
+.. clicmd:: show ipv6 ospf6 [vrf <NAME|all>] interface [json]
To see OSPF interface configuration like costs. JSON output can be
obtained by appending "json" in the end.
-.. clicmd:: show ipv6 ospf6 neighbor [json]
+.. clicmd:: show ipv6 ospf6 [vrf <NAME|all>] neighbor [json]
Shows state and chosen (Backup) DR of neighbor. JSON output can be
obtained by appending 'json' at the end.
-.. clicmd:: show ipv6 ospf6 interface traffic [json]
+.. clicmd:: show ipv6 ospf6 [vrf <NAME|all>] interface traffic [json]
Shows counts of different packets that have been recieved and transmitted
by the interfaces. JSON output can be obtained by appending "json" at the
end.
-.. clicmd:: show ipv6 ospf6 request-list A.B.C.D
-
- Shows requestlist of neighbor.
-
.. clicmd:: show ipv6 route ospf6
This command shows internal routing table.
Shows state about what is being redistributed between zebra and OSPF6.
JSON output can be obtained by appending "json" at the end.
-.. clicmd:: show ipv6 ospf6 redistribute [json]
+.. clicmd:: show ipv6 ospf6 [vrf <NAME|all>] redistribute [json]
Shows the routes which are redistributed by the router. JSON output can
be obtained by appending 'json' at the end.
-.. clicmd:: show ipv6 ospf6 route [<intra-area|inter-area|external-1|external-2|X:X::X:X|X:X::X:X/M|detail|summary>] [json]
+.. clicmd:: show ipv6 ospf6 [vrf <NAME|all>] route [<intra-area|inter-area|external-1|external-2|X:X::X:X|X:X::X:X/M|detail|summary>] [json]
This command displays the ospfv3 routing table as determined by the most
recent SPF calculations. Options are provided to view the different types
and summary. JSON output can be obtained by appending 'json' to the end of
command.
-.. clicmd:: show ipv6 ospf6 route X:X::X:X/M match [detail] [json]
+.. clicmd:: show ipv6 ospf6 [vrf <NAME|all>] route X:X::X:X/M match [detail] [json]
The additional match option will match the given address to the destination
of the routes, and return the result accordingly.
-.. clicmd:: show ipv6 ospf6 interface [IFNAME] prefix [detail|<X:X::X:X|X:X::X:X/M> [<match|detail>]] [json]
+.. clicmd:: show ipv6 ospf6 [vrf <NAME|all>] interface [IFNAME] prefix [detail|<X:X::X:X|X:X::X:X/M> [<match|detail>]] [json]
This command shows the prefixes present in the interface routing table.
Interface name can also be given. JSON output can be obtained by appending
'json' to the end of command.
-.. clicmd:: show ipv6 ospf6 spf tree [json]
+.. clicmd:: show ipv6 ospf6 [vrf <NAME|all>] spf tree [json]
This commands shows the spf tree from the recent spf calculation with the
calling router as the root. If json is appended in the end, we can get the
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.
urib-only
Lookup in the Unicast Rib only.
-.. clicmd:: ip msdp mesh-group [WORD]
-
- Create or Delete a multicast source discovery protocol mesh-group using
- [WORD] as the group name.
-
-.. clicmd:: ip msdp mesh-group WORD member A.B.C.D
-
- Attach or Delete A.B.C.D to the MSDP mesh group WORD specified.
-
-.. clicmd:: ip msdp mesh-group WORD source A.B.C.D
-
- For the address specified A.B.C.D use that as the source address for
- mesh group packets being sent.
-
.. clicmd:: ip igmp generate-query-once [version (2-3)]
Generate IGMP query (v2/v3) on user requirement. This will not depend on
Multicast Source Discovery Protocol (MSDP) Configuration
========================================================
-.. clicmd:: ip msdp mesh-group [WORD] member A.B.C.D
+MSDP can be setup in different ways:
- Include a MSDP peer as a member of a MSDP mesh-group.
+* MSDP meshed-group: where all peers are connected with each other creating
+ a fully meshed network. SAs (source active) messages are not forwarded in
+ this mode because the origin is able to send SAs to all members.
-.. clicmd:: ip msdp mesh-group [WORD] source A.B.C.D
+ This setup is commonly used with anycast.
- Create a MSDP mesh-group, defining a name for it and an associated local source
- address.
+* MSDP peering: when there is one or more peers that are not fully meshed. SAs
+ may be forwarded depending on the result of filtering and RPF checks.
-.. clicmd:: ip msdp peer A.B.C.D source A.B.C.D
+ This setup is commonly consistent with BGP peerings (for RPF checks).
- Establish a MSDP connection with a peer.
+* MSDP default peer: there is only one peer and all SAs will be forwarded
+ there.
+.. note::
- Remove a MSDP peer member from a MSDP mesh-group.
+ MSDP default peer and SA filtering is not implemented.
- Delete a MSDP mesh-group.
+Commands available for MSDP:
+
+
+.. clicmd:: ip msdp mesh-group WORD member A.B.C.D
+
+ Create or update a mesh group to include the specified MSDP peer.
+
+.. clicmd:: ip msdp mesh-group WORD source A.B.C.D
+
+ Create or update a mesh group to set the source address used to connect to
+ peers.
+
+.. clicmd:: ip msdp peer A.B.C.D source A.B.C.D
+ Create a regular MSDP session with peer using the specified source address.
- Delete a MSDP peer connection.
.. _show-pim-information:
RIP routes can be filtered by a distribute-list.
-.. clicmd:: distribute-list ACCESS_LIST DIRECT IFNAME
+.. clicmd:: distribute-list [prefix] LIST <in|out> IFNAME
You can apply access lists to the interface with a `distribute-list` command.
- ACCESS_LIST is the access list name. DIRECT is ``in`` or ``out``. If DIRECT
- is ``in`` the access list is applied to input packets.
+ If prefix is specified LIST is a prefix-list. If prefix is not specified
+ then LIST is the access list name. `in` specifies packets being received,
+ and `out` specifies outgoing packets. Finally if an interface is specified
+ it will be applied against a specific interface.
The `distribute-list` command can be used to filter the RIP path.
`distribute-list` can apply access-lists to a chosen interface. First, one
`distribute-list` can be applied to both incoming and outgoing data.
-.. clicmd:: distribute-list prefix PREFIX_LIST (in|out) IFNAME
-
- You can apply prefix lists to the interface with a `distribute-list`
- command. PREFIX_LIST is the prefix list name. Next is the direction of
- ``in`` or ``out``. If DIRECT is ``in`` the access list is applied to input
- packets.
-
.. _rip-metric-manipulation:
RIP Metric Manipulation
ripngd Filtering Commands
=========================
-.. clicmd:: distribute-list ACCESS_LIST (in|out) IFNAME
+RIPng routes can be filtered by a distribute-list.
- You can apply an access-list to the interface using the `distribute-list`
- command. ACCESS_LIST is an access-list name. `direct` is ``in`` or
- ``out``. If `direct` is ``in``, the access-list is applied only to incoming
- packets.::
+.. clicmd:: distribute-list [prefix] LIST <in|out> IFNAME
- distribute-list local-only out sit1
+ You can apply access lists to the interface with a `distribute-list` command.
+ If prefix is specified LIST is a prefix-list. If prefix is not specified
+ then LIST is the access list name. `in` specifies packets being received,
+ and `out` specifies outgoing packets. Finally if an interface is specified
+ it will be applied against a specific interface.
+
+ The ``distribute-list`` command can be used to filter the RIPNG path.
+ ``distribute-list`` can apply access-lists to a chosen interface. First, one
+ should specify the access-list. Next, the name of the access-list is used in
+ the distribute-list command. For example, in the following configuration
+ ``eth0`` will permit only the paths that match the route 10.0.0.0/8
+
+ .. code-block:: frr
+
+ !
+ router ripng
+ distribute-list private in eth0
+ !
+ access-list private permit 10 10.0.0.0/8
+ access-list private deny any
+ !
+
+
+ `distribute-list` can be applied to both incoming and outgoing data.
Sample configuration
Allow end user to dump associated data with the nexthop tracking that
may have been turned on.
+.. clicmd:: sharp watch [vrf NAME] redistribute ROUTETYPE
+
+ Allow end user to monitor redistributed routes of ROUTETYPE
+ origin.
+
.. clicmd:: sharp lsp [update] (0-100000) nexthop-group NAME [prefix A.B.C.D/M TYPE [instance (0-255)]]
Install an LSP using the specified in-label, with nexthops as
./configure --with-defaultvrfname=global
+.. _zebra-ecmp:
+
+ECMP
+====
+
+FRR supports ECMP as part of normal operations and is generally compiled
+with a limit of 64 way ECMP. This of course can be modified via configure
+options on compilation if the end operator desires to do so. Individual
+protocols each have their own way of dictating ECMP policy and their
+respective documentation should be read.
+
+ECMP can be inspected in zebra by doing a `show ip route X` command.
+
+.. code-block:: shell
+
+ eva# show ip route 4.4.4.4/32
+ Codes: K - kernel route, C - connected, S - static, R - RIP,
+ O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP,
+ T - Table, v - VNC, V - VNC-Direct, A - Babel, D - SHARP,
+ F - PBR, f - OpenFabric,
+ > - selected route, * - FIB route, q - queued, r - rejected, b - backup
+ t - trapped, o - offload failure
+
+ D>* 4.4.4.4/32 [150/0] via 192.168.161.1, enp39s0, weight 1, 00:00:02
+ * via 192.168.161.2, enp39s0, weight 1, 00:00:02
+ * via 192.168.161.3, enp39s0, weight 1, 00:00:02
+ * via 192.168.161.4, enp39s0, weight 1, 00:00:02
+ * via 192.168.161.5, enp39s0, weight 1, 00:00:02
+ * via 192.168.161.6, enp39s0, weight 1, 00:00:02
+ * via 192.168.161.7, enp39s0, weight 1, 00:00:02
+ * via 192.168.161.8, enp39s0, weight 1, 00:00:02
+ * via 192.168.161.9, enp39s0, weight 1, 00:00:02
+ * via 192.168.161.10, enp39s0, weight 1, 00:00:02
+ * via 192.168.161.11, enp39s0, weight 1, 00:00:02
+ * via 192.168.161.12, enp39s0, weight 1, 00:00:02
+ * via 192.168.161.13, enp39s0, weight 1, 00:00:02
+ * via 192.168.161.14, enp39s0, weight 1, 00:00:02
+ * via 192.168.161.15, enp39s0, weight 1, 00:00:02
+ * via 192.168.161.16, enp39s0, weight 1, 00:00:02
+
+In this example we have 16 way ecmp for the 4.4.4.4/32 route. The `*` character
+tells us that the route is installed in the Data Plane, or FIB.
+
+If you are using the Linux kernel as a Data Plane, this can be inspected
+via a `ip route show X` command:
+
+.. code-block:: shell
+
+ sharpd@eva ~/f/doc(ecmp_doc_change)> ip route show 4.4.4.4/32
+ 4.4.4.4 nhid 185483868 proto sharp metric 20
+ nexthop via 192.168.161.1 dev enp39s0 weight 1
+ nexthop via 192.168.161.10 dev enp39s0 weight 1
+ nexthop via 192.168.161.11 dev enp39s0 weight 1
+ nexthop via 192.168.161.12 dev enp39s0 weight 1
+ nexthop via 192.168.161.13 dev enp39s0 weight 1
+ nexthop via 192.168.161.14 dev enp39s0 weight 1
+ nexthop via 192.168.161.15 dev enp39s0 weight 1
+ nexthop via 192.168.161.16 dev enp39s0 weight 1
+ nexthop via 192.168.161.2 dev enp39s0 weight 1
+ nexthop via 192.168.161.3 dev enp39s0 weight 1
+ nexthop via 192.168.161.4 dev enp39s0 weight 1
+ nexthop via 192.168.161.5 dev enp39s0 weight 1
+ nexthop via 192.168.161.6 dev enp39s0 weight 1
+ nexthop via 192.168.161.7 dev enp39s0 weight 1
+ nexthop via 192.168.161.8 dev enp39s0 weight 1
+ nexthop via 192.168.161.9 dev enp39s0 weight 1
+
+Once installed into the FIB, FRR currently has little control over what
+nexthops are choosen to forward packets on. Currently the Linux kernel
+has a `fib_multipath_hash_policy` sysctl which dictates how the hashing
+algorithm is used to forward packets.
+
.. _zebra-mpls:
MPLS Commands
Display the user configured IPv6 router-id.
+Expected sysctl settings
+========================
+
+The linux kernel has a variety of sysctl's that affect it's operation as a router. This
+section is meant to act as a starting point for those sysctl's that must be used in
+order to provide FRR with smooth operation as a router. This section is not meant
+as the full documentation for sysctl's. The operator must use the sysctl documentation
+with the linux kernel for that.
+
+.. option:: net.ipv4.ip_forward = 1
+
+ This option allows the linux kernel to forward ipv4 packets incoming from one interface
+ to an outgoing interface. Without this no forwarding will take place from off box packets.
+
+.. option:: net.ipv6.conf.all_forwarding=1
+
+ This option allows the linux kernel to forward ipv6 packets incoming from one interface
+ to an outgoing interface. Without this no forwarding will take place from off box packets.
+
+.. option:: net.ipv6.conf.all.keep_addr_on_down=1
+
+ When an interface is taken down, do not remove the v6 addresses associated with the interface.
+ This option is recommended because this is the default behavior for v4 as well.
+
+.. option:: net.ipv6.route.skip_notify_on_dev_down=1
+
+ When an interface is taken down, the linux kernel will not notify, via netlink, about routes
+ that used that interface being removed from the FIB. This option is recommended because this
+ is the default behavior for v4 as well.
Debugging
=========
# 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 \
--allow-untrusted /pkgs/apk/*/*.apk \
&& rm -rf /pkgs
COPY docker/alpine/docker-start /usr/lib/frr/docker-start
-ENTRYPOINT [ "/sbin/tini", "--", "/usr/lib/frr/docker-start" ]
+CMD [ "/sbin/tini", "--", "/usr/lib/frr/docker-start" ]
RUN yum install -y /pkgs/rpm/*/*.rpm \
&& rm -rf /pkgs
COPY docker/centos-7/docker-start /usr/lib/frr/docker-start
-ENTRYPOINT [ "/usr/lib/frr/docker-start" ]
+CMD [ "/usr/lib/frr/docker-start" ]
RUN yum install -y /pkgs/rpm/*/*.rpm \
&& rm -rf /pkgs
COPY docker/centos-8/docker-start /usr/lib/frr/docker-start
-ENTRYPOINT [ "/usr/lib/frr/docker-start" ]
+CMD [ "/usr/lib/frr/docker-start" ]
rm -rf /var/lib/apt/lists/*
ADD docker-start /usr/sbin/docker-start
-ENTRYPOINT ["/usr/sbin/docker-start"]
+CMD ["/usr/sbin/docker-start"]
##
chown -R frr:frr /etc/frr
/etc/init.d/frr start
-exec sleep 10000d
+
+# Sleep forever
+exec tail -f /dev/null
--- /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
+CMD ["/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
+CMD ["/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
struct eigrp *eigrp = nbr->ei->eigrp;
struct TLV_Parameter_Type *param = (struct TLV_Parameter_Type *)tlv;
+ /* First validate TLV length */
+ if (tlv->length < sizeof(struct TLV_Parameter_Type))
+ return NULL;
+
/* copy over the values passed in by the neighbor */
nbr->K1 = param->K1;
nbr->K2 = param->K2;
md5 = (struct TLV_MD5_Authentication_Type *)tlv_header;
- if (md5->auth_type == EIGRP_AUTH_TYPE_MD5)
+ if (md5->auth_type == EIGRP_AUTH_TYPE_MD5) {
+ /* Validate tlv length */
+ if (md5->length < sizeof(struct TLV_MD5_Authentication_Type))
+ return 0;
+
return eigrp_check_md5_digest(s, md5, nbr,
EIGRP_AUTH_BASIC_HELLO_FLAG);
- else if (md5->auth_type == EIGRP_AUTH_TYPE_SHA256)
+ } else if (md5->auth_type == EIGRP_AUTH_TYPE_SHA256) {
+ /* Validate tlv length */
+ if (md5->length < sizeof(struct TLV_SHA256_Authentication_Type))
+ return 0;
+
return eigrp_check_sha256_digest(
s, (struct TLV_SHA256_Authentication_Type *)tlv_header,
nbr, EIGRP_AUTH_BASIC_HELLO_FLAG);
+ }
return 0;
}
{
struct TLV_Software_Type *version = (struct TLV_Software_Type *)tlv;
+ /* Validate TLV length */
+ if (tlv->length < sizeof(struct TLV_Software_Type))
+ return;
+
nbr->os_rel_major = version->vender_major;
nbr->os_rel_minor = version->vender_minor;
nbr->tlv_rel_major = version->eigrp_major;
struct TLV_Peer_Termination_type *param =
(struct TLV_Peer_Termination_type *)tlv;
+ /* Validate TLV length */
+ if (tlv->length < sizeof(struct TLV_Peer_Termination_type))
+ return;
+
uint32_t my_ip = nbr->ei->address.u.prefix4.s_addr;
uint32_t received_ip = param->neighbor_ip;
type = ntohs(tlv_header->type);
length = ntohs(tlv_header->length);
+ /* Validate length against packet size */
+ if (length > size)
+ return;
+
if ((length > 0) && (length <= size)) {
if (IS_DEBUG_EIGRP_PACKET(0, RECV))
zlog_debug(
route_map_add_hook (eigrp_rmap_update);
route_map_delete_hook (eigrp_rmap_update);*/
/*if_rmap_init (EIGRP_NODE); */
- /* Distribute list install. */
- distribute_list_init(EIGRP_NODE);
frr_config_fork();
frr_run(master);
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <zebra.h>
+
#include "eigrpd/eigrp_structs.h"
#include "eigrpd/eigrpd.h"
#include "eigrpd/eigrp_types.h"
&& IS_DEBUG_EIGRP_TRANSMIT(0, PACKET_DETAIL))
eigrp_header_dump(eigrph);
- // if (MSG_OK != eigrp_packet_examin(eigrph, stream_get_endp(ibuf) -
- // stream_get_getp(ibuf)))
- // return -1;
+ if (ntohs(eigrph->ASNumber) != eigrp->AS) {
+ if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
+ zlog_debug(
+ "ignoring packet from router %u sent to %pI4, wrong AS Number received: %u",
+ ntohs(eigrph->vrid), &iph->ip_dst,
+ ntohs(eigrph->ASNumber));
+ return 0;
+ }
/* If incoming interface is passive one, ignore it. */
if (eigrp_if_is_passive(ei)) {
"Tag value for routing protocol\n"
"Tag value\n")
+DEFUN (eigrp_distribute_list,
+ eigrp_distribute_list_cmd,
+ "distribute-list [prefix] WORD <in|out> [WORD]",
+ "Filter networks in routing updates\n"
+ "Specify a prefix\n"
+ "Access-list name\n"
+ "Filter incoming routing updates\n"
+ "Filter outgoing routing updates\n"
+ "Interface name\n")
+{
+ const char *ifname = NULL;
+ int prefix = (argv[1]->type == WORD_TKN) ? 1 : 0;
+
+ if (argv[argc - 1]->type == VARIABLE_TKN)
+ ifname = argv[argc - 1]->arg;
+
+ return distribute_list_parser(prefix, true, argv[2 + prefix]->text,
+ argv[1 + prefix]->arg, ifname);
+}
+
+DEFUN (eigrp_no_distribute_list,
+ eigrp_no_distribute_list_cmd,
+ "no distribute-list [prefix] WORD <in|out> [WORD]",
+ NO_STR
+ "Filter networks in routing updates\n"
+ "Specify a prefix\n"
+ "Access-list name\n"
+ "Filter incoming routing updates\n"
+ "Filter outgoing routing updates\n"
+ "Interface name\n")
+{
+ const char *ifname = NULL;
+ int prefix = (argv[2]->type == WORD_TKN) ? 1 : 0;
+
+ if (argv[argc - 1]->type == VARIABLE_TKN)
+ ifname = argv[argc - 1]->arg;
+
+ return distribute_list_no_parser(vty, prefix, true,
+ argv[3 + prefix]->text,
+ argv[2 + prefix]->arg, ifname);
+}
+
/* Route-map init */
void eigrp_route_map_init()
route_map_add_hook(eigrp_route_map_update);
route_map_delete_hook(eigrp_route_map_update);
+ install_element(EIGRP_NODE, &eigrp_distribute_list_cmd);
+ install_element(EIGRP_NODE, &eigrp_no_distribute_list_cmd);
+
/*route_map_install_match (&route_match_metric_cmd);
route_map_install_match (&route_match_interface_cmd);*/
/*route_map_install_match (&route_match_ip_next_hop_cmd);
#ifndef _FPM_PB_H
#define _FPM_PB_H
-#include "route_types.h"
+#include "lib/route_types.h"
#include "qpb/qpb.h"
#include "fpm/fpm.pb-c.h"
AM_V_PROTOC = $(am__v_PROTOC_$(V))
am__v_PROTOC_ = $(am__v_PROTOC_$(AM_DEFAULT_VERBOSITY))
-am__v_PROTOC_0 = @echo " PROTOC" $@;
+am__v_PROTOC_0 = @echo " PROTOC " $@;
am__v_PROTOC_1 =
SUFFIXES += .pb.h .pb.cc .grpc.pb.cc
.proto.pb.cc:
- $(AM_V_PROTOC)$(PROTOC) -I$(top_srcdir) --cpp_out=$(top_srcdir) $(top_srcdir)/$^
+ $(AM_V_PROTOC)$(PROTOC) -I$(top_srcdir) --cpp_out=$(top_builddir) $^
.proto.grpc.pb.cc:
- $(AM_V_PROTOC)$(PROTOC) -I$(top_srcdir) --grpc_out=$(top_srcdir) --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` $(top_srcdir)/$^
+ $(AM_V_PROTOC)$(PROTOC) -I$(top_srcdir) --grpc_out=$(top_builddir) --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` $^
--- /dev/null
+#ifndef __LINUX_IF_PACKET_H
+#define __LINUX_IF_PACKET_H
+
+#include <linux/types.h>
+
+struct sockaddr_ll {
+ unsigned short sll_family;
+ __be16 sll_protocol;
+ int sll_ifindex;
+ unsigned short sll_hatype;
+ unsigned char sll_pkttype;
+ unsigned char sll_halen;
+ unsigned char sll_addr[8];
+};
+
+#endif
--- /dev/null
+#ifndef _IF_TUNNEL_H_
+#define _IF_TUNNEL_H_
+
+#include <linux/types.h>
+#include <linux/if.h>
+#include <linux/ip.h>
+#include <linux/in6.h>
+#include <asm/byteorder.h>
+
+
+#define SIOCGETTUNNEL (SIOCDEVPRIVATE + 0)
+#define SIOCADDTUNNEL (SIOCDEVPRIVATE + 1)
+#define SIOCDELTUNNEL (SIOCDEVPRIVATE + 2)
+#define SIOCCHGTUNNEL (SIOCDEVPRIVATE + 3)
+#define SIOCGETPRL (SIOCDEVPRIVATE + 4)
+#define SIOCADDPRL (SIOCDEVPRIVATE + 5)
+#define SIOCDELPRL (SIOCDEVPRIVATE + 6)
+#define SIOCCHGPRL (SIOCDEVPRIVATE + 7)
+
+#define GRE_CSUM __cpu_to_be16(0x8000)
+#define GRE_ROUTING __cpu_to_be16(0x4000)
+#define GRE_KEY __cpu_to_be16(0x2000)
+#define GRE_SEQ __cpu_to_be16(0x1000)
+#define GRE_STRICT __cpu_to_be16(0x0800)
+#define GRE_REC __cpu_to_be16(0x0700)
+#define GRE_FLAGS __cpu_to_be16(0x00F8)
+#define GRE_VERSION __cpu_to_be16(0x0007)
+
+struct ip_tunnel_parm {
+ char name[IFNAMSIZ];
+ int link;
+ __be16 i_flags;
+ __be16 o_flags;
+ __be32 i_key;
+ __be32 o_key;
+ struct iphdr iph;
+};
+
+/* SIT-mode i_flags */
+#define SIT_ISATAP 0x0001
+
+struct ip_tunnel_prl {
+ __be32 addr;
+ __u16 flags;
+ __u16 __reserved;
+ __u32 datalen;
+ __u32 __reserved2;
+ /* data follows */
+};
+
+/* PRL flags */
+#define PRL_DEFAULT 0x0001
+
+enum {
+ IFLA_GRE_UNSPEC,
+ IFLA_GRE_LINK,
+ IFLA_GRE_IFLAGS,
+ IFLA_GRE_OFLAGS,
+ IFLA_GRE_IKEY,
+ IFLA_GRE_OKEY,
+ IFLA_GRE_LOCAL,
+ IFLA_GRE_REMOTE,
+ IFLA_GRE_TTL,
+ IFLA_GRE_TOS,
+ IFLA_GRE_PMTUDISC,
+ __IFLA_GRE_MAX,
+};
+
+#define IFLA_GRE_MAX (__IFLA_GRE_MAX - 1)
+
+#endif /* _IF_TUNNEL_H_ */
int isis_if_new_hook(struct interface *);
int isis_if_delete_hook(struct interface *);
-static int isis_circuit_smmp_id_gen(struct isis_circuit *circuit)
-{
- struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
- struct isis *isis = NULL;
- uint32_t id;
- uint32_t i;
-
- isis = isis_lookup_by_vrfid(vrf->vrf_id);
- if (isis == NULL)
- return 0;
-
- id = isis->snmp_circuit_id_last;
- id++;
+DEFINE_HOOK(isis_circuit_new_hook, (struct isis_circuit *circuit), (circuit));
+DEFINE_HOOK(isis_circuit_del_hook, (struct isis_circuit *circuit), (circuit));
- /* find next unused entry */
- for (i = 0; i < SNMP_CIRCUITS_MAX; i++) {
- if (id >= SNMP_CIRCUITS_MAX) {
- id = 0;
- continue;
- }
-
- if (id == 0)
- continue;
+static void isis_circuit_enable(struct isis_circuit *circuit)
+{
+ struct isis_area *area;
+ struct interface *ifp = circuit->interface;
- if (isis->snmp_circuits[id] == NULL)
- break;
+ area = isis_area_lookup(circuit->tag, ifp->vrf_id);
+ if (area)
+ isis_area_add_circuit(area, circuit);
- id++;
- }
+ if (if_is_operative(ifp))
+ isis_csm_state_change(IF_UP_FROM_Z, circuit, ifp);
+}
- if (i == SNMP_CIRCUITS_MAX) {
- zlog_warn("Could not allocate a smmp-circuit-id");
- return 0;
- }
+static void isis_circuit_disable(struct isis_circuit *circuit)
+{
+ struct isis_area *area = circuit->area;
+ struct interface *ifp = circuit->interface;
- isis->snmp_circuits[id] = circuit;
- isis->snmp_circuit_id_last = id;
- circuit->snmp_id = id;
+ if (if_is_operative(ifp))
+ isis_csm_state_change(IF_DOWN_FROM_Z, circuit, ifp);
- return 1;
+ if (area)
+ isis_area_del_circuit(area, circuit);
}
-struct isis_circuit *isis_circuit_new(struct isis *isis)
+struct isis_circuit *isis_circuit_new(struct interface *ifp, const char *tag)
{
struct isis_circuit *circuit;
int i;
circuit = XCALLOC(MTYPE_ISIS_CIRCUIT, sizeof(struct isis_circuit));
- circuit->isis = isis;
- /*
- * Note: if snmp-id generation failed circuit will fail
- * up operation
- */
- isis_circuit_smmp_id_gen(circuit);
+ circuit->tag = XSTRDUP(MTYPE_ISIS_CIRCUIT, tag);
/*
* Default values
isis_lfa_excluded_ifaces_init(circuit, ISIS_LEVEL1);
isis_lfa_excluded_ifaces_init(circuit, ISIS_LEVEL2);
+ circuit->ldp_sync_info = ldp_sync_info_create();
+ circuit->ldp_sync_info->enabled = LDP_IGP_SYNC_ENABLED;
+
QOBJ_REG(circuit, isis_circuit);
+ isis_circuit_if_bind(circuit, ifp);
+
+ if (ifp->ifindex != IFINDEX_INTERNAL)
+ isis_circuit_enable(circuit);
+
return circuit;
}
void isis_circuit_del(struct isis_circuit *circuit)
{
- struct isis *isis = NULL;
-
if (!circuit)
return;
- QOBJ_UNREG(circuit);
-
- if (circuit->interface) {
- isis = isis_lookup_by_vrfid(circuit->interface->vrf_id);
- isis->snmp_circuits[circuit->snmp_id] = NULL;
- }
+ if (circuit->interface->ifindex != IFINDEX_INTERNAL)
+ isis_circuit_disable(circuit);
isis_circuit_if_unbind(circuit, circuit->interface);
+ QOBJ_UNREG(circuit);
+
+ ldp_sync_info_free(&circuit->ldp_sync_info);
+
circuit_mt_finish(circuit);
isis_lfa_excluded_ifaces_clear(circuit, ISIS_LEVEL1);
isis_lfa_excluded_ifaces_clear(circuit, ISIS_LEVEL2);
+ XFREE(MTYPE_ISIS_CIRCUIT, circuit->tag);
+
/* and lastly the circuit itself */
XFREE(MTYPE_ISIS_CIRCUIT, circuit);
struct isis_area *area)
{
assert(area);
+ circuit->isis = area->isis;
circuit->area = area;
/*
circuit->idx = flags_get_index(&area->flags);
+ hook_call(isis_circuit_new_hook, circuit);
+
return;
}
void isis_circuit_deconfigure(struct isis_circuit *circuit,
struct isis_area *area)
{
+ hook_call(isis_circuit_del_hook, circuit);
+
/* Free the index of SRM and SSN flags */
flags_free_index(&area->flags, circuit->idx);
circuit->idx = 0;
assert(circuit->area == area);
listnode_delete(area->circuit_list, circuit);
circuit->area = NULL;
+ circuit->isis = NULL;
return;
}
struct isis_circuit *circuit_scan_by_ifp(struct interface *ifp)
{
- struct isis_area *area;
- struct listnode *node;
- struct isis_circuit *circuit;
- struct isis *isis = NULL;
-
- if (ifp->info)
- return (struct isis_circuit *)ifp->info;
-
- isis = isis_lookup_by_vrfid(ifp->vrf_id);
- if (isis == NULL) {
- zlog_warn(" %s : ISIS routing instance not found", __func__);
- return NULL;
- }
-
- if (isis->area_list) {
- for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
- circuit =
- circuit_lookup_by_ifp(ifp, area->circuit_list);
- if (circuit)
- return circuit;
- }
- }
- return circuit_lookup_by_ifp(ifp, isis->init_circ_list);
+ return (struct isis_circuit *)ifp->info;
}
DEFINE_HOOK(isis_circuit_add_addr_hook, (struct isis_circuit *circuit),
struct listnode *node, *nnode;
struct connected *conn;
- isis_circuit_if_bind(circuit, ifp);
-
if (if_is_broadcast(ifp)) {
if (fabricd || circuit->circ_type_config == CIRCUIT_T_P2P)
circuit->circ_type = CIRCUIT_T_P2P;
return ISIS_OK;
}
- if (circuit->snmp_id == 0) {
- /* We cannot bring circuit up if does not have snmp-id */
- flog_err(EC_ISIS_CONFIG,
- "No snnmp-id: there are too many circuits:");
- return ISIS_ERROR;
- }
-
if (circuit->area->lsp_mtu > isis_circuit_pdu_size(circuit)) {
flog_err(
EC_ISIS_CONFIG,
circuit->last_uptime = time(NULL);
+ if (circuit->area->mta && circuit->area->mta->status)
+ isis_link_params_update(circuit, circuit->interface);
+
+ isis_if_ldp_sync_enable(circuit);
+
#ifndef FABRICD
/* send northbound notification */
isis_notif_if_state_change(circuit, false);
isis_notif_if_state_change(circuit, true);
#endif /* ifndef FABRICD */
+ isis_if_ldp_sync_disable(circuit);
+
/* log adjacency changes if configured to do so */
if (circuit->area->log_adj_changes) {
struct isis_adjacency *adj = NULL;
}
#endif /* ifdef FABRICD */
-struct isis_circuit *isis_circuit_create(struct isis_area *area,
- struct interface *ifp)
-{
- struct isis_circuit *circuit = circuit_scan_by_ifp(ifp);
-
- if (circuit && circuit->area)
- return NULL;
- circuit = isis_csm_state_change(ISIS_ENABLE, circuit, area);
- if (circuit->state != C_STATE_CONF && circuit->state != C_STATE_UP)
- return circuit;
- isis_circuit_if_bind(circuit, ifp);
- if (circuit->area->mta && circuit->area->mta->status)
- isis_link_params_update(circuit, ifp);
-
- return circuit;
-}
-
void isis_circuit_af_set(struct isis_circuit *circuit, bool ip_router,
bool ipv6_router)
{
circuit->ipv6_router = ipv6_router;
circuit_update_nlpids(circuit);
- /* the area should always be there if we get here, but in the past
- * there were corner cases where the area was NULL (e.g. because the
- * circuit was deconfigured following a validation error). Do not
- * segfault if this happens again.
- */
- if (!area) {
- zlog_err("%s: NULL area for circuit %u", __func__,
- circuit->circuit_id);
- return;
- }
-
- area->ip_circuits += ip_router - old_ipr;
- area->ipv6_circuits += ipv6_router - old_ipv6r;
+ if (area) {
+ area->ip_circuits += ip_router - old_ipr;
+ area->ipv6_circuits += ipv6_router - old_ipv6r;
- if (!ip_router && !ipv6_router)
- isis_csm_state_change(ISIS_DISABLE, circuit, area);
- else
- lsp_regenerate_schedule(area, circuit->is_type, 0);
+ if (ip_router || ipv6_router)
+ lsp_regenerate_schedule(area, circuit->is_type, 0);
+ }
}
ferr_r isis_circuit_passive_set(struct isis_circuit *circuit, bool passive)
setting = circuit_get_mt_setting(circuit, mtid);
if (setting->enabled != enabled) {
setting->enabled = enabled;
- lsp_regenerate_schedule(circuit->area, IS_LEVEL_1 | IS_LEVEL_2,
- 0);
+ if (circuit->area)
+ lsp_regenerate_schedule(circuit->area,
+ IS_LEVEL_1 | IS_LEVEL_2, 0);
}
return CMD_SUCCESS;
int isis_if_delete_hook(struct interface *ifp)
{
- struct isis_circuit *circuit;
- /* Clean up the circuit data */
- if (ifp && ifp->info) {
- circuit = ifp->info;
- isis_csm_state_change(IF_DOWN_FROM_Z, circuit, ifp);
- }
+ if (ifp->info)
+ isis_circuit_del(ifp->info);
return 0;
}
static int isis_ifp_create(struct interface *ifp)
{
- struct vrf *vrf = NULL;
+ struct isis_circuit *circuit = ifp->info;
+
+ if (circuit)
+ isis_circuit_enable(circuit);
- if (if_is_operative(ifp)) {
- vrf = vrf_lookup_by_id(ifp->vrf_id);
- if (vrf)
- isis_global_instance_create(vrf->name);
- isis_csm_state_change(IF_UP_FROM_Z, circuit_scan_by_ifp(ifp),
- ifp);
- }
hook_call(isis_if_new_hook, ifp);
return 0;
static int isis_ifp_up(struct interface *ifp)
{
- isis_csm_state_change(IF_UP_FROM_Z, circuit_scan_by_ifp(ifp), ifp);
+ struct isis_circuit *circuit = ifp->info;
+
+ if (circuit)
+ isis_csm_state_change(IF_UP_FROM_Z, circuit, ifp);
return 0;
}
static int isis_ifp_down(struct interface *ifp)
{
- struct isis_circuit *circuit;
+ struct isis_circuit *circuit = ifp->info;
+
+ if (circuit) {
+ isis_csm_state_change(IF_DOWN_FROM_Z, circuit, ifp);
- circuit = isis_csm_state_change(IF_DOWN_FROM_Z,
- circuit_scan_by_ifp(ifp), ifp);
- if (circuit)
SET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF);
+ }
return 0;
}
static int isis_ifp_destroy(struct interface *ifp)
{
- if (if_is_operative(ifp))
- zlog_warn("Zebra: got delete of %s, but interface is still up",
- ifp->name);
-
- isis_csm_state_change(IF_DOWN_FROM_Z, circuit_scan_by_ifp(ifp), ifp);
+ struct isis_circuit *circuit = ifp->info;
- /* Cannot call if_delete because we should retain the pseudo interface
- in case there is configuration info attached to it. */
- if_delete_retain(ifp);
+ if (circuit)
+ isis_circuit_disable(circuit);
return 0;
}
#include "isis_constants.h"
#include "isis_common.h"
+#include "isis_csm.h"
DECLARE_HOOK(isis_if_new_hook, (struct interface *ifp), (ifp));
};
struct isis_circuit {
- int state;
+ enum isis_circuit_state state;
uint8_t circuit_id; /* l1/l2 bcast CircuitID */
time_t last_uptime;
struct isis *isis;
/*
* Configurables
*/
+ char *tag; /* area tag */
struct isis_passwd passwd; /* Circuit rx/tx password */
int is_type; /* circuit is type == level of circuit
* differentiated from circuit type (media) */
struct hash *lfa_excluded_ifaces[ISIS_LEVELS];
bool tilfa_protection[ISIS_LEVELS];
bool tilfa_node_protection[ISIS_LEVELS];
+ bool tilfa_link_fallback[ISIS_LEVELS];
/*
* Counters as in 10589--11.2.5.9
*/
DECLARE_QOBJ_TYPE(isis_circuit);
void isis_circuit_init(void);
-struct isis_circuit *isis_circuit_new(struct isis *isis);
+struct isis_circuit *isis_circuit_new(struct interface *ifp, const char *tag);
void isis_circuit_del(struct isis_circuit *circuit);
struct isis_circuit *circuit_lookup_by_ifp(struct interface *ifp,
struct list *list);
size_t isis_circuit_pdu_size(struct isis_circuit *circuit);
void isis_circuit_stream(struct isis_circuit *circuit, struct stream **stream);
-struct isis_circuit *isis_circuit_create(struct isis_area *area,
- struct interface *ifp);
void isis_circuit_af_set(struct isis_circuit *circuit, bool ip_router,
bool ipv6_router);
ferr_r isis_circuit_passive_set(struct isis_circuit *circuit, bool passive);
DECLARE_HOOK(isis_circuit_add_addr_hook, (struct isis_circuit *circuit),
(circuit));
+DECLARE_HOOK(isis_circuit_new_hook, (struct isis_circuit *circuit), (circuit));
+DECLARE_HOOK(isis_circuit_del_hook, (struct isis_circuit *circuit), (circuit));
+
#endif /* _ZEBRA_ISIS_CIRCUIT_H */
"/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']", tag,
vrf_name);
nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL);
- /* default value in yang for is-type is level-1, but in FRR
- * the first instance is assigned is-type level-1-2. We
- * need to make sure to set it in the yang model so that it
- * is consistent with what FRR sees.
- */
-
- if (!im) {
- return CMD_SUCCESS;
- }
- if (listcount(im->isis) == 0)
- nb_cli_enqueue_change(vty, "./is-type", NB_OP_MODIFY,
- "level-1-2");
ret = nb_cli_apply_changes(vty, base_xpath);
if (ret == CMD_SUCCESS)
VTY_PUSH_XPATH(ISIS_NODE, base_xpath);
return ret;
}
+struct if_iter {
+ struct vty *vty;
+ const char *tag;
+};
+
+static int if_iter_cb(const struct lyd_node *dnode, void *arg)
+{
+ struct if_iter *iter = arg;
+ const char *tag;
+
+ if (!yang_dnode_exists(dnode, "frr-isisd:isis/area-tag"))
+ return YANG_ITER_CONTINUE;
+
+ tag = yang_dnode_get_string(dnode, "frr-isisd:isis/area-tag");
+ if (strmatch(tag, iter->tag)) {
+ char xpath[XPATH_MAXLEN];
+ const char *name = yang_dnode_get_string(dnode, "name");
+ const char *vrf = yang_dnode_get_string(dnode, "vrf");
+
+ snprintf(
+ xpath, XPATH_MAXLEN,
+ "/frr-interface:lib/interface[name='%s'][vrf='%s']/frr-isisd:isis",
+ name, vrf);
+ nb_cli_enqueue_change(iter->vty, xpath, NB_OP_DESTROY, NULL);
+ }
+
+ return YANG_ITER_CONTINUE;
+}
+
DEFPY_YANG(no_router_isis, no_router_isis_cmd,
"no router isis WORD$tag [vrf NAME$vrf_name]",
NO_STR ROUTER_STR
"ISO IS-IS\n"
"ISO Routing area tag\n" VRF_CMD_HELP_STR)
{
- char temp_xpath[XPATH_MAXLEN];
- struct listnode *node, *nnode;
- struct isis_circuit *circuit = NULL;
- struct isis_area *area = NULL;
+ struct if_iter iter;
if (!vrf_name)
vrf_name = VRF_DEFAULT_NAME;
return CMD_ERR_NOTHING_TODO;
}
+ iter.vty = vty;
+ iter.tag = tag;
+
+ yang_dnode_iterate(if_iter_cb, &iter, vty->candidate_config->dnode,
+ "/frr-interface:lib/interface[vrf='%s']", vrf_name);
+
nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
- area = isis_area_lookup_by_vrf(tag, vrf_name);
- if (area && area->circuit_list && listcount(area->circuit_list)) {
- for (ALL_LIST_ELEMENTS(area->circuit_list, node, nnode,
- circuit)) {
- /* add callbacks to delete each of the circuits listed
- */
- const char *vrf_name =
- vrf_lookup_by_id(circuit->interface->vrf_id)
- ->name;
- snprintf(
- temp_xpath, XPATH_MAXLEN,
- "/frr-interface:lib/interface[name='%s'][vrf='%s']/frr-isisd:isis",
- circuit->interface->name, vrf_name);
- nb_cli_enqueue_change(vty, temp_xpath, NB_OP_DESTROY,
- NULL);
- }
- }
return nb_cli_apply_changes(
vty, "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']", tag,
* XPath: /frr-isisd:isis/instance
*/
DEFPY_YANG(ip_router_isis, ip_router_isis_cmd,
- "ip router isis WORD$tag [vrf NAME$vrf_name]",
+ "ip router isis WORD$tag",
"Interface Internet Protocol config commands\n"
"IP router interface commands\n"
"IS-IS routing protocol\n"
- "Routing process tag\n" VRF_CMD_HELP_STR)
+ "Routing process tag\n")
{
- char temp_xpath[XPATH_MAXLEN];
- const char *circ_type;
- struct isis_area *area = NULL;
+ char inst_xpath[XPATH_MAXLEN];
+ struct lyd_node *if_dnode, *inst_dnode;
+ const char *circ_type = NULL;
+ const char *vrf_name;
struct interface *ifp;
- struct vrf *vrf;
-
- /* area will be created if it is not present. make sure the yang model
- * is synced with FRR and call the appropriate NB cb.
- */
- if (!im) {
- return CMD_SUCCESS;
- }
- ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
- if (!vrf_name) {
- if (ifp) {
- if (ifp->vrf_id == VRF_DEFAULT)
- vrf_name = VRF_DEFAULT_NAME;
- else {
- vrf = vrf_lookup_by_id(ifp->vrf_id);
- if (vrf && !vrf_name)
- vrf_name = vrf->name;
- }
- } else
- vrf_name = VRF_DEFAULT_NAME;
+ if_dnode = yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
+ if (!if_dnode) {
+ vty_out(vty, "%% Failed to get iface dnode in candidate DB\n");
+ return CMD_WARNING_CONFIG_FAILED;
}
- area = isis_area_lookup_by_vrf(tag, vrf_name);
- if (!area) {
- isis_global_instance_create(vrf_name);
- snprintf(temp_xpath, XPATH_MAXLEN,
- "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']",
- tag, vrf_name);
- nb_cli_enqueue_change(vty, temp_xpath, NB_OP_CREATE, tag);
- snprintf(
- temp_xpath, XPATH_MAXLEN,
- "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']/is-type",
- tag, vrf_name);
- nb_cli_enqueue_change(vty, temp_xpath, NB_OP_MODIFY,
- listcount(im->isis) == 0 ? "level-1-2"
- : NULL);
- nb_cli_enqueue_change(vty, "./frr-isisd:isis", NB_OP_CREATE,
- NULL);
- nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag",
- NB_OP_MODIFY, tag);
+ vrf_name = yang_dnode_get_string(if_dnode, "vrf");
- nb_cli_enqueue_change(vty, "./frr-isisd:isis/vrf", NB_OP_MODIFY,
- vrf_name);
- nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv4-routing",
- NB_OP_MODIFY, "true");
- nb_cli_enqueue_change(
- vty, "./frr-isisd:isis/circuit-type", NB_OP_MODIFY,
- listcount(im->isis) == 0 ? "level-1-2" : "level-1");
- } else {
- /* area exists, circuit type defaults to its area's is_type */
- switch (area->is_type) {
- case IS_LEVEL_1:
- circ_type = "level-1";
- break;
- case IS_LEVEL_2:
- circ_type = "level-2";
- break;
- case IS_LEVEL_1_AND_2:
- circ_type = "level-1-2";
- break;
- default:
- /* just to silence compiler warnings */
- return CMD_WARNING_CONFIG_FAILED;
- }
- nb_cli_enqueue_change(vty, "./frr-isisd:isis", NB_OP_CREATE,
- NULL);
- nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag",
- NB_OP_MODIFY, tag);
- nb_cli_enqueue_change(vty, "./frr-isisd:isis/vrf", NB_OP_MODIFY,
- vrf_name);
+ snprintf(inst_xpath, XPATH_MAXLEN,
+ "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']", tag,
+ vrf_name);
- nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv4-routing",
- NB_OP_MODIFY, "true");
+ /* if instance exists then inherit its type, create it otherwise */
+ inst_dnode = yang_dnode_get(vty->candidate_config->dnode, inst_xpath);
+ if (inst_dnode)
+ circ_type = yang_dnode_get_string(inst_dnode, "is-type");
+ else
+ nb_cli_enqueue_change(vty, inst_xpath, NB_OP_CREATE, NULL);
+
+ nb_cli_enqueue_change(vty, "./frr-isisd:isis", NB_OP_CREATE, NULL);
+ nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag", NB_OP_MODIFY,
+ tag);
+ nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv4-routing",
+ NB_OP_MODIFY, "true");
+ if (circ_type)
nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type",
NB_OP_MODIFY, circ_type);
- }
/* check if the interface is a loopback and if so set it as passive */
+ ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
if (ifp && if_is_loopback(ifp))
nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive",
NB_OP_MODIFY, "true");
return nb_cli_apply_changes(vty, NULL);
}
+ALIAS_HIDDEN(ip_router_isis, ip_router_isis_vrf_cmd,
+ "ip router isis WORD$tag vrf NAME$vrf_name",
+ "Interface Internet Protocol config commands\n"
+ "IP router interface commands\n"
+ "IS-IS routing protocol\n"
+ "Routing process tag\n" VRF_CMD_HELP_STR)
+
DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd,
- "ipv6 router isis WORD$tag [vrf NAME$vrf_name]",
+ "ipv6 router isis WORD$tag",
"Interface Internet Protocol config commands\n"
"IP router interface commands\n"
"IS-IS routing protocol\n"
- "Routing process tag\n" VRF_CMD_HELP_STR)
+ "Routing process tag\n")
{
- char temp_xpath[XPATH_MAXLEN];
- const char *circ_type;
+ char inst_xpath[XPATH_MAXLEN];
+ struct lyd_node *if_dnode, *inst_dnode;
+ const char *circ_type = NULL;
+ const char *vrf_name;
struct interface *ifp;
- struct isis_area *area;
- struct vrf *vrf;
- /* area will be created if it is not present. make sure the yang model
- * is synced with FRR and call the appropriate NB cb.
- */
-
- if (!im)
- return CMD_SUCCESS;
-
- ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
- if (!vrf_name) {
- if (ifp) {
- if (ifp->vrf_id == VRF_DEFAULT)
- vrf_name = VRF_DEFAULT_NAME;
- else {
- vrf = vrf_lookup_by_id(ifp->vrf_id);
- if (vrf && !vrf_name)
- vrf_name = vrf->name;
- }
- } else
- vrf_name = VRF_DEFAULT_NAME;
+ if_dnode = yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
+ if (!if_dnode) {
+ vty_out(vty, "%% Failed to get iface dnode in candidate DB\n");
+ return CMD_WARNING_CONFIG_FAILED;
}
- area = isis_area_lookup_by_vrf(tag, vrf_name);
- if (!area) {
- isis_global_instance_create(vrf_name);
- snprintf(temp_xpath, XPATH_MAXLEN,
- "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']",
- tag, vrf_name);
- nb_cli_enqueue_change(vty, temp_xpath, NB_OP_CREATE, tag);
- snprintf(
- temp_xpath, XPATH_MAXLEN,
- "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']/is-type",
- tag, vrf_name);
- nb_cli_enqueue_change(vty, temp_xpath, NB_OP_MODIFY,
- listcount(im->isis) == 0 ? "level-1-2"
- : NULL);
- nb_cli_enqueue_change(vty, "./frr-isisd:isis", NB_OP_CREATE,
- NULL);
- nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag",
- NB_OP_MODIFY, tag);
- nb_cli_enqueue_change(vty, "./frr-isisd:isis/vrf", NB_OP_MODIFY,
- vrf_name);
+ vrf_name = yang_dnode_get_string(if_dnode, "vrf");
- nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv6-routing",
- NB_OP_MODIFY, "true");
- nb_cli_enqueue_change(
- vty, "./frr-isisd:isis/circuit-type", NB_OP_MODIFY,
- listcount(im->isis) == 0 ? "level-1-2" : "level-1");
- } else {
- /* area exists, circuit type defaults to its area's is_type */
- switch (area->is_type) {
- case IS_LEVEL_1:
- circ_type = "level-1";
- break;
- case IS_LEVEL_2:
- circ_type = "level-2";
- break;
- case IS_LEVEL_1_AND_2:
- circ_type = "level-1-2";
- break;
- default:
- /* just to silence compiler warnings */
- return CMD_WARNING_CONFIG_FAILED;
- }
- nb_cli_enqueue_change(vty, "./frr-isisd:isis", NB_OP_CREATE,
- NULL);
- nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag",
- NB_OP_MODIFY, tag);
- nb_cli_enqueue_change(vty, "./frr-isisd:isis/vrf", NB_OP_MODIFY,
- vrf_name);
- nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv6-routing",
- NB_OP_MODIFY, "true");
+ snprintf(inst_xpath, XPATH_MAXLEN,
+ "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']", tag,
+ vrf_name);
+
+ /* if instance exists then inherit its type, create it otherwise */
+ inst_dnode = yang_dnode_get(vty->candidate_config->dnode, inst_xpath);
+ if (inst_dnode)
+ circ_type = yang_dnode_get_string(inst_dnode, "is-type");
+ else
+ nb_cli_enqueue_change(vty, inst_xpath, NB_OP_CREATE, NULL);
+
+ nb_cli_enqueue_change(vty, "./frr-isisd:isis", NB_OP_CREATE, NULL);
+ nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag", NB_OP_MODIFY,
+ tag);
+ nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv6-routing",
+ NB_OP_MODIFY, "true");
+ if (circ_type)
nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type",
NB_OP_MODIFY, circ_type);
- }
/* check if the interface is a loopback and if so set it as passive */
+ ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
if (ifp && if_is_loopback(ifp))
nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive",
NB_OP_MODIFY, "true");
return nb_cli_apply_changes(vty, NULL);
}
+ALIAS_HIDDEN(ip6_router_isis, ip6_router_isis_vrf_cmd,
+ "ipv6 router isis WORD$tag vrf NAME$vrf_name",
+ "Interface Internet Protocol config commands\n"
+ "IP router interface commands\n"
+ "IS-IS routing protocol\n"
+ "Routing process tag\n" VRF_CMD_HELP_STR)
+
DEFPY_YANG(no_ip_router_isis, no_ip_router_isis_cmd,
- "no <ip|ipv6>$ip router isis [WORD]$tag [vrf NAME$vrf_name]",
+ "no <ip|ipv6>$ip router isis [WORD]$tag",
NO_STR
"Interface Internet Protocol config commands\n"
"IP router interface commands\n"
"IP router interface commands\n"
"IS-IS routing protocol\n"
- "Routing process tag\n"
- VRF_CMD_HELP_STR)
+ "Routing process tag\n")
{
const struct lyd_node *dnode;
return nb_cli_apply_changes(vty, NULL);
}
+ALIAS_HIDDEN(no_ip_router_isis, no_ip_router_isis_vrf_cmd,
+ "no <ip|ipv6>$ip router isis WORD$tag vrf NAME$vrf_name",
+ NO_STR
+ "Interface Internet Protocol config commands\n"
+ "IP router interface commands\n"
+ "IP router interface commands\n"
+ "IS-IS routing protocol\n"
+ "Routing process tag\n"
+ VRF_CMD_HELP_STR)
+
void cli_show_ip_isis_ipv4(struct vty *vty, struct lyd_node *dnode,
bool show_defaults)
{
- const char *vrf;
-
- vrf = yang_dnode_get_string(dnode, "../vrf");
-
if (!yang_dnode_get_bool(dnode, NULL))
vty_out(vty, " no");
- vty_out(vty, " ip router isis %s",
+ vty_out(vty, " ip router isis %s\n",
yang_dnode_get_string(dnode, "../area-tag"));
- if (!strmatch(vrf, VRF_DEFAULT_NAME))
- vty_out(vty, " vrf %s", vrf);
- vty_out(vty, "\n");
}
void cli_show_ip_isis_ipv6(struct vty *vty, struct lyd_node *dnode,
bool show_defaults)
{
- const char *vrf;
-
- vrf = yang_dnode_get_string(dnode, "../vrf");
-
if (!yang_dnode_get_bool(dnode, NULL))
vty_out(vty, " no");
- vty_out(vty, " ipv6 router isis %s",
+ vty_out(vty, " ipv6 router isis %s\n",
yang_dnode_get_string(dnode, "../area-tag"));
- if (!strmatch(vrf, VRF_DEFAULT_NAME))
- vty_out(vty, " vrf %s", vrf);
- vty_out(vty, "\n");
}
/*
"Level-1-2 adjacencies are formed\n"
"Level-2 only adjacencies are formed\n")
{
- struct interface *ifp;
- struct isis_circuit *circuit;
- int is_type;
- const char *circ_type;
+ char inst_xpath[XPATH_MAXLEN];
+ struct lyd_node *if_dnode, *inst_dnode;
+ const char *vrf_name;
+ const char *tag;
+ const char *circ_type = NULL;
/*
* Default value depends on whether the circuit is part of an area,
* and the is-type of the area if there is one. So we need to do this
* here.
*/
- ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
- if (!ifp)
- goto def_val;
+ if_dnode = yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
+ if (!if_dnode) {
+ vty_out(vty, "%% Failed to get iface dnode in candidate DB\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
- circuit = circuit_scan_by_ifp(ifp);
- if (!circuit)
- goto def_val;
+ if (!yang_dnode_exists(if_dnode, "frr-isisd:isis/area-tag")) {
+ vty_out(vty, "%% ISIS is not configured on the interface\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
- if (circuit->state == C_STATE_UP)
- is_type = circuit->area->is_type;
- else
- goto def_val;
+ vrf_name = yang_dnode_get_string(if_dnode, "vrf");
+ tag = yang_dnode_get_string(if_dnode, "frr-isisd:isis/area-tag");
- switch (is_type) {
- case IS_LEVEL_1:
- circ_type = "level-1";
- break;
- case IS_LEVEL_2:
- circ_type = "level-2";
- break;
- case IS_LEVEL_1_AND_2:
- circ_type = "level-1-2";
- break;
- default:
- return CMD_ERR_NO_MATCH;
- }
- nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type",
- NB_OP_MODIFY, circ_type);
+ snprintf(inst_xpath, XPATH_MAXLEN,
+ "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']", tag,
+ vrf_name);
- return nb_cli_apply_changes(vty, NULL);
+ inst_dnode = yang_dnode_get(vty->candidate_config->dnode, inst_xpath);
+ if (inst_dnode)
+ circ_type = yang_dnode_get_string(inst_dnode, "is-type");
-def_val:
nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type",
- NB_OP_MODIFY, NULL);
+ NB_OP_MODIFY, circ_type);
return nb_cli_apply_changes(vty, NULL);
}
{
bool l1_enabled, l2_enabled;
bool l1_node_protection, l2_node_protection;
+ bool l1_link_fallback, l2_link_fallback;
/* Classic LFA */
l1_enabled = yang_dnode_get_bool(dnode, "./level-1/lfa/enable");
yang_dnode_get_bool(dnode, "./level-1/ti-lfa/node-protection");
l2_node_protection =
yang_dnode_get_bool(dnode, "./level-2/ti-lfa/node-protection");
+ l1_link_fallback =
+ yang_dnode_get_bool(dnode, "./level-1/ti-lfa/link-fallback");
+ l2_link_fallback =
+ yang_dnode_get_bool(dnode, "./level-2/ti-lfa/link-fallback");
+
if (l1_enabled || l2_enabled) {
if (l1_enabled == l2_enabled
- && l1_node_protection == l2_node_protection) {
+ && l1_node_protection == l2_node_protection
+ && l1_link_fallback == l2_link_fallback) {
vty_out(vty, " isis fast-reroute ti-lfa");
if (l1_node_protection)
vty_out(vty, " node-protection");
+ if (l1_link_fallback)
+ vty_out(vty, " link-fallback");
vty_out(vty, "\n");
} else {
if (l1_enabled) {
" isis fast-reroute ti-lfa level-1");
if (l1_node_protection)
vty_out(vty, " node-protection");
+ if (l1_link_fallback)
+ vty_out(vty, " link-fallback");
vty_out(vty, "\n");
}
if (l2_enabled) {
" isis fast-reroute ti-lfa level-2");
if (l2_node_protection)
vty_out(vty, " node-protection");
+ if (l2_link_fallback)
+ vty_out(vty, " link-fallback");
vty_out(vty, "\n");
}
}
* XPath: /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-{1,2}/ti-lfa/enable
*/
DEFPY(isis_ti_lfa, isis_ti_lfa_cmd,
- "[no] isis fast-reroute ti-lfa [level-1|level-2]$level [node-protection$node_protection]",
+ "[no] isis fast-reroute ti-lfa [level-1|level-2]$level [node-protection$node_protection [link-fallback$link_fallback]]",
NO_STR
"IS-IS routing protocol\n"
"Interface IP Fast-reroute configuration\n"
"Enable TI-LFA computation\n"
"Enable TI-LFA computation for Level 1 only\n"
"Enable TI-LFA computation for Level 2 only\n"
- "Protect against node failures\n")
+ "Protect against node failures\n"
+ "Enable link-protection fallback\n")
{
if (!level || strmatch(level, "level-1")) {
if (no) {
vty,
"./frr-isisd:isis/fast-reroute/level-1/ti-lfa/node-protection",
NB_OP_MODIFY, "false");
+ nb_cli_enqueue_change(
+ vty,
+ "./frr-isisd:isis/fast-reroute/level-1/ti-lfa/link-fallback",
+ NB_OP_MODIFY, "false");
} else {
nb_cli_enqueue_change(
vty,
"./frr-isisd:isis/fast-reroute/level-1/ti-lfa/node-protection",
NB_OP_MODIFY,
node_protection ? "true" : "false");
+ nb_cli_enqueue_change(
+ vty,
+ "./frr-isisd:isis/fast-reroute/level-1/ti-lfa/link-fallback",
+ NB_OP_MODIFY, link_fallback ? "true" : "false");
}
}
if (!level || strmatch(level, "level-2")) {
vty,
"./frr-isisd:isis/fast-reroute/level-2/ti-lfa/node-protection",
NB_OP_MODIFY, "false");
+ nb_cli_enqueue_change(
+ vty,
+ "./frr-isisd:isis/fast-reroute/level-2/ti-lfa/link-fallback",
+ NB_OP_MODIFY, "false");
} else {
nb_cli_enqueue_change(
vty,
"./frr-isisd:isis/fast-reroute/level-2/ti-lfa/node-protection",
NB_OP_MODIFY,
node_protection ? "true" : "false");
+ nb_cli_enqueue_change(
+ vty,
+ "./frr-isisd:isis/fast-reroute/level-2/ti-lfa/link-fallback",
+ NB_OP_MODIFY, link_fallback ? "true" : "false");
}
}
NO_STR "IS-IS routing protocol\n" MPLS_STR MPLS_LDP_SYNC_STR)
{
const struct lyd_node *dnode;
- struct interface *ifp;
dnode = yang_dnode_get(vty->candidate_config->dnode,
"%s/frr-isisd:isis", VTY_CURR_XPATH);
return CMD_SUCCESS;
}
- ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
- if (if_is_loopback(ifp)) {
- vty_out(vty, "ldp-sync does not run on loopback interface\n");
- return CMD_SUCCESS;
- }
-
- if (ifp->vrf_id != VRF_DEFAULT) {
- vty_out(vty, "ldp-sync only runs on DEFAULT VRF\n");
- return CMD_SUCCESS;
- }
-
nb_cli_enqueue_change(vty, "./frr-isisd:isis/mpls/ldp-sync",
NB_OP_MODIFY, no ? "false" : "true");
"Time in seconds\n")
{
const struct lyd_node *dnode;
- struct interface *ifp;
dnode = yang_dnode_get(vty->candidate_config->dnode,
"%s/frr-isisd:isis", VTY_CURR_XPATH);
return CMD_SUCCESS;
}
- ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
- if (if_is_loopback(ifp)) {
- vty_out(vty, "ldp-sync does not run on loopback interface\n");
- return CMD_SUCCESS;
- }
-
- if (ifp->vrf_id != VRF_DEFAULT) {
- vty_out(vty, "ldp-sync only runs on DEFAULT VRF\n");
- return CMD_SUCCESS;
- }
-
nb_cli_enqueue_change(vty, "./frr-isisd:isis/mpls/holddown",
NB_OP_MODIFY, holddown_str);
NO_MPLS_LDP_SYNC_HOLDDOWN_STR "Time in seconds\n")
{
const struct lyd_node *dnode;
- struct interface *ifp;
dnode = yang_dnode_get(vty->candidate_config->dnode,
"%s/frr-isisd:isis", VTY_CURR_XPATH);
return CMD_SUCCESS;
}
- ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
- if (if_is_loopback(ifp)) {
- vty_out(vty, "ldp-sync does not run on loopback interface\n");
- return CMD_SUCCESS;
- }
-
- if (ifp->vrf_id != VRF_DEFAULT) {
- vty_out(vty, "ldp-sync only runs on DEFAULT VRF\n");
- return CMD_SUCCESS;
- }
-
nb_cli_enqueue_change(vty, "./frr-isisd:isis/mpls/holddown",
NB_OP_DESTROY, NULL);
install_element(CONFIG_NODE, &no_router_isis_cmd);
install_element(INTERFACE_NODE, &ip_router_isis_cmd);
+ install_element(INTERFACE_NODE, &ip_router_isis_vrf_cmd);
install_element(INTERFACE_NODE, &ip6_router_isis_cmd);
+ install_element(INTERFACE_NODE, &ip6_router_isis_vrf_cmd);
install_element(INTERFACE_NODE, &no_ip_router_isis_cmd);
+ install_element(INTERFACE_NODE, &no_ip_router_isis_vrf_cmd);
install_element(INTERFACE_NODE, &isis_bfd_cmd);
install_element(INTERFACE_NODE, &isis_bfd_profile_cmd);
#define EVENT2STR(E) csm_eventstr[E]
-struct isis_circuit *
-isis_csm_state_change(int event, struct isis_circuit *circuit, void *arg)
+struct isis_circuit *isis_csm_state_change(enum isis_circuit_event event,
+ struct isis_circuit *circuit,
+ void *arg)
{
- int old_state;
- struct isis *isis = NULL;
+ enum isis_circuit_state old_state;
struct isis_area *area = NULL;
+ struct interface *ifp;
- old_state = circuit ? circuit->state : C_STATE_NA;
+ assert(circuit);
+
+ old_state = circuit->state;
if (IS_DEBUG_EVENTS)
- zlog_debug("CSM_EVENT: %s", EVENT2STR(event));
+ zlog_debug("CSM_EVENT for %s: %s", circuit->interface->name,
+ EVENT2STR(event));
switch (old_state) {
case C_STATE_NA:
- if (circuit)
- zlog_warn("Non-null circuit while state C_STATE_NA");
- assert(circuit == NULL);
switch (event) {
case ISIS_ENABLE:
area = arg;
- circuit = isis_circuit_new(area->isis);
isis_circuit_configure(circuit, area);
circuit->state = C_STATE_CONF;
break;
case IF_UP_FROM_Z:
- isis = isis_lookup_by_vrfid(((struct interface *)arg)->vrf_id);
- if (isis == NULL) {
- zlog_warn(
- " %s : ISIS routing instance not found",
- __func__);
- break;
- }
- circuit = isis_circuit_new(isis);
- isis_circuit_if_add(circuit, (struct interface *)arg);
- listnode_add(isis->init_circ_list, circuit);
+ ifp = arg;
+
+ isis_circuit_if_add(circuit, ifp);
circuit->state = C_STATE_INIT;
break;
case ISIS_DISABLE:
- zlog_warn("circuit already disabled");
+ if (IS_DEBUG_EVENTS)
+ zlog_debug("circuit %s already disabled",
+ circuit->interface->name);
break;
case IF_DOWN_FROM_Z:
- zlog_warn("circuit already disconnected");
+ if (IS_DEBUG_EVENTS)
+ zlog_debug("circuit %s already disconnected",
+ circuit->interface->name);
break;
}
break;
case C_STATE_INIT:
- assert(circuit);
switch (event) {
case ISIS_ENABLE:
- isis_circuit_configure(circuit,
- (struct isis_area *)arg);
+ area = arg;
+
+ isis_circuit_configure(circuit, area);
if (isis_circuit_up(circuit) != ISIS_OK) {
- isis_circuit_deconfigure(
- circuit, (struct isis_area *)arg);
+ isis_circuit_deconfigure(circuit, area);
break;
}
circuit->state = C_STATE_UP;
isis_event_circuit_state_change(circuit, circuit->area,
1);
- listnode_delete(circuit->isis->init_circ_list,
- circuit);
break;
case IF_UP_FROM_Z:
- assert(circuit);
- zlog_warn("circuit already connected");
+ if (IS_DEBUG_EVENTS)
+ zlog_debug("circuit %s already connected",
+ circuit->interface->name);
break;
case ISIS_DISABLE:
- zlog_warn("circuit already disabled");
+ if (IS_DEBUG_EVENTS)
+ zlog_debug("circuit %s already disabled",
+ circuit->interface->name);
break;
case IF_DOWN_FROM_Z:
- isis_circuit_if_del(circuit, (struct interface *)arg);
- listnode_delete(circuit->isis->init_circ_list,
- circuit);
- isis_circuit_del(circuit);
- circuit = NULL;
+ ifp = arg;
+
+ isis_circuit_if_del(circuit, ifp);
+ circuit->state = C_STATE_NA;
break;
}
break;
case C_STATE_CONF:
- assert(circuit);
switch (event) {
case ISIS_ENABLE:
- zlog_warn("circuit already enabled");
+ if (IS_DEBUG_EVENTS)
+ zlog_debug("circuit %s is already enabled",
+ circuit->interface->name);
break;
case IF_UP_FROM_Z:
- isis_circuit_if_add(circuit, (struct interface *)arg);
+ ifp = arg;
+
+ isis_circuit_if_add(circuit, ifp);
if (isis_circuit_up(circuit) != ISIS_OK) {
- isis_circuit_if_del(circuit, (struct interface *)arg);
+ isis_circuit_if_del(circuit, ifp);
flog_err(
EC_ISIS_CONFIG,
"Could not bring up %s because of invalid config.",
1);
break;
case ISIS_DISABLE:
- isis_circuit_deconfigure(circuit,
- (struct isis_area *)arg);
- isis_circuit_del(circuit);
- circuit = NULL;
+ area = arg;
+
+ isis_circuit_deconfigure(circuit, area);
+ circuit->state = C_STATE_NA;
break;
case IF_DOWN_FROM_Z:
- zlog_warn("circuit already disconnected");
+ if (IS_DEBUG_EVENTS)
+ zlog_debug("circuit %s already disconnected",
+ circuit->interface->name);
break;
}
break;
case C_STATE_UP:
- assert(circuit);
switch (event) {
case ISIS_ENABLE:
- zlog_warn("circuit already configured");
+ if (IS_DEBUG_EVENTS)
+ zlog_debug("circuit %s already enabled",
+ circuit->interface->name);
break;
case IF_UP_FROM_Z:
- zlog_warn("circuit already connected");
+ if (IS_DEBUG_EVENTS)
+ zlog_debug("circuit %s already connected",
+ circuit->interface->name);
break;
case ISIS_DISABLE:
- isis = circuit->isis;
+ area = arg;
+
isis_circuit_down(circuit);
- isis_circuit_deconfigure(circuit,
- (struct isis_area *)arg);
+ isis_circuit_deconfigure(circuit, area);
circuit->state = C_STATE_INIT;
- isis_event_circuit_state_change(
- circuit, (struct isis_area *)arg, 0);
- listnode_add(isis->init_circ_list, circuit);
+ isis_event_circuit_state_change(circuit, area, 0);
break;
case IF_DOWN_FROM_Z:
+ ifp = arg;
+
isis_circuit_down(circuit);
- isis_circuit_if_del(circuit, (struct interface *)arg);
+ isis_circuit_if_del(circuit, ifp);
circuit->state = C_STATE_CONF;
isis_event_circuit_state_change(circuit, circuit->area,
0);
break;
}
break;
-
- default:
- zlog_warn("Invalid circuit state %d", old_state);
}
if (IS_DEBUG_EVENTS)
zlog_debug("CSM_STATE_CHANGE: %s -> %s ", STATE2STR(old_state),
- circuit ? STATE2STR(circuit->state)
- : STATE2STR(C_STATE_NA));
+ STATE2STR(circuit->state));
return circuit;
}
/*
* Circuit states
*/
-#define C_STATE_NA 0
-#define C_STATE_INIT 1 /* Connected to interface */
-#define C_STATE_CONF 2 /* Configured for ISIS */
-#define C_STATE_UP 3 /* CONN | CONF */
+enum isis_circuit_state {
+ C_STATE_NA,
+ C_STATE_INIT, /* Connected to interface */
+ C_STATE_CONF, /* Configured for ISIS */
+ C_STATE_UP, /* CONN | CONF */
+};
/*
* Circuit events
*/
-#define ISIS_ENABLE 1
-#define IF_UP_FROM_Z 2
-#define ISIS_DISABLE 3
-#define IF_DOWN_FROM_Z 4
+enum isis_circuit_event {
+ ISIS_ENABLE = 1,
+ IF_UP_FROM_Z,
+ ISIS_DISABLE,
+ IF_DOWN_FROM_Z,
+};
-struct isis_circuit *
-isis_csm_state_change(int event, struct isis_circuit *circuit, void *arg);
+struct isis_circuit *isis_csm_state_change(enum isis_circuit_event event,
+ struct isis_circuit *circuit,
+ void *arg);
#endif /* _ZEBRA_ISIS_CSM_H */
struct interface *ifp;
struct isis_circuit *circuit = NULL;
struct isis_area *area;
- struct listnode *node;
- struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
-
- /* if isis is not enabled or LDP-SYNC is not configured ignore */
- if (!isis ||
- !CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
- return 0;
/* lookup circuit */
ifp = if_lookup_by_index(state.ifindex, VRF_DEFAULT);
if (ifp == NULL)
return 0;
- for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
- circuit = circuit_lookup_by_ifp(ifp, area->circuit_list);
- if (circuit != NULL)
- break;
- }
+ circuit = ifp->info;
+ if (circuit == NULL)
+ return 0;
/* if isis is not enabled or LDP-SYNC is not configured ignore */
- if (circuit == NULL ||
- !CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
+ area = circuit->area;
+ if (area == NULL
+ || !CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
return 0;
/* received ldp-sync interface state from LDP */
int isis_ldp_sync_announce_update(struct ldp_igp_sync_announce announce)
{
struct isis_area *area;
- struct listnode *node;
- struct vrf *vrf;
- struct interface *ifp;
+ struct listnode *anode, *cnode;
struct isis_circuit *circuit;
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
- /* if isis is not enabled or LDP-SYNC is not configured ignore */
- if (!isis ||
- !CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
+ /* if isis is not enabled ignore */
+ if (!isis)
return 0;
if (announce.proto != ZEBRA_ROUTE_LDP)
* set cost to LSInfinity
* send request to LDP for LDP-SYNC state for each interface
*/
- vrf = vrf_lookup_by_id(VRF_DEFAULT);
- FOR_ALL_INTERFACES (vrf, ifp) {
- for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
- circuit = circuit_lookup_by_ifp(ifp,
- area->circuit_list);
- if (circuit == NULL)
- continue;
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) {
+ if (!CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
+ continue;
+
+ for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit))
isis_ldp_sync_if_start(circuit, true);
- }
}
return 0;
/*
* LDP-SYNC general interface routines
*/
-void isis_ldp_sync_if_init(struct isis_circuit *circuit, struct isis *isis)
-{
- struct ldp_sync_info *ldp_sync_info;
- struct interface *ifp = circuit->interface;
-
- /* called when ISIS is configured on an interface
- * if LDP-IGP Sync is configured globally set state
- * and if ptop interface LDP LDP-SYNC is enabled
- */
- ils_debug("ldp_sync: init if %s ", ifp->name);
- if (circuit->ldp_sync_info == NULL)
- circuit->ldp_sync_info = ldp_sync_info_create();
- ldp_sync_info = circuit->ldp_sync_info;
-
- /* specifed on interface overrides global config. */
- if (!CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN))
- ldp_sync_info->holddown = isis->ldp_sync_cmd.holddown;
-
- if (!CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG))
- ldp_sync_info->enabled = LDP_IGP_SYNC_ENABLED;
-
- if ((circuit->circ_type == CIRCUIT_T_P2P || if_is_pointopoint(ifp)) &&
- ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED)
- ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
-}
-
void isis_ldp_sync_if_start(struct isis_circuit *circuit,
bool send_state_req)
{
}
}
-void isis_ldp_sync_if_remove(struct isis_circuit *circuit, bool remove)
-{
- struct ldp_sync_info *ldp_sync_info;
-
- if (circuit->ldp_sync_info == NULL)
- return;
-
- ldp_sync_info = circuit->ldp_sync_info;
-
- /* Stop LDP-SYNC on this interface:
- * if holddown timer is running stop it
- * delete ldp instance on interface
- * restore metric
- */
- ils_debug("ldp_sync: remove if %s", circuit->interface
- ? circuit->interface->name : "");
-
- THREAD_OFF(ldp_sync_info->t_holddown);
- ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED;
- isis_ldp_sync_set_if_metric(circuit, true);
- if (remove) {
- /* ISIS instance being removed free ldp-sync info */
- ldp_sync_info_free((struct ldp_sync_info **)&(ldp_sync_info));
- circuit->ldp_sync_info = NULL;
- }
-}
-
static int isis_ldp_sync_adj_state_change(struct isis_adjacency *adj)
{
struct isis_circuit *circuit = adj->circuit;
- struct ldp_sync_info *ldp_sync_info;
- struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+ struct ldp_sync_info *ldp_sync_info = circuit->ldp_sync_info;
+ struct isis_area *area = circuit->area;
- if (!isis ||
- !CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE) ||
- circuit->interface->vrf_id != VRF_DEFAULT ||
- if_is_loopback(circuit->interface))
+ if (!CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)
+ || circuit->interface->vrf_id != VRF_DEFAULT
+ || if_is_loopback(circuit->interface))
return 0;
- if (circuit->ldp_sync_info == NULL)
- isis_ldp_sync_if_init(circuit, isis);
- ldp_sync_info = circuit->ldp_sync_info;
-
if (ldp_sync_info->enabled != LDP_IGP_SYNC_ENABLED)
return 0;
int metric)
{
struct ldp_sync_info *ldp_sync_info = circuit->ldp_sync_info;
- struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+ struct isis_area *area = circuit->area;
/* configured interface metric has been changed:
* if LDP-IGP Sync is running and metric has been set to LSInfinity
* change saved value so when ldp-sync completes proper metric is
* restored
*/
- if (isis &&
- CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE) &&
- ldp_sync_info != NULL) {
+ if (area && CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)
+ && ldp_sync_info != NULL) {
if (CHECK_FLAG(ldp_sync_info->flags,
LDP_SYNC_FLAG_SET_METRIC)) {
void isis_ldp_sync_handle_client_close(struct zapi_client_close_info *info)
{
struct isis_area *area;
- struct listnode *node;
+ struct listnode *anode, *cnode;
struct isis_circuit *circuit;
- struct interface *ifp;
- struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
- /* if isis is not enabled or LDP-SYNC is not configured ignore */
- if (!isis
- || !CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
+ /* if isis is not enabled ignore */
+ if (!isis)
return;
/* Check if the LDP main client session closed */
*/
zlog_err("ldp_sync: LDP down");
- FOR_ALL_INTERFACES (vrf, ifp) {
- for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
- circuit =
- circuit_lookup_by_ifp(ifp, area->circuit_list);
- if (circuit == NULL)
- continue;
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) {
+ if (!CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
+ continue;
+
+ for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit))
isis_ldp_sync_ldp_fail(circuit);
- }
}
}
* LDP-SYNC routes used by set commands.
*/
-void isis_if_set_ldp_sync_enable(struct isis_circuit *circuit)
+void isis_area_ldp_sync_enable(struct isis_area *area)
{
- struct ldp_sync_info *ldp_sync_info;
- struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+ struct isis_circuit *circuit;
+ struct listnode *node;
+
+ if (!CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) {
+ SET_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE);
+
+ for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit))
+ isis_if_ldp_sync_enable(circuit);
+ }
+}
+
+void isis_area_ldp_sync_disable(struct isis_area *area)
+{
+ struct isis_circuit *circuit;
+ struct listnode *node;
+
+ if (CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) {
+ for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit))
+ isis_if_ldp_sync_disable(circuit);
+
+ UNSET_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE);
+
+ UNSET_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN);
+ area->ldp_sync_cmd.holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT;
+ }
+}
+
+void isis_area_ldp_sync_set_holddown(struct isis_area *area, uint16_t holddown)
+{
+ struct isis_circuit *circuit;
+ struct listnode *node;
+
+ if (holddown == LDP_IGP_SYNC_HOLDDOWN_DEFAULT)
+ UNSET_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN);
+ else
+ SET_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN);
+
+ area->ldp_sync_cmd.holddown = holddown;
+
+ for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit))
+ isis_if_set_ldp_sync_holddown(circuit);
+}
+
+void isis_if_ldp_sync_enable(struct isis_circuit *circuit)
+{
+ struct ldp_sync_info *ldp_sync_info = circuit->ldp_sync_info;
+ struct isis_area *area = circuit->area;
/* called when setting LDP-SYNC at the global level:
* specifed on interface overrides global config
* if ptop link send msg to LDP indicating ldp-sync enabled
*/
- if (!isis || if_is_loopback(circuit->interface))
+ if (if_is_loopback(circuit->interface))
return;
- if (CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) {
- if (circuit->ldp_sync_info == NULL)
- isis_ldp_sync_if_init(circuit, isis);
- ldp_sync_info = circuit->ldp_sync_info;
+ ils_debug("ldp_sync: enable if %s", circuit->interface->name);
- /* config on interface, overrides global config. */
- if (CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG))
- if (ldp_sync_info->enabled != LDP_IGP_SYNC_ENABLED)
- return;
+ if (!CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
+ return;
- ldp_sync_info->enabled = LDP_IGP_SYNC_ENABLED;
- ils_debug("ldp_sync: enable if %s", circuit->interface->name);
+ /* config on interface, overrides global config. */
+ if (CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG))
+ if (ldp_sync_info->enabled != LDP_IGP_SYNC_ENABLED)
+ return;
- /* send message to LDP if ptop link */
- if (circuit->circ_type == CIRCUIT_T_P2P ||
- if_is_pointopoint(circuit->interface)) {
- ldp_sync_info->state =
- LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
- isis_ldp_sync_state_req_msg(circuit);
- } else {
- ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED;
- zlog_debug("ldp_sync: Sync only runs on P2P links %s",
- circuit->interface->name);
- }
- } else
- /* delete LDP sync even if configured on an interface */
- isis_ldp_sync_if_remove(circuit, false);
+ if (!CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN))
+ ldp_sync_info->holddown = area->ldp_sync_cmd.holddown;
+
+ if (circuit->circ_type == CIRCUIT_T_P2P
+ || if_is_pointopoint(circuit->interface)) {
+ ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
+ isis_ldp_sync_state_req_msg(circuit);
+ } else {
+ ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED;
+ ils_debug("ldp_sync: Sync only runs on P2P links %s",
+ circuit->interface->name);
+ }
+}
+
+void isis_if_ldp_sync_disable(struct isis_circuit *circuit)
+{
+ struct ldp_sync_info *ldp_sync_info = circuit->ldp_sync_info;
+ struct isis_area *area = circuit->area;
+
+ /* Stop LDP-SYNC on this interface:
+ * if holddown timer is running stop it
+ * delete ldp instance on interface
+ * restore metric
+ */
+ if (if_is_loopback(circuit->interface))
+ return;
+
+ ils_debug("ldp_sync: remove if %s", circuit->interface->name);
+
+ if (!CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
+ return;
+
+ THREAD_OFF(ldp_sync_info->t_holddown);
+ ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED;
+ isis_ldp_sync_set_if_metric(circuit, true);
}
void isis_if_set_ldp_sync_holddown(struct isis_circuit *circuit)
{
- struct ldp_sync_info *ldp_sync_info;
- struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+ struct ldp_sync_info *ldp_sync_info = circuit->ldp_sync_info;
+ struct isis_area *area = circuit->area;
/* called when setting LDP-SYNC at the global level:
* specifed on interface overrides global config.
*/
- if (!isis || if_is_loopback(circuit->interface))
+ if (if_is_loopback(circuit->interface))
return;
- if (circuit->ldp_sync_info == NULL)
- isis_ldp_sync_if_init(circuit, isis);
- ldp_sync_info = circuit->ldp_sync_info;
-
/* config on interface, overrides global config. */
if (CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN))
return;
- if (CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN))
- ldp_sync_info->holddown = isis->ldp_sync_cmd.holddown;
+ if (CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN))
+ ldp_sync_info->holddown = area->ldp_sync_cmd.holddown;
else
ldp_sync_info->holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT;
}
-void isis_ldp_sync_gbl_exit(bool remove)
-{
- struct isis_area *area;
- struct listnode *node;
- struct isis_circuit *circuit;
- struct interface *ifp;
- struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
- struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
-
- /* if you delete LDP-SYNC at a gobal level is clears all LDP-SYNC
- * configuration, even interface configuration
- */
- if (isis &&
- CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) {
- /* register with opaque client to recv LDP-IGP Sync msgs */
- zclient_unregister_opaque(zclient,
- LDP_IGP_SYNC_IF_STATE_UPDATE);
- zclient_unregister_opaque(zclient,
- LDP_IGP_SYNC_ANNOUNCE_UPDATE);
-
- /* disable LDP-SYNC globally */
- UNSET_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE);
- UNSET_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN);
- isis->ldp_sync_cmd.holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT;
-
- /* remove LDP-SYNC on all ISIS interfaces */
- FOR_ALL_INTERFACES (vrf, ifp) {
- for (ALL_LIST_ELEMENTS_RO(isis->area_list, node,
- area)) {
- circuit = circuit_lookup_by_ifp(ifp,
- area->circuit_list);
- if (circuit == NULL)
- continue;
- isis_ldp_sync_if_remove(circuit, remove);
- }
- }
- }
-}
-
/*
* LDP-SYNC routines used by show commands.
*/
return CMD_SUCCESS;
}
- if (!CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) {
- vty_out(vty, "LDP-sync is disabled\n");
- return CMD_SUCCESS;
- }
-
if (argv_find(argv, argc, "INTERFACE", &idx_intf))
ifname = argv[idx_intf]->arg;
zlog_debug(__VA_ARGS__); \
} while (0)
-extern void isis_if_set_ldp_sync_enable(struct isis_circuit *circuit);
+extern void isis_area_ldp_sync_enable(struct isis_area *area);
+extern void isis_area_ldp_sync_disable(struct isis_area *area);
+extern void isis_area_ldp_sync_set_holddown(struct isis_area *area,
+ uint16_t holddown);
+extern void isis_if_ldp_sync_enable(struct isis_circuit *circuit);
+extern void isis_if_ldp_sync_disable(struct isis_circuit *circuit);
extern void isis_if_set_ldp_sync_holddown(struct isis_circuit *circuit);
-extern void isis_ldp_sync_if_init(struct isis_circuit *circuit,
- struct isis *isis);
extern void isis_ldp_sync_if_start(struct isis_circuit *circuit,
bool send_state_req);
-extern void isis_ldp_sync_if_remove(struct isis_circuit *circuit, bool remove);
extern void isis_ldp_sync_if_complete(struct isis_circuit *circuit);
extern void isis_ldp_sync_holddown_timer_add(struct isis_circuit *circuit);
extern void
extern bool isis_ldp_sync_if_metric_config(struct isis_circuit *circuit,
int level, int metric);
extern void isis_ldp_sync_init(void);
-extern void isis_ldp_sync_gbl_exit(bool remove);
#endif /* _ZEBRA_ISIS_LDP_SYNC_H */
/*
* Compute the reverse SPF in the behalf of the node
- * adjacent to the failure.
+ * adjacent to the failure, if we haven't done that
+ * before
*/
- adj_node->lfa.spftree_reverse =
- isis_spf_reverse_run(adj_node->lfa.spftree);
+ if (!adj_node->lfa.spftree_reverse)
+ adj_node->lfa.spftree_reverse =
+ isis_spf_reverse_run(
+ adj_node->lfa.spftree);
lfa_calc_reach_nodes(adj_node->lfa.spftree_reverse,
spftree_reverse, adj_nodes, false,
spftree_pc_node = isis_tilfa_compute(area, spftree,
spftree_reverse, resource);
isis_spftree_del(spftree_pc_node);
+
+ /* don't do link protection unless link-fallback is configured
+ */
+ if (!circuit->tilfa_link_fallback[spftree->level - 1])
+ return;
}
/* Compute link protecting repair paths. */
.modify = lib_interface_isis_area_tag_modify,
},
},
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/vrf",
- .cbs = {
- .modify = lib_interface_isis_vrf_modify,
- },
- },
-
{
.xpath = "/frr-interface:lib/interface/frr-isisd:isis/circuit-type",
.cbs = {
.modify = lib_interface_isis_fast_reroute_level_1_ti_lfa_node_protection_modify,
}
},
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/ti-lfa/link-fallback",
+ .cbs = {
+ .modify = lib_interface_isis_fast_reroute_level_1_ti_lfa_link_fallback_modify,
+ }
+ },
{
.xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/lfa/enable",
.cbs = {
.modify = lib_interface_isis_fast_reroute_level_2_ti_lfa_node_protection_modify,
}
},
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/ti-lfa/link-fallback",
+ .cbs = {
+ .modify = lib_interface_isis_fast_reroute_level_2_ti_lfa_link_fallback_modify,
+ }
+ },
{
.xpath = "/frr-interface:lib/interface/state/frr-isisd:isis",
.cbs = {
int lib_interface_isis_create(struct nb_cb_create_args *args);
int lib_interface_isis_destroy(struct nb_cb_destroy_args *args);
int lib_interface_isis_area_tag_modify(struct nb_cb_modify_args *args);
-int lib_interface_isis_vrf_modify(struct nb_cb_modify_args *args);
int lib_interface_isis_ipv4_routing_modify(struct nb_cb_modify_args *args);
int lib_interface_isis_ipv6_routing_modify(struct nb_cb_modify_args *args);
int lib_interface_isis_circuit_type_modify(struct nb_cb_modify_args *args);
struct nb_cb_modify_args *args);
int lib_interface_isis_fast_reroute_level_1_ti_lfa_node_protection_modify(
struct nb_cb_modify_args *args);
+int lib_interface_isis_fast_reroute_level_1_ti_lfa_link_fallback_modify(
+ struct nb_cb_modify_args *args);
int lib_interface_isis_fast_reroute_level_2_lfa_enable_modify(
struct nb_cb_modify_args *args);
int lib_interface_isis_fast_reroute_level_2_lfa_exclude_interface_create(
struct nb_cb_modify_args *args);
int lib_interface_isis_fast_reroute_level_2_ti_lfa_node_protection_modify(
struct nb_cb_modify_args *args);
+int lib_interface_isis_fast_reroute_level_2_ti_lfa_link_fallback_modify(
+ struct nb_cb_modify_args *args);
struct yang_data *
lib_interface_state_isis_get_elem(struct nb_cb_get_elem_args *args);
const void *lib_interface_state_isis_adjacencies_adjacency_get_next(
#include "spf_backoff.h"
#include "lib_errors.h"
#include "vrf.h"
-#include "zclient.h"
#include "ldp_sync.h"
#include "isisd/isisd.h"
DEFINE_MTYPE_STATIC(ISISD, ISIS_MPLS_TE, "ISIS MPLS_TE parameters");
DEFINE_MTYPE_STATIC(ISISD, ISIS_PLIST_NAME, "ISIS prefix-list name");
-extern struct zclient *zclient;
-
/*
* XPath: /frr-isisd:isis/instance
*/
int isis_instance_destroy(struct nb_cb_destroy_args *args)
{
struct isis_area *area;
- vrf_id_t vrf_id;
if (args->event != NB_EV_APPLY)
return NB_OK;
area = nb_running_unset_entry(args->dnode);
- vrf_id = area->isis->vrf_id;
-
- /* remove ldp-sync config */
- if (vrf_id == VRF_DEFAULT)
- isis_ldp_sync_gbl_exit(true);
isis_area_destroy(area);
return NB_OK;
int isis_instance_mpls_ldp_sync_create(struct nb_cb_create_args *args)
{
struct isis_area *area;
- struct listnode *node;
- struct isis_circuit *circuit;
- struct interface *ifp;
- struct vrf *vrf;
- struct isis *isis;
switch (args->event) {
case NB_EV_VALIDATE:
break;
case NB_EV_APPLY:
area = nb_running_get_entry(args->dnode, NULL, true);
- isis = area->isis;
- vrf = vrf_lookup_by_id(isis->vrf_id);
-
- /* register with opaque client to recv LDP-IGP Sync msgs */
- zclient_register_opaque(zclient, LDP_IGP_SYNC_IF_STATE_UPDATE);
- zclient_register_opaque(zclient, LDP_IGP_SYNC_ANNOUNCE_UPDATE);
-
- if (!CHECK_FLAG(isis->ldp_sync_cmd.flags,
- LDP_SYNC_FLAG_ENABLE)) {
- SET_FLAG(isis->ldp_sync_cmd.flags,
- LDP_SYNC_FLAG_ENABLE);
-
- /* turn on LDP-IGP Sync on all ptop ISIS interfaces */
- FOR_ALL_INTERFACES (vrf, ifp) {
- for (ALL_LIST_ELEMENTS_RO(isis->area_list, node,
- area)) {
- circuit = circuit_lookup_by_ifp(
- ifp, area->circuit_list);
- if (circuit == NULL)
- continue;
- isis_if_set_ldp_sync_enable(circuit);
- }
- }
- }
+ isis_area_ldp_sync_enable(area);
break;
}
return NB_OK;
int isis_instance_mpls_ldp_sync_destroy(struct nb_cb_destroy_args *args)
{
+ struct isis_area *area;
+
if (args->event != NB_EV_APPLY)
return NB_OK;
- /* remove ldp-sync config */
- isis_ldp_sync_gbl_exit(false);
+ area = nb_running_get_entry(args->dnode, NULL, true);
+ isis_area_ldp_sync_disable(area);
return NB_OK;
}
int isis_instance_mpls_ldp_sync_holddown_modify(struct nb_cb_modify_args *args)
{
struct isis_area *area;
- struct listnode *node;
- struct isis_circuit *circuit;
- struct interface *ifp;
- struct vrf *vrf;
- uint16_t holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT;
- struct isis *isis;
+ uint16_t holddown;
switch (args->event) {
case NB_EV_VALIDATE:
break;
case NB_EV_APPLY:
area = nb_running_get_entry(args->dnode, NULL, true);
- isis = area->isis;
- vrf = vrf_lookup_by_id(isis->vrf_id);
holddown = yang_dnode_get_uint16(args->dnode, NULL);
-
- if (holddown == LDP_IGP_SYNC_HOLDDOWN_DEFAULT)
- UNSET_FLAG(isis->ldp_sync_cmd.flags,
- LDP_SYNC_FLAG_HOLDDOWN);
- else
- SET_FLAG(isis->ldp_sync_cmd.flags,
- LDP_SYNC_FLAG_HOLDDOWN);
- isis->ldp_sync_cmd.holddown = holddown;
-
- /* set holddown time on all ISIS interfaces */
- FOR_ALL_INTERFACES (vrf, ifp) {
- for (ALL_LIST_ELEMENTS_RO(isis->area_list, node,
- area)) {
- circuit = circuit_lookup_by_ifp(ifp,
- area->circuit_list);
- if (circuit == NULL)
- continue;
- isis_if_set_ldp_sync_holddown(circuit);
- }
- }
+ isis_area_ldp_sync_set_holddown(area, holddown);
break;
}
return NB_OK;
struct isis_area *area = NULL;
struct interface *ifp;
struct isis_circuit *circuit = NULL;
- struct vrf *vrf;
const char *area_tag = yang_dnode_get_string(args->dnode, "./area-tag");
- const char *vrf_name = yang_dnode_get_string(args->dnode, "./vrf");
uint32_t min_mtu, actual_mtu;
switch (args->event) {
/* zebra might not know yet about the MTU - nothing we can do */
if (!ifp || ifp->mtu == 0)
break;
- vrf = vrf_lookup_by_id(ifp->vrf_id);
- if (ifp->vrf_id != VRF_DEFAULT && vrf
- && strcmp(vrf->name, vrf_name) != 0) {
- snprintf(args->errmsg, args->errmsg_len,
- "interface %s not in vrf %s\n", ifp->name,
- vrf_name);
- return NB_ERR_VALIDATION;
- }
actual_mtu =
if_is_broadcast(ifp) ? ifp->mtu - LLC_LEN : ifp->mtu;
}
break;
case NB_EV_APPLY:
- area = isis_area_lookup_by_vrf(area_tag, vrf_name);
- /* The area should have already be created. We are
- * setting the priority of the global isis area creation
- * slightly lower, so it should be executed first, but I
- * cannot rely on that so here I have to check.
- */
- if (!area) {
- flog_err(
- EC_LIB_NB_CB_CONFIG_APPLY,
- "%s: attempt to create circuit for area %s before the area has been created",
- __func__, area_tag);
- abort();
- }
ifp = nb_running_get_entry(args->dnode, NULL, true);
- circuit = isis_circuit_create(area, ifp);
- assert(circuit
- && (circuit->state == C_STATE_CONF
- || circuit->state == C_STATE_UP));
+ circuit = isis_circuit_new(ifp, area_tag);
nb_running_set_entry(args->dnode, circuit);
break;
}
return NB_OK;
circuit = nb_running_unset_entry(args->dnode);
- if (!circuit)
- return NB_ERR_INCONSISTENCY;
- /* remove ldp-sync config */
- isis_ldp_sync_if_remove(circuit, true);
+ isis_circuit_del(circuit);
- /* disable both AFs for this circuit. this will also update the
- * CSM state by sending an ISIS_DISABLED signal. If there is no
- * area associated to the circuit there is nothing to do
- */
- if (circuit->area)
- isis_circuit_af_set(circuit, false, false);
return NB_OK;
}
return NB_OK;
}
-/*
- * XPath: /frr-interface:lib/interface/frr-isisd:isis/vrf
- */
-int lib_interface_isis_vrf_modify(struct nb_cb_modify_args *args)
-{
- struct interface *ifp;
- struct vrf *vrf;
- const char *ifname, *vrfname, *vrf_name;
- struct isis_circuit *circuit;
-
- if (args->event == NB_EV_VALIDATE) {
- /* libyang doesn't like relative paths across module boundaries
- */
- ifname = yang_dnode_get_string(args->dnode->parent->parent,
- "./name");
- vrfname = yang_dnode_get_string(args->dnode->parent->parent,
- "./vrf");
- vrf = vrf_lookup_by_name(vrfname);
- assert(vrf);
- ifp = if_lookup_by_name(ifname, vrf->vrf_id);
-
- if (!ifp)
- return NB_OK;
-
- vrf_name = yang_dnode_get_string(args->dnode, NULL);
- circuit = circuit_scan_by_ifp(ifp);
- if (circuit && circuit->area && circuit->isis
- && strcmp(circuit->isis->name, vrf_name)) {
- snprintf(args->errmsg, args->errmsg_len,
- "ISIS circuit is already defined on vrf %s",
- circuit->isis->name);
- return NB_ERR_VALIDATION;
- }
- }
-
- return NB_OK;
-}
-
/*
* XPath: /frr-interface:lib/interface/frr-isisd:isis/circuit-type
*/
struct interface *ifp;
struct vrf *vrf;
const char *ifname, *vrfname;
- struct isis *isis = NULL;
switch (args->event) {
case NB_EV_VALIDATE:
if (!ifp)
break;
- isis = isis_lookup_by_vrfid(ifp->vrf_id);
- if (isis == NULL)
- return NB_ERR_VALIDATION;
-
- circuit = circuit_lookup_by_ifp(ifp, isis->init_circ_list);
+ circuit = circuit_scan_by_ifp(ifp);
if (circuit && circuit->state == C_STATE_UP
&& circuit->area->is_type != IS_LEVEL_1_AND_2
&& circuit->area->is_type != circ_type) {
int lib_interface_isis_passive_modify(struct nb_cb_modify_args *args)
{
struct isis_circuit *circuit;
- struct isis_area *area;
struct interface *ifp;
bool passive = yang_dnode_get_bool(args->dnode, NULL);
return NB_OK;
circuit = nb_running_get_entry(args->dnode, NULL, true);
- if (circuit->state != C_STATE_UP) {
- circuit->is_passive = passive;
- } else {
- area = circuit->area;
- isis_csm_state_change(ISIS_DISABLE, circuit, area);
- circuit->is_passive = passive;
- isis_csm_state_change(ISIS_ENABLE, circuit, area);
- }
+ isis_circuit_passive_set(circuit, passive);
return NB_OK;
}
struct isis_circuit *circuit;
struct ldp_sync_info *ldp_sync_info;
bool ldp_sync_enable;
- struct isis *isis;
+ struct interface *ifp;
switch (args->event) {
case NB_EV_VALIDATE:
+ ifp = nb_running_get_entry(args->dnode->parent->parent->parent,
+ NULL, false);
+ if (ifp == NULL)
+ return NB_ERR_VALIDATION;
+ if (if_is_loopback(ifp)) {
+ snprintf(args->errmsg, args->errmsg_len,
+ "LDP-Sync does not run on loopback interface");
+ return NB_ERR_VALIDATION;
+ }
+
circuit = nb_running_get_entry(args->dnode, NULL, false);
if (circuit == NULL || circuit->area == NULL)
- return NB_ERR_VALIDATION;
+ break;
if (circuit->isis->vrf_id != VRF_DEFAULT) {
snprintf(args->errmsg, args->errmsg_len,
case NB_EV_APPLY:
circuit = nb_running_get_entry(args->dnode, NULL, true);
ldp_sync_enable = yang_dnode_get_bool(args->dnode, NULL);
- isis = circuit->isis;
- if (circuit->ldp_sync_info == NULL)
- isis_ldp_sync_if_init(circuit, isis);
- assert(circuit->ldp_sync_info != NULL);
ldp_sync_info = circuit->ldp_sync_info;
- if (ldp_sync_enable) {
- /* enable LDP-SYNC on an interface
- * if ptop interface send message to LDP to get state
- */
- SET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG);
- ldp_sync_info->enabled = LDP_IGP_SYNC_ENABLED;
- if (circuit->circ_type == CIRCUIT_T_P2P) {
- ldp_sync_info->state =
- LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
- isis_ldp_sync_state_req_msg(circuit);
- } else {
- zlog_debug("ldp_sync: only runs on P2P links %s",
- circuit->interface->name);
- ldp_sync_info->state =
- LDP_IGP_SYNC_STATE_NOT_REQUIRED;
- }
- } else {
- /* disable LDP-SYNC on an interface
- * stop holddown timer if running
- * restore isis metric
- */
- SET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG);
- ldp_sync_info->enabled = LDP_IGP_SYNC_DEFAULT;
- ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED;
- THREAD_OFF(ldp_sync_info->t_holddown);
- isis_ldp_sync_set_if_metric(circuit, true);
+ SET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG);
+ ldp_sync_info->enabled = ldp_sync_enable;
+
+ if (circuit->area) {
+ if (ldp_sync_enable)
+ isis_if_ldp_sync_enable(circuit);
+ else
+ isis_if_ldp_sync_disable(circuit);
}
break;
}
struct isis_circuit *circuit;
struct ldp_sync_info *ldp_sync_info;
uint16_t holddown;
- struct isis *isis;
+ struct interface *ifp;
switch (args->event) {
case NB_EV_VALIDATE:
+ ifp = nb_running_get_entry(args->dnode->parent->parent->parent,
+ NULL, false);
+ if (ifp == NULL)
+ return NB_ERR_VALIDATION;
+ if (if_is_loopback(ifp)) {
+ snprintf(args->errmsg, args->errmsg_len,
+ "LDP-Sync does not run on loopback interface");
+ return NB_ERR_VALIDATION;
+ }
+
circuit = nb_running_get_entry(args->dnode, NULL, false);
if (circuit == NULL || circuit->area == NULL)
- return NB_ERR_VALIDATION;
+ break;
if (circuit->isis->vrf_id != VRF_DEFAULT) {
snprintf(args->errmsg, args->errmsg_len,
case NB_EV_APPLY:
circuit = nb_running_get_entry(args->dnode, NULL, true);
holddown = yang_dnode_get_uint16(args->dnode, NULL);
- isis = circuit->isis;
- if (circuit->ldp_sync_info == NULL)
- isis_ldp_sync_if_init(circuit, isis);
- assert(circuit->ldp_sync_info != NULL);
ldp_sync_info = circuit->ldp_sync_info;
SET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN);
{
struct isis_circuit *circuit;
struct ldp_sync_info *ldp_sync_info;
- struct isis *isis;
+ struct interface *ifp;
switch (args->event) {
case NB_EV_VALIDATE:
- circuit = nb_running_get_entry(args->dnode, NULL, false);
- if (circuit == NULL || circuit->ldp_sync_info == NULL
- || circuit->area == NULL)
+ ifp = nb_running_get_entry(args->dnode->parent->parent->parent,
+ NULL, false);
+ if (ifp == NULL)
+ return NB_ERR_VALIDATION;
+ if (if_is_loopback(ifp)) {
+ snprintf(args->errmsg, args->errmsg_len,
+ "LDP-Sync does not run on loopback interface");
return NB_ERR_VALIDATION;
+ }
+
+ circuit = nb_running_get_entry(args->dnode, NULL, false);
+ if (circuit == NULL || circuit->area == NULL)
+ break;
if (circuit->isis->vrf_id != VRF_DEFAULT) {
snprintf(args->errmsg, args->errmsg_len,
break;
case NB_EV_APPLY:
circuit = nb_running_get_entry(args->dnode, NULL, true);
- isis = circuit->isis;
ldp_sync_info = circuit->ldp_sync_info;
+
UNSET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN);
- if (CHECK_FLAG(isis->ldp_sync_cmd.flags,
- LDP_SYNC_FLAG_HOLDDOWN))
- ldp_sync_info->holddown = isis->ldp_sync_cmd.holddown;
- else
- ldp_sync_info->holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT;
+ if (circuit->area)
+ isis_if_set_ldp_sync_holddown(circuit);
break;
}
circuit = nb_running_get_entry(args->dnode, NULL, true);
circuit->lfa_protection[0] = yang_dnode_get_bool(args->dnode, NULL);
- if (circuit->lfa_protection[0])
- circuit->area->lfa_protected_links[0]++;
- else {
- assert(circuit->area->lfa_protected_links[0] > 0);
- circuit->area->lfa_protected_links[0]--;
- }
area = circuit->area;
- lsp_regenerate_schedule(area, area->is_type, 0);
+ if (area) {
+ if (circuit->lfa_protection[0])
+ area->lfa_protected_links[0]++;
+ else {
+ assert(area->lfa_protected_links[0] > 0);
+ area->lfa_protected_links[0]--;
+ }
+
+ lsp_regenerate_schedule(area, area->is_type, 0);
+ }
return NB_OK;
}
isis_lfa_excluded_iface_add(circuit, ISIS_LEVEL1, exclude_ifname);
area = circuit->area;
- lsp_regenerate_schedule(area, area->is_type, 0);
+ if (area)
+ lsp_regenerate_schedule(area, area->is_type, 0);
return NB_OK;
}
isis_lfa_excluded_iface_delete(circuit, ISIS_LEVEL1, exclude_ifname);
area = circuit->area;
- lsp_regenerate_schedule(area, area->is_type, 0);
+ if (area)
+ lsp_regenerate_schedule(area, area->is_type, 0);
return NB_OK;
}
circuit = nb_running_get_entry(args->dnode, NULL, true);
circuit->rlfa_protection[0] = yang_dnode_get_bool(args->dnode, NULL);
- if (circuit->rlfa_protection[0])
- circuit->area->rlfa_protected_links[0]++;
- else {
- assert(circuit->area->rlfa_protected_links[0] > 0);
- circuit->area->rlfa_protected_links[0]--;
- }
area = circuit->area;
- lsp_regenerate_schedule(area, area->is_type, 0);
+ if (area) {
+ if (circuit->rlfa_protection[0])
+ area->rlfa_protected_links[0]++;
+ else {
+ assert(area->rlfa_protected_links[0] > 0);
+ area->rlfa_protected_links[0]--;
+ }
+
+ lsp_regenerate_schedule(area, area->is_type, 0);
+ }
return NB_OK;
}
circuit->rlfa_max_metric[0] = yang_dnode_get_uint32(args->dnode, NULL);
area = circuit->area;
- lsp_regenerate_schedule(area, area->is_type, 0);
+ if (area)
+ lsp_regenerate_schedule(area, area->is_type, 0);
return NB_OK;
}
circuit->rlfa_max_metric[0] = 0;
area = circuit->area;
- lsp_regenerate_schedule(area, area->is_type, 0);
+ if (area)
+ lsp_regenerate_schedule(area, area->is_type, 0);
return NB_OK;
}
circuit = nb_running_get_entry(args->dnode, NULL, true);
circuit->tilfa_protection[0] = yang_dnode_get_bool(args->dnode, NULL);
- if (circuit->tilfa_protection[0])
- circuit->area->tilfa_protected_links[0]++;
- else {
- assert(circuit->area->tilfa_protected_links[0] > 0);
- circuit->area->tilfa_protected_links[0]--;
- }
area = circuit->area;
- lsp_regenerate_schedule(area, area->is_type, 0);
+ if (area) {
+ if (circuit->tilfa_protection[0])
+ area->tilfa_protected_links[0]++;
+ else {
+ assert(area->tilfa_protected_links[0] > 0);
+ area->tilfa_protected_links[0]--;
+ }
+
+ lsp_regenerate_schedule(area, area->is_type, 0);
+ }
return NB_OK;
}
yang_dnode_get_bool(args->dnode, NULL);
area = circuit->area;
- lsp_regenerate_schedule(area, area->is_type, 0);
+ if (area)
+ lsp_regenerate_schedule(area, area->is_type, 0);
+
+ return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/ti-lfa/link-fallback
+ */
+int lib_interface_isis_fast_reroute_level_1_ti_lfa_link_fallback_modify(
+ struct nb_cb_modify_args *args)
+{
+ struct isis_area *area;
+ struct isis_circuit *circuit;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ circuit = nb_running_get_entry(args->dnode, NULL, true);
+ circuit->tilfa_link_fallback[0] =
+ yang_dnode_get_bool(args->dnode, NULL);
+
+ area = circuit->area;
+ if (area)
+ lsp_regenerate_schedule(area, area->is_type, 0);
return NB_OK;
}
circuit = nb_running_get_entry(args->dnode, NULL, true);
circuit->lfa_protection[1] = yang_dnode_get_bool(args->dnode, NULL);
- if (circuit->lfa_protection[1])
- circuit->area->lfa_protected_links[1]++;
- else {
- assert(circuit->area->lfa_protected_links[1] > 0);
- circuit->area->lfa_protected_links[1]--;
- }
area = circuit->area;
- lsp_regenerate_schedule(area, area->is_type, 0);
+ if (area) {
+ if (circuit->lfa_protection[1])
+ area->lfa_protected_links[1]++;
+ else {
+ assert(area->lfa_protected_links[1] > 0);
+ area->lfa_protected_links[1]--;
+ }
+
+ lsp_regenerate_schedule(area, area->is_type, 0);
+ }
return NB_OK;
}
isis_lfa_excluded_iface_add(circuit, ISIS_LEVEL2, exclude_ifname);
area = circuit->area;
- lsp_regenerate_schedule(area, area->is_type, 0);
+ if (area)
+ lsp_regenerate_schedule(area, area->is_type, 0);
return NB_OK;
}
isis_lfa_excluded_iface_delete(circuit, ISIS_LEVEL2, exclude_ifname);
area = circuit->area;
- lsp_regenerate_schedule(area, area->is_type, 0);
+ if (area)
+ lsp_regenerate_schedule(area, area->is_type, 0);
return NB_OK;
}
circuit = nb_running_get_entry(args->dnode, NULL, true);
circuit->rlfa_protection[1] = yang_dnode_get_bool(args->dnode, NULL);
- if (circuit->rlfa_protection[1])
- circuit->area->rlfa_protected_links[1]++;
- else {
- assert(circuit->area->rlfa_protected_links[1] > 0);
- circuit->area->rlfa_protected_links[1]--;
- }
area = circuit->area;
- lsp_regenerate_schedule(area, area->is_type, 0);
+ if (area) {
+ if (circuit->rlfa_protection[1])
+ area->rlfa_protected_links[1]++;
+ else {
+ assert(area->rlfa_protected_links[1] > 0);
+ area->rlfa_protected_links[1]--;
+ }
+
+ lsp_regenerate_schedule(area, area->is_type, 0);
+ }
return NB_OK;
}
circuit->rlfa_max_metric[1] = yang_dnode_get_uint32(args->dnode, NULL);
area = circuit->area;
- lsp_regenerate_schedule(area, area->is_type, 0);
+ if (area)
+ lsp_regenerate_schedule(area, area->is_type, 0);
return NB_OK;
}
circuit->rlfa_max_metric[1] = 0;
area = circuit->area;
- lsp_regenerate_schedule(area, area->is_type, 0);
+ if (area)
+ lsp_regenerate_schedule(area, area->is_type, 0);
return NB_OK;
}
circuit = nb_running_get_entry(args->dnode, NULL, true);
circuit->tilfa_protection[1] = yang_dnode_get_bool(args->dnode, NULL);
- if (circuit->tilfa_protection[1])
- circuit->area->tilfa_protected_links[1]++;
- else {
- assert(circuit->area->tilfa_protected_links[1] > 0);
- circuit->area->tilfa_protected_links[1]--;
- }
area = circuit->area;
- lsp_regenerate_schedule(area, area->is_type, 0);
+ if (area) {
+ if (circuit->tilfa_protection[1])
+ area->tilfa_protected_links[1]++;
+ else {
+ assert(area->tilfa_protected_links[1] > 0);
+ area->tilfa_protected_links[1]--;
+ }
+
+ lsp_regenerate_schedule(area, area->is_type, 0);
+ }
return NB_OK;
}
yang_dnode_get_bool(args->dnode, NULL);
area = circuit->area;
- lsp_regenerate_schedule(area, area->is_type, 0);
+ if (area)
+ lsp_regenerate_schedule(area, area->is_type, 0);
+
+ return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/ti-lfa/link-fallback
+ */
+int lib_interface_isis_fast_reroute_level_2_ti_lfa_link_fallback_modify(
+ struct nb_cb_modify_args *args)
+{
+ struct isis_area *area;
+ struct isis_circuit *circuit;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ circuit = nb_running_get_entry(args->dnode, NULL, true);
+ circuit->tilfa_link_fallback[1] =
+ yang_dnode_get_bool(args->dnode, NULL);
+
+ area = circuit->area;
+ if (area)
+ lsp_regenerate_schedule(area, area->is_type, 0);
return NB_OK;
}
#include "memory.h"
#include "smux.h"
#include "libfrr.h"
-#include "version.h"
+#include "lib/version.h"
#include "isisd/isis_constants.h"
#include "isisd/isis_common.h"
/* Protocols supported value */
static uint8_t isis_snmp_protocols_supported = 0x7; /* All: iso, ipv4, ipv6 */
+#define SNMP_CIRCUITS_MAX (512)
+
+static struct isis_circuit *snmp_circuits[SNMP_CIRCUITS_MAX];
+static uint32_t snmp_circuit_id_last;
+
+static int isis_circuit_snmp_id_gen(struct isis_circuit *circuit)
+{
+ uint32_t id;
+ uint32_t i;
+
+ id = snmp_circuit_id_last;
+ id++;
+
+ /* find next unused entry */
+ for (i = 0; i < SNMP_CIRCUITS_MAX; i++) {
+ if (id >= SNMP_CIRCUITS_MAX) {
+ id = 0;
+ continue;
+ }
+
+ if (id == 0)
+ continue;
+
+ if (snmp_circuits[id] == NULL)
+ break;
+
+ id++;
+ }
+
+ if (i == SNMP_CIRCUITS_MAX) {
+ zlog_warn("Could not allocate a smmp-circuit-id");
+ return 0;
+ }
+
+ snmp_circuits[id] = circuit;
+ snmp_circuit_id_last = id;
+ circuit->snmp_id = id;
+
+ return 0;
+}
+
+static int isis_circuit_snmp_id_free(struct isis_circuit *circuit)
+{
+ snmp_circuits[circuit->snmp_id] = NULL;
+ circuit->snmp_id = 0;
+ return 0;
+}
+
/*
* Convenience function to move to the next circuit,
*/
{
uint32_t start;
uint32_t off;
- struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
-
- if (isis == NULL)
- return NULL;
start = 1;
start = circuit->snmp_id + 1;
for (off = start; off < SNMP_CIRCUITS_MAX; off++) {
- circuit = isis->snmp_circuits[off];
+ circuit = snmp_circuits[off];
if (circuit != NULL)
return circuit;
struct isis_circuit **ret_circuit)
{
struct isis_circuit *circuit;
- struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
-
- if (isis == NULL)
- return 0;
if (oid_idx == NULL || oid_idx_len < 1
|| oid_idx[0] > SNMP_CIRCUITS_MAX)
return 0;
- circuit = isis->snmp_circuits[oid_idx[0]];
+ circuit = snmp_circuits[oid_idx[0]];
if (circuit == NULL)
return 0;
oid off;
oid start;
struct isis_circuit *circuit;
- struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
-
- if (isis == NULL)
- return 0;
start = 0;
}
for (off = start; off < SNMP_CIRCUITS_MAX; ++off) {
- circuit = isis->snmp_circuits[off];
+ circuit = snmp_circuits[off];
if (circuit != NULL && off > start) {
if (ret_circuit != NULL)
{
oid off;
oid start;
- struct isis_circuit *circuit;
+ struct isis_circuit *circuit = NULL;
int level;
- struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
-
- if (isis == NULL)
- return 0;
start = 0;
}
for (off = start; off < SNMP_CIRCUITS_MAX; off++) {
- circuit = isis->snmp_circuits[off];
+ circuit = snmp_circuits[off];
if (circuit == NULL)
continue;
/* If level does not match all counters are zeros */
return SNMP_INTEGER(0);
- val = 0;
-
switch (v->magic) {
case ISIS_SYSSTAT_CORRLSPS:
val = 0;
switch (v->magic) {
case ISIS_ISADJ_STATE:
- val = ISIS_SNMP_ADJ_STATE_DOWN;
switch (adj->adj_state) {
case ISIS_ADJ_UNKNOWN:
}
case ISIS_ISADJ_NEIGHSYSTYPE:
- val = ISIS_SNMP_ADJ_NEIGHTYPE_UNKNOWN;
switch (adj->sys_type) {
case ISIS_SYSTYPE_UNKNOWN:
hook_register(isis_hook_adj_state_change,
isis_snmp_adj_state_change_update);
hook_register(isis_hook_lsp_error, isis_snmp_lsp_error_update);
+ hook_register(isis_circuit_new_hook, isis_circuit_snmp_id_gen);
+ hook_register(isis_circuit_del_hook, isis_circuit_snmp_id_free);
hook_register(frr_late_init, isis_snmp_init);
return 0;
area = isis_area_lookup(area_tag, VRF_DEFAULT);
if (!area)
- area = isis_area_create(area_tag, VRF_DEFAULT_NAME);
+ isis_area_create(area_tag, VRF_DEFAULT_NAME);
- if (!circuit || !circuit->area) {
- circuit = isis_circuit_create(area, ifp);
+ if (!circuit) {
+ circuit = isis_circuit_new(ifp, area_tag);
if (circuit->state != C_STATE_CONF
&& circuit->state != C_STATE_UP) {
return CMD_ERR_NO_MATCH;
}
- circuit = circuit_lookup_by_ifp(ifp, area->circuit_list);
+ circuit = circuit_scan_by_ifp(ifp);
if (!circuit) {
vty_out(vty, "ISIS is not enabled on circuit %s\n", ifp->name);
return CMD_ERR_NO_MATCH;
ip = false;
isis_circuit_af_set(circuit, ip, ipv6);
+
+ if (!ip && !ipv6)
+ isis_circuit_del(circuit);
+
return CMD_SUCCESS;
}
{
zclient_send_reg_requests(zclient, VRF_DEFAULT);
zclient_register_opaque(zclient, LDP_RLFA_LABELS);
+ zclient_register_opaque(zclient, LDP_IGP_SYNC_IF_STATE_UPDATE);
+ zclient_register_opaque(zclient, LDP_IGP_SYNC_ANNOUNCE_UPDATE);
}
/*
void isis_zebra_stop(void)
{
zclient_unregister_opaque(zclient, LDP_RLFA_LABELS);
+ zclient_unregister_opaque(zclient, LDP_IGP_SYNC_IF_STATE_UPDATE);
+ zclient_unregister_opaque(zclient, LDP_IGP_SYNC_ANNOUNCE_UPDATE);
zclient_stop(zclient_sync);
zclient_free(zclient_sync);
zclient_stop(zclient);
int clear_isis_neighbor_common(struct vty *, const char *id, const char *vrf_name,
bool all_vrf);
-static void isis_add(struct isis *isis)
-{
- listnode_add(im->isis, isis);
-}
-
-static void isis_delete(struct isis *isis)
-{
- listnode_delete(im->isis, isis);
-}
-
/* Link ISIS instance to VRF. */
void isis_vrf_link(struct isis *isis, struct vrf *vrf)
{
struct isis *isis;
isis = isis_lookup_by_vrfname(vrf_name);
- if (isis == NULL) {
- isis = isis_new(vrf_name);
- isis_add(isis);
- }
+ if (isis == NULL)
+ isis_new(vrf_name);
}
struct isis *isis_new(const char *vrf_name)
struct isis *isis;
isis = XCALLOC(MTYPE_ISIS, sizeof(struct isis));
+
+ isis->name = XSTRDUP(MTYPE_ISIS_NAME, vrf_name);
+
vrf = vrf_lookup_by_name(vrf_name);
- if (vrf) {
- isis->vrf_id = vrf->vrf_id;
+ if (vrf)
isis_vrf_link(isis, vrf);
- isis->name = XSTRDUP(MTYPE_ISIS_NAME, vrf->name);
- } else {
+ else
isis->vrf_id = VRF_UNKNOWN;
- isis->name = XSTRDUP(MTYPE_ISIS_NAME, vrf_name);
- }
if (IS_DEBUG_EVENTS)
zlog_debug(
isis->process_id = getpid();
isis->router_id = 0;
isis->area_list = list_new();
- isis->init_circ_list = list_new();
isis->uptime = time(NULL);
isis->snmp_notifications = 1;
dyn_cache_init(isis);
+ listnode_add(im->isis, isis);
+
return isis;
}
+void isis_finish(struct isis *isis)
+{
+ struct vrf *vrf = NULL;
+
+ listnode_delete(im->isis, isis);
+
+ vrf = vrf_lookup_by_name(isis->name);
+ if (vrf)
+ isis_vrf_unlink(isis, vrf);
+ XFREE(MTYPE_ISIS_NAME, isis->name);
+
+ isis_redist_free(isis);
+ list_delete(&isis->area_list);
+ XFREE(MTYPE_ISIS, isis);
+}
+
+void isis_area_add_circuit(struct isis_area *area, struct isis_circuit *circuit)
+{
+ isis_csm_state_change(ISIS_ENABLE, circuit, area);
+
+ area->ip_circuits += circuit->ip_router;
+ area->ipv6_circuits += circuit->ipv6_router;
+
+ area->lfa_protected_links[0] += circuit->lfa_protection[0];
+ area->rlfa_protected_links[0] += circuit->rlfa_protection[0];
+ area->tilfa_protected_links[0] += circuit->tilfa_protection[0];
+
+ area->lfa_protected_links[1] += circuit->lfa_protection[1];
+ area->rlfa_protected_links[1] += circuit->rlfa_protection[1];
+ area->tilfa_protected_links[1] += circuit->tilfa_protection[1];
+}
+
+void isis_area_del_circuit(struct isis_area *area, struct isis_circuit *circuit)
+{
+ area->ip_circuits -= circuit->ip_router;
+ area->ipv6_circuits -= circuit->ipv6_router;
+
+ area->lfa_protected_links[0] -= circuit->lfa_protection[0];
+ area->rlfa_protected_links[0] -= circuit->rlfa_protection[0];
+ area->tilfa_protected_links[0] -= circuit->tilfa_protection[0];
+
+ area->lfa_protected_links[1] -= circuit->lfa_protection[1];
+ area->rlfa_protected_links[1] -= circuit->rlfa_protection[1];
+ area->tilfa_protected_links[1] -= circuit->tilfa_protection[1];
+
+ isis_csm_state_change(ISIS_DISABLE, circuit, area);
+}
+
struct isis_area *isis_area_create(const char *area_tag, const char *vrf_name)
{
struct isis_area *area;
struct isis *isis = NULL;
struct vrf *vrf = NULL;
+ struct interface *ifp;
+ struct isis_circuit *circuit;
+
area = XCALLOC(MTYPE_ISIS_AREA, sizeof(struct isis_area));
- if (vrf_name) {
- vrf = vrf_lookup_by_name(vrf_name);
- if (vrf) {
- isis = isis_lookup_by_vrfid(vrf->vrf_id);
- if (isis == NULL) {
- isis = isis_new(vrf_name);
- isis_add(isis);
- }
- } else {
- isis = isis_lookup_by_vrfid(VRF_UNKNOWN);
- if (isis == NULL) {
- isis = isis_new(vrf_name);
- isis_add(isis);
- }
- }
- } else {
- isis = isis_lookup_by_vrfid(VRF_DEFAULT);
- if (isis == NULL) {
- isis = isis_new(VRF_DEFAULT_NAME);
- isis_add(isis);
- }
- }
+ if (!vrf_name)
+ vrf_name = VRF_DEFAULT_NAME;
+
+ vrf = vrf_lookup_by_name(vrf_name);
+ isis = isis_lookup_by_vrfname(vrf_name);
+
+ if (isis == NULL)
+ isis = isis_new(vrf_name);
listnode_add(isis->area_list, area);
area->isis = isis;
area->bfd_signalled_down = false;
area->bfd_force_spf_refresh = false;
-
QOBJ_REG(area, isis_area);
+ if (vrf) {
+ FOR_ALL_INTERFACES (vrf, ifp) {
+ if (ifp->ifindex == IFINDEX_INTERNAL)
+ continue;
+
+ circuit = ifp->info;
+ if (circuit)
+ isis_area_add_circuit(area, circuit);
+ }
+ }
+
return area;
}
if (area->circuit_list) {
for (ALL_LIST_ELEMENTS(area->circuit_list, node, nnode,
- circuit)) {
- circuit->ip_router = 0;
- circuit->ipv6_router = 0;
- isis_csm_state_change(ISIS_DISABLE, circuit, area);
- }
+ circuit))
+ isis_area_del_circuit(area, circuit);
+
list_delete(&area->circuit_list);
}
list_delete(&area->adjacency_list);
isis = isis_lookup_by_vrfname(vrf->name);
if (isis) {
- if (isis->name && strmatch(vrf->name, VRF_DEFAULT_NAME)) {
- XFREE(MTYPE_ISIS_NAME, isis->name);
- isis->name = NULL;
- }
old_vrf_id = isis->vrf_id;
/* We have instance configured, link to VRF and make it "up". */
isis_vrf_link(isis, vrf);
isis_vrf_delete, isis_vrf_enable);
}
-void isis_finish(struct isis *isis)
-{
- struct vrf *vrf = NULL;
-
- isis_delete(isis);
- if (isis->name) {
- vrf = vrf_lookup_by_name(isis->name);
- if (vrf)
- isis_vrf_unlink(isis, vrf);
- XFREE(MTYPE_ISIS_NAME, isis->name);
- } else {
- vrf = vrf_lookup_by_id(VRF_DEFAULT);
- if (vrf)
- isis_vrf_unlink(isis, vrf);
- }
-
- isis_redist_free(isis);
- list_delete(&isis->area_list);
- list_delete(&isis->init_circ_list);
- XFREE(MTYPE_ISIS, isis);
-}
-
void isis_terminate()
{
struct isis *isis;
print_debug(vty, DEBUG_BFD, 1);
if (IS_DEBUG_LDP_SYNC)
print_debug(vty, DEBUG_LDP_SYNC, 1);
+ if (IS_DEBUG_LFA)
+ print_debug(vty, DEBUG_LFA, 1);
+
return CMD_SUCCESS;
}
all_vrf = strmatch(vrf_name, "all"); \
}
-#define SNMP_CIRCUITS_MAX (512)
-
extern struct zebra_privs_t isisd_privs;
/* uncomment if you are a developer in bug hunt */
uint8_t sysid[ISIS_SYS_ID_LEN]; /* SystemID for this IS */
uint32_t router_id; /* Router ID from zebra */
struct list *area_list; /* list of IS-IS areas */
- struct list *init_circ_list;
uint8_t max_area_addrs; /* maximumAreaAdresses */
struct area_addr *man_area_addrs; /* manualAreaAddresses */
time_t uptime; /* when did we start */
struct thread *t_dync_clean; /* dynamic hostname cache cleanup thread */
uint32_t circuit_ids_used[8]; /* 256 bits to track circuit ids 1 through 255 */
- struct isis_circuit *snmp_circuits[SNMP_CIRCUITS_MAX];
- uint32_t snmp_circuit_id_last;
int snmp_notifications;
struct route_table *ext_info[REDIST_PROTOCOL_COUNT];
- struct ldp_sync_info_cmd ldp_sync_cmd; /* MPLS LDP-IGP Sync */
};
extern struct isis_master *im;
struct prefix_list *rlfa_plist[ISIS_LEVELS];
size_t rlfa_protected_links[ISIS_LEVELS];
size_t tilfa_protected_links[ISIS_LEVELS];
+ /* MPLS LDP-IGP Sync */
+ struct ldp_sync_info_cmd ldp_sync_cmd;
/* Counters */
uint32_t circuit_state_changes;
struct isis_redist redist_settings[REDIST_PROTOCOL_COUNT]
DECLARE_HOOK(isis_area_overload_bit_update, (struct isis_area * area), (area));
void isis_terminate(void);
-void isis_finish(struct isis *isis);
void isis_master_init(struct thread_master *master);
void isis_vrf_link(struct isis *isis, struct vrf *vrf);
void isis_vrf_unlink(struct isis *isis, struct vrf *vrf);
void isis_vrf_init(void);
struct isis *isis_new(const char *vrf_name);
+void isis_finish(struct isis *isis);
+
+void isis_area_add_circuit(struct isis_area *area,
+ struct isis_circuit *circuit);
+void isis_area_del_circuit(struct isis_area *area,
+ struct isis_circuit *circuit);
+
struct isis_area *isis_area_create(const char *, const char *);
struct isis_area *isis_area_lookup(const char *, vrf_id_t vrf_id);
struct isis_area *isis_area_lookup_by_vrf(const char *area_tag,
# end
isisd_isisd_snmp_la_SOURCES = isisd/isis_snmp.c
-isisd_isisd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11
+isisd_isisd_snmp_la_CFLAGS = $(AM_CFLAGS) $(SNMP_CFLAGS) -std=gnu11
isisd_isisd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
isisd_isisd_snmp_la_LIBADD = lib/libfrrsnmp.la
log_procname = log_procnames[PROC_LDE_ENGINE];
master = frr_init();
+ /* no frr_config_fork() here, allow frr_pthread to create threads */
+ frr_is_after_fork = true;
/* setup signal handler */
signal_init(master, array_size(lde_signals), lde_signals);
}
}
+void
+lde_allow_broken_lsp_update(int new_config)
+{
+ struct fec_node *fn;
+ struct fec_nh *fnh;
+ struct fec *f;
+
+ RB_FOREACH(f, fec_tree, &ft) {
+ fn = (struct fec_node *)f;
+
+ LIST_FOREACH(fnh, &fn->nexthops, entry) {
+ /* allow-broken-lsp config is changing so
+ * we need to reprogram labeled routes to
+ * have proper top-level label
+ */
+ if (!(new_config & F_LDPD_ALLOW_BROKEN_LSP))
+ lde_send_delete_klabel(fn, fnh);
+
+ if (fn->local_label != NO_LABEL)
+ lde_send_change_klabel(fn, fnh);
+ }
+ }
+}
+
static __inline int
lde_map_compare(const struct lde_map *a, const struct lde_map *b)
{
void lde_route_update_release_all(int);
struct lde_addr *lde_address_find(struct lde_nbr *, int,
union ldpd_addr *);
+void lde_allow_broken_lsp_update(int new_config);
/* lde_lib.c */
void fec_init(struct fec_tree *);
#include "memory.h"
#include "smux.h"
#include "libfrr.h"
-#include "version.h"
+#include "lib/version.h"
#include "ldpd.h"
#include "ldpe.h"
union ldpd_addr;
int ldp_get_address(const char *, int *, union ldpd_addr *);
int ldp_vty_mpls_ldp (struct vty *, const char *);
+int ldp_vty_allow_broken_lsp(struct vty *, const char *);
int ldp_vty_address_family (struct vty *, const char *, const char *);
int ldp_vty_disc_holdtime(struct vty *, const char *, enum hello_type, long);
int ldp_vty_disc_interval(struct vty *, const char *, enum hello_type, long);
}
+DEFPY (ldp_allow_broken_lsps,
+ ldp_allow_broken_lsps_cmd,
+ "[no] install allow-broken-lsps",
+ NO_STR
+ "install lsps\n"
+ "if no remote-label install with imp-null")
+{
+ return (ldp_vty_allow_broken_lsp(vty, no));
+}
+
DEFPY (ldp_discovery_targeted_hello_accept,
ldp_discovery_targeted_hello_accept_cmd,
"[no] discovery targeted-hello accept [from <(1-199)|(1300-2699)|WORD>$from_acl]",
install_element(LDP_NODE, &ldp_router_id_cmd);
install_element(LDP_NODE, &ldp_ordered_control_cmd);
install_element(LDP_NODE, &ldp_wait_for_sync_cmd);
+ install_element(LDP_NODE, &ldp_allow_broken_lsps_cmd);
install_element(LDP_IPV4_NODE, &ldp_discovery_link_holdtime_cmd);
install_element(LDP_IPV4_NODE, &ldp_discovery_targeted_holdtime_cmd);
vty_out (vty, " wait-for-sync %u\n",
ldpd_conf->wait_for_sync_interval);
+ if (ldpd_conf->flags & F_LDPD_ALLOW_BROKEN_LSP)
+ vty_out(vty, " install allow-broken-lsp\n");
+
RB_FOREACH(nbrp, nbrp_head, &ldpd_conf->nbrp_tree) {
if (nbrp->flags & F_NBRP_KEEPALIVE)
vty_out (vty, " neighbor %pI4 session holdtime %u\n",
vty_conf->flags |= F_LDPD_ENABLED;
}
+ /* register / de-register to recv info from zebra */
+ ldp_zebra_regdereg_zebra_info(!negate);
+
ldp_config_apply(vty, vty_conf);
return (CMD_SUCCESS);
return (CMD_SUCCESS);
}
+int
+ldp_vty_allow_broken_lsp(struct vty *vty, const char *negate)
+{
+ if (negate)
+ vty_conf->flags &= ~F_LDPD_ALLOW_BROKEN_LSP;
+ else
+ vty_conf->flags |= F_LDPD_ALLOW_BROKEN_LSP;
+
+ ldp_config_apply(vty, vty_conf);
+
+ return (CMD_SUCCESS);
+}
+
int
ldp_vty_ds_cisco_interop(struct vty *vty, const char * negate)
{
static void ldp_sync_zebra_init(void);
static struct zclient *zclient;
+static bool zebra_registered = false;
static void
ifp2kif(struct interface *ifp, struct kif *kif)
zl.route.instance = kr->route_instance;
}
- /*
- * For broken LSPs, instruct the forwarding plane to pop the top-level
+ /* If allow-broken-lsps is enabled then if an lsp is received with
+ * no remote label, instruct the forwarding plane to pop the top-level
* label and forward packets normally. This is a best-effort attempt
* to deliver labeled IP packets to their final destination (instead of
* dropping them).
*/
+ if (kr->remote_label == NO_LABEL
+ && !(ldpd_conf->flags & F_LDPD_ALLOW_BROKEN_LSP)
+ && cmd == ZEBRA_MPLS_LABELS_ADD)
+ return 0;
+
if (kr->remote_label == NO_LABEL)
kr->remote_label = MPLS_LABEL_IMPLICIT_NULL;
return (0);
}
+void ldp_zebra_regdereg_zebra_info(bool want_register)
+{
+ if (zebra_registered == want_register)
+ return;
+
+ log_debug("%s to receive default VRF information",
+ want_register ? "Register" : "De-register");
+
+ if (want_register) {
+ zclient_send_reg_requests(zclient, VRF_DEFAULT);
+ zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP,
+ ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT);
+ zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient,
+ AFI_IP6, ZEBRA_ROUTE_ALL, 0,
+ VRF_DEFAULT);
+ } else {
+ zclient_send_dereg_requests(zclient, VRF_DEFAULT);
+ zebra_redistribute_send(ZEBRA_REDISTRIBUTE_DELETE, zclient,
+ AFI_IP, ZEBRA_ROUTE_ALL, 0,
+ VRF_DEFAULT);
+ zebra_redistribute_send(ZEBRA_REDISTRIBUTE_DELETE, zclient,
+ AFI_IP6, ZEBRA_ROUTE_ALL, 0,
+ VRF_DEFAULT);
+ }
+ zebra_registered = want_register;
+}
+
static void
ldp_zebra_connected(struct zclient *zclient)
{
- zclient_send_reg_requests(zclient, VRF_DEFAULT);
- zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP,
- ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT);
- zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6,
- ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT);
+ zebra_registered = false;
+
+ /* if MPLS was already enabled and we are re-connecting, register again
+ */
+ if (vty_conf->flags & F_LDPD_ENABLED)
+ ldp_zebra_regdereg_zebra_info(true);
ldp_zebra_opaque_register();
if (access && access->name[0] != '\0') {
strlcpy(laccess.name, access->name, sizeof(laccess.name));
- laccess.type = access->type;
- debug_evt("%s ACL update filter name %s type %d", __func__,
- access->name, access->type);
+ debug_evt("%s ACL update filter name %s", __func__,
+ access->name);
main_imsg_compose_both(IMSG_FILTER_UPDATE, &laccess,
sizeof(laccess));
ldpe_reset_ds_nbrs();
}
+ /*
+ * Configuration of allow-broken-lsp requires reprograming all
+ * labeled routes
+ */
+ if ((conf->flags & F_LDPD_ALLOW_BROKEN_LSP) !=
+ (xconf->flags & F_LDPD_ALLOW_BROKEN_LSP)) {
+ if (ldpd_process == PROC_LDE_ENGINE)
+ lde_allow_broken_lsp_update(xconf->flags);
+ }
+
if (ldpd_process == PROC_LDP_ENGINE)
ldpe_set_config_change_time();
struct ldp_access {
char name[ACL_NAMSIZ];
- enum access_type type;
};
union ldpd_addr {
#define F_LDPD_DS_CISCO_INTEROP 0x0002
#define F_LDPD_ENABLED 0x0004
#define F_LDPD_ORDERED_CONTROL 0x0008
-
+#define F_LDPD_ALLOW_BROKEN_LSP 0x0010
struct ldpd_af_global {
struct thread *disc_ev;
int ldp_zebra_send_rlfa_labels(struct zapi_rlfa_response *
rlfa_labels);
+void ldp_zebra_regdereg_zebra_info(bool want_register);
+
/* compatibility */
#ifndef __OpenBSD__
#define __IPV6_ADDR_MC_SCOPE(a) ((a)->s6_addr[1] & 0x0f)
log_procname = log_procnames[ldpd_process];
master = frr_init();
+ /* no frr_config_fork() here, allow frr_pthread to create threads */
+ frr_is_after_fork = true;
/* setup signal handler */
signal_init(master, array_size(ldpe_signals), ldpe_signals);
ldpd_ldpd_LDADD = ldpd/libldp.a lib/libfrr.la $(LIBCAP)
ldpd_ldpd_snmp_la_SOURCES = ldpd/ldp_snmp.c
-ldpd_ldpd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11
+ldpd_ldpd_snmp_la_CFLAGS = $(AM_CFLAGS) $(SNMP_CFLAGS) -std=gnu11
ldpd_ldpd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
ldpd_ldpd_snmp_la_LIBADD = lib/libfrrsnmp.la
#include "smux.h"
#include "memory.h"
#include "linklist.h"
-#include "version.h"
+#include "lib/version.h"
#include "lib_errors.h"
#include "xref.h"
--- /dev/null
+/*
+ * Copyright (c) 2021 David Lamparter, for NetDEF, Inc.
+ *
+ * Permission to use, copy, modify, and 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 THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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.
+ */
+
+/* WARNING: this file is "special" in that it overrides the system-provided
+ * assert.h by being on the include path before it. That means it should
+ * provide the functional equivalent.
+ *
+ * This is intentional because FRR extends assert() to write to the log and
+ * add backtraces. Overriding the entire file is the simplest and most
+ * reliable way to get this to work; there were problems previously with the
+ * system assert.h getting included afterwards and redefining assert() back to
+ * the system variant.
+ */
+
+#ifndef _FRR_ASSERT_H
+#define _FRR_ASSERT_H
+
+#include "xref.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef __cplusplus
+/* C++ has this built-in, but C provides it in assert.h for >=C11. Since we
+ * replace assert.h entirely, we need to provide it here too.
+ */
+#define static_assert _Static_assert
+#endif
+
+struct xref_assert {
+ struct xref xref;
+
+ const char *expr;
+ const char *extra, *args;
+};
+
+extern void _zlog_assert_failed(const struct xref_assert *xref,
+ const char *extra, ...) PRINTFRR(2, 3)
+ __attribute__((noreturn));
+
+/* the "do { } while (expr_)" is there to get a warning for assignments inside
+ * the assert expression aka "assert(x = 1)". The (necessary) braces around
+ * expr_ in the if () statement would suppress these warnings. Since
+ * _zlog_assert_failed() is noreturn, the while condition will never be
+ * checked.
+ */
+#define assert(expr_) \
+ ({ \
+ static const struct xref_assert _xref __attribute__( \
+ (used)) = { \
+ .xref = XREF_INIT(XREFT_ASSERT, NULL, __func__), \
+ .expr = #expr_, \
+ }; \
+ XREF_LINK(_xref.xref); \
+ if (__builtin_expect((expr_) ? 0 : 1, 0)) \
+ do { \
+ _zlog_assert_failed(&_xref, NULL); \
+ } while (expr_); \
+ })
+
+#define assertf(expr_, extra_, ...) \
+ ({ \
+ static const struct xref_assert _xref __attribute__( \
+ (used)) = { \
+ .xref = XREF_INIT(XREFT_ASSERT, NULL, __func__), \
+ .expr = #expr_, \
+ .extra = extra_, \
+ .args = #__VA_ARGS__, \
+ }; \
+ XREF_LINK(_xref.xref); \
+ if (__builtin_expect((expr_) ? 0 : 1, 0)) \
+ do { \
+ _zlog_assert_failed(&_xref, extra_, \
+ ##__VA_ARGS__); \
+ } while (expr_); \
+ })
+
+#define zassert assert
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FRR_ASSERT_H */
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;
}
/*
/** BFD session installation state. */
bool installed;
- /** BFD session enabled. */
- bool enabled;
/** Global BFD paramaters list. */
TAILQ_ENTRY(bfd_session_params) entry;
bsp->installed = false;
else if (bsp->args.command == ZEBRA_BFD_DEST_REGISTER)
bsp->installed = true;
+ } else {
+ struct ipaddr src, dst;
+
+ src.ipa_type = bsp->args.family;
+ src.ipaddr_v6 = bsp->args.src;
+ dst.ipa_type = bsp->args.family;
+ dst.ipaddr_v6 = bsp->args.dst;
+
+ zlog_err(
+ "%s: BFD session %pIA -> %pIA interface %s VRF %s(%u) was not %s",
+ __func__, &src, &dst,
+ bsp->args.ifnamelen ? bsp->args.ifname : "*",
+ vrf_id_to_name(bsp->args.vrf_id), bsp->args.vrf_id,
+ bsp->lastev == BSE_INSTALL ? "installed"
+ : "uninstalled");
}
return 0;
XFREE(MTYPE_BFD_INFO, (*bsp));
}
-void bfd_sess_enable(struct bfd_session_params *bsp, bool enable)
+static bool bfd_sess_address_changed(const struct bfd_session_params *bsp,
+ uint32_t family,
+ const struct in6_addr *src,
+ const struct in6_addr *dst)
{
- /* Remove the session when disabling. */
- if (!enable)
- _bfd_sess_remove(bsp);
+ size_t addrlen;
- bsp->enabled = enable;
+ if (bsp->args.family != family)
+ return true;
+
+ addrlen = (family == AF_INET) ? sizeof(struct in_addr)
+ : sizeof(struct in6_addr);
+ if ((src == NULL && memcmp(&bsp->args.src, &i6a_zero, addrlen))
+ || (src && memcmp(src, &bsp->args.src, addrlen))
+ || memcmp(dst, &bsp->args.dst, addrlen))
+ return true;
+
+ return false;
}
void bfd_sess_set_ipv4_addrs(struct bfd_session_params *bsp,
struct in_addr *src, struct in_addr *dst)
{
+ if (!bfd_sess_address_changed(bsp, AF_INET, (struct in6_addr *)src,
+ (struct in6_addr *)dst))
+ return;
+
/* If already installed, remove the old setting. */
_bfd_sess_remove(bsp);
void bfd_sess_set_ipv6_addrs(struct bfd_session_params *bsp,
struct in6_addr *src, struct in6_addr *dst)
{
+ if (!bfd_sess_address_changed(bsp, AF_INET, (struct in6_addr *)src,
+ (struct in6_addr *)dst))
+ return;
+
/* If already installed, remove the old setting. */
_bfd_sess_remove(bsp);
void bfd_sess_set_interface(struct bfd_session_params *bsp, const char *ifname)
{
+ if ((ifname == NULL && bsp->args.ifnamelen == 0)
+ || (ifname && strcmp(bsp->args.ifname, ifname) == 0))
+ return;
+
/* If already installed, remove the old setting. */
_bfd_sess_remove(bsp);
void bfd_sess_set_vrf(struct bfd_session_params *bsp, vrf_id_t vrf_id)
{
+ if (bsp->args.vrf_id == vrf_id)
+ return;
+
/* If already installed, remove the old setting. */
_bfd_sess_remove(bsp);
{
assert(min_ttl != 0);
+ if (bsp->args.ttl == ((BFD_SINGLE_HOP_TTL + 1) - min_ttl))
+ return;
+
/* If already installed, remove the old setting. */
_bfd_sess_remove(bsp);
void bfd_sess_set_hop_count(struct bfd_session_params *bsp, uint8_t min_ttl)
{
+ if (bsp->args.ttl == min_ttl)
+ return;
+
/* If already installed, remove the old setting. */
_bfd_sess_remove(bsp);
void bfd_sess_install(struct bfd_session_params *bsp)
{
- /* Don't attempt to install/update when disabled. */
- if (!bsp->enabled)
- return;
-
bsp->lastev = BSE_INSTALL;
thread_add_event(bsglobal.tm, _bfd_sess_send, bsp, 0, &bsp->installev);
}
/* Replay all activated peers. */
TAILQ_FOREACH (bsp, &bsglobal.bsplist, entry) {
- /* Skip disabled sessions. */
- if (!bsp->enabled)
+ /* Skip not installed sessions. */
+ if (!bsp->installed)
continue;
/* We are reconnecting, so we must send installation. */
static int zclient_bfd_session_update(ZAPI_CALLBACK_ARGS)
{
- struct bfd_session_params *bsp;
+ struct bfd_session_params *bsp, *bspn;
size_t sessions_updated = 0;
struct interface *ifp;
int remote_cbit = false;
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;
now = monotime(NULL);
/* Notify all matching sessions about update. */
- TAILQ_FOREACH (bsp, &bsglobal.bsplist, entry) {
- /* Skip disabled or not installed entries. */
- if (!bsp->enabled || !bsp->installed)
+ TAILQ_FOREACH_SAFE (bsp, &bsglobal.bsplist, entry, bspn) {
+ /* Skip not installed entries. */
+ if (!bsp->installed)
continue;
/* Skip different VRFs. */
if (bsp->args.vrf_id != vrf_id)
/**
* Allocates and initializes the session parameters.
*
- * \param updatedb status update notification callback.
+ * \param updatecb status update notification callback.
* \param args application independent data.
*
* \returns pointer to configuration storage.
*/
void bfd_sess_free(struct bfd_session_params **bsp);
-/**
- * Enable/disable session installation.
- *
- * \param bsp session parameters.
- * \param enable knob variable.
- */
-void bfd_sess_enable(struct bfd_session_params *bsp, bool enable);
-
/**
* Set the local and peer address of the BFD session.
*
+ * NOTE:
+ * If the address changed the session is removed and must be installed again
+ * with `bfd_sess_install`.
+ *
* \param bsp BFD session parameters.
* \param src local address (optional, can be `NULL`).
* \param dst remote address (mandatory).
/**
* Set the local and peer address of the BFD session.
*
+ * NOTE:
+ * If the address changed the session is removed and must be installed again
+ * with `bfd_sess_install`.
+ *
* \param bsp BFD session parameters.
* \param src local address (optional, can be `NULL`).
* \param dst remote address (mandatory).
/**
* Configure the BFD session interface.
*
+ * NOTE:
+ * If the interface changed the session is removed and must be installed again
+ * with `bfd_sess_install`.
+ *
* \param bsp BFD session parameters.
* \param ifname interface name (or `NULL` to remove it).
*/
/**
* Configure the BFD session profile name.
*
+ * NOTE:
+ * Session profile will only change after a `bfd_sess_install`.
+ *
* \param bsp BFD session parameters.
* \param profile profile name (or `NULL` to remove it).
*/
/**
* Configure the BFD session VRF.
*
+ * NOTE:
+ * If the VRF changed the session is removed and must be installed again
+ * with `bfd_sess_install`.
+ *
* \param bsp BFD session parameters.
* \param vrf_id the VRF identification number.
*/
/**
* Configure the BFD session single/multi hop setting.
*
+ * NOTE:
+ * If the TTL changed the session is removed and must be installed again
+ * with `bfd_sess_install`.
+ *
* \param bsp BFD session parameters.
* \param min_ttl minimum TTL value expected (255 for single hop, 254 for
* multi hop with single hop, 253 for multi hop with two hops
* Instead of receiving the minimum expected TTL, it receives the amount of
* hops the protocol will jump.
*
+ * NOTE:
+ * If the TTL changed the session is removed and must be installed again
+ * with `bfd_sess_install`.
+ *
* \param bsp BFD session parameters.
* \param min_ttl minimum amount of hops expected (1 for single hop, 2 or
* more for multi hop).
/**
* Configure the BFD session to set the Control Plane Independent bit.
*
+ * NOTE:
+ * Session CPI bit will only change after a `bfd_sess_install`.
+ *
* \param bsp BFD session parameters.
* \param enable BFD Control Plane Independent state.
*/
* Configures the BFD session timers to use. This is specially useful with
* `ptm-bfd` which does not support timers.
*
+ * NOTE:
+ * Session timers will only apply if the session has not been created yet.
+ * If the session is already installed you must uninstall and install again
+ * to take effect.
+ *
* \param bsp BFD session parameters.
* \param detection_multiplier the detection multiplier value.
* \param min_rx minimum required receive period.
/**
* Installs or updates the BFD session based on the saved session arguments.
*
+ * NOTE:
+ * This function has a delayed effect: it will only install/update after
+ * all northbound/CLI command batch finishes.
+ *
* \param bsp session parameters.
*/
void bfd_sess_install(struct bfd_session_params *bsp);
/**
* Uninstall the BFD session based on the saved session arguments.
*
+ * NOTE:
+ * This function uninstalls the session immediately (if installed) and cancels
+ * any previous `bfd_sess_install` calls.
+ *
* \param bsp session parameters.
*/
void bfd_sess_uninstall(struct bfd_session_params *bsp);
/* and now for the ugly part... provide simplified logging functions so we
* don't need to link libzebra (which would be a circular build dep) */
-#ifdef __ASSERT_FUNCTION
-#undef __ASSERT_FUNCTION
-#endif
-
#include "log.h"
-#include "zassert.h"
void vzlogx(const struct xref_logmsg *xref, int prio,
const char *format, va_list args)
fputs("\n", stderr);
}
-void _zlog_assert_failed(const char *assertion, const char *file,
- unsigned int line, const char *function)
-{
- fprintf(stderr,
- "Assertion `%s' failed in file %s, line %u, function %s",
- assertion, file, line, (function ? function : "?"));
- abort();
-}
-
void memory_oom(size_t size, const char *name)
{
abort();
/* Execute command by argument vline vector. */
static int cmd_execute_command_real(vector vline, enum cmd_filter_type filter,
struct vty *vty,
- const struct cmd_element **cmd)
+ const struct cmd_element **cmd,
+ unsigned int up_level)
{
struct list *argv_list;
enum matcher_rv status;
const struct cmd_element *matched_element = NULL;
+ unsigned int i;
+ int xpath_index = vty->xpath_index;
+ int node = vty->node;
- struct graph *cmdgraph = cmd_node_graph(cmdvec, vty->node);
+ /* only happens for legacy split config file load; need to check for
+ * a match before calling node_exit handlers below
+ */
+ for (i = 0; i < up_level; i++) {
+ if (node <= CONFIG_NODE)
+ return CMD_NO_LEVEL_UP;
+
+ node = node_parent(node);
+
+ if (xpath_index > 0
+ && vty_check_node_for_xpath_decrement(node, vty->node))
+ xpath_index--;
+ }
+
+ struct graph *cmdgraph = cmd_node_graph(cmdvec, node);
status = command_match(cmdgraph, vline, &argv_list, &matched_element);
if (cmd)
}
}
+ for (i = 0; i < up_level; i++)
+ cmd_exit(vty);
+
// build argv array from argv list
struct cmd_token **argv = XMALLOC(
MTYPE_TMP, argv_list->count * sizeof(struct cmd_token *));
struct listnode *ln;
struct cmd_token *token;
- unsigned int i = 0;
+
+ i = 0;
for (ALL_LIST_ELEMENTS_RO(argv_list, ln, token))
argv[i++] = token;
vector_lookup(vline, index));
ret = cmd_execute_command_real(shifted_vline, FILTER_RELAXED,
- vty, cmd);
+ vty, cmd, 0);
vector_free(shifted_vline);
vty->node = onode;
}
saved_ret = ret =
- cmd_execute_command_real(vline, FILTER_RELAXED, vty, cmd);
+ cmd_execute_command_real(vline, FILTER_RELAXED, vty, cmd, 0);
if (vtysh)
return saved_ret;
onode))
vty->xpath_index--;
ret = cmd_execute_command_real(vline, FILTER_RELAXED,
- vty, cmd);
+ vty, cmd, 0);
if (ret == CMD_SUCCESS || ret == CMD_WARNING
|| ret == CMD_NOT_MY_INSTANCE
|| ret == CMD_WARNING_CONFIG_FAILED)
int cmd_execute_command_strict(vector vline, struct vty *vty,
const struct cmd_element **cmd)
{
- return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd);
+ return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd, 0);
}
/*
{
vector vline;
int ret;
+ unsigned up_level = 0;
vline = cmd_make_strvec(vty->buf);
/* Execute configuration command : this is strict match */
ret = cmd_execute_command_strict(vline, vty, cmd);
- // Climb the tree and try the command again at each node
- if (!(use_daemon && ret == CMD_SUCCESS_DAEMON)
- && !(!use_daemon && ret == CMD_ERR_NOTHING_TODO)
- && ret != CMD_SUCCESS && ret != CMD_WARNING
- && ret != CMD_NOT_MY_INSTANCE && ret != CMD_WARNING_CONFIG_FAILED
- && vty->node != CONFIG_NODE) {
- int saved_node = vty->node;
- int saved_xpath_index = vty->xpath_index;
-
- while (!(use_daemon && ret == CMD_SUCCESS_DAEMON)
- && !(!use_daemon && ret == CMD_ERR_NOTHING_TODO)
- && ret != CMD_SUCCESS && ret != CMD_WARNING
- && vty->node > CONFIG_NODE) {
- vty->node = node_parent(vty->node);
- if (vty->xpath_index > 0
- && vty_check_node_for_xpath_decrement(vty->node,
- saved_node))
- vty->xpath_index--;
- ret = cmd_execute_command_strict(vline, vty, cmd);
- }
-
- // If climbing the tree did not work then ignore the command and
- // stay at the same node
- if (!(use_daemon && ret == CMD_SUCCESS_DAEMON)
- && !(!use_daemon && ret == CMD_ERR_NOTHING_TODO)
- && ret != CMD_SUCCESS && ret != CMD_WARNING) {
- vty->node = saved_node;
- vty->xpath_index = saved_xpath_index;
- }
- }
+ /* The logic for trying parent nodes is in cmd_execute_command_real()
+ * since calling ->node_exit() correctly is a bit involved. This is
+ * also the only reason CMD_NO_LEVEL_UP exists.
+ */
+ while (!(use_daemon && ret == CMD_SUCCESS_DAEMON)
+ && !(!use_daemon && ret == CMD_ERR_NOTHING_TODO)
+ && ret != CMD_SUCCESS && ret != CMD_WARNING
+ && ret != CMD_NOT_MY_INSTANCE && ret != CMD_WARNING_CONFIG_FAILED
+ && ret != CMD_NO_LEVEL_UP)
+ ret = cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd,
+ ++up_level);
+
+ if (ret == CMD_NO_LEVEL_UP)
+ ret = CMD_ERR_NO_MATCH;
if (ret != CMD_SUCCESS &&
ret != CMD_WARNING &&
PREFIX_IPV6_NODE, /* Prefix list node. */
AS_LIST_NODE, /* AS list node. */
COMMUNITY_LIST_NODE, /* Community list node. */
+ COMMUNITY_ALIAS_NODE, /* Community alias node. */
RMAP_NODE, /* Route map node. */
PBRMAP_NODE, /* PBR map node. */
SMUX_NODE, /* SNMP configuration node. */
#define CMD_SUSPEND 12
#define CMD_WARNING_CONFIG_FAILED 13
#define CMD_NOT_MY_INSTANCE 14
+#define CMD_NO_LEVEL_UP 15
/* Argc max counts. */
#define CMD_ARGC_MAX 256
#pragma GCC diagnostic ignored "-Wsign-compare"
#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-#include "command_parse.h"
+#include "lib/command_parse.h"
#define YY_USER_ACTION yylloc->last_column += yyleng;
#define LOC_STEP do { if (yylloc) { \
%code provides {
#ifndef FLEX_SCANNER
- #include "command_lex.h"
+ #include "lib/command_lex.h"
#endif
extern void set_lexer_string (yyscan_t *scn, const char *string);
#else /* !_FRR_ATTRIBUTE_PRINTFRR */
#define PRINTFRR(a, b) __attribute__((format(printf, a, b)))
+/* frr-format plugin is C-only for now, so no point in doing these shenanigans
+ * for C++... (also they can break some C++ stuff...)
+ */
+#ifndef __cplusplus
/* these should be typedefs, but might also be #define */
#ifdef uint64_t
#undef uint64_t
#define PRIu64 "llu"
#define PRId64 "lld"
#define PRIx64 "llx"
+
+#endif /* !__cplusplus */
#endif /* !_FRR_ATTRIBUTE_PRINTFRR */
#ifdef __cplusplus
#include <zebra.h>
#include "defaults.h"
-#include "version.h"
+#include "lib/version.h"
static char df_version[128] = FRR_VER_SHORT, df_profile[128] = DFLT_NAME;
static struct frr_default *dflt_first = NULL, **dflt_next = &dflt_first;
return 1;
}
-DEFUN (distribute_list,
- distribute_list_cmd,
- "distribute-list [prefix] WORD <in|out> [WORD]",
- "Filter networks in routing updates\n"
- "Specify a prefix\n"
- "Access-list name\n"
- "Filter incoming routing updates\n"
- "Filter outgoing routing updates\n"
- "Interface name\n")
+static enum distribute_type distribute_direction(const char *dir, bool v4)
{
- int prefix = (argv[1]->type == WORD_TKN) ? 1 : 0;
- /* Check of distribute list type. */
- enum distribute_type type = argv[2 + prefix]->arg[0] == 'i'
- ? DISTRIBUTE_V4_IN
- : DISTRIBUTE_V4_OUT;
-
- /* Set appropriate function call */
- void (*distfn)(struct distribute_ctx *, const char *,
- enum distribute_type, const char *) =
- prefix ? &distribute_list_prefix_set : &distribute_list_set;
- struct distribute_ctx *ctx =
- (struct distribute_ctx *)listnode_head(dist_ctx_list);
-
- /* if interface is present, get name */
- const char *ifname = NULL;
- if (argv[argc - 1]->type == VARIABLE_TKN)
- ifname = argv[argc - 1]->arg;
+ if (dir[0] == 'i') {
+ if (v4)
+ return DISTRIBUTE_V4_IN;
+ else
+ return DISTRIBUTE_V6_IN;
+ } else if (dir[0] == 'o') {
+ if (v4)
+ return DISTRIBUTE_V4_OUT;
+ else
+ return DISTRIBUTE_V6_OUT;
+ }
- /* Get interface name corresponding distribute list. */
- distfn(ctx, ifname, type, argv[1 + prefix]->arg);
+ assert(!"Expecting in or out only, fix your code");
- return CMD_SUCCESS;
+ __builtin_unreachable();
}
-DEFUN (ipv6_distribute_list,
- ipv6_distribute_list_cmd,
- "ipv6 distribute-list [prefix] WORD <in|out> [WORD]",
- "IPv6\n"
- "Filter networks in routing updates\n"
- "Specify a prefix\n"
- "Access-list name\n"
- "Filter incoming routing updates\n"
- "Filter outgoing routing updates\n"
- "Interface name\n")
+int distribute_list_parser(bool prefix, bool v4, const char *dir,
+ const char *list, const char *ifname)
{
- int prefix = (argv[2]->type == WORD_TKN) ? 1 : 0;
- /* Check of distribute list type. */
- enum distribute_type type = argv[3 + prefix]->arg[0] == 'i'
- ? DISTRIBUTE_V6_IN
- : DISTRIBUTE_V6_OUT;
+ enum distribute_type type = distribute_direction(dir, v4);
+ struct distribute_ctx *ctx = listnode_head(dist_ctx_list);
- /* Set appropriate function call */
void (*distfn)(struct distribute_ctx *, const char *,
enum distribute_type, const char *) =
prefix ? &distribute_list_prefix_set : &distribute_list_set;
- struct distribute_ctx *ctx = listnode_head(dist_ctx_list);
- /* if interface is present, get name */
- const char *ifname = NULL;
- if (argv[argc - 1]->type == VARIABLE_TKN)
- ifname = argv[argc - 1]->arg;
-
- /* Get interface name corresponding distribute list. */
- distfn(ctx, ifname, type, argv[2 + prefix]->arg);
+ distfn(ctx, ifname, type, list);
return CMD_SUCCESS;
}
-DEFUN (no_distribute_list,
- no_distribute_list_cmd,
- "no distribute-list [prefix] WORD <in|out> [WORD]",
- NO_STR
- "Filter networks in routing updates\n"
- "Specify a prefix\n"
- "Access-list name\n"
- "Filter incoming routing updates\n"
- "Filter outgoing routing updates\n"
- "Interface name\n")
+int distribute_list_no_parser(struct vty *vty, bool prefix, bool v4,
+ const char *dir, const char *list,
+ const char *ifname)
{
- int prefix = (argv[2]->type == WORD_TKN) ? 1 : 0;
- int idx_alname = 2 + prefix;
- int idx_disttype = idx_alname + 1;
- enum distribute_type type =
- argv[idx_disttype]->arg[0] == 'i' ?
- DISTRIBUTE_V4_IN : DISTRIBUTE_V4_OUT;
-
- /* Set appropriate function call */
- int (*distfn)(struct distribute_ctx *, const char *,
- enum distribute_type, const char *) =
- prefix ? &distribute_list_prefix_unset : &distribute_list_unset;
+ enum distribute_type type = distribute_direction(dir, v4);
struct distribute_ctx *ctx = listnode_head(dist_ctx_list);
+ int ret;
- /* if interface is present, get name */
- const char *ifname = NULL;
- if (argv[argc - 1]->type == VARIABLE_TKN)
- ifname = argv[argc - 1]->arg;
- /* Get interface name corresponding distribute list. */
- int ret = distfn(ctx, ifname, type, argv[2 + prefix]->arg);
-
- if (!ret) {
- vty_out(vty, "distribute list doesn't exist\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- return CMD_SUCCESS;
-}
-
-DEFUN (no_ipv6_distribute_list,
- no_ipv6_distribute_list_cmd,
- "no ipv6 distribute-list [prefix] WORD <in|out> [WORD]",
- NO_STR
- "IPv6\n"
- "Filter networks in routing updates\n"
- "Specify a prefix\n"
- "Access-list name\n"
- "Filter incoming routing updates\n"
- "Filter outgoing routing updates\n"
- "Interface name\n")
-{
- int prefix = (argv[3]->type == WORD_TKN) ? 1 : 0;
- int idx_alname = 3 + prefix;
- int idx_disttype = idx_alname + 1;
-
- enum distribute_type type =
- argv[idx_disttype]->arg[0] == 'i' ?
- DISTRIBUTE_V6_IN : DISTRIBUTE_V6_OUT;
- struct distribute_ctx *ctx = listnode_head(dist_ctx_list);
-
- /* Set appropriate function call */
int (*distfn)(struct distribute_ctx *, const char *,
- enum distribute_type, const char *) =
+ enum distribute_type, const char *) =
prefix ? &distribute_list_prefix_unset : &distribute_list_unset;
- /* if interface is present, get name */
- const char *ifname = NULL;
-
- if (argv[argc - 1]->type == VARIABLE_TKN)
- ifname = argv[argc - 1]->arg;
- /* Get interface name corresponding distribute list. */
- int ret = distfn(ctx, ifname, type, argv[3 + prefix]->arg);
+ ret = distfn(ctx, ifname, type, list);
if (!ret) {
vty_out(vty, "distribute list doesn't exist\n");
return CMD_WARNING_CONFIG_FAILED;
}
+
return CMD_SUCCESS;
}
listnode_add(dist_ctx_list, ctx);
return ctx;
}
-
-/* Initialize distribute list vty commands */
-void distribute_list_init(int node)
-{
- /* vtysh command-extraction doesn't grok install_element(node, ) */
- if (node == RIP_NODE) {
- install_element(RIP_NODE, &distribute_list_cmd);
- install_element(RIP_NODE, &no_distribute_list_cmd);
- } else if (node == RIPNG_NODE) {
- install_element(RIPNG_NODE, &distribute_list_cmd);
- install_element(RIPNG_NODE, &no_distribute_list_cmd);
- /* install v6 */
- install_element(RIPNG_NODE, &ipv6_distribute_list_cmd);
- install_element(RIPNG_NODE, &no_ipv6_distribute_list_cmd);
- }
-
- /* TODO: install v4 syntax command for v6 only protocols. */
- /* if (node == RIPNG_NODE) {
- * install_element (node, &ipv6_as_v4_distribute_list_all_cmd);
- * install_element (node, &no_ipv6_as_v4_distribute_list_all_cmd);
- * install_element (node, &ipv6_as_v4_distribute_list_cmd);
- * install_element (node, &no_ipv6_as_v4_distribute_list_cmd);
- * install_element (node, &ipv6_as_v4_distribute_list_prefix_all_cmd);
- * install_element (node,
- &no_ipv6_as_v4_distribute_list_prefix_all_cmd);
- * install_element (node, &ipv6_as_v4_distribute_list_prefix_cmd);
- * install_element (node, &no_ipv6_as_v4_distribute_list_prefix_cmd);
- }*/
-}
};
/* Prototypes for distribute-list. */
-extern void distribute_list_init(int node);
extern struct distribute_ctx *distribute_list_ctx_create(struct vrf *vrf);
extern void distribute_list_delete(struct distribute_ctx **ctx);
extern void distribute_list_add_hook(struct distribute_ctx *ctx,
extern enum filter_type distribute_apply_out(struct interface *,
struct prefix *);
+extern int distribute_list_parser(bool prefix, bool v4, const char *dir,
+ const char *list, const char *ifname);
+extern int distribute_list_no_parser(struct vty *vty, bool prefix, bool v4,
+ const char *dir, const char *list,
+ const char *ifname);
#ifdef __cplusplus
}
#endif
/* Static structure for mac access_list's master. */
static struct access_master access_master_mac = {
- {NULL, NULL},
{NULL, NULL},
NULL,
NULL,
/* Static structure for IPv4 access_list's master. */
static struct access_master access_master_ipv4 = {
- {NULL, NULL},
{NULL, NULL},
NULL,
NULL,
/* Static structure for IPv6 access_list's master. */
static struct access_master access_master_ipv6 = {
- {NULL, NULL},
{NULL, NULL},
NULL,
NULL,
master = access->master;
- if (access->type == ACCESS_TYPE_NUMBER)
- list = &master->num;
- else
- list = &master->str;
+ list = &master->str;
if (access->next)
access->next->prev = access->prev;
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);
is sorted by the name. */
static struct access_list *access_list_insert(afi_t afi, const char *name)
{
- unsigned int i;
- long number;
struct access_list *access;
struct access_list *point;
struct access_list_list *alist;
access->name = XSTRDUP(MTYPE_ACCESS_LIST_STR, name);
access->master = master;
- /* If name is made by all digit character. We treat it as
- number. */
- for (number = 0, i = 0; i < strlen(name); i++) {
- if (isdigit((unsigned char)name[i]))
- number = (number * 10) + (name[i] - '0');
- else
- break;
- }
+ /* Set access_list to string list. */
+ alist = &master->str;
- /* In case of name is all digit character */
- if (i == strlen(name)) {
- access->type = ACCESS_TYPE_NUMBER;
-
- /* Set access_list to number list. */
- alist = &master->num;
-
- for (point = alist->head; point; point = point->next)
- if (atol(point->name) >= number)
- break;
- } else {
- access->type = ACCESS_TYPE_STRING;
-
- /* Set access_list to string list. */
- alist = &master->str;
-
- /* Set point to insertion point. */
- for (point = alist->head; point; point = point->next)
- if (strcmp(point->name, name) >= 0)
- break;
- }
+ /* Set point to insertion point. */
+ for (point = alist->head; point; point = point->next)
+ if (strcmp(point->name, name) >= 0)
+ break;
/* In case of this is the first element of master. */
if (alist->head == NULL) {
if (master == NULL)
return NULL;
- for (access = master->num.head; access; access = access->next)
- if (strcmp(access->name, name) == 0)
- return access;
-
for (access = master->str.head; access; access = access->next)
if (strcmp(access->name, name) == 0)
return access;
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 *);
/* Print the name of the protocol */
vty_out(vty, "%s:\n", frr_protoname);
- for (access = master->num.head; access; access = access->next) {
- if (name && strcmp(access->name, name) != 0)
- continue;
-
- write = 1;
-
- for (mfilter = access->head; mfilter; mfilter = mfilter->next) {
- filter = &mfilter->u.cfilter;
-
- if (write) {
- vty_out(vty, "%s %s access list %s\n",
- mfilter->cisco ? (filter->extended
- ? "Extended"
- : "Standard")
- : "Zebra",
- (afi == AFI_IP)
- ? ("IP")
- : ((afi == AFI_IP6) ? ("IPv6 ")
- : ("MAC ")),
- access->name);
- write = 0;
- }
-
- vty_out(vty, " seq %" PRId64, mfilter->seq);
- vty_out(vty, " %s%s", filter_type_str(mfilter),
- mfilter->type == FILTER_DENY ? " " : "");
-
- if (!mfilter->cisco)
- config_write_access_zebra(vty, mfilter);
- else if (filter->extended)
- config_write_access_cisco(vty, mfilter);
- else {
- if (filter->addr_mask.s_addr == 0xffffffff)
- vty_out(vty, " any\n");
- else {
- vty_out(vty, " %pI4", &filter->addr);
- if (filter->addr_mask.s_addr
- != INADDR_ANY)
- vty_out(vty,
- ", wildcard bits %pI4",
- &filter->addr_mask);
- vty_out(vty, "\n");
- }
- }
- }
- }
-
for (access = master->str.head; access; access = access->next) {
if (name && strcmp(access->name, name) != 0)
continue;
if (master == NULL)
return;
- for (access = master->num.head; access; access = next) {
- next = access->next;
- access_list_delete(access);
- }
for (access = master->str.head; access; access = next) {
next = access->next;
access_list_delete(access);
}
- assert(master->num.head == NULL);
- assert(master->num.tail == NULL);
-
assert(master->str.head == NULL);
assert(master->str.tail == NULL);
}
if (master == NULL)
return;
- for (access = master->num.head; access; access = next) {
- next = access->next;
- access_list_delete(access);
- }
for (access = master->str.head; access; access = next) {
next = access->next;
access_list_delete(access);
}
- assert(master->num.head == NULL);
- assert(master->num.tail == NULL);
-
assert(master->str.head == NULL);
assert(master->str.tail == NULL);
}
if (master == NULL)
return;
- for (access = master->num.head; access; access = next) {
- next = access->next;
- access_list_delete(access);
- }
for (access = master->str.head; access; access = next) {
next = access->next;
access_list_delete(access);
}
- assert(master->num.head == NULL);
- assert(master->num.tail == NULL);
-
assert(master->str.head == NULL);
assert(master->str.tail == NULL);
}
/* Filter type is made by `permit', `deny' and `dynamic'. */
enum filter_type { FILTER_DENY, FILTER_PERMIT, FILTER_DYNAMIC };
-enum access_type { ACCESS_TYPE_STRING, ACCESS_TYPE_NUMBER };
-
struct filter_cisco {
/* Cisco access-list */
int extended;
struct access_master *master;
- enum access_type type;
-
struct access_list *next;
struct access_list *prev;
/* Master structure of access_list. */
struct access_master {
- /* List of access_list which name is number. */
- struct access_list_list num;
-
/* List of access_list which name is string. */
struct access_list_list str;
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);
nb_cli_enqueue_change(vty, "./ipv4-prefix", NB_OP_MODIFY,
prefix_str);
- if (ge_str)
+ if (ge_str) {
nb_cli_enqueue_change(
vty, "./ipv4-prefix-length-greater-or-equal",
NB_OP_MODIFY, ge_str);
- if (le_str)
+ } else {
+ /*
+ * Remove old ge if not being modified
+ */
+ nb_cli_enqueue_change(
+ vty, "./ipv4-prefix-length-greater-or-equal",
+ NB_OP_DESTROY, NULL);
+ }
+
+ if (le_str) {
nb_cli_enqueue_change(
vty, "./ipv4-prefix-length-lesser-or-equal",
NB_OP_MODIFY, le_str);
+ } else {
+ /*
+ * Remove old le if not being modified
+ */
+ nb_cli_enqueue_change(
+ vty, "./ipv4-prefix-length-lesser-or-equal",
+ NB_OP_DESTROY, NULL);
+ }
} else {
nb_cli_enqueue_change(vty, "./any", NB_OP_CREATE, 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(
nb_cli_enqueue_change(vty, "./ipv6-prefix", NB_OP_MODIFY,
prefix_str);
- if (ge_str)
+ if (ge_str) {
nb_cli_enqueue_change(
vty, "./ipv6-prefix-length-greater-or-equal",
NB_OP_MODIFY, ge_str);
- if (le_str)
+ } else {
+ /*
+ * Remove old ge if not being modified
+ */
+ nb_cli_enqueue_change(
+ vty, "./ipv6-prefix-length-greater-or-equal",
+ NB_OP_DESTROY, NULL);
+ }
+
+ if (le_str) {
nb_cli_enqueue_change(
vty, "./ipv6-prefix-length-lesser-or-equal",
NB_OP_MODIFY, le_str);
+ } else {
+ /*
+ * Remove old le if not being modified
+ */
+ nb_cli_enqueue_change(
+ vty, "./ipv6-prefix-length-lesser-or-equal",
+ NB_OP_DESTROY, NULL);
+ }
} else {
nb_cli_enqueue_change(vty, "./any", NB_OP_CREATE, NULL);
}
"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;
#include "memory.h"
#include "linklist.h"
#include "zlog.h"
+#include "libfrr.h"
#include "libfrr_trace.h"
DEFINE_MTYPE_STATIC(LIB, FRR_PTHREAD, "FRR POSIX Thread");
int ret;
sigset_t oldsigs, blocksigs;
+ assert(frr_is_after_fork || !"trying to start thread before fork()");
+
/* Ensure we never handle signals on a background thread by blocking
* everything here (new thread inherits signal mask)
*/
.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,
#include "privs.h"
#include "vty.h"
#include "command.h"
-#include "version.h"
+#include "lib/version.h"
#include "lib_vty.h"
#include "log_vty.h"
#include "zclient.h"
#include "frrscript.h"
DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm));
-DEFINE_HOOK(frr_very_late_init, (struct thread_master * tm), (tm));
+DEFINE_HOOK(frr_config_pre, (struct thread_master * tm), (tm));
+DEFINE_HOOK(frr_config_post, (struct thread_master * tm), (tm));
DEFINE_KOOH(frr_early_fini, (), ());
DEFINE_KOOH(frr_fini, (), ());
#endif
static char vtypath_default[512];
+/* cleared in frr_preinit(), then re-set after daemonizing */
+bool frr_is_after_fork = true;
bool debug_memstats_at_exit = false;
static bool nodetach_term, nodetach_daemon;
static uint64_t startup_fds;
void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv)
{
di = daemon;
+ frr_is_after_fork = false;
/* basename(), opencoded. */
char *p = strrchr(argv[0], '/');
*/
static int frr_config_read_in(struct thread *t)
{
+ hook_call(frr_config_pre, master);
+
if (!vty_read_config(vty_shared_candidate_config, di->config_file,
config_default)
&& di->backup_config_file) {
__func__, nb_err_name(ret), errmsg);
}
- hook_call(frr_very_late_init, master);
+ hook_call(frr_config_post, master);
return 0;
}
if (di->daemon_mode || di->terminal)
frr_daemonize();
+ frr_is_after_fork = true;
+
if (!di->pid_file)
di->pid_file = pidfile_default;
pid_output(di->pid_file);
extern uint32_t frr_get_fd_limit(void);
extern bool frr_is_startup_fd(int fd);
+/* call order of these hooks is as ordered here */
DECLARE_HOOK(frr_late_init, (struct thread_master * tm), (tm));
-DECLARE_HOOK(frr_very_late_init, (struct thread_master * tm), (tm));
+/* fork() happens between late_init and config_pre */
+DECLARE_HOOK(frr_config_pre, (struct thread_master * tm), (tm));
+DECLARE_HOOK(frr_config_post, (struct thread_master * tm), (tm));
+
extern void frr_config_fork(void);
extern void frr_run(struct thread_master *master);
extern char frr_protoname[];
extern char frr_protonameinst[];
+/* always set in the spot where we *would* fork even if we don't do so */
+extern bool frr_is_after_fork;
extern bool debug_memstats_at_exit;
#define TRACEPOINT_CREATE_PROBES
#define TRACEPOINT_DEFINE
+#include <zebra.h>
+
#include "libfrr_trace.h"
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <zebra.h>
+
#include "if.h"
#include "linklist.h"
#include "log.h"
list->count = 0;
}
-void list_filter_out_nodes(struct list *list, bool (*cond)(void *data))
-{
- struct listnode *node;
- struct listnode *next;
- void *data;
-
- assert(list);
-
- for (ALL_LIST_ELEMENTS(list, node, next, data)) {
- if ((cond && cond(data)) || (!cond)) {
- if (*list->del)
- (*list->del)(data);
- list_delete_node(list, node);
- }
- }
-}
-
void list_delete(struct list **list)
{
assert(*list);
*/
extern void list_delete_node(struct list *list, struct listnode *node);
-/*
- * Delete all nodes which satisfy a condition from a list.
- * Deletes the node if cond function returns true for the node.
- * If function ptr passed is NULL, it deletes all nodes
- *
- * list
- * list to operate on
- * cond
- * function pointer which takes node data as input and return true or false
- */
-
-extern void list_filter_out_nodes(struct list *list, bool (*cond)(void *data));
-
/*
* Insert a new element into a list with insertion sort if there is no
* duplicate element present in the list. This assumes the input list is
zlog(log_level, "Current thread not known/applicable");
}
-void _zlog_assert_failed(const char *assertion, const char *file,
- unsigned int line, const char *function)
-{
- zlog(LOG_CRIT, "Assertion `%s' failed in file %s, line %u, function %s",
- assertion, file, line, (function ? function : "?"));
- zlog_backtrace(LOG_CRIT);
- zlog_thread_info(LOG_CRIT);
- log_memstats(stderr, "log");
- abort();
-}
-
void memory_oom(size_t size, const char *name)
{
zlog(LOG_CRIT,
DESC_ENTRY(ZEBRA_NHRP_NEIGH_UNREGISTER),
DESC_ENTRY(ZEBRA_NEIGH_IP_ADD),
DESC_ENTRY(ZEBRA_NEIGH_IP_DEL),
- DESC_ENTRY(ZEBRA_CONFIGURE_ARP)};
+ DESC_ENTRY(ZEBRA_CONFIGURE_ARP),
+ DESC_ENTRY(ZEBRA_GRE_GET),
+ DESC_ENTRY(ZEBRA_GRE_UPDATE),
+ DESC_ENTRY(ZEBRA_GRE_SOURCE_SET)};
#undef DESC_ENTRY
static const struct zebra_desc_table unknown = {0, "unknown", '?'};
#ifndef _ZEBRA_LOG_H
#define _ZEBRA_LOG_H
-#include "zassert.h"
-
#include <syslog.h>
#include <stdint.h>
#include <stdbool.h>
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);
return CMD_SUCCESS;
}
+/* Enable/disable 'immediate' mode, with no output buffering */
+DEFPY (log_immediate_mode,
+ log_immediate_mode_cmd,
+ "[no] log immediate-mode",
+ NO_STR
+ "Logging control"
+ "Output immediately, without buffering")
+{
+ zlog_set_immediate(!no);
+ return CMD_SUCCESS;
+}
+
void log_config_write(struct vty *vty)
{
bool show_cmdline_hint = false;
install_element(CONFIG_NODE, &log_filter_clear_cmd);
install_element(CONFIG_NODE, &config_log_filterfile_cmd);
install_element(CONFIG_NODE, &no_config_log_filterfile_cmd);
+ install_element(CONFIG_NODE, &log_immediate_mode_cmd);
}
#include "module.h"
#include "memory.h"
-#include "version.h"
+#include "lib/version.h"
DEFINE_MTYPE_STATIC(LIB, MODULE_LOADNAME, "Module loading name");
DEFINE_MTYPE_STATIC(LIB, MODULE_LOADARGS, "Module loading arguments");
if (nhl1->num_labels < nhl2->num_labels)
return -1;
- return memcmp(nhl1->label, nhl2->label, nhl1->num_labels);
+ return memcmp(nhl1->label, nhl2->label,
+ (nhl1->num_labels * sizeof(mpls_label_t)));
}
int nexthop_g_addr_cmp(enum nexthop_types_t type, const union g_addr *addr1,
return ret;
}
+/*
+ * More-limited comparison function used to detect duplicate
+ * nexthops. This is used in places where we don't need the full
+ * comparison of 'nexthop_cmp()'.
+ */
+int nexthop_cmp_basic(const struct nexthop *nh1,
+ const struct nexthop *nh2)
+{
+ int ret = 0;
+ const struct mpls_label_stack *nhl1 = NULL;
+ const struct mpls_label_stack *nhl2 = NULL;
+
+ if (nh1 == NULL && nh2 == NULL)
+ return 0;
+
+ if (nh1 && !nh2)
+ return 1;
+
+ if (!nh1 && nh2)
+ return -1;
+
+ if (nh1->vrf_id < nh2->vrf_id)
+ return -1;
+
+ if (nh1->vrf_id > nh2->vrf_id)
+ return 1;
+
+ if (nh1->type < nh2->type)
+ return -1;
+
+ if (nh1->type > nh2->type)
+ return 1;
+
+ if (nh1->weight < nh2->weight)
+ return -1;
+
+ if (nh1->weight > nh2->weight)
+ return 1;
+
+ switch (nh1->type) {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV6:
+ ret = nexthop_g_addr_cmp(nh1->type, &nh1->gate, &nh2->gate);
+ if (ret != 0)
+ return ret;
+ break;
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ ret = nexthop_g_addr_cmp(nh1->type, &nh1->gate, &nh2->gate);
+ if (ret != 0)
+ return ret;
+ /* Intentional Fall-Through */
+ case NEXTHOP_TYPE_IFINDEX:
+ if (nh1->ifindex < nh2->ifindex)
+ return -1;
+
+ if (nh1->ifindex > nh2->ifindex)
+ return 1;
+ break;
+ case NEXTHOP_TYPE_BLACKHOLE:
+ if (nh1->bh_type < nh2->bh_type)
+ return -1;
+
+ if (nh1->bh_type > nh2->bh_type)
+ return 1;
+ break;
+ }
+
+ /* Compare source addr */
+ ret = nexthop_g_addr_cmp(nh1->type, &nh1->src, &nh2->src);
+ if (ret != 0)
+ goto done;
+
+ nhl1 = nh1->nh_label;
+ nhl2 = nh2->nh_label;
+
+ /* No labels is a match */
+ if (!nhl1 && !nhl2)
+ return 0;
+
+ if (nhl1 && !nhl2)
+ return 1;
+
+ if (nhl2 && !nhl1)
+ return -1;
+
+ if (nhl1->num_labels > nhl2->num_labels)
+ return 1;
+
+ if (nhl1->num_labels < nhl2->num_labels)
+ return -1;
+
+ ret = memcmp(nhl1->label, nhl2->label,
+ (nhl1->num_labels * sizeof(mpls_label_t)));
+
+done:
+ return ret;
+}
+
/*
* nexthop_type_to_str
*/
const union g_addr *addr1,
const union g_addr *addr2);
+/* More-limited comparison function used to detect duplicate nexthops.
+ * Returns -1, 0, 1
+ */
+int nexthop_cmp_basic(const struct nexthop *nh1, const struct nexthop *nh2);
+
extern const char *nexthop_type_to_str(enum nexthop_types_t nh_type);
extern bool nexthop_labels_match(const struct nexthop *nh1,
const struct nexthop *nh2);
#include <zebra.h>
#include "libfrr.h"
-#include "version.h"
+#include "lib/version.h"
#include "defaults.h"
#include "log.h"
#include "lib_errors.h"
#include "command.h"
#include "debug.h"
#include "libfrr.h"
-#include "version.h"
+#include "lib/version.h"
#include "northbound.h"
#include <confd_lib.h>
#include "log.h"
#include "libfrr.h"
-#include "version.h"
+#include "lib/version.h"
#include "command.h"
#include "lib_errors.h"
#include "northbound.h"
#include "debug.h"
#include "memory.h"
#include "libfrr.h"
-#include "version.h"
+#include "lib/version.h"
#include "northbound.h"
#include <sysrepo.h>
return 0;
}
-static int frr_sr_module_very_late_init(struct thread_master *tm)
+static int frr_sr_module_config_loaded(struct thread_master *tm)
{
master = tm;
static int frr_sr_module_init(void)
{
hook_register(frr_late_init, frr_sr_module_late_init);
- hook_register(frr_very_late_init, frr_sr_module_very_late_init);
+ hook_register(frr_config_post, frr_sr_module_config_loaded);
return 0;
}
#include <zebra.h>
#include <fcntl.h>
#include <log.h>
-#include "version.h"
+#include "lib/version.h"
#include "network.h"
#include "lib_errors.h"
/* Master structure of prefix_list. */
struct prefix_master {
- /* List of prefix_list which name is number. */
- struct prefix_list_list num;
-
/* 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, 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, 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, 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, PLC_MAXLEVELV6,
};
static struct prefix_master *prefix_master_get(afi_t afi, int orf)
if (master == NULL)
return NULL;
- for (plist = master->num.head; plist; plist = plist->next)
- if (strcmp(plist->name, name) == 0)
- return plist;
-
for (plist = master->str.head; plist; plist = plist->next)
if (strcmp(plist->name, name) == 0)
return plist;
static struct prefix_list *prefix_list_insert(afi_t afi, int orf,
const char *name)
{
- unsigned int i;
- long number;
struct prefix_list *plist;
struct prefix_list *point;
struct prefix_list_list *list;
plist->trie =
XCALLOC(MTYPE_PREFIX_LIST_TRIE, sizeof(struct pltrie_table));
- /* If name is made by all digit character. We treat it as
- number. */
- for (number = 0, i = 0; i < strlen(name); i++) {
- if (isdigit((unsigned char)name[i]))
- number = (number * 10) + (name[i] - '0');
- else
- break;
- }
-
- /* In case of name is all digit character */
- if (i == strlen(name)) {
- plist->type = PREFIX_TYPE_NUMBER;
+ /* Set prefix_list to string list. */
+ list = &master->str;
- /* Set prefix_list to number list. */
- list = &master->num;
-
- for (point = list->head; point; point = point->next)
- if (atol(point->name) >= number)
- break;
- } else {
- plist->type = PREFIX_TYPE_STRING;
-
- /* Set prefix_list to string list. */
- list = &master->str;
-
- /* Set point to insertion point. */
- for (point = list->head; point; point = point->next)
- if (strcmp(point->name, name) >= 0)
- break;
- }
+ /* Set point to insertion point. */
+ for (point = list->head; point; point = point->next)
+ if (strcmp(point->name, name) >= 0)
+ break;
/* In case of this is the first element of master. */
if (list->head == NULL) {
master = plist->master;
- if (plist->type == PREFIX_TYPE_NUMBER)
- list = &master->num;
- else
- list = &master->str;
+ list = &master->str;
if (plist->next)
plist->next->prev = plist->prev;
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));
master->recent->name);
}
- for (plist = master->num.head; plist; plist = plist->next)
- vty_show_prefix_entry(vty, afi, plist, master, dtype,
- seqnum);
-
for (plist = master->str.head; plist; plist = plist->next)
vty_show_prefix_entry(vty, afi, plist, master, dtype,
seqnum);
return CMD_WARNING;
if (name == NULL && prefix == NULL) {
- for (plist = master->num.head; plist; plist = plist->next)
- for (pentry = plist->head; pentry;
- pentry = pentry->next)
- pentry->hitcnt = 0;
-
for (plist = master->str.head; plist; plist = plist->next)
for (pentry = plist->head; pentry;
pentry = pentry->next)
#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]]",
if (master == NULL)
return;
- for (plist = master->num.head; plist; plist = next) {
- next = plist->next;
- prefix_list_delete(plist);
- }
for (plist = master->str.head; plist; plist = next) {
next = plist->next;
prefix_list_delete(plist);
}
- assert(master->num.head == NULL);
- assert(master->num.tail == NULL);
-
assert(master->str.head == NULL);
assert(master->str.tail == NULL);
- master->seqnum = true;
master->recent = NULL;
}
for (plist = master->str.head; plist; plist = plist->next)
vector_set(comps, XSTRDUP(MTYPE_COMPLETION, plist->name));
- for (plist = master->num.head; plist; plist = plist->next)
- vector_set(comps, XSTRDUP(MTYPE_COMPLETION, plist->name));
}
static void plist_autocomplete(vector comps, struct cmd_token *token)
{
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);
extern "C" {
#endif
-enum prefix_name_type { PREFIX_TYPE_STRING, PREFIX_TYPE_NUMBER };
-
struct pltrie_table;
struct prefix_list {
struct prefix_master *master;
- enum prefix_name_type type;
-
int count;
int rangecount;
#define FMT_NSTD(expr) \
({ \
- typeof(expr) _v; \
FMT_NSTD_BEGIN \
+ typeof(expr) _v; \
_v = expr; \
FMT_NSTD_END \
_v; \
memset(buf->data, 0x00, buf->size);
ringbuf_reset(buf);
}
-
-ssize_t ringbuf_read(struct ringbuf *buf, int sock)
-{
- size_t to_read = ringbuf_space(buf);
- size_t bytes_to_end = buf->size - buf->end;
- ssize_t bytes_read;
- struct iovec iov[2] = {};
-
- /* Calculate amount of read blocks. */
- if (to_read > bytes_to_end) {
- iov[0].iov_base = buf->data + buf->end;
- iov[0].iov_len = bytes_to_end;
- iov[1].iov_base = buf->data;
- iov[1].iov_len = to_read - bytes_to_end;
- } else {
- iov[0].iov_base = buf->data + buf->end;
- iov[0].iov_len = to_read;
- }
-
- /* Do the system call. */
- bytes_read = readv(sock, iov, 2);
- if (bytes_read <= 0)
- return bytes_read;
-
- /* Calculate the new end. */
- if ((size_t)bytes_read > bytes_to_end)
- buf->end = bytes_read - bytes_to_end;
- else
- buf->end += bytes_read;
-
- /* Set emptiness state. */
- buf->empty = (buf->start == buf->end) && (buf->empty && !bytes_read);
-
- return bytes_read;
-}
*/
void ringbuf_wipe(struct ringbuf *buf);
-/**
- * Perform a socket/file `read()` in to the ring buffer.
- *
- * \param buf the ring buffer pointer.
- * \param sock the file descriptor.
- * \returns the number of bytes read, `0` on connection close or `-1` with
- * `errno` pointing the error (see `readv()` man page for more
- * information.)
- */
-ssize_t ringbuf_read(struct ringbuf *buf, int sock);
-
#ifdef __cplusplus
}
#endif
static int lib_route_map_entry_action_modify(struct nb_cb_modify_args *args)
{
struct route_map_index *rmi;
+ struct route_map *map;
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_APPLY:
rmi = nb_running_get_entry(args->dnode, NULL, true);
rmi->type = yang_dnode_get_enum(args->dnode, NULL);
- /* TODO: notify? */
+ map = rmi->map;
+
+ /* Execute event hook. */
+ if (route_map_master.event_hook) {
+ (*route_map_master.event_hook)(map->name);
+ route_map_notify_dependencies(map->name,
+ RMAP_EVENT_CALL_ADDED);
+ }
+
break;
}
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <zebra.h>
+
#include "northbound.h"
#include "libfrr.h"
#include "routing_nb.h"
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <zebra.h>
+
#include "northbound.h"
#include "libfrr.h"
#include "vrf.h"
return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8)
+ ((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24));
}
-#else
-#include <sys/endian.h>
#endif
#if !HAVE_DECL_BE32ENC
p[1] = (x >> 16) & 0xff;
p[0] = (x >> 24) & 0xff;
}
-#else
-#include <sys/endian.h>
#endif
/*
/* 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)
#include "sockunion.h"
#include "lib_errors.h"
+#if (defined(__FreeBSD__) \
+ && ((__FreeBSD_version >= 500022 && __FreeBSD_version < 700000) \
+ || (__FreeBSD_version < 500000 && __FreeBSD_version >= 440000))) \
+ || (defined(__NetBSD__) && defined(__NetBSD_Version__) \
+ && __NetBSD_Version__ >= 106010000) \
+ || defined(__OpenBSD__) || defined(__APPLE__) \
+ || defined(__DragonFly__) || defined(__sun)
+#define HAVE_BSD_STRUCT_IP_MREQ_HACK
+#endif
+
void setsockopt_so_recvbuf(int sock, int size)
{
int orig_req = size;
{
return sockopt_tcp_signature_ext(sock, su, 0, password);
}
+
+/* set TCP mss value to socket */
+int sockopt_tcp_mss_set(int sock, int tcp_maxseg)
+{
+ int ret = 0;
+ socklen_t tcp_maxseg_len = sizeof(tcp_maxseg);
+
+ ret = setsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, &tcp_maxseg,
+ tcp_maxseg_len);
+ if (ret != 0) {
+ flog_err_sys(EC_LIB_SYSTEM_CALL,
+ "%s failed: setsockopt(%d): %s", __func__, sock,
+ safe_strerror(errno));
+ }
+
+ return ret;
+}
+
+/* get TCP mss value synced by socket */
+int sockopt_tcp_mss_get(int sock)
+{
+ int ret = 0;
+ int tcp_maxseg = 0;
+ socklen_t tcp_maxseg_len = sizeof(tcp_maxseg);
+
+ ret = getsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, &tcp_maxseg,
+ &tcp_maxseg_len);
+ if (ret != 0) {
+ flog_err_sys(EC_LIB_SYSTEM_CALL,
+ "%s failed: getsockopt(%d): %s", __func__, sock,
+ safe_strerror(errno));
+ return 0;
+ }
+
+ return tcp_maxseg;
+}
extern int sockopt_tcp_signature_ext(int sock, union sockunion *su,
uint16_t prefixlen, const char *password);
+/*
+ * set TCP max segment size. This option allows user to configure
+ * max segment size for TCP session
+ *
+ * sock
+ * Socket to enable option on.
+ *
+ * tcp_maxseg
+ * value used for TCP segment size negotiation during SYN
+ */
+extern int sockopt_tcp_mss_set(int sock, int tcp_maxseg);
+
+/*
+ * get TCP max segment size. This option allows user to get
+ * the segment size for TCP session
+ *
+ * sock
+ * Socket to get max segement size.
+ */
+extern int sockopt_tcp_mss_get(int sock);
#ifdef __cplusplus
}
#endif
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
lib/yang.h \
lib/yang_translator.h \
lib/yang_wrappers.h \
- lib/zassert.h \
lib/zclient.h \
lib/zebra.h \
lib/zlog.h \
lib/zlog_targets.h \
lib/pbr.h \
lib/routing_nb.h \
+ \
+ lib/assert/assert.h \
# end
lib_LTLIBRARIES += lib/libfrrsnmp.la
endif
-lib_libfrrsnmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11
+lib_libfrrsnmp_la_CFLAGS = $(AM_CFLAGS) $(SNMP_CFLAGS) -std=gnu11
lib_libfrrsnmp_la_LDFLAGS = -version-info 0:0:0
lib_libfrrsnmp_la_LIBADD = $(SNMP_LIBS)
lib_libfrrsnmp_la_SOURCES = \
pkginclude_HEADERS += lib/resolver.h
endif
-lib_libfrrcares_la_CFLAGS = $(WERROR) $(CARES_CFLAGS)
+lib_libfrrcares_la_CFLAGS = $(AM_CFLAGS) $(CARES_CFLAGS)
lib_libfrrcares_la_LDFLAGS = -version-info 0:0:0
lib_libfrrcares_la_LIBADD = $(CARES_LIBS)
lib_libfrrcares_la_SOURCES = \
pkginclude_HEADERS += lib/frr_zmq.h
endif
-lib_libfrrzmq_la_CFLAGS = $(WERROR) $(ZEROMQ_CFLAGS)
+lib_libfrrzmq_la_CFLAGS = $(AM_CFLAGS) $(ZEROMQ_CFLAGS)
lib_libfrrzmq_la_LDFLAGS = -version-info 0:0:0
lib_libfrrzmq_la_LIBADD = $(ZEROMQ_LIBS)
lib_libfrrzmq_la_SOURCES = \
module_LTLIBRARIES += lib/confd.la
endif
-lib_confd_la_CFLAGS = $(WERROR) $(CONFD_CFLAGS)
+lib_confd_la_CFLAGS = $(AM_CFLAGS) $(CONFD_CFLAGS)
lib_confd_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
lib_confd_la_LIBADD = lib/libfrr.la $(CONFD_LIBS)
lib_confd_la_SOURCES = lib/northbound_confd.c
module_LTLIBRARIES += lib/sysrepo.la
endif
-lib_sysrepo_la_CFLAGS = $(WERROR) $(SYSREPO_CFLAGS)
+lib_sysrepo_la_CFLAGS = $(AM_CFLAGS) $(SYSREPO_CFLAGS)
lib_sysrepo_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
lib_sysrepo_la_LIBADD = lib/libfrr.la $(SYSREPO_LIBS)
lib_sysrepo_la_SOURCES = lib/northbound_sysrepo.c
lib_grammar_sandbox_LDADD = \
lib/libfrr.la
-lib_clippy_CPPFLAGS = $(AM_CPPFLAGS) -D_GNU_SOURCE -DBUILDING_CLIPPY
-lib_clippy_CFLAGS = $(PYTHON_CFLAGS)
+lib_clippy_CPPFLAGS = $(CPPFLAGS_BASE) -D_GNU_SOURCE -DBUILDING_CLIPPY
+lib_clippy_CFLAGS = $(AC_CFLAGS) $(PYTHON_CFLAGS)
lib_clippy_LDADD = $(PYTHON_LIBS) $(UST_LIBS) -lelf
lib_clippy_LDFLAGS = -export-dynamic
lib_clippy_SOURCES = \
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;
long mm;
int wr;
- zassert(buf_size >= 8);
+ assert(buf_size >= 8);
hh = sec / 3600;
sec %= 3600;
xref->funcname, xref->xref.file, xref->xref.line,
t_ptr, fd, 0, arg, 0);
- assert(fd >= 0 && fd < m->fd_limit);
+ assert(fd >= 0);
+ if (fd >= m->fd_limit)
+ assert(!"Number of FD's open is greater than FRR currently configured to handle, aborting");
+
frr_with_mutex(&m->mtx) {
if (t_ptr && *t_ptr)
// thread is already scheduled; don't reschedule
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 {
typed_rb_remove(&h->rr, re); \
return container_of(re, type, field.re); \
} \
+TYPESAFE_SWAP_ALL_SIMPLE(prefix) \
macro_pure const type *prefix ## _const_first(const struct prefix##_head *h) \
{ \
const struct typed_rb_entry *re; \
} \
/* ... */
+/* SWAP_ALL_SIMPLE = for containers where the items don't point back to the
+ * head *AND* the head doesn'T points to itself (= everything except LIST,
+ * DLIST and SKIPLIST), just switch out the entire head
+ */
+#define TYPESAFE_SWAP_ALL_SIMPLE(prefix) \
+macro_inline void prefix ## _swap_all(struct prefix##_head *a, \
+ struct prefix##_head *b) \
+{ \
+ struct prefix##_head tmp = *a; \
+ *a = *b; \
+ *b = tmp; \
+} \
+/* ... */
/* single-linked list, unsorted/arbitrary.
* can be used as queue with add_tail / pop
h->sh.last_next = &h->sh.first; \
return container_of(sitem, type, field.si); \
} \
+macro_inline void prefix ## _swap_all(struct prefix##_head *a, \
+ struct prefix##_head *b) \
+{ \
+ struct prefix##_head tmp = *a; \
+ *a = *b; \
+ *b = tmp; \
+ if (a->sh.last_next == &b->sh.first) \
+ a->sh.last_next = &a->sh.first; \
+ if (b->sh.last_next == &a->sh.first) \
+ b->sh.last_next = &b->sh.first; \
+} \
macro_pure const type *prefix ## _const_first(const struct prefix##_head *h) \
{ \
return container_of_null(h->sh.first, type, field.si); \
head->count++;
}
+static inline void typesafe_dlist_swap_all(struct dlist_head *a,
+ struct dlist_head *b)
+{
+ struct dlist_head tmp = *a;
+
+ a->count = b->count;
+ if (a->count) {
+ a->hitem.next = b->hitem.next;
+ a->hitem.prev = b->hitem.prev;
+ a->hitem.next->prev = &a->hitem;
+ a->hitem.prev->next = &a->hitem;
+ } else {
+ a->hitem.next = &a->hitem;
+ a->hitem.prev = &a->hitem;
+ }
+
+ b->count = tmp.count;
+ if (b->count) {
+ b->hitem.next = tmp.hitem.next;
+ b->hitem.prev = tmp.hitem.prev;
+ b->hitem.next->prev = &b->hitem;
+ b->hitem.prev->next = &b->hitem;
+ } else {
+ b->hitem.next = &b->hitem;
+ b->hitem.prev = &b->hitem;
+ }
+}
+
/* double-linked list, for fast item deletion
*/
#define PREDECL_DLIST(prefix) \
h->dh.count--; \
return container_of(ditem, type, field.di); \
} \
+macro_inline void prefix ## _swap_all(struct prefix##_head *a, \
+ struct prefix##_head *b) \
+{ \
+ typesafe_dlist_swap_all(&a->dh, &b->dh); \
+} \
macro_pure const type *prefix ## _const_first(const struct prefix##_head *h) \
{ \
const struct dlist_item *ditem = h->dh.hitem.next; \
typesafe_heap_resize(&h->hh, false); \
return container_of(hitem, type, field.hi); \
} \
+TYPESAFE_SWAP_ALL_SIMPLE(prefix) \
macro_pure const type *prefix ## _const_first(const struct prefix##_head *h) \
{ \
if (h->hh.count == 0) \
h->sh.first = sitem->next; \
return container_of(sitem, type, field.si); \
} \
+TYPESAFE_SWAP_ALL_SIMPLE(prefix) \
macro_pure const type *prefix ## _const_first(const struct prefix##_head *h) \
{ \
return container_of_null(h->sh.first, type, field.si); \
} \
return NULL; \
} \
+TYPESAFE_SWAP_ALL_SIMPLE(prefix) \
macro_pure const type *prefix ## _const_first(const struct prefix##_head *h) \
{ \
uint32_t i; \
struct sskip_item *sitem = typesafe_skiplist_pop(&h->sh); \
return container_of_null(sitem, type, field.si); \
} \
+macro_inline void prefix ## _swap_all(struct prefix##_head *a, \
+ struct prefix##_head *b) \
+{ \
+ struct prefix##_head tmp = *a; \
+ *a = *b; \
+ *b = tmp; \
+ a->sh.hitem.next[SKIPLIST_OVERFLOW] = (struct sskip_item *) \
+ ((uintptr_t)a->sh.overflow | 1); \
+ b->sh.hitem.next[SKIPLIST_OVERFLOW] = (struct sskip_item *) \
+ ((uintptr_t)b->sh.overflow | 1); \
+} \
macro_pure const type *prefix ## _const_first(const struct prefix##_head *h) \
{ \
const struct sskip_item *first = h->sh.hitem.next[0]; \
#define _ZEBRA_VERSION_H
#ifdef GIT_VERSION
-#include "gitversion.h"
+#include "lib/gitversion.h"
#endif
#ifdef __cplusplus
#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 */
XREFT_THREADSCHED = 0x100,
XREFT_LOGMSG = 0x200,
+ XREFT_ASSERT = 0x280,
XREFT_DEFUN = 0x300,
XREFT_INSTALL_ELEMENT = 0x301,
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 */
+++ /dev/null
-/*
- * This file is part of Quagga.
- *
- * Quagga is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * Quagga is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef _QUAGGA_ASSERT_H
-#define _QUAGGA_ASSERT_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern void _zlog_assert_failed(const char *assertion, const char *file,
- unsigned int line, const char *function)
- __attribute__((noreturn));
-
-#undef __ASSERT_FUNCTION
-#define __ASSERT_FUNCTION __func__
-
-#define zassert(EX) \
- ((void)((EX) ? 0 : (_zlog_assert_failed(#EX, __FILE__, __LINE__, \
- __ASSERT_FUNCTION), \
- 0)))
-
-#undef assert
-#define assert(EX) zassert(EX)
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _QUAGGA_ASSERT_H */
enum zclient_send_status
zclient_send_interface_radv_req(struct zclient *zclient, vrf_id_t vrf_id,
struct interface *ifp, int enable,
- int ra_interval)
+ uint32_t ra_interval)
{
struct stream *s;
(*zclient->neighbor_get)(command, zclient, length,
vrf_id);
break;
+ case ZEBRA_GRE_UPDATE:
+ if (zclient->gre_update)
+ (*zclient->gre_update)(command, zclient,
+ length, vrf_id);
+ break;
default:
break;
}
stream_failure:
return -1;
}
+
+int zclient_send_zebra_gre_request(struct zclient *client,
+ struct interface *ifp)
+{
+ struct stream *s;
+
+ if (!client || client->sock < 0) {
+ zlog_err("%s : zclient not ready", __func__);
+ return -1;
+ }
+ s = client->obuf;
+ stream_reset(s);
+ zclient_create_header(s,
+ ZEBRA_GRE_GET,
+ ifp->vrf_id);
+ stream_putl(s, ifp->ifindex);
+ stream_putw_at(s, 0, stream_get_endp(s));
+ zclient_send_message(client);
+ return 0;
+}
ZEBRA_NEIGH_IP_ADD,
ZEBRA_NEIGH_IP_DEL,
ZEBRA_CONFIGURE_ARP,
+ ZEBRA_GRE_GET,
+ ZEBRA_GRE_UPDATE,
+ ZEBRA_GRE_SOURCE_SET,
} zebra_message_types_t;
enum zebra_error_types {
void (*neighbor_added)(ZAPI_CALLBACK_ARGS);
void (*neighbor_removed)(ZAPI_CALLBACK_ARGS);
void (*neighbor_get)(ZAPI_CALLBACK_ARGS);
+ void (*gre_update)(ZAPI_CALLBACK_ARGS);
};
/* Zebra API message flag. */
ZCLIENT_SEND_BUFFERED = 1
};
+static inline const char *
+zapi_nhg_notify_owner2str(enum zapi_nhg_notify_owner note)
+{
+ const char *ret = "UNKNOWN";
+
+ switch (note) {
+ case ZAPI_NHG_FAIL_INSTALL:
+ ret = "ZAPI_NHG_FAIL_INSTALL";
+ break;
+ case ZAPI_NHG_INSTALLED:
+ ret = "ZAPI_NHG_INSTALLED";
+ break;
+ case ZAPI_NHG_REMOVE_FAIL:
+ ret = "ZAPI_NHG_REMOVE_FAIL";
+ break;
+ case ZAPI_NHG_REMOVED:
+ ret = "ZAPI_NHG_REMOVED";
+ break;
+ }
+
+ return ret;
+}
+
static inline const char *
zapi_rule_notify_owner2str(enum zapi_rule_notify_owner note)
{
extern enum zclient_send_status
zclient_send_interface_radv_req(struct zclient *zclient, vrf_id_t vrf_id,
struct interface *ifp, int enable,
- int ra_interval);
+ uint32_t ra_interval);
extern enum zclient_send_status
zclient_send_interface_protodown(struct zclient *zclient, vrf_id_t vrf_id,
struct interface *ifp, bool down);
extern int zapi_client_close_notify_decode(struct stream *s,
struct zapi_client_close_info *info);
+extern int zclient_send_zebra_gre_request(struct zclient *client,
+ struct interface *ifp);
#ifdef __cplusplus
}
#endif
#include <limits.h>
#include <inttypes.h>
#include <stdbool.h>
+#ifdef HAVE_SYS_ENDIAN_H
+#include <sys/endian.h>
+#endif
+#ifdef HAVE_ENDIAN_H
+#include <endian.h>
+#endif
/* machine dependent includes */
#ifdef HAVE_LINUX_VERSION_H
#define __attribute__(x)
#endif /* !__GNUC__ || VTYSH_EXTRACT_PL */
-#include "zassert.h"
+#include <assert.h>
/*
* Add explicit static cast only when using a C++ compiler.
#define HAVE_IP_HDRINCL_BSD_ORDER
#endif
-/* Define BYTE_ORDER, if not defined. Useful for compiler conditional
- * code, rather than preprocessor conditional.
- * Not all the world has this BSD define.
- */
+/* autoconf macros for this are deprecated, just find endian.h */
#ifndef BYTE_ORDER
-#define BIG_ENDIAN 4321 /* least-significant byte first (vax, pc) */
-#define LITTLE_ENDIAN 1234 /* most-significant byte first (IBM, net) */
-#define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long (pdp) */
-
-#if defined(WORDS_BIGENDIAN)
-#define BYTE_ORDER BIG_ENDIAN
-#else /* !WORDS_BIGENDIAN */
-#define BYTE_ORDER LITTLE_ENDIAN
-#endif /* WORDS_BIGENDIAN */
-
-#endif /* ndef BYTE_ORDER */
+#error please locate an endian.h file appropriate to your platform
+#endif
/* For old definition. */
#ifndef IN6_ARE_ADDR_EQUAL
#include "compiler.h"
/* Zebra route's types are defined in route_types.h */
-#include "route_types.h"
+#include "lib/route_types.h"
#define strmatch(a,b) (!strcmp((a), (b)))
DECLARE_ATOMLIST(zlog_targets, struct zlog_target, head);
static struct zlog_targets_head zlog_targets;
+/* Global setting for buffered vs immediate output. The default is
+ * per-pthread buffering.
+ */
+static bool default_immediate;
+
/* cf. zlog.h for additional comments on this struct.
*
* Note: you MUST NOT pass the format string + va_list to non-FRR format
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);
}
struct zlog_msg *msg;
char *buf;
bool ignoremsg = true;
- bool immediate = false;
+ bool immediate = default_immediate;
/* avoid further processing cost if no target wants this message */
rcu_read_lock();
}
}
+void _zlog_assert_failed(const struct xref_assert *xref, const char *extra, ...)
+{
+ va_list ap;
+ static bool assert_in_assert; /* "global-ish" variable, init to 0 */
+
+ if (assert_in_assert)
+ abort();
+ assert_in_assert = true;
+
+ if (extra) {
+ struct va_format vaf;
+
+ va_start(ap, extra);
+ vaf.fmt = extra;
+ vaf.va = ≈
+
+ zlog(LOG_CRIT,
+ "%s:%d: %s(): assertion (%s) failed, extra info: %pVA",
+ xref->xref.file, xref->xref.line, xref->xref.func,
+ xref->expr, &vaf);
+
+ va_end(ap);
+ } else
+ zlog(LOG_CRIT, "%s:%d: %s(): assertion (%s) failed",
+ xref->xref.file, xref->xref.line, xref->xref.func,
+ xref->expr);
+
+ /* abort() prints backtrace & memstats in SIGABRT handler */
+ abort();
+}
int zlog_msg_prio(struct zlog_msg *msg)
{
return oldzt;
}
+/*
+ * Enable or disable 'immediate' output - default is to buffer
+ * each pthread's messages.
+ */
+void zlog_set_immediate(bool set_p)
+{
+ default_immediate = set_p;
+}
/* common init */
#include <unistd.h>
#include <sys/uio.h>
+#include <assert.h>
+
#include "atomlist.h"
#include "frrcu.h"
#include "memory.h"
extern void zlog_tls_buffer_flush(void);
extern void zlog_tls_buffer_fini(void);
+/* Enable or disable 'immediate' output - default is to buffer messages. */
+extern void zlog_set_immediate(bool set_p);
+
#ifdef __cplusplus
}
#endif
struct zlog_msg *msg = msgs[i];
int prio = zlog_msg_prio(msg);
- if (prio > zt->prio_min)
- continue;
-
- iov[iovpos].iov_base = ts_pos;
- if (iovpos > 0)
- *ts_pos++ = '\n';
- ts_pos += zlog_msg_ts(msg, ts_pos, sizeof(ts_buf) - 1
- - (ts_pos - ts_buf),
- ZLOG_TS_LEGACY | zte->ts_subsec);
- *ts_pos++ = ' ';
- iov[iovpos].iov_len = ts_pos - (char *)iov[iovpos].iov_base;
+ if (prio <= zt->prio_min) {
+ iov[iovpos].iov_base = ts_pos;
+ if (iovpos > 0)
+ *ts_pos++ = '\n';
+ ts_pos += zlog_msg_ts(msg, ts_pos,
+ sizeof(ts_buf) - 1
+ - (ts_pos - ts_buf),
+ ZLOG_TS_LEGACY | zte->ts_subsec);
+ *ts_pos++ = ' ';
+ iov[iovpos].iov_len =
+ ts_pos - (char *)iov[iovpos].iov_base;
- iovpos++;
+ iovpos++;
- if (zte->record_priority) {
- iov[iovpos].iov_base = (char *)prionames[prio];
- iov[iovpos].iov_len = strlen(iov[iovpos].iov_base);
+ if (zte->record_priority) {
+ iov[iovpos].iov_base = (char *)prionames[prio];
+ iov[iovpos].iov_len =
+ strlen(iov[iovpos].iov_base);
- iovpos++;
- }
+ iovpos++;
+ }
- iov[iovpos].iov_base = zlog_prefix;
- iov[iovpos].iov_len = zlog_prefixsz;
+ iov[iovpos].iov_base = zlog_prefix;
+ iov[iovpos].iov_len = zlog_prefixsz;
- iovpos++;
+ iovpos++;
- iov[iovpos].iov_base = (char *)zlog_msg_text(msg, &textlen);
- iov[iovpos].iov_len = textlen;
+ iov[iovpos].iov_base =
+ (char *)zlog_msg_text(msg, &textlen);
+ iov[iovpos].iov_len = textlen;
- iovpos++;
+ iovpos++;
+ }
- if (ts_buf + sizeof(ts_buf) - ts_pos < TS_LEN
- || i + 1 == nmsgs
- || array_size(iov) - iovpos < 5) {
+ /* conditions that trigger writing:
+ * - out of space for more timestamps/headers
+ * - this being the last message in the batch
+ * - not enough remaining iov entries
+ */
+ if (iovpos > 0 && (ts_buf + sizeof(ts_buf) - ts_pos < TS_LEN
+ || i + 1 == nmsgs
+ || array_size(iov) - iovpos < 5)) {
iov[iovpos].iov_base = (char *)"\n";
iov[iovpos].iov_len = 1;
!ax_sys_weak_alias.m4
!ax_sys_weak_alias.m4
!pkg.m4
+
+/ac
])
AS_IF([test "x$ac_cv_header_lua_h" = 'xyes'],
- [ dnl Make a program to print LUA_VERSION defined in the header.
- dnl TODO It would be really nice if we could do this without compiling a
- dnl program, then it would work when cross compiling. But I'm not sure how
- dnl to do this reliably. For now, assume versions match when cross compiling.
-
- AS_IF([test "x$cross_compiling" != 'xyes'],
- [ AC_CACHE_CHECK([for Lua header version],
- [ax_cv_lua_header_version],
- [ _ax_lua_saved_cppflags=$CPPFLAGS
- CPPFLAGS="$CPPFLAGS $LUA_INCLUDE"
- AC_RUN_IFELSE(
- [ AC_LANG_SOURCE([[
-#include <lua.h>
-#include <stdlib.h>
-#include <stdio.h>
-int main(int argc, char ** argv)
-{
- if(argc > 1) printf("%s", LUA_VERSION);
- exit(EXIT_SUCCESS);
-}
-]])
- ],
- [ ax_cv_lua_header_version=`./conftest$EXEEXT p | \
+ [ AC_CACHE_CHECK([for Lua header version],
+ [ax_cv_lua_header_version],
+ [
+ ax_cv_lua_header_version=`echo LUA_VERSION | \
+ $CC -P -E $LUA_INCLUDE -imacros lua.h - | \
+ $SED -e 's%"\s*"%%g' -e 's%^\s*%%' | \
+ tr -d '"\n' | \
$SED -n "s|^Lua \(@<:@0-9@:>@\{1,\}\.@<:@0-9@:>@\{1,\}\).\{0,\}|\1|p"`
- ],
- [ax_cv_lua_header_version='unknown'])
- CPPFLAGS=$_ax_lua_saved_cppflags
- ])
-
- dnl Compare this to the previously found LUA_VERSION.
- AC_MSG_CHECKING([if Lua header version matches $LUA_VERSION])
- AS_IF([test "x$ax_cv_lua_header_version" = "x$LUA_VERSION"],
- [ AC_MSG_RESULT([yes])
- ax_header_version_match='yes'
- ],
- [ AC_MSG_RESULT([no])
- ax_header_version_match='no'
- ])
- ],
- [ AC_MSG_WARN([cross compiling so assuming header version number matches])
+ ])
+
+ dnl Compare this to the previously found LUA_VERSION.
+ AC_MSG_CHECKING([if Lua header version matches $LUA_VERSION])
+ AS_IF([test "x$ax_cv_lua_header_version" = "x$LUA_VERSION"],
+ [ AC_MSG_RESULT([yes])
ax_header_version_match='yes'
+ ],
+ [ AC_MSG_RESULT([no])
+ ax_header_version_match='no'
])
])
* (at your option) any later version.
*/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <fcntl.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <asm/types.h>
-#include <arpa/inet.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-#include <linux/ip.h>
-#include <linux/if_arp.h>
-#include <linux/if_tunnel.h>
-#include <linux/limits.h>
+#include <errno.h>
+#include "zebra.h"
+#include <linux/if_packet.h>
#include "nhrp_protocol.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_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;
* (at your option) any later version.
*/
-#include <stdint.h>
+#include <zebra.h>
+#include <vrf.h>
+#include <if.h>
-union sockunion;
-struct interface;
extern int netlink_nflog_group;
-extern int netlink_req_fd;
+extern int netlink_mcast_nflog_group;
-void netlink_init(void);
int netlink_configure_arp(unsigned int ifindex, int pf);
void netlink_update_binding(struct interface *ifp, union sockunion *proto,
union sockunion *nbma);
void netlink_set_nflog_group(int nlgroup);
-void netlink_gre_get_info(unsigned int ifindex, uint32_t *gre_key,
- unsigned int *link_index, struct in_addr *saddr);
-void netlink_gre_set_link(unsigned int ifindex, unsigned int link_index);
#include "netlink.h"
#include "znl.h"
-int netlink_req_fd = -1;
int netlink_nflog_group;
static int netlink_log_fd = -1;
static struct thread *netlink_log_thread;
nhrp_cache_set_used(c, state == ZEBRA_NEIGH_STATE_REACHABLE);
}
}
-
-void netlink_init(void)
-{
- netlink_req_fd = znl_open(NETLINK_ROUTE, 0);
- if (netlink_req_fd < 0)
- return;
-}
+++ /dev/null
-/* NHRP netlink/GRE tunnel configuration code
- * Copyright (c) 2014-2016 Timo Teräs
- *
- * 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 <sys/socket.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-#include <linux/in.h>
-#include <linux/if.h>
-#include <linux/ip.h>
-#include <linux/ipv6.h>
-#include <linux/if_tunnel.h>
-
-#include "debug.h"
-#include "netlink.h"
-#include "znl.h"
-
-static int __netlink_gre_get_data(struct zbuf *zb, struct zbuf *data,
- int ifindex)
-{
- struct nlmsghdr *n;
- struct ifinfomsg *ifi;
- struct zbuf payload, rtapayload;
- struct rtattr *rta;
-
- debugf(NHRP_DEBUG_KERNEL, "netlink-link-gre: get-info %u", ifindex);
-
- n = znl_nlmsg_push(zb, RTM_GETLINK, NLM_F_REQUEST);
- ifi = znl_push(zb, sizeof(*ifi));
- *ifi = (struct ifinfomsg){
- .ifi_index = ifindex,
- };
- znl_nlmsg_complete(zb, n);
-
- if (zbuf_send(zb, netlink_req_fd) < 0
- || zbuf_recv(zb, netlink_req_fd) < 0)
- return -1;
-
- n = znl_nlmsg_pull(zb, &payload);
- if (!n)
- return -1;
-
- if (n->nlmsg_type != RTM_NEWLINK)
- return -1;
-
- ifi = znl_pull(&payload, sizeof(struct ifinfomsg));
- if (!ifi)
- return -1;
-
- debugf(NHRP_DEBUG_KERNEL,
- "netlink-link-gre: ifindex %u, receive msg_type %u, msg_flags %u",
- ifi->ifi_index, n->nlmsg_type, n->nlmsg_flags);
-
- if (ifi->ifi_index != ifindex)
- return -1;
-
- while ((rta = znl_rta_pull(&payload, &rtapayload)) != NULL)
- if (rta->rta_type == IFLA_LINKINFO)
- break;
- if (!rta)
- return -1;
-
- payload = rtapayload;
- while ((rta = znl_rta_pull(&payload, &rtapayload)) != NULL)
- if (rta->rta_type == IFLA_INFO_DATA)
- break;
- if (!rta)
- return -1;
-
- *data = rtapayload;
- return 0;
-}
-
-void netlink_gre_get_info(unsigned int ifindex, uint32_t *gre_key,
- unsigned int *link_index, struct in_addr *saddr)
-{
- struct zbuf *zb = zbuf_alloc(8192), data, rtapl;
- struct rtattr *rta;
-
- *link_index = 0;
- *gre_key = 0;
- saddr->s_addr = 0;
-
- if (__netlink_gre_get_data(zb, &data, ifindex) < 0)
- goto err;
-
- while ((rta = znl_rta_pull(&data, &rtapl)) != NULL) {
- switch (rta->rta_type) {
- case IFLA_GRE_LINK:
- *link_index = zbuf_get32(&rtapl);
- break;
- case IFLA_GRE_IKEY:
- case IFLA_GRE_OKEY:
- *gre_key = zbuf_get32(&rtapl);
- break;
- case IFLA_GRE_LOCAL:
- saddr->s_addr = zbuf_get32(&rtapl);
- break;
- }
- }
-err:
- zbuf_free(zb);
-}
-
-void netlink_gre_set_link(unsigned int ifindex, unsigned int link_index)
-{
- struct nlmsghdr *n;
- struct ifinfomsg *ifi;
- struct rtattr *rta_info, *rta_data, *rta;
- struct zbuf *zr = zbuf_alloc(8192), data, rtapl;
- struct zbuf *zb = zbuf_alloc(8192);
- size_t len;
-
- if (__netlink_gre_get_data(zr, &data, ifindex) < 0)
- goto err;
-
- n = znl_nlmsg_push(zb, RTM_NEWLINK, NLM_F_REQUEST);
- ifi = znl_push(zb, sizeof(*ifi));
- *ifi = (struct ifinfomsg){
- .ifi_index = ifindex,
- };
- rta_info = znl_rta_nested_push(zb, IFLA_LINKINFO);
- znl_rta_push(zb, IFLA_INFO_KIND, "gre", 3);
- rta_data = znl_rta_nested_push(zb, IFLA_INFO_DATA);
-
- znl_rta_push_u32(zb, IFLA_GRE_LINK, link_index);
- while ((rta = znl_rta_pull(&data, &rtapl)) != NULL) {
- if (rta->rta_type == IFLA_GRE_LINK)
- continue;
- len = zbuf_used(&rtapl);
- znl_rta_push(zb, rta->rta_type, zbuf_pulln(&rtapl, len), len);
- }
-
- znl_rta_nested_complete(zb, rta_data);
- znl_rta_nested_complete(zb, rta_info);
-
- znl_nlmsg_complete(zb, n);
- zbuf_send(zb, netlink_req_fd);
- zbuf_recv(zb, netlink_req_fd);
-err:
- zbuf_free(zb);
- zbuf_free(zr);
-}
debugf(NHRP_DEBUG_COMMON, "Deleting cache entry");
nhrp_cache_counts[c->cur.type]--;
notifier_call(&c->notifier_list, NOTIFY_CACHE_DELETE);
- zassert(!notifier_active(&c->notifier_list));
+ assert(!notifier_active(&c->notifier_list));
hash_release(nifp->cache_hash, c);
THREAD_OFF(c->t_timeout);
THREAD_OFF(c->t_auth);
#include "nhrpd.h"
#include "os.h"
-#include "netlink.h"
+#include "hash.h"
DEFINE_MTYPE_STATIC(NHRPD, NHRP_IF, "NHRP interface");
+DEFINE_MTYPE_STATIC(NHRPD, NHRP_IF_GRE, "NHRP GRE interface");
+
+struct hash *nhrp_gre_list;
static void nhrp_interface_update_cache_config(struct interface *ifp,
bool available,
uint8_t family);
+static unsigned int nhrp_gre_info_key(const void *data)
+{
+ const struct nhrp_gre_info *r = data;
+
+ return r->ifindex;
+}
+
+static bool nhrp_gre_info_cmp(const void *data, const void *key)
+{
+ const struct nhrp_gre_info *a = data, *b = key;
+
+ if (a->ifindex == b->ifindex)
+ return true;
+ return false;
+}
+
+static void *nhrp_interface_gre_alloc(void *data)
+{
+ struct nhrp_gre_info *a;
+ struct nhrp_gre_info *b = data;
+
+ a = XMALLOC(MTYPE_NHRP_IF_GRE, sizeof(struct nhrp_gre_info));
+ memcpy(a, b, sizeof(struct nhrp_gre_info));
+ return a;
+}
+
+struct nhrp_gre_info *nhrp_gre_info_alloc(struct nhrp_gre_info *p)
+{
+ struct nhrp_gre_info *a;
+
+ a = (struct nhrp_gre_info *)hash_get(nhrp_gre_list, p,
+ nhrp_interface_gre_alloc);
+ return a;
+}
+
static int nhrp_if_new_hook(struct interface *ifp)
{
struct nhrp_interface *nifp;
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)
{
hook_register_prio(if_add, 0, nhrp_if_new_hook);
hook_register_prio(if_del, 0, nhrp_if_delete_hook);
+
+ nhrp_gre_list = hash_create(nhrp_gre_info_key, nhrp_gre_info_cmp,
+ "NHRP GRE list Hash");
}
void nhrp_interface_update_mtu(struct interface *ifp, afi_t afi)
{
struct nhrp_interface *nifp = ifp->info;
- if (!nifp->source || !nifp->nbmaifp
- || (ifindex_t)nifp->linkidx == nifp->nbmaifp->ifindex)
+ if (!nifp->source || !nifp->nbmaifp ||
+ ((ifindex_t)nifp->link_idx == nifp->nbmaifp->ifindex &&
+ (nifp->link_vrf_id == nifp->nbmaifp->vrf_id)))
return;
- nifp->linkidx = nifp->nbmaifp->ifindex;
- debugf(NHRP_DEBUG_IF, "%s: bound device index changed to %d", ifp->name,
- nifp->linkidx);
- netlink_gre_set_link(ifp->ifindex, nifp->linkidx);
+ nifp->link_idx = nifp->nbmaifp->ifindex;
+ nifp->link_vrf_id = nifp->nbmaifp->vrf_id;
+ debugf(NHRP_DEBUG_IF, "%s: bound device index changed to %d, vr %u",
+ ifp->name, nifp->link_idx, nifp->link_vrf_id);
+ nhrp_send_zebra_gre_source_set(ifp, nifp->link_idx, nifp->link_vrf_id);
}
static void nhrp_interface_interface_notifier(struct notifier_block *n,
}
}
-static void nhrp_interface_update_nbma(struct interface *ifp)
+void nhrp_interface_update_nbma(struct interface *ifp,
+ struct nhrp_gre_info *gre_info)
{
struct nhrp_interface *nifp = ifp->info, *nbmanifp = NULL;
struct interface *nbmaifp = NULL;
sockunion_family(&nbma) = AF_UNSPEC;
if (nifp->source)
- nbmaifp = if_lookup_by_name(nifp->source, VRF_DEFAULT);
+ nbmaifp = if_lookup_by_name(nifp->source, nifp->link_vrf_id);
switch (ifp->ll_type) {
case ZEBRA_LLT_IPGRE: {
struct in_addr saddr = {0};
- netlink_gre_get_info(ifp->ifindex, &nifp->grekey,
- &nifp->linkidx, &saddr);
+
+ if (!gre_info) {
+ nhrp_send_zebra_gre_request(ifp);
+ return;
+ }
+ nifp->i_grekey = gre_info->ikey;
+ nifp->o_grekey = gre_info->okey;
+ nifp->link_idx = gre_info->ifindex_link;
+ nifp->link_vrf_id = gre_info->vrfid_link;
+ saddr.s_addr = gre_info->vtep_ip.s_addr;
+
debugf(NHRP_DEBUG_IF, "%s: GRE: %x %x %x", ifp->name,
- nifp->grekey, nifp->linkidx, saddr.s_addr);
- if (saddr.s_addr != INADDR_ANY)
- sockunion_set(&nbma, AF_INET, (uint8_t *)&saddr.s_addr,
+ nifp->i_grekey, nifp->link_idx, saddr.s_addr);
+ if (saddr.s_addr)
+ sockunion_set(&nbma, AF_INET,
+ (uint8_t *)&saddr.s_addr,
sizeof(saddr.s_addr));
- else if (!nbmaifp && nifp->linkidx != IFINDEX_INTERNAL)
+ else if (!nbmaifp && nifp->link_idx != IFINDEX_INTERNAL)
nbmaifp =
- if_lookup_by_index(nifp->linkidx, VRF_DEFAULT);
+ if_lookup_by_index(nifp->link_idx,
+ nifp->link_vrf_id);
} break;
default:
break;
ifp->name, ifp->ifindex, ifp->ll_type,
if_link_type_str(ifp->ll_type));
- nhrp_interface_update_nbma(ifp);
+ nhrp_interface_update_nbma(ifp, NULL);
return 0;
}
int nhrp_ifp_up(struct interface *ifp)
{
debugf(NHRP_DEBUG_IF, "if-up: %s", ifp->name);
- nhrp_interface_update_nbma(ifp);
+ nhrp_interface_update_nbma(ifp, NULL);
return 0;
}
free(nifp->source);
nifp->source = ifname ? strdup(ifname) : NULL;
- nhrp_interface_update_nbma(ifp);
+ nhrp_interface_update_nbma(ifp, NULL);
}
#include "getopt.h"
#include "thread.h"
#include "sigevent.h"
-#include "version.h"
+#include "lib/version.h"
#include "log.h"
#include "memory.h"
#include "command.h"
#include "filter.h"
#include "nhrpd.h"
-#include "netlink.h"
#include "nhrp_errors.h"
DEFINE_MGROUP(NHRPD, "NHRP");
assert(nhrpd_privs.change);
nhrpd_privs.change(ZPRIVS_RAISE);
- netlink_init();
evmgr_init();
nhrp_vc_init();
nhrp_packet_init();
--- /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);
+ }
+}
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);
}
zclient->neighbor_added = nhrp_neighbor_operation;
zclient->neighbor_removed = nhrp_neighbor_operation;
zclient->neighbor_get = nhrp_neighbor_operation;
+ zclient->gre_update = nhrp_gre_update;
zclient_init(zclient, ZEBRA_ROUTE_NHRP, 0, &nhrpd_privs);
}
zclient_send_message(zclient);
}
+void nhrp_send_zebra_gre_source_set(struct interface *ifp,
+ unsigned int link_idx,
+ vrf_id_t link_vrf_id)
+{
+ struct stream *s;
+
+ if (!zclient || zclient->sock < 0) {
+ zlog_err("%s : zclient not ready", __func__);
+ return;
+ }
+ if (link_idx == IFINDEX_INTERNAL || link_vrf_id == VRF_UNKNOWN) {
+ /* silently ignore */
+ return;
+ }
+ s = zclient->obuf;
+ stream_reset(s);
+ zclient_create_header(s,
+ ZEBRA_GRE_SOURCE_SET,
+ ifp->vrf_id);
+ stream_putl(s, ifp->ifindex);
+ stream_putl(s, link_idx);
+ stream_putl(s, link_vrf_id);
+ stream_putl(s, 0); /* mtu provisioning */
+ 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)
zclient_send_message(zclient);
}
+int nhrp_send_zebra_gre_request(struct interface *ifp)
+{
+ return zclient_send_zebra_gre_request(zclient, ifp);
+}
+
void nhrp_zebra_terminate(void)
{
nhrp_zebra_register_neigh(VRF_DEFAULT, AFI_IP, false);
route_table_finish(zebra_rib[AFI_IP]);
route_table_finish(zebra_rib[AFI_IP6]);
}
+
+void nhrp_gre_update(ZAPI_CALLBACK_ARGS)
+{
+ struct stream *s;
+ struct nhrp_gre_info gre_info, *val;
+ struct interface *ifp;
+
+ /* result */
+ s = zclient->ibuf;
+ if (vrf_id != VRF_DEFAULT)
+ return;
+
+ /* read GRE information */
+ STREAM_GETL(s, gre_info.ifindex);
+ STREAM_GETL(s, gre_info.ikey);
+ STREAM_GETL(s, gre_info.okey);
+ STREAM_GETL(s, gre_info.ifindex_link);
+ STREAM_GETL(s, gre_info.vrfid_link);
+ STREAM_GETL(s, gre_info.vtep_ip.s_addr);
+ STREAM_GETL(s, gre_info.vtep_ip_remote.s_addr);
+ if (gre_info.ifindex == IFINDEX_INTERNAL)
+ val = NULL;
+ else
+ val = hash_lookup(nhrp_gre_list, &gre_info);
+ if (val) {
+ if (gre_info.vtep_ip.s_addr != val->vtep_ip.s_addr ||
+ gre_info.vrfid_link != val->vrfid_link ||
+ gre_info.ifindex_link != val->ifindex_link ||
+ gre_info.ikey != val->ikey ||
+ gre_info.okey != val->okey) {
+ /* update */
+ memcpy(val, &gre_info, sizeof(struct nhrp_gre_info));
+ }
+ } else {
+ val = nhrp_gre_info_alloc(&gre_info);
+ }
+ ifp = if_lookup_by_index(gre_info.ifindex, vrf_id);
+ debugf(NHRP_DEBUG_EVENT, "%s: gre interface %d vr %d obtained from system",
+ ifp ? ifp->name : "<none>", gre_info.ifindex, vrf_id);
+ if (ifp)
+ nhrp_interface_update_nbma(ifp, val);
+ return;
+stream_failure:
+ zlog_err("%s(): error reading response ..", __func__);
+}
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);
}
return !list_empty(&l->notifier_head);
}
+extern struct hash *nhrp_gre_list;
+
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);
+
+void nhrp_send_zebra_gre_source_set(struct interface *ifp,
+ unsigned int link_idx,
+ vrf_id_t link_vrf_id);
+
+extern int nhrp_send_zebra_gre_request(struct interface *ifp);
+extern struct nhrp_gre_info *nhrp_gre_info_alloc(struct nhrp_gre_info *p);
+
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;
char *ipsec_profile, *ipsec_fallback_profile, *source;
union sockunion nbma;
union sockunion nat_nbma;
- unsigned int linkidx;
- uint32_t grekey;
+ unsigned int link_idx;
+ unsigned int link_vrf_id;
+ uint32_t i_grekey;
+ uint32_t o_grekey;
struct hash *peer_hash;
struct hash *cache_config_hash;
unsigned short mtu;
unsigned int holdtime;
struct list_head nhslist_head;
+ struct list_head mcastlist_head;
} afi[AFI_MAX];
};
+struct nhrp_gre_info {
+ ifindex_t ifindex;
+ struct in_addr vtep_ip; /* IFLA_GRE_LOCAL */
+ struct in_addr vtep_ip_remote; /* IFLA_GRE_REMOTE */
+ uint32_t ikey;
+ uint32_t okey;
+ ifindex_t ifindex_link; /* Interface index of interface
+ * linked with GRE
+ */
+ vrf_id_t vrfid_link;
+};
+
extern struct zebra_privs_t nhrpd_privs;
int sock_open_unix(const char *path);
void nhrp_interface_init(void);
void nhrp_interface_update(struct interface *ifp);
void nhrp_interface_update_mtu(struct interface *ifp, afi_t afi);
+void nhrp_interface_update_nbma(struct interface *ifp,
+ struct nhrp_gre_info *gre_info);
int nhrp_interface_add(ZAPI_CALLBACK_ARGS);
int nhrp_interface_delete(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_gre_update(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_nhrpd_SOURCES = \
nhrpd/linux.c \
nhrpd/netlink_arp.c \
- nhrpd/netlink_gre.c \
nhrpd/nhrp_cache.c \
nhrpd/nhrp_errors.c \
nhrpd/nhrp_event.c \
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 \
#include <string.h>
#include <unistd.h>
#include <errno.h>
-#include "zassert.h"
+#include <assert.h>
#include "zbuf.h"
#include "memory.h"
#include "nhrpd.h"
void zbuf_reset_head(struct zbuf *zb, void *ptr)
{
- zassert((void *)zb->buf <= ptr && ptr <= (void *)zb->tail);
+ assert((void *)zb->buf <= ptr && ptr <= (void *)zb->tail);
zb->head = ptr;
}
#include <endian.h>
#include <sys/types.h>
-#include "zassert.h"
#include "list.h"
struct zbuf {
zlog_debug(
"prefix %pFX was denied by export list",
&route->prefix);
+ ospf6_abr_delete_route(route, summary,
+ summary_table, old);
return 0;
}
}
zlog_debug(
"prefix %pFX was denied by filter-list out",
&route->prefix);
+ ospf6_abr_delete_route(route, summary, summary_table,
+ old);
+
return 0;
}
== FILTER_DENY) {
if (is_debug)
zlog_debug(
- "Prefix was denied by import-list");
+ "Prefix %pFX was denied by import-list",
+ &prefix);
if (old)
ospf6_route_remove(old, table);
return;
if (prefix_list_apply(PREFIX_LIST_IN(oa), &prefix)
!= PREFIX_PERMIT) {
if (is_debug)
- zlog_debug("Prefix was denied by prefix-list");
+ zlog_debug(
+ "Prefix %pFX was denied by prefix-list in",
+ &prefix);
if (old)
ospf6_route_remove(old, table);
return;
ospf6_abr_examin_summary(lsa, oa);
}
+/* export filter removed so determine if we should reoriginate summary LSAs */
+void ospf6_abr_reexport(struct ospf6_area *oa)
+{
+ struct ospf6_route *route;
+
+ /* if not a ABR return success */
+ if (!ospf6_is_router_abr(oa->ospf6))
+ return;
+
+ /* Redo summaries if required */
+ for (route = ospf6_route_head(oa->ospf6->route_table); route;
+ route = ospf6_route_next(route))
+ ospf6_abr_originate_summary_to_area(route, oa);
+}
+
void ospf6_abr_prefix_resummarize(struct ospf6 *o)
{
struct ospf6_route *route;
struct ospf6_route *route,
struct ospf6 *ospf6);
extern void ospf6_abr_reimport(struct ospf6_area *oa);
+extern void ospf6_abr_reexport(struct ospf6_area *oa);
extern void ospf6_abr_range_reset_cost(struct ospf6 *ospf6);
extern void ospf6_abr_prefix_resummarize(struct ospf6 *ospf6);
struct ospf6_route *route,
struct ospf6_route_table *table);
extern void ospf6_abr_init(void);
+extern void ospf6_abr_reexport(struct ospf6_area *oa);
#endif /*OSPF6_ABR_H*/
XFREE(MTYPE_OSPF6_PLISTNAME, PREFIX_NAME_OUT(area));
PREFIX_NAME_OUT(area) =
XSTRDUP(MTYPE_OSPF6_PLISTNAME, plistname);
- ospf6_abr_enable_area(area);
+
+ /* Redo summaries if required */
+ ospf6_abr_reexport(area);
}
return CMD_SUCCESS;
return CMD_SUCCESS;
XFREE(MTYPE_OSPF6_PLISTNAME, PREFIX_NAME_OUT(area));
- ospf6_abr_enable_area(area);
+ PREFIX_LIST_OUT(area) = NULL;
+ ospf6_abr_reexport(area);
}
return CMD_SUCCESS;
}
+void ospf6_filter_update(struct access_list *access)
+{
+ struct ospf6_area *oa;
+ struct listnode *n, *node, *nnode;
+ struct ospf6 *ospf6;
+
+ for (ALL_LIST_ELEMENTS(om6->ospf6, node, nnode, ospf6)) {
+ for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, n, oa)) {
+ if (IMPORT_NAME(oa)
+ && strcmp(IMPORT_NAME(oa), access->name) == 0)
+ ospf6_abr_reimport(oa);
+
+ if (EXPORT_NAME(oa)
+ && strcmp(EXPORT_NAME(oa), access->name) == 0)
+ ospf6_abr_reexport(oa);
+ }
+ }
+}
+
void ospf6_area_plist_update(struct prefix_list *plist, int add)
{
struct listnode *node, *nnode;
for (ALL_LIST_ELEMENTS(om6->ospf6, node, nnode, ospf6)) {
for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, n, oa)) {
if (PREFIX_NAME_IN(oa)
- && !strcmp(PREFIX_NAME_IN(oa), name))
+ && !strcmp(PREFIX_NAME_IN(oa), name)) {
PREFIX_LIST_IN(oa) = add ? plist : NULL;
+ ospf6_abr_reexport(oa);
+ }
if (PREFIX_NAME_OUT(oa)
- && !strcmp(PREFIX_NAME_OUT(oa), name))
+ && !strcmp(PREFIX_NAME_OUT(oa), name)) {
PREFIX_LIST_OUT(oa) = add ? plist : NULL;
+ ospf6_abr_reexport(oa);
+ }
}
}
}
free(EXPORT_NAME(area));
EXPORT_NAME(area) = strdup(argv[idx_name]->arg);
- ospf6_abr_enable_area(area);
+
+ /* Redo summaries if required */
+ ospf6_abr_reexport(area);
return CMD_SUCCESS;
}
free(EXPORT_NAME(area));
EXPORT_NAME(area) = NULL;
- ospf6_abr_enable_area(area);
+ ospf6_abr_reexport(area);
return CMD_SUCCESS;
}
-DEFUN (show_ipv6_ospf6_spf_tree,
- show_ipv6_ospf6_spf_tree_cmd,
- "show ipv6 ospf6 spf tree [json]",
- SHOW_STR
- IP6_STR
- OSPF6_STR
- "Shortest Path First calculation\n"
- "Show SPF tree\n"
- JSON_STR)
+static int ipv6_ospf6_spf_tree_common(struct vty *vty, struct ospf6 *ospf6,
+ bool uj)
{
struct listnode *node;
struct ospf6_area *oa;
+ struct prefix prefix;
struct ospf6_vertex *root;
struct ospf6_route *route;
- struct prefix prefix;
- struct ospf6 *ospf6;
json_object *json = NULL;
json_object *json_area = NULL;
json_object *json_head = NULL;
- bool uj = use_json(argc, argv);
-
- ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
- OSPF6_CMD_CHECK_RUNNING(ospf6);
if (uj)
json = json_object_new_object();
ospf6_linkstate_prefix(ospf6->router_id, htonl(0), &prefix);
-
for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) {
if (uj) {
json_area = json_object_new_object();
return CMD_SUCCESS;
}
-DEFUN (show_ipv6_ospf6_area_spf_tree,
- show_ipv6_ospf6_area_spf_tree_cmd,
- "show ipv6 ospf6 area A.B.C.D spf tree",
- SHOW_STR
- IP6_STR
- OSPF6_STR
- OSPF6_AREA_STR
- OSPF6_AREA_ID_STR
- "Shortest Path First calculation\n"
- "Show SPF tree\n")
+DEFUN(show_ipv6_ospf6_spf_tree, show_ipv6_ospf6_spf_tree_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] spf tree [json]",
+ SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "Shortest Path First calculation\n"
+ "Show SPF tree\n" JSON_STR)
{
- int idx_ipv4 = 4;
- uint32_t area_id;
- struct ospf6_area *oa;
- struct ospf6_vertex *root;
- struct ospf6_route *route;
- struct prefix prefix;
+ struct listnode *node;
struct ospf6 *ospf6;
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+ bool uj = use_json(argc, argv);
+
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
- ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ ipv6_ospf6_spf_tree_common(vty, ospf6, uj);
+ if (!all_vrf)
+ break;
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+static int show_ospf6_area_spf_tree_common(struct vty *vty,
+ struct cmd_token **argv,
+ struct ospf6 *ospf6,
+ uint32_t area_id, int idx_ipv4)
+{
- OSPF6_CMD_CHECK_RUNNING(ospf6);
+ struct ospf6_area *oa;
+ struct prefix prefix;
+ struct ospf6_vertex *root;
+ struct ospf6_route *route;
ospf6_linkstate_prefix(ospf6->router_id, htonl(0), &prefix);
- if (inet_pton(AF_INET, argv[idx_ipv4]->arg, &area_id) != 1) {
- vty_out(vty, "Malformed Area-ID: %s\n", argv[idx_ipv4]->arg);
- return CMD_SUCCESS;
- }
oa = ospf6_area_lookup(area_id, ospf6);
if (oa == NULL) {
vty_out(vty, "No such Area: %s\n", argv[idx_ipv4]->arg);
return CMD_SUCCESS;
}
-DEFUN (show_ipv6_ospf6_simulate_spf_tree_root,
- show_ipv6_ospf6_simulate_spf_tree_root_cmd,
- "show ipv6 ospf6 simulate spf-tree A.B.C.D area A.B.C.D",
- SHOW_STR
- IP6_STR
- OSPF6_STR
- "Shortest Path First calculation\n"
- "Show SPF tree\n"
- "Specify root's router-id to calculate another router's SPF tree\n"
- "OSPF6 area parameters\n"
- OSPF6_AREA_ID_STR)
+DEFUN(show_ipv6_ospf6_area_spf_tree, show_ipv6_ospf6_area_spf_tree_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] area A.B.C.D spf tree",
+ SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR
+ "All VRFs\n" OSPF6_AREA_STR OSPF6_AREA_ID_STR
+ "Shortest Path First calculation\n"
+ "Show SPF tree\n")
{
- int idx_ipv4 = 5;
- int idx_ipv4_2 = 7;
+ int idx_ipv4 = 4;
uint32_t area_id;
+ struct ospf6 *ospf6;
+ struct listnode *node;
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (idx_vrf > 0)
+ idx_ipv4 += 2;
+
+ if (inet_pton(AF_INET, argv[idx_ipv4]->arg, &area_id) != 1) {
+ vty_out(vty, "Malformed Area-ID: %s\n", argv[idx_ipv4]->arg);
+ return CMD_SUCCESS;
+ }
+
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ show_ospf6_area_spf_tree_common(vty, argv, ospf6,
+ area_id, idx_ipv4);
+ if (!all_vrf)
+ break;
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+static int
+show_ospf6_simulate_spf_tree_commen(struct vty *vty, struct cmd_token **argv,
+ struct ospf6 *ospf6, uint32_t router_id,
+ uint32_t area_id, struct prefix prefix,
+ int idx_ipv4, int idx_ipv4_2)
+{
struct ospf6_area *oa;
struct ospf6_vertex *root;
struct ospf6_route *route;
- struct prefix prefix;
- uint32_t router_id;
struct ospf6_route_table *spf_table;
unsigned char tmp_debug_ospf6_spf = 0;
- struct ospf6 *ospf6;
-
- ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
-
- OSPF6_CMD_CHECK_RUNNING(ospf6);
- inet_pton(AF_INET, argv[idx_ipv4]->arg, &router_id);
- ospf6_linkstate_prefix(router_id, htonl(0), &prefix);
-
- if (inet_pton(AF_INET, argv[idx_ipv4_2]->arg, &area_id) != 1) {
- vty_out(vty, "Malformed Area-ID: %s\n", argv[idx_ipv4_2]->arg);
- return CMD_SUCCESS;
- }
oa = ospf6_area_lookup(area_id, ospf6);
if (oa == NULL) {
vty_out(vty, "No such Area: %s\n", argv[idx_ipv4_2]->arg);
return CMD_SUCCESS;
}
+DEFUN(show_ipv6_ospf6_simulate_spf_tree_root,
+ show_ipv6_ospf6_simulate_spf_tree_root_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] simulate spf-tree A.B.C.D area A.B.C.D",
+ SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "Shortest Path First calculation\n"
+ "Show SPF tree\n"
+ "Specify root's router-id to calculate another router's SPF tree\n"
+ "OSPF6 area parameters\n" OSPF6_AREA_ID_STR)
+{
+ int idx_ipv4 = 5;
+ int idx_ipv4_2 = 7;
+ uint32_t area_id;
+ struct prefix prefix;
+ uint32_t router_id;
+ struct ospf6 *ospf6;
+ struct listnode *node;
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (idx_vrf > 0) {
+ idx_ipv4 += 2;
+ idx_ipv4_2 += 2;
+ }
+ inet_pton(AF_INET, argv[idx_ipv4]->arg, &router_id);
+ ospf6_linkstate_prefix(router_id, htonl(0), &prefix);
+
+ if (inet_pton(AF_INET, argv[idx_ipv4_2]->arg, &area_id) != 1) {
+ vty_out(vty, "Malformed Area-ID: %s\n", argv[idx_ipv4_2]->arg);
+ return CMD_SUCCESS;
+ }
+
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ show_ospf6_simulate_spf_tree_commen(
+ vty, argv, ospf6, router_id, area_id, prefix,
+ idx_ipv4, idx_ipv4_2);
+ if (!all_vrf)
+ break;
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
DEFUN (ospf6_area_stub,
ospf6_area_stub_cmd,
"area <A.B.C.D|(0-4294967295)> stub",
if (!om6->ospf6)
return;
- for (ALL_LIST_ELEMENTS(om6->ospf6, node, nnode, ospf6))
+ for (ALL_LIST_ELEMENTS(om6->ospf6, node, nnode, ospf6)) {
for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, oa))
if (listnode_lookup(oa->if_list, oi))
listnode_delete(oa->if_list, oi);
+ }
}
json_object *json_areas, bool use_json);
extern void ospf6_area_plist_update(struct prefix_list *plist, int add);
+extern void ospf6_filter_update(struct access_list *access);
extern void ospf6_area_config_write(struct vty *vty, struct ospf6 *ospf6);
extern void ospf6_area_init(void);
struct ospf6_interface;
#include "ospf6_spf.h"
#include "ospf6_top.h"
+#include "ospf6d.h"
#include "ospf6_area.h"
#include "ospf6_interface.h"
#include "ospf6_neighbor.h"
struct ospf6_redist *red;
VTY_DECLVAR_CONTEXT(ospf6, ospf6);
- OSPF6_CMD_CHECK_RUNNING(ospf6);
+
char *proto = argv[argc - 1]->text;
type = proto_redistnum(AFI_IP6, proto);
if (type < 0)
struct ospf6_redist *red;
VTY_DECLVAR_CONTEXT(ospf6, ospf6);
- OSPF6_CMD_CHECK_RUNNING(ospf6);
char *proto = argv[idx_protocol]->text;
type = proto_redistnum(AFI_IP6, proto);
VTY_DECLVAR_CONTEXT(ospf6, ospf6);
- OSPF6_CMD_CHECK_RUNNING(ospf6);
-
char *proto = argv[idx_protocol]->text;
type = proto_redistnum(AFI_IP6, proto);
if (type < 0)
int cur_originate = ospf6->default_originate;
- OSPF6_CMD_CHECK_RUNNING(ospf6);
-
red = ospf6_redist_add(ospf6, DEFAULT_ROUTE, 0);
if (always != NULL)
VTY_DECLVAR_CONTEXT(ospf6, ospf6);
- OSPF6_CMD_CHECK_RUNNING(ospf6);
-
red = ospf6_redist_lookup(ospf6, DEFAULT_ROUTE, 0);
if (!red)
return CMD_SUCCESS;
forwarding);
}
-DEFUN (show_ipv6_ospf6_redistribute,
- show_ipv6_ospf6_redistribute_cmd,
- "show ipv6 ospf6 redistribute [json]",
- SHOW_STR
- IP6_STR
- OSPF6_STR
- "redistributing External information\n"
- JSON_STR)
+DEFUN(show_ipv6_ospf6_redistribute, show_ipv6_ospf6_redistribute_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] redistribute [json]",
+ SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "redistributing External information\n" JSON_STR)
{
struct ospf6_route *route;
struct ospf6 *ospf6 = NULL;
json_object *json = NULL;
bool uj = use_json(argc, argv);
+ struct listnode *node;
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+
json_object *json_array_routes = NULL;
json_object *json_array_redistribute = NULL;
- ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
- OSPF6_CMD_CHECK_RUNNING(ospf6);
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
if (uj) {
json = json_object_new_object();
json_array_routes = json_object_new_array();
json_array_redistribute = json_object_new_array();
}
- ospf6_redistribute_show_config(vty, ospf6, json_array_redistribute,
- json, uj);
- for (route = ospf6_route_head(ospf6->external_table); route;
- route = ospf6_route_next(route)) {
- ospf6_asbr_external_route_show(vty, route, json_array_routes,
- uj);
- }
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf
+ || ((ospf6->name == NULL && vrf_name == NULL)
+ || (ospf6->name && vrf_name
+ && strcmp(ospf6->name, vrf_name) == 0))) {
+ ospf6_redistribute_show_config(
+ vty, ospf6, json_array_redistribute, json, uj);
+
+ for (route = ospf6_route_head(ospf6->external_table);
+ route; route = ospf6_route_next(route)) {
+ ospf6_asbr_external_route_show(
+ vty, route, json_array_routes, uj);
+ }
- if (uj) {
- json_object_object_add(json, "routes", json_array_routes);
- vty_out(vty, "%s\n",
- json_object_to_json_string_ext(
- json, JSON_C_TO_STRING_PRETTY));
- json_object_free(json);
+ if (uj) {
+ json_object_object_add(json, "routes",
+ json_array_routes);
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+
+ if (!all_vrf)
+ break;
+ }
}
+
return CMD_SUCCESS;
}
extern struct zclient *zclient;
-/*
- * ospf6_bfd_info_free - Free BFD info structure
- */
-void ospf6_bfd_info_free(void **bfd_info)
-{
- bfd_info_free((struct bfd_info **)bfd_info);
-}
-
-/*
- * ospf6_bfd_show_info - Show BFD info structure
- */
-void ospf6_bfd_show_info(struct vty *vty, void *bfd_info, int param_only,
- json_object *json_obj, bool use_json)
-{
- if (param_only)
- bfd_show_param(vty, bfd_info, 1, 0, use_json, json_obj);
- else
- bfd_show_info(vty, bfd_info, 0, 1, use_json, json_obj);
-}
-
-/*
- * ospf6_bfd_reg_dereg_nbr - Register/Deregister a neighbor with BFD through
- * zebra for starting/stopping the monitoring of
- * the neighbor rechahability.
- */
-void ospf6_bfd_reg_dereg_nbr(struct ospf6_neighbor *on, int command)
-{
- struct ospf6_interface *oi = on->ospf6_if;
- struct interface *ifp = oi->interface;
- struct bfd_info *bfd_info;
- char src[64];
- int cbit;
-
- if (!oi->bfd_info || !on->bfd_info)
- return;
- bfd_info = (struct bfd_info *)oi->bfd_info;
-
- if (IS_OSPF6_DEBUG_ZEBRA(SEND)) {
- inet_ntop(AF_INET6, &on->linklocal_addr, src, sizeof(src));
- zlog_debug("%s nbr (%s) with BFD",
- bfd_get_command_dbg_str(command), src);
- }
-
- cbit = CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON);
-
- bfd_peer_sendmsg(zclient, bfd_info, AF_INET6, &on->linklocal_addr,
- on->ospf6_if->linklocal_addr, ifp->name, 0, 0, cbit,
- command, 0, ifp->vrf_id);
-
- if (command == ZEBRA_BFD_DEST_DEREGISTER)
- bfd_info_free((struct bfd_info **)&on->bfd_info);
-}
-
/*
* ospf6_bfd_trigger_event - Neighbor is registered/deregistered with BFD when
* neighbor state is changed to/from 2way.
void ospf6_bfd_trigger_event(struct ospf6_neighbor *on, int old_state,
int state)
{
- if ((old_state < OSPF6_NEIGHBOR_TWOWAY)
- && (state >= OSPF6_NEIGHBOR_TWOWAY))
- ospf6_bfd_reg_dereg_nbr(on, ZEBRA_BFD_DEST_REGISTER);
- else if ((old_state >= OSPF6_NEIGHBOR_TWOWAY)
- && (state < OSPF6_NEIGHBOR_TWOWAY))
- ospf6_bfd_reg_dereg_nbr(on, ZEBRA_BFD_DEST_DEREGISTER);
+ int family;
+ struct in6_addr src, dst;
+
+ /* Skip sessions without BFD. */
+ if (on->bfd_session == NULL)
+ return;
+
+ if (old_state < OSPF6_NEIGHBOR_TWOWAY
+ && state >= OSPF6_NEIGHBOR_TWOWAY) {
+ /*
+ * Check if neighbor address changed.
+ *
+ * When the neighbor is configured BFD before having an existing
+ * connection, then the destination address will be set to `::`
+ * which will cause session installation failure. This piece of
+ * code updates the address in that case.
+ */
+ bfd_sess_addresses(on->bfd_session, &family, &src, &dst);
+ if (memcmp(&on->linklocal_addr, &dst, sizeof(dst))) {
+ bfd_sess_set_ipv6_addrs(on->bfd_session, &src,
+ &on->linklocal_addr);
+ }
+
+ bfd_sess_install(on->bfd_session);
+ } else if (old_state >= OSPF6_NEIGHBOR_TWOWAY
+ && state < OSPF6_NEIGHBOR_TWOWAY)
+ bfd_sess_uninstall(on->bfd_session);
}
/*
* zebra for starting/stopping the monitoring of
* the neighbor rechahability.
*/
-static void ospf6_bfd_reg_dereg_all_nbr(struct ospf6_interface *oi, int command)
+static void ospf6_bfd_reg_dereg_all_nbr(struct ospf6_interface *oi,
+ bool install)
{
struct ospf6_neighbor *on;
struct listnode *node;
for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, node, on)) {
- if (command == ZEBRA_BFD_DEST_REGISTER)
- ospf6_bfd_info_nbr_create(oi, on);
-
- if (on->state < OSPF6_NEIGHBOR_TWOWAY) {
- if (command == ZEBRA_BFD_DEST_DEREGISTER)
- bfd_info_free(
- (struct bfd_info **)&on->bfd_info);
+ /* Remove all sessions. */
+ if (!install) {
+ bfd_sess_free(&on->bfd_session);
continue;
}
- ospf6_bfd_reg_dereg_nbr(on, command);
- }
-}
+ /* Always allocate session data even if not enabled. */
+ ospf6_bfd_info_nbr_create(oi, on);
-/*
- * ospf6_bfd_nbr_replay - Replay all the neighbors that have BFD enabled
- * to zebra
- */
-static int ospf6_bfd_nbr_replay(ZAPI_CALLBACK_ARGS)
-{
- struct vrf *vrf = vrf_lookup_by_id(vrf_id);
- struct listnode *node;
- struct interface *ifp;
- struct ospf6_interface *oi;
- struct ospf6_neighbor *on;
- char dst[64];
-
- if (IS_OSPF6_DEBUG_ZEBRA(RECV))
- zlog_debug("Zebra: BFD Dest replay request");
-
- /* Send the client registration */
- bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id);
-
- /* Replay the neighbor, if BFD is enabled on the interface*/
- FOR_ALL_INTERFACES (vrf, ifp) {
- oi = (struct ospf6_interface *)ifp->info;
-
- if (!oi || !oi->bfd_info)
+ /*
+ * If not connected yet, don't create any session but defer it
+ * for later. See function `ospf6_bfd_trigger_event`.
+ */
+ if (on->state < OSPF6_NEIGHBOR_TWOWAY)
continue;
- for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, node, on)) {
- if (on->state < OSPF6_NEIGHBOR_TWOWAY)
- continue;
-
- if (IS_OSPF6_DEBUG_ZEBRA(SEND)) {
- inet_ntop(AF_INET6, &on->linklocal_addr, dst,
- sizeof(dst));
- zlog_debug("Replaying nbr (%s) to BFD", dst);
- }
-
- ospf6_bfd_reg_dereg_nbr(on, ZEBRA_BFD_DEST_UPDATE);
- }
+ bfd_sess_install(on->bfd_session);
}
- return 0;
}
-/*
- * ospf6_bfd_interface_dest_update - Find the neighbor for which the BFD status
- * has changed and bring down the neighbor
- * connectivity if BFD down is received.
- */
-static int ospf6_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS)
+static void ospf6_bfd_callback(struct bfd_session_params *bsp,
+ const struct bfd_session_status *bss, void *arg)
{
- struct interface *ifp;
- struct ospf6_interface *oi;
- struct ospf6_neighbor *on;
- struct prefix dp;
- struct prefix sp;
- struct listnode *node, *nnode;
- char dst[64];
- int status;
- int old_status;
- struct bfd_info *bfd_info;
- struct timeval tv;
-
- ifp = bfd_get_peer_info(zclient->ibuf, &dp, &sp, &status,
- NULL, vrf_id);
-
- if ((ifp == NULL) || (dp.family != AF_INET6))
- return 0;
-
- if (IS_OSPF6_DEBUG_ZEBRA(RECV))
- zlog_debug("Zebra: interface %s bfd destination %pFX %s",
- ifp->name, &dp, bfd_get_status_str(status));
-
-
- oi = (struct ospf6_interface *)ifp->info;
- if (!oi || !oi->bfd_info)
- return 0;
-
- for (ALL_LIST_ELEMENTS(oi->neighbor_list, node, nnode, on)) {
- if (memcmp(&(on->linklocal_addr), &dp.u.prefix6,
- sizeof(struct in6_addr)))
- continue;
-
- if (IS_OSPF6_DEBUG_NEIGHBOR(EVENT)) {
- inet_ntop(AF_INET6, &on->linklocal_addr, dst,
- sizeof(dst));
- zlog_debug("[%s:%s]: BFD %s", ifp->name, dst,
- bfd_get_status_str(status));
- }
-
- if (!on->bfd_info)
- continue;
-
- bfd_info = (struct bfd_info *)on->bfd_info;
- if (bfd_info->status == status)
- continue;
+ struct ospf6_neighbor *on = arg;
- old_status = bfd_info->status;
- BFD_SET_CLIENT_STATUS(bfd_info->status, status);
- monotime(&tv);
- bfd_info->last_update = tv.tv_sec;
-
- if ((status == BFD_STATUS_DOWN)
- && (old_status == BFD_STATUS_UP)) {
- THREAD_OFF(on->inactivity_timer);
- thread_add_event(master, inactivity_timer, on, 0, NULL);
- }
+ if (bss->state == BFD_STATUS_DOWN
+ && bss->previous_state == BFD_STATUS_UP) {
+ THREAD_OFF(on->inactivity_timer);
+ thread_add_event(master, inactivity_timer, on, 0, NULL);
}
-
- return 0;
}
/*
void ospf6_bfd_info_nbr_create(struct ospf6_interface *oi,
struct ospf6_neighbor *on)
{
- struct bfd_info *oi_bfd_info;
- struct bfd_info *on_bfd_info;
-
- if (!oi->bfd_info)
+ if (!oi->bfd_config.enabled)
return;
- oi_bfd_info = (struct bfd_info *)oi->bfd_info;
-
- if (!on->bfd_info)
- on->bfd_info = bfd_info_create();
+ if (on->bfd_session == NULL)
+ on->bfd_session = bfd_sess_new(ospf6_bfd_callback, on);
- on_bfd_info = (struct bfd_info *)on->bfd_info;
- on_bfd_info->detect_mult = oi_bfd_info->detect_mult;
- on_bfd_info->desired_min_tx = oi_bfd_info->desired_min_tx;
- on_bfd_info->required_min_rx = oi_bfd_info->required_min_rx;
+ bfd_sess_set_timers(on->bfd_session,
+ oi->bfd_config.detection_multiplier,
+ oi->bfd_config.min_rx, oi->bfd_config.min_tx);
+ bfd_sess_set_ipv6_addrs(on->bfd_session, on->ospf6_if->linklocal_addr,
+ &on->linklocal_addr);
+ bfd_sess_set_interface(on->bfd_session, oi->interface->name);
+ bfd_sess_set_profile(on->bfd_session, oi->bfd_config.profile);
}
/*
*/
void ospf6_bfd_write_config(struct vty *vty, struct ospf6_interface *oi)
{
-#if HAVE_BFDD == 0
- struct bfd_info *bfd_info;
-#endif /* ! HAVE_BFDD */
-
- if (!oi->bfd_info)
+ if (!oi->bfd_config.enabled)
return;
#if HAVE_BFDD == 0
- bfd_info = (struct bfd_info *)oi->bfd_info;
-
- if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG))
+ if (oi->bfd_config.detection_multiplier != BFD_DEF_DETECT_MULT
+ || oi->bfd_config.min_rx != BFD_DEF_MIN_RX
+ || oi->bfd_config.min_tx != BFD_DEF_MIN_TX)
vty_out(vty, " ipv6 ospf6 bfd %d %d %d\n",
- bfd_info->detect_mult, bfd_info->required_min_rx,
- bfd_info->desired_min_tx);
+ oi->bfd_config.detection_multiplier,
+ oi->bfd_config.min_rx, oi->bfd_config.min_tx);
else
#endif /* ! HAVE_BFDD */
vty_out(vty, " ipv6 ospf6 bfd\n");
+
+ if (oi->bfd_config.profile)
+ vty_out(vty, " ipv6 ospf6 bfd profile %s\n",
+ oi->bfd_config.profile);
}
-/*
- * ospf6_bfd_if_param_set - Set the configured BFD paramter values for
- * interface.
- */
-static void ospf6_bfd_if_param_set(struct ospf6_interface *oi, uint32_t min_rx,
- uint32_t min_tx, uint8_t detect_mult,
- int defaults)
+DEFUN(ipv6_ospf6_bfd, ipv6_ospf6_bfd_cmd,
+ "ipv6 ospf6 bfd [profile BFDPROF]",
+ IP6_STR OSPF6_STR
+ "Enables BFD support\n"
+ "BFD Profile selection\n"
+ "BFD Profile name\n")
{
- int command = 0;
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct ospf6_interface *oi;
+ int prof_idx = 4;
+ assert(ifp);
- bfd_set_param((struct bfd_info **)&(oi->bfd_info), min_rx, min_tx,
- detect_mult, NULL, defaults, &command);
- if (command)
- ospf6_bfd_reg_dereg_all_nbr(oi, command);
+ oi = (struct ospf6_interface *)ifp->info;
+ if (oi == NULL)
+ oi = ospf6_interface_create(ifp);
+ assert(oi);
+
+ oi->bfd_config.detection_multiplier = BFD_DEF_DETECT_MULT;
+ oi->bfd_config.min_rx = BFD_DEF_MIN_RX;
+ oi->bfd_config.min_tx = BFD_DEF_MIN_TX;
+ oi->bfd_config.enabled = true;
+ if (argc > prof_idx) {
+ XFREE(MTYPE_TMP, oi->bfd_config.profile);
+ oi->bfd_config.profile =
+ XSTRDUP(MTYPE_TMP, argv[prof_idx]->arg);
+ }
+
+ ospf6_bfd_reg_dereg_all_nbr(oi, true);
+
+ return CMD_SUCCESS;
}
-DEFUN (ipv6_ospf6_bfd,
- ipv6_ospf6_bfd_cmd,
- "ipv6 ospf6 bfd",
- IP6_STR
- OSPF6_STR
- "Enables BFD support\n"
- )
+DEFUN(no_ipv6_ospf6_bfd_profile, no_ipv6_ospf6_bfd_profile_cmd,
+ "no ipv6 ospf6 bfd profile [BFDPROF]",
+ NO_STR IP6_STR OSPF6_STR
+ "BFD support\n"
+ "BFD Profile selection\n"
+ "BFD Profile name\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct ospf6_interface *oi;
oi = ospf6_interface_create(ifp);
assert(oi);
- ospf6_bfd_if_param_set(oi, BFD_DEF_MIN_RX, BFD_DEF_MIN_TX,
- BFD_DEF_DETECT_MULT, 1);
+ /* BFD not enabled, nothing to do. */
+ if (!oi->bfd_config.enabled)
+ return CMD_SUCCESS;
+
+ /* Remove profile and apply new configuration. */
+ XFREE(MTYPE_TMP, oi->bfd_config.profile);
+ ospf6_bfd_reg_dereg_all_nbr(oi, true);
+
return CMD_SUCCESS;
}
int idx_number_2 = 4;
int idx_number_3 = 5;
struct ospf6_interface *oi;
- uint32_t rx_val;
- uint32_t tx_val;
- uint8_t dm_val;
- int ret;
assert(ifp);
oi = ospf6_interface_create(ifp);
assert(oi);
- if ((ret = bfd_validate_param(
- vty, argv[idx_number]->arg, argv[idx_number_2]->arg,
- argv[idx_number_3]->arg, &dm_val, &rx_val, &tx_val))
- != CMD_SUCCESS)
- return ret;
+ oi->bfd_config.detection_multiplier =
+ strtoul(argv[idx_number]->arg, NULL, 10);
+ oi->bfd_config.min_rx = strtoul(argv[idx_number_2]->arg, NULL, 10);
+ oi->bfd_config.min_tx = strtoul(argv[idx_number_3]->arg, NULL, 10);
+ oi->bfd_config.enabled = true;
- ospf6_bfd_if_param_set(oi, rx_val, tx_val, dm_val, 0);
+ ospf6_bfd_reg_dereg_all_nbr(oi, true);
return CMD_SUCCESS;
}
oi = ospf6_interface_create(ifp);
assert(oi);
- if (oi->bfd_info) {
- ospf6_bfd_reg_dereg_all_nbr(oi, ZEBRA_BFD_DEST_DEREGISTER);
- bfd_info_free((struct bfd_info **)&(oi->bfd_info));
- }
+ oi->bfd_config.enabled = false;
+ ospf6_bfd_reg_dereg_all_nbr(oi, false);
return CMD_SUCCESS;
}
void ospf6_bfd_init(void)
{
- bfd_gbl_init();
-
- /* Initialize BFD client functions */
- zclient->interface_bfd_dest_update = ospf6_bfd_interface_dest_update;
- zclient->bfd_dest_replay = ospf6_bfd_nbr_replay;
+ bfd_protocol_integration_init(zclient, master);
/* Install BFD command */
install_element(INTERFACE_NODE, &ipv6_ospf6_bfd_cmd);
install_element(INTERFACE_NODE, &ipv6_ospf6_bfd_param_cmd);
+ install_element(INTERFACE_NODE, &no_ipv6_ospf6_bfd_profile_cmd);
install_element(INTERFACE_NODE, &no_ipv6_ospf6_bfd_cmd);
}
#define OSPF6_BFD_H
#include "lib/json.h"
+/**
+ * Initialize BFD integration.
+ */
extern void ospf6_bfd_init(void);
extern void ospf6_bfd_trigger_event(struct ospf6_neighbor *nbr, int old_state,
extern void ospf6_bfd_info_nbr_create(struct ospf6_interface *oi,
struct ospf6_neighbor *on);
-extern void ospf6_bfd_info_free(void **bfd_info);
-
-extern void ospf6_bfd_show_info(struct vty *vty, void *bfd_info, int param_only,
- json_object *json_obj, bool use_json);
-
-extern void ospf6_bfd_reg_dereg_nbr(struct ospf6_neighbor *on, int command);
#endif /* OSPF6_BFD_H */
} else {
/* (d) add retrans-list, schedule retransmission */
if (is_debug)
- zlog_debug("Add retrans-list of this neighbor");
+ zlog_debug("Add retrans-list of neighbor %s ",
+ on->name);
ospf6_increment_retrans_count(lsa);
ospf6_lsdb_add(ospf6_lsa_copy(lsa), on->retrans_list);
thread_add_timer(master, ospf6_lsupdate_send_neighbor,
if (retrans_added == 0) {
if (is_debug)
zlog_debug(
- "No retransmission scheduled, next interface");
+ "No retransmission scheduled, next interface %s",
+ oi->interface->name);
return;
}
if (oi->plist_name)
XFREE(MTYPE_CFG_PLIST_NAME, oi->plist_name);
- ospf6_bfd_info_free(&(oi->bfd_info));
-
/* disable from area list if possible */
ospf6_area_interface_delete(oi);
+ /* Free BFD allocated data. */
+ XFREE(MTYPE_TMP, oi->bfd_config.profile);
+
XFREE(MTYPE_OSPF6_IF, oi);
}
OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(oi->area);
}
-static void ospf6_interface_state_change(uint8_t next_state,
- struct ospf6_interface *oi)
+static int ospf6_interface_state_change(uint8_t next_state,
+ struct ospf6_interface *oi)
{
uint8_t prev_state;
struct ospf6 *ospf6;
oi->state = next_state;
if (prev_state == next_state)
- return;
+ return -1;
/* log */
if (IS_OSPF6_DEBUG_INTERFACE) {
}
hook_call(ospf6_interface_change, oi, next_state, prev_state);
+
+ return 0;
}
for (ALL_LSDB(oi->lsack_list, lsa, lsanext))
vty_out(vty, " %s\n", lsa->name);
}
- ospf6_bfd_show_info(vty, oi->bfd_info, 1, json_obj, use_json);
+
+ /* BFD specific. */
+ if (oi->bfd_config.enabled) {
+ if (use_json) {
+ struct json_object *json_bfd = json_object_new_object();
+
+ json_object_int_add(
+ json_bfd, "detectMultiplier",
+ oi->bfd_config.detection_multiplier);
+ json_object_int_add(json_bfd, "rxMinInterval",
+ oi->bfd_config.min_rx);
+ json_object_int_add(json_bfd, "txMinInterval",
+ oi->bfd_config.min_tx);
+ json_object_object_add(json_obj, "peerBfdInfo",
+ json_bfd);
+ } else {
+ vty_out(vty,
+ " BFD: Detect Multiplier: %d, Min Rx interval: %d, Min Tx interval: %d\n",
+ oi->bfd_config.detection_multiplier,
+ oi->bfd_config.min_rx, oi->bfd_config.min_tx);
+ }
+ }
+
return 0;
}
-/* show interface */
-DEFUN(show_ipv6_ospf6_interface,
- show_ipv6_ospf6_interface_ifname_cmd,
- "show ipv6 ospf6 interface [IFNAME] [json]",
- SHOW_STR
- IP6_STR
- OSPF6_STR
- INTERFACE_STR
- IFNAME_STR
- JSON_STR)
+static int show_ospf6_interface_common(struct vty *vty, vrf_id_t vrf_id,
+ int argc, struct cmd_token **argv,
+ int idx_ifname, int intf_idx,
+ int json_idx)
{
- struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
- int idx_ifname = 4;
+
+ struct vrf *vrf = vrf_lookup_by_id(vrf_id);
struct interface *ifp;
json_object *json;
json_object *json_int;
if (uj) {
json = json_object_new_object();
- if (argc == 6) {
- ifp = if_lookup_by_name(argv[idx_ifname]->arg,
- VRF_DEFAULT);
+ if (argc == json_idx) {
+ ifp = if_lookup_by_name(argv[idx_ifname]->arg, vrf_id);
json_int = json_object_new_object();
if (ifp == NULL) {
json_object_string_add(json, "noSuchInterface",
json, JSON_C_TO_STRING_PRETTY));
json_object_free(json);
} else {
- if (argc == 5) {
- ifp = if_lookup_by_name(argv[idx_ifname]->arg,
- VRF_DEFAULT);
+ if (argc == intf_idx) {
+ ifp = if_lookup_by_name(argv[idx_ifname]->arg, vrf_id);
if (ifp == NULL) {
vty_out(vty, "No such Interface: %s\n",
argv[idx_ifname]->arg);
ospf6_interface_show(vty, ifp, NULL, uj);
}
}
+ return CMD_SUCCESS;
+}
+
+/* show interface */
+DEFUN(show_ipv6_ospf6_interface, show_ipv6_ospf6_interface_ifname_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] interface [IFNAME] [json]",
+ SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR
+ "All VRFs\n" INTERFACE_STR IFNAME_STR JSON_STR)
+{
+ int idx_ifname = 4;
+ int intf_idx = 5;
+ int json_idx = 6;
+ struct listnode *node;
+ struct ospf6 *ospf6;
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (idx_vrf > 0) {
+ idx_ifname += 2;
+ intf_idx += 2;
+ json_idx += 2;
+ }
+
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ show_ospf6_interface_common(vty, ospf6->vrf_id, argc,
+ argv, idx_ifname, intf_idx,
+ json_idx);
+
+ if (!all_vrf)
+ break;
+ }
+ }
return CMD_SUCCESS;
}
static int ospf6_interface_show_traffic(struct vty *vty,
struct interface *intf_ifp,
int display_once, json_object *json,
- bool use_json)
+ bool use_json, vrf_id_t vrf_id)
{
struct interface *ifp;
struct vrf *vrf = NULL;
if (intf_ifp)
vrf = vrf_lookup_by_id(intf_ifp->vrf_id);
else
- vrf = vrf_lookup_by_id(VRF_DEFAULT);
+ vrf = vrf_lookup_by_id(vrf_id);
if (!display_once && !use_json) {
vty_out(vty, "\n");
return CMD_SUCCESS;
}
-/* show interface */
-DEFUN(show_ipv6_ospf6_interface_traffic,
- show_ipv6_ospf6_interface_traffic_cmd,
- "show ipv6 ospf6 interface traffic [IFNAME] [json]",
- SHOW_STR
- IP6_STR
- OSPF6_STR
- INTERFACE_STR
- "Protocol Packet counters\n"
- IFNAME_STR
- JSON_STR)
+static int ospf6_interface_show_traffic_common(struct vty *vty, int argc,
+ struct cmd_token **argv,
+ vrf_id_t vrf_id)
{
int idx_ifname = 0;
int display_once = 0;
if (argv_find(argv, argc, "IFNAME", &idx_ifname)) {
intf_name = argv[idx_ifname]->arg;
- ifp = if_lookup_by_name(intf_name, VRF_DEFAULT);
+ ifp = if_lookup_by_name(intf_name, vrf_id);
if (uj) {
if (ifp == NULL) {
json_object_string_add(json, "status",
}
}
- ospf6_interface_show_traffic(vty, ifp, display_once, json, uj);
+ ospf6_interface_show_traffic(vty, ifp, display_once, json, uj, vrf_id);
if (uj) {
vty_out(vty, "%s\n",
json_object_free(json);
}
+ return CMD_SUCCESS;
+}
+
+/* show interface */
+DEFUN(show_ipv6_ospf6_interface_traffic, show_ipv6_ospf6_interface_traffic_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] interface traffic [IFNAME] [json]",
+ SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR
+ "All VRFs\n" INTERFACE_STR
+ "Protocol Packet counters\n" IFNAME_STR JSON_STR)
+{
+ struct ospf6 *ospf6;
+ struct listnode *node;
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ ospf6_interface_show_traffic_common(vty, argc, argv,
+ ospf6->vrf_id);
+
+ if (!all_vrf)
+ break;
+ }
+ }
return CMD_SUCCESS;
}
-DEFUN (show_ipv6_ospf6_interface_ifname_prefix,
- show_ipv6_ospf6_interface_ifname_prefix_cmd,
- "show ipv6 ospf6 interface IFNAME prefix\
+DEFUN(show_ipv6_ospf6_interface_ifname_prefix,
+ show_ipv6_ospf6_interface_ifname_prefix_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] interface IFNAME prefix\
[<\
detail\
|<X:X::X:X|X:X::X:X/M> [<match|detail>]\
>] [json]",
- SHOW_STR
- IP6_STR
- OSPF6_STR
- INTERFACE_STR
- IFNAME_STR
- "Display connected prefixes to advertise\n"
- "Display details of the prefixes\n"
- OSPF6_ROUTE_ADDRESS_STR
- OSPF6_ROUTE_PREFIX_STR
- OSPF6_ROUTE_MATCH_STR
- "Display details of the prefixes\n"
- JSON_STR)
+ SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR
+ "All VRFs\n" INTERFACE_STR IFNAME_STR
+ "Display connected prefixes to advertise\n"
+ "Display details of the prefixes\n" OSPF6_ROUTE_ADDRESS_STR
+ OSPF6_ROUTE_PREFIX_STR OSPF6_ROUTE_MATCH_STR
+ "Display details of the prefixes\n" JSON_STR)
{
int idx_ifname = 4;
int idx_prefix = 6;
- struct interface *ifp;
struct ospf6_interface *oi;
bool uj = use_json(argc, argv);
- ifp = if_lookup_by_name(argv[idx_ifname]->arg, VRF_DEFAULT);
- if (ifp == NULL) {
- vty_out(vty, "No such Interface: %s\n", argv[idx_ifname]->arg);
- return CMD_WARNING;
+ struct ospf6 *ospf6;
+ struct listnode *node;
+ struct interface *ifp;
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (idx_vrf > 0) {
+ idx_ifname += 2;
+ idx_prefix += 2;
}
- oi = ifp->info;
- if (oi == NULL) {
- vty_out(vty, "OSPFv3 is not enabled on %s\n",
- argv[idx_ifname]->arg);
- return CMD_WARNING;
- }
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ ifp = if_lookup_by_name(argv[idx_ifname]->arg,
+ ospf6->vrf_id);
+ if (ifp == NULL) {
+ vty_out(vty, "No such Interface: %s\n",
+ argv[idx_ifname]->arg);
+ return CMD_WARNING;
+ }
- if (CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE)) {
- vty_out(vty, "Interface %s not attached to area\n",
- argv[idx_ifname]->arg);
- return CMD_WARNING;
- }
+ oi = ifp->info;
+ if (oi == NULL
+ || CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE)) {
+ vty_out(vty,
+ "Interface %s not attached to area\n",
+ argv[idx_ifname]->arg);
+ return CMD_WARNING;
+ }
+
+ ospf6_route_table_show(vty, idx_prefix, argc, argv,
+ oi->route_connected, uj);
- ospf6_route_table_show(vty, idx_prefix, argc, argv, oi->route_connected,
- uj);
+ if (!all_vrf)
+ break;
+ }
+ }
return CMD_SUCCESS;
}
-DEFUN (show_ipv6_ospf6_interface_prefix,
- show_ipv6_ospf6_interface_prefix_cmd,
- "show ipv6 ospf6 interface prefix\
+DEFUN(show_ipv6_ospf6_interface_prefix, show_ipv6_ospf6_interface_prefix_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] interface prefix\
[<\
detail\
|<X:X::X:X|X:X::X:X/M> [<match|detail>]\
>] [json]",
- SHOW_STR
- IP6_STR
- OSPF6_STR
- INTERFACE_STR
- "Display connected prefixes to advertise\n"
- "Display details of the prefixes\n"
- OSPF6_ROUTE_ADDRESS_STR
- OSPF6_ROUTE_PREFIX_STR
- OSPF6_ROUTE_MATCH_STR
- "Display details of the prefixes\n"
- JSON_STR)
+ SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR
+ "All VRFs\n" INTERFACE_STR
+ "Display connected prefixes to advertise\n"
+ "Display details of the prefixes\n" OSPF6_ROUTE_ADDRESS_STR
+ OSPF6_ROUTE_PREFIX_STR OSPF6_ROUTE_MATCH_STR
+ "Display details of the prefixes\n" JSON_STR)
{
- struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+ struct vrf *vrf = NULL;
int idx_prefix = 5;
struct ospf6_interface *oi;
struct interface *ifp;
bool uj = use_json(argc, argv);
-
- FOR_ALL_INTERFACES (vrf, ifp) {
- oi = (struct ospf6_interface *)ifp->info;
- if (oi == NULL || CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE))
- continue;
-
- ospf6_route_table_show(vty, idx_prefix, argc, argv,
- oi->route_connected, uj);
+ struct listnode *node;
+ struct ospf6 *ospf6;
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (idx_vrf > 0)
+ idx_prefix += 2;
+
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ vrf = vrf_lookup_by_id(ospf6->vrf_id);
+ FOR_ALL_INTERFACES (vrf, ifp) {
+ oi = (struct ospf6_interface *)ifp->info;
+ if (oi == NULL
+ || CHECK_FLAG(oi->flag,
+ OSPF6_INTERFACE_DISABLE))
+ continue;
+
+ ospf6_route_table_show(vty, idx_prefix, argc,
+ argv,
+ oi->route_connected, uj);
+ }
+ if (!all_vrf)
+ break;
+ }
}
return CMD_SUCCESS;
? OSPF6_INTERFACE_PRIORITY
: strtoul(argv[idx_number]->arg, NULL, 10);
- if (oi->area && (oi->state == OSPF6_INTERFACE_DROTHER
- || oi->state == OSPF6_INTERFACE_BDR
- || oi->state == OSPF6_INTERFACE_DR))
- ospf6_interface_state_change(dr_election(oi), oi);
+ if (oi->area
+ && (oi->state == OSPF6_INTERFACE_DROTHER
+ || oi->state == OSPF6_INTERFACE_BDR
+ || oi->state == OSPF6_INTERFACE_DR)) {
+ if (ospf6_interface_state_change(dr_election(oi), oi) == -1)
+ OSPF6_LINK_LSA_SCHEDULE(oi);
+ }
return CMD_SUCCESS;
}
return CMD_SUCCESS;
}
-static int config_write_ospf6_interface(struct vty *vty)
+static int config_write_ospf6_interface(struct vty *vty, struct vrf *vrf)
{
- struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
struct ospf6_interface *oi;
struct interface *ifp;
if (oi == NULL)
continue;
- vty_frame(vty, "interface %s\n", oi->interface->name);
+ if (vrf->vrf_id == VRF_DEFAULT)
+ vty_frame(vty, "interface %s\n", oi->interface->name);
+ else
+ vty_frame(vty, "interface %s vrf %s\n",
+ oi->interface->name, vrf->name);
if (ifp->desc)
vty_out(vty, " description %s\n", ifp->desc);
return 0;
}
-static int config_write_ospf6_interface(struct vty *vty);
+/* Configuration write function for ospfd. */
+static int config_write_interface(struct vty *vty)
+{
+ int write = 0;
+ struct vrf *vrf = NULL;
+
+ /* Display all VRF aware OSPF interface configuration */
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ write += config_write_ospf6_interface(vty, vrf);
+ }
+
+ return write;
+}
+
+static int config_write_ospf6_interface(struct vty *vty, struct vrf *vrf);
static struct cmd_node interface_node = {
.name = "interface",
.node = INTERFACE_NODE,
.parent_node = CONFIG_NODE,
.prompt = "%s(config-if)# ",
- .config_write = config_write_ospf6_interface,
+ .config_write = config_write_interface,
};
static int ospf6_ifp_create(struct interface *ifp)
char *plist_name;
/* BFD information */
- void *bfd_info;
+ struct {
+ bool enabled;
+ uint8_t detection_multiplier;
+ uint32_t min_rx;
+ uint32_t min_tx;
+ char *profile;
+ } bfd_config;
/* Statistics Fields */
uint32_t hello_in;
if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
zlog_debug(
- "%s: route %pFX %p with final effective paths %u nh%u",
+ "%s: route %pFX %p with final effective paths %u nh %u",
__func__, &route->prefix,
(void *)old_route,
old_route->paths
/* thread master */
master = om6->master;
- vrf_init(NULL, NULL, NULL, NULL, NULL);
+ ospf6_vrf_init();
access_list_init();
prefix_list_init();
ntohs(oh->checksum), oh->instance_id);
}
-void ospf6_hello_print(struct ospf6_header *oh)
+void ospf6_hello_print(struct ospf6_header *oh, int action)
{
struct ospf6_hello *hello;
char options[16];
ntohs(hello->hello_interval), ntohs(hello->dead_interval));
zlog_debug(" DR:%pI4 BDR:%pI4", &hello->drouter, &hello->bdrouter);
- for (p = (char *)((caddr_t)hello + sizeof(struct ospf6_hello));
- p + sizeof(uint32_t) <= OSPF6_MESSAGE_END(oh);
- p += sizeof(uint32_t))
- zlog_debug(" Neighbor: %pI4", (in_addr_t *)p);
+ if ((IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV)
+ && action == OSPF6_ACTION_RECV)
+ || (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND)
+ && action == OSPF6_ACTION_SEND)) {
- assert(p == OSPF6_MESSAGE_END(oh));
+ for (p = (char *)((caddr_t)hello + sizeof(struct ospf6_hello));
+ p + sizeof(uint32_t) <= OSPF6_MESSAGE_END(oh);
+ p += sizeof(uint32_t))
+ zlog_debug(" Neighbor: %pI4", (in_addr_t *)p);
+
+ assert(p == OSPF6_MESSAGE_END(oh));
+ }
}
-void ospf6_dbdesc_print(struct ospf6_header *oh)
+void ospf6_dbdesc_print(struct ospf6_header *oh, int action)
{
struct ospf6_dbdesc *dbdesc;
char options[16];
(CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_MSBIT) ? "m" : "s"),
(unsigned long)ntohl(dbdesc->seqnum));
- for (p = (char *)((caddr_t)dbdesc + sizeof(struct ospf6_dbdesc));
- p + sizeof(struct ospf6_lsa_header) <= OSPF6_MESSAGE_END(oh);
- p += sizeof(struct ospf6_lsa_header))
- ospf6_lsa_header_print_raw((struct ospf6_lsa_header *)p);
+ if ((IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV)
+ && action == OSPF6_ACTION_RECV)
+ || (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND)
+ && action == OSPF6_ACTION_SEND)) {
- assert(p == OSPF6_MESSAGE_END(oh));
+ for (p = (char *)((caddr_t)dbdesc
+ + sizeof(struct ospf6_dbdesc));
+ p + sizeof(struct ospf6_lsa_header)
+ <= OSPF6_MESSAGE_END(oh);
+ p += sizeof(struct ospf6_lsa_header))
+ ospf6_lsa_header_print_raw(
+ (struct ospf6_lsa_header *)p);
+
+ assert(p == OSPF6_MESSAGE_END(oh));
+ }
}
-void ospf6_lsreq_print(struct ospf6_header *oh)
+void ospf6_lsreq_print(struct ospf6_header *oh, int action)
{
char *p;
ospf6_header_print(oh);
assert(oh->type == OSPF6_MESSAGE_TYPE_LSREQ);
- for (p = (char *)((caddr_t)oh + sizeof(struct ospf6_header));
- p + sizeof(struct ospf6_lsreq_entry) <= OSPF6_MESSAGE_END(oh);
- p += sizeof(struct ospf6_lsreq_entry)) {
- struct ospf6_lsreq_entry *e = (struct ospf6_lsreq_entry *)p;
+ if ((IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV)
+ && action == OSPF6_ACTION_RECV)
+ || (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND)
+ && action == OSPF6_ACTION_SEND)) {
+
+ for (p = (char *)((caddr_t)oh + sizeof(struct ospf6_header));
+ p + sizeof(struct ospf6_lsreq_entry)
+ <= OSPF6_MESSAGE_END(oh);
+ p += sizeof(struct ospf6_lsreq_entry)) {
+ struct ospf6_lsreq_entry *e =
+ (struct ospf6_lsreq_entry *)p;
+
+ zlog_debug(" [%s Id:%pI4 Adv:%pI4]",
+ ospf6_lstype_name(e->type), &e->id,
+ &e->adv_router);
+ }
- zlog_debug(" [%s Id:%pI4 Adv:%pI4]",
- ospf6_lstype_name(e->type), &e->id, &e->adv_router);
+ assert(p == OSPF6_MESSAGE_END(oh));
}
-
- assert(p == OSPF6_MESSAGE_END(oh));
}
-void ospf6_lsupdate_print(struct ospf6_header *oh)
+void ospf6_lsupdate_print(struct ospf6_header *oh, int action)
{
struct ospf6_lsupdate *lsupdate;
unsigned long num;
num = ntohl(lsupdate->lsa_number);
zlog_debug(" Number of LSA: %ld", num);
- for (p = (char *)((caddr_t)lsupdate + sizeof(struct ospf6_lsupdate));
- p < OSPF6_MESSAGE_END(oh)
- && p + OSPF6_LSA_SIZE(p) <= OSPF6_MESSAGE_END(oh);
- p += OSPF6_LSA_SIZE(p)) {
- ospf6_lsa_header_print_raw((struct ospf6_lsa_header *)p);
- }
+ if ((IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV)
+ && action == OSPF6_ACTION_RECV)
+ || (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND)
+ && action == OSPF6_ACTION_SEND)) {
+
+ for (p = (char *)((caddr_t)lsupdate
+ + sizeof(struct ospf6_lsupdate));
+ p < OSPF6_MESSAGE_END(oh)
+ && p + OSPF6_LSA_SIZE(p) <= OSPF6_MESSAGE_END(oh);
+ p += OSPF6_LSA_SIZE(p)) {
+ ospf6_lsa_header_print_raw(
+ (struct ospf6_lsa_header *)p);
+ }
- assert(p == OSPF6_MESSAGE_END(oh));
+ assert(p == OSPF6_MESSAGE_END(oh));
+ }
}
-void ospf6_lsack_print(struct ospf6_header *oh)
+void ospf6_lsack_print(struct ospf6_header *oh, int action)
{
char *p;
ospf6_header_print(oh);
assert(oh->type == OSPF6_MESSAGE_TYPE_LSACK);
- for (p = (char *)((caddr_t)oh + sizeof(struct ospf6_header));
- p + sizeof(struct ospf6_lsa_header) <= OSPF6_MESSAGE_END(oh);
- p += sizeof(struct ospf6_lsa_header))
- ospf6_lsa_header_print_raw((struct ospf6_lsa_header *)p);
+ if ((IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV)
+ && action == OSPF6_ACTION_RECV)
+ || (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND)
+ && action == OSPF6_ACTION_SEND)) {
- assert(p == OSPF6_MESSAGE_END(oh));
+ for (p = (char *)((caddr_t)oh + sizeof(struct ospf6_header));
+ p + sizeof(struct ospf6_lsa_header)
+ <= OSPF6_MESSAGE_END(oh);
+ p += sizeof(struct ospf6_lsa_header))
+ ospf6_lsa_header_print_raw(
+ (struct ospf6_lsa_header *)p);
+
+ assert(p == OSPF6_MESSAGE_END(oh));
+ }
}
static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst,
+ sizeof(struct ospf6_header));
if (on->state < OSPF6_NEIGHBOR_INIT) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
zlog_debug("Neighbor state less than Init, ignore");
return;
}
switch (on->state) {
case OSPF6_NEIGHBOR_TWOWAY:
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
zlog_debug("Neighbor state is 2-Way, ignore");
return;
case OSPF6_NEIGHBOR_INIT:
thread_execute(master, twoway_received, on, 0);
if (on->state != OSPF6_NEIGHBOR_EXSTART) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
zlog_debug(
"Neighbor state is not ExStart, ignore");
return;
sizeof(struct ospf6_dbdesc))) {
/* Duplicated DatabaseDescription is dropped by master
*/
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
zlog_debug(
"Duplicated dbdesc discarded by Master, ignore");
return;
}
if (CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_MSBIT)) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
zlog_debug("Master/Slave bit mismatch");
thread_add_event(master, seqnumber_mismatch, on, 0,
NULL);
}
if (CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_IBIT)) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
zlog_debug("Initialize bit mismatch");
thread_add_event(master, seqnumber_mismatch, on, 0,
NULL);
}
if (memcmp(on->options, dbdesc->options, sizeof(on->options))) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
zlog_debug("Option field mismatch");
thread_add_event(master, seqnumber_mismatch, on, 0,
NULL);
}
if (ntohl(dbdesc->seqnum) != on->dbdesc_seqnum) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
zlog_debug(
"Sequence number mismatch (%#lx expected)",
(unsigned long)on->dbdesc_seqnum);
sizeof(struct ospf6_dbdesc))) {
/* Duplicated DatabaseDescription is dropped by master
*/
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
zlog_debug(
"Duplicated dbdesc discarded by Master, ignore");
return;
}
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
zlog_debug("Not duplicate dbdesc in state %s",
ospf6_neighbor_state_str[on->state]);
thread_add_event(master, seqnumber_mismatch, on, 0, NULL);
+ sizeof(struct ospf6_header));
if (on->state < OSPF6_NEIGHBOR_INIT) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
zlog_debug("Neighbor state less than Init, ignore");
return;
}
switch (on->state) {
case OSPF6_NEIGHBOR_TWOWAY:
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
zlog_debug("Neighbor state is 2-Way, ignore");
return;
case OSPF6_NEIGHBOR_INIT:
thread_execute(master, twoway_received, on, 0);
if (on->state != OSPF6_NEIGHBOR_EXSTART) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
zlog_debug(
"Neighbor state is not ExStart, ignore");
return;
sizeof(struct ospf6_dbdesc))) {
/* Duplicated DatabaseDescription causes slave to
* retransmit */
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
zlog_debug(
"Duplicated dbdesc causes retransmit");
THREAD_OFF(on->thread_send_dbdesc);
}
if (!CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_MSBIT)) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
zlog_debug("Master/Slave bit mismatch");
thread_add_event(master, seqnumber_mismatch, on, 0,
NULL);
}
if (CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_IBIT)) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
zlog_debug("Initialize bit mismatch");
thread_add_event(master, seqnumber_mismatch, on, 0,
NULL);
}
if (memcmp(on->options, dbdesc->options, sizeof(on->options))) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
zlog_debug("Option field mismatch");
thread_add_event(master, seqnumber_mismatch, on, 0,
NULL);
}
if (ntohl(dbdesc->seqnum) != on->dbdesc_seqnum + 1) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
zlog_debug(
"Sequence number mismatch (%#lx expected)",
(unsigned long)on->dbdesc_seqnum + 1);
sizeof(struct ospf6_dbdesc))) {
/* Duplicated DatabaseDescription causes slave to
* retransmit */
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
zlog_debug(
"Duplicated dbdesc causes retransmit");
THREAD_OFF(on->thread_send_dbdesc);
return;
}
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
zlog_debug("Not duplicate dbdesc in state %s",
ospf6_neighbor_state_str[on->state]);
thread_add_event(master, seqnumber_mismatch, on, 0, NULL);
on = ospf6_neighbor_lookup(oh->router_id, oi);
if (on == NULL) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
zlog_debug("Neighbor not found, ignore");
return;
}
}
if (dbdesc->reserved1 || dbdesc->reserved2) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
zlog_debug(
"Non-0 reserved field in %s's DbDesc, correct",
on->name);
else if (ntohl(oi->area->ospf6->router_id) < ntohl(oh->router_id))
ospf6_dbdesc_recv_slave(oh, on);
else {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
zlog_debug("Can't decide which is master, ignore");
}
}
on = ospf6_neighbor_lookup(oh->router_id, oi);
if (on == NULL) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
zlog_debug("Neighbor not found, ignore");
return;
}
if (on->state != OSPF6_NEIGHBOR_EXCHANGE
&& on->state != OSPF6_NEIGHBOR_LOADING
&& on->state != OSPF6_NEIGHBOR_FULL) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
zlog_debug("Neighbor state less than Exchange, ignore");
return;
}
while (length) {
if (length < OSPF6_PREFIX_MIN_SIZE) {
if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV))
+ RECV_HDR))
zlog_debug("%s: undersized IPv6 prefix header",
__func__);
return MSG_NG;
/* safe to look deeper */
if (current->prefix_length > IPV6_MAX_BITLEN) {
if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV))
+ RECV_HDR))
zlog_debug("%s: invalid PrefixLength (%u bits)",
__func__, current->prefix_length);
return MSG_NG;
+ OSPF6_PREFIX_SPACE(current->prefix_length);
if (requested_pfx_bytes > length) {
if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV))
+ RECV_HDR))
zlog_debug("%s: undersized IPv6 prefix",
__func__);
return MSG_NG;
real_num_pfxs++;
}
if (real_num_pfxs != req_num_pfxs) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
+ RECV_HDR))
zlog_debug(
"%s: IPv6 prefix number mismatch (%u required, %u real)",
__func__, req_num_pfxs, real_num_pfxs);
ltindex = lsatype & OSPF6_LSTYPE_FCODE_MASK;
if (ltindex < OSPF6_LSTYPE_SIZE && ospf6_lsa_minlen[ltindex]
&& lsalen < ospf6_lsa_minlen[ltindex] + OSPF6_LSA_HEADER_SIZE) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
+ RECV_HDR))
zlog_debug("%s: undersized (%u B) LSA", __func__,
lsalen);
return MSG_NG;
if ((lsalen - OSPF6_LSA_HEADER_SIZE - OSPF6_ROUTER_LSA_MIN_SIZE)
% OSPF6_ROUTER_LSDESC_FIX_SIZE) {
if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV))
+ RECV_HDR))
zlog_debug(
"%s: interface description alignment error",
__func__);
- OSPF6_NETWORK_LSA_MIN_SIZE)
% OSPF6_NETWORK_LSDESC_FIX_SIZE) {
if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV))
+ RECV_HDR))
zlog_debug(
"%s: router description alignment error",
__func__);
if (lsalen
> OSPF6_LSA_HEADER_SIZE + OSPF6_INTER_ROUTER_LSA_FIX_SIZE) {
if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV))
+ RECV_HDR))
zlog_debug("%s: oversized (%u B) LSA", __func__,
lsalen);
return MSG_NG;
prefix before ospf6_prefix_examin() confirms its sizing. */
if (exp_length + OSPF6_PREFIX_MIN_SIZE > lsalen) {
if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV))
+ RECV_HDR))
zlog_debug("%s: undersized (%u B) LSA header",
__func__, lsalen);
return MSG_NG;
this check does not include any IPv6 prefix fields. */
if (exp_length > lsalen) {
if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV))
+ RECV_HDR))
zlog_debug("%s: undersized (%u B) LSA header",
__func__, lsalen);
return MSG_NG;
uint16_t lsalen;
if (length < OSPF6_LSA_HEADER_SIZE) {
if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV))
+ RECV_HDR))
zlog_debug(
"%s: undersized (%zu B) trailing (#%u) LSA header",
__func__, length, counted_lsas);
lsalen = OSPF6_LSA_SIZE(lsah);
if (lsalen < OSPF6_LSA_HEADER_SIZE) {
if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
- RECV))
+ RECV_HDR))
zlog_debug(
"%s: malformed LSA header #%u, declared length is %u B",
__func__, counted_lsas, lsalen);
/* less checks here and in ospf6_lsa_examin() */
if (MSG_OK != ospf6_lsa_examin(lsah, lsalen, 1)) {
if (IS_OSPF6_DEBUG_MESSAGE(
- OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ OSPF6_MESSAGE_TYPE_UNKNOWN,
+ RECV_HDR))
zlog_debug(
"%s: anomaly in header-only %s LSA #%u",
__func__,
* further checks */
if (lsalen > length) {
if (IS_OSPF6_DEBUG_MESSAGE(
- OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ OSPF6_MESSAGE_TYPE_UNKNOWN,
+ RECV_HDR))
zlog_debug(
"%s: anomaly in %s LSA #%u: declared length is %u B, buffered length is %zu B",
__func__,
}
if (MSG_OK != ospf6_lsa_examin(lsah, lsalen, 0)) {
if (IS_OSPF6_DEBUG_MESSAGE(
- OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ OSPF6_MESSAGE_TYPE_UNKNOWN,
+ RECV_HDR))
zlog_debug(
"%s: anomaly in %s LSA #%u",
__func__,
}
if (declared_num_lsas && counted_lsas != declared_num_lsas) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
+ RECV_HDR))
zlog_debug(
"%s: #LSAs declared (%u) does not match actual (%u)",
__func__, declared_num_lsas, counted_lsas);
/* length, 1st approximation */
if (bytesonwire < OSPF6_HEADER_SIZE) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
+ RECV_HDR))
zlog_debug("%s: undersized (%u B) packet", __func__,
bytesonwire);
return MSG_NG;
}
/* Now it is safe to access header fields. */
if (bytesonwire != ntohs(oh->length)) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
+ RECV_HDR))
zlog_debug(
"%s: %s packet length error (%u real, %u declared)",
__func__, lookup_msg(ospf6_message_type_str,
}
/* version check */
if (oh->version != OSPFV3_VERSION) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
+ RECV_HDR))
zlog_debug("%s: invalid (%u) protocol version",
__func__, oh->version);
return MSG_NG;
if (oh->type < OSPF6_MESSAGE_TYPE_ALL && ospf6_packet_minlen[oh->type]
&& bytesonwire
< OSPF6_HEADER_SIZE + ospf6_packet_minlen[oh->type]) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
+ RECV_HDR))
zlog_debug("%s: undersized (%u B) %s packet", __func__,
bytesonwire,
lookup_msg(ospf6_message_type_str, oh->type,
== (bytesonwire - OSPF6_HEADER_SIZE - OSPF6_HELLO_MIN_SIZE)
% 4)
return MSG_OK;
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
+ RECV_HDR))
zlog_debug("%s: alignment error in %s packet", __func__,
lookup_msg(ospf6_message_type_str, oh->type,
NULL));
== (bytesonwire - OSPF6_HEADER_SIZE - OSPF6_LS_REQ_MIN_SIZE)
% OSPF6_LSREQ_LSDESC_FIX_SIZE)
return MSG_OK;
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
+ RECV_HDR))
zlog_debug("%s: alignment error in %s packet", __func__,
lookup_msg(ospf6_message_type_str, oh->type,
NULL));
1, 0);
break;
default:
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
+ RECV_HDR))
zlog_debug("%s: invalid (%u) message type", __func__,
oh->type);
return MSG_NG;
}
if (test != MSG_OK
- && IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ && IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN, RECV_HDR))
zlog_debug("%s: anomaly in %s packet", __func__,
lookup_msg(ospf6_message_type_str, oh->type, NULL));
return test;
on = ospf6_neighbor_lookup(oh->router_id, oi);
if (on == NULL) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
zlog_debug("Neighbor not found, ignore");
return;
}
if (on->state != OSPF6_NEIGHBOR_EXCHANGE
&& on->state != OSPF6_NEIGHBOR_LOADING
&& on->state != OSPF6_NEIGHBOR_FULL) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
zlog_debug("Neighbor state less than Exchange, ignore");
return;
}
on = ospf6_neighbor_lookup(oh->router_id, oi);
if (on == NULL) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
zlog_debug("Neighbor not found, ignore");
return;
}
if (on->state != OSPF6_NEIGHBOR_EXCHANGE
&& on->state != OSPF6_NEIGHBOR_LOADING
&& on->state != OSPF6_NEIGHBOR_FULL) {
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
zlog_debug("Neighbor state less than Exchange, ignore");
return;
}
oi = ospf6_interface_lookup_by_ifindex(ifindex, ospf6->vrf_id);
if (oi == NULL || oi->area == NULL
|| CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE)) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
+ RECV_HDR))
zlog_debug("Message received on disabled interface");
return 0;
}
if (CHECK_FLAG(oi->flag, OSPF6_INTERFACE_PASSIVE)) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
+ RECV_HDR))
zlog_debug("%s: Ignore message on passive interface %s",
__func__, oi->interface->name);
return 0;
which can be dismissed in a cleanup-focused review round later. */
/* Log */
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV)) {
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR)) {
zlog_debug("%s received on %s",
lookup_msg(ospf6_message_type_str, oh->type, NULL),
oi->interface->name);
switch (oh->type) {
case OSPF6_MESSAGE_TYPE_HELLO:
- ospf6_hello_print(oh);
+ ospf6_hello_print(oh, OSPF6_ACTION_RECV);
break;
case OSPF6_MESSAGE_TYPE_DBDESC:
- ospf6_dbdesc_print(oh);
+ ospf6_dbdesc_print(oh, OSPF6_ACTION_RECV);
break;
case OSPF6_MESSAGE_TYPE_LSREQ:
- ospf6_lsreq_print(oh);
+ ospf6_lsreq_print(oh, OSPF6_ACTION_RECV);
break;
case OSPF6_MESSAGE_TYPE_LSUPDATE:
- ospf6_lsupdate_print(oh);
+ ospf6_lsupdate_print(oh, OSPF6_ACTION_RECV);
break;
case OSPF6_MESSAGE_TYPE_LSACK:
- ospf6_lsack_print(oh);
+ ospf6_lsack_print(oh, OSPF6_ACTION_RECV);
break;
default:
assert(0);
oh->reserved = 0;
/* Log */
- if (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND)) {
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND_HDR)) {
if (src)
inet_ntop(AF_INET6, src, srcname, sizeof(srcname));
else
switch (oh->type) {
case OSPF6_MESSAGE_TYPE_HELLO:
- ospf6_hello_print(oh);
+ ospf6_hello_print(oh, OSPF6_ACTION_RECV);
break;
case OSPF6_MESSAGE_TYPE_DBDESC:
- ospf6_dbdesc_print(oh);
+ ospf6_dbdesc_print(oh, OSPF6_ACTION_RECV);
break;
case OSPF6_MESSAGE_TYPE_LSREQ:
- ospf6_lsreq_print(oh);
+ ospf6_lsreq_print(oh, OSPF6_ACTION_RECV);
break;
case OSPF6_MESSAGE_TYPE_LSUPDATE:
- ospf6_lsupdate_print(oh);
+ ospf6_lsupdate_print(oh, OSPF6_ACTION_RECV);
break;
case OSPF6_MESSAGE_TYPE_LSACK:
- ospf6_lsack_print(oh);
+ ospf6_lsack_print(oh, OSPF6_ACTION_RECV);
break;
default:
zlog_debug("Unknown message");
oi->thread_send_hello = (struct thread *)NULL;
if (oi->state <= OSPF6_INTERFACE_DOWN) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_HELLO, SEND))
+ if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_HELLO, SEND_HDR))
zlog_debug("Unable to send Hello on down interface %s",
oi->interface->name);
return 0;
if (p - sendbuf + sizeof(uint32_t) > ospf6_packet_max(oi)) {
if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_HELLO,
- SEND))
+ SEND_HDR))
zlog_debug(
"sending Hello message: exceeds I/F MTU");
break;
on->thread_send_dbdesc = (struct thread *)NULL;
if (on->state < OSPF6_NEIGHBOR_EXSTART) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_DBDESC, SEND))
+ if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_DBDESC, SEND_HDR))
zlog_debug(
"Quit to send DbDesc to neighbor %s state %s",
on->name, ospf6_neighbor_state_str[on->state]);
/* LSReq will be sent only in ExStart or Loading */
if (on->state != OSPF6_NEIGHBOR_EXCHANGE
&& on->state != OSPF6_NEIGHBOR_LOADING) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_LSREQ, SEND))
+ if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_LSREQ, SEND_HDR))
zlog_debug("Quit to send LSReq to neighbor %s state %s",
on->name,
ospf6_neighbor_state_str[on->state]);
on = (struct ospf6_neighbor *)THREAD_ARG(thread);
on->thread_send_lsupdate = (struct thread *)NULL;
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_LSUPDATE, SEND))
+ if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_LSUPDATE, SEND_HDR))
zlog_debug("LSUpdate to neighbor %s", on->name);
if (on->state < OSPF6_NEIGHBOR_EXCHANGE) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_LSUPDATE, SEND))
+ if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_LSUPDATE,
+ SEND_HDR))
zlog_debug("Quit to send (neighbor state %s)",
ospf6_neighbor_state_str[on->state]);
return 0;
lsupdate->lsa_number = htonl(lsa_cnt);
if (IS_OSPF6_DEBUG_FLOODING
- || IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_LSUPDATE, SEND))
+ || IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_LSUPDATE, SEND_HDR))
zlog_debug("%s: Send lsupdate with lsa %s (age %u)", __func__,
lsa->name, ntohs(lsa->header->age));
oi->thread_send_lsupdate = (struct thread *)NULL;
if (oi->state <= OSPF6_INTERFACE_WAITING) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_LSUPDATE, SEND))
+ if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_LSUPDATE,
+ SEND_HDR))
zlog_debug(
"Quit to send LSUpdate to interface %s state %s",
oi->interface->name,
on->thread_send_lsack = (struct thread *)NULL;
if (on->state < OSPF6_NEIGHBOR_EXCHANGE) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_LSACK, SEND))
+ if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_LSACK, SEND_HDR))
zlog_debug("Quit to send LSAck to neighbor %s state %s",
on->name,
ospf6_neighbor_state_str[on->state]);
oi->thread_send_lsack = (struct thread *)NULL;
if (oi->state <= OSPF6_INTERFACE_WAITING) {
- if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_LSACK, SEND))
+ if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_LSACK, SEND_HDR))
zlog_debug(
"Quit to send LSAck to interface %s state %s",
oi->interface->name,
/* Commands */
-DEFUN (debug_ospf6_message,
- debug_ospf6_message_cmd,
- "debug ospf6 message <unknown|hello|dbdesc|lsreq|lsupdate|lsack|all> [<send|recv>]",
- DEBUG_STR
- OSPF6_STR
- "Debug OSPFv3 message\n"
- "Debug Unknown message\n"
- "Debug Hello message\n"
- "Debug Database Description message\n"
- "Debug Link State Request message\n"
- "Debug Link State Update message\n"
- "Debug Link State Acknowledgement message\n"
- "Debug All message\n"
- "Debug only sending message\n"
- "Debug only receiving message\n")
+DEFUN(debug_ospf6_message, debug_ospf6_message_cmd,
+ "debug ospf6 message <unknown|hello|dbdesc|lsreq|lsupdate|lsack|all> [<send|recv|send-hdr|recv-hdr>]",
+ DEBUG_STR OSPF6_STR
+ "Debug OSPFv3 message\n"
+ "Debug Unknown message\n"
+ "Debug Hello message\n"
+ "Debug Database Description message\n"
+ "Debug Link State Request message\n"
+ "Debug Link State Update message\n"
+ "Debug Link State Acknowledgement message\n"
+ "Debug All message\n"
+ "Debug only sending message, entire packet\n"
+ "Debug only receiving message, entire packet\n"
+ "Debug only sending message, header only\n"
+ "Debug only receiving message, header only\n")
{
int idx_packet = 3;
int idx_send_recv = 4;
if (argc == 4)
level = OSPF6_DEBUG_MESSAGE_SEND | OSPF6_DEBUG_MESSAGE_RECV;
+ else if (!strncmp(argv[idx_send_recv]->arg, "send-h", 6))
+ level = OSPF6_DEBUG_MESSAGE_SEND_HDR;
else if (!strncmp(argv[idx_send_recv]->arg, "s", 1))
level = OSPF6_DEBUG_MESSAGE_SEND;
+ else if (!strncmp(argv[idx_send_recv]->arg, "recv-h", 6))
+ level = OSPF6_DEBUG_MESSAGE_RECV_HDR;
else if (!strncmp(argv[idx_send_recv]->arg, "r", 1))
level = OSPF6_DEBUG_MESSAGE_RECV;
return CMD_SUCCESS;
}
-DEFUN (no_debug_ospf6_message,
- no_debug_ospf6_message_cmd,
- "no debug ospf6 message <unknown|hello|dbdesc|lsreq|lsupdate|lsack|all> [<send|recv>]",
- NO_STR
- DEBUG_STR
- OSPF6_STR
- "Debug OSPFv3 message\n"
- "Debug Unknown message\n"
- "Debug Hello message\n"
- "Debug Database Description message\n"
- "Debug Link State Request message\n"
- "Debug Link State Update message\n"
- "Debug Link State Acknowledgement message\n"
- "Debug All message\n"
- "Debug only sending message\n"
- "Debug only receiving message\n")
+DEFUN(no_debug_ospf6_message, no_debug_ospf6_message_cmd,
+ "no debug ospf6 message <unknown|hello|dbdesc|lsreq|lsupdate|lsack|all> [<send|recv|send-hdr|recv-hdr>]",
+ NO_STR DEBUG_STR OSPF6_STR
+ "Debug OSPFv3 message\n"
+ "Debug Unknown message\n"
+ "Debug Hello message\n"
+ "Debug Database Description message\n"
+ "Debug Link State Request message\n"
+ "Debug Link State Update message\n"
+ "Debug Link State Acknowledgement message\n"
+ "Debug All message\n"
+ "Debug only sending message, entire pkt\n"
+ "Debug only receiving message, entire pkt\n"
+ "Debug only sending message, header only\n"
+ "Debug only receiving message, header only\n")
{
int idx_packet = 4;
int idx_send_recv = 5;
type = OSPF6_MESSAGE_TYPE_ALL;
if (argc == 5)
- level = OSPF6_DEBUG_MESSAGE_SEND | OSPF6_DEBUG_MESSAGE_RECV;
+ level = OSPF6_DEBUG_MESSAGE_SEND | OSPF6_DEBUG_MESSAGE_RECV
+ | OSPF6_DEBUG_MESSAGE_SEND_HDR
+ | OSPF6_DEBUG_MESSAGE_RECV_HDR;
+ else if (!strncmp(argv[idx_send_recv]->arg, "send-h", 6))
+ level = OSPF6_DEBUG_MESSAGE_SEND_HDR;
else if (!strncmp(argv[idx_send_recv]->arg, "s", 1))
level = OSPF6_DEBUG_MESSAGE_SEND;
+ else if (!strncmp(argv[idx_send_recv]->arg, "recv-h", 6))
+ level = OSPF6_DEBUG_MESSAGE_RECV_HDR;
else if (!strncmp(argv[idx_send_recv]->arg, "r", 1))
level = OSPF6_DEBUG_MESSAGE_RECV;
{
const char *type_str[] = {"unknown", "hello", "dbdesc",
"lsreq", "lsupdate", "lsack"};
- unsigned char s = 0, r = 0;
+ unsigned char s = 0, r = 0, sh = 0, rh = 0;
int i;
for (i = 0; i < 6; i++) {
- if (IS_OSPF6_DEBUG_MESSAGE(i, SEND))
+ if (IS_OSPF6_DEBUG_MESSAGE_ENABLED(i, SEND))
s |= 1 << i;
- if (IS_OSPF6_DEBUG_MESSAGE(i, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE_ENABLED(i, RECV))
r |= 1 << i;
}
+ for (i = 0; i < 6; i++) {
+ if (IS_OSPF6_DEBUG_MESSAGE_ENABLED(i, SEND_HDR))
+ sh |= 1 << i;
+ if (IS_OSPF6_DEBUG_MESSAGE_ENABLED(i, RECV_HDR))
+ rh |= 1 << i;
+ }
+
if (s == 0x3f && r == 0x3f) {
vty_out(vty, "debug ospf6 message all\n");
return 0;
return 0;
}
+ if (sh == 0x3f && rh == 0) {
+ vty_out(vty, "debug ospf6 message all send-hdr\n");
+ return 0;
+ } else if (sh == 0 && rh == 0x3f) {
+ vty_out(vty, "debug ospf6 message all recv-hdr\n");
+ return 0;
+ }
+
/* Unknown message is logged by default */
if (!IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN, SEND)
&& !IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
vty_out(vty, "no debug ospf6 message unknown recv\n");
for (i = 1; i < 6; i++) {
- if (IS_OSPF6_DEBUG_MESSAGE(i, SEND)
- && IS_OSPF6_DEBUG_MESSAGE(i, RECV))
+ if (IS_OSPF6_DEBUG_MESSAGE_ENABLED(i, SEND)
+ && IS_OSPF6_DEBUG_MESSAGE_ENABLED(i, RECV))
vty_out(vty, "debug ospf6 message %s\n", type_str[i]);
- else if (IS_OSPF6_DEBUG_MESSAGE(i, SEND))
+ else if (IS_OSPF6_DEBUG_MESSAGE_ENABLED(i, SEND))
vty_out(vty, "debug ospf6 message %s send\n",
type_str[i]);
- else if (IS_OSPF6_DEBUG_MESSAGE(i, RECV))
+ else if (IS_OSPF6_DEBUG_MESSAGE_ENABLED(i, RECV))
vty_out(vty, "debug ospf6 message %s recv\n",
type_str[i]);
+ else if (IS_OSPF6_DEBUG_MESSAGE_ENABLED(i, SEND_HDR)
+ && IS_OSPF6_DEBUG_MESSAGE_ENABLED(i, RECV_HDR))
+ vty_out(vty, "debug ospf6 message %s; header only\n",
+ type_str[i]);
+ else if (IS_OSPF6_DEBUG_MESSAGE_ENABLED(i, RECV_HDR))
+ vty_out(vty, "debug ospf6 message %s recv-hdr\n",
+ type_str[i]);
+ else if (IS_OSPF6_DEBUG_MESSAGE_ENABLED(i, SEND_HDR))
+ vty_out(vty, "debug ospf6 message %s send-hdr\n",
+ type_str[i]);
}
return 0;
/* Debug option */
extern unsigned char conf_debug_ospf6_message[];
+#define OSPF6_ACTION_SEND 0x01
+#define OSPF6_ACTION_RECV 0x02
#define OSPF6_DEBUG_MESSAGE_SEND 0x01
#define OSPF6_DEBUG_MESSAGE_RECV 0x02
+#define OSPF6_DEBUG_MESSAGE_SEND_HDR 0x04
+#define OSPF6_DEBUG_MESSAGE_RECV_HDR 0x08
+#define OSPF6_DEBUG_MESSAGE_SEND_BOTH \
+ OSPF6_DEBUG_MESSAGE_SEND | OSPF6_DEBUG_MESSAGE_SEND_HDR
+#define OSPF6_DEBUG_MESSAGE_RECV_BOTH \
+ OSPF6_DEBUG_MESSAGE_RECV | OSPF6_DEBUG_MESSAGE_RECV_HDR
+
#define OSPF6_DEBUG_MESSAGE_ON(type, level) \
(conf_debug_ospf6_message[type] |= (level))
#define OSPF6_DEBUG_MESSAGE_OFF(type, level) \
(conf_debug_ospf6_message[type] &= ~(level))
+
#define IS_OSPF6_DEBUG_MESSAGE(t, e) \
- (conf_debug_ospf6_message[t] & OSPF6_DEBUG_MESSAGE_##e)
+ ((OSPF6_DEBUG_MESSAGE_##e) == OSPF6_DEBUG_MESSAGE_RECV_HDR) \
+ ? (conf_debug_ospf6_message[t] \
+ & (OSPF6_DEBUG_MESSAGE_RECV_BOTH)) \
+ : (((OSPF6_DEBUG_MESSAGE_##e) == OSPF6_DEBUG_MESSAGE_SEND_HDR) \
+ ? (conf_debug_ospf6_message[t] \
+ & (OSPF6_DEBUG_MESSAGE_SEND_BOTH)) \
+ : (conf_debug_ospf6_message[t] \
+ & (OSPF6_DEBUG_MESSAGE_##e)))
+
+#define IS_OSPF6_DEBUG_MESSAGE_ENABLED(type, e) \
+ (conf_debug_ospf6_message[type] & (OSPF6_DEBUG_MESSAGE_##e))
/* Type */
#define OSPF6_MESSAGE_TYPE_UNKNOWN 0x0
/* It is just a sequence of LSA Headers */
/* Function definition */
-extern void ospf6_hello_print(struct ospf6_header *);
-extern void ospf6_dbdesc_print(struct ospf6_header *);
-extern void ospf6_lsreq_print(struct ospf6_header *);
-extern void ospf6_lsupdate_print(struct ospf6_header *);
-extern void ospf6_lsack_print(struct ospf6_header *);
+extern void ospf6_hello_print(struct ospf6_header *, int action);
+extern void ospf6_dbdesc_print(struct ospf6_header *, int action);
+extern void ospf6_lsreq_print(struct ospf6_header *, int action);
+extern void ospf6_lsupdate_print(struct ospf6_header *, int action);
+extern void ospf6_lsack_print(struct ospf6_header *, int action);
extern int ospf6_iobuf_size(unsigned int size);
extern void ospf6_message_terminate(void);
#include "linklist.h"
#include "vty.h"
#include "command.h"
+#include "lib/bfd.h"
#include "ospf6_proto.h"
#include "ospf6_lsa.h"
THREAD_OFF(on->thread_send_lsupdate);
THREAD_OFF(on->thread_send_lsack);
- ospf6_bfd_reg_dereg_nbr(on, ZEBRA_BFD_DEST_DEREGISTER);
+ bfd_sess_free(&on->bfd_session);
XFREE(MTYPE_OSPF6_NEIGHBOR, on);
}
json_object_object_add(json_neighbor, "pendingLsaLsAck",
json_array);
- ospf6_bfd_show_info(vty, on->bfd_info, 0, json_neighbor,
- use_json);
+ bfd_sess_show(vty, json_neighbor, on->bfd_session);
json_object_object_add(json, on->name, json_neighbor);
for (ALL_LSDB(on->lsack_list, lsa, lsanext))
vty_out(vty, " %s\n", lsa->name);
- ospf6_bfd_show_info(vty, on->bfd_info, 0, NULL, use_json);
+ bfd_sess_show(vty, NULL, on->bfd_session);
}
}
-DEFUN (show_ipv6_ospf6_neighbor,
- show_ipv6_ospf6_neighbor_cmd,
- "show ipv6 ospf6 neighbor [<detail|drchoice>] [json]",
- SHOW_STR
- IP6_STR
- OSPF6_STR
- "Neighbor list\n"
- "Display details\n"
- "Display DR choices\n"
- JSON_STR)
+static void ospf6_neighbor_show_detail_common(struct vty *vty, int argc,
+ struct cmd_token **argv,
+ struct ospf6 *ospf6, int idx_type,
+ int detail_idx, int json_idx)
{
- int idx_type = 4;
struct ospf6_neighbor *on;
struct ospf6_interface *oi;
struct ospf6_area *oa;
struct listnode *i, *j, *k;
- struct ospf6 *ospf6;
json_object *json = NULL;
json_object *json_array = NULL;
bool uj = use_json(argc, argv);
void (*showfunc)(struct vty *, struct ospf6_neighbor *,
json_object *json, bool use_json);
- ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
-
- OSPF6_CMD_CHECK_RUNNING(ospf6);
showfunc = ospf6_neighbor_show;
- if ((uj && argc == 6) || (!uj && argc == 5)) {
+ if ((uj && argc == detail_idx) || (!uj && argc == json_idx)) {
if (!strncmp(argv[idx_type]->arg, "de", 2))
showfunc = ospf6_neighbor_show_detail;
else if (!strncmp(argv[idx_type]->arg, "dr", 2))
json, JSON_C_TO_STRING_PRETTY));
json_object_free(json);
}
- return CMD_SUCCESS;
}
+DEFUN(show_ipv6_ospf6_neighbor, show_ipv6_ospf6_neighbor_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] neighbor [<detail|drchoice>] [json]",
+ SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "Neighbor list\n"
+ "Display details\n"
+ "Display DR choices\n" JSON_STR)
+{
+ int idx_type = 4;
+ int detail_idx = 5;
+ int json_idx = 6;
+ struct ospf6 *ospf6;
+ struct listnode *node;
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (idx_vrf > 0) {
+ idx_type += 2;
+ detail_idx += 2;
+ json_idx += 2;
+ }
+
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ ospf6_neighbor_show_detail_common(vty, argc, argv,
+ ospf6, idx_type,
+ detail_idx, json_idx);
+ if (!all_vrf)
+ break;
+ }
+ }
-DEFUN (show_ipv6_ospf6_neighbor_one,
- show_ipv6_ospf6_neighbor_one_cmd,
- "show ipv6 ospf6 neighbor A.B.C.D [json]",
- SHOW_STR
- IP6_STR
- OSPF6_STR
- "Neighbor list\n"
- "Specify Router-ID as IPv4 address notation\n"
- JSON_STR)
+ return CMD_SUCCESS;
+}
+
+static int ospf6_neighbor_show_common(struct vty *vty, int argc,
+ struct cmd_token **argv,
+ struct ospf6 *ospf6, int idx_ipv4)
{
- int idx_ipv4 = 4;
struct ospf6_neighbor *on;
struct ospf6_interface *oi;
struct ospf6_area *oa;
void (*showfunc)(struct vty *, struct ospf6_neighbor *,
json_object *json, bool use_json);
uint32_t router_id;
- struct ospf6 *ospf6;
json_object *json = NULL;
bool uj = use_json(argc, argv);
- ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
- OSPF6_CMD_CHECK_RUNNING(ospf6);
showfunc = ospf6_neighbor_show_detail;
if (uj)
json = json_object_new_object();
json, JSON_C_TO_STRING_PRETTY));
json_object_free(json);
}
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(show_ipv6_ospf6_neighbor_one, show_ipv6_ospf6_neighbor_one_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] neighbor A.B.C.D [json]",
+ SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "Neighbor list\n"
+ "Specify Router-ID as IPv4 address notation\n" JSON_STR)
+{
+ int idx_ipv4 = 4;
+ struct ospf6 *ospf6;
+ struct listnode *node;
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (idx_vrf > 0)
+ idx_ipv4 += 2;
+
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ ospf6_neighbor_show_common(vty, argc, argv, ospf6,
+ idx_ipv4);
+
+ if (!all_vrf)
+ break;
+ }
+ }
+
return CMD_SUCCESS;
}
struct thread *thread_send_lsack;
/* BFD information */
- void *bfd_info;
+ struct bfd_session_params *bfd_session;
};
/* Neighbor state */
/* VTY commands */
void ospf6_route_show(struct vty *vty, struct ospf6_route *route,
- json_object *json_array_routes, bool use_json)
+ json_object *json_routes, bool use_json)
{
int i;
char destination[PREFIX2STR_BUFFER], nexthop[64];
if (use_json) {
json_route = json_object_new_object();
- json_object_string_add(json_route, "destination", destination);
json_object_boolean_add(json_route, "isBestRoute",
ospf6_route_is_best(route));
json_object_string_add(json_route, "destinationType",
if (use_json) {
json_object_object_add(json_route, "nextHops",
json_array_next_hops);
- json_object_array_add(json_array_routes, json_route);
+ json_object_object_add(json_routes, destination, json_route);
}
}
void ospf6_route_show_detail(struct vty *vty, struct ospf6_route *route,
- json_object *json_array_routes, bool use_json)
+ json_object *json_routes, bool use_json)
{
char destination[PREFIX2STR_BUFFER], nexthop[64];
char area_id[16], id[16], adv_router[16], capa[16], options[16];
if (use_json) {
json_route = json_object_new_object();
- json_object_string_add(json_route, "destination", destination);
json_object_string_add(json_route, "destinationType",
OSPF6_DEST_TYPE_NAME(route->type));
} else {
if (use_json) {
json_object_object_add(json_route, "nextHops",
json_array_next_hops);
- json_object_array_add(json_array_routes, json_route);
+ json_object_object_add(json_routes, destination, json_route);
} else
vty_out(vty, "\n");
}
json_object *json, bool use_json)
{
struct ospf6_route *route;
- json_object *json_array_routes = NULL;
+ json_object *json_routes = NULL;
route = ospf6_route_lookup(prefix, table);
if (route == NULL)
return;
if (use_json)
- json_array_routes = json_object_new_array();
+ json_routes = json_object_new_object();
ospf6_route_lock(route);
while (route && ospf6_route_is_prefix(prefix, route)) {
/* Specifying a prefix will always display details */
- ospf6_route_show_detail(vty, route, json_array_routes,
- use_json);
+ ospf6_route_show_detail(vty, route, json_routes, use_json);
route = ospf6_route_next(route);
}
if (use_json)
- json_object_object_add(json, "routes", json_array_routes);
+ json_object_object_add(json, "routes", json_routes);
if (route)
ospf6_route_unlock(route);
}
json_object *json, bool use_json)
{
struct ospf6_route *route;
- json_object *json_array_routes = NULL;
+ json_object *json_routes = NULL;
route = ospf6_route_lookup_bestmatch(prefix, table);
if (route == NULL)
return;
if (use_json)
- json_array_routes = json_object_new_array();
+ json_routes = json_object_new_object();
prefix = &route->prefix;
ospf6_route_lock(route);
while (route && ospf6_route_is_prefix(prefix, route)) {
/* Specifying a prefix will always display details */
- ospf6_route_show_detail(vty, route, json_array_routes,
- use_json);
+ ospf6_route_show_detail(vty, route, json_routes, use_json);
route = ospf6_route_next(route);
}
if (use_json)
- json_object_object_add(json, "routes", json_array_routes);
+ json_object_object_add(json, "routes", json_routes);
if (route)
ospf6_route_unlock(route);
}
json_object *json, bool use_json)
{
struct ospf6_route *route;
- json_object *json_array_routes = NULL;
+ json_object *json_routes = NULL;
assert(prefix->family);
route = ospf6_route_match_head(prefix, table);
if (use_json)
- json_array_routes = json_object_new_array();
+ json_routes = json_object_new_object();
while (route) {
if (detail)
- ospf6_route_show_detail(vty, route, json_array_routes,
+ ospf6_route_show_detail(vty, route, json_routes,
use_json);
else
- ospf6_route_show(vty, route, json_array_routes,
- use_json);
+ ospf6_route_show(vty, route, json_routes, use_json);
route = ospf6_route_match_next(prefix, route);
}
if (use_json)
- json_object_object_add(json, "routes", json_array_routes);
+ json_object_object_add(json, "routes", json_routes);
}
static void ospf6_route_show_table_type(struct vty *vty, int detail,
json_object *json, bool use_json)
{
struct ospf6_route *route;
- json_object *json_array_routes = NULL;
+ json_object *json_routes = NULL;
route = ospf6_route_head(table);
if (use_json)
- json_array_routes = json_object_new_array();
+ json_routes = json_object_new_object();
while (route) {
if (route->path.type == type) {
if (detail)
- ospf6_route_show_detail(vty, route,
- json_array_routes,
+ ospf6_route_show_detail(vty, route, json_routes,
use_json);
else
- ospf6_route_show(vty, route, json_array_routes,
+ ospf6_route_show(vty, route, json_routes,
use_json);
}
route = ospf6_route_next(route);
}
if (use_json)
- json_object_object_add(json, "routes", json_array_routes);
+ json_object_object_add(json, "routes", json_routes);
}
static void ospf6_route_show_table(struct vty *vty, int detail,
json_object *json, bool use_json)
{
struct ospf6_route *route;
- json_object *json_array_routes = NULL;
+ json_object *json_routes = NULL;
route = ospf6_route_head(table);
if (use_json)
- json_array_routes = json_object_new_array();
+ json_routes = json_object_new_object();
while (route) {
if (detail)
- ospf6_route_show_detail(vty, route, json_array_routes,
+ ospf6_route_show_detail(vty, route, json_routes,
use_json);
else
- ospf6_route_show(vty, route, json_array_routes,
- use_json);
+ ospf6_route_show(vty, route, json_routes, use_json);
route = ospf6_route_next(route);
}
if (use_json)
- json_object_object_add(json, "routes", json_array_routes);
+ json_object_object_add(json, "routes", json_routes);
}
int ospf6_route_table_show(struct vty *vty, int argc_start, int argc,
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <zebra.h>
+
#include "lib/northbound.h"
#include "lib/routemap.h"
#include "ospf6_routemap_nb.h"
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <zebra.h>
+
#include "lib/command.h"
#include "lib/log.h"
#include "lib/northbound.h"
#include "vrf.h"
#include "smux.h"
#include "libfrr.h"
-#include "version.h"
+#include "lib/version.h"
#include "ospf6_proto.h"
#include "ospf6_lsa.h"
return NULL;
}
+/* This is hook function for vrf create called as part of vrf_init */
+static int ospf6_vrf_new(struct vrf *vrf)
+{
+ return 0;
+}
+
+/* This is hook function for vrf delete call as part of vrf_init */
+static int ospf6_vrf_delete(struct vrf *vrf)
+{
+ return 0;
+}
+
+static void ospf6_set_redist_vrf_bitmaps(struct ospf6 *ospf6, bool set)
+{
+ int type;
+ struct list *red_list;
+
+ for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
+ red_list = ospf6->redist[type];
+ if (!red_list)
+ continue;
+ if (IS_OSPF6_DEBUG_ZEBRA(RECV))
+ zlog_debug(
+ "%s: setting redist vrf %d bitmap for type %d",
+ __func__, ospf6->vrf_id, type);
+ if (set)
+ vrf_bitmap_set(zclient->redist[AFI_IP6][type],
+ ospf6->vrf_id);
+ else
+ vrf_bitmap_unset(zclient->redist[AFI_IP6][type],
+ ospf6->vrf_id);
+ }
+}
+
+/* Disable OSPF6 VRF instance */
+static int ospf6_vrf_disable(struct vrf *vrf)
+{
+ struct ospf6 *ospf6 = NULL;
+
+ if (vrf->vrf_id == VRF_DEFAULT)
+ return 0;
+
+ ospf6 = ospf6_lookup_by_vrf_name(vrf->name);
+ if (ospf6) {
+ ospf6_zebra_vrf_deregister(ospf6);
+
+ ospf6_set_redist_vrf_bitmaps(ospf6, false);
+
+ /* We have instance configured, unlink
+ * from VRF and make it "down".
+ */
+ ospf6_vrf_unlink(ospf6, vrf);
+ thread_cancel(&ospf6->t_ospf6_receive);
+ close(ospf6->fd);
+ ospf6->fd = -1;
+ }
+
+ /* Note: This is a callback, the VRF will be deleted by the caller. */
+ return 0;
+}
+
+/* Enable OSPF6 VRF instance */
+static int ospf6_vrf_enable(struct vrf *vrf)
+{
+ struct ospf6 *ospf6 = NULL;
+ vrf_id_t old_vrf_id;
+ int ret = 0;
+
+ ospf6 = ospf6_lookup_by_vrf_name(vrf->name);
+ if (ospf6) {
+ old_vrf_id = ospf6->vrf_id;
+ /* We have instance configured, link to VRF and make it "up". */
+ ospf6_vrf_link(ospf6, vrf);
+
+ if (old_vrf_id != ospf6->vrf_id) {
+ ospf6_set_redist_vrf_bitmaps(ospf6, true);
+
+ /* start zebra redist to us for new vrf */
+ ospf6_zebra_vrf_register(ospf6);
+
+ ret = ospf6_serv_sock(ospf6);
+ if (ret < 0 || ospf6->fd <= 0)
+ return 0;
+ thread_add_read(master, ospf6_receive, ospf6, ospf6->fd,
+ &ospf6->t_ospf6_receive);
+
+ ospf6_router_id_update(ospf6);
+ }
+ }
+
+ return 0;
+}
+
+void ospf6_vrf_init(void)
+{
+ vrf_init(ospf6_vrf_new, ospf6_vrf_enable, ospf6_vrf_disable,
+ ospf6_vrf_delete, ospf6_vrf_enable);
+}
static void ospf6_top_lsdb_hook_add(struct ospf6_lsa *lsa)
{
if (ospf6->router_id == 0)
ospf6_router_id_update(ospf6);
ospf6_add(ospf6);
+ if (ospf6->fd < 0)
+ return ospf6;
+
thread_add_read(master, ospf6_receive, ospf6, ospf6->fd,
&ospf6->t_ospf6_receive);
ospf6_disable(o);
ospf6_del(o);
+ ospf6_zebra_vrf_deregister(o);
+
ospf6_serv_close(&o->fd);
for (ALL_LIST_ELEMENTS(o->area_list, node, nnode, oa))
}
/* start ospf6 */
-DEFUN_NOSH (router_ospf6,
- router_ospf6_cmd,
- "router ospf6",
- ROUTER_STR
- OSPF6_STR)
+DEFUN_NOSH(router_ospf6, router_ospf6_cmd, "router ospf6 [vrf NAME]",
+ ROUTER_STR OSPF6_STR VRF_CMD_HELP_STR)
{
struct ospf6 *ospf6;
+ const char *vrf_name = VRF_DEFAULT_NAME;
+ int idx_vrf = 0;
- ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
+ if (argv_find(argv, argc, "vrf", &idx_vrf)) {
+ vrf_name = argv[idx_vrf + 1]->arg;
+ }
+
+ ospf6 = ospf6_lookup_by_vrf_name(vrf_name);
if (ospf6 == NULL)
- ospf6 = ospf6_instance_create(VRF_DEFAULT_NAME);
+ ospf6 = ospf6_instance_create(vrf_name);
/* set current ospf point. */
VTY_PUSH_CONTEXT(OSPF6_NODE, ospf6);
}
/* stop ospf6 */
-DEFUN (no_router_ospf6,
- no_router_ospf6_cmd,
- "no router ospf6",
- NO_STR
- ROUTER_STR
- OSPF6_STR)
+DEFUN(no_router_ospf6, no_router_ospf6_cmd, "no router ospf6 [vrf NAME]",
+ NO_STR ROUTER_STR OSPF6_STR VRF_CMD_HELP_STR)
{
struct ospf6 *ospf6;
+ const char *vrf_name = VRF_DEFAULT_NAME;
+ int idx_vrf = 0;
- ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
+ if (argv_find(argv, argc, "vrf", &idx_vrf)) {
+ vrf_name = argv[idx_vrf + 1]->arg;
+ }
+
+ ospf6 = ospf6_lookup_by_vrf_name(vrf_name);
if (ospf6 == NULL)
vty_out(vty, "OSPFv3 is not configured\n");
else {
"OSPF6 area ID in decimal notation\n"
)
{
+ VTY_DECLVAR_CONTEXT(ospf6, ospf6);
int idx_ifname = 1;
int idx_ipv4 = 3;
struct ospf6_area *oa;
struct ospf6_interface *oi;
struct interface *ifp;
+ vrf_id_t vrf_id = VRF_DEFAULT;
- VTY_DECLVAR_CONTEXT(ospf6, ospf6);
+ if (ospf6->vrf_id != VRF_UNKNOWN)
+ vrf_id = ospf6->vrf_id;
/* find/create ospf6 interface */
- ifp = if_get_by_name(argv[idx_ifname]->arg, VRF_DEFAULT);
+ ifp = if_get_by_name(argv[idx_ifname]->arg, vrf_id);
oi = (struct ospf6_interface *)ifp->info;
if (oi == NULL)
oi = ospf6_interface_create(ifp);
"OSPF6 area ID in decimal notation\n"
)
{
+ VTY_DECLVAR_CONTEXT(ospf6, ospf6);
int idx_ifname = 2;
int idx_ipv4 = 4;
struct ospf6_interface *oi;
struct ospf6_area *oa;
struct interface *ifp;
uint32_t area_id;
+ vrf_id_t vrf_id = VRF_DEFAULT;
+
+ if (ospf6->vrf_id != VRF_UNKNOWN)
+ vrf_id = ospf6->vrf_id;
+
+ /* find/create ospf6 interface */
+ ifp = if_get_by_name(argv[idx_ifname]->arg, vrf_id);
- ifp = if_lookup_by_name(argv[idx_ifname]->arg, VRF_DEFAULT);
if (ifp == NULL) {
vty_out(vty, "No such interface %s\n", argv[idx_ifname]->arg);
return CMD_SUCCESS;
/* 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;
}
{
ospf6_route_remove_all(ospf6->route_table);
ospf6_route_remove_all(ospf6->brouter_table);
- ospf6_route_remove_all(ospf6->external_table);
/* Trigger SPF */
ospf6_spf_schedule(ospf6, OSPF6_SPF_FLAGS_CONFIG_CHANGE);
}
}
+DEFUN(show_ipv6_ospf6_vrfs, show_ipv6_ospf6_vrfs_cmd,
+ "show ipv6 ospf6 vrfs [json]",
+ SHOW_STR IP6_STR OSPF6_STR "Show OSPF6 VRFs \n" JSON_STR)
+{
+ bool uj = use_json(argc, argv);
+ json_object *json = NULL;
+ json_object *json_vrfs = NULL;
+ struct ospf6 *ospf6 = NULL;
+ struct listnode *node = NULL;
+ int count = 0;
+ char buf[PREFIX_STRLEN];
+ static const char header[] =
+ "Name Id RouterId ";
+
+ if (uj) {
+ json = json_object_new_object();
+ json_vrfs = json_object_new_object();
+ }
+
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ json_object *json_vrf = NULL;
+ const char *name = NULL;
+ int64_t vrf_id_ui = 0;
+ struct in_addr router_id;
+
+ router_id.s_addr = ospf6->router_id;
+ count++;
+
+ if (!uj && count == 1)
+ vty_out(vty, "%s\n", header);
+ if (uj)
+ json_vrf = json_object_new_object();
+
+ if (ospf6->vrf_id == VRF_DEFAULT)
+ name = VRF_DEFAULT_NAME;
+ else
+ name = ospf6->name;
+
+ vrf_id_ui = (ospf6->vrf_id == VRF_UNKNOWN)
+ ? -1
+ : (int64_t)ospf6->vrf_id;
+
+ if (uj) {
+ json_object_int_add(json_vrf, "vrfId", vrf_id_ui);
+ json_object_string_add(json_vrf, "routerId",
+ inet_ntop(AF_INET, &router_id,
+ buf, sizeof(buf)));
+ json_object_object_add(json_vrfs, name, json_vrf);
+
+ } else {
+ vty_out(vty, "%-25s %-5d %-16s \n", name,
+ ospf6->vrf_id,
+ inet_ntop(AF_INET, &router_id, buf,
+ sizeof(buf)));
+ }
+ }
+
+ if (uj) {
+ json_object_object_add(json, "vrfs", json_vrfs);
+ json_object_int_add(json, "totalVrfs", count);
+
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ } else {
+ if (count)
+ vty_out(vty, "\nTotal number of OSPF VRFs: %d\n",
+ count);
+ }
+
+ return CMD_SUCCESS;
+}
+
/* show top level structures */
-DEFUN(show_ipv6_ospf6,
- show_ipv6_ospf6_cmd,
- "show ipv6 ospf6 [json]",
- SHOW_STR
- IP6_STR
- OSPF6_STR
- JSON_STR)
+DEFUN(show_ipv6_ospf6, show_ipv6_ospf6_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] [json]",
+ SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR "All VRFs\n" JSON_STR)
{
struct ospf6 *ospf6;
+ struct listnode *node;
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+
bool uj = use_json(argc, argv);
json_object *json = NULL;
- ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
- OSPF6_CMD_CHECK_RUNNING(ospf6);
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
- if (uj)
- json = json_object_new_object();
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ if (uj)
+ json = json_object_new_object();
+ ospf6_show(vty, ospf6, json, uj);
- ospf6_show(vty, ospf6, json, uj);
+ if (!all_vrf)
+ break;
+ }
+ }
if (uj)
json_object_free(json);
+
return CMD_SUCCESS;
}
-DEFUN (show_ipv6_ospf6_route,
- show_ipv6_ospf6_route_cmd,
- "show ipv6 ospf6 route [<intra-area|inter-area|external-1|external-2|X:X::X:X|X:X::X:X/M|detail|summary>] [json]",
- SHOW_STR
- IP6_STR
- OSPF6_STR
- ROUTE_STR
- "Display Intra-Area routes\n"
- "Display Inter-Area routes\n"
- "Display Type-1 External routes\n"
- "Display Type-2 External routes\n"
- "Specify IPv6 address\n"
- "Specify IPv6 prefix\n"
- "Detailed information\n"
- "Summary of route table\n"
- JSON_STR)
+DEFUN(show_ipv6_ospf6_route, show_ipv6_ospf6_route_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] route [<intra-area|inter-area|external-1|external-2|X:X::X:X|X:X::X:X/M|detail|summary>] [json]",
+ SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR
+ "All VRFs\n" ROUTE_STR
+ "Display Intra-Area routes\n"
+ "Display Inter-Area routes\n"
+ "Display Type-1 External routes\n"
+ "Display Type-2 External routes\n"
+ "Specify IPv6 address\n"
+ "Specify IPv6 prefix\n"
+ "Detailed information\n"
+ "Summary of route table\n" JSON_STR)
{
struct ospf6 *ospf6;
+ struct listnode *node;
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+ int idx_arg_start = 4;
bool uj = use_json(argc, argv);
- ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
- OSPF6_CMD_CHECK_RUNNING(ospf6);
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (idx_vrf > 0)
+ idx_arg_start += 2;
+
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ ospf6_route_table_show(vty, idx_arg_start, argc, argv,
+ ospf6->route_table, uj);
+
+ if (!all_vrf)
+ break;
+ }
+ }
- ospf6_route_table_show(vty, 4, argc, argv, ospf6->route_table, uj);
return CMD_SUCCESS;
}
-DEFUN (show_ipv6_ospf6_route_match,
- show_ipv6_ospf6_route_match_cmd,
- "show ipv6 ospf6 route X:X::X:X/M <match|longer> [json]",
- SHOW_STR
- IP6_STR
- OSPF6_STR
- ROUTE_STR
- "Specify IPv6 prefix\n"
- "Display routes which match the specified route\n"
- "Display routes longer than the specified route\n"
- JSON_STR)
+DEFUN(show_ipv6_ospf6_route_match, show_ipv6_ospf6_route_match_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] route X:X::X:X/M <match|longer> [json]",
+ SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR
+ "All VRFs\n" ROUTE_STR
+ "Specify IPv6 prefix\n"
+ "Display routes which match the specified route\n"
+ "Display routes longer than the specified route\n" JSON_STR)
{
struct ospf6 *ospf6;
+ struct listnode *node;
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+ int idx_start_arg = 4;
bool uj = use_json(argc, argv);
- ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
- OSPF6_CMD_CHECK_RUNNING(ospf6);
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (idx_vrf > 0)
+ idx_start_arg += 2;
+
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ ospf6_route_table_show(vty, idx_start_arg, argc, argv,
+ ospf6->route_table, uj);
+
+ if (!all_vrf)
+ break;
+ }
+ }
- ospf6_route_table_show(vty, 4, argc, argv, ospf6->route_table, uj);
return CMD_SUCCESS;
}
-DEFUN (show_ipv6_ospf6_route_match_detail,
- show_ipv6_ospf6_route_match_detail_cmd,
- "show ipv6 ospf6 route X:X::X:X/M match detail [json]",
- SHOW_STR
- IP6_STR
- OSPF6_STR
- ROUTE_STR
- "Specify IPv6 prefix\n"
- "Display routes which match the specified route\n"
- "Detailed information\n"
- JSON_STR)
+DEFUN(show_ipv6_ospf6_route_match_detail,
+ show_ipv6_ospf6_route_match_detail_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] route X:X::X:X/M match detail [json]",
+ SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR
+ "All VRFs\n" ROUTE_STR
+ "Specify IPv6 prefix\n"
+ "Display routes which match the specified route\n"
+ "Detailed information\n" JSON_STR)
{
struct ospf6 *ospf6;
+ struct listnode *node;
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+ int idx_start_arg = 4;
bool uj = use_json(argc, argv);
- ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
- OSPF6_CMD_CHECK_RUNNING(ospf6);
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (idx_vrf > 0)
+ idx_start_arg += 2;
+
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ ospf6_route_table_show(vty, idx_start_arg, argc, argv,
+ ospf6->route_table, uj);
+
+ if (!all_vrf)
+ break;
+ }
+ }
- ospf6_route_table_show(vty, 4, argc, argv, ospf6->route_table, uj);
return CMD_SUCCESS;
}
-
-DEFUN (show_ipv6_ospf6_route_type_detail,
- show_ipv6_ospf6_route_type_detail_cmd,
- "show ipv6 ospf6 route <intra-area|inter-area|external-1|external-2> detail [json]",
- SHOW_STR
- IP6_STR
- OSPF6_STR
- ROUTE_STR
- "Display Intra-Area routes\n"
- "Display Inter-Area routes\n"
- "Display Type-1 External routes\n"
- "Display Type-2 External routes\n"
- "Detailed information\n"
- JSON_STR)
+DEFUN(show_ipv6_ospf6_route_type_detail, show_ipv6_ospf6_route_type_detail_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] route <intra-area|inter-area|external-1|external-2> detail [json]",
+ SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR
+ "All VRFs\n" ROUTE_STR
+ "Display Intra-Area routes\n"
+ "Display Inter-Area routes\n"
+ "Display Type-1 External routes\n"
+ "Display Type-2 External routes\n"
+ "Detailed information\n" JSON_STR)
{
struct ospf6 *ospf6;
+ struct listnode *node;
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+ int idx_start_arg = 4;
bool uj = use_json(argc, argv);
- ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
- OSPF6_CMD_CHECK_RUNNING(ospf6);
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (idx_vrf > 0)
+ idx_start_arg += 2;
+
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ ospf6_route_table_show(vty, idx_start_arg, argc, argv,
+ ospf6->route_table, uj);
+
+ if (!all_vrf)
+ break;
+ }
+ }
- ospf6_route_table_show(vty, 4, argc, argv, ospf6->route_table, uj);
return CMD_SUCCESS;
}
return CMD_SUCCESS;
for (ALL_LIST_ELEMENTS(om6->ospf6, node, nnode, ospf6)) {
- vty_out(vty, "router ospf6\n");
+ if (ospf6->name && strcmp(ospf6->name, VRF_DEFAULT_NAME))
+ vty_out(vty, "router ospf6 vrf %s\n", ospf6->name);
+ else
+ vty_out(vty, "router ospf6\n");
+
if (ospf6->router_id_static != 0)
vty_out(vty, " ospf6 router-id %pI4\n",
&ospf6->router_id_static);
install_node(&ospf6_node);
install_element(VIEW_NODE, &show_ipv6_ospf6_cmd);
+ install_element(VIEW_NODE, &show_ipv6_ospf6_vrfs_cmd);
install_element(CONFIG_NODE, &router_ospf6_cmd);
install_element(CONFIG_NODE, &no_router_ospf6_cmd);
struct ospf6 *ospf6_lookup_by_vrf_id(vrf_id_t vrf_id);
struct ospf6 *ospf6_lookup_by_vrf_name(const char *name);
const char *ospf6_vrf_id_to_name(vrf_id_t vrf_id);
-
+void ospf6_vrf_init(void);
#endif /* OSPF6_TOP_H */
#include "vty.h"
#include "command.h"
#include "plist.h"
+#include "filter.h"
#include "ospf6_proto.h"
#include "ospf6_top.h"
vty_out(vty, "\n");
}
-DEFUN (show_ipv6_ospf6_database,
- show_ipv6_ospf6_database_cmd,
- "show ipv6 ospf6 database [<detail|dump|internal>] [json]",
- SHOW_STR
- IPV6_STR
- OSPF6_STR
- "Display Link state database\n"
- "Display details of LSAs\n"
- "Dump LSAs\n"
- "Display LSA's internal information\n"
- JSON_STR)
+DEFUN(show_ipv6_ospf6_database, show_ipv6_ospf6_database_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] database [<detail|dump|internal>] [json]",
+ SHOW_STR IPV6_STR OSPF6_STR VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "Display Link state database\n"
+ "Display details of LSAs\n"
+ "Dump LSAs\n"
+ "Display LSA's internal information\n" JSON_STR)
{
- int idx_level = 4;
int level;
- bool uj = use_json(argc, argv);
+ int idx_level = 4;
+ struct listnode *node;
struct ospf6 *ospf6;
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+ bool uj = use_json(argc, argv);
- ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
- OSPF6_CMD_CHECK_RUNNING(ospf6);
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (idx_vrf > 0)
+ idx_level += 2;
level = parse_show_level(idx_level, argc, argv);
- ospf6_lsdb_show_wrapper(vty, level, NULL, NULL, NULL, uj, ospf6);
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ ospf6_lsdb_show_wrapper(vty, level, NULL, NULL, NULL,
+ uj, ospf6);
+ if (!all_vrf)
+ break;
+ }
+ }
+
return CMD_SUCCESS;
}
-DEFUN (show_ipv6_ospf6_database_type, show_ipv6_ospf6_database_type_cmd,
- "show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> [<detail|dump|internal>] [json]",
- SHOW_STR
- IPV6_STR
- OSPF6_STR
- "Display Link state database\n"
- "Display Router LSAs\n"
- "Display Network LSAs\n"
- "Display Inter-Area-Prefix LSAs\n"
- "Display Inter-Area-Router LSAs\n"
- "Display As-External LSAs\n"
- "Display Group-Membership LSAs\n"
- "Display Type-7 LSAs\n"
- "Display Link LSAs\n"
- "Display Intra-Area-Prefix LSAs\n"
- "Display details of LSAs\n"
- "Dump LSAs\n"
- "Display LSA's internal information\n"
- JSON_STR)
+DEFUN(show_ipv6_ospf6_database_type, show_ipv6_ospf6_database_type_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> [<detail|dump|internal>] [json]",
+ SHOW_STR IPV6_STR OSPF6_STR VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "Display Link state database\n"
+ "Display Router LSAs\n"
+ "Display Network LSAs\n"
+ "Display Inter-Area-Prefix LSAs\n"
+ "Display Inter-Area-Router LSAs\n"
+ "Display As-External LSAs\n"
+ "Display Group-Membership LSAs\n"
+ "Display Type-7 LSAs\n"
+ "Display Link LSAs\n"
+ "Display Intra-Area-Prefix LSAs\n"
+ "Display details of LSAs\n"
+ "Dump LSAs\n"
+ "Display LSA's internal information\n" JSON_STR)
{
int idx_lsa = 4;
int idx_level = 5;
int level;
- uint16_t type = 0;
bool uj = use_json(argc, argv);
+ struct listnode *node;
struct ospf6 *ospf6;
-
-
- ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
- OSPF6_CMD_CHECK_RUNNING(ospf6);
+ uint16_t type = 0;
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (idx_vrf > 0) {
+ idx_lsa += 2;
+ idx_level += 2;
+ }
type = parse_type_spec(idx_lsa, argc, argv);
level = parse_show_level(idx_level, argc, argv);
- ospf6_lsdb_type_show_wrapper(vty, level, &type, NULL, NULL, uj, ospf6);
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ ospf6_lsdb_type_show_wrapper(vty, level, &type, NULL,
+ NULL, uj, ospf6);
+ if (!all_vrf)
+ break;
+ }
+ }
+
return CMD_SUCCESS;
}
-DEFUN (show_ipv6_ospf6_database_id,
- show_ipv6_ospf6_database_id_cmd,
- "show ipv6 ospf6 database <*|linkstate-id> A.B.C.D [<detail|dump|internal>] [json]",
- SHOW_STR
- IPV6_STR
- OSPF6_STR
- "Display Link state database\n"
- "Any Link state Type\n"
- "Search by Link state ID\n"
- "Specify Link state ID as IPv4 address notation\n"
- "Display details of LSAs\n"
- "Dump LSAs\n"
- "Display LSA's internal information\n"
- JSON_STR)
+DEFUN(show_ipv6_ospf6_database_id, show_ipv6_ospf6_database_id_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] database <*|linkstate-id> A.B.C.D [<detail|dump|internal>] [json]",
+ SHOW_STR IPV6_STR OSPF6_STR VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "Display Link state database\n"
+ "Any Link state Type\n"
+ "Search by Link state ID\n"
+ "Specify Link state ID as IPv4 address notation\n"
+ "Display details of LSAs\n"
+ "Dump LSAs\n"
+ "Display LSA's internal information\n" JSON_STR)
{
int idx_ipv4 = 5;
int idx_level = 6;
int level;
- uint32_t id = 0;
bool uj = use_json(argc, argv);
+ struct listnode *node;
struct ospf6 *ospf6;
+ uint32_t id = 0;
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
-
- ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
- OSPF6_CMD_CHECK_RUNNING(ospf6);
-
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
if (argv[idx_ipv4]->type == IPV4_TKN)
inet_pton(AF_INET, argv[idx_ipv4]->arg, &id);
level = parse_show_level(idx_level, argc, argv);
- ospf6_lsdb_show_wrapper(vty, level, NULL, &id, NULL, uj, ospf6);
+
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ ospf6_lsdb_show_wrapper(vty, level, NULL, &id, NULL, uj,
+ ospf6);
+ if (!all_vrf)
+ break;
+ }
+ }
return CMD_SUCCESS;
}
-DEFUN (show_ipv6_ospf6_database_router,
- show_ipv6_ospf6_database_router_cmd,
- "show ipv6 ospf6 database <*|adv-router> * A.B.C.D <detail|dump|internal> [json]",
- SHOW_STR
- IPV6_STR
- OSPF6_STR
- "Display Link state database\n"
- "Any Link state Type\n"
- "Search by Advertising Router\n"
- "Any Link state ID\n"
- "Specify Advertising Router as IPv4 address notation\n"
- "Display details of LSAs\n"
- "Dump LSAs\n"
- "Display LSA's internal information\n"
- JSON_STR)
+DEFUN(show_ipv6_ospf6_database_router, show_ipv6_ospf6_database_router_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] database <*|adv-router> * A.B.C.D <detail|dump|internal> [json]",
+ SHOW_STR IPV6_STR OSPF6_STR VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "Display Link state database\n"
+ "Any Link state Type\n"
+ "Search by Advertising Router\n"
+ "Any Link state ID\n"
+ "Specify Advertising Router as IPv4 address notation\n"
+ "Display details of LSAs\n"
+ "Dump LSAs\n"
+ "Display LSA's internal information\n" JSON_STR)
{
int idx_ipv4 = 6;
int idx_level = 7;
int level;
+ struct listnode *node;
+ struct ospf6 *ospf6;
uint32_t adv_router = 0;
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
bool uj = use_json(argc, argv);
- struct ospf6 *ospf6;
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (idx_vrf > 0) {
+ idx_ipv4 += 2;
+ idx_level += 2;
+ }
- ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
- OSPF6_CMD_CHECK_RUNNING(ospf6);
inet_pton(AF_INET, argv[idx_ipv4]->arg, &adv_router);
level = parse_show_level(idx_level, argc, argv);
- ospf6_lsdb_show_wrapper(vty, level, NULL, NULL, &adv_router, uj, ospf6);
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ ospf6_lsdb_show_wrapper(vty, level, NULL, NULL,
+ &adv_router, uj, ospf6);
+ if (!all_vrf)
+ break;
+ }
+ }
+
return CMD_SUCCESS;
}
-DEFUN_HIDDEN (show_ipv6_ospf6_database_aggr_router,
- show_ipv6_ospf6_database_aggr_router_cmd,
- "show ipv6 ospf6 database aggr adv-router A.B.C.D",
- SHOW_STR
- IPV6_STR
- OSPF6_STR
- "Display Link state database\n"
- "Aggregated Router LSA\n"
- "Search by Advertising Router\n"
- "Specify Advertising Router as IPv4 address notation\n")
+static int ipv6_ospf6_database_aggr_router_common(struct vty *vty,
+ uint32_t adv_router,
+ struct ospf6 *ospf6)
{
int level = OSPF6_LSDB_SHOW_LEVEL_DETAIL;
uint16_t type = htons(OSPF6_LSTYPE_ROUTER);
- int idx_ipv4 = 6;
struct listnode *i;
- struct ospf6 *ospf6;
struct ospf6_area *oa;
struct ospf6_lsdb *lsdb;
- uint32_t adv_router = 0;
-
- ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
- OSPF6_CMD_CHECK_RUNNING(ospf6);
-
- inet_pton(AF_INET, argv[idx_ipv4]->arg, &adv_router);
for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) {
if (adv_router == ospf6->router_id)
}
vty_out(vty, "\n");
+ return CMD_SUCCESS;
+}
+
+DEFUN_HIDDEN(
+ show_ipv6_ospf6_database_aggr_router,
+ show_ipv6_ospf6_database_aggr_router_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] database aggr adv-router A.B.C.D",
+ SHOW_STR IPV6_STR OSPF6_STR VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "Display Link state database\n"
+ "Aggregated Router LSA\n"
+ "Search by Advertising Router\n"
+ "Specify Advertising Router as IPv4 address notation\n")
+{
+ int idx_ipv4 = 6;
+ struct listnode *node;
+ struct ospf6 *ospf6;
+ uint32_t adv_router = 0;
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (idx_vrf > 0)
+ idx_ipv4 += 2;
+
+ inet_pton(AF_INET, argv[idx_ipv4]->arg, &adv_router);
+
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ ipv6_ospf6_database_aggr_router_common(vty, adv_router,
+ ospf6);
+
+ if (!all_vrf)
+ break;
+ }
+ }
return CMD_SUCCESS;
}
-DEFUN (show_ipv6_ospf6_database_type_id,
- show_ipv6_ospf6_database_type_id_cmd,
- "show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> linkstate-id A.B.C.D [<detail|dump|internal>] [json]",
- SHOW_STR
- IPV6_STR
- OSPF6_STR
- "Display Link state database\n"
- "Display Router LSAs\n"
- "Display Network LSAs\n"
- "Display Inter-Area-Prefix LSAs\n"
- "Display Inter-Area-Router LSAs\n"
- "Display As-External LSAs\n"
- "Display Group-Membership LSAs\n"
- "Display Type-7 LSAs\n"
- "Display Link LSAs\n"
- "Display Intra-Area-Prefix LSAs\n"
- "Search by Link state ID\n"
- "Specify Link state ID as IPv4 address notation\n"
- "Display details of LSAs\n"
- "Dump LSAs\n"
- "Display LSA's internal information\n"
- JSON_STR)
+DEFUN(show_ipv6_ospf6_database_type_id, show_ipv6_ospf6_database_type_id_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> linkstate-id A.B.C.D [<detail|dump|internal>] [json]",
+ SHOW_STR IPV6_STR OSPF6_STR VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "Display Link state database\n"
+ "Display Router LSAs\n"
+ "Display Network LSAs\n"
+ "Display Inter-Area-Prefix LSAs\n"
+ "Display Inter-Area-Router LSAs\n"
+ "Display As-External LSAs\n"
+ "Display Group-Membership LSAs\n"
+ "Display Type-7 LSAs\n"
+ "Display Link LSAs\n"
+ "Display Intra-Area-Prefix LSAs\n"
+ "Search by Link state ID\n"
+ "Specify Link state ID as IPv4 address notation\n"
+ "Display details of LSAs\n"
+ "Dump LSAs\n"
+ "Display LSA's internal information\n" JSON_STR)
{
int idx_lsa = 4;
int idx_ipv4 = 6;
int idx_level = 7;
int level;
- uint16_t type = 0;
- uint32_t id = 0;
bool uj = use_json(argc, argv);
+ struct listnode *node;
struct ospf6 *ospf6;
-
-
- ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
- OSPF6_CMD_CHECK_RUNNING(ospf6);
+ uint16_t type = 0;
+ uint32_t id = 0;
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (idx_vrf > 0) {
+ idx_lsa += 2;
+ idx_ipv4 += 2;
+ idx_level += 2;
+ }
type = parse_type_spec(idx_lsa, argc, argv);
inet_pton(AF_INET, argv[idx_ipv4]->arg, &id);
level = parse_show_level(idx_level, argc, argv);
- ospf6_lsdb_type_show_wrapper(vty, level, &type, &id, NULL, uj, ospf6);
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ ospf6_lsdb_type_show_wrapper(vty, level, &type, &id,
+ NULL, uj, ospf6);
+ if (!all_vrf)
+ break;
+ }
+ }
+
return CMD_SUCCESS;
}
-DEFUN (show_ipv6_ospf6_database_type_router,
- show_ipv6_ospf6_database_type_router_cmd,
- "show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> <*|adv-router> A.B.C.D [<detail|dump|internal>] [json]",
- SHOW_STR
- IPV6_STR
- OSPF6_STR
- "Display Link state database\n"
- "Display Router LSAs\n"
- "Display Network LSAs\n"
- "Display Inter-Area-Prefix LSAs\n"
- "Display Inter-Area-Router LSAs\n"
- "Display As-External LSAs\n"
- "Display Group-Membership LSAs\n"
- "Display Type-7 LSAs\n"
- "Display Link LSAs\n"
- "Display Intra-Area-Prefix LSAs\n"
- "Any Link state ID\n"
- "Search by Advertising Router\n"
- "Specify Advertising Router as IPv4 address notation\n"
- "Display details of LSAs\n"
- "Dump LSAs\n"
- "Display LSA's internal information\n"
- JSON_STR)
+DEFUN(show_ipv6_ospf6_database_type_router,
+ show_ipv6_ospf6_database_type_router_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> <*|adv-router> A.B.C.D [<detail|dump|internal>] [json]",
+ SHOW_STR IPV6_STR OSPF6_STR VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "Display Link state database\n"
+ "Display Router LSAs\n"
+ "Display Network LSAs\n"
+ "Display Inter-Area-Prefix LSAs\n"
+ "Display Inter-Area-Router LSAs\n"
+ "Display As-External LSAs\n"
+ "Display Group-Membership LSAs\n"
+ "Display Type-7 LSAs\n"
+ "Display Link LSAs\n"
+ "Display Intra-Area-Prefix LSAs\n"
+ "Any Link state ID\n"
+ "Search by Advertising Router\n"
+ "Specify Advertising Router as IPv4 address notation\n"
+ "Display details of LSAs\n"
+ "Dump LSAs\n"
+ "Display LSA's internal information\n" JSON_STR)
{
int idx_lsa = 4;
int idx_ipv4 = 6;
int idx_level = 7;
int level;
- uint16_t type = 0;
- uint32_t adv_router = 0;
bool uj = use_json(argc, argv);
+ struct listnode *node;
struct ospf6 *ospf6;
+ uint16_t type = 0;
+ uint32_t adv_router = 0;
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (idx_vrf > 0) {
+ idx_lsa += 2;
+ idx_ipv4 += 2;
+ idx_level += 2;
+ }
-
- ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
- OSPF6_CMD_CHECK_RUNNING(ospf6);
type = parse_type_spec(idx_lsa, argc, argv);
inet_pton(AF_INET, argv[idx_ipv4]->arg, &adv_router);
level = parse_show_level(idx_level, argc, argv);
- ospf6_lsdb_type_show_wrapper(vty, level, &type, NULL, &adv_router, uj,
- ospf6);
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ ospf6_lsdb_type_show_wrapper(vty, level, &type, NULL,
+ &adv_router, uj, ospf6);
+
+ if (!all_vrf)
+ break;
+ }
+ }
+
return CMD_SUCCESS;
}
-
-DEFUN (show_ipv6_ospf6_database_id_router,
- show_ipv6_ospf6_database_id_router_cmd,
- "show ipv6 ospf6 database * A.B.C.D A.B.C.D [<detail|dump|internal>] [json]",
- SHOW_STR
- IPV6_STR
- OSPF6_STR
- "Display Link state database\n"
- "Any Link state Type\n"
- "Specify Link state ID as IPv4 address notation\n"
- "Specify Advertising Router as IPv4 address notation\n"
- "Display details of LSAs\n"
- "Dump LSAs\n"
- "Display LSA's internal information\n"
- JSON_STR)
+DEFUN(show_ipv6_ospf6_database_id_router,
+ show_ipv6_ospf6_database_id_router_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] database * A.B.C.D A.B.C.D [<detail|dump|internal>] [json]",
+ SHOW_STR IPV6_STR OSPF6_STR VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "Display Link state database\n"
+ "Any Link state Type\n"
+ "Specify Link state ID as IPv4 address notation\n"
+ "Specify Advertising Router as IPv4 address notation\n"
+ "Display details of LSAs\n"
+ "Dump LSAs\n"
+ "Display LSA's internal information\n" JSON_STR)
{
int idx_ls_id = 5;
int idx_adv_rtr = 6;
int idx_level = 7;
int level;
- uint32_t id = 0;
- uint32_t adv_router = 0;
bool uj = use_json(argc, argv);
+ struct listnode *node;
struct ospf6 *ospf6;
+ uint32_t id = 0;
+ uint32_t adv_router = 0;
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (idx_vrf > 0) {
+ idx_ls_id += 2;
+ idx_adv_rtr += 2;
+ idx_level += 2;
+ }
- ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
- OSPF6_CMD_CHECK_RUNNING(ospf6);
inet_pton(AF_INET, argv[idx_ls_id]->arg, &id);
inet_pton(AF_INET, argv[idx_adv_rtr]->arg, &adv_router);
level = parse_show_level(idx_level, argc, argv);
- ospf6_lsdb_show_wrapper(vty, level, NULL, &id, &adv_router, uj, ospf6);
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ ospf6_lsdb_show_wrapper(vty, level, NULL, &id,
+ &adv_router, uj, ospf6);
+ if (!all_vrf)
+ break;
+ }
+ }
+
return CMD_SUCCESS;
}
-
-DEFUN (show_ipv6_ospf6_database_adv_router_linkstate_id,
- show_ipv6_ospf6_database_adv_router_linkstate_id_cmd,
- "show ipv6 ospf6 database adv-router A.B.C.D linkstate-id A.B.C.D [<detail|dump|internal>] [json]",
- SHOW_STR
- IPV6_STR
- OSPF6_STR
- "Display Link state database\n"
- "Search by Advertising Router\n"
- "Specify Advertising Router as IPv4 address notation\n"
- "Search by Link state ID\n"
- "Specify Link state ID as IPv4 address notation\n"
- "Display details of LSAs\n"
- "Dump LSAs\n"
- "Display LSA's internal information\n"
- JSON_STR)
+DEFUN(show_ipv6_ospf6_database_adv_router_linkstate_id,
+ show_ipv6_ospf6_database_adv_router_linkstate_id_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] database adv-router A.B.C.D linkstate-id A.B.C.D [<detail|dump|internal>] [json]",
+ SHOW_STR IPV6_STR OSPF6_STR VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "Display Link state database\n"
+ "Search by Advertising Router\n"
+ "Specify Advertising Router as IPv4 address notation\n"
+ "Search by Link state ID\n"
+ "Specify Link state ID as IPv4 address notation\n"
+ "Display details of LSAs\n"
+ "Dump LSAs\n"
+ "Display LSA's internal information\n" JSON_STR)
{
int idx_adv_rtr = 5;
int idx_ls_id = 7;
int idx_level = 8;
int level;
- uint32_t id = 0;
- uint32_t adv_router = 0;
bool uj = use_json(argc, argv);
+ struct listnode *node;
struct ospf6 *ospf6;
+ uint32_t id = 0;
+ uint32_t adv_router = 0;
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
- ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
- OSPF6_CMD_CHECK_RUNNING(ospf6);
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (idx_vrf > 0) {
+ idx_adv_rtr += 2;
+ idx_ls_id += 2;
+ idx_level += 2;
+ }
inet_pton(AF_INET, argv[idx_adv_rtr]->arg, &adv_router);
inet_pton(AF_INET, argv[idx_ls_id]->arg, &id);
level = parse_show_level(idx_level, argc, argv);
- ospf6_lsdb_show_wrapper(vty, level, NULL, &id, &adv_router, uj, ospf6);
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ ospf6_lsdb_type_show_wrapper(vty, level, NULL, &id,
+ &adv_router, uj, ospf6);
+
+ if (!all_vrf)
+ break;
+ }
+ }
+
return CMD_SUCCESS;
}
-DEFUN (show_ipv6_ospf6_database_type_id_router,
- show_ipv6_ospf6_database_type_id_router_cmd,
- "show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> A.B.C.D A.B.C.D [<dump|internal>] [json]",
- SHOW_STR
- IPV6_STR
- OSPF6_STR
- "Display Link state database\n"
- "Display Router LSAs\n"
- "Display Network LSAs\n"
- "Display Inter-Area-Prefix LSAs\n"
- "Display Inter-Area-Router LSAs\n"
- "Display As-External LSAs\n"
- "Display Group-Membership LSAs\n"
- "Display Type-7 LSAs\n"
- "Display Link LSAs\n"
- "Display Intra-Area-Prefix LSAs\n"
- "Specify Link state ID as IPv4 address notation\n"
- "Specify Advertising Router as IPv4 address notation\n"
- "Dump LSAs\n"
- "Display LSA's internal information\n"
- JSON_STR)
+DEFUN(show_ipv6_ospf6_database_type_id_router,
+ show_ipv6_ospf6_database_type_id_router_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> A.B.C.D A.B.C.D [<dump|internal>] [json]",
+ SHOW_STR IPV6_STR OSPF6_STR VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "Display Link state database\n"
+ "Display Router LSAs\n"
+ "Display Network LSAs\n"
+ "Display Inter-Area-Prefix LSAs\n"
+ "Display Inter-Area-Router LSAs\n"
+ "Display As-External LSAs\n"
+ "Display Group-Membership LSAs\n"
+ "Display Type-7 LSAs\n"
+ "Display Link LSAs\n"
+ "Display Intra-Area-Prefix LSAs\n"
+ "Specify Link state ID as IPv4 address notation\n"
+ "Specify Advertising Router as IPv4 address notation\n"
+ "Dump LSAs\n"
+ "Display LSA's internal information\n" JSON_STR)
{
int idx_lsa = 4;
int idx_ls_id = 5;
int idx_adv_rtr = 6;
int idx_level = 7;
int level;
+ bool uj = use_json(argc, argv);
+ struct listnode *node;
+ struct ospf6 *ospf6;
uint16_t type = 0;
uint32_t id = 0;
uint32_t adv_router = 0;
- bool uj = use_json(argc, argv);
- struct ospf6 *ospf6;
-
-
- ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
- OSPF6_CMD_CHECK_RUNNING(ospf6);
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (idx_vrf > 0) {
+ idx_lsa += 2;
+ idx_ls_id += 2;
+ idx_adv_rtr += 2;
+ idx_level += 2;
+ }
type = parse_type_spec(idx_lsa, argc, argv);
inet_pton(AF_INET, argv[idx_ls_id]->arg, &id);
inet_pton(AF_INET, argv[idx_adv_rtr]->arg, &adv_router);
level = parse_show_level(idx_level, argc, argv);
- ospf6_lsdb_type_show_wrapper(vty, level, &type, &id, &adv_router, uj,
- ospf6);
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ ospf6_lsdb_type_show_wrapper(vty, level, &type, &id,
+ &adv_router, uj, ospf6);
+
+ if (!all_vrf)
+ break;
+ }
+ }
+
return CMD_SUCCESS;
}
DEFUN (show_ipv6_ospf6_database_type_adv_router_linkstate_id,
show_ipv6_ospf6_database_type_adv_router_linkstate_id_cmd,
- "show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> adv-router A.B.C.D linkstate-id A.B.C.D [<dump|internal>] [json]",
+ "show ipv6 ospf6 [vrf <NAME|all>] database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> adv-router A.B.C.D linkstate-id A.B.C.D [<dump|internal>] [json]",
SHOW_STR
IPV6_STR
OSPF6_STR
+ VRF_CMD_HELP_STR
+ "All VRFs\n"
"Display Link state database\n"
"Display Router LSAs\n"
"Display Network LSAs\n"
int idx_ls_id = 8;
int idx_level = 9;
int level;
+ bool uj = use_json(argc, argv);
+ struct listnode *node;
+ struct ospf6 *ospf6;
uint16_t type = 0;
uint32_t id = 0;
uint32_t adv_router = 0;
- bool uj = use_json(argc, argv);
- struct ospf6 *ospf6;
-
-
- ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
- OSPF6_CMD_CHECK_RUNNING(ospf6);
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (idx_vrf > 0) {
+ idx_lsa += 2;
+ idx_adv_rtr += 2;
+ idx_ls_id += 2;
+ idx_level += 2;
+ }
type = parse_type_spec(idx_lsa, argc, argv);
inet_pton(AF_INET, argv[idx_adv_rtr]->arg, &adv_router);
inet_pton(AF_INET, argv[idx_ls_id]->arg, &id);
level = parse_show_level(idx_level, argc, argv);
- ospf6_lsdb_type_show_wrapper(vty, level, &type, &id, &adv_router, uj,
- ospf6);
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ ospf6_lsdb_type_show_wrapper(vty, level, &type, &id,
+ &adv_router, uj, ospf6);
+
+ if (!all_vrf)
+ break;
+ }
+ }
+
return CMD_SUCCESS;
}
-DEFUN (show_ipv6_ospf6_database_self_originated,
- show_ipv6_ospf6_database_self_originated_cmd,
- "show ipv6 ospf6 database self-originated [<detail|dump|internal>] [json]",
- SHOW_STR
- IPV6_STR
- OSPF6_STR
- "Display Link state database\n"
- "Display Self-originated LSAs\n"
- "Display details of LSAs\n"
- "Dump LSAs\n"
- "Display LSA's internal information\n"
- JSON_STR)
+DEFUN(show_ipv6_ospf6_database_self_originated,
+ show_ipv6_ospf6_database_self_originated_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] database self-originated [<detail|dump|internal>] [json]",
+ SHOW_STR IPV6_STR OSPF6_STR VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "Display Link state database\n"
+ "Display Self-originated LSAs\n"
+ "Display details of LSAs\n"
+ "Dump LSAs\n"
+ "Display LSA's internal information\n" JSON_STR)
{
int idx_level = 5;
int level;
+ struct listnode *node;
+ struct ospf6 *ospf6;
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
uint32_t adv_router = 0;
bool uj = use_json(argc, argv);
- struct ospf6 *ospf6;
- ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
- OSPF6_CMD_CHECK_RUNNING(ospf6);
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (idx_vrf > 0)
+ idx_level += 2;
+
level = parse_show_level(idx_level, argc, argv);
- adv_router = ospf6->router_id;
- ospf6_lsdb_show_wrapper(vty, level, NULL, NULL, &adv_router, uj, ospf6);
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ adv_router = ospf6->router_id;
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ ospf6_lsdb_show_wrapper(vty, level, NULL, NULL,
+ &adv_router, uj, ospf6);
+
+ if (!all_vrf)
+ break;
+ }
+ }
+
return CMD_SUCCESS;
}
-DEFUN (show_ipv6_ospf6_database_type_self_originated,
- show_ipv6_ospf6_database_type_self_originated_cmd,
- "show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> self-originated [<detail|dump|internal>] [json]",
- SHOW_STR
- IPV6_STR
- OSPF6_STR
- "Display Link state database\n"
- "Display Router LSAs\n"
- "Display Network LSAs\n"
- "Display Inter-Area-Prefix LSAs\n"
- "Display Inter-Area-Router LSAs\n"
- "Display As-External LSAs\n"
- "Display Group-Membership LSAs\n"
- "Display Type-7 LSAs\n"
- "Display Link LSAs\n"
- "Display Intra-Area-Prefix LSAs\n"
- "Display Self-originated LSAs\n"
- "Display details of LSAs\n"
- "Dump LSAs\n"
- "Display LSA's internal information\n"
- JSON_STR)
+DEFUN(show_ipv6_ospf6_database_type_self_originated,
+ show_ipv6_ospf6_database_type_self_originated_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> self-originated [<detail|dump|internal>] [json]",
+ SHOW_STR IPV6_STR OSPF6_STR VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "Display Link state database\n"
+ "Display Router LSAs\n"
+ "Display Network LSAs\n"
+ "Display Inter-Area-Prefix LSAs\n"
+ "Display Inter-Area-Router LSAs\n"
+ "Display As-External LSAs\n"
+ "Display Group-Membership LSAs\n"
+ "Display Type-7 LSAs\n"
+ "Display Link LSAs\n"
+ "Display Intra-Area-Prefix LSAs\n"
+ "Display Self-originated LSAs\n"
+ "Display details of LSAs\n"
+ "Dump LSAs\n"
+ "Display LSA's internal information\n" JSON_STR)
{
int idx_lsa = 4;
int idx_level = 6;
int level;
+ struct listnode *node;
+ struct ospf6 *ospf6;
uint16_t type = 0;
uint32_t adv_router = 0;
bool uj = use_json(argc, argv);
- struct ospf6 *ospf6;
- ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
- OSPF6_CMD_CHECK_RUNNING(ospf6);
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (idx_vrf > 0) {
+ idx_lsa += 2;
+ idx_level += 2;
+ }
+
type = parse_type_spec(idx_lsa, argc, argv);
level = parse_show_level(idx_level, argc, argv);
- adv_router = ospf6->router_id;
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ adv_router = ospf6->router_id;
+ ospf6_lsdb_type_show_wrapper(vty, level, &type, NULL,
+ &adv_router, uj, ospf6);
+
+ if (!all_vrf)
+ break;
+ }
+ }
- ospf6_lsdb_type_show_wrapper(vty, level, &type, NULL, &adv_router, uj,
- ospf6);
return CMD_SUCCESS;
}
-DEFUN (show_ipv6_ospf6_database_type_self_originated_linkstate_id,
- show_ipv6_ospf6_database_type_self_originated_linkstate_id_cmd,
- "show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> self-originated linkstate-id A.B.C.D [<detail|dump|internal>] [json]",
- SHOW_STR
- IPV6_STR
- OSPF6_STR
- "Display Link state database\n"
- "Display Router LSAs\n"
- "Display Network LSAs\n"
- "Display Inter-Area-Prefix LSAs\n"
- "Display Inter-Area-Router LSAs\n"
- "Display As-External LSAs\n"
- "Display Group-Membership LSAs\n"
- "Display Type-7 LSAs\n"
- "Display Link LSAs\n"
- "Display Intra-Area-Prefix LSAs\n"
- "Display Self-originated LSAs\n"
- "Search by Link state ID\n"
- "Specify Link state ID as IPv4 address notation\n"
- "Display details of LSAs\n"
- "Dump LSAs\n"
- "Display LSA's internal information\n"
- JSON_STR)
+DEFUN(show_ipv6_ospf6_database_type_self_originated_linkstate_id,
+ show_ipv6_ospf6_database_type_self_originated_linkstate_id_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> self-originated linkstate-id A.B.C.D [<detail|dump|internal>] [json]",
+ SHOW_STR IPV6_STR OSPF6_STR VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "Display Link state database\n"
+ "Display Router LSAs\n"
+ "Display Network LSAs\n"
+ "Display Inter-Area-Prefix LSAs\n"
+ "Display Inter-Area-Router LSAs\n"
+ "Display As-External LSAs\n"
+ "Display Group-Membership LSAs\n"
+ "Display Type-7 LSAs\n"
+ "Display Link LSAs\n"
+ "Display Intra-Area-Prefix LSAs\n"
+ "Display Self-originated LSAs\n"
+ "Search by Link state ID\n"
+ "Specify Link state ID as IPv4 address notation\n"
+ "Display details of LSAs\n"
+ "Dump LSAs\n"
+ "Display LSA's internal information\n" JSON_STR)
{
int idx_lsa = 4;
int idx_ls_id = 7;
int idx_level = 8;
int level;
+ bool uj = use_json(argc, argv);
+ struct listnode *node;
+ struct ospf6 *ospf6;
uint16_t type = 0;
uint32_t adv_router = 0;
uint32_t id = 0;
- bool uj = use_json(argc, argv);
- struct ospf6 *ospf6;
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (idx_vrf > 0) {
+ idx_lsa += 2;
+ idx_ls_id += 2;
+ idx_level += 2;
+ }
+
- ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
- OSPF6_CMD_CHECK_RUNNING(ospf6);
type = parse_type_spec(idx_lsa, argc, argv);
inet_pton(AF_INET, argv[idx_ls_id]->arg, &id);
level = parse_show_level(idx_level, argc, argv);
- adv_router = ospf6->router_id;
- ospf6_lsdb_type_show_wrapper(vty, level, &type, &id, &adv_router, uj,
- ospf6);
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ adv_router = ospf6->router_id;
+ ospf6_lsdb_type_show_wrapper(vty, level, &type, &id,
+ &adv_router, uj, ospf6);
+
+ if (!all_vrf)
+ break;
+ }
+ }
+
return CMD_SUCCESS;
}
-DEFUN (show_ipv6_ospf6_database_type_id_self_originated,
- show_ipv6_ospf6_database_type_id_self_originated_cmd,
- "show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> A.B.C.D self-originated [<detail|dump|internal>] [json]",
- SHOW_STR
- IPV6_STR
- OSPF6_STR
- "Display Link state database\n"
- "Display Router LSAs\n"
- "Display Network LSAs\n"
- "Display Inter-Area-Prefix LSAs\n"
- "Display Inter-Area-Router LSAs\n"
- "Display As-External LSAs\n"
- "Display Group-Membership LSAs\n"
- "Display Type-7 LSAs\n"
- "Display Link LSAs\n"
- "Display Intra-Area-Prefix LSAs\n"
- "Specify Link state ID as IPv4 address notation\n"
- "Display Self-originated LSAs\n"
- "Display details of LSAs\n"
- "Dump LSAs\n"
- "Display LSA's internal information\n"
- JSON_STR)
+DEFUN(show_ipv6_ospf6_database_type_id_self_originated,
+ show_ipv6_ospf6_database_type_id_self_originated_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> A.B.C.D self-originated [<detail|dump|internal>] [json]",
+ SHOW_STR IPV6_STR OSPF6_STR VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "Display Link state database\n"
+ "Display Router LSAs\n"
+ "Display Network LSAs\n"
+ "Display Inter-Area-Prefix LSAs\n"
+ "Display Inter-Area-Router LSAs\n"
+ "Display As-External LSAs\n"
+ "Display Group-Membership LSAs\n"
+ "Display Type-7 LSAs\n"
+ "Display Link LSAs\n"
+ "Display Intra-Area-Prefix LSAs\n"
+ "Specify Link state ID as IPv4 address notation\n"
+ "Display Self-originated LSAs\n"
+ "Display details of LSAs\n"
+ "Dump LSAs\n"
+ "Display LSA's internal information\n" JSON_STR)
{
int idx_lsa = 4;
int idx_ls_id = 5;
int idx_level = 7;
int level;
+ bool uj = use_json(argc, argv);
+ struct listnode *node;
+ struct ospf6 *ospf6;
uint16_t type = 0;
uint32_t adv_router = 0;
uint32_t id = 0;
- bool uj = use_json(argc, argv);
- struct ospf6 *ospf6;
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (idx_vrf > 0) {
+ idx_lsa += 2;
+ idx_ls_id += 2;
+ idx_level += 2;
+ }
- ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
- OSPF6_CMD_CHECK_RUNNING(ospf6);
type = parse_type_spec(idx_lsa, argc, argv);
inet_pton(AF_INET, argv[idx_ls_id]->arg, &id);
level = parse_show_level(idx_level, argc, argv);
- adv_router = ospf6->router_id;
- ospf6_lsdb_type_show_wrapper(vty, level, &type, &id, &adv_router, uj,
- ospf6);
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ adv_router = ospf6->router_id;
+ ospf6_lsdb_type_show_wrapper(vty, level, &type, &id,
+ &adv_router, uj, ospf6);
+
+ if (!all_vrf)
+ break;
+ }
+ }
+
return CMD_SUCCESS;
}
-DEFUN (show_ipv6_ospf6_border_routers,
- show_ipv6_ospf6_border_routers_cmd,
- "show ipv6 ospf6 border-routers [<A.B.C.D|detail>]",
- SHOW_STR
- IP6_STR
- OSPF6_STR
- "Display routing table for ABR and ASBR\n"
- "Router ID\n"
- "Show detailed output\n")
+static int show_ospf6_border_routers_common(struct vty *vty, int argc,
+ struct cmd_token **argv,
+ struct ospf6 *ospf6, int idx_ipv4,
+ int idx_argc)
{
- int idx_ipv4 = 4;
uint32_t adv_router;
struct ospf6_route *ro;
struct prefix prefix;
- struct ospf6 *ospf6 = NULL;
- ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
- OSPF6_CMD_CHECK_RUNNING(ospf6);
- if (argc == 5) {
+ if (argc == idx_argc) {
if (strmatch(argv[idx_ipv4]->text, "detail")) {
for (ro = ospf6_route_head(ospf6->brouter_table); ro;
ro = ospf6_route_next(ro))
if (!ro) {
vty_out(vty,
"No Route found for Router ID: %s\n",
- argv[4]->arg);
+ argv[idx_ipv4]->arg);
return CMD_SUCCESS;
}
return CMD_SUCCESS;
}
+DEFUN(show_ipv6_ospf6_border_routers, show_ipv6_ospf6_border_routers_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] border-routers [<A.B.C.D|detail>]",
+ SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "Display routing table for ABR and ASBR\n"
+ "Router ID\n"
+ "Show detailed output\n")
+{
+ int idx_ipv4 = 4;
+ struct ospf6 *ospf6 = NULL;
+ struct listnode *node;
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+ int idx_argc = 5;
+
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (idx_vrf > 0) {
+ idx_argc += 2;
+ idx_ipv4 += 2;
+ }
-DEFUN (show_ipv6_ospf6_linkstate,
- show_ipv6_ospf6_linkstate_cmd,
- "show ipv6 ospf6 linkstate <router A.B.C.D|network A.B.C.D A.B.C.D>",
- SHOW_STR
- IP6_STR
- OSPF6_STR
- "Display linkstate routing table\n"
- "Display Router Entry\n"
- "Specify Router ID as IPv4 address notation\n"
- "Display Network Entry\n"
- "Specify Router ID as IPv4 address notation\n"
- "Specify Link state ID as IPv4 address notation\n")
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ show_ospf6_border_routers_common(vty, argc, argv, ospf6,
+ idx_ipv4, idx_argc);
+
+ if (!all_vrf)
+ break;
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+
+DEFUN(show_ipv6_ospf6_linkstate, show_ipv6_ospf6_linkstate_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] linkstate <router A.B.C.D|network A.B.C.D A.B.C.D>",
+ SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "Display linkstate routing table\n"
+ "Display Router Entry\n"
+ "Specify Router ID as IPv4 address notation\n"
+ "Display Network Entry\n"
+ "Specify Router ID as IPv4 address notation\n"
+ "Specify Link state ID as IPv4 address notation\n")
{
int idx_ipv4 = 5;
- struct listnode *node;
+ struct listnode *node, *nnode;
struct ospf6_area *oa;
struct ospf6 *ospf6 = NULL;
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (idx_vrf > 0)
+ idx_ipv4 += 2;
+
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, nnode, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) {
+ vty_out(vty,
+ "\n SPF Result in Area %s\n\n",
+ oa->name);
+ ospf6_linkstate_table_show(vty, idx_ipv4, argc,
+ argv, oa->spf_table);
+ }
+ vty_out(vty, "\n");
- ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
- OSPF6_CMD_CHECK_RUNNING(ospf6);
- for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) {
- vty_out(vty, "\n SPF Result in Area %s\n\n", oa->name);
- ospf6_linkstate_table_show(vty, idx_ipv4, argc, argv,
- oa->spf_table);
+ if (!all_vrf)
+ break;
+ }
}
- vty_out(vty, "\n");
return CMD_SUCCESS;
}
-DEFUN (show_ipv6_ospf6_linkstate_detail,
- show_ipv6_ospf6_linkstate_detail_cmd,
- "show ipv6 ospf6 linkstate detail",
- SHOW_STR
- IP6_STR
- OSPF6_STR
- "Display linkstate routing table\n"
- "Display detailed information\n")
+DEFUN(show_ipv6_ospf6_linkstate_detail, show_ipv6_ospf6_linkstate_detail_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] linkstate detail",
+ SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "Display linkstate routing table\n"
+ "Display detailed information\n")
{
int idx_detail = 4;
struct listnode *node;
struct ospf6_area *oa;
struct ospf6 *ospf6 = NULL;
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+
- ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
- OSPF6_CMD_CHECK_RUNNING(ospf6);
+ OSPF6_CMD_CHECK_RUNNING();
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (idx_vrf > 0)
+ idx_detail += 2;
- for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) {
- vty_out(vty, "\n SPF Result in Area %s\n\n", oa->name);
- ospf6_linkstate_table_show(vty, idx_detail, argc, argv,
- oa->spf_table);
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) {
+ vty_out(vty,
+ "\n SPF Result in Area %s\n\n",
+ oa->name);
+ ospf6_linkstate_table_show(vty, idx_detail,
+ argc, argv,
+ oa->spf_table);
+ }
+ vty_out(vty, "\n");
+
+ if (!all_vrf)
+ break;
+ }
}
- vty_out(vty, "\n");
return CMD_SUCCESS;
}
ospf6_asbr_init();
ospf6_abr_init();
+ /* initialize hooks for modifying filter rules */
prefix_list_add_hook(ospf6_plist_add);
prefix_list_delete_hook(ospf6_plist_del);
+ access_list_add_hook(ospf6_filter_update);
+ access_list_delete_hook(ospf6_filter_update);
ospf6_bfd_init();
install_node(&debug_node);
#define OSPF6_ROUTER_ID_STR "Specify Router-ID\n"
#define OSPF6_LS_ID_STR "Specify Link State ID\n"
-#define OSPF6_CMD_CHECK_RUNNING(ospf6) \
- if (ospf6 == NULL) { \
+#define OSPF6_CMD_CHECK_RUNNING() \
+ if (om6->ospf6 == NULL) { \
vty_out(vty, "OSPFv3 is not running\n"); \
return CMD_SUCCESS; \
}
#define IS_OSPF6_ASBR(O) ((O)->flag & OSPF6_FLAG_ASBR)
+#define OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf) \
+ if (argv_find(argv, argc, "vrf", &idx_vrf)) { \
+ vrf_name = argv[idx_vrf + 1]->arg; \
+ all_vrf = strmatch(vrf_name, "all"); \
+ } else { \
+ vrf_name = VRF_DEFAULT_NAME; \
+ }
+
extern struct zebra_privs_t ospf6d_privs;
/* Function Prototypes */
# end
ospf6d_ospf6d_snmp_la_SOURCES = ospf6d/ospf6_snmp.c
-ospf6d_ospf6d_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11
+ospf6d_ospf6d_snmp_la_CFLAGS = $(AM_CFLAGS) $(SNMP_CFLAGS) -std=gnu11
ospf6d_ospf6d_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
ospf6d_ospf6d_snmp_la_LIBADD = lib/libfrrsnmp.la
ospf_abr_task(ospf);
ospf_abr_nssa_task(ospf); /* if nssa-abr, then scan Type-7 LSDB */
- ospf_asbr_nssa_redist_task(ospf);
return 0;
}
struct external_info *new;
struct route_node *rn;
struct ospf_external *ext;
- char inetbuf[INET6_BUFSIZ];
ext = ospf_external_lookup(ospf, type, instance);
if (!ext)
rn = route_node_get(EXTERNAL_INFO(ext), (struct prefix *)&p);
/* If old info exists, -- discard new one or overwrite with new one? */
- if (rn)
- if (rn->info) {
- new = rn->info;
- if ((new->ifindex == ifindex)
- && (new->nexthop.s_addr == nexthop.s_addr)
- && (new->tag == tag)) {
- route_unlock_node(rn);
- return NULL; /* NULL => no LSA to refresh */
- }
-
- inet_ntop(AF_INET, (void *)&nexthop.s_addr, inetbuf,
- sizeof(inetbuf));
- if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
- zlog_debug(
- "Redistribute[%s][%d][%u]: %pFX discarding old info with NH %s.",
- ospf_redist_string(type), instance,
- ospf->vrf_id, &p, inetbuf);
- XFREE(MTYPE_OSPF_EXTERNAL_INFO, rn->info);
+ if (rn && rn->info) {
+ new = rn->info;
+ if ((new->ifindex == ifindex)
+ && (new->nexthop.s_addr == nexthop.s_addr)
+ && (new->tag == tag)) {
+ route_unlock_node(rn);
+ return NULL; /* NULL => no LSA to refresh */
}
+ if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
+ zlog_debug(
+ "Redistribute[%s][%d][%u]: %pFX discarding old info with NH %pI4.",
+ ospf_redist_string(type), instance,
+ ospf->vrf_id, &p, &nexthop.s_addr);
+ XFREE(MTYPE_OSPF_EXTERNAL_INFO, rn->info);
+ }
+
/* Create new External info instance. */
new = ospf_external_info_new(type, instance);
new->p = p;
rn->info = new;
if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) {
- inet_ntop(AF_INET, (void *)&nexthop.s_addr, inetbuf,
- sizeof(inetbuf));
zlog_debug(
- "Redistribute[%s][%u]: %pFX external info created, with NH %s",
- ospf_redist_string(type), ospf->vrf_id,
- &p, inetbuf);
+ "Redistribute[%s][%u]: %pFX external info created, with NH %pI4",
+ ospf_redist_string(type), ospf->vrf_id, &p,
+ &nexthop.s_addr);
}
return new;
}
/* If there's redistribution configured, we need to refresh external
* LSAs in order to install Type-7 and flood to all NSSA Areas
*/
-void ospf_asbr_nssa_redist_task(struct ospf *ospf)
+static int ospf_asbr_nssa_redist_update_timer(struct thread *thread)
{
+ struct ospf *ospf = THREAD_ARG(thread);
int type;
+ ospf->t_asbr_nssa_redist_update = NULL;
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug("Running ASBR NSSA redistribution update on timer");
+
for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
struct list *red_list;
struct listnode *node;
for (ALL_LIST_ELEMENTS_RO(red_list, node, red))
ospf_external_lsa_refresh_type(ospf, type,
red->instance,
- LSA_REFRESH_IF_CHANGED);
+ LSA_REFRESH_FORCE);
}
ospf_external_lsa_refresh_default(ospf);
+
+ return 0;
+}
+
+void ospf_schedule_asbr_nssa_redist_update(struct ospf *ospf)
+{
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug("Scheduling ASBR NSSA redistribution update");
+
+ thread_add_timer(master, ospf_asbr_nssa_redist_update_timer, ospf,
+ OSPF_ASBR_NSSA_REDIST_UPDATE_DELAY,
+ &ospf->t_asbr_nssa_redist_update);
}
void ospf_redistribute_withdraw(struct ospf *ospf, uint8_t type,
return;
/* Delete external info for specified type. */
- if (EXTERNAL_INFO(ext))
- for (rn = route_top(EXTERNAL_INFO(ext)); rn;
- rn = route_next(rn))
- if ((ei = rn->info))
- if (ospf_external_info_find_lsa(ospf, &ei->p)) {
- if (is_prefix_default(&ei->p)
- && ospf->default_originate
- != DEFAULT_ORIGINATE_NONE)
- continue;
- ospf_external_lsa_flush(
- ospf, type, &ei->p,
+ if (!EXTERNAL_INFO(ext))
+ return;
+
+ for (rn = route_top(EXTERNAL_INFO(ext)); rn; rn = route_next(rn)) {
+ ei = rn->info;
+
+ if (!ei)
+ continue;
+
+ struct ospf_external_aggr_rt *aggr;
+
+ if (is_prefix_default(&ei->p)
+ && ospf->default_originate != DEFAULT_ORIGINATE_NONE)
+ continue;
+
+ aggr = ei->aggr_route;
+
+ if (aggr)
+ ospf_unlink_ei_from_aggr(ospf, aggr, ei);
+ else if (ospf_external_info_find_lsa(ospf, &ei->p))
+ ospf_external_lsa_flush(ospf, type, &ei->p,
ei->ifindex /*, ei->nexthop */);
- ospf_external_info_free(ei);
- route_unlock_node(rn);
- rn->info = NULL;
- }
+ ospf_external_info_free(ei);
+ route_unlock_node(rn);
+ rn->info = NULL;
+ }
}
+
/* External Route Aggregator Handlers */
bool is_valid_summary_addr(struct prefix_ipv4 *p)
{
};
#define OSPF_ASBR_CHECK_DELAY 30
+#define OSPF_ASBR_NSSA_REDIST_UPDATE_DELAY 9
extern void ospf_external_route_remove(struct ospf *, struct prefix_ipv4 *);
extern struct external_info *ospf_external_info_new(uint8_t, unsigned short);
unsigned short,
struct prefix_ipv4 *);
extern void ospf_asbr_status_update(struct ospf *, uint8_t);
-extern void ospf_asbr_nssa_redist_task(struct ospf *ospf);
+extern void ospf_schedule_asbr_nssa_redist_update(struct ospf *ospf);
extern void ospf_redistribute_withdraw(struct ospf *, uint8_t, unsigned short);
extern void ospf_asbr_check(void);
bfd_sess_set_ipv4_addrs(nbr->bfd_session, NULL, &nbr->src);
bfd_sess_set_interface(nbr->bfd_session, oi->ifp->name);
bfd_sess_set_vrf(nbr->bfd_session, oi->ospf->vrf_id);
- bfd_sess_enable(nbr->bfd_session, true);
}
/* Set new configuration. */
/* 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;
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <zebra.h>
+
#include "lib/northbound.h"
#include "lib/routemap.h"
#include "ospf_routemap_nb.h"
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <zebra.h>
+
#include "lib/command.h"
#include "lib/log.h"
#include "lib/northbound.h"
#include "memory.h"
#include "smux.h"
#include "libfrr.h"
-#include "version.h"
+#include "lib/version.h"
#include "ospfd/ospfd.h"
#include "ospfd/ospf_interface.h"
* 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
else
srl->nhlfe[1].nexthop = exti->rmt_itf_addr.value;
break;
- default:
+ case PREF_SID:
+ case LOCAL_SID:
/* Wrong SID Type. Abort! */
XFREE(MTYPE_OSPF_SR_PARAMS, srl);
return;
/* Initialize TLV browsing */
tlvh = TLV_HDR_TOP(lsa->data);
+ uint32_t total_len = TLV_BODY_SIZE(lsa->data) - OSPF_LSA_HEADER_SIZE;
+
+ /* If TE Router-ID is only TLV we are done */
+ if (ntohs(tlvh->type) == TE_TLV_ROUTER_ADDR
+ && total_len == sizeof(struct te_tlv_router_addr))
+ return 0;
+
/* Skip TE Router-ID if present */
if (ntohs(tlvh->type) == TE_TLV_ROUTER_ADDR)
tlvh = TLV_HDR_NEXT(tlvh);
&lsa->data->id, &edge->attributes->standard.local);
/* Initialize TLV browsing */
- len = TLV_BODY_SIZE(&ext->header);
+ len = TLV_BODY_SIZE(&ext->header) - EXT_TLV_LINK_SIZE;
tlvh = (struct tlv_header *)((char *)(ext) + TLV_HDR_SIZE
+ EXT_TLV_LINK_SIZE);
for (; sum < len; tlvh = TLV_HDR_NEXT(tlvh)) {
/* Flush the external LSA for the specified area */
ospf_flush_lsa_from_area(ospf, area_id, OSPF_AS_EXTERNAL_LSA);
ospf_schedule_abr_task(ospf);
+ ospf_schedule_asbr_nssa_redist_update(ospf);
return CMD_SUCCESS;
}
vty_out(vty,
" No backup designated router on this network\n");
} else {
+ nbr = ospf_nbr_lookup_by_addr(oi->nbrs, &DR(oi));
+ if (nbr) {
+ if (use_json) {
+ json_object_string_add(
+ json_interface_sub, "drId",
+ inet_ntop(AF_INET,
+ &nbr->router_id, buf,
+ sizeof(buf)));
+ json_object_string_add(
+ json_interface_sub, "drAddress",
+ inet_ntop(
+ AF_INET,
+ &nbr->address.u.prefix4,
+ buf, sizeof(buf)));
+ } else {
+ vty_out(vty,
+ " Designated Router (ID) %pI4",
+ &nbr->router_id);
+ vty_out(vty,
+ " Interface Address %pFX\n",
+ &nbr->address);
+ }
+ }
+ nbr = NULL;
+
nbr = ospf_nbr_lookup_by_addr(oi->nbrs, &BDR(oi));
if (nbr == NULL) {
if (!use_json)
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;
int metric = -1;
struct ospf_redist *red;
int idx = 0;
+ bool update = false;
/* Get distribute source. */
source = proto_redistnum(AFI_IP, argv[idx_protocol]->text);
if (source < 0)
return CMD_WARNING_CONFIG_FAILED;
- red = ospf_redist_add(ospf, source, 0);
-
/* Get metric value. */
if (argv_find(argv, argc, "(0-16777214)", &idx)) {
if (!str2metric(argv[idx]->arg, &metric))
return CMD_WARNING_CONFIG_FAILED;
}
idx = 1;
+
+ red = ospf_redist_lookup(ospf, source, 0);
+ if (!red)
+ red = ospf_redist_add(ospf, source, 0);
+ else
+ update = true;
+
/* Get route-map */
if (argv_find(argv, argc, "WORD", &idx)) {
ospf_routemap_set(red, argv[idx]->arg);
} else
ospf_routemap_unset(red);
- return ospf_redistribute_set(ospf, source, 0, type, metric);
+ if (update)
+ return ospf_redistribute_update(ospf, red, source, 0, type,
+ metric);
+ else
+ return ospf_redistribute_set(ospf, red, source, 0, type,
+ metric);
}
DEFUN (no_ospf_redistribute_source,
int metric = -1;
unsigned short instance;
struct ospf_redist *red;
+ bool update = false;
source = proto_redistnum(AFI_IP, argv[idx_ospf_table]->text);
if (!str2metric_type(argv[idx + 1]->arg, &type))
return CMD_WARNING_CONFIG_FAILED;
- red = ospf_redist_add(ospf, source, instance);
+ red = ospf_redist_lookup(ospf, source, instance);
+ if (!red)
+ red = ospf_redist_add(ospf, source, instance);
+ else
+ update = true;
idx = 3;
if (argv_find(argv, argc, "route-map", &idx))
else
ospf_routemap_unset(red);
- return ospf_redistribute_set(ospf, source, instance, type, metric);
+ if (update)
+ return ospf_redistribute_update(ospf, red, source, instance,
+ type, metric);
+ else
+ return ospf_redistribute_set(ospf, red, source, instance, type,
+ metric);
}
DEFUN (no_ospf_redistribute_instance_source,
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);
}
}
break;
- default:
+ case ADJ_SID:
+ case LAN_ADJ_SID:
return;
}
ospf->vrf_id)
: ((instance
&& redist_check_instance(
- &zclient->mi_redist[AFI_IP][type],
- instance))
+ &zclient->mi_redist[AFI_IP][type],
+ instance))
|| (!instance
&& vrf_bitmap_check(
- zclient->redist[AFI_IP][type],
- ospf->vrf_id))));
+ zclient->redist[AFI_IP][type],
+ ospf->vrf_id))));
}
-int ospf_redistribute_set(struct ospf *ospf, int type, unsigned short instance,
- int mtype, int mvalue)
+int ospf_redistribute_update(struct ospf *ospf, struct ospf_redist *red,
+ int type, unsigned short instance, int mtype,
+ int mvalue)
{
int force = 0;
- struct ospf_redist *red;
-
- red = ospf_redist_lookup(ospf, type, instance);
- if (red == NULL) {
- zlog_err(
- "Redistribute[%s][%d]: Lookup failed Type[%d] , Metric[%d]",
- ospf_redist_string(type), instance,
- metric_type(ospf, type, instance),
- metric_value(ospf, type, instance));
- return CMD_WARNING_CONFIG_FAILED;
+ if (mtype != red->dmetric.type) {
+ red->dmetric.type = mtype;
+ force = LSA_REFRESH_FORCE;
+ }
+ if (mvalue != red->dmetric.value) {
+ red->dmetric.value = mvalue;
+ force = LSA_REFRESH_FORCE;
}
- if (ospf_is_type_redistributed(ospf, type, instance)) {
- if (mtype != red->dmetric.type) {
- red->dmetric.type = mtype;
- force = LSA_REFRESH_FORCE;
- }
- if (mvalue != red->dmetric.value) {
- red->dmetric.value = mvalue;
- force = LSA_REFRESH_FORCE;
- }
-
- ospf_external_lsa_refresh_type(ospf, type, instance, force);
+ ospf_external_lsa_refresh_type(ospf, type, instance, force);
- if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE))
- zlog_debug(
- "Redistribute[%s][%d]: Refresh Type[%d], Metric[%d]",
- ospf_redist_string(type), instance,
- metric_type(ospf, type, instance),
- metric_value(ospf, type, instance));
+ if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE))
+ zlog_debug(
+ "Redistribute[%s][%d]: Refresh Type[%d], Metric[%d]",
+ ospf_redist_string(type), instance,
+ metric_type(ospf, type, instance),
+ metric_value(ospf, type, instance));
- return CMD_SUCCESS;
- }
+ return CMD_SUCCESS;
+}
+int ospf_redistribute_set(struct ospf *ospf, struct ospf_redist *red, int type,
+ unsigned short instance, int mtype, int mvalue)
+{
red->dmetric.type = mtype;
red->dmetric.value = mvalue;
if (type == zclient->redist_default && instance == zclient->instance)
return CMD_SUCCESS;
- if (!ospf_is_type_redistributed(ospf, type, instance))
- return CMD_SUCCESS;
-
zclient_redistribute(ZEBRA_REDISTRIBUTE_DELETE, zclient, AFI_IP, type,
instance, ospf->vrf_id);
return 0;
}
if (ospf->router_id.s_addr != INADDR_ANY) {
- if (ei) {
- if (is_prefix_default(&p))
- ospf_external_lsa_refresh_default(ospf);
- else {
- struct ospf_external_aggr_rt *aggr;
- struct as_external_lsa *al;
- struct ospf_lsa *lsa = NULL;
- struct in_addr mask;
-
- aggr = ospf_external_aggr_match(ospf,
- &ei->p);
+ if (is_prefix_default(&p))
+ ospf_external_lsa_refresh_default(ospf);
+ else {
+ struct ospf_external_aggr_rt *aggr;
+ struct as_external_lsa *al;
+ struct ospf_lsa *lsa = NULL;
+ struct in_addr mask;
+
+ aggr = ospf_external_aggr_match(ospf, &ei->p);
+
+ if (aggr) {
+ /* Check the AS-external-LSA
+ * should be originated.
+ */
+ if (!ospf_redistribute_check(ospf, ei,
+ NULL))
+ return 0;
+
+ if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
+ zlog_debug(
+ "%s: Send Aggreate LSA (%pI4/%d)",
+ __func__,
+ &aggr->p.prefix,
+ aggr->p.prefixlen);
+
+ ospf_originate_summary_lsa(ospf, aggr,
+ ei);
+
+ /* Handling the case where the
+ * external route prefix
+ * and aggegate prefix is same
+ * If same dont flush the
+ * originated
+ * external LSA.
+ */
+ if (prefix_same(
+ (struct prefix *)&aggr->p,
+ (struct prefix *)&ei->p))
+ return 0;
+
+ lsa = ospf_external_info_find_lsa(
+ ospf, &ei->p);
+
+ if (lsa) {
+ al = (struct as_external_lsa *)
+ lsa->data;
+ masklen2ip(ei->p.prefixlen,
+ &mask);
+
+ if (mask.s_addr
+ != al->mask.s_addr)
+ return 0;
- if (aggr) {
- /* Check the AS-external-LSA
- * should be originated.
+ ospf_external_lsa_flush(
+ ospf, ei->type, &ei->p,
+ 0);
+ }
+ } else {
+ struct ospf_lsa *current;
+
+ current = ospf_external_info_find_lsa(
+ ospf, &ei->p);
+ if (!current) {
+ /* Check the
+ * AS-external-LSA
+ * should be
+ * originated.
*/
if (!ospf_redistribute_check(
ospf, ei, NULL))
return 0;
+ ospf_external_lsa_originate(
+ ospf, ei);
+ } else {
if (IS_DEBUG_OSPF(
- lsa,
- EXTNL_LSA_AGGR))
+ zebra,
+ ZEBRA_REDISTRIBUTE))
zlog_debug(
- "%s: Send Aggreate LSA (%pI4/%d)",
+ "%s: %pI4 refreshing LSA",
__func__,
- &aggr->p.prefix,
- aggr->p.prefixlen);
-
- ospf_originate_summary_lsa(
- ospf, aggr, ei);
-
- /* Handling the case where the
- * external route prefix
- * and aggegate prefix is same
- * If same dont flush the
- * originated
- * external LSA.
- */
- if (prefix_same(
- (struct prefix
- *)&aggr->p,
- (struct prefix *)&ei
- ->p))
- return 0;
-
- lsa = ospf_external_info_find_lsa(
- ospf, &ei->p);
-
- if (lsa) {
- al = (struct
- as_external_lsa *)
- lsa->data;
- masklen2ip(
- ei->p.prefixlen,
- &mask);
-
- if (mask.s_addr
- != al->mask.s_addr)
- return 0;
-
- ospf_external_lsa_flush(
- ospf, ei->type,
- &ei->p, 0);
- }
- } else {
- struct ospf_lsa *current;
-
- current =
- ospf_external_info_find_lsa(
- ospf, &ei->p);
- if (!current) {
- /* Check the
- * AS-external-LSA
- * should be
- * originated.
- */
- if (!ospf_redistribute_check(
- ospf, ei,
- NULL))
- return 0;
-
- ospf_external_lsa_originate(
- ospf, ei);
- } else {
- if (IS_DEBUG_OSPF(
- zebra,
- ZEBRA_REDISTRIBUTE))
- zlog_debug(
- "%s: %pI4 refreshing LSA",
- __func__,
- &p.prefix);
- ospf_external_lsa_refresh(
- ospf, current,
- ei,
- LSA_REFRESH_FORCE,
- false);
- }
+ &p.prefix);
+ ospf_external_lsa_refresh(
+ ospf, current, ei,
+ LSA_REFRESH_FORCE,
+ false);
}
}
}
*/
ospf_external_lsa_default_routemap_apply(ospf, ei, cmd);
- } else /* if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_DEL) */
- {
+ } else { /* if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_DEL) */
struct ospf_external_aggr_rt *aggr;
ei = ospf_external_info_lookup(ospf, rt_type, api.instance, &p);
if (ei == NULL)
return 0;
- else
- /*
- * Check if default-information originate i
- * with some routemap prefix/access list match.
- * Apply before ei is deleted.
- */
- ospf_external_lsa_default_routemap_apply(ospf, ei, cmd);
+
+ /*
+ * Check if default-information originate i
+ * with some routemap prefix/access list match.
+ * Apply before ei is deleted.
+ */
+ ospf_external_lsa_default_routemap_apply(ospf, ei, cmd);
aggr = ospf_external_aggr_match(ospf, &ei->p);
}
}
-
return 0;
}
rt = ext->external_info;
if (!rt)
continue;
- for (rn = route_top(rt); rn; rn = route_next(rn))
- if ((ei = rn->info) != NULL) {
- if (is_prefix_default(&ei->p))
- default_refresh = 1;
- else {
- struct ospf_external_aggr_rt
- *aggr;
- aggr = ospf_external_aggr_match(
- ospf, &ei->p);
- if (aggr) {
- /* Check the
- * AS-external-LSA
- * should be originated.
- */
- if (!ospf_redistribute_check(
- ospf, ei,
- NULL)) {
-
- ospf_unlink_ei_from_aggr(
- ospf,
- aggr,
- ei);
- continue;
- }
-
- if (IS_DEBUG_OSPF(
- lsa,
- EXTNL_LSA_AGGR))
- zlog_debug(
- "%s: Send Aggregate LSA (%pI4/%d)",
- __func__,
- &aggr->p.prefix,
- aggr->p.prefixlen);
-
- /* Originate Aggregate
- * LSA
- */
- ospf_originate_summary_lsa(
+ for (rn = route_top(rt); rn; rn = route_next(rn)) {
+ ei = rn->info;
+ if (!ei)
+ continue;
+
+ if (is_prefix_default(&ei->p))
+ default_refresh = 1;
+ else {
+ struct ospf_external_aggr_rt *aggr;
+
+ aggr = ospf_external_aggr_match(ospf,
+ &ei->p);
+ if (aggr) {
+ /* Check the
+ * AS-external-LSA
+ * should be originated.
+ */
+ if (!ospf_redistribute_check(
+ ospf, ei, NULL)) {
+
+ ospf_unlink_ei_from_aggr(
ospf, aggr, ei);
- } else if (
- (lsa = ospf_external_info_find_lsa(
- ospf,
- &ei->p))) {
- int force =
- LSA_REFRESH_IF_CHANGED;
- /* If this is a MaxAge
- * LSA, we need to
- * force refresh it
- * because distribute
- * settings might have
- * changed and now,
- * this LSA needs to be
- * originated, not be
- * removed.
- * If we don't force
- * refresh it, it will
- * remain a MaxAge LSA
- * because it will look
- * like it hasn't
- * changed. Neighbors
- * will not receive
- * updates for this LSA.
- */
- if (IS_LSA_MAXAGE(lsa))
- force = LSA_REFRESH_FORCE;
-
- ospf_external_lsa_refresh(
- ospf, lsa, ei,
- force, false);
- } else {
- if (!ospf_redistribute_check(
- ospf, ei,
- NULL))
- continue;
- ospf_external_lsa_originate(
- ospf, ei);
+ continue;
}
+
+ if (IS_DEBUG_OSPF(
+ lsa,
+ EXTNL_LSA_AGGR))
+ zlog_debug(
+ "%s: Send Aggregate LSA (%pI4/%d)",
+ __func__,
+ &aggr->p.prefix,
+ aggr->p.prefixlen);
+
+ /* Originate Aggregate
+ * LSA
+ */
+ ospf_originate_summary_lsa(
+ ospf, aggr, ei);
+ } else if (
+ (lsa = ospf_external_info_find_lsa(
+ ospf, &ei->p))) {
+ int force =
+ LSA_REFRESH_IF_CHANGED;
+ /* If this is a MaxAge
+ * LSA, we need to
+ * force refresh it
+ * because distribute
+ * settings might have
+ * changed and now,
+ * this LSA needs to be
+ * originated, not be
+ * removed.
+ * If we don't force
+ * refresh it, it will
+ * remain a MaxAge LSA
+ * because it will look
+ * like it hasn't
+ * changed. Neighbors
+ * will not receive
+ * updates for this LSA.
+ */
+ if (IS_LSA_MAXAGE(lsa))
+ force = LSA_REFRESH_FORCE;
+
+ ospf_external_lsa_refresh(
+ ospf, lsa, ei, force,
+ false);
+ } else {
+ if (!ospf_redistribute_check(
+ ospf, ei, NULL))
+ continue;
+ ospf_external_lsa_originate(
+ ospf, ei);
}
}
+ }
}
}
if (default_refresh)
struct ospf_redist *red;
red_list = ospf->redist[type];
- if (red_list) {
- for (ALL_LIST_ELEMENTS_RO(red_list, node,
- red)) {
- if (ROUTEMAP(red)) {
- /* if route-map is not NULL
- * it may be using
- * this prefix list */
- ospf_distribute_list_update(
- ospf, type,
- red->instance);
- }
+ if (!red_list)
+ continue;
+
+ for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) {
+ if (ROUTEMAP(red)) {
+ /* if route-map is not NULL
+ * it may be using
+ * this prefix list */
+ ospf_distribute_list_update(
+ ospf, type, red->instance);
}
}
}
/* Update area filter-lists. */
for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area)) {
/* Update filter-list in. */
- if (PREFIX_NAME_IN(area))
- if (strcmp(PREFIX_NAME_IN(area),
- prefix_list_name(plist))
- == 0) {
- PREFIX_LIST_IN(area) =
- prefix_list_lookup(
- AFI_IP,
- PREFIX_NAME_IN(area));
- abr_inv++;
- }
+ if (PREFIX_NAME_IN(area)
+ && strcmp(PREFIX_NAME_IN(area),
+ prefix_list_name(plist))
+ == 0) {
+ PREFIX_LIST_IN(area) = prefix_list_lookup(
+ AFI_IP, PREFIX_NAME_IN(area));
+ abr_inv++;
+ }
/* Update filter-list out. */
- if (PREFIX_NAME_OUT(area))
- if (strcmp(PREFIX_NAME_OUT(area),
- prefix_list_name(plist))
- == 0) {
- PREFIX_LIST_IN(area) =
- prefix_list_lookup(
- AFI_IP,
- PREFIX_NAME_OUT(area));
- abr_inv++;
- }
+ if (PREFIX_NAME_OUT(area)
+ && strcmp(PREFIX_NAME_OUT(area),
+ prefix_list_name(plist))
+ == 0) {
+ PREFIX_LIST_IN(area) = prefix_list_lookup(
+ AFI_IP, PREFIX_NAME_OUT(area));
+ abr_inv++;
+ }
}
/* Schedule ABR task. */
struct route_node *rn;
struct ospf_distance *odistance;
- for (rn = route_top(ospf->distance_table); rn; rn = route_next(rn))
- if ((odistance = rn->info) != NULL) {
- if (odistance->access_list)
- free(odistance->access_list);
- ospf_distance_free(odistance);
- rn->info = NULL;
- route_unlock_node(rn);
- }
+ for (rn = route_top(ospf->distance_table); rn; rn = route_next(rn)) {
+ odistance = rn->info;
+ if (!odistance)
+ continue;
+
+ if (odistance->access_list)
+ free(odistance->access_list);
+ ospf_distance_free(odistance);
+ rn->info = NULL;
+ route_unlock_node(rn);
+ }
}
uint8_t ospf_distance_apply(struct ospf *ospf, struct prefix_ipv4 *p,
if (ospf == NULL)
return 0;
- if (ospf->distance_intra)
- if (or->path_type == OSPF_PATH_INTRA_AREA)
- return ospf->distance_intra;
+ if (ospf->distance_intra && or->path_type == OSPF_PATH_INTRA_AREA)
+ return ospf->distance_intra;
- if (ospf->distance_inter)
- if (or->path_type == OSPF_PATH_INTER_AREA)
- return ospf->distance_inter;
+ if (ospf->distance_inter && or->path_type == OSPF_PATH_INTER_AREA)
+ return ospf->distance_inter;
- if (ospf->distance_external)
- if (or->path_type == OSPF_PATH_TYPE1_EXTERNAL ||
- or->path_type == OSPF_PATH_TYPE2_EXTERNAL)
- return ospf->distance_external;
+ if (ospf->distance_external
+ && (or->path_type == OSPF_PATH_TYPE1_EXTERNAL ||
+ or->path_type == OSPF_PATH_TYPE2_EXTERNAL))
+ return ospf->distance_external;
if (ospf->distance_all)
return ospf->distance_all;
unsigned short);
extern void ospf_redist_del(struct ospf *, uint8_t, unsigned short);
-extern int ospf_redistribute_set(struct ospf *, int, unsigned short, int, int);
+extern int ospf_redistribute_update(struct ospf *, struct ospf_redist *, int,
+ unsigned short, int, int);
+extern int ospf_redistribute_set(struct ospf *, struct ospf_redist *, int,
+ unsigned short, int, int);
extern int ospf_redistribute_unset(struct ospf *, int, unsigned short);
extern int ospf_redistribute_default_set(struct ospf *, int, int, int);
-extern int ospf_redistribute_default_unset(struct ospf *);
extern int ospf_distribute_list_out_set(struct ospf *, int, const char *);
extern int ospf_distribute_list_out_unset(struct ospf *, int, const char *);
extern void ospf_routemap_set(struct ospf_redist *, const char *);
struct ospf_area *area;
struct ospf_vl_data *vl_data;
struct listnode *node, *nnode;
+ struct ospf_redist *red;
int i;
QOBJ_UNREG(ospf);
/* Unregister redistribution */
for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
struct list *red_list;
- struct ospf_redist *red;
red_list = ospf->redist[i];
if (!red_list)
ospf_redist_del(ospf, i, red->instance);
}
}
- ospf_redistribute_default_set(ospf, DEFAULT_ORIGINATE_NONE, 0, 0);
+ red = ospf_redist_lookup(ospf, DEFAULT_ROUTE, 0);
+ if (red) {
+ ospf_routemap_unset(red);
+ ospf_redist_del(ospf, DEFAULT_ROUTE, 0);
+ ospf_redistribute_default_set(ospf, DEFAULT_ORIGINATE_NONE, 0, 0);
+ }
for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area))
ospf_remove_vls_through_area(ospf, area);
OSPF_TIMER_OFF(ospf->t_maxage_walker);
OSPF_TIMER_OFF(ospf->t_abr_task);
OSPF_TIMER_OFF(ospf->t_asbr_check);
+ OSPF_TIMER_OFF(ospf->t_asbr_nssa_redist_update);
OSPF_TIMER_OFF(ospf->t_distribute_update);
OSPF_TIMER_OFF(ospf->t_lsa_refresher);
OSPF_TIMER_OFF(ospf->t_opaque_lsa_self);
/* 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);
return 0;
}
-static void ospf_set_redist_vrf_bitmaps(struct ospf *ospf)
+static void ospf_set_redist_vrf_bitmaps(struct ospf *ospf, bool set)
{
int type;
struct list *red_list;
zlog_debug(
"%s: setting redist vrf %d bitmap for type %d",
__func__, ospf->vrf_id, type);
- vrf_bitmap_set(zclient->redist[AFI_IP][type], ospf->vrf_id);
+ if (set)
+ vrf_bitmap_set(zclient->redist[AFI_IP][type],
+ ospf->vrf_id);
+ else
+ vrf_bitmap_unset(zclient->redist[AFI_IP][type],
+ ospf->vrf_id);
}
}
__func__, vrf->name, ospf->vrf_id, old_vrf_id);
if (old_vrf_id != ospf->vrf_id) {
- frr_with_privs(&ospfd_privs) {
- /* stop zebra redist to us for old vrf */
- zclient_send_dereg_requests(zclient,
- old_vrf_id);
-
- ospf_set_redist_vrf_bitmaps(ospf);
+ ospf_set_redist_vrf_bitmaps(ospf, true);
- /* start zebra redist to us for new vrf */
- ospf_zebra_vrf_register(ospf);
+ /* start zebra redist to us for new vrf */
+ ospf_zebra_vrf_register(ospf);
- ret = ospf_sock_init(ospf);
- }
+ ret = ospf_sock_init(ospf);
if (ret < 0 || ospf->fd <= 0)
return 0;
thread_add_read(master, ospf_read, ospf, ospf->fd,
if (ospf) {
old_vrf_id = ospf->vrf_id;
+ ospf_zebra_vrf_deregister(ospf);
+
+ ospf_set_redist_vrf_bitmaps(ospf, false);
+
/* We have instance configured, unlink
* from VRF and make it "down".
*/
/* Threads. */
struct thread *t_abr_task; /* ABR task timer. */
struct thread *t_asbr_check; /* ASBR check timer. */
+ struct thread *t_asbr_nssa_redist_update; /* ASBR NSSA redistribution
+ update timer. */
struct thread *t_distribute_update; /* Distirbute list update timer. */
struct thread *t_spf_calc; /* SPF calculation timer. */
struct thread *t_ase_calc; /* ASE calculation timer. */
ospfd_ospfd_SOURCES = ospfd/ospf_main.c
ospfd_ospfd_snmp_la_SOURCES = ospfd/ospf_snmp.c
-ospfd_ospfd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11
+ospfd_ospfd_snmp_la_CFLAGS = $(AM_CFLAGS) $(SNMP_CFLAGS) -std=gnu11
ospfd_ospfd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
ospfd_ospfd_snmp_la_LIBADD = lib/libfrrsnmp.la
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <zebra.h>
+
#include <float.h>
#include <math.h>
#include <zebra.h>
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <zebra.h>
+
#include <string.h>
#include <stdbool.h>
#include <time.h>
#include "command.h"
#include "libfrr.h"
#include "printfrr.h"
-#include "version.h"
+#include "lib/version.h"
#include "northbound.h"
#include "frr_pthread.h"
#include "jhash.h"
/* ------------ Module Functions ------------ */
-int pcep_module_late_init(struct thread_master *tm)
+/* this creates threads, therefore must run after fork(). but it must also
+ * run before config load, so the CLI commands don't try to touch things that
+ * aren't set up yet...
+ */
+static int pcep_module_config_pre(struct thread_master *tm)
{
assert(pcep_g->fpt == NULL);
assert(pcep_g->master == NULL);
pcep_g->master = tm;
pcep_g->fpt = fpt;
+ return 0;
+}
+
+static int pcep_module_late_init(struct thread_master *tm)
+{
hook_register(pathd_candidate_created, pathd_candidate_created_handler);
hook_register(pathd_candidate_updated, pathd_candidate_updated_handler);
hook_register(pathd_candidate_removed, pathd_candidate_removed_handler);
+ hook_register(frr_config_pre, pcep_module_config_pre);
hook_register(frr_fini, pcep_module_finish);
pcep_cli_init();
#include "command.h"
#include "libfrr.h"
#include "printfrr.h"
-#include "version.h"
+#include "lib/version.h"
#include "northbound.h"
#include "frr_pthread.h"
#include "jhash.h"
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <zebra.h>
+
#include <northbound.h>
#include <yang.h>
#include <printfrr.h>
#include "command.h"
#include "libfrr.h"
#include "printfrr.h"
-#include "version.h"
+#include "lib/version.h"
#include "northbound.h"
#include "frr_pthread.h"
#include "jhash.h"
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <zebra.h>
+
#include <string.h>
#include <stdbool.h>
#include <time.h>
#include "command.h"
#include "libfrr.h"
#include "printfrr.h"
-#include "version.h"
+#include "lib/version.h"
#include "northbound.h"
#include "frr_pthread.h"
#include "jhash.h"
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <zebra.h>
+
#include "thread.h"
#include "log.h"
#include "lib_errors.h"
if PATHD
noinst_LIBRARIES += pathd/libpath.a
sbin_PROGRAMS += pathd/pathd
-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
endif
-pathd_pathd_pcep_la_CFLAGS = $(WERROR)
+#pathd_pathd_pcep_la_CFLAGS = $(AM_CFLAGS)
pathd_pathd_pcep_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
{
struct pbr_interface *pbr_ifp;
- zassert(ifp);
- zassert(!ifp->info);
+ assert(ifp);
+ assert(!ifp->info);
pbr_ifp = XCALLOC(MTYPE_PBR_INTERFACE, sizeof(*pbr_ifp));
* This is the implementation of a High Level PCEP message API.
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <string.h>
#include <arpa/inet.h>
#include <stdarg.h>
* Encoding and decoding for PCEP messages.
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
* Author : Brady Johnson <brady@voltanet.io>
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <stdlib.h>
#include "pcep_msg_object_error_types.h"
* This is the implementation of a High Level PCEP message object API.
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <string.h>
#include <arpa/inet.h>
#include <stdarg.h>
* Encoding and decoding for PCEP Objects.
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <stdlib.h>
#include <string.h>
* This is the implementation of a High Level PCEP message object TLV API.
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <errno.h>
#include <stdio.h>
#include <string.h>
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <errno.h>
#include <limits.h>
#include <pthread.h>
* PCEP session logic counters configuration.
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <stdio.h>
#include <time.h>
*
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <pthread.h>
#include <stdbool.h>
#include <stdio.h>
*
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <pthread.h>
#include <stdbool.h>
#include <stdio.h>
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <errno.h>
#include <stdbool.h>
#include <stddef.h>
* created.
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <netinet/in.h>
#include <stdbool.h>
#include <stdlib.h>
* Implementation of public API timer functions.
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <limits.h>
#include <pthread.h>
#include <stddef.h>
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <errno.h>
#include <stddef.h>
#include <stdbool.h>
*
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <stddef.h>
#include <string.h>
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <stdarg.h>
#include <stdio.h>
#include "pcep_utils_logging.h"
*
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <stdlib.h>
#include <string.h>
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <stdio.h>
#include <string.h>
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
if PATHD_PCEP
noinst_LTLIBRARIES = pceplib/libpcep_pcc.la pceplib/libsocket_comm_mock.la
-pceplib_libpcep_pcc_la_CFLAGS = -fPIC
+pceplib_libpcep_pcc_la_CFLAGS = $(AM_CFLAGS) -fPIC
pceplib_libpcep_pcc_la_SOURCES = pceplib/pcep_msg_messages.c \
pceplib/pcep_msg_objects.c \
pceplib/pcep_msg_tlvs.c \
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <stdlib.h>
#include <CUnit/CUnit.h>
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <CUnit/Basic.h>
#include <CUnit/CUnit.h>
#include <CUnit/TestDB.h>
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <stdio.h>
#include <CUnit/CUnit.h>
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <stdlib.h>
#include <CUnit/CUnit.h>
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <netdb.h> // gethostbyname
#include <pthread.h>
#include <stdlib.h>
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <CUnit/Basic.h>
#include <CUnit/CUnit.h>
#include <CUnit/TestDB.h>
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <stdlib.h>
#include <string.h>
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <stdlib.h>
#include <string.h>
#include <time.h>
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <CUnit/Basic.h>
#include <CUnit/CUnit.h>
#include <CUnit/TestDB.h>
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <pthread.h>
#include <stdlib.h>
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <netinet/in.h>
#include <CUnit/CUnit.h>
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <CUnit/Basic.h>
#include <CUnit/CUnit.h>
#include <CUnit/TestDB.h>
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <stdlib.h>
#include <CUnit/CUnit.h>
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <stdbool.h>
#include <CUnit/CUnit.h>
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <CUnit/Basic.h>
#include <CUnit/CUnit.h>
#include <CUnit/TestDB.h>
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <stdlib.h>
#include <CUnit/CUnit.h>
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <CUnit/CUnit.h>
#include "pcep_utils_double_linked_list.h"
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <stdlib.h>
#include <stdint.h>
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <CUnit/CUnit.h>
#include "pcep_utils_ordered_list.h"
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <CUnit/CUnit.h>
#include "pcep_utils_queue.h"
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <CUnit/Basic.h>
#include <CUnit/CUnit.h>
#include <CUnit/TestDB.h>
pceplib/test/pcep_utils_ordered_list_test.h \
pceplib/test/pcep_utils_queue_test.h
-pceplib_test_pcep_msg_tests_CFLAGS = -I$(top_srcdir)/pceplib
+pceplib_test_pcep_msg_tests_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/pceplib
pceplib_test_pcep_msg_tests_LDADD = $(top_builddir)/pceplib/libpcep_pcc.la lib/libfrr.la -lcunit -lpthread
pceplib_test_pcep_msg_tests_SOURCES = pceplib/test/pcep_msg_messages_test.c \
pceplib/test/pcep_msg_messages_tests.c \
# The pcc_api_tests and pcep_session_logic_tests use the
# socket_comm_mock, so the LDADD variable needs to be modified
-pceplib_test_pcep_pcc_api_tests_CFLAGS = -I$(top_srcdir)/pceplib
+pceplib_test_pcep_pcc_api_tests_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/pceplib
pceplib_test_pcep_pcc_api_tests_LDADD = $(top_builddir)/pceplib/libsocket_comm_mock.la $(top_builddir)/pceplib/libpcep_pcc.la lib/libfrr.la -lcunit -lpthread
pceplib_test_pcep_pcc_api_tests_SOURCES = pceplib/test/pcep_pcc_api_test.c pceplib/test/pcep_pcc_api_tests.c
msg_metric.ip_address = src_addr;
pim_ifp = ifp->info;
- zassert(pim_ifp);
+ assert(pim_ifp);
++pim_ifp->pim_ifstat_assert_recv;
return dispatch_assert(ifp, msg_source_addr.u.prefix4, sg.grp,
void pim_bfd_write_config(struct vty *vty, struct interface *ifp)
{
struct pim_interface *pim_ifp = ifp->info;
- struct bfd_info *bfd_info = NULL;
- if (!pim_ifp)
- return;
-
- bfd_info = pim_ifp->bfd_info;
- if (!bfd_info)
+ if (!pim_ifp || !pim_ifp->bfd_config.enabled)
return;
#if HAVE_BFDD == 0
- if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG))
- vty_out(vty, " ip pim bfd %d %d %d\n", bfd_info->detect_mult,
- bfd_info->required_min_rx, bfd_info->desired_min_tx);
+ if (pim_ifp->bfd_config.detection_multiplier != BFD_DEF_DETECT_MULT
+ || pim_ifp->bfd_config.min_rx != BFD_DEF_MIN_RX
+ || pim_ifp->bfd_config.min_tx != BFD_DEF_MIN_TX)
+ vty_out(vty, " ip pim bfd %d %d %d\n",
+ pim_ifp->bfd_config.detection_multiplier,
+ pim_ifp->bfd_config.min_rx, pim_ifp->bfd_config.min_tx);
else
#endif /* ! HAVE_BFDD */
vty_out(vty, " ip pim bfd\n");
+
+ if (pim_ifp->bfd_config.profile)
+ vty_out(vty, " ip pim bfd profile %s\n",
+ pim_ifp->bfd_config.profile);
}
-/*
- * pim_bfd_show_info - Show BFD info structure
- */
-void pim_bfd_show_info(struct vty *vty, void *bfd_info, json_object *json_obj,
- bool use_json, int param_only)
+static void pim_neighbor_bfd_cb(struct bfd_session_params *bsp,
+ const struct bfd_session_status *bss, void *arg)
{
- if (param_only)
- bfd_show_param(vty, (struct bfd_info *)bfd_info, 1, 0, use_json,
- json_obj);
- else
- bfd_show_info(vty, (struct bfd_info *)bfd_info, 0, 1, use_json,
- json_obj);
+ struct pim_neighbor *nbr = arg;
+
+ if (PIM_DEBUG_PIM_TRACE) {
+ zlog_debug("%s: status %s old_status %s", __func__,
+ bfd_get_status_str(bss->state),
+ bfd_get_status_str(bss->previous_state));
+ }
+
+ if (bss->state == BFD_STATUS_DOWN
+ && bss->previous_state == BFD_STATUS_UP)
+ pim_neighbor_delete(nbr->interface, nbr, "BFD Session Expired");
}
/*
void pim_bfd_info_nbr_create(struct pim_interface *pim_ifp,
struct pim_neighbor *neigh)
{
- struct bfd_info *nbr_bfd_info = NULL;
-
/* Check if Pim Interface BFD is enabled */
- if (!pim_ifp || !pim_ifp->bfd_info)
- return;
-
- if (!neigh->bfd_info)
- neigh->bfd_info = bfd_info_create();
-
- if (!neigh->bfd_info)
- return;
-
- nbr_bfd_info = neigh->bfd_info;
- nbr_bfd_info->detect_mult = pim_ifp->bfd_info->detect_mult;
- nbr_bfd_info->desired_min_tx = pim_ifp->bfd_info->desired_min_tx;
- nbr_bfd_info->required_min_rx = pim_ifp->bfd_info->required_min_rx;
-}
-
-/*
- * pim_bfd_info_free - Free BFD info structure
- */
-void pim_bfd_info_free(struct bfd_info **bfd_info)
-{
- bfd_info_free(bfd_info);
-}
-
-static void pim_bfd_reg_dereg_nbr(struct pim_neighbor *nbr, int command)
-{
- struct pim_interface *pim_ifp = NULL;
- struct bfd_info *bfd_info = NULL;
- struct zclient *zclient = NULL;
- int cbit;
-
- zclient = pim_zebra_zclient_get();
-
- if (!nbr)
+ if (!pim_ifp || !pim_ifp->bfd_config.enabled)
return;
- pim_ifp = nbr->interface->info;
- bfd_info = pim_ifp->bfd_info;
- if (!bfd_info)
- return;
- if (PIM_DEBUG_PIM_TRACE) {
- char str[INET_ADDRSTRLEN];
- pim_inet4_dump("<bfd_nbr?>", nbr->source_addr, str,
- sizeof(str));
- zlog_debug("%s Nbr %s %s with BFD", __func__, str,
- bfd_get_command_dbg_str(command));
- }
- cbit = CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON);
+ if (neigh->bfd_session == NULL)
+ neigh->bfd_session = bfd_sess_new(pim_neighbor_bfd_cb, neigh);
- bfd_peer_sendmsg(zclient, bfd_info, AF_INET, &nbr->source_addr, NULL,
- nbr->interface->name, 0, 0, cbit,
- command, 0, VRF_DEFAULT);
+ bfd_sess_set_timers(
+ neigh->bfd_session, pim_ifp->bfd_config.detection_multiplier,
+ pim_ifp->bfd_config.min_rx, pim_ifp->bfd_config.min_tx);
+ bfd_sess_set_ipv4_addrs(neigh->bfd_session, NULL, &neigh->source_addr);
+ bfd_sess_set_interface(neigh->bfd_session, neigh->interface->name);
+ bfd_sess_set_profile(neigh->bfd_session, pim_ifp->bfd_config.profile);
+ bfd_sess_install(neigh->bfd_session);
}
/*
* zebra for starting/stopping the monitoring of
* the neighbor rechahability.
*/
-int pim_bfd_reg_dereg_all_nbr(struct interface *ifp, int command)
+void pim_bfd_reg_dereg_all_nbr(struct interface *ifp)
{
struct pim_interface *pim_ifp = NULL;
struct listnode *node = NULL;
pim_ifp = ifp->info;
if (!pim_ifp)
- return -1;
- if (!pim_ifp->bfd_info)
- return -1;
+ return;
for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) {
- if (command != ZEBRA_BFD_DEST_DEREGISTER)
+ if (pim_ifp->bfd_config.enabled)
pim_bfd_info_nbr_create(pim_ifp, neigh);
else
- pim_bfd_info_free((struct bfd_info **)&neigh->bfd_info);
-
- pim_bfd_reg_dereg_nbr(neigh, command);
- }
-
- return 0;
-}
-
-/*
- * pim_bfd_trigger_event - Neighbor is registered/deregistered with BFD when
- * neighbor state is changed to/from 2way.
- */
-void pim_bfd_trigger_event(struct pim_interface *pim_ifp,
- struct pim_neighbor *nbr, uint8_t nbr_up)
-{
- if (nbr_up) {
- pim_bfd_info_nbr_create(pim_ifp, nbr);
- pim_bfd_reg_dereg_nbr(nbr, ZEBRA_BFD_DEST_REGISTER);
- } else {
- pim_bfd_info_free(&nbr->bfd_info);
- pim_bfd_reg_dereg_nbr(nbr, ZEBRA_BFD_DEST_DEREGISTER);
- }
-}
-
-/*
- * pim_bfd_if_param_set - Set the configured BFD paramter values for
- * interface.
- */
-void pim_bfd_if_param_set(struct interface *ifp, uint32_t min_rx,
- uint32_t min_tx, uint8_t detect_mult, int defaults)
-{
- struct pim_interface *pim_ifp = ifp->info;
- int command = 0;
-
- if (!pim_ifp)
- return;
- bfd_set_param(&(pim_ifp->bfd_info), min_rx, min_tx, detect_mult, NULL,
- defaults, &command);
-
- if (pim_ifp->bfd_info) {
- if (PIM_DEBUG_PIM_TRACE)
- zlog_debug("%s: interface %s has bfd_info", __func__,
- ifp->name);
- }
- if (command)
- pim_bfd_reg_dereg_all_nbr(ifp, command);
-}
-
-
-/*
- * pim_bfd_interface_dest_update - Find the neighbor for which the BFD status
- * has changed and bring down the neighbor
- * connectivity if the BFD status changed to
- * down.
- */
-static int pim_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS)
-{
- struct interface *ifp = NULL;
- struct pim_interface *pim_ifp = NULL;
- struct prefix p, src_p;
- int status;
- char msg[100];
- int old_status;
- struct bfd_info *bfd_info = NULL;
- struct timeval tv;
- struct listnode *neigh_node = NULL;
- struct listnode *neigh_nextnode = NULL;
- struct pim_neighbor *neigh = NULL;
-
- ifp = bfd_get_peer_info(zclient->ibuf, &p, &src_p, &status, NULL,
- vrf_id);
-
- if ((ifp == NULL) || (p.family != AF_INET))
- return 0;
-
- pim_ifp = ifp->info;
- if (!pim_ifp)
- return 0;
-
- if (!pim_ifp->bfd_info) {
- if (PIM_DEBUG_PIM_TRACE)
- zlog_debug("%s: pim interface %s BFD is disabled ",
- __func__, ifp->name);
- return 0;
+ bfd_sess_free(&neigh->bfd_session);
}
-
- if (PIM_DEBUG_PIM_TRACE)
- zlog_debug("%s: interface %s bfd destination %pFX %s", __func__,
- ifp->name, &p, bfd_get_status_str(status));
-
- for (ALL_LIST_ELEMENTS(pim_ifp->pim_neighbor_list, neigh_node,
- neigh_nextnode, neigh)) {
- /* Check neigh address matches with BFD address */
- if (neigh->source_addr.s_addr != p.u.prefix4.s_addr)
- continue;
-
- bfd_info = (struct bfd_info *)neigh->bfd_info;
- if (bfd_info->status == status) {
- if (PIM_DEBUG_PIM_TRACE) {
- char str[INET_ADDRSTRLEN];
- pim_inet4_dump("<nht_nbr?>", neigh->source_addr,
- str, sizeof(str));
- zlog_debug("%s: bfd status is same for nbr %s",
- __func__, str);
- }
- continue;
- }
- old_status = bfd_info->status;
- BFD_SET_CLIENT_STATUS(bfd_info->status, status);
- monotime(&tv);
- bfd_info->last_update = tv.tv_sec;
-
- if (PIM_DEBUG_PIM_TRACE) {
- zlog_debug("%s: status %s old_status %s", __func__,
- bfd_get_status_str(status),
- bfd_get_status_str(old_status));
- }
- if ((status == BFD_STATUS_DOWN)
- && (old_status == BFD_STATUS_UP)) {
- snprintf(msg, sizeof(msg), "BFD Session Expired");
- pim_neighbor_delete(ifp, neigh, msg);
- }
- }
- return 0;
-}
-
-/*
- * pim_bfd_nbr_replay - Replay all the neighbors that have BFD enabled
- * to zebra
- */
-static int pim_bfd_nbr_replay(ZAPI_CALLBACK_ARGS)
-{
- struct interface *ifp = NULL;
- struct pim_interface *pim_ifp = NULL;
- struct pim_neighbor *neigh = NULL;
- struct listnode *neigh_node;
- struct listnode *neigh_nextnode;
- struct vrf *vrf = NULL;
-
- /* Send the client registration */
- bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id);
-
- RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
- FOR_ALL_INTERFACES (vrf, ifp) {
- pim_ifp = ifp->info;
-
- if (!pim_ifp)
- continue;
-
- if (pim_ifp->pim_sock_fd < 0)
- continue;
-
- for (ALL_LIST_ELEMENTS(pim_ifp->pim_neighbor_list,
- neigh_node, neigh_nextnode,
- neigh)) {
- if (!neigh->bfd_info)
- continue;
- if (PIM_DEBUG_PIM_TRACE) {
- char str[INET_ADDRSTRLEN];
-
- pim_inet4_dump("<bfd_nbr?>",
- neigh->source_addr, str,
- sizeof(str));
- zlog_debug(
- "%s: Replaying Pim Neigh %s to BFD vrf_id %u",
- __func__, str, vrf->vrf_id);
- }
- pim_bfd_reg_dereg_nbr(neigh,
- ZEBRA_BFD_DEST_UPDATE);
- }
- }
- }
- return 0;
}
void pim_bfd_init(void)
{
- struct zclient *zclient = NULL;
-
- zclient = pim_zebra_zclient_get();
-
- bfd_gbl_init();
-
- zclient->interface_bfd_dest_update = pim_bfd_interface_dest_update;
- zclient->bfd_dest_replay = pim_bfd_nbr_replay;
+ bfd_protocol_integration_init(pim_zebra_zclient_get(), router->master);
}
#include "if.h"
+/**
+ * Initializes PIM BFD integration code.
+ */
void pim_bfd_init(void);
+
+/**
+ * Write configuration to `show running-config`.
+ *
+ * \param vty the vty output pointer.
+ * \param ifp the interface pointer that has the configuration.
+ */
void pim_bfd_write_config(struct vty *vty, struct interface *ifp);
-void pim_bfd_show_info(struct vty *vty, void *bfd_info, json_object *json_obj,
- bool use_json, int param_only);
-void pim_bfd_if_param_set(struct interface *ifp, uint32_t min_rx,
- uint32_t min_tx, uint8_t detect_mult, int defaults);
-int pim_bfd_reg_dereg_all_nbr(struct interface *ifp, int command);
-void pim_bfd_trigger_event(struct pim_interface *pim_ifp,
- struct pim_neighbor *nbr, uint8_t nbr_up);
+
+/**
+ * Enables or disables all peers BFD sessions.
+ *
+ * \param ifp interface pointer.
+ * \param enable session state to set.
+ */
+void pim_bfd_reg_dereg_all_nbr(struct interface *ifp);
+
+/**
+ * Create and configure peer BFD session if it does not exist. It will use
+ * the interface configured parameters as the peer configuration.
+ *
+ * \param pim_ifp the interface configuration pointer.
+ * \param neigh the neighbor configuration pointer.
+ */
void pim_bfd_info_nbr_create(struct pim_interface *pim_ifp,
struct pim_neighbor *neigh);
-void pim_bfd_info_free(struct bfd_info **bfd_info);
+
#endif /* _PIM_BFD_H */
/* Memory Types */
DEFINE_MTYPE_STATIC(PIMD, PIM_BSGRP_NODE, "PIM BSR advertised grp info");
-DEFINE_MTYPE_STATIC(PIMD, PIM_BSRP_NODE, "PIM BSR advertised RP info");
-DEFINE_MTYPE_STATIC(PIMD, PIM_BSM_INFO, "PIM BSM Info");
+DEFINE_MTYPE_STATIC(PIMD, PIM_BSRP_INFO, "PIM BSR advertised RP info");
+DEFINE_MTYPE_STATIC(PIMD, PIM_BSM_FRAG, "PIM BSM fragment");
DEFINE_MTYPE_STATIC(PIMD, PIM_BSM_PKT_VAR_MEM, "PIM BSM Packet");
/* All bsm packets forwarded shall be fit within ip mtu less iphdr(max) */
}
}
+static void pim_bsm_rpinfo_free(struct bsm_rpinfo *bsrp_info)
+{
+ THREAD_OFF(bsrp_info->g2rp_timer);
+ XFREE(MTYPE_PIM_BSRP_INFO, bsrp_info);
+}
+
+void pim_bsm_rpinfos_free(struct bsm_rpinfos_head *head)
+{
+ struct bsm_rpinfo *bsrp_info;
+
+ while ((bsrp_info = bsm_rpinfos_pop(head)))
+ pim_bsm_rpinfo_free(bsrp_info);
+}
+
void pim_free_bsgrp_data(struct bsgrp_node *bsgrp_node)
{
- if (bsgrp_node->bsrp_list)
- list_delete(&bsgrp_node->bsrp_list);
- if (bsgrp_node->partial_bsrp_list)
- list_delete(&bsgrp_node->partial_bsrp_list);
+ pim_bsm_rpinfos_free(bsgrp_node->bsrp_list);
+ pim_bsm_rpinfos_free(bsgrp_node->partial_bsrp_list);
XFREE(MTYPE_PIM_BSGRP_NODE, bsgrp_node);
}
}
}
-static void pim_bsm_node_free(struct bsm_info *bsm)
+static void pim_bsm_frag_free(struct bsm_frag *bsfrag)
{
- XFREE(MTYPE_PIM_BSM_PKT_VAR_MEM, bsm->bsm);
- XFREE(MTYPE_PIM_BSM_INFO, bsm);
+ XFREE(MTYPE_PIM_BSM_FRAG, bsfrag);
}
-static int pim_g2rp_list_compare(struct bsm_rpinfo *node1,
- struct bsm_rpinfo *node2)
+void pim_bsm_frags_free(struct bsm_scope *scope)
+{
+ struct bsm_frag *bsfrag;
+
+ while ((bsfrag = bsm_frags_pop(scope->bsm_frags)))
+ pim_bsm_frag_free(bsfrag);
+}
+
+int pim_bsm_rpinfo_cmp(const struct bsm_rpinfo *node1,
+ const struct bsm_rpinfo *node2)
{
/* RP election Algo :
* Step-1 : Loweset Rp priority will have higher precedance.
return 0;
}
-static void pim_free_bsrp_node(struct bsm_rpinfo *bsrp_info)
-{
- THREAD_OFF(bsrp_info->g2rp_timer);
- XFREE(MTYPE_PIM_BSRP_NODE, bsrp_info);
-}
-
-static struct list *pim_alloc_bsrp_list(void)
-{
- struct list *new_list = NULL;
-
- new_list = list_new();
-
- if (!new_list)
- return NULL;
-
- new_list->cmp = (int (*)(void *, void *))pim_g2rp_list_compare;
- new_list->del = (void (*)(void *))pim_free_bsrp_node;
-
- return new_list;
-}
-
static struct bsgrp_node *pim_bsm_new_bsgrp_node(struct route_table *rt,
struct prefix *grp)
{
bsgrp = XCALLOC(MTYPE_PIM_BSGRP_NODE, sizeof(struct bsgrp_node));
rn->info = bsgrp;
- bsgrp->bsrp_list = pim_alloc_bsrp_list();
- bsgrp->partial_bsrp_list = pim_alloc_bsrp_list();
-
- if ((!bsgrp->bsrp_list) || (!bsgrp->partial_bsrp_list)) {
- route_unlock_node(rn);
- pim_free_bsgrp_data(bsgrp);
- return NULL;
- }
+ bsm_rpinfos_init(bsgrp->bsrp_list);
+ bsm_rpinfos_init(bsgrp->partial_bsrp_list);
prefix_copy(&bsgrp->group, grp);
return bsgrp;
scope->current_bsr_first_ts = 0;
scope->current_bsr_last_ts = 0;
scope->bsm_frag_tag = 0;
- list_delete_all_node(scope->bsm_list);
+ pim_bsm_frags_free(scope);
for (rn = route_top(scope->bsrp_table); rn; rn = route_next(rn)) {
continue;
}
/* Give grace time for rp to continue for another hold time */
- if ((bsgrp_node->bsrp_list) && (bsgrp_node->bsrp_list->count)) {
- bsrp = listnode_head(bsgrp_node->bsrp_list);
+ bsrp = bsm_rpinfos_first(bsgrp_node->bsrp_list);
+ if (bsrp)
pim_g2rp_timer_restart(bsrp, bsrp->rp_holdtime);
- }
+
/* clear pending list */
- if ((bsgrp_node->partial_bsrp_list)
- && (bsgrp_node->partial_bsrp_list->count)) {
- list_delete_all_node(bsgrp_node->partial_bsrp_list);
- bsgrp_node->pend_rp_cnt = 0;
- }
+ pim_bsm_rpinfos_free(bsgrp_node->partial_bsrp_list);
+ bsgrp_node->pend_rp_cnt = 0;
}
return 0;
}
pim->global_scope.accept_nofwd_bsm = true;
pim->global_scope.state = NO_INFO;
pim->global_scope.pim = pim;
- pim->global_scope.bsm_list = list_new();
- pim->global_scope.bsm_list->del = (void (*)(void *))pim_bsm_node_free;
+ bsm_frags_init(pim->global_scope.bsm_frags);
pim_bs_timer_start(&pim->global_scope, PIM_BS_TIME);
}
struct bsgrp_node *bsgrp;
pim_bs_timer_stop(&pim->global_scope);
-
- if (pim->global_scope.bsm_list)
- list_delete(&pim->global_scope.bsm_list);
+ pim_bsm_frags_free(&pim->global_scope);
for (rn = route_top(pim->global_scope.bsrp_table); rn;
rn = route_next(rn)) {
struct bsm_rpinfo *bsrp;
struct bsm_rpinfo *bsrp_node;
struct bsgrp_node *bsgrp_node;
- struct listnode *bsrp_ln;
struct pim_instance *pim;
struct rp_info *rp_info;
struct route_node *rn;
bsrp_addr = bsrp->rp_address;
/* update elapse for all bsrp nodes */
- for (ALL_LIST_ELEMENTS_RO(bsgrp_node->bsrp_list, bsrp_ln, bsrp_node))
+ frr_each_safe (bsm_rpinfos, bsgrp_node->bsrp_list, bsrp_node) {
bsrp_node->elapse_time += elapse;
- /* remove the expired nodes from the list */
- list_filter_out_nodes(bsgrp_node->bsrp_list, is_hold_time_elapsed);
+ if (is_hold_time_elapsed(bsrp_node)) {
+ bsm_rpinfos_del(bsgrp_node->bsrp_list, bsrp_node);
+ pim_bsm_rpinfo_free(bsrp_node);
+ }
+ }
/* Get the next elected rp node */
- bsrp = listnode_head(bsgrp_node->bsrp_list);
+ bsrp = bsm_rpinfos_first(bsgrp_node->bsrp_list);
pim = bsgrp_node->scope->pim;
rn = route_node_lookup(pim->rp_table, &bsgrp_node->group);
}
}
- if ((!bsgrp_node->bsrp_list->count)
- && (!bsgrp_node->partial_bsrp_list->count)) {
+ if (!bsm_rpinfos_count(bsgrp_node->bsrp_list)
+ && !bsm_rpinfos_count(bsgrp_node->partial_bsrp_list)) {
pim_free_bsgrp_node(pim->global_scope.bsrp_table,
&bsgrp_node->group);
pim_free_bsgrp_data(bsgrp_node);
{
struct bsm_rpinfo *active;
struct bsm_rpinfo *pend;
- struct list *temp;
struct rp_info *rp_info;
struct route_node *rn;
struct pim_instance *pim;
bool had_rp_node = true;
pim = bsgrp_node->scope->pim;
- active = listnode_head(bsgrp_node->bsrp_list);
+ active = bsm_rpinfos_first(bsgrp_node->bsrp_list);
/* Remove nodes with hold time 0 & check if list still has a head */
- list_filter_out_nodes(bsgrp_node->partial_bsrp_list, is_hold_time_zero);
- pend = listnode_head(bsgrp_node->partial_bsrp_list);
+ frr_each_safe (bsm_rpinfos, bsgrp_node->partial_bsrp_list, pend)
+ if (is_hold_time_zero(pend))
+ bsm_rpinfos_del(bsgrp_node->partial_bsrp_list, pend);
+
+ pend = bsm_rpinfos_first(bsgrp_node->partial_bsrp_list);
if (!str2prefix("224.0.0.0/4", &group_all))
return;
* pend is head of bsrp list
* So check appriate head after swap and clean the new partial list
*/
- temp = bsgrp_node->bsrp_list;
- bsgrp_node->bsrp_list = bsgrp_node->partial_bsrp_list;
- bsgrp_node->partial_bsrp_list = temp;
+ bsm_rpinfos_swap_all(bsgrp_node->bsrp_list,
+ bsgrp_node->partial_bsrp_list);
- if (active) {
+ if (active)
pim_g2rp_timer_stop(active);
- list_delete_all_node(bsgrp_node->partial_bsrp_list);
- }
+ pim_bsm_rpinfos_free(bsgrp_node->partial_bsrp_list);
}
static bool pim_bsr_rpf_check(struct pim_instance *pim, struct in_addr bsr,
struct in_addr dst_addr;
struct pim_interface *pim_ifp;
struct bsm_scope *scope;
- struct listnode *bsm_ln;
- struct bsm_info *bsminfo;
+ struct bsm_frag *bsfrag;
char neigh_src_str[INET_ADDRSTRLEN];
uint32_t pim_mtu;
bool no_fwd = true;
scope = &pim_ifp->pim->global_scope;
- if (!scope->bsm_list->count) {
+ if (!bsm_frags_count(scope->bsm_frags)) {
if (PIM_DEBUG_BSM)
zlog_debug("%s: BSM list for the scope is empty",
__func__);
pim_mtu = ifp->mtu - MAX_IP_HDR_LEN;
pim_hello_require(ifp);
- for (ALL_LIST_ELEMENTS_RO(scope->bsm_list, bsm_ln, bsminfo)) {
- if (pim_mtu < bsminfo->size) {
- ret = pim_bsm_frag_send(bsminfo->bsm, bsminfo->size,
- ifp, pim_mtu, dst_addr, no_fwd);
+ frr_each (bsm_frags, scope->bsm_frags, bsfrag) {
+ if (pim_mtu < bsfrag->size) {
+ ret = pim_bsm_frag_send(bsfrag->data, bsfrag->size, ifp,
+ pim_mtu, dst_addr, no_fwd);
if (!ret) {
if (PIM_DEBUG_BSM)
zlog_debug(
}
} else {
/* Pim header needs to be constructed */
- pim_msg_build_header(bsminfo->bsm, bsminfo->size,
+ pim_msg_build_header(bsfrag->data, bsfrag->size,
PIM_MSG_TYPE_BOOTSTRAP, no_fwd);
- ret = pim_bsm_send_intf(bsminfo->bsm, bsminfo->size,
- ifp, dst_addr);
+ ret = pim_bsm_send_intf(bsfrag->data, bsfrag->size, ifp,
+ dst_addr);
if (!ret) {
if (PIM_DEBUG_BSM)
zlog_debug(
uint8_t hashMask_len = pim->global_scope.hashMasklen;
/*memory allocation for bsm_rpinfo */
- bsm_rpinfo = XCALLOC(MTYPE_PIM_BSRP_NODE, sizeof(*bsm_rpinfo));
+ bsm_rpinfo = XCALLOC(MTYPE_PIM_BSRP_INFO, sizeof(*bsm_rpinfo));
bsm_rpinfo->rp_prio = rp->rp_pri;
bsm_rpinfo->rp_holdtime = rp->rp_holdtime;
/* update hash for this rp node */
bsm_rpinfo->hash = hash_calc_on_grp_rp(grpnode->group, rp->rpaddr.addr,
hashMask_len);
- if (listnode_add_sort_nodup(grpnode->partial_bsrp_list, bsm_rpinfo)) {
+ if (bsm_rpinfos_add(grpnode->partial_bsrp_list, bsm_rpinfo) == NULL) {
if (PIM_DEBUG_BSM)
zlog_debug(
"%s, bs_rpinfo node added to the partial bs_rplist.",
if (PIM_DEBUG_BSM)
zlog_debug("%s: list node not added", __func__);
- XFREE(MTYPE_PIM_BSRP_NODE, bsm_rpinfo);
+ XFREE(MTYPE_PIM_BSRP_INFO, bsm_rpinfo);
return false;
}
zlog_debug(
"%s,Received a new BSM ,so clear the pending bs_rpinfo list.",
__func__);
- list_delete_all_node(bsgrp->partial_bsrp_list);
+ pim_bsm_rpinfos_free(bsgrp->partial_bsrp_list);
bsgrp->pend_rp_cnt = total_rp_count;
}
} else
int sz = PIM_GBL_SZ_ID;
struct bsmmsg_grpinfo *msg_grp;
struct pim_interface *pim_ifp = NULL;
- struct bsm_info *bsminfo;
+ struct bsm_frag *bsfrag;
struct pim_instance *pim;
char bsr_str[INET_ADDRSTRLEN];
uint16_t frag_tag;
pim_ifp->pim->global_scope.bsm_frag_tag,
frag_tag);
}
- list_delete_all_node(pim_ifp->pim->global_scope.bsm_list);
+ pim_bsm_frags_free(&pim_ifp->pim->global_scope);
pim_ifp->pim->global_scope.bsm_frag_tag = frag_tag;
}
if (!no_fwd) {
pim_bsm_fwd_whole_sz(pim_ifp->pim, buf, buf_size, sz);
- bsminfo = XCALLOC(MTYPE_PIM_BSM_INFO, sizeof(struct bsm_info));
-
- bsminfo->bsm = XCALLOC(MTYPE_PIM_BSM_PKT_VAR_MEM, buf_size);
+ bsfrag = XCALLOC(MTYPE_PIM_BSM_FRAG,
+ sizeof(struct bsm_frag) + buf_size);
- bsminfo->size = buf_size;
- memcpy(bsminfo->bsm, buf, buf_size);
- listnode_add(pim_ifp->pim->global_scope.bsm_list, bsminfo);
+ bsfrag->size = buf_size;
+ memcpy(bsfrag->data, buf, buf_size);
+ bsm_frags_add_tail(pim_ifp->pim->global_scope.bsm_frags,
+ bsfrag);
}
return 0;
#include "if.h"
#include "vty.h"
-#include "linklist.h"
+#include "typesafe.h"
#include "table.h"
#include "pim_rp.h"
#include "pim_msg.h"
ACCEPT_PREFERRED
};
+PREDECL_DLIST(bsm_frags);
+
/* BSM scope - bsm processing is per scope */
struct bsm_scope {
int sz_id; /* scope zone id */
uint16_t bsm_frag_tag; /* Last received frag tag from E-BSR */
uint8_t hashMasklen; /* Mask in hash calc RFC 7761 4.7.2 */
struct pim_instance *pim; /* Back pointer to pim instance */
- struct list *bsm_list; /* list of bsm frag for frowarding */
+
+ /* current set of fragments for forwarding */
+ struct bsm_frags_head bsm_frags[1];
+
struct route_table *bsrp_table; /* group2rp mapping rcvd from BSR */
struct thread *bs_timer; /* Boot strap timer */
- struct thread *sz_timer;
};
-/* BSM packet - this is stored as list in bsm_list inside scope
+/* BSM packet (= fragment) - this is stored as list in bsm_frags inside scope
* This is used for forwarding to new neighbors or restarting mcast routers
*/
-struct bsm_info {
- uint32_t size; /* size of the packet */
- unsigned char *bsm; /* Actual packet */
+struct bsm_frag {
+ struct bsm_frags_item item;
+
+ uint32_t size; /* size of the packet */
+ uint8_t data[0]; /* Actual packet (dyn size) */
};
+DECLARE_DLIST(bsm_frags, struct bsm_frag, item);
+
+PREDECL_SORTLIST_UNIQ(bsm_rpinfos);
+
/* This is the group node of the bsrp table in scope.
* this node maintains the list of rp for the group.
*/
struct bsgrp_node {
struct prefix group; /* Group range */
struct bsm_scope *scope; /* Back ptr to scope */
- struct list *bsrp_list; /* list of RPs adv by BSR */
- struct list *partial_bsrp_list; /* maintained until all RPs received */
+
+ /* RPs advertised by BSR, and temporary list while receiving new set */
+ struct bsm_rpinfos_head bsrp_list[1];
+ struct bsm_rpinfos_head partial_bsrp_list[1];
+
int pend_rp_cnt; /* Total RP - Received RP */
uint16_t frag_tag; /* frag tag to identify the fragment */
};
-/* This is the list node of bsrp_list and partial bsrp list in
- * bsgrp_node. Hold info of each RP received for the group
+/* Items on [partial_]bsrp_list above.
+ * Holds info of each candidate RP received for the bsgrp_node's prefix.
*/
struct bsm_rpinfo {
+ struct bsm_rpinfos_item item;
+
uint32_t hash; /* Hash Value as per RFC 7761 4.7.2 */
uint32_t elapse_time; /* upd at expiry of elected RP node */
uint16_t rp_prio; /* RP priority */
struct thread *g2rp_timer; /* Run only for elected RP node */
};
+extern int pim_bsm_rpinfo_cmp(const struct bsm_rpinfo *a,
+ const struct bsm_rpinfo *b);
+DECLARE_SORTLIST_UNIQ(bsm_rpinfos, struct bsm_rpinfo, item, pim_bsm_rpinfo_cmp);
+
/* Structures to extract Bootstrap Message header and Grp to RP Mappings
* =====================================================================
* BSM Format:
struct bsgrp_node *pim_bsm_get_bsgrp_node(struct bsm_scope *scope,
struct prefix *grp);
void pim_bs_timer_stop(struct bsm_scope *scope);
+void pim_bsm_frags_free(struct bsm_scope *scope);
+void pim_bsm_rpinfos_free(struct bsm_rpinfos_head *head);
void pim_free_bsgrp_data(struct bsgrp_node *bsgrp_node);
void pim_free_bsgrp_node(struct route_table *rt, struct prefix *grp);
#endif
vty_out(vty,
" Hello Option - T-bit : %s\n",
option_t_bit ? "yes" : "no");
- pim_bfd_show_info(vty, neigh->bfd_info,
- json_ifp, uj, 0);
+ bfd_sess_show(vty, json_ifp,
+ neigh->bfd_session);
vty_out(vty, "\n");
}
}
/* Display the bsm database details */
static void pim_show_bsm_db(struct pim_instance *pim, struct vty *vty, bool uj)
{
- struct listnode *bsmnode;
int count = 0;
int fragment = 1;
- struct bsm_info *bsm;
+ struct bsm_frag *bsfrag;
json_object *json = NULL;
json_object *json_group = NULL;
json_object *json_row = NULL;
- count = pim->global_scope.bsm_list->count;
+ count = bsm_frags_count(pim->global_scope.bsm_frags);
if (uj) {
json = json_object_new_object();
vty_out(vty, "\n");
}
- for (ALL_LIST_ELEMENTS_RO(pim->global_scope.bsm_list, bsmnode, bsm)) {
+ frr_each (bsm_frags, pim->global_scope.bsm_frags, bsfrag) {
char grp_str[PREFIX_STRLEN];
char rp_str[INET_ADDRSTRLEN];
char bsr_str[INET_ADDRSTRLEN];
uint32_t len = 0;
uint32_t frag_rp_cnt = 0;
- buf = bsm->bsm;
- len = bsm->size;
+ buf = bsfrag->data;
+ len = bsfrag->size;
/* skip pim header */
buf += PIM_MSG_HEADER_LEN;
struct vty *vty, bool uj)
{
struct bsgrp_node *bsgrp;
- struct listnode *rpnode;
struct bsm_rpinfo *bsm_rp;
struct route_node *rn;
char bsr_str[INET_ADDRSTRLEN];
vty_out(vty, "(ACTIVE)\n");
}
- if (bsgrp->bsrp_list) {
- for (ALL_LIST_ELEMENTS_RO(bsgrp->bsrp_list, rpnode,
- bsm_rp)) {
- char rp_str[INET_ADDRSTRLEN];
+ frr_each (bsm_rpinfos, bsgrp->bsrp_list, bsm_rp) {
+ char rp_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<Rp Address?>",
- bsm_rp->rp_address, rp_str,
- sizeof(rp_str));
+ pim_inet4_dump("<Rp Address?>", bsm_rp->rp_address,
+ rp_str, sizeof(rp_str));
- if (uj) {
- json_row = json_object_new_object();
- json_object_string_add(
- json_row, "Rp Address", rp_str);
- json_object_int_add(
- json_row, "Rp HoldTime",
- bsm_rp->rp_holdtime);
- json_object_int_add(json_row,
- "Rp Priority",
- bsm_rp->rp_prio);
- json_object_int_add(json_row,
- "Hash Val",
- bsm_rp->hash);
- json_object_object_add(
- json_group, rp_str, json_row);
+ if (uj) {
+ json_row = json_object_new_object();
+ json_object_string_add(json_row, "Rp Address",
+ rp_str);
+ json_object_int_add(json_row, "Rp HoldTime",
+ bsm_rp->rp_holdtime);
+ json_object_int_add(json_row, "Rp Priority",
+ bsm_rp->rp_prio);
+ json_object_int_add(json_row, "Hash Val",
+ bsm_rp->hash);
+ json_object_object_add(json_group, rp_str,
+ json_row);
- } else {
- vty_out(vty,
- "%-15s %-15u %-15u %-15u\n",
- rp_str, bsm_rp->rp_prio,
- bsm_rp->rp_holdtime,
- bsm_rp->hash);
- }
+ } else {
+ vty_out(vty, "%-15s %-15u %-15u %-15u\n",
+ rp_str, bsm_rp->rp_prio,
+ bsm_rp->rp_holdtime, bsm_rp->hash);
}
- if (!bsgrp->bsrp_list->count && !uj)
- vty_out(vty, "Active List is empty.\n");
}
+ if (!bsm_rpinfos_count(bsgrp->bsrp_list) && !uj)
+ vty_out(vty, "Active List is empty.\n");
if (uj) {
json_object_int_add(json_group, "Pending RP count",
"Hash");
}
- if (bsgrp->partial_bsrp_list) {
- for (ALL_LIST_ELEMENTS_RO(bsgrp->partial_bsrp_list,
- rpnode, bsm_rp)) {
- char rp_str[INET_ADDRSTRLEN];
+ frr_each (bsm_rpinfos, bsgrp->partial_bsrp_list, bsm_rp) {
+ char rp_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<Rp Addr?>", bsm_rp->rp_address,
- rp_str, sizeof(rp_str));
+ pim_inet4_dump("<Rp Addr?>", bsm_rp->rp_address, rp_str,
+ sizeof(rp_str));
- if (uj) {
- json_row = json_object_new_object();
- json_object_string_add(
- json_row, "Rp Address", rp_str);
- json_object_int_add(
- json_row, "Rp HoldTime",
- bsm_rp->rp_holdtime);
- json_object_int_add(json_row,
- "Rp Priority",
- bsm_rp->rp_prio);
- json_object_int_add(json_row,
- "Hash Val",
- bsm_rp->hash);
- json_object_object_add(
- json_group, rp_str, json_row);
- } else {
- vty_out(vty,
- "%-15s %-15u %-15u %-15u\n",
- rp_str, bsm_rp->rp_prio,
- bsm_rp->rp_holdtime,
- bsm_rp->hash);
- }
+ if (uj) {
+ json_row = json_object_new_object();
+ json_object_string_add(json_row, "Rp Address",
+ rp_str);
+ json_object_int_add(json_row, "Rp HoldTime",
+ bsm_rp->rp_holdtime);
+ json_object_int_add(json_row, "Rp Priority",
+ bsm_rp->rp_prio);
+ json_object_int_add(json_row, "Hash Val",
+ bsm_rp->hash);
+ json_object_object_add(json_group, rp_str,
+ json_row);
+ } else {
+ vty_out(vty, "%-15s %-15u %-15u %-15u\n",
+ rp_str, bsm_rp->rp_prio,
+ bsm_rp->rp_holdtime, bsm_rp->hash);
}
- if (!bsgrp->partial_bsrp_list->count && !uj)
- vty_out(vty, "Partial List is empty\n");
}
+ if (!bsm_rpinfos_count(bsgrp->partial_bsrp_list) && !uj)
+ vty_out(vty, "Partial List is empty\n");
if (!uj)
vty_out(vty, "\n");
return CMD_WARNING_CONFIG_FAILED; \
}
+/**
+ * Get current node VRF name.
+ *
+ * NOTE:
+ * In case of failure it will print error message to user.
+ *
+ * \returns name or NULL if failed to get VRF.
+ */
+static const char *pim_cli_get_vrf_name(struct vty *vty)
+{
+ const struct lyd_node *vrf_node;
+
+ /* Not inside any VRF context. */
+ if (vty->xpath_index == 0)
+ return VRF_DEFAULT_NAME;
+
+ vrf_node = yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
+ if (vrf_node == NULL) {
+ vty_out(vty, "%% Failed to get vrf dnode in configuration\n");
+ return NULL;
+ }
+
+ return yang_dnode_get_string(vrf_node, "./name");
+}
+
DEFUN (clear_ip_interfaces,
clear_ip_interfaces_cmd,
"clear ip interfaces [vrf NAME]",
pim->global_scope.current_bsr_first_ts = 0;
pim->global_scope.current_bsr_last_ts = 0;
pim->global_scope.bsm_frag_tag = 0;
- list_delete_all_node(pim->global_scope.bsm_list);
+ pim_bsm_frags_free(&pim->global_scope);
pim_bs_timer_stop(&pim->global_scope);
"SPT-Switchover\n"
"Never switch to SPT Tree\n")
{
- const struct lyd_node *vrf_dnode;
const char *vrfname;
char spt_plist_xpath[XPATH_MAXLEN];
char spt_action_xpath[XPATH_MAXLEN];
- if (vty->xpath_index) {
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode,
- VTY_CURR_XPATH);
-
- if (!vrf_dnode) {
- vty_out(vty,
- "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
- } else
- vrfname = VRF_DEFAULT_NAME;
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
snprintf(spt_plist_xpath, sizeof(spt_plist_xpath),
FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname,
"Prefix-List to control which groups to switch\n"
"Prefix-List name\n")
{
- const struct lyd_node *vrf_dnode;
const char *vrfname;
char spt_plist_xpath[XPATH_MAXLEN];
char spt_action_xpath[XPATH_MAXLEN];
- if (vty->xpath_index) {
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode,
- VTY_CURR_XPATH);
-
- if (!vrf_dnode) {
- vty_out(vty,
- "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
- } else
- vrfname = VRF_DEFAULT_NAME;
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
snprintf(spt_plist_xpath, sizeof(spt_plist_xpath),
FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname,
"SPT_Switchover\n"
"Never switch to SPT Tree\n")
{
- const struct lyd_node *vrf_dnode;
const char *vrfname;
char spt_plist_xpath[XPATH_MAXLEN];
char spt_action_xpath[XPATH_MAXLEN];
- if (vty->xpath_index) {
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode,
- VTY_CURR_XPATH);
-
- if (!vrf_dnode) {
- vty_out(vty,
- "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
- } else
- vrfname = VRF_DEFAULT_NAME;
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
snprintf(spt_plist_xpath, sizeof(spt_plist_xpath),
FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname,
"Prefix-List to control which groups to switch\n"
"Prefix-List name\n")
{
- const struct lyd_node *vrf_dnode;
const char *vrfname;
char spt_plist_xpath[XPATH_MAXLEN];
char spt_action_xpath[XPATH_MAXLEN];
- if (vty->xpath_index) {
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode,
- VTY_CURR_XPATH);
-
- if (!vrf_dnode) {
- vty_out(vty,
- "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
- } else
- vrfname = VRF_DEFAULT_NAME;
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
snprintf(spt_plist_xpath, sizeof(spt_plist_xpath),
FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname,
"Only accept registers from a specific source prefix list\n"
"Prefix-List name\n")
{
- const struct lyd_node *vrf_dnode;
const char *vrfname;
char reg_alist_xpath[XPATH_MAXLEN];
- if (vty->xpath_index) {
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode,
- VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty,
- "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
- } else
- vrfname = VRF_DEFAULT_NAME;
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
snprintf(reg_alist_xpath, sizeof(reg_alist_xpath),
FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname,
"Keep alive Timer\n"
"Seconds\n")
{
- const struct lyd_node *vrf_dnode;
const char *vrfname;
char rp_ka_timer_xpath[XPATH_MAXLEN];
- if (vty->xpath_index) {
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode,
- VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty,
- "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
- } else
- vrfname = VRF_DEFAULT_NAME;
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath),
FRR_PIM_XPATH, "frr-pim:pimd", "pim", vrfname);
"Keep alive Timer\n"
"Seconds\n")
{
- const struct lyd_node *vrf_dnode;
const char *vrfname;
char rp_ka_timer[5];
char rp_ka_timer_xpath[XPATH_MAXLEN];
- snprintf(rp_ka_timer, sizeof(rp_ka_timer), "%d", PIM_KEEPALIVE_PERIOD);
-
- if (vty->xpath_index) {
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode,
- VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty,
- "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
- } else
- vrfname = VRF_DEFAULT_NAME;
+ snprintf(rp_ka_timer, sizeof(rp_ka_timer), "%d",
+ PIM_RP_KEEPALIVE_PERIOD);
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath),
FRR_PIM_XPATH, "frr-pim:pimd", "pim", vrfname);
"Keep alive Timer\n"
"Seconds\n")
{
- const struct lyd_node *vrf_dnode;
const char *vrfname;
char ka_timer_xpath[XPATH_MAXLEN];
- if (vty->xpath_index) {
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode,
- VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty,
- "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
- } else
- vrfname = VRF_DEFAULT_NAME;
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_XPATH,
"frr-pim:pimd", "pim", vrfname);
"Keep alive Timer\n"
"Seconds\n")
{
- const struct lyd_node *vrf_dnode;
const char *vrfname;
char ka_timer[5];
char ka_timer_xpath[XPATH_MAXLEN];
snprintf(ka_timer, sizeof(ka_timer), "%d", PIM_KEEPALIVE_PERIOD);
- if (vty->xpath_index) {
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode,
- VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty,
- "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
- } else
- vrfname = VRF_DEFAULT_NAME;
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_XPATH,
"frr-pim:pimd", "pim", vrfname);
"pim multicast routing\n"
"Send v6 secondary addresses\n")
{
- const struct lyd_node *vrf_dnode;
const char *vrfname;
char send_v6_secondary_xpath[XPATH_MAXLEN];
- if (vty->xpath_index) {
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode,
- VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty,
- "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
- } else
- vrfname = VRF_DEFAULT_NAME;
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
snprintf(send_v6_secondary_xpath, sizeof(send_v6_secondary_xpath),
FRR_PIM_AF_XPATH,
"pim multicast routing\n"
"Send v6 secondary addresses\n")
{
- const struct lyd_node *vrf_dnode;
const char *vrfname;
char send_v6_secondary_xpath[XPATH_MAXLEN];
- if (vty->xpath_index) {
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode,
- VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty,
- "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
- } else
- vrfname = VRF_DEFAULT_NAME;
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
snprintf(send_v6_secondary_xpath, sizeof(send_v6_secondary_xpath),
FRR_PIM_AF_XPATH,
"ip address of RP\n"
"Group Address range to cover\n")
{
- const struct lyd_node *vrf_dnode;
const char *vrfname;
int idx_rp = 3, idx_group = 4;
char rp_group_xpath[XPATH_MAXLEN];
return CMD_WARNING_CONFIG_FAILED;
}
- if (vty->xpath_index) {
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode,
- VTY_CURR_XPATH);
-
- if (!vrf_dnode) {
- vty_out(vty,
- "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
- } else
- vrfname = VRF_DEFAULT_NAME;
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
snprintf(rp_group_xpath, sizeof(rp_group_xpath),
FRR_PIM_STATIC_RP_XPATH,
"Name of a prefix-list\n")
{
int idx_rp = 3, idx_plist = 5;
- const struct lyd_node *vrf_dnode;
const char *vrfname;
char rp_plist_xpath[XPATH_MAXLEN];
- if (vty->xpath_index) {
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode,
- VTY_CURR_XPATH);
-
- if (!vrf_dnode) {
- vty_out(vty,
- "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
- } else
- vrfname = VRF_DEFAULT_NAME;
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
snprintf(rp_plist_xpath, sizeof(rp_plist_xpath),
FRR_PIM_STATIC_RP_XPATH,
char group_list_xpath[XPATH_MAXLEN + 32];
char group_xpath[XPATH_MAXLEN + 64];
char rp_xpath[XPATH_MAXLEN];
- const struct lyd_node *vrf_dnode;
const char *vrfname;
const struct lyd_node *group_dnode;
- if (vty->xpath_index) {
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode,
- VTY_CURR_XPATH);
-
- if (!vrf_dnode) {
- vty_out(vty,
- "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
- } else
- vrfname = VRF_DEFAULT_NAME;
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH,
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4",
int idx_plist = 6;
char rp_xpath[XPATH_MAXLEN];
char plist_xpath[XPATH_MAXLEN];
- const struct lyd_node *vrf_dnode;
const char *vrfname;
const struct lyd_node *plist_dnode;
const char *plist;
- if (vty->xpath_index) {
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode,
- VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty,
- "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
- } else
- vrfname = VRF_DEFAULT_NAME;
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH,
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4",
"group range prefix-list filter\n"
"Name of a prefix-list\n")
{
- const struct lyd_node *vrf_dnode;
const char *vrfname;
char ssm_plist_xpath[XPATH_MAXLEN];
- if (vty->xpath_index) {
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode,
- VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty,
- "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
- } else
- vrfname = VRF_DEFAULT_NAME;
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), FRR_PIM_AF_XPATH,
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
"Source Specific Multicast\n"
"group range prefix-list filter\n")
{
- const struct lyd_node *vrf_dnode;
const char *vrfname;
char ssm_plist_xpath[XPATH_MAXLEN];
- if (vty->xpath_index) {
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode,
- VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty,
- "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
- } else
- vrfname = VRF_DEFAULT_NAME;
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath),
FRR_PIM_AF_XPATH,
"group range prefix-list filter\n"
"Name of a prefix-list\n")
{
- const struct lyd_node *vrf_dnode;
const char *vrfname;
const struct lyd_node *ssm_plist_dnode;
char ssm_plist_xpath[XPATH_MAXLEN];
const char *ssm_plist_name;
- if (vty->xpath_index) {
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode,
- VTY_CURR_XPATH);
-
- if (!vrf_dnode) {
- vty_out(vty,
- "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
- } else
- vrfname = VRF_DEFAULT_NAME;
-
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath),
FRR_PIM_AF_XPATH,
{
int idx_ipv4 = 2;
const char *source_str = (argc == 3) ? argv[idx_ipv4]->arg : "0.0.0.0";
- const struct lyd_node *vrf_dnode;
const char *vrfname;
char ssmpingd_ip_xpath[XPATH_MAXLEN];
- if (vty->xpath_index) {
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode,
- VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty,
- "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
- } else
- vrfname = VRF_DEFAULT_NAME;
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
snprintf(ssmpingd_ip_xpath, sizeof(ssmpingd_ip_xpath),
FRR_PIM_AF_XPATH,
CONF_SSMPINGD_STR
"Source address\n")
{
- const struct lyd_node *vrf_dnode;
const char *vrfname;
int idx_ipv4 = 3;
const char *source_str = (argc == 4) ? argv[idx_ipv4]->arg : "0.0.0.0";
char ssmpingd_ip_xpath[XPATH_MAXLEN];
- if (vty->xpath_index) {
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode,
- VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty,
- "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
- } else
- vrfname = VRF_DEFAULT_NAME;
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
snprintf(ssmpingd_ip_xpath, sizeof(ssmpingd_ip_xpath),
FRR_PIM_AF_XPATH,
"pim multicast routing\n"
"Enable PIM ECMP \n")
{
- const struct lyd_node *vrf_dnode;
const char *vrfname;
char ecmp_xpath[XPATH_MAXLEN];
- if (vty->xpath_index) {
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode,
- VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty,
- "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
- } else
- vrfname = VRF_DEFAULT_NAME;
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_XPATH,
"frr-pim:pimd", "pim", vrfname);
"pim multicast routing\n"
"Disable PIM ECMP \n")
{
- const struct lyd_node *vrf_dnode;
const char *vrfname;
char ecmp_xpath[XPATH_MAXLEN];
- if (vty->xpath_index) {
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode,
- VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty,
- "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
- } else
- vrfname = VRF_DEFAULT_NAME;
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_XPATH,
"frr-pim:pimd", "pim", vrfname);
"Enable PIM ECMP \n"
"Enable PIM ECMP Rebalance\n")
{
- const struct lyd_node *vrf_dnode;
const char *vrfname;
char ecmp_xpath[XPATH_MAXLEN];
char ecmp_rebalance_xpath[XPATH_MAXLEN];
- if (vty->xpath_index) {
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode,
- VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty,
- "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
- } else
- vrfname = VRF_DEFAULT_NAME;
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_XPATH,
"frr-pim:pimd", "pim", vrfname);
"Disable PIM ECMP \n"
"Disable PIM ECMP Rebalance\n")
{
- const struct lyd_node *vrf_dnode;
const char *vrfname;
char ecmp_rebalance_xpath[XPATH_MAXLEN];
- if (vty->xpath_index) {
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode,
- VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty,
- "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
- } else
- vrfname = VRF_DEFAULT_NAME;
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
snprintf(ecmp_rebalance_xpath, sizeof(ecmp_rebalance_xpath),
FRR_PIM_XPATH,
"frr-routing:ipv4");
}
-DEFUN (ip_pim_bfd,
+DEFPY (ip_pim_bfd,
ip_pim_bfd_cmd,
- "ip pim bfd",
+ "ip pim bfd [profile BFDPROF$prof]",
IP_STR
PIM_STR
- "Enables BFD support\n")
+ "Enables BFD support\n"
+ "Use BFD profile\n"
+ "Use BFD profile name\n")
{
- struct bfd_info *bfd_info = NULL;
- char default_rx_interval[5];
- char default_tx_interval[5];
- char default_detect_mult[3];
const struct lyd_node *igmp_enable_dnode;
- char bfd_xpath[XPATH_MAXLEN + 20];
igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
"%s/frr-igmp:igmp/igmp-enable",
"true");
}
- snprintf(default_rx_interval, sizeof(default_rx_interval), "%d",
- BFD_DEF_MIN_RX);
- snprintf(default_tx_interval, sizeof(default_tx_interval), "%d",
- BFD_DEF_MIN_TX);
- snprintf(default_detect_mult, sizeof(default_detect_mult), "%d",
- BFD_DEF_DETECT_MULT);
-
- snprintf(bfd_xpath, sizeof(bfd_xpath), "%s/frr-pim:pim/bfd",
- VTY_CURR_XPATH);
- bfd_info = nb_running_get_entry(NULL, bfd_xpath, false);
+ nb_cli_enqueue_change(vty, "./bfd", NB_OP_CREATE, NULL);
+ if (prof)
+ nb_cli_enqueue_change(vty, "./bfd/profile", NB_OP_MODIFY, prof);
- if (!bfd_info ||
- !CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG)) {
- nb_cli_enqueue_change(vty, "./bfd/min-rx-interval",
- NB_OP_MODIFY, default_rx_interval);
- nb_cli_enqueue_change(vty, "./bfd/min-tx-interval",
- NB_OP_MODIFY, default_tx_interval);
- nb_cli_enqueue_change(vty, "./bfd/detect_mult",
- NB_OP_MODIFY,
- default_detect_mult);
+ return nb_cli_apply_changes(vty, "./frr-pim:pim");
+}
- return nb_cli_apply_changes(vty, "./frr-pim:pim");
- }
+DEFPY(no_ip_pim_bfd_profile, no_ip_pim_bfd_profile_cmd,
+ "no ip pim bfd profile [BFDPROF]",
+ NO_STR
+ IP_STR
+ PIM_STR
+ "Enables BFD support\n"
+ "Disable BFD profile\n"
+ "BFD Profile name\n")
+{
+ nb_cli_enqueue_change(vty, "./bfd/profile", NB_OP_DESTROY, NULL);
- return NB_OK;
+ return nb_cli_apply_changes(vty, "./frr-pim:pim");
}
DEFUN (no_ip_pim_bfd,
int idx_number = 3;
int idx_number_2 = 4;
int idx_number_3 = 5;
- uint32_t rx_val;
- uint32_t tx_val;
- uint8_t dm_val;
- int ret;
const struct lyd_node *igmp_enable_dnode;
- if ((ret = bfd_validate_param(vty, argv[idx_number]->arg,
- argv[idx_number_2]->arg,
- argv[idx_number_3]->arg, &dm_val, &rx_val,
- &tx_val))
- != CMD_SUCCESS)
- return ret;
-
igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
"%s/frr-igmp:igmp/igmp-enable",
VTY_CURR_XPATH);
"true");
}
+ nb_cli_enqueue_change(vty, "./bfd", NB_OP_CREATE, NULL);
nb_cli_enqueue_change(vty, "./bfd/min-rx-interval", NB_OP_MODIFY,
argv[idx_number_2]->arg);
nb_cli_enqueue_change(vty, "./bfd/min-tx-interval", NB_OP_MODIFY,
"Source address for TCP connection\n"
"local ip address\n")
{
- const struct lyd_node *vrf_dnode;
const char *vrfname;
char temp_xpath[XPATH_MAXLEN];
char msdp_peer_source_xpath[XPATH_MAXLEN];
- if (vty->xpath_index) {
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode,
- VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty,
- "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
- } else
- vrfname = VRF_DEFAULT_NAME;
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
snprintf(msdp_peer_source_xpath, sizeof(msdp_peer_source_xpath),
FRR_PIM_AF_XPATH,
"Delete MSDP peer\n"
"peer ip address\n")
{
- const struct lyd_node *vrf_dnode;
const char *vrfname;
char msdp_peer_xpath[XPATH_MAXLEN];
char temp_xpath[XPATH_MAXLEN];
- if (vty->xpath_index) {
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode,
- VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty,
- "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
- } else
- vrfname = VRF_DEFAULT_NAME;
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
snprintf(msdp_peer_xpath, sizeof(msdp_peer_xpath),
FRR_PIM_AF_XPATH,
"mesh group member\n"
"peer ip address\n")
{
- const struct lyd_node *vrf_dnode;
const char *vrfname;
char msdp_mesh_group_name_xpath[XPATH_MAXLEN];
char msdp_mesh_group_member_xpath[XPATH_MAXLEN];
- if (vty->xpath_index) {
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode,
- VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty,
- "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
- } else
- vrfname = VRF_DEFAULT_NAME;
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
snprintf(msdp_mesh_group_name_xpath, sizeof(msdp_mesh_group_name_xpath),
FRR_PIM_AF_XPATH,
"mesh group member\n"
"peer ip address\n")
{
- const struct lyd_node *vrf_dnode;
const char *vrfname;
char pim_af_xpath[XPATH_MAXLEN];
char mesh_group_xpath[XPATH_MAXLEN + 32];
const char *mesh_group_name;
const struct lyd_node *member_dnode;
- if (vty->xpath_index) {
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode,
- VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty,
- "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
- } else
- vrfname = VRF_DEFAULT_NAME;
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
snprintf(pim_af_xpath, sizeof(pim_af_xpath), FRR_PIM_AF_XPATH,
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
"mesh group local address\n"
"source ip address for the TCP connection\n")
{
- const struct lyd_node *vrf_dnode;
const char *vrfname;
char msdp_mesh_source_ip_xpath[XPATH_MAXLEN];
char msdp_mesh_group_name_xpath[XPATH_MAXLEN];
- if (vty->xpath_index) {
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode,
- VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty,
- "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
- } else
- vrfname = VRF_DEFAULT_NAME;
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
snprintf(msdp_mesh_group_name_xpath, sizeof(msdp_mesh_group_name_xpath),
FRR_PIM_AF_XPATH,
"mesh group source\n"
"mesh group local address\n")
{
- const struct lyd_node *vrf_dnode;
const char *vrfname;
char msdp_mesh_xpath[XPATH_MAXLEN];
char source_xpath[XPATH_MAXLEN];
char mesh_group_name_xpath[XPATH_MAXLEN];
const char *mesh_group_name;
- if (vty->xpath_index) {
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode,
- VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty,
- "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
- } else
- vrfname = VRF_DEFAULT_NAME;
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
snprintf(msdp_mesh_xpath, sizeof(msdp_mesh_xpath),
FRR_PIM_AF_XPATH,
"Delete MSDP mesh-group\n"
"mesh group name")
{
- const struct lyd_node *vrf_dnode;
const char *vrfname;
const char *mesh_group_name;
char xpath[XPATH_MAXLEN];
char msdp_mesh_xpath[XPATH_MAXLEN];
- if (vty->xpath_index) {
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode,
- VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty,
- "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
- } else
- vrfname = VRF_DEFAULT_NAME;
+ vrfname = pim_cli_get_vrf_name(vty);
+ if (vrfname == NULL)
+ return CMD_WARNING_CONFIG_FAILED;
if (argc == 5) {
snprintf(xpath, sizeof(xpath), FRR_PIM_AF_XPATH, "frr-pim:pimd",
install_element(CONFIG_NODE, &ip_pim_ssm_prefix_list_cmd);
install_element(VRF_NODE, &ip_pim_ssm_prefix_list_cmd);
install_element(CONFIG_NODE, &ip_pim_register_suppress_cmd);
- install_element(VRF_NODE, &ip_pim_register_suppress_cmd);
install_element(CONFIG_NODE, &no_ip_pim_register_suppress_cmd);
- install_element(VRF_NODE, &no_ip_pim_register_suppress_cmd);
install_element(CONFIG_NODE, &ip_pim_spt_switchover_infinity_cmd);
install_element(VRF_NODE, &ip_pim_spt_switchover_infinity_cmd);
install_element(CONFIG_NODE, &ip_pim_spt_switchover_infinity_plist_cmd);
install_element(CONFIG_NODE, &pim_register_accept_list_cmd);
install_element(VRF_NODE, &pim_register_accept_list_cmd);
install_element(CONFIG_NODE, &ip_pim_joinprune_time_cmd);
- install_element(VRF_NODE, &ip_pim_joinprune_time_cmd);
install_element(CONFIG_NODE, &no_ip_pim_joinprune_time_cmd);
- install_element(VRF_NODE, &no_ip_pim_joinprune_time_cmd);
install_element(CONFIG_NODE, &ip_pim_keep_alive_cmd);
install_element(VRF_NODE, &ip_pim_keep_alive_cmd);
install_element(CONFIG_NODE, &ip_pim_rp_keep_alive_cmd);
install_element(CONFIG_NODE, &no_ip_pim_rp_keep_alive_cmd);
install_element(VRF_NODE, &no_ip_pim_rp_keep_alive_cmd);
install_element(CONFIG_NODE, &ip_pim_packets_cmd);
- install_element(VRF_NODE, &ip_pim_packets_cmd);
install_element(CONFIG_NODE, &no_ip_pim_packets_cmd);
- install_element(VRF_NODE, &no_ip_pim_packets_cmd);
install_element(CONFIG_NODE, &ip_pim_v6_secondary_cmd);
install_element(VRF_NODE, &ip_pim_v6_secondary_cmd);
install_element(CONFIG_NODE, &no_ip_pim_v6_secondary_cmd);
/* Install BFD command */
install_element(INTERFACE_NODE, &ip_pim_bfd_cmd);
install_element(INTERFACE_NODE, &ip_pim_bfd_param_cmd);
+ install_element(INTERFACE_NODE, &no_ip_pim_bfd_profile_cmd);
install_element(INTERFACE_NODE, &no_ip_pim_bfd_cmd);
#if HAVE_BFDD == 0
install_element(INTERFACE_NODE, &no_ip_pim_bfd_param_cmd);
on_trace(__func__, ifp, src_addr);
pim_ifp = ifp->info;
- zassert(pim_ifp);
+ assert(pim_ifp);
++pim_ifp->pim_ifstat_hello_recv;
/*
Parse PIM hello TLVs
*/
- zassert(tlv_buf_size >= 0);
+ assert(tlv_buf_size >= 0);
tlv_curr = tlv_buf;
tlv_pastend = tlv_buf + tlv_buf_size;
{
struct pim_interface *pim_ifp;
- zassert(ifp);
+ assert(ifp);
pim_ifp = ifp->info;
- zassert(pim_ifp);
+ assert(pim_ifp);
if (pim_ifp->pim_ifstat_hello_sent)
return;
{
struct pim_interface *pim_ifp;
- zassert(ifp);
- zassert(!ifp->info);
+ assert(ifp);
+ assert(!ifp->info);
pim_ifp = XCALLOC(MTYPE_PIM_INTERFACE, sizeof(*pim_ifp));
The number of seconds represented by the [Query Response Interval]
must be less than the [Query Interval].
*/
- zassert(pim_ifp->igmp_query_max_response_time_dsec
- < pim_ifp->igmp_default_query_interval);
+ assert(pim_ifp->igmp_query_max_response_time_dsec
+ < pim_ifp->igmp_default_query_interval);
if (pim)
PIM_IF_DO_PIM(pim_ifp->options);
struct pim_interface *pim_ifp;
struct pim_ifchannel *ch;
- zassert(ifp);
+ assert(ifp);
pim_ifp = ifp->info;
- zassert(pim_ifp);
+ assert(pim_ifp);
if (pim_ifp->igmp_join_list) {
pim_if_igmp_join_del_all(ifp);
struct pim_ifchannel *ch;
pim_ifp = ifp->info;
- zassert(pim_ifp);
+ assert(pim_ifp);
RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
pim_ifchannel_update_could_assert(ch);
struct pim_ifchannel *ch;
pim_ifp = ifp->info;
- zassert(pim_ifp);
+ assert(pim_ifp);
RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
pim_ifchannel_update_my_assert_metric(ch);
struct pim_interface *pim_ifp;
pim_ifp = ifp->info;
- zassert(pim_ifp);
+ assert(pim_ifp);
pim_if_dr_election(ifp); /* router's own DR Priority (addr) changes --
Done TODO T30 */
struct in_addr ifaddr;
bool vxlan_term;
- zassert(ifc);
+ assert(ifc);
ifp = ifc->ifp;
- zassert(ifp);
+ assert(ifp);
pim_ifp = ifp->info;
if (!pim_ifp)
return;
{
struct interface *ifp;
- zassert(ifc);
+ assert(ifc);
ifp = ifc->ifp;
- zassert(ifp);
+ assert(ifp);
if (PIM_DEBUG_ZEBRA)
zlog_debug("%s: %s ifindex=%d disconnected IP address %pFX %s",
struct in_addr ifaddr;
unsigned char flags = 0;
- zassert(pim_ifp);
+ assert(pim_ifp);
if (pim_ifp->mroute_vif_index > 0) {
zlog_warn("%s: vif_index=%d > 0 on interface %s ifindex=%d",
struct pim_interface *pim_ifp;
pim_ifp = ifp->info;
- zassert(pim_ifp);
- zassert(pim_ifp->pim_number_of_nonlandelay_neighbors >= 0);
+ assert(pim_ifp);
+ assert(pim_ifp->pim_number_of_nonlandelay_neighbors >= 0);
return pim_ifp->pim_number_of_nonlandelay_neighbors == 0;
}
struct pim_interface *pim_ifp;
struct prefix p;
- zassert(ifp);
+ assert(ifp);
pim_ifp = ifp->info;
if (!pim_ifp) {
uint32_t ramount = 0;
pim_ifp = ifp->info;
- zassert(pim_ifp);
+ assert(pim_ifp);
/* join suppression disabled ? */
if (PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPPRESSION(pim_ifp->options))
struct listnode *node;
struct igmp_join *ij;
- zassert(join_list);
+ assert(join_list);
for (ALL_LIST_ELEMENTS_RO(join_list, node, ij)) {
if ((group_addr.s_addr == ij->group_addr.s_addr)
int join_fd;
pim_ifp = ifp->info;
- zassert(pim_ifp);
+ assert(pim_ifp);
join_fd = igmp_join_sock(ifp->name, ifp->ifindex, group_addr,
source_addr);
struct pim_ifchannel *ch;
pim_ifp = ifp->info;
- zassert(pim_ifp);
+ assert(pim_ifp);
RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
/* Is (S,G,I) assert loser ? */
uint32_t pim_ifstat_bsm_cfg_miss;
uint32_t pim_ifstat_ucast_bsm_cfg_miss;
uint32_t pim_ifstat_bsm_invalid_sz;
- struct bfd_info *bfd_info;
bool bsm_enable; /* bsm processing enable */
bool ucast_bsm_accept; /* ucast bsm processing */
+
+ struct {
+ bool enabled;
+ uint32_t min_rx;
+ uint32_t min_tx;
+ uint8_t detection_multiplier;
+ char *profile;
+ } bfd_config;
};
/*
struct pim_ifchannel *ch;
pim_ifp = ifp->info;
- zassert(pim_ifp);
+ assert(pim_ifp);
RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb)
ifmembership_set(ch, PIM_IFMEMBERSHIP_NOINFO);
struct pim_ifchannel *ch, *ch_tmp;
pim_ifp = ifp->info;
- zassert(pim_ifp);
+ assert(pim_ifp);
RB_FOREACH_SAFE (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb, ch_tmp)
delete_on_noinfo(ch);
int is_local; /* boolean */
recv_pim_ifp = recv_ifp->info;
- zassert(recv_pim_ifp);
+ assert(recv_pim_ifp);
is_local = (upstream.s_addr == recv_pim_ifp->primary_address.s_addr);
}
pim_ifp = ifp->info;
- zassert(pim_ifp);
+ assert(pim_ifp);
switch (ch->ifjoin_state) {
case PIM_IFJOIN_NOINFO:
}
break;
case PIM_IFJOIN_JOIN:
- zassert(!ch->t_ifjoin_prune_pending_timer);
+ assert(!ch->t_ifjoin_prune_pending_timer);
/*
In the JOIN state ch->t_ifjoin_expiry_timer may be NULL due to
igmp = THREAD_ARG(t);
- zassert(!igmp->t_igmp_query_timer);
+ assert(!igmp->t_igmp_query_timer);
if (PIM_DEBUG_IGMP_TRACE) {
char ifaddr_str[INET_ADDRSTRLEN];
long other_querier_present_interval_msec;
struct pim_interface *pim_ifp;
- zassert(igmp);
- zassert(igmp->interface);
- zassert(igmp->interface->info);
+ assert(igmp);
+ assert(igmp->interface);
+ assert(igmp->interface->info);
pim_ifp = igmp->interface->info;
Since this socket is starting the other-querier-present timer,
there should not be periodic query timer for this socket.
*/
- zassert(!igmp->t_igmp_query_timer);
+ assert(!igmp->t_igmp_query_timer);
/*
RFC 3376: 8.5. Other Querier Present Interval
void pim_igmp_other_querier_timer_off(struct igmp_sock *igmp)
{
- zassert(igmp);
+ assert(igmp);
if (PIM_DEBUG_IGMP_TRACE) {
if (igmp->t_other_querier_timer) {
Since this socket is starting as querier,
there should not exist a timer for other-querier-present.
*/
- zassert(!igmp->t_other_querier_timer);
+ assert(!igmp->t_other_querier_timer);
pim_ifp = igmp->interface->info;
- zassert(pim_ifp);
+ assert(pim_ifp);
/*
RFC 3376: 8.6. Startup Query Interval
void pim_igmp_general_query_off(struct igmp_sock *igmp)
{
- zassert(igmp);
+ assert(igmp);
if (PIM_DEBUG_IGMP_TRACE) {
if (igmp->t_igmp_query_timer) {
igmp = THREAD_ARG(t);
- zassert(igmp->interface);
- zassert(igmp->interface->info);
+ assert(igmp->interface);
+ assert(igmp->interface->info);
pim_ifp = igmp->interface->info;
void igmp_group_delete_empty_include(struct igmp_group *group)
{
- zassert(!group->group_filtermode_isexcl);
- zassert(!listcount(group->group_source_list));
+ assert(!group->group_filtermode_isexcl);
+ assert(!listcount(group->group_source_list));
igmp_group_delete(group);
}
void igmp_sock_free(struct igmp_sock *igmp)
{
- zassert(!igmp->t_igmp_read);
- zassert(!igmp->t_igmp_query_timer);
- zassert(!igmp->t_other_querier_timer);
- zassert(igmp->igmp_group_list);
- zassert(!listcount(igmp->igmp_group_list));
+ assert(!igmp->t_igmp_read);
+ assert(!igmp->t_igmp_query_timer);
+ assert(!igmp->t_other_querier_timer);
+ assert(igmp->igmp_group_list);
+ assert(!listcount(igmp->igmp_group_list));
list_delete(&igmp->igmp_group_list);
hash_free(igmp->igmp_group_hash);
group_str, group->group_igmp_sock->interface->name);
}
- zassert(group->group_filtermode_isexcl);
+ assert(group->group_filtermode_isexcl);
group->group_filtermode_isexcl = 0;
igmp_source_delete_expired(group->group_source_list);
- zassert(!group->group_filtermode_isexcl);
+ assert(!group->group_filtermode_isexcl);
/*
RFC 3376: 6.2.2. Definition of Group Timers
it represents the time for the *filter-mode* of the group to
expire and switch to INCLUDE mode.
*/
- zassert(group->group_filtermode_isexcl);
+ assert(group->group_filtermode_isexcl);
thread_add_timer_msec(router->master, igmp_group_timer, group,
interval_msec, &group->t_group_timer);
it represents the time for the *filter-mode* of the group to
expire and switch to INCLUDE mode.
*/
- zassert(!group->group_filtermode_isexcl); /* INCLUDE mode */
- zassert(!group->t_group_timer); /* group timer == 0 */
+ assert(!group->group_filtermode_isexcl); /* INCLUDE mode */
+ assert(!group->t_group_timer); /* group timer == 0 */
/* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
igmp_anysource_forward_stop(group);
/* max_resp_code must be non-zero else this will look like an IGMP v1
* query */
max_resp_code = igmp_msg_encode16to8(query_max_response_time_dsec);
- zassert(max_resp_code > 0);
+ assert(max_resp_code > 0);
query_buf[0] = PIM_IGMP_MEMBERSHIP_QUERY;
query_buf[1] = max_resp_code;
it represents the time for the *filter-mode* of the group to
expire and switch to INCLUDE mode.
*/
- zassert(group->group_filtermode_isexcl);
+ assert(group->group_filtermode_isexcl);
igmp_group_timer_on(group, group_membership_interval_msec, ifp->name);
}
{
struct pim_interface *pim_ifp = group->group_igmp_sock->interface->info;
- zassert(group->group_filtermode_isexcl);
+ assert(group->group_filtermode_isexcl);
if (listcount(group->group_source_list) < 1) {
igmp_anysource_forward_start(pim_ifp->pim, group);
void igmp_source_free(struct igmp_source *source)
{
/* make sure there is no source timer running */
- zassert(!source->t_source_timer);
+ assert(!source->t_source_timer);
XFREE(MTYPE_PIM_IGMP_GROUP_SOURCE, source);
}
int i;
/* EXCLUDE mode */
- zassert(group->group_filtermode_isexcl);
+ assert(group->group_filtermode_isexcl);
/* E.1: set deletion flag for known sources (X,Y) */
source_mark_delete_flag(group);
/* E.4: if not found, create source with timer=GMI:
* (A-X-Y) */
source = source_new(group, *src_addr);
- zassert(!source->t_source_timer); /* timer == 0 */
+ assert(!source->t_source_timer); /* timer == 0 */
igmp_source_reset_gmi(group->group_igmp_sock, group,
source);
- zassert(source->t_source_timer); /* (A-X-Y) timer > 0 */
+ assert(source->t_source_timer); /* (A-X-Y) timer > 0 */
}
} /* scan received sources */
int i;
/* INCLUDE mode */
- zassert(!group->group_filtermode_isexcl);
+ assert(!group->group_filtermode_isexcl);
/* I.1: set deletion flag for known sources (A) */
source_mark_delete_flag(group);
/* I.4: if not found, create source with timer=0 (B-A)
*/
source = source_new(group, *src_addr);
- zassert(!source->t_source_timer); /* (B-A) timer=0 */
+ assert(!source->t_source_timer); /* (B-A) timer=0 */
}
} /* scan received sources */
group->group_filtermode_isexcl = 1; /* boolean=true */
- zassert(group->group_filtermode_isexcl);
+ assert(group->group_filtermode_isexcl);
group_exclude_fwd_anysrc_ifempty(group);
}
} else {
/* INCLUDE mode */
isex_incl(group, num_sources, sources);
- zassert(group->group_filtermode_isexcl);
+ assert(group->group_filtermode_isexcl);
}
- zassert(group->group_filtermode_isexcl);
+ assert(group->group_filtermode_isexcl);
igmp_group_reset_gmi(group);
}
int num_sources_tosend = 0;
int i;
- zassert(!group->group_filtermode_isexcl);
+ assert(!group->group_filtermode_isexcl);
/* Set DELETE flag for all known sources (A) */
source_mark_delete_flag(group);
/* If source not found, create source with timer=0:
* (B-A)=0 */
source = source_new(group, *src_addr);
- zassert(!source->t_source_timer); /* (B-A) timer=0 */
+ assert(!source->t_source_timer); /* (B-A) timer=0 */
}
} /* Scan received sources (B) */
source_query_send_by_flag(group, num_sources_tosend);
}
- zassert(group->group_filtermode_isexcl);
+ assert(group->group_filtermode_isexcl);
group_exclude_fwd_anysrc_ifempty(group);
}
long group_timer_msec;
source = source_new(group, *src_addr);
- zassert(!source->t_source_timer); /* timer == 0 */
+ assert(!source->t_source_timer); /* timer == 0 */
group_timer_msec = igmp_group_timer_remain_msec(group);
igmp_source_timer_on(group, source, group_timer_msec);
- zassert(source->t_source_timer); /* (A-X-Y) timer > 0 */
+ assert(source->t_source_timer); /* (A-X-Y) timer > 0 */
/* make sure source is created with DELETE flag unset */
- zassert(!IGMP_SOURCE_TEST_DELETE(source->source_flags));
+ assert(!IGMP_SOURCE_TEST_DELETE(source->source_flags));
}
/* make sure reported source has DELETE flag unset */
- zassert(!IGMP_SOURCE_TEST_DELETE(source->source_flags));
+ assert(!IGMP_SOURCE_TEST_DELETE(source->source_flags));
if (source->t_source_timer) {
/* if source timer>0 mark SEND flag: Q(G,A-Y) */
} else {
/* INCLUDE mode */
toex_incl(group, num_sources, sources);
- zassert(group->group_filtermode_isexcl);
+ assert(group->group_filtermode_isexcl);
}
- zassert(group->group_filtermode_isexcl);
+ assert(group->group_filtermode_isexcl);
/* Group Timer=GMI */
igmp_group_reset_gmi(group);
long lmqi_msec; /* Last Member Query Interval */
long lmqt_msec; /* Last Member Query Time */
- zassert(num_sources_tosend > 0);
+ assert(num_sources_tosend > 0);
igmp = group->group_igmp_sock;
pim_ifp = igmp->interface->info;
long group_timer_msec;
source = source_new(group, *src_addr);
- zassert(!source->t_source_timer); /* timer == 0 */
+ assert(!source->t_source_timer); /* timer == 0 */
group_timer_msec = igmp_group_timer_remain_msec(group);
igmp_source_timer_on(group, source, group_timer_msec);
- zassert(source->t_source_timer); /* (A-X-Y) timer > 0 */
+ assert(source->t_source_timer); /* (A-X-Y) timer > 0 */
}
if (source->t_source_timer) {
lmqt_msec);
}
- zassert(group->group_filtermode_isexcl);
+ assert(group->group_filtermode_isexcl);
igmp_group_timer_on(group, lmqt_msec, ifname);
}
socklen_t tolen;
uint16_t checksum;
- zassert(num_sources >= 0);
+ assert(num_sources >= 0);
msg_size = IGMP_V3_SOURCES_OFFSET + (num_sources << 2);
if (msg_size > query_buf_size) {
}
s_flag = PIM_FORCE_BOOLEAN(s_flag);
- zassert((s_flag == 0) || (s_flag == 1));
+ assert((s_flag == 0) || (s_flag == 1));
max_resp_code = igmp_msg_encode16to8(query_max_response_time_dsec);
qqic = igmp_msg_encode16to8(querier_query_interval);
}
pim_ifp = ifp->info;
- zassert(pim_ifp);
+ assert(pim_ifp);
++pim_ifp->pim_ifstat_join_recv;
}
pim_ifp = ifp->info;
- zassert(pim_ifp);
+ assert(pim_ifp);
++pim_ifp->pim_ifstat_prune_recv;
#include "log.h"
#include "privs.h"
-#include "version.h"
+#include "lib/version.h"
#include <getopt.h>
#include "command.h"
#include "thread.h"
#include "filter.h"
#include "vty.h"
#include "sigevent.h"
-#include "version.h"
+#include "lib/version.h"
#include "prefix.h"
#include "plist.h"
#include "vrf.h"
return count;
}
+bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim,
+ const char *spaces)
+{
+ struct pim_msdp_peer *mp;
+ struct listnode *node;
+ bool written = false;
+
+ for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, node, mp)) {
+ /* Non meshed peers have the group name set to 'default'. */
+ if (strcmp(mp->mesh_group_name, "default"))
+ continue;
+
+ vty_out(vty, "%sip msdp peer %pI4 source %pI4\n", spaces,
+ &mp->peer, &mp->local);
+ written = true;
+ }
+
+ return written;
+}
+
/* Enable feature including active/periodic timers etc. on the first peer
* config. Till then MSDP should just stay quiet. */
static void pim_msdp_enable(struct pim_instance *pim)
bool long_format);
int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty,
const char *spaces);
+bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim,
+ const char *spaces);
void pim_msdp_peer_pkt_txed(struct pim_msdp_peer *mp);
void pim_msdp_sa_ref(struct pim_instance *pim, struct pim_msdp_peer *mp,
struct prefix_sg *sg, struct in_addr rp);
.modify = lib_interface_pim_bfd_detect_mult_modify,
}
},
+ {
+ .xpath = "/frr-interface:lib/interface/frr-pim:pim/bfd/profile",
+ .cbs = {
+ .modify = lib_interface_pim_bfd_profile_modify,
+ .destroy = lib_interface_pim_bfd_profile_destroy,
+ }
+ },
{
.xpath = "/frr-interface:lib/interface/frr-pim:pim/bsm",
.cbs = {
int lib_interface_pim_bfd_min_tx_interval_modify(
struct nb_cb_modify_args *args);
int lib_interface_pim_bfd_detect_mult_modify(struct nb_cb_modify_args *args);
+int lib_interface_pim_bfd_profile_modify(struct nb_cb_modify_args *args);
+int lib_interface_pim_bfd_profile_destroy(struct nb_cb_destroy_args *args);
int lib_interface_pim_bsm_modify(struct nb_cb_modify_args *args);
int lib_interface_pim_unicast_bsm_modify(struct nb_cb_modify_args *args);
int lib_interface_pim_active_active_modify(struct nb_cb_modify_args *args);
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <zebra.h>
+
#include "pimd.h"
#include "pim_nb.h"
#include "lib/northbound_cli.h"
struct pim_interface *pim_ifp;
pim_ifp = ifp->info;
- zassert(pim_ifp);
+ assert(pim_ifp);
if (PIM_IF_TEST_PIM(pim_ifp->options)
&& PIM_IF_TEST_IGMP(pim_ifp->options)) {
struct igmp_sock *igmp;
pim_ifp = ifp->info;
- zassert(pim_ifp);
+ assert(pim_ifp);
if (!PIM_IF_TEST_PIM(pim_ifp->options))
return;
struct interface *ifp;
struct pim_interface *pim_ifp;
- zassert(igmp);
+ assert(igmp);
/* other querier present? */
/* this is the querier */
- zassert(igmp->interface);
- zassert(igmp->interface->info);
+ assert(igmp->interface);
+ assert(igmp->interface->info);
ifp = igmp->interface;
pim_ifp = ifp->info;
if (igmp->t_igmp_query_timer) {
/* other querier present */
- zassert(igmp->t_igmp_query_timer);
- zassert(!igmp->t_other_querier_timer);
+ assert(igmp->t_igmp_query_timer);
+ assert(!igmp->t_other_querier_timer);
pim_igmp_general_query_off(igmp);
pim_igmp_general_query_on(igmp);
- zassert(igmp->t_igmp_query_timer);
- zassert(!igmp->t_other_querier_timer);
+ assert(igmp->t_igmp_query_timer);
+ assert(!igmp->t_other_querier_timer);
} else {
/* this is the querier */
- zassert(!igmp->t_igmp_query_timer);
- zassert(igmp->t_other_querier_timer);
+ assert(!igmp->t_igmp_query_timer);
+ assert(igmp->t_other_querier_timer);
pim_igmp_other_querier_timer_off(igmp);
pim_igmp_other_querier_timer_on(igmp);
- zassert(!igmp->t_igmp_query_timer);
- zassert(igmp->t_other_querier_timer);
+ assert(!igmp->t_igmp_query_timer);
+ assert(igmp->t_other_querier_timer);
}
}
*/
int pim_register_suppress_time_modify(struct nb_cb_modify_args *args)
{
- struct vrf *vrf;
- struct pim_instance *pim;
-
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
- vrf = nb_running_get_entry(args->dnode, NULL, true);
- pim = vrf->info;
- pim->keep_alive_time = yang_dnode_get_uint16(args->dnode, NULL);
+ pim_update_suppress_timers(
+ yang_dnode_get_uint16(args->dnode, NULL));
break;
}
*/
int lib_interface_pim_bfd_create(struct nb_cb_create_args *args)
{
+ struct interface *ifp;
+ struct pim_interface *pim_ifp;
+
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
+ /* NOTHING */
+ break;
case NB_EV_APPLY:
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
+ pim_ifp = ifp->info;
+ pim_ifp->bfd_config.enabled = true;
break;
}
case NB_EV_PREPARE:
break;
case NB_EV_APPLY:
- ifp = nb_running_get_entry(args->dnode->parent, NULL, true);
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
pim_ifp = ifp->info;
- if (pim_ifp->bfd_info) {
- pim_bfd_reg_dereg_all_nbr(ifp,
- ZEBRA_BFD_DEST_DEREGISTER);
- bfd_info_free(&(pim_ifp->bfd_info));
- }
+ pim_ifp->bfd_config.enabled = false;
+ pim_bfd_reg_dereg_all_nbr(ifp);
break;
}
{
struct interface *ifp;
struct pim_interface *pim_ifp;
- uint32_t min_rx;
- uint32_t min_tx;
- uint8_t detect_mult;
- ifp = nb_running_get_entry(args->dnode->parent, NULL, true);
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
pim_ifp = ifp->info;
if (!pim_ifp) {
return;
}
- min_rx = yang_dnode_get_uint16(args->dnode, "./min-rx-interval");
- min_tx = yang_dnode_get_uint16(args->dnode, "./min-tx-interval");
- detect_mult = yang_dnode_get_uint8(args->dnode, "./detect_mult");
-
- if ((min_rx == BFD_DEF_MIN_RX) && (min_tx == BFD_DEF_MIN_TX)
- && (detect_mult == BFD_DEF_DETECT_MULT))
- pim_bfd_if_param_set(ifp, min_rx, min_tx, detect_mult, 1);
- else
- pim_bfd_if_param_set(ifp, min_rx, min_tx, detect_mult, 0);
+ pim_ifp->bfd_config.detection_multiplier =
+ yang_dnode_get_uint8(args->dnode, "./detect_mult");
+ pim_ifp->bfd_config.min_rx =
+ yang_dnode_get_uint16(args->dnode, "./min-rx-interval");
+ pim_ifp->bfd_config.min_tx =
+ yang_dnode_get_uint16(args->dnode, "./min-tx-interval");
- nb_running_set_entry(args->dnode, pim_ifp->bfd_info);
+ pim_bfd_reg_dereg_all_nbr(ifp);
}
/*
return NB_OK;
}
+/*
+ * XPath: /frr-interface:lib/interface/frr-pim:pim/bfd/profile
+ */
+int lib_interface_pim_bfd_profile_modify(struct nb_cb_modify_args *args)
+{
+ struct interface *ifp;
+ struct pim_interface *pim_ifp;
+
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
+ pim_ifp = ifp->info;
+ XFREE(MTYPE_TMP, pim_ifp->bfd_config.profile);
+ pim_ifp->bfd_config.profile = XSTRDUP(
+ MTYPE_TMP, yang_dnode_get_string(args->dnode, NULL));
+ break;
+ }
+
+ return NB_OK;
+}
+
+int lib_interface_pim_bfd_profile_destroy(struct nb_cb_destroy_args *args)
+{
+ struct interface *ifp;
+ struct pim_interface *pim_ifp;
+
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
+ pim_ifp = ifp->info;
+ XFREE(MTYPE_TMP, pim_ifp->bfd_config.profile);
+ break;
+ }
+
+ return NB_OK;
+}
+
/*
* XPath: /frr-interface:lib/interface/frr-pim:pim/bsm
*/
struct pim_neighbor *neigh;
pim_ifp = ifp->info;
- zassert(pim_ifp);
+ assert(pim_ifp);
pim_ifp->pim_dr_addr = pim_ifp->primary_address;
uint32_t dr_pri;
pim_ifp = ifp->info;
- zassert(pim_ifp);
+ assert(pim_ifp);
pim_ifp->pim_dr_addr = pim_ifp->primary_address;
dr_pri = pim_ifp->pim_dr_priority;
struct pim_neighbor *neigh;
char src_str[INET_ADDRSTRLEN];
- zassert(ifp);
+ assert(ifp);
pim_ifp = ifp->info;
- zassert(pim_ifp);
+ assert(pim_ifp);
neigh = XCALLOC(MTYPE_PIM_NEIGHBOR, sizeof(*neigh));
}
// Register PIM Neighbor with BFD
- pim_bfd_trigger_event(pim_ifp, neigh, 1);
+ pim_bfd_info_nbr_create(pim_ifp, neigh);
return neigh;
}
void pim_neighbor_free(struct pim_neighbor *neigh)
{
- zassert(!neigh->t_expire_timer);
+ assert(!neigh->t_expire_timer);
delete_prefix_list(neigh);
list_delete(&neigh->upstream_jp_agg);
THREAD_OFF(neigh->jp_timer);
- if (neigh->bfd_info)
- pim_bfd_info_free(&neigh->bfd_info);
+ bfd_sess_free(&neigh->bfd_session);
XFREE(MTYPE_PIM_NEIGHBOR, neigh);
}
}
pim_ifp = ifp->info;
- zassert(pim_ifp);
+ assert(pim_ifp);
listnode_add(pim_ifp->pim_neighbor_list, neigh);
uint16_t next_highest_delay_msec;
pim_ifp = ifp->info;
- zassert(pim_ifp);
+ assert(pim_ifp);
next_highest_delay_msec = pim_ifp->pim_propagation_delay_msec;
uint16_t next_highest_interval_msec;
pim_ifp = ifp->info;
- zassert(pim_ifp);
+ assert(pim_ifp);
next_highest_interval_msec = pim_ifp->pim_override_interval_msec;
char src_str[INET_ADDRSTRLEN];
pim_ifp = ifp->info;
- zassert(pim_ifp);
+ assert(pim_ifp);
pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str));
zlog_info("PIM NEIGHBOR DOWN: neighbor %s on interface %s: %s", src_str,
--pim_ifp->pim_dr_num_nondrpri_neighbors;
}
- zassert(neigh->propagation_delay_msec
- <= pim_ifp->pim_neighbors_highest_propagation_delay_msec);
- zassert(neigh->override_interval_msec
- <= pim_ifp->pim_neighbors_highest_override_interval_msec);
+ assert(neigh->propagation_delay_msec
+ <= pim_ifp->pim_neighbors_highest_propagation_delay_msec);
+ assert(neigh->override_interval_msec
+ <= pim_ifp->pim_neighbors_highest_override_interval_msec);
if (pim_if_lan_delay_enabled(ifp)) {
__func__, src_str, ifp->name);
}
- // De-Register PIM Neighbor with BFD
- pim_bfd_trigger_event(pim_ifp, neigh, 0);
-
listnode_delete(pim_ifp->pim_neighbor_list, neigh);
pim_neighbor_free(neigh);
struct pim_neighbor *neigh;
pim_ifp = ifp->info;
- zassert(pim_ifp);
+ assert(pim_ifp);
for (ALL_LIST_ELEMENTS(pim_ifp->pim_neighbor_list, neigh_node,
neigh_nextnode, neigh)) {
struct pim_interface *pim_ifp;
pim_ifp = ifp->info;
- zassert(pim_ifp);
+ assert(pim_ifp);
- zassert(addr_list);
+ assert(addr_list);
/*
Scan secondary address list
struct thread *jp_timer;
struct list *upstream_jp_agg;
- struct bfd_info *bfd_info;
+ struct bfd_session_params *bfd_session;
};
void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime);
{
struct pim_interface *pim_ifp;
- zassert(channel_oil);
- zassert(oif);
+ assert(channel_oil);
+ assert(oif);
pim_ifp = oif->info;
{
struct pim_interface *pim_ifp;
- zassert(ifp);
- zassert(ifp->info);
+ assert(ifp);
+ assert(ifp->info);
pim_ifp = ifp->info;
{
struct pim_interface *pim_ifp;
- zassert(ifp);
+ assert(ifp);
pim_ifp = ifp->info;
if (!pim_ifp) {
{
struct pim_interface *pim_ifp;
- zassert(ifp);
- zassert(ifp->info);
+ assert(ifp);
+ assert(ifp->info);
pim_ifp = ifp->info;
pim_msg_size = pim_tlv_size + PIM_PIM_MIN_LEN;
- zassert(pim_msg_size >= PIM_PIM_MIN_LEN);
- zassert(pim_msg_size <= PIM_PIM_BUFSIZE_WRITE);
+ assert(pim_msg_size >= PIM_PIM_MIN_LEN);
+ assert(pim_msg_size <= PIM_PIM_BUFSIZE_WRITE);
pim_msg_build_header(pim_msg, pim_msg_size, PIM_MSG_TYPE_HELLO, false);
uint32_t old_genid;
pim_ifp = ifp->info;
- zassert(pim_ifp);
+ assert(pim_ifp);
if (pim_ifp->pim_sock_fd >= 0) {
if (PIM_DEBUG_PIM_PACKETS)
bsgrp = pim_bsm_get_bsgrp_node(&pim->global_scope, &group);
if (bsgrp) {
- bsrp = listnode_head(bsgrp->bsrp_list);
+ bsrp = bsm_rpinfos_first(bsgrp->bsrp_list);
if (bsrp) {
if (PIM_DEBUG_PIM_TRACE) {
char bsrp_str[INET_ADDRSTRLEN];
{
int result;
- zassert(!pim->ssmpingd_list);
+ assert(!pim->ssmpingd_list);
result = inet_pton(AF_INET, PIM_SSMPINGD_REPLY_GROUP,
&pim->ssmpingd_group_addr);
- zassert(result > 0);
+ assert(result > 0);
}
void pim_ssmpingd_destroy(struct pim_instance *pim)
static void ssmpingd_delete(struct ssmpingd_sock *ss)
{
- zassert(ss);
+ assert(ss);
THREAD_OFF(ss->t_sock_read);
long mm;
int wr;
- zassert(buf_size >= 5);
+ assert(buf_size >= 5);
mm = sec / 60;
sec %= 60;
long mm;
int wr;
- zassert(buf_size >= 8);
+ assert(buf_size >= 8);
hh = sec / 3600;
sec %= 3600;
void pim_time_uptime(char *buf, int buf_size, int64_t uptime_sec)
{
- zassert(buf_size >= 8);
+ assert(buf_size >= 8);
pim_time_hhmmss(buf, buf_size, uptime_sec);
}
const uint8_t *addr;
const uint8_t *pastend;
- zassert(hello_option_addr_list);
+ assert(hello_option_addr_list);
/*
Scan addr list
&up->t_join_timer);
}
+void pim_update_suppress_timers(uint32_t suppress_time)
+{
+ struct pim_instance *pim;
+ struct vrf *vrf;
+ unsigned int old_rp_ka_time;
+
+ /* stash the old one so we know which values were manually configured */
+ old_rp_ka_time = (3 * router->register_suppress_time
+ + router->register_probe_time);
+ router->register_suppress_time = suppress_time;
+
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ pim = vrf->info;
+ if (!pim)
+ continue;
+
+ /* Only adjust if not manually configured */
+ if (pim->rp_keep_alive_time == old_rp_ka_time)
+ pim->rp_keep_alive_time = PIM_RP_KEEPALIVE_PERIOD;
+ }
+}
+
void pim_upstream_join_suppress(struct pim_upstream *up,
struct in_addr rpf_addr, int holdtime)
{
void pim_upstream_update_join_desired(struct pim_instance *pim,
struct pim_upstream *up);
+void pim_update_suppress_timers(uint32_t suppress_time);
void pim_upstream_join_suppress(struct pim_upstream *up,
struct in_addr rpf_addr, int holdtime);
else
snprintf(spaces, sizeof(spaces), "%s", " ");
+ writes += pim_msdp_peer_config_write(vty, pim, spaces);
writes += pim_msdp_config_write(pim, vty, spaces);
if (!pim->send_v6_secondary) {
writes += pim_rp_config_write(pim, vty, spaces);
- if (router->register_suppress_time
- != PIM_REGISTER_SUPPRESSION_TIME_DEFAULT) {
- vty_out(vty, "%sip pim register-suppress-time %d\n", spaces,
- router->register_suppress_time);
- ++writes;
- }
- if (router->t_periodic != PIM_DEFAULT_T_PERIODIC) {
- vty_out(vty, "%sip pim join-prune-interval %d\n", spaces,
- router->t_periodic);
- ++writes;
+ if (pim->vrf_id == VRF_DEFAULT) {
+ if (router->register_suppress_time
+ != PIM_REGISTER_SUPPRESSION_TIME_DEFAULT) {
+ vty_out(vty, "%sip pim register-suppress-time %d\n",
+ spaces, router->register_suppress_time);
+ ++writes;
+ }
+ if (router->t_periodic != PIM_DEFAULT_T_PERIODIC) {
+ vty_out(vty, "%sip pim join-prune-interval %d\n",
+ spaces, router->t_periodic);
+ ++writes;
+ }
+
+ if (router->packet_process != PIM_DEFAULT_PACKET_PROCESS) {
+ vty_out(vty, "%sip pim packets %d\n", spaces,
+ router->packet_process);
+ ++writes;
+ }
}
if (pim->keep_alive_time != PIM_KEEPALIVE_PERIOD) {
vty_out(vty, "%sip pim keep-alive-timer %d\n", spaces,
pim->rp_keep_alive_time);
++writes;
}
- if (router->packet_process != PIM_DEFAULT_PACKET_PROCESS) {
- vty_out(vty, "%sip pim packets %d\n", spaces,
- router->packet_process);
- ++writes;
- }
if (ssm->plist_name) {
vty_out(vty, "%sip pim ssm prefix-list %s\n", spaces,
ssm->plist_name);
struct igmp_source *source;
struct in_addr src_addr = {.s_addr = 0};
/* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
- zassert(group->group_filtermode_isexcl);
- zassert(listcount(group->group_source_list) < 1);
+ assert(group->group_filtermode_isexcl);
+ assert(listcount(group->group_source_list) < 1);
source = source_new(group, src_addr);
if (!source) {
}
stream_get(&lastused, s, sizeof(lastused));
- stream_getl(s);
+ /* signed success value from netlink_talk; currently unused */
+ (void)stream_getl(s);
c_oil->cc.lastused = lastused;
"%s %s: could not solve %s to group address: errno=%d: %s",
__FILE__, __func__, PIM_ALL_PIM_ROUTERS, errno,
safe_strerror(errno));
- zassert(0);
+ assert(0);
return;
}
-#
# check that the first header included in C files is either
# zebra.h or config.h
#
+# Copyright (C) 2020 David Lamparter for NetDEF, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; either version 2 of the License, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; see the file COPYING; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-import sys, os, re, subprocess
+import sys
+import os
+import re
+import subprocess
+import argparse
+
+argp = argparse.ArgumentParser(description="include fixer")
+argp.add_argument("--autofix", action="store_const", const=True)
+argp.add_argument("--warn-empty", action="store_const", const=True)
+argp.add_argument("--pipe", action="store_const", const=True)
include_re = re.compile('^#\s*include\s+["<]([^ ">]+)[">]', re.M)
-errors = 0
+ignore = [
+ lambda fn: fn.startswith("tools/"),
+ lambda fn: fn
+ in [
+ "lib/elf_py.c",
+ ],
+]
+
+
+def run(args):
+ out = []
+
+ files = subprocess.check_output(["git", "ls-files"]).decode("ASCII")
+ for fn in files.splitlines():
+ if not fn.endswith(".c"):
+ continue
+ if max([i(fn) for i in ignore]):
+ continue
+
+ with open(fn, "r") as fd:
+ data = fd.read()
-files = subprocess.check_output(["git", "ls-files"]).decode("ASCII")
-for fn in files.splitlines():
- if not fn.endswith(".c"):
- continue
- if fn.startswith("tools/"):
- continue
- with open(fn, "r") as fd:
- data = fd.read()
m = include_re.search(data)
if m is None:
- # sys.stderr.write('no #include in %s?\n' % (fn))
+ if args.warn_empty:
+ sys.stderr.write("no #include in %s?\n" % (fn))
continue
if m.group(1) in ["config.h", "zebra.h", "lib/zebra.h"]:
continue
- sys.stderr.write("%s: %s\n" % (fn, m.group(0)))
- errors += 1
-if errors:
- sys.exit(1)
+ if args.autofix:
+ sys.stderr.write("%s: %s - fixing\n" % (fn, m.group(0)))
+ if fn.startswith("pceplib/"):
+ insert = '#ifdef HAVE_CONFIG_H\n#include "config.h"\n#endif\n\n'
+ else:
+ insert = "#include <zebra.h>\n\n"
+
+ pos = m.span()[0]
+
+ data = data[:pos] + insert + data[pos:]
+ with open(fn + ".new", "w") as fd:
+ fd.write(data)
+ os.rename(fn + ".new", fn)
+ else:
+ sys.stderr.write("%s: %s\n" % (fn, m.group(0)))
+ out.append(fn)
+
+ if len(out):
+ if args.pipe:
+ # for "vim `firstheader.py`"
+ print("\n".join(out))
+ return 1
+ return 0
+
+
+if __name__ == "__main__":
+ args = argp.parse_args()
+ sys.exit(run(args))
--- /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)))
# Rules
.proto.pb.h:
- $(PROTOC) -I$(top_srcdir) --cpp_out=$(top_srcdir) $(top_srcdir)/$^
+ $(PROTOC) -I$(top_srcdir) --cpp_out=$(top_builddir) $^
AM_V_PROTOC_C = $(am__v_PROTOC_C_$(V))
am__v_PROTOC_C_ = $(am__v_PROTOC_C_$(AM_DEFAULT_VERBOSITY))
am__v_PROTOC_C_1 =
.proto.pb-c.c:
- $(AM_V_PROTOC_C)$(PROTOC_C) -I$(top_srcdir) --c_out=$(top_srcdir) $(top_srcdir)/$^
+ $(AM_V_PROTOC_C)$(PROTOC_C) -I$(top_srcdir) --c_out=$(top_builddir) $^
+ $(AM_V_GEN)$(SED) -e '1i#include "config.h"' -i $@
.pb-c.c.pb-c.h:
@/bin/true
return ret;
}
+DEFUN (rip_distribute_list,
+ rip_distribute_list_cmd,
+ "distribute-list [prefix] WORD <in|out> [WORD]",
+ "Filter networks in routing updates\n"
+ "Specify a prefix\n"
+ "Access-list name\n"
+ "Filter incoming routing updates\n"
+ "Filter outgoing routing updates\n"
+ "Interface name\n")
+{
+ const char *ifname = NULL;
+ int prefix = (argv[1]->type == WORD_TKN) ? 1 : 0;
+
+ if (argv[argc - 1]->type == VARIABLE_TKN)
+ ifname = argv[argc - 1]->arg;
+
+ return distribute_list_parser(prefix, true, argv[2 + prefix]->text,
+ argv[1 + prefix]->arg, ifname);
+}
+
+DEFUN (rip_no_distribute_list,
+ rip_no_distribute_list_cmd,
+ "no distribute-list [prefix] WORD <in|out> [WORD]",
+ NO_STR
+ "Filter networks in routing updates\n"
+ "Specify a prefix\n"
+ "Access-list name\n"
+ "Filter incoming routing updates\n"
+ "Filter outgoing routing updates\n"
+ "Interface name\n")
+{
+ const char *ifname = NULL;
+ int prefix = (argv[2]->type == WORD_TKN) ? 1 : 0;
+
+ if (argv[argc - 1]->type == VARIABLE_TKN)
+ ifname = argv[argc - 1]->arg;
+
+ return distribute_list_no_parser(vty, prefix, true,
+ argv[3 + prefix]->text,
+ argv[2 + prefix]->arg, ifname);
+}
+
void rip_cli_init(void)
{
install_element(CONFIG_NODE, &router_rip_cmd);
install_element(CONFIG_NODE, &no_router_rip_cmd);
+ install_element(RIP_NODE, &rip_distribute_list_cmd);
+ install_element(RIP_NODE, &rip_no_distribute_list_cmd);
+
install_element(RIP_NODE, &rip_allow_ecmp_cmd);
install_element(RIP_NODE, &rip_default_information_originate_cmd);
install_element(RIP_NODE, &rip_default_metric_cmd);
#include "table.h"
#include "smux.h"
#include "libfrr.h"
-#include "version.h"
+#include "lib/version.h"
#include "ripd/ripd.h"
prefix_list_add_hook(rip_distribute_update_all);
prefix_list_delete_hook(rip_distribute_update_all);
- /* Distribute list install. */
- distribute_list_init(RIP_NODE);
-
/* Route-map */
rip_route_map_init();
# end
ripd_ripd_snmp_la_SOURCES = ripd/rip_snmp.c
-ripd_ripd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11
+ripd_ripd_snmp_la_CFLAGS = $(AM_CFLAGS) $(SNMP_CFLAGS) -std=gnu11
ripd_ripd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
ripd_ripd_snmp_la_LIBADD = lib/libfrrsnmp.la
return ret;
}
+DEFUN (ripng_ipv6_distribute_list,
+ ripng_ipv6_distribute_list_cmd,
+ "ipv6 distribute-list [prefix] WORD <in|out> [WORD]",
+ "IPv6\n"
+ "Filter networks in routing updates\n"
+ "Specify a prefix\n"
+ "Access-list name\n"
+ "Filter incoming routing updates\n"
+ "Filter outgoing routing updates\n"
+ "Interface name\n")
+{
+ const char *ifname = NULL;
+ int prefix = (argv[2]->type == WORD_TKN) ? 1 : 0;
+
+ if (argv[argc - 1]->type == VARIABLE_TKN)
+ ifname = argv[argc - 1]->arg;
+
+ return distribute_list_parser(prefix, false, argv[3 + prefix]->text,
+ argv[2 + prefix]->arg, ifname);
+}
+
+DEFUN (ripng_no_ipv6_distribute_list,
+ ripng_no_ipv6_distribute_list_cmd,
+ "no ipv6 distribute-list [prefix] WORD <in|out> [WORD]",
+ NO_STR
+ "IPv6\n"
+ "Filter networks in routing updates\n"
+ "Specify a prefix\n"
+ "Access-list name\n"
+ "Filter incoming routing updates\n"
+ "Filter outgoing routing updates\n"
+ "Interface name\n")
+{
+ const char *ifname = NULL;
+ int prefix = (argv[3]->type == WORD_TKN) ? 1 : 0;
+
+ if (argv[argc - 1]->type == VARIABLE_TKN)
+ ifname = argv[argc - 1]->arg;
+
+ return distribute_list_no_parser(vty, prefix, false,
+ argv[4 + prefix]->text,
+ argv[3 + prefix]->arg, ifname);
+}
+
void ripng_cli_init(void)
{
install_element(CONFIG_NODE, &router_ripng_cmd);
install_element(CONFIG_NODE, &no_router_ripng_cmd);
+ install_element(RIPNG_NODE, &ripng_ipv6_distribute_list_cmd);
+ install_element(RIPNG_NODE, &ripng_no_ipv6_distribute_list_cmd);
+
install_element(RIPNG_NODE, &ripng_allow_ecmp_cmd);
install_element(RIPNG_NODE, &ripng_default_information_originate_cmd);
install_element(RIPNG_NODE, &ripng_default_metric_cmd);
prefix_list_add_hook(ripng_distribute_update_all);
prefix_list_delete_hook(ripng_distribute_update_all);
- /* Distribute list install. */
- distribute_list_init(RIPNG_NODE);
-
/* Route-map for interface. */
ripng_route_map_init();
#include "sharpd/sharp_vty_clippy.c"
#endif
+DEFPY(watch_redistribute, watch_redistribute_cmd,
+ "sharp watch [vrf NAME$vrf_name] redistribute " FRR_REDIST_STR_SHARPD,
+ "Sharp routing Protocol\n"
+ "Watch for changes\n"
+ "The vrf we would like to watch if non-default\n"
+ "The NAME of the vrf\n"
+ "Redistribute into Sharp\n"
+ FRR_REDIST_HELP_STR_SHARPD)
+{
+ struct vrf *vrf;
+ int source;
+
+ if (!vrf_name)
+ vrf_name = VRF_DEFAULT_NAME;
+ vrf = vrf_lookup_by_name(vrf_name);
+ if (!vrf) {
+ vty_out(vty, "The vrf NAME specified: %s does not exist\n",
+ vrf_name);
+ return CMD_WARNING;
+ }
+
+ source = proto_redistnum(AFI_IP, argv[argc-1]->text);
+ sharp_redistribute_vrf(vrf, source);
+
+ return CMD_SUCCESS;
+}
+
DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd,
"sharp watch [vrf NAME$vrf_name] <nexthop$n X:X::X:X$nhop|import$import X:X::X:X/M$inhop> [connected$connected]",
"Sharp routing Protocol\n"
(0-100000)$inlabel\
[nexthop-group NHGNAME$nhgname] \
[prefix A.B.C.D/M$pfx\
- " FRR_IP_REDIST_STR_SHARPD "$type_str [instance (0-255)$instance]]",
+ " FRR_IP_REDIST_STR_ZEBRA "$type_str [instance (0-255)$instance]]",
"Sharp Routing Protocol\n"
"Remove data\n"
"Remove an LSP\n"
"The nexthop-group name\n"
"Specify a v4 prefix\n"
"The v4 prefix to label\n"
- FRR_IP_REDIST_HELP_STR_SHARPD
+ FRR_IP_REDIST_HELP_STR_ZEBRA
"Routing instance\n"
"Instance to use\n")
{
install_element(ENABLE_NODE, &remove_routes_cmd);
install_element(ENABLE_NODE, &vrf_label_cmd);
install_element(ENABLE_NODE, &sharp_nht_data_dump_cmd);
+ install_element(ENABLE_NODE, &watch_redistribute_cmd);
install_element(ENABLE_NODE, &watch_nexthop_v6_cmd);
install_element(ENABLE_NODE, &watch_nexthop_v4_cmd);
install_element(ENABLE_NODE, &sharp_lsp_prefix_v4_cmd);
return 0;
}
+void sharp_redistribute_vrf(struct vrf *vrf, int type)
+{
+ zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, type,
+ 0, vrf->vrf_id);
+}
+
/* Add a zclient with a specified session id, for testing. */
int sharp_zclient_create(uint32_t session_id)
{
/* Register Link State Opaque messages */
extern void sharp_zebra_register_te(void);
+extern void sharp_redistribute_vrf(struct vrf *vrf, int source);
+
#endif
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <zebra.h>
+
#include "northbound.h"
#include "libfrr.h"
#include "static_nb.h"
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <zebra.h>
+
#include "northbound.h"
#include "libfrr.h"
#include "log.h"
/lib/cli/test_commands_defun.c
/lib/northbound/test_oper_data
/lib/cxxcompat
+/lib/test_assert
/lib/test_atomlist
/lib/test_buffer
/lib/test_checksum
/lib/test_zmq
/ospf6d/test_lsdb
/ospf6d/test_lsdb_clippy.c
-/zebra/test_lm_plugin
\ No newline at end of file
+/zebra/test_lm_plugin
/* Excercise AS4 parsing a bit, with a dogfood test */
if (!s)
- s = stream_new(BGP_MAX_EXTENDED_MESSAGE_PACKET_SIZE);
+ s = stream_new(BGP_MAX_PACKET_SIZE);
bytes4 = aspath_put(s, as, 1);
as4 = make_aspath(STREAM_DATA(s), bytes4, 1);
asp = make_aspath(t->segment->asdata, t->segment->len, 0);
- peer.curr = stream_new(BGP_MAX_EXTENDED_MESSAGE_PACKET_SIZE);
+ peer.curr = stream_new(BGP_MAX_PACKET_SIZE);
peer.obuf = stream_fifo_new();
peer.bgp = &bgp;
peer.host = (char *)"none";
peer.fd = -1;
peer.cap = t->cap;
- peer.max_packet_size = BGP_MAX_PACKET_SIZE;
+ peer.max_packet_size = BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE;
stream_write(peer.curr, t->attrheader, t->len);
datalen = aspath_put(peer.curr, asp, t->as4 == AS4_DATA);
peer->afc_adv[i][j] = 1;
}
- peer->curr = stream_new(BGP_MAX_EXTENDED_MESSAGE_PACKET_SIZE);
+ peer->curr = stream_new(BGP_MAX_PACKET_SIZE);
i = 0;
while (mp_segments[i].name)
peer = peer_create_accept(bgp);
peer->host = (char *)"foo";
peer->status = Established;
- peer->curr = stream_new(BGP_MAX_EXTENDED_MESSAGE_PACKET_SIZE);
+ peer->curr = stream_new(BGP_MAX_PACKET_SIZE);
ifp.ifindex = 0;
peer->nexthop.ifp = &ifp;
/* IS-IS inits. */
yang_module_load("frr-isisd");
isis = isis_new(VRF_DEFAULT_NAME);
- listnode_add(im->isis, isis);
SET_FLAG(im->options, F_ISIS_UNIT_TEST);
debug_spf_events |= DEBUG_SPF_EVENTS;
debug_lfa |= DEBUG_LFA;
#include "lib/yang.h"
#include "lib/yang_translator.h"
#include "lib/yang_wrappers.h"
-#include "lib/zassert.h"
#include "lib/zclient.h"
PREDECL_RBTREE_UNIQ(footree);
--- /dev/null
+/*
+ * Quick test for assert()
+ * Copyright (C) 2021 David Lamparter for NetDEF, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* make sure this works with assert.h & nothing else. also check the include
+ * shadowing, we don't want to pick up system assert.h
+ */
+#include <assert.h>
+
+__attribute__((noinline))
+void func_for_bt(int number)
+{
+ assert(number > 2);
+ assertf(number > 3, "(A) the number was %d", number);
+}
+
+#include <zebra.h>
+#include "lib/zlog.h"
+#include "lib/thread.h"
+#include "lib/sigevent.h"
+
+int main(int argc, char **argv)
+{
+ int number = 10;
+ struct thread_master *master;
+
+ zlog_aux_init("NONE: ", LOG_DEBUG);
+
+ if (argc > 1)
+ number = atoi(argv[1]);
+
+ assert(number > 0);
+ assertf(number > 1, "(B) the number was %d", number);
+
+ /* set up SIGABRT handler */
+ master = thread_master_create("test");
+ signal_init(master, 0, NULL);
+
+ func_for_bt(number);
+ assert(number > 4);
+ assertf(number > 5, "(C) the number was %d", number);
+
+ assertf(number > 10, "(D) the number was %d", number);
+ return 0;
+}
--- /dev/null
+import frrtest
+import os
+import re
+import subprocess
+import inspect
+
+basedir = os.path.dirname(__file__)
+program = os.path.join(basedir, "test_assert")
+
+
+def check(number, rex=None):
+ proc = subprocess.Popen(
+ [frrtest.binpath(program), str(number)],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ )
+ out, err = proc.communicate()
+ exitcode = proc.wait()
+
+ if rex is None:
+ assert exitcode == 0
+ else:
+ assert exitcode != 0
+
+ text = out.decode("US-ASCII") + err.decode("US-ASCII")
+ rex = re.compile(rex, re.M | re.S)
+ m = rex.search(text)
+ assert m is not None, "non-matching output: %s" % text
+
+
+def test_assert_0():
+ check(0, r"test_assert\.c:\d+.*number > 0")
+
+
+def test_assert_1():
+ check(1, r"test_assert\.c:\d+.*number > 1.*\(B\) the number was 1")
+
+
+def test_assert_2():
+ check(2, r"test_assert\.c:\d+.*number > 2")
+
+
+def test_assert_3():
+ check(3, r"test_assert\.c:\d+.*number > 3.*\(A\) the number was 3")
+
+
+def test_assert_4():
+ check(4, r"test_assert\.c:\d+.*number > 4")
+
+
+def test_assert_10():
+ check(10, r"test_assert\.c:\d+.*number > 10.*\(D\) the number was 10")
+
+
+def test_assert_11():
+ check(11)
--- /dev/null
+/*
+ * Nexthop module test.
+ *
+ * Copyright (C) 2021 by Volta Networks, Inc.
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+#include <nexthop.h>
+
+static bool verbose;
+
+static void test_run_first(void)
+{
+ int ret, i;
+ struct nexthop *nh1, *nh2;
+ struct in_addr addr;
+ struct in6_addr addr6;
+ mpls_label_t labels[MPLS_MAX_LABELS];
+
+ /* Test comparison apis */
+
+ /* ifindex comparisons */
+ nh1 = nexthop_from_ifindex(11, 0);
+ nh2 = nexthop_from_ifindex(12, 0);
+
+ ret = nexthop_cmp_basic(nh1, nh2);
+ assert(ret < 0);
+
+ nexthop_free(nh1);
+ nh1 = nexthop_from_ifindex(12, 0);
+
+ ret = nexthop_cmp_basic(nh1, nh2);
+ assert(ret == 0);
+
+ nexthop_free(nh1);
+ nexthop_free(nh2);
+
+ /* ipv4, vrf */
+ addr.s_addr = 0x04030201;
+ nh1 = nexthop_from_ipv4(&addr, NULL, 0);
+ nh2 = nexthop_from_ipv4(&addr, NULL, 111);
+
+ ret = nexthop_cmp_basic(nh1, nh2);
+ assert(ret != 0);
+
+ nexthop_free(nh2);
+
+ addr.s_addr = 0x04030202;
+ nh2 = nexthop_from_ipv4(&addr, NULL, 0);
+
+ ret = nexthop_cmp_basic(nh1, nh2);
+ assert(ret != 0);
+
+ nexthop_free(nh2);
+
+ addr.s_addr = 0x04030201;
+ nh2 = nexthop_from_ipv4(&addr, NULL, 0);
+
+ ret = nexthop_cmp_basic(nh1, nh2);
+ assert(ret == 0);
+
+ /* Weight */
+ nh2->weight = 20;
+
+ ret = nexthop_cmp_basic(nh1, nh2);
+ assert(ret != 0);
+
+ nexthop_free(nh1);
+ nexthop_free(nh2);
+
+ /* ipv6 */
+ memset(addr6.s6_addr, 0, sizeof(addr6.s6_addr));
+ nh1 = nexthop_from_ipv6(&addr6, 0);
+ nh2 = nexthop_from_ipv6(&addr6, 0);
+
+ ret = nexthop_cmp_basic(nh1, nh2);
+ assert(ret == 0);
+
+ nexthop_free(nh2);
+
+ nh2 = nexthop_from_ipv6(&addr6, 1);
+
+ ret = nexthop_cmp_basic(nh1, nh2);
+ assert(ret != 0);
+
+ nexthop_free(nh2);
+
+ addr6.s6_addr[14] = 1;
+ addr6.s6_addr[15] = 1;
+ nh2 = nexthop_from_ipv6(&addr6, 0);
+
+ ret = nexthop_cmp_basic(nh1, nh2);
+ assert(ret != 0);
+
+ nexthop_free(nh1);
+ nexthop_free(nh2);
+
+ /* Blackhole */
+ nh1 = nexthop_from_blackhole(BLACKHOLE_REJECT);
+ nh2 = nexthop_from_blackhole(BLACKHOLE_REJECT);
+
+ ret = nexthop_cmp_basic(nh1, nh2);
+ assert(ret == 0);
+
+ nexthop_free(nh2);
+
+ nh2 = nexthop_from_blackhole(BLACKHOLE_NULL);
+
+ ret = nexthop_cmp_basic(nh1, nh2);
+ assert(ret != 0);
+
+ /* Labels */
+ addr.s_addr = 0x04030201;
+ nh1 = nexthop_from_ipv4(&addr, NULL, 0);
+ nh2 = nexthop_from_ipv4(&addr, NULL, 0);
+
+ memset(labels, 0, sizeof(labels));
+ labels[0] = 111;
+ labels[1] = 222;
+
+ nexthop_add_labels(nh1, ZEBRA_LSP_STATIC, 2, labels);
+
+ ret = nexthop_cmp_basic(nh1, nh2);
+ assert(ret != 0);
+
+ nexthop_add_labels(nh2, ZEBRA_LSP_STATIC, 2, labels);
+
+ ret = nexthop_cmp_basic(nh1, nh2);
+ assert(ret == 0);
+
+ nexthop_free(nh2);
+
+ /* LSP type isn't included */
+ nh2 = nexthop_from_ipv4(&addr, NULL, 0);
+ nexthop_add_labels(nh2, ZEBRA_LSP_LDP, 2, labels);
+
+ ret = nexthop_cmp_basic(nh1, nh2);
+ assert(ret == 0);
+
+ nexthop_free(nh2);
+
+ labels[2] = 333;
+ nh2 = nexthop_from_ipv4(&addr, NULL, 0);
+ nexthop_add_labels(nh2, ZEBRA_LSP_LDP, 3, labels);
+
+ ret = nexthop_cmp_basic(nh1, nh2);
+ assert(ret != 0);
+
+ nexthop_free(nh1);
+ nexthop_free(nh2);
+
+ nh1 = nexthop_from_ipv4(&addr, NULL, 0);
+ nh2 = nexthop_from_ipv4(&addr, NULL, 0);
+
+ for (i = 0; i < MPLS_MAX_LABELS; i++)
+ labels[i] = 111 * (i + 1);
+
+ nexthop_add_labels(nh1, ZEBRA_LSP_LDP, MPLS_MAX_LABELS, labels);
+ nexthop_add_labels(nh2, ZEBRA_LSP_LDP, MPLS_MAX_LABELS, labels);
+
+ ret = nexthop_cmp_basic(nh1, nh2);
+ assert(ret == 0);
+
+ nexthop_free(nh2);
+
+ /* Test very last label in stack */
+ labels[15] = 999;
+ nh2 = nexthop_from_ipv4(&addr, NULL, 0);
+ nexthop_add_labels(nh2, ZEBRA_LSP_LDP, MPLS_MAX_LABELS, labels);
+
+ ret = nexthop_cmp_basic(nh1, nh2);
+ assert(ret != 0);
+
+ /* End */
+ nexthop_free(nh1);
+ nexthop_free(nh2);
+}
+
+int main(int argc, char **argv)
+{
+ if (argc >= 2 && !strcmp("-v", argv[1]))
+ verbose = true;
+ test_run_first();
+ printf("Simple test passed.\n");
+}
--- /dev/null
+import frrtest
+
+
+class TestNexthopIter(frrtest.TestMultiOut):
+ program = "./test_nexthop"
+
+
+TestNexthopIter.onesimple("Simple test passed.")
assert(ringbuf_get(soil, &compost, BUFSIZ) == BUFSIZ);
validate_state(soil, BUFSIZ, 0);
- assert(soil->empty = true);
+ assert(soil->empty == true);
assert(soil->start == soil->end);
assert(soil->start == 15);
#include "monotime.h"
#include "seqlock.h"
+#include "printfrr.h"
static struct seqlock sqlo;
static pthread_t thr1;
char buf[32];
int64_t usec = monotime_since(&start, NULL);
- snprintf(buf, sizeof(buf), "[%02"PRId64"] ", usec / 100000);
+ snprintfrr(buf, sizeof(buf), "[%02" PRId64 "] ", usec / 100000);
iov[0].iov_base = buf;
iov[0].iov_len = strlen(buf);
/* C++ called, they want their templates back */
#define item concat(item_, TYPE)
#define itm concat(itm_, TYPE)
+#define itmswap concat(itmswap_, TYPE)
#define head concat(head_, TYPE)
#define list concat(TYPE, )
#define list_head concat(TYPE, _head)
#define list_find_gteq concat(TYPE, _find_gteq)
#define list_del concat(TYPE, _del)
#define list_pop concat(TYPE, _pop)
+#define list_swap_all concat(TYPE, _swap_all)
-#define ts_hash concat(ts_hash_, TYPE)
+#define ts_hash_head concat(ts_hash_head_, TYPE)
#ifndef REALTYPE
#define REALTYPE TYPE
#endif
#define NITEM 10000
-struct item itm[NITEM];
+#define NITEM_SWAP 100 /* other container for swap */
+struct item itm[NITEM], itmswap[NITEM_SWAP];
static struct list_head head = concat(INIT_, REALTYPE)(head);
-static void ts_hash(const char *text, const char *expect)
+static void ts_hash_head(struct list_head *h, const char *text,
+ const char *expect)
{
int64_t us = monotime_since(&ref, NULL);
SHA256_CTX ctx;
char hashtext[65];
uint32_t swap_count, count;
- count = list_count(&head);
+ count = list_count(h);
swap_count = htonl(count);
SHA256_Init(&ctx);
SHA256_Update(&ctx, &swap_count, sizeof(swap_count));
- frr_each (list, &head, item) {
+ frr_each (list, h, item) {
struct {
uint32_t val_upper, val_lower, index;
} hashitem = {
}
/* hashes will have different item ordering */
#if IS_HASH(REALTYPE) || IS_HEAP(REALTYPE)
-#define ts_hashx(pos, csum) ts_hash(pos, NULL)
+#define ts_hash(pos, csum) ts_hash_head(&head, pos, NULL)
+#define ts_hashx(pos, csum) ts_hash_head(&head, pos, NULL)
+#define ts_hash_headx(head, pos, csum) ts_hash_head(head, pos, NULL)
#else
-#define ts_hashx(pos, csum) ts_hash(pos, csum)
+#define ts_hash(pos, csum) ts_hash_head(&head, pos, csum)
+#define ts_hashx(pos, csum) ts_hash_head(&head, pos, csum)
+#define ts_hash_headx(head, pos, csum) ts_hash_head(head, pos, csum)
#endif
static void concat(test_, TYPE)(void)
{
size_t i, j, k, l;
struct prng *prng;
+ struct prng *prng_swap __attribute__((unused));
struct item *item, *prev __attribute__((unused));
struct item dummy __attribute__((unused));
for (i = 0; i < NITEM; i++)
itm[i].val = i;
+ memset(itmswap, 0, sizeof(itmswap));
+ for (i = 0; i < NITEM_SWAP; i++)
+ itmswap[i].val = i;
+
printfrr("%s start\n", str(TYPE));
ts_start();
assert(list_first(&head) != NULL);
ts_hashx("fill", "a538546a6e6ab0484e925940aa8dd02fd934408bbaed8cb66a0721841584d838");
+#if !IS_ATOMIC(REALTYPE)
+ struct list_head other;
+
+ list_init(&other);
+ list_swap_all(&head, &other);
+
+ assert(list_count(&head) == 0);
+ assert(!list_first(&head));
+ assert(list_count(&other) == k);
+ assert(list_first(&other) != NULL);
+ ts_hash_headx(
+ &other, "swap1",
+ "a538546a6e6ab0484e925940aa8dd02fd934408bbaed8cb66a0721841584d838");
+
+ prng_swap = prng_new(0x1234dead);
+ l = 0;
+ for (i = 0; i < NITEM_SWAP; i++) {
+ j = prng_rand(prng_swap) % NITEM_SWAP;
+ if (itmswap[j].scratchpad == 0) {
+ list_add(&head, &itmswap[j]);
+ itmswap[j].scratchpad = 1;
+ l++;
+ }
+#if !IS_HEAP(REALTYPE)
+ else {
+ struct item *rv = list_add(&head, &itmswap[j]);
+ assert(rv == &itmswap[j]);
+ }
+#endif
+ }
+ assert(list_count(&head) == l);
+ assert(list_first(&head) != NULL);
+ ts_hash_headx(
+ &head, "swap-fill",
+ "26df437174051cf305d1bbb62d779ee450ca764167a1e7a94be1aece420008e6");
+
+ list_swap_all(&head, &other);
+
+ assert(list_count(&other) == l);
+ assert(list_first(&other));
+ ts_hash_headx(
+ &other, "swap2a",
+ "26df437174051cf305d1bbb62d779ee450ca764167a1e7a94be1aece420008e6");
+ assert(list_count(&head) == k);
+ assert(list_first(&head) != NULL);
+ ts_hash_headx(
+ &head, "swap2b",
+ "a538546a6e6ab0484e925940aa8dd02fd934408bbaed8cb66a0721841584d838");
+#endif /* !IS_ATOMIC */
+
k = 0;
#if IS_ATOMIC(REALTYPE)
assert(list_first(&head) != NULL);
ts_hash("fill / add_tail", "eabfcf1413936daaf20965abced95762f45110a6619b84aac7d38481bce4ea19");
+#if !IS_ATOMIC(REALTYPE)
+ struct list_head other;
+
+ list_init(&other);
+ list_swap_all(&head, &other);
+
+ assert(list_count(&head) == 0);
+ assert(!list_first(&head));
+ assert(list_count(&other) == k);
+ assert(list_first(&other) != NULL);
+ ts_hash_head(
+ &other, "swap1",
+ "eabfcf1413936daaf20965abced95762f45110a6619b84aac7d38481bce4ea19");
+
+ prng_swap = prng_new(0x1234dead);
+ l = 0;
+ for (i = 0; i < NITEM_SWAP; i++) {
+ j = prng_rand(prng_swap) % NITEM_SWAP;
+ if (itmswap[j].scratchpad == 0) {
+ list_add_tail(&head, &itmswap[j]);
+ itmswap[j].scratchpad = 1;
+ l++;
+ }
+ }
+ assert(list_count(&head) == l);
+ assert(list_first(&head) != NULL);
+ ts_hash_head(
+ &head, "swap-fill",
+ "833e6ae437e322dfbd36eda8cfc33a61109be735b43f15d256c05e52d1b01909");
+
+ list_swap_all(&head, &other);
+
+ assert(list_count(&other) == l);
+ assert(list_first(&other));
+ ts_hash_head(
+ &other, "swap2a",
+ "833e6ae437e322dfbd36eda8cfc33a61109be735b43f15d256c05e52d1b01909");
+ assert(list_count(&head) == k);
+ assert(list_first(&head) != NULL);
+ ts_hash_head(
+ &head, "swap2b",
+ "eabfcf1413936daaf20965abced95762f45110a6619b84aac7d38481bce4ea19");
+#endif
+
for (i = 0; i < NITEM / 2; i++) {
j = prng_rand(prng) % NITEM;
if (itm[j].scratchpad == 1) {
printfrr("%s end\n", str(TYPE));
}
+#undef ts_hash
#undef ts_hashx
+#undef ts_hash_head
+#undef ts_hash_headx
#undef item
#undef itm
+#undef itmswap
#undef head
#undef list
#undef list_head
#undef list_find_gteq
#undef list_del
#undef list_pop
+#undef list_swap_all
#undef REALTYPE
#undef TYPE
check_PROGRAMS = \
tests/lib/cxxcompat \
+ tests/lib/test_assert \
tests/lib/test_atomlist \
tests/lib/test_buffer \
tests/lib/test_checksum \
tests/lib/test_idalloc \
tests/lib/test_memory \
tests/lib/test_nexthop_iter \
+ tests/lib/test_nexthop \
tests/lib/test_ntop \
tests/lib/test_prefix2str \
tests/lib/test_printfrr \
-I$(top_builddir)/tests/helpers/c \
# end
TESTS_CFLAGS = \
+ $(AC_CFLAGS) \
$(LIBYANG_CFLAGS) \
$(SAN_FLAGS) \
# end
tests_lib_northbound_test_oper_data_LDADD = $(ALL_TESTS_LDADD)
tests_lib_northbound_test_oper_data_SOURCES = tests/lib/northbound/test_oper_data.c
nodist_tests_lib_northbound_test_oper_data_SOURCES = yang/frr-test-module.yang.c
+tests_lib_test_assert_CFLAGS = $(TESTS_CFLAGS)
+tests_lib_test_assert_CPPFLAGS = $(TESTS_CPPFLAGS)
+tests_lib_test_assert_LDADD = $(ALL_TESTS_LDADD)
+tests_lib_test_assert_SOURCES = tests/lib/test_assert.c
tests_lib_test_atomlist_CFLAGS = $(TESTS_CFLAGS)
tests_lib_test_atomlist_CPPFLAGS = $(TESTS_CPPFLAGS)
tests_lib_test_atomlist_LDADD = $(ALL_TESTS_LDADD)
tests_lib_test_nexthop_iter_CPPFLAGS = $(TESTS_CPPFLAGS)
tests_lib_test_nexthop_iter_LDADD = $(ALL_TESTS_LDADD)
tests_lib_test_nexthop_iter_SOURCES = tests/lib/test_nexthop_iter.c tests/helpers/c/prng.c
+tests_lib_test_nexthop_CFLAGS = $(TESTS_CFLAGS)
+tests_lib_test_nexthop_CPPFLAGS = $(TESTS_CPPFLAGS)
+tests_lib_test_nexthop_LDADD = $(ALL_TESTS_LDADD)
+tests_lib_test_nexthop_SOURCES = tests/lib/test_nexthop.c
tests_lib_test_ntop_CFLAGS = $(TESTS_CFLAGS)
-tests_lib_test_ntop_CPPFLAGS = $(TESTS_CPPFLAGS)
+tests_lib_test_ntop_CPPFLAGS = $(CPPFLAGS_BASE) # no assert override
tests_lib_test_ntop_LDADD = # none
tests_lib_test_ntop_SOURCES = tests/lib/test_ntop.c tests/helpers/c/prng.c
tests_lib_test_prefix2str_CFLAGS = $(TESTS_CFLAGS)
tests/lib/northbound/test_oper_data.in \
tests/lib/northbound/test_oper_data.py \
tests/lib/northbound/test_oper_data.refout \
+ tests/lib/test_assert.py \
tests/lib/test_atomlist.py \
tests/lib/test_nexthop_iter.py \
+ tests/lib/test_nexthop.py \
tests/lib/test_ntop.py \
tests/lib/test_prefix2str.py \
tests/lib/test_printfrr.py \
xterm \
&& pip install \
exabgp==3.4.17 \
+ "scapy>=2.4.2" \
ipaddr \
pytest \
&& rm -rf /var/lib/apt/lists/*
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
MTU mismatch detection: enabled
Router ID 192.168.0.1, Network Type BROADCAST, Cost: 10
Transmit Delay is 1 sec, State DR, Priority 1
+ Designated Router (ID) 192.168.0.1 Interface Address 192.168.0.1/24
No backup designated router on this network
Multicast group memberships: OSPFAllRouters OSPFDesignatedRouters
Timer intervals configured, Hello 10s, Dead 40s, Wait 40s, Retransmit 5
MTU mismatch detection: enabled
Router ID 192.168.0.1, Network Type BROADCAST, Cost: 10
Transmit Delay is 1 sec, State DR, Priority 1
+ Designated Router (ID) 192.168.0.1 Interface Address 192.168.3.1/26
No backup designated router on this network
Multicast group memberships: OSPFAllRouters OSPFDesignatedRouters
Timer intervals configured, Hello 10s, Dead 40s, Wait 40s, Retransmit 5
"multihop":true,
"peer":"2001:db8:4::1",
"local":"2001:db8:1::1",
- "status":"up",
+ "status":"init",
"receive-interval":300,
"transmit-interval":300,
"echo-receive-interval":50,
"echo-transmit-interval":0,
- "remote-receive-interval":300,
- "remote-transmit-interval":300,
+ "remote-receive-interval":1000,
+ "remote-transmit-interval":1000,
"remote-echo-receive-interval":50
}
]
"local": "*",
"multihop": false,
"peer": "*",
- "receive-interval": 300,
+ "receive-interval": 250,
"remote-detect-multiplier": 3,
"remote-diagnostic": "ok",
"remote-echo-receive-interval": 50,
"remote-receive-interval": 300,
"remote-transmit-interval": 300,
"status": "up",
- "transmit-interval": 300,
+ "transmit-interval": 250,
"uptime": "*",
"vrf": "default"
}
debug bfd zebra
!
bfd
+ profile fast-tx
+ receive-interval 250
+ transmit-interval 250
+ !
!
interface r4-eth1
- ipv6 ospf6 bfd
+ ipv6 ospf6 bfd profile fast-tx
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 10
!
router ospf6
ospf6 router-id 10.254.254.4
"remote-detect-multiplier": 3,
"remote-diagnostic": "ok",
"remote-id": "*",
- "remote-receive-interval": 300,
- "remote-transmit-interval": 300,
+ "remote-receive-interval": 250,
+ "remote-transmit-interval": 250,
"status": "up",
"transmit-interval": 300,
"uptime": "*",
interface r5-eth0
ipv6 ospf6 bfd
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 10
!
router ospf6
ospf6 router-id 10.254.254.5
raise InvalidCLIError("%s" % output)
-def clear_bgp(vrf=""):
- " clear bgp configuration for a vrf"
+def clear_bgp():
+ "clear bgp configuration for a vrf"
tgen = get_topogen()
r1 = tgen.gears["R1"]
r2 = tgen.gears["R2"]
r3 = tgen.gears["R3"]
- router_list = tgen.routers()
- if vrf == "":
- r1.vtysh_cmd("conf t\nno router bgp 65001")
- r2.vtysh_cmd("conf t\nno router bgp 65002")
- r2.vtysh_cmd("conf t\nno router bgp 65003")
- else:
- r1.vtysh_cmd("conf t\nno router bgp 65001 vrf {}".format(vrf))
- r2.vtysh_cmd("conf t\nno router bgp 65002 vrf {}".format(vrf))
- r3.vtysh_cmd("conf t\nno router bgp 65003 vrf {}".format(vrf))
+ r1.vtysh_cmd("conf t\nno router bgp 65001")
+ r2.vtysh_cmd("conf t\nno router bgp 65002")
+ r3.vtysh_cmd("conf t\nno router bgp 65003")
+ r1.vtysh_cmd("conf t\nno router bgp 65001 vrf blue")
+ r2.vtysh_cmd("conf t\nno router bgp 65002 vrf blue")
+ r3.vtysh_cmd("conf t\nno router bgp 65003 vrf blue")
+ r1.vtysh_cmd("conf t\nno router bgp 65001 vrf red")
+ r2.vtysh_cmd("conf t\nno router bgp 65002 vrf red")
+ r3.vtysh_cmd("conf t\nno router bgp 65003 vrf red")
+
+def configure_bgp(conf_file):
+ "configure bgp from file"
-def clear_ospf(vrf=""):
+ clear_bgp()
+ configure(conf_file)
+
+
+def clear_ospf():
"clear ospf configuration for a vrf"
tgen = get_topogen()
router_list = tgen.routers()
for rname, router in router_list.items():
- if vrf == "":
- router.vtysh_cmd("conf t\nno router ospf")
- else:
- router.vtysh_cmd("conf t\nno router ospf vrf {}".format(vrf))
+ router.vtysh_cmd("conf t\nno router ospf")
+ router.vtysh_cmd("conf t\nno router ospf vrf blue")
+ router.vtysh_cmd("conf t\nno router ospf vrf red")
+
+
+def configure_ospf(conf_file):
+ "configure bgp from file"
+
+ clear_ospf()
+ configure(conf_file)
def check_neigh_state(router, peer, state, vrf=""):
"show bgp vrf {} neighbors {} json".format(vrf, peer)
)
neigh_output_json = json.loads(neigh_output)
- if neigh_output_json[peer]["bgpState"] == state:
- matched = True
- break
+ if peer in neigh_output_json.keys():
+ if neigh_output_json[peer]["bgpState"] == state:
+ matched = True
+ break
count += 1
sleep(1)
r2 = tgen.gears["R2"]
r3 = tgen.gears["R3"]
+ check_all_peers_established(vrf)
+
r1.vtysh_cmd(
"conf t\nrouter bgp 65001 {}\nno neighbor {} password".format(
vrf_str(vrf), peer_name("R2", prefix, vrf)
def test_default_peer_established():
"default vrf 3 peers same password"
+ configure_bgp("bgpd.conf")
+ configure_ospf("ospfd.conf")
check_all_peers_established()
- clear_bgp()
# tgen.mininet_cli()
def test_default_peer_remove_passwords():
"selectively remove passwords checking state"
- configure("bgpd.conf")
+ configure_bgp("bgpd.conf")
+ configure_ospf("ospfd.conf")
check_vrf_peer_remove_passwords()
- clear_bgp()
def test_default_peer_change_passwords():
"selectively change passwords checking state"
- configure("bgpd.conf")
+ configure_bgp("bgpd.conf")
+ configure_ospf("ospfd.conf")
check_vrf_peer_change_passwords()
- clear_bgp()
def test_default_prefix_peer_established():
if topotest.version_cmp(platform.release(), "5.3") < 0:
return
- configure("bgpd_prefix.conf")
+ configure_bgp("bgpd_prefix.conf")
+ configure_ospf("ospfd.conf")
check_all_peers_established()
- clear_bgp()
# tgen.mininet_cli()
# only supported in kernel > 5.3
if topotest.version_cmp(platform.release(), "5.3") < 0:
return
- configure("bgpd_prefix.conf")
+
+ configure_bgp("bgpd_prefix.conf")
+ configure_ospf("ospfd.conf")
check_vrf_peer_remove_passwords(prefix="yes")
- clear_bgp()
def test_prefix_peer_change_passwords():
# only supported in kernel > 5.3
if topotest.version_cmp(platform.release(), "5.3") < 0:
return
- configure("bgpd_prefix.conf")
+
+ configure_bgp("bgpd_prefix.conf")
+ configure_ospf("ospfd.conf")
check_vrf_peer_change_passwords(prefix="yes")
- clear_bgp()
- clear_ospf()
def test_vrf_peer_established():
"default vrf 3 peers same password with VRF config"
# clean routers and load vrf config
- configure("bgpd_vrf.conf")
- configure("ospfd_vrf.conf")
-
+ configure_bgp("bgpd_vrf.conf")
+ configure_ospf("ospfd_vrf.conf")
check_all_peers_established("blue")
- clear_bgp("blue")
# tgen.mininet_cli()
def test_vrf_peer_remove_passwords():
"selectively remove passwords checking state with VRF config"
- configure("bgpd_vrf.conf")
+ configure_bgp("bgpd_vrf.conf")
+ configure_ospf("ospfd_vrf.conf")
check_vrf_peer_remove_passwords(vrf="blue")
- clear_bgp("blue")
def test_vrf_peer_change_passwords():
"selectively change passwords checking state with VRF config"
- configure("bgpd_vrf.conf")
+ configure_bgp("bgpd_vrf.conf")
+ configure_ospf("ospfd_vrf.conf")
check_vrf_peer_change_passwords(vrf="blue")
- clear_bgp("blue")
def test_vrf_prefix_peer_established():
# only supported in kernel > 5.3
if topotest.version_cmp(platform.release(), "5.3") < 0:
- clear_bgp("blue")
return
- configure("bgpd_vrf_prefix.conf")
+ configure_bgp("bgpd_vrf_prefix.conf")
+ configure_ospf("ospfd_vrf.conf")
check_all_peers_established("blue")
- clear_bgp("blue")
def test_vrf_prefix_peer_remove_passwords():
if topotest.version_cmp(platform.release(), "5.3") < 0:
return
- configure("bgpd_vrf_prefix.conf")
+ configure_bgp("bgpd_vrf_prefix.conf")
+ configure_ospf("ospfd_vrf.conf")
check_vrf_peer_remove_passwords(vrf="blue", prefix="yes")
- clear_bgp("blue")
def test_vrf_prefix_peer_change_passwords():
"selectively change passwords checking state with VRF prefix config"
- tgen = get_topogen()
- r1 = tgen.gears["R1"]
- r2 = tgen.gears["R2"]
- r3 = tgen.gears["R3"]
-
# only supported in kernel > 5.3
if topotest.version_cmp(platform.release(), "5.3") < 0:
- clear_ospf("blue")
return
- configure("bgpd_vrf_prefix.conf")
+ configure_bgp("bgpd_vrf_prefix.conf")
+ configure_ospf("ospfd_vrf.conf")
check_vrf_peer_change_passwords(vrf="blue", prefix="yes")
- clear_bgp("blue")
- clear_ospf("blue")
def test_multiple_vrf_peer_established():
"default vrf 3 peers same password with multiple VRFs"
- configure("bgpd_multi_vrf.conf")
- configure("ospfd_multi_vrf.conf")
+ configure_bgp("bgpd_multi_vrf.conf")
+ configure_ospf("ospfd_multi_vrf.conf")
check_all_peers_established("blue")
check_all_peers_established("red")
- clear_bgp("blue")
- clear_bgp("red")
# tgen.mininet_cli()
def test_multiple_vrf_peer_remove_passwords():
"selectively remove passwords checking state with multiple VRFs"
- configure("bgpd_multi_vrf.conf")
+ configure_bgp("bgpd_multi_vrf.conf")
+ configure_ospf("ospfd_multi_vrf.conf")
check_vrf_peer_remove_passwords("blue")
check_all_peers_established("red")
check_vrf_peer_remove_passwords("red")
check_all_peers_established("blue")
- clear_bgp("blue")
- clear_bgp("red")
# tgen.mininet_cli()
def test_multiple_vrf_peer_change_passwords():
"selectively change passwords checking state with multiple VRFs"
- configure("bgpd_multi_vrf.conf")
+ configure_bgp("bgpd_multi_vrf.conf")
+ configure_ospf("ospfd_multi_vrf.conf")
check_vrf_peer_change_passwords("blue")
check_all_peers_established("red")
check_vrf_peer_change_passwords("red")
check_all_peers_established("blue")
- clear_bgp("blue")
- clear_bgp("red")
# tgen.mininet_cli()
if topotest.version_cmp(platform.release(), "5.3") < 0:
return
- configure("bgpd_multi_vrf.conf")
- configure("ospfd_multi_vrf.conf")
+ configure_bgp("bgpd_multi_vrf_prefix.conf")
+ configure_ospf("ospfd_multi_vrf.conf")
check_all_peers_established("blue")
check_all_peers_established("red")
- clear_bgp("blue")
- clear_bgp("red")
# tgen.mininet_cli()
if topotest.version_cmp(platform.release(), "5.3") < 0:
return
- configure("bgpd_multi_vrf_prefix.conf")
- tgen = get_topogen()
+ configure_bgp("bgpd_multi_vrf_prefix.conf")
+ configure_ospf("ospfd_multi_vrf.conf")
check_vrf_peer_remove_passwords(vrf="blue", prefix="yes")
check_all_peers_established("red")
check_vrf_peer_remove_passwords(vrf="red", prefix="yes")
check_all_peers_established("blue")
- clear_bgp("blue")
- clear_bgp("red")
# tgen.mininet_cli()
# only supported in kernel > 5.3
if topotest.version_cmp(platform.release(), "5.3") < 0:
- clear_bgp("blue")
- clear_bgp("red")
- clear_ospf("blue")
- clear_ospf("red")
return
- configure("bgpd_multi_vrf_prefix.conf")
+ configure_bgp("bgpd_multi_vrf_prefix.conf")
+ configure_ospf("ospfd_multi_vrf.conf")
check_vrf_peer_change_passwords(vrf="blue", prefix="yes")
check_all_peers_established("red")
check_vrf_peer_change_passwords(vrf="red", prefix="yes")
check_all_peers_established("blue")
- clear_bgp("blue")
- clear_bgp("red")
- clear_ospf("blue")
- clear_ospf("red")
# tgen.mininet_cli()
--- /dev/null
+!
+bgp community alias 65002:1 community-r2-1
+bgp community alias 65002:2 community-r2-2
+bgp community alias 65002:1:1 large-community-r2-1
+!
+router bgp 65001
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.2 remote-as external
+!
--- /dev/null
+!
+int r1-eth0
+ ip address 192.168.1.1/24
+!
--- /dev/null
+router bgp 65002
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.1 remote-as external
+ address-family ipv4 unicast
+ redistribute connected
+ neighbor 192.168.1.1 route-map r1 out
+ exit-address-family
+!
+route-map r1 permit 10
+ set community 65002:1 65002:2
+ set large-community 65002:1:1 65002:2:1
+!
--- /dev/null
+!
+int r2-eth0
+ ip address 192.168.1.2/24
+!
--- /dev/null
+#!/usr/bin/env python
+
+# Copyright (c) 2021 by
+# Donatas Abraitis <donatas.abraitis@gmail.com>
+#
+# 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 if BGP community alias is visible in CLI outputs
+"""
+
+import os
+import sys
+import json
+import time
+import pytest
+import functools
+
+pytestmark = pytest.mark.bgpd
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+from mininet.topo import Topo
+
+
+class TemplateTopo(Topo):
+ def build(self, *_args, **_opts):
+ tgen = get_topogen(self)
+
+ for routern in range(1, 3):
+ tgen.add_router("r{}".format(routern))
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+
+def setup_module(mod):
+ tgen = Topogen(TemplateTopo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for i, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_community_alias():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router = tgen.gears["r1"]
+
+ def _bgp_converge(router):
+ output = json.loads(router.vtysh_cmd("show ip bgp 192.168.1.0/24 json"))
+ expected = {
+ "paths": [
+ {
+ "community": {"string": "community-r2-1 community-r2-2"},
+ "largeCommunity": {"string": "large-community-r2-1 65002:2:1"},
+ }
+ ]
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_converge, router)
+ success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+
+ assert result is None, 'Cannot see BGP community aliases "{}"'.format(router)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
import pytest
import functools
+pytestmark = [pytest.mark.bgpd]
+
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
import pytest
import functools
+pytestmark = [pytest.mark.bgpd]
+
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
check_router_status,
shutdown_bringup_interface,
step,
- kill_mininet_routers_process,
get_frr_ipv6_linklocal,
create_route_maps,
required_linux_kernel_version,
tgen = Topogen(GenerateTopo, mod.__name__)
# ... and here it calls Mininet initialization functions.
- # Kill stale mininet routers and process
- kill_mininet_routers_process(tgen)
-
# Starting topology, create tmp files which are loaded to routers
# to start deamons and then start routers
start_topology(tgen)
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
check_router_status,
shutdown_bringup_interface,
step,
- kill_mininet_routers_process,
get_frr_ipv6_linklocal,
create_route_maps,
required_linux_kernel_version,
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)
create_static_routes,
create_prefix_lists,
create_interface_in_kernel,
- kill_mininet_routers_process,
create_bgp_community_lists,
check_router_status,
apply_raw_config,
tgen = Topogen(CreateTopo, mod.__name__)
# ... and here it calls Mininet initialization functions.
- # Kill stale mininet routers and process
- kill_mininet_routers_process(tgen)
-
# Starting topology, create tmp files which are loaded to routers
# to start deamons and then start routers
start_topology(tgen)
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)
create_vrf_cfg,
create_interfaces_cfg,
create_interface_in_kernel,
- kill_mininet_routers_process,
get_frr_ipv6_linklocal,
check_router_status,
apply_raw_config,
tgen = Topogen(CreateTopo, mod.__name__)
# ... and here it calls Mininet initialization functions.
- # Kill stale mininet routers and process
- kill_mininet_routers_process(tgen)
-
# Starting topology, create tmp files which are loaded to routers
# to start deamons and then start routers
start_topology(tgen)
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
shutdown_bringup_interface,
addKernelRoute,
delete_route_maps,
- kill_mininet_routers_process,
)
from lib.topolog import logger
from lib.bgp import (
--- /dev/null
+router bgp 65000
+ no bgp ebgp-requires-policy
+ neighbor 192.168.255.2 remote-as 65001
+ neighbor 192.168.255.2 timers 3 10
+ exit-address-family
+!
--- /dev/null
+!
+interface r1-eth0
+ ip address 192.168.255.1/24
+!
+ip forwarding
+!
--- /dev/null
+router bgp 65001
+ no bgp ebgp-requires-policy
+ neighbor 192.168.255.1 remote-as 65000
+ neighbor 192.168.255.1 timers 3 10
+ exit-address-family
+!
--- /dev/null
+!
+interface r2-eth0
+ ip address 192.168.255.2/24
+!
+ip forwarding
+!
--- /dev/null
+#!/usr/bin/env python
+
+#
+# bgp_tcp_mss.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2021 by
+# Abhinay Ramesh <rabhinay@vmware.com>
+#
+# 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.
+#
+
+"""
+bgp_tcp_mss.py:
+
+Test if works the following commands:
+router bgp 65000
+ neighbor 192.168.255.2 tcp-mss 500
+
+Need to verify if the tcp-mss value is reflected in the TCP session.
+"""
+
+import os
+import sys
+import json
+import time
+import pytest
+import functools
+
+# add after imports, before defining classes or functions:
+pytestmark = [pytest.mark.bgpd]
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+from mininet.topo import Topo
+
+
+class TemplateTopo(Topo):
+ def build(self, *_args, **_opts):
+ tgen = get_topogen(self)
+
+ for routern in range(1, 3):
+ tgen.add_router("r{}".format(routern))
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+
+def setup_module(mod):
+ tgen = Topogen(TemplateTopo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for i, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_tcp_mss():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+
+ def _bgp_converge(router):
+ output = json.loads(router.vtysh_cmd("show ip bgp neighbor 192.168.255.2 json"))
+ expected = {
+ "192.168.255.2": {
+ "bgpState": "Established",
+ "addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 0}},
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ def _bgp_conf_tcp_mss(router, as_num, neigh):
+ router.vtysh_cmd(
+ """configure terminal
+ router bgp {0}
+ neighbor {1} tcp-mss 500""".format(
+ as_num, neigh
+ )
+ )
+
+ def _bgp_clear_session(router):
+ router.vtysh_cmd("clear bgp *")
+
+ def _bgp_check_neighbor_tcp_mss(router, neigh):
+ output = json.loads(router.vtysh_cmd("show bgp neighbor {} json".format(neigh)))
+ expected = {
+ "{}".format(neigh): {"bgpTcpMssConfigured": 500, "bgpTcpMssSynced": 488}
+ }
+ return topotest.json_cmp(output, expected)
+
+ logger.info("Check if neighbor sessions are up in {}".format(router1.name))
+ test_func = functools.partial(_bgp_converge, router1)
+ success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5)
+ assert result is None, 'Failed to see BGP convergence in "{}"'.format(router1.name)
+
+ logger.info("BGP neighbor session is up in {}".format(router1.name))
+
+ logger.info(
+ "Configure tcp-mss 500 on {} and reset the session".format(router1.name)
+ )
+ _bgp_conf_tcp_mss(router1, "65000", "192.168.255.2")
+ _bgp_clear_session(router1)
+
+ logger.info(
+ "Configure tcp-mss 500 on {} and reset the session".format(router2.name)
+ )
+ _bgp_conf_tcp_mss(router2, "65001", "192.168.255.1")
+ _bgp_clear_session(router2)
+
+ logger.info(
+ "Check if neighbor session is up after reset in {}".format(router1.name)
+ )
+ test_func = functools.partial(_bgp_converge, router1)
+ success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5)
+ assert result is None, 'Failed to see BGP convergence after reset in "{}"'.format(
+ router1.name
+ )
+
+ logger.info(
+ "Verify if TCP MSS value is synced with neighbor in {}".format(router1.name)
+ )
+ test_func = functools.partial(_bgp_check_neighbor_tcp_mss, router1, "192.168.255.2")
+ success, result = topotest.run_and_expect(test_func, None, count=3, wait=0.5)
+ assert (
+ result is None
+ ), 'Failed to sync TCP MSS value over BGP session in "{}"'.format(router1.name)
+ logger.info("TCP MSS value is synced with neighbor in {}".format(router1.name))
+
+ logger.info(
+ "Verify if TCP MSS value is synced with neighbor in {}".format(router2.name)
+ )
+ test_func = functools.partial(_bgp_check_neighbor_tcp_mss, router2, "192.168.255.1")
+ success, result = topotest.run_and_expect(test_func, None, count=3, wait=0.5)
+ assert (
+ result is None
+ ), 'Failed to sync TCP MSS value over BGP session in "{}"'.format(router2.name)
+ logger.info("TCP MSS value is synced with neighbor in {}".format(router2.name))
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
"""
+ tc_name = request.node.name
logger.info("Remove prefer-global rmap applied on neighbors")
input_dict = {
"r1": {
parser.addoption(
"--topology-only",
action="store_true",
+ default=False,
help="Only set up this topology, don't run tests",
)
circtable_test = {
- "isisCircAdminState": ["on(1)", "on(1)", "on(1)"],
- "isisCircExistState": ["active(1)", "active(1)", "active(1)"],
- "isisCircType": ["broadcast(1)", "ptToPt(2)", "staticIn(3)"],
- "isisCircExtDomain": ["false(2)", "false(2)", "false(2)"],
- "isisCircLevelType": ["level1(1)", "level1(1)", "level1and2(3)"],
- "isisCircPassiveCircuit": ["false(2)", "false(2)", "true(1)"],
- "isisCircMeshGroupEnabled": ["inactive(1)", "inactive(1)", "inactive(1)"],
- "isisCircSmallHellos": ["false(2)", "false(2)", "false(2)"],
- "isisCirc3WayEnabled": ["false(2)", "false(2)", "false(2)"],
+ "isisCircAdminState": ["on(1)", "on(1)"],
+ "isisCircExistState": ["active(1)", "active(1)"],
+ "isisCircType": ["broadcast(1)", "ptToPt(2)"],
+ "isisCircExtDomain": ["false(2)", "false(2)"],
+ "isisCircLevelType": ["level1(1)", "level1(1)"],
+ "isisCircPassiveCircuit": ["false(2)", "false(2)"],
+ "isisCircMeshGroupEnabled": ["inactive(1)", "inactive(1)"],
+ "isisCircSmallHellos": ["false(2)", "false(2)"],
+ "isisCirc3WayEnabled": ["false(2)", "false(2)"],
}
oids = []
oids.append(generate_oid(1, 1, 0))
oids.append(generate_oid(1, 2, 0))
- oids.append(generate_oid(1, 3, 0))
# check items
for item in circtable_test.keys():
circleveltable_test = {
- "isisCircLevelMetric": ["10", "10", "10", "10"],
- "isisCircLevelWideMetric": ["10", "10", "0", "0"],
- "isisCircLevelISPriority": ["64", "64", "64", "64"],
- "isisCircLevelHelloMultiplier": ["10", "10", "10", "10"],
+ "isisCircLevelMetric": ["10", "10"],
+ "isisCircLevelWideMetric": ["10", "10"],
+ "isisCircLevelISPriority": ["64", "64"],
+ "isisCircLevelHelloMultiplier": ["10", "10"],
"isisCircLevelHelloTimer": [
"3000 milliseconds",
"3000 milliseconds",
- "3000 milliseconds",
- "3000 milliseconds",
],
"isisCircLevelMinLSPRetransInt": [
"1 seconds",
"1 seconds",
- "0 seconds",
- "0 seconds",
],
}
oids = []
oids.append(generate_oid(2, 1, "area"))
oids.append(generate_oid(2, 2, "area"))
- oids.append(generate_oid(2, 3, "area"))
- oids.append(generate_oid(2, 3, "domain"))
# check items
for item in circleveltable_test.keys():
tgen.net["rt4"].cmd(
'vtysh -c "conf t" -c "interface eth-rt5" -c "ipv6 router isis 1"'
)
+ tgen.net["rt4"].cmd(
+ 'vtysh -c "conf t" -c "interface eth-rt5" -c "isis network point-to-point"'
+ )
+ tgen.net["rt4"].cmd(
+ 'vtysh -c "conf t" -c "interface eth-rt5" -c "isis hello-multiplier 3"'
+ )
tgen.net["rt6"].cmd(
'vtysh -c "conf t" -c "router isis 1" -c "segment-routing global-block 16000 23999"'
)
"vertex": "r1"
},
{
- "metric": "internal",
- "parent": "0",
- "type": "IP",
+ "metric": "0",
+ "parent": "r1(4)",
+ "type": "IP internal",
"vertex": "10.0.20.0/24"
},
{
"vertex": "r3"
},
{
- "interface": "r3",
- "metric": "TE",
- "next-hop": "10",
- "parent": "r1-eth0",
- "type": "IP",
+ "interface": "r1-eth0",
+ "metric": "10",
+ "next-hop": "r3",
+ "parent": "r3(4)",
+ "type": "IP TE",
"vertex": "10.0.10.0/24"
},
{
- "interface": "r3",
- "metric": "TE",
- "next-hop": "10",
- "parent": "r1-eth0",
- "type": "IP",
+ "interface": "r1-eth0",
+ "metric": "10",
+ "next-hop": "r3",
+ "parent": "r3(4)",
+ "type": "IP TE",
"vertex": "10.0.20.0/24"
},
{
- "interface": "r3",
- "metric": "TE",
- "next-hop": "10",
- "parent": "r1-eth0",
- "type": "IP",
+ "interface": "r1-eth0",
+ "metric": "10",
+ "next-hop": "r3",
+ "parent": "r3(4)",
+ "type": "IP TE",
"vertex": "10.254.0.3/32"
}
],
"vertex": "r1"
},
{
- "metric": "internal",
- "parent": "0",
- "type": "IP6",
+ "metric": "0",
+ "parent": "r1(4)",
+ "type": "IP6 internal",
"vertex": "2001:db8:1:1::/64"
},
{
"vertex": "r3"
},
{
- "interface": "r3",
- "next-hop": "10",
- "parent": "r1-eth0",
- "type": "IP6",
+ "metric": "10",
+ "interface": "r1-eth0",
+ "next-hop": "r3",
+ "parent": "r3(4)",
+ "type": "IP6 internal",
"vertex": "2001:db8:2:1::/64"
},
{
- "interface": "r3",
- "next-hop": "10",
- "parent": "r1-eth0",
- "type": "IP6",
+ "metric": "10",
+ "interface": "r1-eth0",
+ "next-hop": "r3",
+ "parent": "r3(4)",
+ "type": "IP6 internal",
"vertex": "2001:db8:f::3/128"
}
]
"vertex": "r2"
},
{
- "metric": "internal",
- "parent": "0",
- "type": "IP",
+ "metric": "0",
+ "parent": "r2(4)",
+ "type": "IP internal",
"vertex": "10.0.21.0/24"
},
{
"vertex": "r4"
},
{
- "interface": "r4",
- "metric": "TE",
- "next-hop": "10",
- "parent": "r2-eth0",
- "type": "IP",
+ "interface": "r2-eth0",
+ "metric": "10",
+ "next-hop": "r4",
+ "parent": "r4(4)",
+ "type": "IP TE",
"vertex": "10.0.11.0/24"
},
{
- "interface": "r4",
- "metric": "TE",
- "next-hop": "10",
- "parent": "r2-eth0",
- "type": "IP",
+ "interface": "r2-eth0",
+ "metric": "10",
+ "next-hop": "r4",
+ "parent": "r4(4)",
+ "type": "IP TE",
"vertex": "10.0.21.0/24"
},
{
- "interface": "r4",
- "metric": "TE",
- "next-hop": "10",
- "parent": "r2-eth0",
- "type": "IP",
+ "interface": "r2-eth0",
+ "metric": "10",
+ "next-hop": "r4",
+ "parent": "r4(4)",
+ "type": "IP TE",
"vertex": "10.254.0.4/32"
}
],
"vertex": "r2"
},
{
- "metric": "internal",
- "parent": "0",
- "type": "IP6",
+ "metric": "0",
+ "parent": "r2(4)",
+ "type": "IP6 internal",
"vertex": "2001:db8:1:2::/64"
},
{
"vertex": "r4"
},
{
- "interface": "r4",
- "next-hop": "10",
- "parent": "r2-eth0",
- "type": "IP6",
+ "metric": "10",
+ "interface": "r2-eth0",
+ "next-hop": "r4",
+ "parent": "r4(4)",
+ "type": "IP6 internal",
"vertex": "2001:db8:2:2::/64"
},
{
- "interface": "r4",
- "next-hop": "10",
- "parent": "r2-eth0",
- "type": "IP6",
+ "metric": "10",
+ "interface": "r2-eth0",
+ "next-hop": "r4",
+ "parent": "r4(4)",
+ "type": "IP6 internal",
"vertex": "2001:db8:f::4/128"
}
]
"vertex": "r3"
},
{
- "metric": "internal",
- "parent": "0",
- "type": "IP",
+ "metric": "0",
+ "parent": "r3(4)",
+ "type": "IP internal",
"vertex": "10.0.10.0/24"
},
{
"vertex": "r5"
},
{
- "interface": "r5",
- "metric": "TE",
- "next-hop": "10",
- "parent": "r3-eth1",
- "type": "IP",
+ "interface": "r3-eth1",
+ "metric": "10",
+ "next-hop": "r5",
+ "parent": "r5(4)",
+ "type": "IP TE",
"vertex": "10.0.10.0/24"
},
{
- "interface": "r5",
- "metric": "TE",
- "next-hop": "10",
- "parent": "r3-eth1",
- "type": "IP",
+ "interface": "r3-eth1",
+ "metric": "10",
+ "next-hop": "r5",
+ "parent": "r5(4)",
+ "type": "IP TE",
"vertex": "10.0.11.0/24"
},
{
- "interface": "r5",
- "metric": "TE",
- "next-hop": "10",
- "parent": "r3-eth1",
- "type": "IP",
+ "interface": "r3-eth1",
+ "metric": "10",
+ "next-hop": "r5",
+ "parent": "r5(4)",
+ "type": "IP TE",
"vertex": "10.254.0.5/32"
},
{
"vertex": "r4"
},
{
- "interface": "r5",
- "metric": "TE",
- "next-hop": "20",
- "parent": "r3-eth1",
- "type": "IP",
+ "interface": "r3-eth1",
+ "metric": "20",
+ "next-hop": "r5",
+ "parent": "r4(4)",
+ "type": "IP TE",
"vertex": "10.0.21.0/24"
},
{
- "interface": "r5",
- "metric": "TE",
- "next-hop": "20",
- "parent": "r3-eth1",
- "type": "IP",
+ "interface": "r3-eth1",
+ "metric": "20",
+ "next-hop": "r5",
+ "parent": "r4(4)",
+ "type": "IP TE",
"vertex": "10.254.0.4/32"
}
],
"vertex": "r3"
},
{
- "metric": "internal",
- "parent": "0",
- "type": "IP6",
+ "metric": "0",
+ "parent": "r3(4)",
+ "type": "IP6 internal",
"vertex": "2001:db8:2:1::/64"
},
{
"vertex": "r5"
},
{
- "interface": "r5",
- "next-hop": "10",
- "parent": "r3-eth1",
- "type": "IP6",
+ "metric": "10",
+ "interface": "r3-eth1",
+ "next-hop": "r5",
+ "parent": "r5(4)",
+ "type": "IP6 internal",
"vertex": "2001:db8:2:2::/64"
},
{
- "interface": "r5",
- "next-hop": "10",
- "parent": "r3-eth1",
- "type": "IP6",
+ "metric": "10",
+ "interface": "r3-eth1",
+ "next-hop": "r5",
+ "parent": "r5(4)",
+ "type": "IP6 internal",
"vertex": "2001:db8:f::5/128"
},
{
"vertex": "r4"
},
{
- "interface": "r5",
- "next-hop": "20",
- "parent": "r3-eth1",
- "type": "IP6",
+ "metric": "20",
+ "interface": "r3-eth1",
+ "next-hop": "r5",
+ "parent": "r4(4)",
+ "type": "IP6 internal",
"vertex": "2001:db8:1:2::/64"
},
{
- "interface": "r5",
- "next-hop": "20",
- "parent": "r3-eth1",
- "type": "IP6",
+ "metric": "20",
+ "interface": "r3-eth1",
+ "next-hop": "r5",
+ "parent": "r4(4)",
+ "type": "IP6 internal",
"vertex": "2001:db8:f::4/128"
}
]
"vertex": "r3"
},
{
- "metric": "internal",
- "parent": "0",
- "type": "IP",
+ "metric": "0",
+ "parent": "r3(4)",
+ "type": "IP internal",
"vertex": "10.0.20.0/24"
},
{
"vertex": "r1"
},
{
- "interface": "r1",
- "metric": "TE",
- "next-hop": "10",
- "parent": "r3-eth0",
- "type": "IP",
+ "interface": "r3-eth0",
+ "metric": "10",
+ "next-hop": "r1",
+ "parent": "r1(4)",
+ "type": "IP TE",
"vertex": "10.0.20.0/24"
},
{
- "interface": "r1",
- "metric": "TE",
- "next-hop": "10",
- "parent": "r3-eth0",
- "type": "IP",
+ "interface": "r3-eth0",
+ "metric": "10",
+ "next-hop": "r1",
+ "parent": "r1(4)",
+ "type": "IP TE",
"vertex": "10.254.0.1/32"
}
],
"vertex": "r3"
},
{
- "metric": "internal",
- "parent": "0",
- "type": "IP6",
+ "metric": "0",
+ "parent": "r3(4)",
+ "type": "IP6 internal",
"vertex": "2001:db8:1:1::/64"
},
{
"vertex": "r1"
},
{
- "interface": "r1",
- "next-hop": "10",
- "parent": "r3-eth0",
- "type": "IP6",
+ "metric": "10",
+ "interface": "r3-eth0",
+ "next-hop": "r1",
+ "parent": "r1(4)",
+ "type": "IP6 internal",
"vertex": "2001:db8:f::1/128"
}
]
"vertex": "r4"
},
{
- "metric": "internal",
- "parent": "0",
- "type": "IP",
+ "metric": "0",
+ "parent": "r4(4)",
+ "type": "IP internal",
"vertex": "10.0.11.0/24"
},
{
"vertex": "r5"
},
{
- "interface": "r5",
- "metric": "TE",
- "next-hop": "10",
- "parent": "r4-eth1",
- "type": "IP",
+ "interface": "r4-eth1",
+ "metric": "10",
+ "next-hop": "r5",
+ "parent": "r5(4)",
+ "type": "IP TE",
"vertex": "10.0.10.0/24"
},
{
- "interface": "r5",
- "metric": "TE",
- "next-hop": "10",
- "parent": "r4-eth1",
- "type": "IP",
+ "interface": "r4-eth1",
+ "metric": "10",
+ "next-hop": "r5",
+ "parent": "r5(4)",
+ "type": "IP TE",
"vertex": "10.0.11.0/24"
},
{
- "interface": "r5",
- "metric": "TE",
- "next-hop": "10",
- "parent": "r4-eth1",
- "type": "IP",
+ "interface": "r4-eth1",
+ "metric": "10",
+ "next-hop": "r5",
+ "parent": "r5(4)",
+ "type": "IP TE",
"vertex": "10.254.0.5/32"
},
{
"vertex": "r3"
},
{
- "interface": "r5",
- "metric": "TE",
- "next-hop": "20",
- "parent": "r4-eth1",
- "type": "IP",
+ "interface": "r4-eth1",
+ "metric": "20",
+ "next-hop": "r5",
+ "parent": "r3(4)",
+ "type": "IP TE",
"vertex": "10.0.20.0/24"
},
{
- "interface": "r5",
- "metric": "TE",
- "next-hop": "20",
- "parent": "r4-eth1",
- "type": "IP",
+ "interface": "r4-eth1",
+ "metric": "20",
+ "next-hop": "r5",
+ "parent": "r3(4)",
+ "type": "IP TE",
"vertex": "10.254.0.3/32"
}
],
"vertex": "r4"
},
{
- "metric": "internal",
- "parent": "0",
- "type": "IP6",
+ "metric": "0",
+ "parent": "r4(4)",
+ "type": "IP6 internal",
"vertex": "2001:db8:2:2::/64"
},
{
"vertex": "r5"
},
{
- "interface": "r5",
- "next-hop": "10",
- "parent": "r4-eth1",
- "type": "IP6",
+ "metric": "10",
+ "interface": "r4-eth1",
+ "next-hop": "r5",
+ "parent": "r5(4)",
+ "type": "IP6 internal",
"vertex": "2001:db8:2:1::/64"
},
{
- "interface": "r5",
- "next-hop": "10",
- "parent": "r4-eth1",
- "type": "IP6",
+ "metric": "10",
+ "interface": "r4-eth1",
+ "next-hop": "r5",
+ "parent": "r5(4)",
+ "type": "IP6 internal",
"vertex": "2001:db8:f::5/128"
},
{
"vertex": "r3"
},
{
- "interface": "r5",
- "next-hop": "20",
- "parent": "r4-eth1",
- "type": "IP6",
+ "metric": "20",
+ "interface": "r4-eth1",
+ "next-hop": "r5",
+ "parent": "r3(4)",
+ "type": "IP6 internal",
"vertex": "2001:db8:1:1::/64"
},
{
- "interface": "r5",
- "next-hop": "20",
- "parent": "r4-eth1",
- "type": "IP6",
+ "metric": "20",
+ "interface": "r4-eth1",
+ "next-hop": "r5",
+ "parent": "r3(4)",
+ "type": "IP6 internal",
"vertex": "2001:db8:f::3/128"
}
]
"vertex": "r4"
},
{
- "metric": "internal",
- "parent": "0",
- "type": "IP",
+ "metric": "0",
+ "parent": "r4(4)",
+ "type": "IP internal",
"vertex": "10.0.21.0/24"
},
{
"vertex": "r2"
},
{
- "interface": "r2",
- "metric": "TE",
- "next-hop": "10",
- "parent": "r4-eth0",
- "type": "IP",
+ "interface": "r4-eth0",
+ "metric": "10",
+ "next-hop": "r2",
+ "parent": "r2(4)",
+ "type": "IP TE",
"vertex": "10.0.21.0/24"
},
{
- "interface": "r2",
- "metric": "TE",
- "next-hop": "10",
- "parent": "r4-eth0",
- "type": "IP",
+ "interface": "r4-eth0",
+ "metric": "10",
+ "next-hop": "r2",
+ "parent": "r2(4)",
+ "type": "IP TE",
"vertex": "10.254.0.2/32"
}
],
"vertex": "r4"
},
{
- "metric": "internal",
- "parent": "0",
- "type": "IP6",
+ "metric": "0",
+ "parent": "r4(4)",
+ "type": "IP6 internal",
"vertex": "2001:db8:1:2::/64"
},
{
"vertex": "r2"
},
{
- "interface": "r2",
- "next-hop": "10",
- "parent": "r4-eth0",
- "type": "IP6",
+ "metric": "10",
+ "interface": "r4-eth0",
+ "next-hop": "r2",
+ "parent": "r2(4)",
+ "type": "IP6 internal",
"vertex": "2001:db8:f::2/128"
}
]
"vertex": "r5"
},
{
- "metric": "internal",
- "parent": "0",
- "type": "IP",
+ "metric": "0",
+ "parent": "r5(4)",
+ "type": "IP internal",
"vertex": "10.0.10.0/24"
},
{
- "metric": "internal",
- "parent": "0",
- "type": "IP",
+ "metric": "0",
+ "parent": "r5(4)",
+ "type": "IP internal",
"vertex": "10.0.11.0/24"
},
{
"vertex": "r4"
},
{
- "interface": "r3",
- "metric": "TE",
- "next-hop": "10",
- "parent": "r5-eth0",
- "type": "IP",
+ "interface": "r5-eth0",
+ "metric": "10",
+ "next-hop": "r3",
+ "parent": "r3(4)",
+ "type": "IP TE",
"vertex": "10.0.10.0/24"
},
{
- "interface": "r3",
- "metric": "TE",
- "next-hop": "10",
- "parent": "r5-eth0",
- "type": "IP",
+ "interface": "r5-eth0",
+ "metric": "10",
+ "next-hop": "r3",
+ "parent": "r3(4)",
+ "type": "IP TE",
"vertex": "10.0.20.0/24"
},
{
- "interface": "r3",
- "metric": "TE",
- "next-hop": "10",
- "parent": "r5-eth0",
- "type": "IP",
+ "interface": "r5-eth0",
+ "metric": "10",
+ "next-hop": "r3",
+ "parent": "r3(4)",
+ "type": "IP TE",
"vertex": "10.254.0.3/32"
},
{
- "interface": "r4",
- "metric": "TE",
- "next-hop": "10",
- "parent": "r5-eth1",
- "type": "IP",
+ "interface": "r5-eth1",
+ "metric": "10",
+ "next-hop": "r4",
+ "parent": "r4(4)",
+ "type": "IP TE",
"vertex": "10.0.11.0/24"
},
{
- "interface": "r4",
- "metric": "TE",
- "next-hop": "10",
- "parent": "r5-eth1",
- "type": "IP",
+ "interface": "r5-eth1",
+ "metric": "10",
+ "next-hop": "r4",
+ "parent": "r4(4)",
+ "type": "IP TE",
"vertex": "10.0.21.0/24"
},
{
- "interface": "r4",
- "metric": "TE",
- "next-hop": "10",
- "parent": "r5-eth1",
- "type": "IP",
+ "interface": "r5-eth1",
+ "metric": "10",
+ "next-hop": "r4",
+ "parent": "r4(4)",
+ "type": "IP TE",
"vertex": "10.254.0.4/32"
}
],
"vertex": "r5"
},
{
- "metric": "internal",
- "parent": "0",
- "type": "IP6",
+ "metric": "0",
+ "parent": "r5(4)",
+ "type": "IP6 internal",
"vertex": "2001:db8:2:1::/64"
},
{
- "metric": "internal",
- "parent": "0",
- "type": "IP6",
+ "metric": "0",
+ "parent": "r5(4)",
+ "type": "IP6 internal",
"vertex": "2001:db8:2:2::/64"
},
{
"vertex": "r4"
},
{
- "interface": "r3",
- "next-hop": "10",
- "parent": "r5-eth0",
- "type": "IP6",
+ "metric": "10",
+ "interface": "r5-eth0",
+ "next-hop": "r3",
+ "parent": "r3(4)",
+ "type": "IP6 internal",
"vertex": "2001:db8:1:1::/64"
},
{
- "interface": "r3",
- "next-hop": "10",
- "parent": "r5-eth0",
- "type": "IP6",
+ "metric": "10",
+ "interface": "r5-eth0",
+ "next-hop": "r3",
+ "parent": "r3(4)",
+ "type": "IP6 internal",
"vertex": "2001:db8:f::3/128"
},
{
- "interface": "r4",
- "next-hop": "10",
- "parent": "r5-eth1",
- "type": "IP6",
+ "metric": "10",
+ "interface": "r5-eth1",
+ "next-hop": "r4",
+ "parent": "r4(4)",
+ "type": "IP6 internal",
"vertex": "2001:db8:1:2::/64"
},
{
- "interface": "r4",
- "next-hop": "10",
- "parent": "r5-eth1",
- "type": "IP6",
+ "metric": "10",
+ "interface": "r5-eth1",
+ "next-hop": "r4",
+ "parent": "r4(4)",
+ "type": "IP6 internal",
"vertex": "2001:db8:f::4/128"
}
]
pytestmark = [pytest.mark.isisd]
+VERTEX_TYPE_LIST = [
+ "pseudo_IS",
+ "pseudo_TE-IS",
+ "IS",
+ "TE-IS",
+ "ES",
+ "IP internal",
+ "IP external",
+ "IP TE",
+ "IP6 internal",
+ "IP6 external",
+ "UNKNOWN",
+]
+
class ISISTopo1(Topo):
"Simple two layer ISIS topology"
areas = {}
area = None
ipv = None
+ vertex_type_regex = "|".join(VERTEX_TYPE_LIST)
for line in lines:
area_match = re.match(r"Area (.+):", line)
ipv = "ipv4"
continue
- item_match = re.match(r"([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+)", line)
- if item_match is not None:
+ item_match = re.match(
+ r"([^\s]+) ([^\s]+) ([^\s]+) ([^\s]+) ([^\s]+) ([^\s]+)", line
+ )
+ if (
+ item_match is not None
+ and item_match.group(1) == "Vertex"
+ and item_match.group(2) == "Type"
+ and item_match.group(3) == "Metric"
+ and item_match.group(4) == "Next-Hop"
+ and item_match.group(5) == "Interface"
+ and item_match.group(6) == "Parent"
+ ):
# Skip header
- if (
- item_match.group(1) == "Vertex"
- and item_match.group(2) == "Type"
- and item_match.group(3) == "Metric"
- and item_match.group(4) == "Next-Hop"
- and item_match.group(5) == "Interface"
- and item_match.group(6) == "Parent"
- ):
- continue
+ continue
+ item_match = re.match(
+ r"([^\s]+) ({}) ([0]|([1-9][0-9]*)) ([^\s]+) ([^\s]+) ([^\s]+)".format(
+ vertex_type_regex
+ ),
+ line,
+ )
+ if item_match is not None:
areas[area][level][ipv].append(
{
"vertex": item_match.group(1),
"type": item_match.group(2),
"metric": item_match.group(3),
- "next-hop": item_match.group(4),
- "interface": item_match.group(5),
- "parent": item_match.group(6),
+ "next-hop": item_match.group(5),
+ "interface": item_match.group(6),
+ "parent": item_match.group(7),
}
)
continue
- item_match = re.match(r"([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+)", line)
+ item_match = re.match(
+ r"([^\s]+) ({}) ([0]|([1-9][0-9]*)) ([^\s]+)".format(vertex_type_regex),
+ line,
+ )
+
if item_match is not None:
areas[area][level][ipv].append(
{
"vertex": item_match.group(1),
"type": item_match.group(2),
"metric": item_match.group(3),
- "parent": item_match.group(4),
+ "parent": item_match.group(5),
}
)
continue
- item_match = re.match(r"([^ ]+)", line)
+ item_match = re.match(r"([^\s]+)", line)
if item_match is not None:
areas[area][level][ipv].append({"vertex": item_match.group(1)})
continue
{
"r3-eth1":{
"ldpIgpSyncEnabled":false,
- "holdDownTimeInSec":50,
+ "holdDownTimeInSec":0,
"ldpIgpSyncState":"Sync not required"
},
"r3-eth2":{
{
"r3-eth1":{
"ldpIgpSyncEnabled":false,
- "holdDownTimeInSec":50,
+ "holdDownTimeInSec":0,
"ldpIgpSyncState":"Sync not required"
},
"r3-eth2":{
{
"r3-eth1":{
"ldpIgpSyncEnabled":false,
- "holdDownTimeInSec":50,
+ "holdDownTimeInSec":0,
"ldpIgpSyncState":"Sync not required"
},
"r3-eth2":{
command = "show bgp"
- sleep(5)
for net in network:
if vrf:
cmd = "{} vrf {} {} {} json".format(command, vrf, addr_type, net)
return res
-def kill_mininet_routers_process(tgen):
- """
- Kill all mininet stale router' processes
- * `tgen` : topogen object
- """
-
- router_list = tgen.routers()
- for rname, router in router_list.items():
- daemon_list = [
- "zebra",
- "ospfd",
- "ospf6d",
- "bgpd",
- "ripd",
- "ripngd",
- "isisd",
- "pimd",
- "ldpd",
- "staticd",
- ]
- for daemon in daemon_list:
- router.run("killall -9 {}".format(daemon))
-
-
def check_router_status(tgen):
"""
Check if all daemons are running for all routers in topology
return result
-def add_rp_interfaces_and_pim_config(tgen, topo, interface, rp, rp_mapping):
- """
- Add physical interfaces tp RP for all the RPs
-
- Parameters
- ----------
- * `tgen` : Topogen object
- * `topo` : json file data
- * `interface` : RP interface
- * `rp` : rp for given topology
- * `rp_mapping` : dictionary of all groups and RPs
-
- Returns
- -------
- True or False
- """
- result = False
- logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
-
- try:
- config_data = []
-
- for group, rp_list in rp_mapping.items():
- for _rp in rp_list:
- config_data.append("interface {}".format(interface))
- config_data.append("ip address {}".format(_rp))
- config_data.append("ip pim")
-
- result = create_common_configuration(
- tgen, rp, config_data, "interface_config"
- )
- if result is not True:
- return False
-
- except InvalidCLIError:
- # Traceback
- errormsg = traceback.format_exc()
- logger.error(errormsg)
- return errormsg
-
- logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
- return result
-
-
def find_rp_details(tgen, topo):
"""
Find who is RP in topology and returns list of RPs
errormsg = (
"[DUT %s]: Verifying pim state for group"
" %s, [FAILED]!! Expected: "
- "(iif: %s, oil: %s, installed: %s) ",
+ "(iif: %s, oil: %s, installed: %s) "
+ % (dut, grp_addr, iif, oil, "1"),
"Found: (iif: %s, oil: %s, installed: %s)"
% (
- dut,
- grp_addr,
- iif,
- oil,
- "1",
data["inboundInterface"],
data["outboundInterface"],
data["installed"],
logger.error(errormsg)
return errormsg
- logger.debug("Exiting lib API: add_rp_interfaces_and_pim_config()")
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return result
if rp is None:
rp_details = find_rp_details(tgen, topo)
else:
- rp_details = {dut: ip}
- rp_details[dut] = rp
+ rp_details = {dut: rp}
if dut in rp_details:
pim_nh_intf_ip = topo["routers"][dut]["links"]["lo"]["ipv4"].split(
if statistics and report:
show_ip_igmp_intf_json = run_frr_cmd(
- rnode, "{} json".format(cmd, interface), isjson=True
+ rnode, "{} json".format(cmd), isjson=True
)
intf_detail_json = show_ip_igmp_intf_json["global"]
else:
dut,
interface,
value,
- intf_detail_json["reportV2"],
)
)
return errormsg
func_name = func.__name__
logger.info(
- "'{}' polling started (interval {} secs, maximum wait {} secs)".format(
- func_name, wait, int(wait * count)
+ "'{}' polling started (interval {} secs, maximum {} tries)".format(
+ func_name, wait, count
)
)
--- /dev/null
+# OSPFv3 (IPv6) Topology Test
+
+## Topology
+ -----\
+ SW1 - Stub Net 1 SW2 - Stub Net 2 \
+ fc00:1:1:1::/64 fc00:2:2:2::/64 \
+ \___________________/ \___________________/ |
+ | | |
+ | | |
+ | ::1 | ::2 |
+ +---------+---------+ +---------+---------+ |
+ | R1 | | R2 | |
+ | FRRouting | | FRRouting | |
+ | Rtr-ID: 10.0.0.1 | | Rtr-ID: 10.0.0.2 | |
+ +---------+---------+ +---------+---------+ |
+ | ::1 | ::2 \
+ \______ ___________/ OSPFv3
+ \ / Area 0.0.0.0
+ \ / /
+ ~~~~~~~~~~~~~~~~~~ |
+ ~~ SW5 ~~ |
+ ~~ Switch ~~ |
+ ~~ fc00:A:A:A::/64 ~~ |
+ ~~~~~~~~~~~~~~~~~~ |
+ | /---- |
+ | ::3 | SW3 - Stub Net 3 |
+ +---------+---------+ /-+ fc00:3:3:3::/64 |
+ | R3 | / | /
+ | FRRouting +--/ \---- /
+ | Rtr-ID: 10.0.0.3 | ::3 ___________/
+ +---------+---------+ \
+ | ::3 \
+ | \
+ ~~~~~~~~~~~~~~~~~~ |
+ ~~ SW6 ~~ |
+ ~~ Switch ~~ |
+ ~~ fc00:B:B:B::/64 ~~ \
+ ~~~~~~~~~~~~~~~~~~ OSPFv3
+ | Area 0.0.0.1
+ | ::4 /
+ +---------+---------+ /---- |
+ | R4 | | SW4 - Stub Net 4 |
+ | FRRouting +------+ fc00:4:4:4::/64 |
+ | Rtr-ID: 10.0.0.4 | ::4 | /
+ +-------------------+ \---- /
+ -----/
+
+## FRR Configuration
+
+Full config as used is in r1 / r2 / r3 / r4 / r5 subdirectories
+
+Simplified `R1` config (R1 is similar)
+
+ hostname r1
+ !
+ interface r1-stubnet vrf r1-cust1
+ ipv6 address fc00:1:1:1::1/64
+ ipv6 ospf6 network broadcast
+ !
+ interface r1-sw5 vrf r1-cust1
+ ipv6 address fc00:a:a:a::1/64
+ ipv6 ospf6 network broadcast
+ !
+ router ospf6 vrf r1-cust1
+ router-id 10.0.0.1
+ log-adjacency-changes detail
+ redistribute static
+ interface r1-stubnet area 0.0.0.0
+ interface r1-sw5 area 0.0.0.0
+ !
+ ipv6 route fc00:1111:1111:1111::/64 fc00:1:1:1::1234 vrf r1-cust1
+
+Simplified `R3` config
+
+ hostname r3
+ !
+ interface r3-stubnet vrf r3-cust1
+ ipv6 address fc00:3:3:3::3/64
+ ipv6 ospf6 network broadcast
+ !
+ interface r3-sw5 vrf r3-cust1
+ ipv6 address fc00:a:a:a::3/64
+ ipv6 ospf6 network broadcast
+ !
+ interface r3-sw6 vrf r3-cust1
+ ipv6 address fc00:b:b:b::3/64
+ ipv6 ospf6 network broadcast
+ !
+ router ospf6 vrf r3-cust1
+ router-id 10.0.0.3
+ log-adjacency-changes detail
+ redistribute static
+ interface r3-stubnet area 0.0.0.0
+ interface r3-sw5 area 0.0.0.0
+ interface r3-sw6 area 0.0.0.1
+ !
+ ipv6 route fc00:3333:3333:3333::/64 fc00:3:3:3::1234 vrf r3-cust1
+
+## Tests executed
+
+### Check if FRR is running
+
+Test is executed by running
+
+ vtysh -c "show logging" | grep "Logging configuration for"
+
+on each FRR router. This should return the logging information for all daemons registered
+to Zebra and the list of running daemons is compared to the daemons started for this test (`zebra` and `ospf6d`)
+
+### Verify for OSPFv3 to converge
+
+OSPFv3 is expected to converge on each view within 60s total time. Convergence is verified by executing (on each node)
+
+ vtysh -c "show ipv6 ospf vrf r1-cust1 neigh"
+
+and checking for "Full" neighbor status in the output. An additional 15 seconds after the full converge is waited for routes to populate before the following routing table checks are executed
+
+### Verifying OSPFv3 Routing Tables
+
+Routing table is verified by running
+
+ vtysh -c "show ipv6 route vrf r1-cust1"
+
+on each node and comparing the result to the stored example config (see `show_ipv6_route.ref` in r1 / r2 / r3 / r4 directories). Link-Local addresses are masked out before the compare.
+
+### Verifying Linux Kernel Routing Table
+
+Linux Kernel IPv6 Routing table is verified on each FRR node with
+
+ ip -6 route vrf r1-cust1
+
+Tables are compared with reference routing table (see `ip_6_address.ref` in r1 / r2 / r3 / r4 directories). Link-Local addresses are translated after getting collected on each node with interface name to make them consistent
--- /dev/null
+fc00:1111:1111:1111::/64 nhid XXXX via fc00:1:1:1::1234 dev r1-stubnet proto XXXX metric 20 pref medium
+fc00:1:1:1::/64 dev r1-stubnet proto XXXX metric 256 pref medium
+fc00:2222:2222:2222::/64 nhid XXXX via fe80::__(r2-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
+fc00:2:2:2::/64 nhid XXXX via fe80::__(r2-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
+fc00:3333:3333:3333::/64 nhid XXXX via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
+fc00:3:3:3::/64 nhid XXXX via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
+fc00:4444:4444:4444::/64 nhid XXXX via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
+fc00:4:4:4::/64 nhid XXXX via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
+fc00:a:a:a::/64 dev r1-sw5 proto XXXX metric 256 pref medium
+fc00:b:b:b::/64 nhid XXXX via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
--- /dev/null
+fc00:1111:1111:1111::/64 via fc00:1:1:1::1234 dev r1-stubnet proto XXXX metric 20 pref medium\r
+fc00:1:1:1::/64 dev r1-stubnet proto XXXX metric 256 pref medium\r
+fc00:2222:2222:2222::/64 via fe80::__(r2-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium\r
+fc00:2:2:2::/64 via fe80::__(r2-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium\r
+fc00:3333:3333:3333::/64 via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium\r
+fc00:3:3:3::/64 via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium\r
+fc00:4444:4444:4444::/64 via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium\r
+fc00:4:4:4::/64 via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium\r
+fc00:a:a:a::/64 dev r1-sw5 proto XXXX metric 256 pref medium\r
+fc00:b:b:b::/64 via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium\r
--- /dev/null
+hostname r1
+log file ospf6d.log
+!
+debug ospf6 message all
+debug ospf6 lsa unknown
+debug ospf6 zebra
+debug ospf6 interface
+debug ospf6 neighbor
+debug ospf6 route table
+debug ospf6 flooding
+!
+interface r1-stubnet vrf r1-cust1
+ ipv6 ospf6 network broadcast
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 10
+!
+interface r1-sw5 vrf r1-cust1
+ ipv6 ospf6 network broadcast
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 10
+!
+router ospf6 vrf r1-cust1
+ ospf6 router-id 10.0.0.1
+ log-adjacency-changes detail
+ redistribute static
+ interface r1-stubnet area 0.0.0.0
+ interface r1-sw5 area 0.0.0.0
+!
+line vty
+ exec-timeout 0 0
+!
--- /dev/null
+O fc00:1:1:1::/64 [110/10] is directly connected, r1-stubnet, weight 1, XX:XX:XX
+O>* fc00:2:2:2::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
+O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
+O>* fc00:4:4:4::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
+O fc00:a:a:a::/64 [110/10] is directly connected, r1-sw5, weight 1, XX:XX:XX
+O>* fc00:b:b:b::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
+O>* fc00:2222:2222:2222::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
+O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
+O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
--- /dev/null
+!
+hostname r1
+log file zebra.log
+!
+debug zebra events
+debug zebra rib
+!
+interface r1-stubnet vrf r1-cust1
+ ipv6 address fc00:1:1:1::1/64
+!
+interface r1-sw5 vrf r1-cust1
+ ipv6 address fc00:a:a:a::1/64
+!
+interface lo
+!
+ipv6 route fc00:1111:1111:1111::/64 fc00:1:1:1::1234 vrf r1-cust1
+!
+!
+line vty
+!
--- /dev/null
+fc00:1111:1111:1111::/64 via fe80::__(r1-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium\r
+fc00:1:1:1::/64 via fe80::__(r1-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium\r
+fc00:2222:2222:2222::/64 via fc00:2:2:2::1234 dev r2-stubnet proto XXXX metric 20 pref medium\r
+fc00:2:2:2::/64 dev r2-stubnet proto XXXX metric 256 pref medium\r
+fc00:3333:3333:3333::/64 via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium\r
+fc00:3:3:3::/64 via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium\r
+fc00:4444:4444:4444::/64 via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium\r
+fc00:4:4:4::/64 via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium\r
+fc00:a:a:a::/64 dev r2-sw5 proto XXXX metric 256 pref medium\r
+fc00:b:b:b::/64 via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium\r
--- /dev/null
+hostname r2
+log file ospf6d.log
+!
+debug ospf6 message all
+debug ospf6 lsa unknown
+debug ospf6 zebra
+debug ospf6 interface
+debug ospf6 neighbor
+debug ospf6 route table
+debug ospf6 flooding
+!
+interface r2-stubnet vrf r2-cust1
+ ipv6 ospf6 network broadcast
+ ipv6 ospf6 dead-interval 10
+ ipv6 ospf6 hello-interval 2
+!
+interface r2-sw5 vrf r2-cust1
+ ipv6 ospf6 network broadcast
+ ipv6 ospf6 dead-interval 10
+ ipv6 ospf6 hello-interval 2
+!
+router ospf6 vrf r2-cust1
+ ospf6 router-id 10.0.0.2
+ log-adjacency-changes detail
+ redistribute static
+ interface r2-stubnet area 0.0.0.0
+ interface r2-sw5 area 0.0.0.0
+!
+line vty
+ exec-timeout 0 0
+!
--- /dev/null
+O>* fc00:1:1:1::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
+O fc00:2:2:2::/64 [110/10] is directly connected, r2-stubnet, weight 1, XX:XX:XX
+O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
+O>* fc00:4:4:4::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
+O fc00:a:a:a::/64 [110/10] is directly connected, r2-sw5, weight 1, XX:XX:XX
+O>* fc00:b:b:b::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
+O>* fc00:1111:1111:1111::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
+O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
+O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
--- /dev/null
+!
+hostname r2
+log file zebra.log
+!
+debug zebra events
+debug zebra rib
+!
+interface r2-stubnet vrf r2-cust1
+ ipv6 address fc00:2:2:2::2/64
+!
+interface r2-sw5 vrf r2-cust1
+ ipv6 address fc00:a:a:a::2/64
+!
+interface lo
+!
+ipv6 route fc00:2222:2222:2222::/64 fc00:2:2:2::1234 vrf r2-cust1
+!
+!
+line vty
+!
--- /dev/null
+fc00:1111:1111:1111::/64 via fe80::__(r1-sw5)__ dev r3-sw5 proto XXXX metric 20 pref medium\r
+fc00:1:1:1::/64 via fe80::__(r1-sw5)__ dev r3-sw5 proto XXXX metric 20 pref medium\r
+fc00:2222:2222:2222::/64 via fe80::__(r2-sw5)__ dev r3-sw5 proto XXXX metric 20 pref medium\r
+fc00:2:2:2::/64 via fe80::__(r2-sw5)__ dev r3-sw5 proto XXXX metric 20 pref medium\r
+fc00:3333:3333:3333::/64 via fc00:3:3:3::1234 dev r3-stubnet proto XXXX metric 20 pref medium\r
+fc00:3:3:3::/64 dev r3-stubnet proto XXXX metric 256 pref medium\r
+fc00:4444:4444:4444::/64 via fe80::__(r4-sw6)__ dev r3-sw6 proto XXXX metric 20 pref medium\r
+fc00:4:4:4::/64 via fe80::__(r4-sw6)__ dev r3-sw6 proto XXXX metric 20 pref medium\r
+fc00:a:a:a::/64 dev r3-sw5 proto XXXX metric 256 pref medium\r
+fc00:b:b:b::/64 dev r3-sw6 proto XXXX metric 256 pref medium\r
--- /dev/null
+hostname r3
+log file ospf6d.log
+!
+debug ospf6 message all
+debug ospf6 lsa unknown
+debug ospf6 zebra
+debug ospf6 interface
+debug ospf6 neighbor
+debug ospf6 route table
+debug ospf6 flooding
+!
+interface r3-stubnet vrf r3-cust1
+ ipv6 ospf6 network broadcast
+ ipv6 ospf6 dead-interval 10
+ ipv6 ospf6 hello-interval 2
+!
+interface r3-sw5 vrf r3-cust1
+ ipv6 ospf6 network broadcast
+ ipv6 ospf6 dead-interval 10
+ ipv6 ospf6 hello-interval 2
+!
+interface r3-sw6 vrf r3-cust1
+ ipv6 ospf6 network broadcast
+ ipv6 ospf6 dead-interval 10
+ ipv6 ospf6 hello-interval 2
+!
+router ospf6 vrf r3-cust1
+ ospf6 router-id 10.0.0.3
+ log-adjacency-changes detail
+ redistribute static
+ interface r3-stubnet area 0.0.0.0
+ interface r3-sw5 area 0.0.0.0
+ interface r3-sw6 area 0.0.0.1
+!
+line vty
+ exec-timeout 0 0
+!
--- /dev/null
+O>* fc00:1:1:1::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, weight 1, XX:XX:XX
+O>* fc00:2:2:2::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, weight 1, XX:XX:XX
+O fc00:3:3:3::/64 [110/10] is directly connected, r3-stubnet, weight 1, XX:XX:XX
+O>* fc00:4:4:4::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6, weight 1, XX:XX:XX
+O fc00:a:a:a::/64 [110/10] is directly connected, r3-sw5, weight 1, XX:XX:XX
+O fc00:b:b:b::/64 [110/10] is directly connected, r3-sw6, weight 1, XX:XX:XX
+O>* fc00:1111:1111:1111::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, weight 1, XX:XX:XX
+O>* fc00:2222:2222:2222::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, weight 1, XX:XX:XX
+O>* fc00:4444:4444:4444::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6, weight 1, XX:XX:XX
--- /dev/null
+!
+hostname r3
+log file zebra.log
+!
+debug zebra events
+debug zebra rib
+!
+interface r3-stubnet vrf r3-cust1
+ ipv6 address fc00:3:3:3::3/64
+!
+interface r3-sw5 vrf r3-cust1
+ ipv6 address fc00:a:a:a::3/64
+!
+interface r3-sw6 vrf r3-cust1
+ ipv6 address fc00:b:b:b::3/64
+!
+interface lo
+!
+ipv6 route fc00:3333:3333:3333::/64 fc00:3:3:3::1234 vrf r3-cust1
+!
+!
+line vty
+!
--- /dev/null
+fc00:1111:1111:1111::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium\r
+fc00:1:1:1::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium\r
+fc00:2222:2222:2222::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium\r
+fc00:2:2:2::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium\r
+fc00:3333:3333:3333::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium\r
+fc00:3:3:3::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium\r
+fc00:4444:4444:4444::/64 via fc00:4:4:4::1234 dev r4-stubnet proto XXXX metric 20 pref medium\r
+fc00:4:4:4::/64 dev r4-stubnet proto XXXX metric 256 pref medium\r
+fc00:a:a:a::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium\r
+fc00:b:b:b::/64 dev r4-sw6 proto XXXX metric 256 pref medium\r
--- /dev/null
+hostname r4
+log file ospf6d.log
+!
+debug ospf6 message all
+debug ospf6 lsa unknown
+debug ospf6 zebra
+debug ospf6 interface
+debug ospf6 neighbor
+debug ospf6 route table
+debug ospf6 flooding
+!
+interface r4-stubnet vrf r4-cust1
+ ipv6 ospf6 network broadcast
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 10
+!
+interface r4-sw6 vrf r4-cust1
+ ipv6 ospf6 network broadcast
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 10
+!
+router ospf6 vrf r4-cust1
+ ospf6 router-id 10.0.0.4
+ log-adjacency-changes detail
+ redistribute static
+ interface r4-stubnet area 0.0.0.1
+ interface r4-sw6 area 0.0.0.1
+!
+line vty
+ exec-timeout 0 0
+!
--- /dev/null
+O>* fc00:1:1:1::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
+O>* fc00:2:2:2::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
+O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
+O fc00:4:4:4::/64 [110/10] is directly connected, r4-stubnet, weight 1, XX:XX:XX
+O>* fc00:a:a:a::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
+O fc00:b:b:b::/64 [110/10] is directly connected, r4-sw6, weight 1, XX:XX:XX
+O>* fc00:1111:1111:1111::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
+O>* fc00:2222:2222:2222::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
+O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
--- /dev/null
+!
+hostname r4
+log file zebra.log
+!
+debug zebra events
+debug zebra rib
+!
+interface r4-stubnet vrf r4-cust1
+ ipv6 address fc00:4:4:4::4/64
+!
+interface r4-sw6 vrf r4-cust1
+ ipv6 address fc00:b:b:b::4/64
+!
+interface lo
+!
+ipv6 route fc00:4444:4444:4444::/64 fc00:4:4:4::1234 vrf r4-cust1
+!
+!
+line vty
+!
--- /dev/null
+#!/usr/bin/env python
+
+#
+# test_ospf6_topo1_vrf.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2021 by Niral Networks, Inc. ("Niral Networks")
+# Used Copyright (c) 2016 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# 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_ospf6_topo1_vrf.py:
+
+ -----\
+ SW1 - Stub Net 1 SW2 - Stub Net 2 \
+ fc00:1:1:1::/64 fc00:2:2:2::/64 \
+\___________________/ \___________________/ |
+ | | |
+ | | |
+ | ::1 | ::2 |
++---------+---------+ +---------+---------+ |
+| R1 | | R2 | |
+| FRRouting | | FRRouting | |
+| Rtr-ID: 10.0.0.1 | | Rtr-ID: 10.0.0.2 | |
++---------+---------+ +---------+---------+ |
+ | ::1 | ::2 \
+ \______ ___________/ OSPFv3
+ \ / Area 0.0.0.0
+ \ / /
+ ~~~~~~~~~~~~~~~~~~ |
+ ~~ SW5 ~~ |
+ ~~ Switch ~~ |
+ ~~ fc00:A:A:A::/64 ~~ |
+ ~~~~~~~~~~~~~~~~~~ |
+ | /---- |
+ | ::3 | SW3 - Stub Net 3 |
+ +---------+---------+ /-+ fc00:3:3:3::/64 |
+ | R3 | / | /
+ | FRRouting +--/ \---- /
+ | Rtr-ID: 10.0.0.3 | ::3 ___________/
+ +---------+---------+ \
+ | ::3 \
+ | \
+ ~~~~~~~~~~~~~~~~~~ |
+ ~~ SW6 ~~ |
+ ~~ Switch ~~ |
+ ~~ fc00:B:B:B::/64 ~~ \
+ ~~~~~~~~~~~~~~~~~~ OSPFv3
+ | Area 0.0.0.1
+ | ::4 /
+ +---------+---------+ /---- |
+ | R4 | | SW4 - Stub Net 4 |
+ | FRRouting +------+ fc00:4:4:4::/64 |
+ | Rtr-ID: 10.0.0.4 | ::4 | /
+ +-------------------+ \---- /
+ -----/
+"""
+
+import os
+import re
+import sys
+import pytest
+import platform
+from time import sleep
+
+from functools import partial
+
+from mininet.topo import Topo
+
+# Save the Current Working Directory to find configuration files later.
+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
+from lib.topotest import iproute2_is_vrf_capable
+from lib.common_config import (
+ required_linux_kernel_version,
+ adjust_router_l3mdev,
+)
+
+#####################################################
+##
+## Network Topology Definition
+##
+#####################################################
+
+
+class NetworkTopo(Topo):
+ "OSPFv3 (IPv6) Test Topology 1"
+
+ def build(self, **_opts):
+ "Build function"
+
+ tgen = get_topogen(self)
+
+ # Create 4 routers
+ for routern in range(1, 5):
+ tgen.add_router("r{}".format(routern))
+
+ #
+ # Wire up the switches and routers
+ # Note that we specify the link names so we match the config files
+ #
+
+ # Create a empty network for router 1
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"], nodeif="r1-stubnet")
+
+ # Create a empty network for router 2
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["r2"], nodeif="r2-stubnet")
+
+ # Create a empty network for router 3
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["r3"], nodeif="r3-stubnet")
+
+ # Create a empty network for router 4
+ switch = tgen.add_switch("s4")
+ switch.add_link(tgen.gears["r4"], nodeif="r4-stubnet")
+
+ # Interconnect routers 1, 2, and 3
+ switch = tgen.add_switch("s5")
+ switch.add_link(tgen.gears["r1"], nodeif="r1-sw5")
+ switch.add_link(tgen.gears["r2"], nodeif="r2-sw5")
+ switch.add_link(tgen.gears["r3"], nodeif="r3-sw5")
+
+ # Interconnect routers 3 and 4
+ switch = tgen.add_switch("s6")
+ switch.add_link(tgen.gears["r3"], nodeif="r3-sw6")
+ switch.add_link(tgen.gears["r4"], nodeif="r4-sw6")
+
+
+#####################################################
+##
+## Tests starting
+##
+#####################################################
+
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+
+ tgen = Topogen(NetworkTopo, mod.__name__)
+ tgen.start_topology()
+
+ logger.info("** %s: Setup Topology" % mod.__name__)
+ logger.info("******************************************")
+
+ # For debugging after starting net, but before starting FRR,
+ # uncomment the next line
+ # tgen.mininet_cli()
+
+ logger.info("Testing with VRF Lite support")
+
+ cmds = [
+ "ip link add {0}-cust1 type vrf table 1001",
+ "ip link add loop1 type dummy",
+ "ip link set {0}-stubnet master {0}-cust1",
+ ]
+
+ cmds1 = [
+ "ip link set {0}-sw5 master {0}-cust1",
+ ]
+
+ cmds2 = [
+ "ip link set {0}-sw6 master {0}-cust1",
+ ]
+
+ # For all registered routers, load the zebra configuration file
+ for rname, router in tgen.routers().items():
+ # create VRF rx-cust1 and link rx-eth0 to rx-cust1
+ for cmd in cmds:
+ output = tgen.net[rname].cmd(cmd.format(rname))
+ if rname == "r1" or rname == "r2" or rname == "r3":
+ for cmd in cmds1:
+ output = tgen.net[rname].cmd(cmd.format(rname))
+ if rname == "r3" or rname == "r4":
+ for cmd in cmds2:
+ output = tgen.net[rname].cmd(cmd.format(rname))
+
+ # adjust handling of vrf traffic
+ adjust_router_l3mdev(tgen, rname)
+
+ for rname, router in tgen.routers().items():
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_OSPF6, os.path.join(CWD, "{}/ospf6d.conf".format(rname))
+ )
+
+ # Initialize all routers.
+ tgen.start_router()
+
+ # For debugging after starting FRR daemons, uncomment the next line
+ # tgen.mininet_cli()
+
+
+def teardown_module(mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+def test_wait_protocol_convergence():
+ "Wait for OSPFv3 to converge"
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("waiting for protocols to converge")
+
+ def expect_neighbor_full(router, neighbor):
+ "Wait until OSPFv3 convergence."
+ logger.info("waiting OSPFv3 router '{}'".format(router))
+ test_func = partial(
+ topotest.router_json_cmp,
+ tgen.gears[router],
+ "show ipv6 ospf6 vrf {0}-cust1 neighbor json".format(router),
+ {"neighbors": [{"neighborId": neighbor, "state": "Full"}]},
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=130, wait=1)
+ assertmsg = '"{}" convergence failure'.format(router)
+ assert result is None, assertmsg
+
+ expect_neighbor_full("r1", "10.0.0.2")
+ expect_neighbor_full("r1", "10.0.0.3")
+
+ expect_neighbor_full("r2", "10.0.0.1")
+ expect_neighbor_full("r2", "10.0.0.3")
+
+ expect_neighbor_full("r3", "10.0.0.1")
+ expect_neighbor_full("r3", "10.0.0.2")
+ expect_neighbor_full("r3", "10.0.0.4")
+
+
+def compare_show_ipv6_vrf(rname, expected):
+ """
+ Calls 'show ipv6 route' for router `rname` and compare the obtained
+ result with the expected output.
+ """
+ tgen = get_topogen()
+
+ # Use the vtysh output, with some masking to make comparison easy
+ vrf_name = "{0}-cust1".format(rname)
+ current = topotest.ip6_route_zebra(tgen.gears[rname], vrf_name)
+
+ # Use just the 'O'spf lines of the output
+ linearr = []
+ for line in current.splitlines():
+ if re.match("^O", line):
+ linearr.append(line)
+
+ current = "\n".join(linearr)
+
+ return topotest.difflines(
+ topotest.normalize_text(current),
+ topotest.normalize_text(expected),
+ title1="Current output",
+ title2="Expected output",
+ )
+
+
+def test_ospfv3_routingTable():
+
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip("skipped because of router(s) failure")
+
+ # For debugging, uncomment the next line
+ # tgen.mininet_cli()
+ # Verify OSPFv3 Routing Table
+ for router, rnode in tgen.routers().iteritems():
+ logger.info('Waiting for router "%s" convergence', router)
+
+ # Load expected results from the command
+ reffile = os.path.join(CWD, "{}/show_ipv6_vrf_route.ref".format(router))
+ expected = open(reffile).read()
+
+ # Run test function until we get an result. Wait at most 60 seconds.
+ test_func = partial(compare_show_ipv6_vrf, router, expected)
+ result, diff = topotest.run_and_expect(test_func, "", count=120, wait=0.5)
+ assert result, "OSPFv3 did not converge on {}:\n{}".format(router, diff)
+
+
+def test_linux_ipv6_kernel_routingTable():
+
+ # Required linux kernel version for this suite to run.
+ result = required_linux_kernel_version("4.15")
+ if result is not True:
+ pytest.skip("Kernel requirements are not met")
+
+ # iproute2 needs to support VRFs for this suite to run.
+ if not iproute2_is_vrf_capable():
+ pytest.skip("Installed iproute2 version does not support VRFs")
+
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip("skipped because of router(s) failure")
+
+ # Verify Linux Kernel Routing Table
+ logger.info("Verifying Linux IPv6 Kernel Routing Table")
+
+ failures = 0
+
+ # Get a list of all current link-local addresses first as they change for
+ # each run and we need to translate them
+ linklocals = []
+ for i in range(1, 5):
+ linklocals += tgen.net["r{}".format(i)].get_ipv6_linklocal()
+
+ # Now compare the routing tables (after substituting link-local addresses)
+
+ for i in range(1, 5):
+ # Actual output from router
+ actual = tgen.gears["r{}".format(i)].run("ip -6 route show vrf r{}-cust1".format(i)).rstrip()
+ if "nhid" in actual:
+ refTableFile = os.path.join(CWD, "r{}/ip_6_address.nhg.ref".format(i))
+ else:
+ refTableFile = os.path.join(CWD, "r{}/ip_6_address.ref".format(i))
+
+ if os.path.isfile(refTableFile):
+ expected = open(refTableFile).read().rstrip()
+ # Fix newlines (make them all the same)
+ expected = ("\n".join(expected.splitlines())).splitlines(1)
+
+ # Mask out Link-Local mac addresses
+ for ll in linklocals:
+ actual = actual.replace(ll[1], "fe80::__(%s)__" % ll[0])
+ # Mask out protocol name or number
+ actual = re.sub(r"[ ]+proto [0-9a-z]+ +", " proto XXXX ", actual)
+ actual = re.sub(r"[ ]+nhid [0-9]+ +", " nhid XXXX ", actual)
+ # Remove ff00::/8 routes (seen on some kernels - not from FRR)
+ actual = re.sub(r"ff00::/8.*", "", actual)
+
+ # Strip empty lines
+ actual = actual.lstrip()
+ actual = actual.rstrip()
+ actual = re.sub(r" +", " ", actual)
+
+ filtered_lines = []
+ for line in sorted(actual.splitlines()):
+ if line.startswith("fe80::/64 ") or line.startswith(
+ "unreachable fe80::/64 "
+ ):
+ continue
+ if 'anycast' in line:
+ continue
+ if 'multicast' in line:
+ continue
+ filtered_lines.append(line)
+ actual = "\n".join(filtered_lines).splitlines(1)
+
+ # Print Actual table
+ # logger.info("Router r%s table" % i)
+ # for line in actual:
+ # logger.info(line.rstrip())
+
+ # Generate Diff
+ diff = topotest.get_textdiff(
+ actual,
+ expected,
+ title1="actual OSPFv3 IPv6 routing table",
+ title2="expected OSPFv3 IPv6 routing table",
+ )
+
+ # Empty string if it matches, otherwise diff contains unified diff
+ if diff:
+ sys.stderr.write(
+ "r%s failed Linux IPv6 Kernel Routing Table Check:\n%s\n"
+ % (i, diff)
+ )
+ failures += 1
+ else:
+ logger.info("r%s ok" % i)
+
+ assert failures == 0, (
+ "Linux Kernel IPv6 Routing Table verification failed for router r%s:\n%s"
+ % (i, diff)
+ )
+
+
+def test_shutdown_check_stderr():
+
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip("skipped because of router(s) failure")
+
+ if os.environ.get("TOPOTESTS_CHECK_STDERR") is None:
+ logger.info(
+ "SKIPPED final check on StdErr output: Disabled (TOPOTESTS_CHECK_STDERR undefined)\n"
+ )
+ pytest.skip("Skipping test for Stderr output")
+
+ net = tgen.net
+
+ logger.info("\n\n** Verifying unexpected STDERR output from daemons")
+ logger.info("******************************************")
+
+ for i in range(1, 5):
+ net["r%s" % i].stopRouter()
+ log = net["r%s" % i].getStdErr("ospf6d")
+ if log:
+ logger.info("\nRouter r%s OSPF6d StdErr Log:\n%s" % (i, log))
+ log = net["r%s" % i].getStdErr("zebra")
+ if log:
+ logger.info("\nRouter r%s Zebra StdErr Log:\n%s" % (i, log))
+
+
+def test_shutdown_check_memleak():
+ "Run the memory leak test and report results."
+
+ if os.environ.get("TOPOTESTS_CHECK_MEMLEAK") is None:
+ logger.info(
+ "SKIPPED final check on Memory leaks: Disabled (TOPOTESTS_CHECK_MEMLEAK undefined)"
+ )
+ pytest.skip("Skipping test for memory leaks")
+
+ tgen = get_topogen()
+
+ net = tgen.net
+
+ for i in range(1, 5):
+ net["r%s" % i].stopRouter()
+ net["r%s" % i].report_memory_leaks(
+ os.environ.get("TOPOTESTS_CHECK_MEMLEAK"), os.path.basename(__file__)
+ )
+
+
+if __name__ == "__main__":
+
+ # To suppress tracebacks, either use the following pytest call or
+ # add "--tb=no" to cli
+ # retval = pytest.main(["-s", "--tb=no"])
+
+ retval = pytest.main(["-s"])
+ sys.exit(retval)
--- /dev/null
+bfd
+ profile fast-tx
+ receive-interval 250
+ transmit-interval 250
+ !
+!
--- /dev/null
+interface r1-eth0
+ ip pim
+ ip pim bfd profile fast-tx
+!
--- /dev/null
+interface r1-eth0
+ ip address 192.168.1.1/24
+!
--- /dev/null
+interface r2-eth0
+ ip pim
+ ip pim bfd
+!
+interface r2-eth1
+ ip pim
+ ip pim bfd
+!
+interface r2-eth2
+ ip pim
+ ip pim bfd
+!
--- /dev/null
+interface r2-eth0
+ ip address 192.168.1.2/24
+!
+interface r2-eth1
+ ip address 192.168.2.1/24
+!
+interface r2-eth2
+ ip address 192.168.3.1/24
+!
--- /dev/null
+interface r3-eth0
+ ip pim
+ ip pim bfd
+!
--- /dev/null
+interface r3-eth0
+ ip address 192.168.2.3/24
+!
--- /dev/null
+interface r4-eth0
+ ip pim
+ ip pim bfd
+!
--- /dev/null
+interface r4-eth0
+ ip address 192.168.3.4/24
+!
--- /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-topo3";
+
+ # 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\n192.168.1.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ sw2 [
+ shape=oval,
+ label="sw2\n192.168.2.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ sw2 [
+ shape=oval,
+ label="sw2\n192.168.3.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+
+ # Connections
+ r1 -- sw1 [label="eth0\n.1"];
+ r2 -- sw1 [label="eth0\n.2"];
+
+ r2 -- sw2 [label="eth1\n.1"];
+ r3 -- sw2 [label="eth0\n.3"];
+
+ r2 -- sw3 [label="eth1\n.1"];
+ r4 -- sw3 [label="eth2\n.4"];
+}
--- /dev/null
+#!/usr/bin/env python
+
+#
+# test_pim_basic_topo2.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2021 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_pim_basic_topo2.py: Test the FRR PIM protocol convergence.
+"""
+
+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
+
+pytestmark = [pytest.mark.bfdd, pytest.mark.pimd]
+
+
+class PimBasicTopo2(Topo):
+ "Test topology builder"
+
+ def build(self, *_args, **_opts):
+ "Build function"
+ tgen = get_topogen(self)
+
+ # Create 4 routers
+ for routern in range(1, 5):
+ tgen.add_router("r{}".format(routern))
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["r2"])
+ switch.add_link(tgen.gears["r3"])
+
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["r2"])
+ switch.add_link(tgen.gears["r4"])
+
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+ tgen = Topogen(PimBasicTopo2, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+ for rname, router in router_list.items():
+ daemon_file = "{}/{}/bfdd.conf".format(CWD, rname)
+ if os.path.isfile(daemon_file):
+ router.load_config(TopoRouter.RD_BFD, daemon_file)
+
+ daemon_file = "{}/{}/pimd.conf".format(CWD, rname)
+ if os.path.isfile(daemon_file):
+ router.load_config(TopoRouter.RD_PIM, daemon_file)
+
+ daemon_file = "{}/{}/zebra.conf".format(CWD, rname)
+ if os.path.isfile(daemon_file):
+ router.load_config(TopoRouter.RD_ZEBRA, daemon_file)
+
+ # Initialize all routers.
+ tgen.start_router()
+
+
+def teardown_module(_mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def expect_neighbor(router, interface, peer):
+ "Wait until peer is present on interface."
+ logger.info("waiting peer {} in {}".format(peer, interface))
+ tgen = get_topogen()
+ test_func = partial(
+ topotest.router_json_cmp,
+ tgen.gears[router],
+ "show ip pim neighbor json",
+ {interface: {peer: {}}}
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=130, wait=1)
+ assertmsg = '"{}" PIM convergence failure'.format(router)
+ assert result is None, assertmsg
+
+
+def test_wait_pim_convergence():
+ "Wait for PIM to converge"
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("waiting for PIM to converge")
+
+ expect_neighbor('r1', 'r1-eth0', '192.168.1.2')
+ expect_neighbor('r2', 'r2-eth0', '192.168.1.1')
+
+ expect_neighbor('r2', 'r2-eth1', '192.168.2.3')
+ expect_neighbor('r2', 'r2-eth2', '192.168.3.4')
+
+ expect_neighbor('r3', 'r3-eth0', '192.168.2.1')
+ expect_neighbor('r4', 'r4-eth0', '192.168.3.1')
+
+
+def test_bfd_peers():
+ "Wait for BFD peers to show up."
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("waiting for BFD to converge")
+
+ def expect_bfd_peer(router, peer):
+ "Wait until peer is present on interface."
+ logger.info("waiting BFD peer {} in {}".format(peer, router))
+ test_func = partial(
+ topotest.router_json_cmp,
+ tgen.gears[router],
+ "show bfd peers json",
+ [{"peer": peer, "status": "up"}]
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=10, wait=1)
+ assertmsg = '"{}" BFD convergence failure'.format(router)
+ assert result is None, assertmsg
+
+ expect_bfd_peer("r1", "192.168.1.2")
+ expect_bfd_peer("r2", "192.168.1.1")
+ expect_bfd_peer("r2", "192.168.2.3")
+ expect_bfd_peer("r2", "192.168.3.4")
+ expect_bfd_peer("r3", "192.168.2.1")
+ expect_bfd_peer("r4", "192.168.3.1")
+
+
+def test_pim_reconvergence():
+ "Disconnect a peer and expect it to disconnect."
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("waiting for disconnect convergence")
+ tgen.gears["r4"].link_enable("r4-eth0", enabled=False)
+
+ def expect_neighbor_down(router, interface, peer):
+ "Wait until peer is present on interface."
+ logger.info("waiting peer {} in {} to disappear".format(peer, interface))
+ test_func = partial(
+ topotest.router_json_cmp,
+ tgen.gears[router],
+ "show ip pim neighbor json",
+ {interface: {peer: None}}
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=4, wait=1)
+ assertmsg = '"{}" PIM convergence failure'.format(router)
+ assert result is None, assertmsg
+
+ expect_neighbor_down("r2", "r2-eth2", "192.168.3.4")
+
+ logger.info("waiting for reconvergence")
+ tgen.gears["r4"].link_enable("r4-eth0", enabled=True)
+ expect_neighbor("r2", "r2-eth2", "192.168.3.4")
+
+
+def test_pim_bfd_profile():
+ "Test that the BFD profile is properly applied in BFD."
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ def expect_bfd_peer_settings(router, settings):
+ "Expect the following BFD configuration"
+ logger.info("Verifying BFD peer {} in {}".format(settings["peer"], router))
+ test_func = partial(
+ topotest.router_json_cmp,
+ tgen.gears[router],
+ "show bfd peers json",
+ [settings]
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=4, wait=1)
+ assertmsg = '"{}" BFD convergence failure'.format(router)
+ assert result is None, assertmsg
+
+ expect_bfd_peer_settings("r1", {
+ "peer": "192.168.1.2",
+ "receive-interval": 250,
+ "transmit-interval": 250,
+ })
+
+ expect_bfd_peer_settings("r2", {
+ "peer": "192.168.1.1",
+ "remote-receive-interval": 250,
+ "remote-transmit-interval": 250,
+ })
+
+
+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))
class Context(object):
"""
- A Context object represents a section of frr configuration such as:
-!
-interface swp3
- description swp3 -> r8's swp1
- ipv6 nd suppress-ra
- link-detect
-!
+ A Context object represents a section of frr configuration such as:
+ !
+ interface swp3
+ description swp3 -> r8's swp1
+ ipv6 nd suppress-ra
+ link-detect
+ !
-or a single line context object such as this:
+ or a single line context object such as this:
-ip forwarding
+ ip forwarding
"""
re_lege.group(2),
re_lege.group(4),
)
- re_lege = re.search(r"(.*)ge\s+(\d+)\s+le\s+(\d+)(.*)", legestr)
-
- if re_lege and (
- (re_key_rt.group(1) == "ip" and re_lege.group(3) == "32")
- or (re_key_rt.group(1) == "ipv6" and re_lege.group(3) == "128")
- ):
- legestr = "%sge %s%s" % (
- re_lege.group(1),
- re_lege.group(2),
- re_lege.group(4),
- )
key[0] = "%s prefix-list%s%s %s%s" % (
re_key_rt.group(1),
add_exit_vrf = False
if ctx_keys[0].startswith("vrf") and line:
- if line is not "exit-vrf":
+ if line != "exit-vrf":
add_exit_vrf = True
prior_ctx_key = ctx_keys[0]
else:
# in-place, to avoid requesting spurious label chunks which might fail
if line and "segment-routing global-block" in line:
for (add_key, add_line) in lines_to_add:
- if ctx_keys[0] == add_key[0] and add_line and "segment-routing global-block" in add_line:
+ if (
+ ctx_keys[0] == add_key[0]
+ and add_line
+ and "segment-routing global-block" in add_line
+ ):
lines_to_del_to_del.append((ctx_keys, line))
break
continue
-
if ctx_keys[0].startswith("router bgp") and line:
if line.startswith("neighbor "):
tools_gen_yang_deviations_LDADD = lib/libfrr.la $(LIBYANG_LIBS)
tools_ssd_SOURCES = tools/start-stop-daemon.c
+tools_ssd_CPPFLAGS =
# don't bother autoconf'ing these for a simple optional tool
llvm_version = $(shell echo __clang_major__ | $(CC) -xc -P -E -)
+tools_frr_llvm_cg_CPPFLAGS = $(CPPFLAGS_BASE)
tools_frr_llvm_cg_CFLAGS = $(AM_CFLAGS) `llvm-config-$(llvm_version) --cflags`
tools_frr_llvm_cg_LDFLAGS = `llvm-config-$(llvm_version) --ldflags --libs`
tools_frr_llvm_cg_SOURCES = \
--- /dev/null
+{
+ <zlog_keep_working_at_exit>
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:calloc
+ fun:qcalloc
+ fun:zlog_target_clone
+}
+{
+ <libyang1_1.0.184>
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:calloc
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ obj:/usr/lib/x86_64-linux-gnu/libyang.so.1.9.2
+ fun:ly_load_plugins
+}
+{
+ <zprivs_init leak in a function we do not control>
+ Memcheck:Leak
+ fun:calloc
+ fun:cap_init
+ fun:zprivs_caps_init
+}
+{
+ <sqlite3 leak in a function we do not control>
+ Memcheck:Leak
+ fun:malloc
+ ...
+ fun:sqlite3_step
+}
--- /dev/null
+#include "lib/compiler.h"
+CPP_NOTICE("Trying to include version.h. Please fix to use lib/version.h.")
+#include "lib/version.h"
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|VTYSH_OSPFD|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_ISISD|VTYSH_FABRICD";
}
}
- elsif ($file =~ /lib\/distribute\.c$/) {
- if ($defun_array[1] =~ m/ipv6/) {
- $protocol = "VTYSH_RIPNGD";
- } else {
- $protocol = "VTYSH_RIPD";
- }
- }
elsif ($file =~ /lib\/if_rmap\.c$/) {
if ($defun_array[1] =~ m/ipv6/) {
$protocol = "VTYSH_RIPNGD";
$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";
}
#endif /* HAVE_BABELD */
#ifdef HAVE_OSPF6D
-DEFUNSH(VTYSH_OSPF6D, router_ospf6, router_ospf6_cmd, "router ospf6",
- ROUTER_STR OSPF6_STR)
+DEFUNSH(VTYSH_OSPF6D, router_ospf6, router_ospf6_cmd, "router ospf6 [vrf NAME]",
+ ROUTER_STR OSPF6_STR VRF_CMD_HELP_STR)
{
vty->node = OSPF6_NODE;
return CMD_SUCCESS;
"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"
/* 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);
strlen("bgp large-community-list"))
== 0)
config = config_get(COMMUNITY_LIST_NODE, line);
+ else if (strncmp(line, "bgp community alias",
+ strlen("bgp community alias")) == 0)
+ config = config_get(COMMUNITY_ALIAS_NODE, line);
else if (strncmp(line, "ip route", strlen("ip route")) == 0)
config = config_get(IP_NODE, line);
else if (strncmp(line, "ipv6 route", strlen("ipv6 route")) == 0)
#define NO_DELIMITER(I) \
((I) == ACCESS_NODE || (I) == PREFIX_NODE || (I) == IP_NODE \
|| (I) == AS_LIST_NODE || (I) == COMMUNITY_LIST_NODE \
- || (I) == ACCESS_IPV6_NODE || (I) == ACCESS_MAC_NODE \
- || (I) == PREFIX_IPV6_NODE || (I) == FORWARDING_NODE \
- || (I) == DEBUG_NODE || (I) == AAA_NODE || (I) == VRF_DEBUG_NODE \
- || (I) == NORTHBOUND_DEBUG_NODE || (I) == RMAP_DEBUG_NODE \
- || (I) == RESOLVER_DEBUG_NODE || (I) == MPLS_NODE)
+ || (I) == COMMUNITY_ALIAS_NODE || (I) == ACCESS_IPV6_NODE \
+ || (I) == ACCESS_MAC_NODE || (I) == PREFIX_IPV6_NODE \
+ || (I) == FORWARDING_NODE || (I) == DEBUG_NODE || (I) == AAA_NODE \
+ || (I) == VRF_DEBUG_NODE || (I) == NORTHBOUND_DEBUG_NODE \
+ || (I) == RMAP_DEBUG_NODE || (I) == RESOLVER_DEBUG_NODE \
+ || (I) == MPLS_NODE)
/* Display configuration to file pointer. */
void vtysh_config_dump(void)
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
"Node protection is provided by the alternate.";
}
+ leaf link-fallback {
+ type boolean;
+ must ". = 'false' or ../enable = 'true'";
+ default false;
+ description
+ "Fallback to link protection.";
+ }
}
}
"Area-tag associated to this circuit.";
}
- leaf vrf {
- type frr-vrf:vrf-ref;
- default "default";
- description
- "VRF NAME.";
- }
-
leaf ipv4-routing {
type boolean;
default "false";
leaf holddown {
type uint16 {
range "0..10000";
- }
- units "seconds";
- description
- "Time to wait for LDP-Sync to occur before restoring interface metric.";
+ }
+ units "seconds";
+ description
+ "Time to wait for LDP-Sync to occur before restoring interface metric.";
}
}
description
"Detect Multiplier";
}
+
+ leaf profile {
+ type string;
+ description
+ "Use a preconfigure BFD profile.";
+ }
}
leaf bsm {
struct zebra_vrf *zvrf;
uint32_t metric;
uint32_t flags = 0;
+ uint32_t count = 0;
+ struct listnode *cnode;
+ struct connected *c;
zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id);
if (!zvrf) {
if (zrouter.asic_offloaded)
flags |= ZEBRA_FLAG_OFFLOADED;
+ /*
+ * It's possible to add the same network and mask
+ * to an interface over and over. This would
+ * result in an equivalent number of connected
+ * routes. Just add one connected route in
+ * for all the addresses on an interface that
+ * resolve to the same network and mask
+ */
+ for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) {
+ struct prefix cp;
+
+ PREFIX_COPY(&cp, CONNECTED_PREFIX(c));
+ apply_mask(&cp);
+
+ if (prefix_same(&cp, &p))
+ count++;
+
+ if (count >= 2)
+ return;
+ }
+
rib_add(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0,
flags, &p, NULL, &nh, 0, zvrf->table_id, metric, 0, 0, 0);
.vrf_id = ifp->vrf_id,
};
struct zebra_vrf *zvrf;
+ uint32_t count = 0;
+ struct listnode *cnode;
+ struct connected *c;
zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id);
if (!zvrf) {
break;
}
+ /*
+ * It's possible to have X number of addresses
+ * on a interface that all resolve to the same
+ * network and mask. Find them and just
+ * allow the deletion when are removing the last
+ * one.
+ */
+ for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) {
+ struct prefix cp;
+
+ PREFIX_COPY(&cp, CONNECTED_PREFIX(c));
+ apply_mask(&cp);
+
+ if (prefix_same(&p, &cp))
+ count++;
+
+ if (count >= 2)
+ return;
+ }
+
/*
* Same logic as for connected_up(): push the changes into the
* head.
return CMD_SUCCESS;
}
-DEFUN (debug_zebra_vxlan,
+DEFPY (debug_zebra_vxlan,
debug_zebra_vxlan_cmd,
"debug zebra vxlan",
DEBUG_STR
{
SET_FLAG(zebra_debug_kernel, ZEBRA_DEBUG_KERNEL);
- if (IS_ZEBRA_DEBUG_KERNEL_MSGDUMP_RECV)
- UNSET_FLAG(zebra_debug_kernel, ZEBRA_DEBUG_KERNEL_MSGDUMP_RECV);
-
- if (IS_ZEBRA_DEBUG_KERNEL_MSGDUMP_SEND)
- UNSET_FLAG(zebra_debug_kernel, ZEBRA_DEBUG_KERNEL_MSGDUMP_SEND);
-
return CMD_SUCCESS;
}
{
int idx = 0;
- if (argv_find(argv, argc, "recv", &idx)) {
+ if (argv_find(argv, argc, "recv", &idx))
SET_FLAG(zebra_debug_kernel, ZEBRA_DEBUG_KERNEL_MSGDUMP_RECV);
-
- if (IS_ZEBRA_DEBUG_KERNEL_MSGDUMP_SEND)
- UNSET_FLAG(zebra_debug_kernel,
- ZEBRA_DEBUG_KERNEL_MSGDUMP_SEND);
-
- } else if (argv_find(argv, argc, "send", &idx)) {
+ else if (argv_find(argv, argc, "send", &idx))
SET_FLAG(zebra_debug_kernel, ZEBRA_DEBUG_KERNEL_MSGDUMP_SEND);
-
- if (IS_ZEBRA_DEBUG_KERNEL_MSGDUMP_RECV)
- UNSET_FLAG(zebra_debug_kernel,
- ZEBRA_DEBUG_KERNEL_MSGDUMP_RECV);
-
- } else {
+ else {
SET_FLAG(zebra_debug_kernel, ZEBRA_DEBUG_KERNEL_MSGDUMP_RECV);
SET_FLAG(zebra_debug_kernel, ZEBRA_DEBUG_KERNEL_MSGDUMP_SEND);
}
"Zebra configuration\n"
"Debug option set for zebra between kernel interface\n")
{
- zebra_debug_kernel = 0;
+ UNSET_FLAG(zebra_debug_kernel, ZEBRA_DEBUG_KERNEL);
+
return CMD_SUCCESS;
}
"Dump raw netlink messages received\n"
"Dump raw netlink messages sent\n")
{
- zebra_debug_kernel = 0;
+ int idx = 0;
+
+ if (argv_find(argv, argc, "recv", &idx))
+ UNSET_FLAG(zebra_debug_kernel, ZEBRA_DEBUG_KERNEL_MSGDUMP_RECV);
+ else if (argv_find(argv, argc, "send", &idx))
+ UNSET_FLAG(zebra_debug_kernel, ZEBRA_DEBUG_KERNEL_MSGDUMP_SEND);
+ else {
+ UNSET_FLAG(zebra_debug_kernel, ZEBRA_DEBUG_KERNEL_MSGDUMP_RECV);
+ UNSET_FLAG(zebra_debug_kernel, ZEBRA_DEBUG_KERNEL_MSGDUMP_SEND);
+ }
+
return CMD_SUCCESS;
}
}
}
+ if (IS_ZEBRA_DEBUG_KERNEL_MSGDUMP_SEND
+ && IS_ZEBRA_DEBUG_KERNEL_MSGDUMP_RECV) {
+ vty_out(vty, "debug zebra kernel msgdump\n");
+ write++;
+ } else if (IS_ZEBRA_DEBUG_KERNEL_MSGDUMP_RECV) {
+ vty_out(vty, "debug zebra kernel msgdump recv\n");
+ write++;
+ } else if (IS_ZEBRA_DEBUG_KERNEL_MSGDUMP_SEND) {
+ vty_out(vty, "debug zebra kernel msgdump send\n");
+ write++;
+ }
+
if (IS_ZEBRA_DEBUG_KERNEL) {
- if (IS_ZEBRA_DEBUG_KERNEL_MSGDUMP_SEND
- && IS_ZEBRA_DEBUG_KERNEL_MSGDUMP_RECV) {
- vty_out(vty, "debug zebra kernel msgdump\n");
- write++;
- } else if (IS_ZEBRA_DEBUG_KERNEL_MSGDUMP_RECV) {
- vty_out(vty, "debug zebra kernel msgdump recv\n");
- write++;
- } else if (IS_ZEBRA_DEBUG_KERNEL_MSGDUMP_SEND) {
- vty_out(vty, "debug zebra kernel msgdump send\n");
- write++;
- } else {
- vty_out(vty, "debug zebra kernel\n");
- write++;
- }
+ vty_out(vty, "debug zebra kernel\n");
+ write++;
}
if (CHECK_FLAG(zebra_debug_rib, ZEBRA_DEBUG_RIB_DETAILED)) {
* Reference - https://sourceware.org/ml/libc-alpha/2013-01/msg00599.html
*/
#define _LINUX_IN6_H
+#define _LINUX_IF_H
+#define _LINUX_IP_H
#include <netinet/if_ether.h>
#include <linux/if_bridge.h>
#include <linux/if_link.h>
+#include <linux/if_tunnel.h>
#include <net/if_arp.h>
#include <linux/sockios.h>
#include <linux/ethtool.h>
#include "zebra/zebra_errors.h"
#include "zebra/zebra_vxlan.h"
#include "zebra/zebra_evpn_mh.h"
+#include "zebra/zebra_l2.h"
extern struct zebra_privs_t zserv_privs;
*zif_type = ZEBRA_IF_BOND;
else if (strcmp(kind, "bond_slave") == 0)
*zif_type = ZEBRA_IF_BOND_SLAVE;
+ else if (strcmp(kind, "gre") == 0)
+ *zif_type = ZEBRA_IF_GRE;
}
#define parse_rtattr_nested(tb, max, rta) \
return get_iflink_speed(ifp, error);
}
+static ssize_t
+netlink_gre_set_msg_encoder(struct zebra_dplane_ctx *ctx, void *buf,
+ size_t buflen)
+{
+ struct {
+ struct nlmsghdr n;
+ struct ifinfomsg ifi;
+ char buf[];
+ } *req = buf;
+ uint32_t link_idx;
+ unsigned int mtu;
+ struct rtattr *rta_info, *rta_data;
+ const struct zebra_l2info_gre *gre_info;
+
+ if (buflen < sizeof(*req))
+ return 0;
+ memset(req, 0, sizeof(*req));
+
+ req->n.nlmsg_type = RTM_NEWLINK;
+ req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+ req->n.nlmsg_flags = NLM_F_REQUEST;
+
+ req->ifi.ifi_index = dplane_ctx_get_ifindex(ctx);
+
+ gre_info = dplane_ctx_gre_get_info(ctx);
+ if (!gre_info)
+ return 0;
+
+ req->ifi.ifi_change = 0xFFFFFFFF;
+ link_idx = dplane_ctx_gre_get_link_ifindex(ctx);
+ mtu = dplane_ctx_gre_get_mtu(ctx);
+
+ if (mtu && !nl_attr_put32(&req->n, buflen, IFLA_MTU, mtu))
+ return 0;
+
+ rta_info = nl_attr_nest(&req->n, buflen, IFLA_LINKINFO);
+ if (!rta_info)
+ return 0;
+
+ if (!nl_attr_put(&req->n, buflen, IFLA_INFO_KIND, "gre", 3))
+ return 0;
+
+ rta_data = nl_attr_nest(&req->n, buflen, IFLA_INFO_DATA);
+ if (!rta_data)
+ return 0;
+
+ if (!nl_attr_put32(&req->n, buflen, IFLA_GRE_LINK, link_idx))
+ return 0;
+
+ if (gre_info->vtep_ip.s_addr &&
+ !nl_attr_put32(&req->n, buflen, IFLA_GRE_LOCAL,
+ gre_info->vtep_ip.s_addr))
+ return 0;
+
+ if (gre_info->vtep_ip_remote.s_addr &&
+ !nl_attr_put32(&req->n, buflen, IFLA_GRE_REMOTE,
+ gre_info->vtep_ip_remote.s_addr))
+ return 0;
+
+ if (gre_info->ikey &&
+ !nl_attr_put32(&req->n, buflen, IFLA_GRE_IKEY,
+ gre_info->ikey))
+ return 0;
+ if (gre_info->okey &&
+ !nl_attr_put32(&req->n, buflen, IFLA_GRE_IKEY,
+ gre_info->okey))
+ return 0;
+
+ nl_attr_nest_end(&req->n, rta_data);
+ nl_attr_nest_end(&req->n, rta_info);
+
+ return NLMSG_ALIGN(req->n.nlmsg_len);
+}
+
static int netlink_extract_bridge_info(struct rtattr *link_data,
struct zebra_l2info_bridge *bridge_info)
{
return 0;
}
+static int netlink_extract_gre_info(struct rtattr *link_data,
+ struct zebra_l2info_gre *gre_info)
+{
+ struct rtattr *attr[IFLA_GRE_MAX + 1];
+
+ memset(gre_info, 0, sizeof(*gre_info));
+ memset(attr, 0, sizeof(attr));
+ parse_rtattr_nested(attr, IFLA_GRE_MAX, link_data);
+
+ if (!attr[IFLA_GRE_LOCAL]) {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug(
+ "IFLA_GRE_LOCAL missing from GRE IF message");
+ } else
+ gre_info->vtep_ip =
+ *(struct in_addr *)RTA_DATA(attr[IFLA_GRE_LOCAL]);
+ if (!attr[IFLA_GRE_REMOTE]) {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug(
+ "IFLA_GRE_REMOTE missing from GRE IF message");
+ } else
+ gre_info->vtep_ip_remote =
+ *(struct in_addr *)RTA_DATA(attr[IFLA_GRE_REMOTE]);
+
+ if (!attr[IFLA_GRE_LINK]) {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("IFLA_GRE_LINK missing from GRE IF message");
+ } else {
+ gre_info->ifindex_link =
+ *(ifindex_t *)RTA_DATA(attr[IFLA_GRE_LINK]);
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("IFLA_GRE_LINK obtained is %u",
+ gre_info->ifindex_link);
+ }
+ if (attr[IFLA_GRE_IKEY])
+ gre_info->ikey = *(uint32_t *)RTA_DATA(attr[IFLA_GRE_IKEY]);
+ if (attr[IFLA_GRE_OKEY])
+ gre_info->okey = *(uint32_t *)RTA_DATA(attr[IFLA_GRE_OKEY]);
+ return 0;
+}
+
static int netlink_extract_vxlan_info(struct rtattr *link_data,
struct zebra_l2info_vxlan *vxl_info)
{
vxlan_info.ifindex_link)
zebra_if_update_link(ifp, vxlan_info.ifindex_link,
link_nsid);
+ } else if (IS_ZEBRA_IF_GRE(ifp)) {
+ struct zebra_l2info_gre gre_info;
+
+ netlink_extract_gre_info(link_data, &gre_info);
+ gre_info.link_nsid = link_nsid;
+ zebra_l2_greif_add_update(ifp, &gre_info, add);
+ if (link_nsid != NS_UNKNOWN &&
+ gre_info.ifindex_link)
+ zebra_if_update_link(ifp, gre_info.ifindex_link,
+ link_nsid);
}
}
return netlink_request(netlink_cmd, &req);
}
+enum netlink_msg_status
+netlink_put_gre_set_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx)
+{
+ enum dplane_op_e op;
+ enum netlink_msg_status ret;
+
+ op = dplane_ctx_get_op(ctx);
+ assert(op == DPLANE_OP_GRE_SET);
+
+ ret = netlink_batch_add_msg(bth, ctx, netlink_gre_set_msg_encoder, false);
+
+ return ret;
+}
+
/* Interface lookup by netlink socket. */
int interface_lookup_netlink(struct zebra_ns *zns)
{
return ret;
/* fixup linkages */
- zebra_if_update_all_links();
+ zebra_if_update_all_links(zns);
return 0;
}
memcpy(old_hw_addr, ifp->hw_addr, INTERFACE_HWADDR_MAX);
+ /* Update link. */
+ zebra_if_update_link(ifp, link_ifindex, ns_id);
+
netlink_interface_update_hw_addr(tb, ifp);
if (if_is_no_ptm_operative(ifp)) {
extern int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup);
extern int interface_lookup_netlink(struct zebra_ns *zns);
+extern enum netlink_msg_status
+netlink_put_gre_set_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx);
+
extern enum netlink_msg_status
netlink_put_address_update_msg(struct nl_batch *bth,
struct zebra_dplane_ctx *ctx);
zif->link_ifindex);
if (link_if)
zebra_vxlan_svi_up(ifp, link_if);
- } else if (IS_ZEBRA_IF_MACVLAN(ifp))
+ } else if (IS_ZEBRA_IF_MACVLAN(ifp)) {
zebra_vxlan_macvlan_up(ifp);
+ }
if (zif->es_info.es)
zebra_evpn_es_if_oper_state_change(zif, true /*up*/);
if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK)
zebra_evpn_mh_uplink_oper_update(zif);
+
+ thread_add_timer(zrouter.master, if_zebra_speed_update, ifp, 0,
+ &zif->speed_update);
}
/* Interface goes down. We have to manage different behavior of based
zif->link_ifindex);
if (link_if)
zebra_vxlan_svi_down(ifp, link_if);
- } else if (IS_ZEBRA_IF_MACVLAN(ifp))
+ } else if (IS_ZEBRA_IF_MACVLAN(ifp)) {
zebra_vxlan_macvlan_down(ifp);
+ }
if (zif->es_info.es)
zebra_evpn_es_if_oper_state_change(zif, false /*up*/);
* during initial link dump kernel does not order lower devices before
* upper devices so we need to fixup link dependencies at the end of dump
*/
-void zebra_if_update_all_links(void)
+void zebra_if_update_all_links(struct zebra_ns *zns)
{
struct route_node *rn;
struct interface *ifp;
struct zebra_if *zif;
- struct zebra_ns *ns;
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_info("fixup link dependencies");
- ns = zebra_ns_lookup(NS_DEFAULT);
- for (rn = route_top(ns->if_table); rn; rn = route_next(rn)) {
+ for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
ifp = (struct interface *)rn->info;
if (!ifp)
continue;
/* update SVI linkages */
if ((zif->link_ifindex != IFINDEX_INTERNAL) && !zif->link) {
- zif->link = if_lookup_by_index_per_ns(ns,
- zif->link_ifindex);
+ zif->link = if_lookup_by_index_per_ns(
+ zns, zif->link_ifindex);
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("interface %s/%d's lower fixup to %s/%d",
ifp->name, ifp->ifindex,
case ZEBRA_IF_MACVLAN:
return "macvlan";
+ case ZEBRA_IF_GRE:
+ return "GRE";
+
default:
return "Unknown";
}
ifp->name);
}
vty_out(vty, "\n");
+ } else if (IS_ZEBRA_IF_GRE(ifp)) {
+ struct zebra_l2info_gre *gre_info;
+
+ gre_info = &zebra_if->l2info.gre;
+ if (gre_info->vtep_ip.s_addr != INADDR_ANY) {
+ vty_out(vty, " VTEP IP: %pI4", &gre_info->vtep_ip);
+ if (gre_info->vtep_ip_remote.s_addr != INADDR_ANY)
+ vty_out(vty, " , remote %pI4",
+ &gre_info->vtep_ip_remote);
+ vty_out(vty, "\n");
+ }
+ if (gre_info->ifindex_link &&
+ (gre_info->link_nsid != NS_UNKNOWN)) {
+ struct interface *ifp;
+
+ ifp = if_lookup_by_index_per_ns(
+ zebra_ns_lookup(gre_info->link_nsid),
+ gre_info->ifindex_link);
+ vty_out(vty, " Link Interface %s\n",
+ ifp == NULL ? "Unknown" :
+ ifp->name);
+ }
}
if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp)) {
ZEBRA_IF_VETH, /* VETH interface*/
ZEBRA_IF_BOND, /* Bond */
ZEBRA_IF_BOND_SLAVE, /* Bond */
+ ZEBRA_IF_GRE, /* GRE interface */
} zebra_iftype_t;
/* Zebra "slave" interface type */
#define IS_ZEBRA_IF_BOND(ifp) \
(((struct zebra_if *)(ifp->info))->zif_type == ZEBRA_IF_BOND)
+#define IS_ZEBRA_IF_GRE(ifp) \
+ (((struct zebra_if *)(ifp->info))->zif_type == ZEBRA_IF_GRE)
+
#define IS_ZEBRA_IF_BRIDGE_SLAVE(ifp) \
(((struct zebra_if *)(ifp->info))->zif_slave_type \
== ZEBRA_IF_SLAVE_BRIDGE)
extern void if_handle_vrf_change(struct interface *ifp, vrf_id_t vrf_id);
extern void zebra_if_update_link(struct interface *ifp, ifindex_t link_ifindex,
ns_id_t ns_id);
-extern void zebra_if_update_all_links(void);
+extern void zebra_if_update_all_links(struct zebra_ns *zns);
extern void zebra_if_set_protodown(struct interface *ifp, bool down);
extern int if_ip_address_install(struct interface *ifp, struct prefix *prefix,
const char *label, struct prefix *pp);
#include "privs.h"
#include "libfrr.h"
#include "lib_errors.h"
-#include "version.h"
+#include "lib/version.h"
#include "zebra/interface.h"
#include "zebra/rtadv.h"
#include "zebra/rib.h"
case DPLANE_OP_IPSET_ENTRY_DELETE:
return FRR_NETLINK_ERROR;
+ case DPLANE_OP_GRE_SET:
+ return netlink_put_gre_set_msg(bth, ctx);
+
case DPLANE_OP_NONE:
return FRR_NETLINK_ERROR;
}
continue;
RNODE_FOREACH_RE (rn, newre) {
- if (CHECK_FLAG(newre->flags, ZEBRA_FLAG_SELECTED)
- && newre->distance != DISTANCE_INFINITY)
+ if (CHECK_FLAG(newre->flags, ZEBRA_FLAG_SELECTED))
zsend_redistribute_route(
ZEBRA_REDISTRIBUTE_ROUTE_ADD, client,
&rn->p, NULL, newre);
&& (newre->type != type
|| newre->instance != instance)))
continue;
- if (newre->distance == DISTANCE_INFINITY)
- continue;
if (!zebra_check_addr(dst_p))
continue;
new_re ? zebra_route_string(new_re->type) : "None");
}
- /* Add DISTANCE_INFINITY check. */
- if (old_re && (old_re->distance == DISTANCE_INFINITY)) {
- if (IS_ZEBRA_DEBUG_RIB)
- zlog_debug(" Skipping due to Infinite Distance");
- return;
- }
-
afi = family2afi(p->family);
if (!afi) {
flog_warn(EC_ZEBRA_REDISTRIBUTE_UNKNOWN_AF,
zvrf_id(zvrf), afi);
}
} else {
- if (!vrf_bitmap_check(client->redist[afi][type],
- zvrf_id(zvrf))) {
- if (IS_ZEBRA_DEBUG_EVENT)
- zlog_debug(
- "%s: setting vrf %s(%u) redist bitmap",
- __func__, VRF_LOGNAME(zvrf->vrf),
- zvrf_id(zvrf));
- vrf_bitmap_set(client->redist[afi][type],
- zvrf_id(zvrf));
- zebra_redistribute(client, type, 0, zvrf_id(zvrf), afi);
- }
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug("%s: setting vrf %s(%u) redist bitmap",
+ __func__, VRF_LOGNAME(zvrf->vrf),
+ zvrf_id(zvrf));
+ vrf_bitmap_set(client->redist[afi][type], zvrf_id(zvrf));
+ zebra_redistribute(client, type, 0, zvrf_id(zvrf), afi);
}
stream_failure:
STREAM_GETC(msg, type);
STREAM_GETW(msg, instance);
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug(
+ "%s: client proto %s afi=%d, no longer wants %s, vrf %s(%u), instance=%d",
+ __func__, zebra_route_string(client->proto), afi,
+ zebra_route_string(type), VRF_LOGNAME(zvrf->vrf),
+ zvrf_id(zvrf), instance);
+
+
if (afi == 0 || afi >= AFI_MAX) {
flog_warn(EC_ZEBRA_REDISTRIBUTE_UNKNOWN_AF,
"%s: Specified afi %d does not exist", __func__, afi);
struct nhg_ctx; /* Forward declaration */
-extern int rib_queue_nhg_add(struct nhg_ctx *ctx);
+/* Enqueue incoming nhg from OS for processing */
+extern int rib_queue_nhg_ctx_add(struct nhg_ctx *ctx);
+
+/* Enqueue incoming nhg from proto daemon for processing */
+extern int rib_queue_nhe_add(struct nhg_hash_entry *nhe);
extern void meta_queue_free(struct meta_queue *mq);
extern int zebra_rib_labeled_unicast(struct route_entry *re);
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.
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)
{
ifindex_t ifindex;
struct interface *ifp;
struct zebra_if *zif;
- int ra_interval_rxd;
+ uint32_t ra_interval;
s = msg;
/* Get interface index and RA interval. */
STREAM_GETL(s, ifindex);
- STREAM_GETL(s, ra_interval_rxd);
-
- if (ra_interval_rxd < 0) {
- zlog_warn(
- "Requested RA interval %d is garbage; ignoring request",
- ra_interval_rxd);
- return;
- }
-
- unsigned int ra_interval = ra_interval_rxd;
+ STREAM_GETL(s, ra_interval);
if (IS_ZEBRA_DEBUG_EVENT) {
struct vrf *vrf = zvrf->vrf;
zebra_zebra_irdp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
zebra_zebra_snmp_la_SOURCES = zebra/zebra_snmp.c
-zebra_zebra_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11
+zebra_zebra_snmp_la_CFLAGS = $(AM_CFLAGS) $(SNMP_CFLAGS) -std=gnu11
zebra_zebra_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
zebra_zebra_snmp_la_LIBADD = lib/libfrrsnmp.la
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
}
if (IS_ZEBRA_DEBUG_SEND)
- zlog_debug("%s: type %d, id %d, note %d",
- __func__, type, id, note);
+ zlog_debug("%s: type %d, id %d, note %s",
+ __func__, type, id, zapi_nhg_notify_owner2str(note));
s = stream_new(ZEBRA_MAX_PACKET_SIZ);
stream_reset(s);
return;
}
- /*
- * Create the nhg
- */
- nhe = zebra_nhg_proto_add(api_nhg.id, api_nhg.proto, client->instance,
- client->session_id, nhg, 0);
+ /* Create a temporary nhe */
+ nhe = zebra_nhg_alloc();
+ nhe->id = api_nhg.id;
+ nhe->type = api_nhg.proto;
+ nhe->zapi_instance = client->instance;
+ nhe->zapi_session = client->session_id;
- nexthop_group_delete(&nhg);
- zebra_nhg_backup_free(&bnhg);
+ /* Take over the list(s) of nexthops */
+ nhe->nhg.nexthop = nhg->nexthop;
+ nhg->nexthop = NULL;
+
+ if (bnhg) {
+ nhe->backup_info = bnhg;
+ bnhg = NULL;
+ }
/*
* TODO:
* Assume fully resolved for now and install.
- *
* Resolution is going to need some more work.
*/
- /* If there's a failure, notify sender immediately */
- if (nhe == NULL)
- zsend_nhg_notify(api_nhg.proto, client->instance,
- client->session_id, api_nhg.id,
- ZAPI_NHG_FAIL_INSTALL);
+ /* Enqueue to workqueue for processing */
+ rib_queue_nhe_add(nhe);
+
+ /* Free any local allocations */
+ nexthop_group_delete(&nhg);
+ zebra_nhg_backup_free(&bnhg);
+
}
static void zread_route_add(ZAPI_HANDLER_ARGS)
return;
}
+static inline void zebra_gre_get(ZAPI_HANDLER_ARGS)
+{
+ struct stream *s;
+ ifindex_t idx;
+ struct interface *ifp;
+ struct zebra_if *zebra_if = NULL;
+ struct zebra_l2info_gre *gre_info;
+ struct interface *ifp_link = NULL;
+ vrf_id_t vrf_id_link = VRF_UNKNOWN;
+ vrf_id_t vrf_id = zvrf->vrf->vrf_id;
+
+ s = msg;
+ STREAM_GETL(s, idx);
+ ifp = if_lookup_by_index(idx, vrf_id);
+
+ if (ifp)
+ zebra_if = ifp->info;
+
+ s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+
+ zclient_create_header(s, ZEBRA_GRE_UPDATE, vrf_id);
+
+ if (ifp && IS_ZEBRA_IF_GRE(ifp) && zebra_if) {
+ gre_info = &zebra_if->l2info.gre;
+
+ stream_putl(s, idx);
+ stream_putl(s, gre_info->ikey);
+ stream_putl(s, gre_info->ikey);
+ stream_putl(s, gre_info->ifindex_link);
+
+ ifp_link = if_lookup_by_index_per_ns(
+ zebra_ns_lookup(gre_info->link_nsid),
+ gre_info->ifindex_link);
+ if (ifp_link)
+ vrf_id_link = ifp_link->vrf_id;
+ stream_putl(s, vrf_id_link);
+ stream_putl(s, gre_info->vtep_ip.s_addr);
+ stream_putl(s, gre_info->vtep_ip_remote.s_addr);
+ } else {
+ stream_putl(s, idx);
+ stream_putl(s, 0);
+ stream_putl(s, 0);
+ stream_putl(s, IFINDEX_INTERNAL);
+ stream_putl(s, VRF_UNKNOWN);
+ stream_putl(s, 0);
+ }
+ /* Write packet size. */
+ stream_putw_at(s, 0, stream_get_endp(s));
+ zserv_send_message(client, s);
+
+ return;
+ stream_failure:
+ return;
+}
+
static inline void zebra_configure_arp(ZAPI_HANDLER_ARGS)
{
struct stream *s;
return;
}
+static inline void zebra_gre_source_set(ZAPI_HANDLER_ARGS)
+{
+ struct stream *s;
+ ifindex_t idx, link_idx;
+ vrf_id_t link_vrf_id;
+ struct interface *ifp;
+ struct interface *ifp_link;
+ vrf_id_t vrf_id = zvrf->vrf->vrf_id;
+ struct zebra_if *zif, *gre_zif;
+ struct zebra_l2info_gre *gre_info;
+ unsigned int mtu;
+
+ s = msg;
+ STREAM_GETL(s, idx);
+ ifp = if_lookup_by_index(idx, vrf_id);
+ STREAM_GETL(s, link_idx);
+ STREAM_GETL(s, link_vrf_id);
+ STREAM_GETL(s, mtu);
+
+ ifp_link = if_lookup_by_index(link_idx, link_vrf_id);
+ if (!ifp_link || !ifp) {
+ zlog_warn("GRE (index %u, VRF %u) or GRE link interface (index %u, VRF %u) not found, when setting GRE params",
+ idx, vrf_id, link_idx, link_vrf_id);
+ return;
+ }
+
+ if (!IS_ZEBRA_IF_GRE(ifp))
+ return;
+
+ gre_zif = (struct zebra_if *)ifp->info;
+ zif = (struct zebra_if *)ifp_link->info;
+ if (!zif || !gre_zif)
+ return;
+
+ gre_info = &zif->l2info.gre;
+ if (!gre_info)
+ return;
+
+ if (!mtu)
+ mtu = ifp->mtu;
+
+ /* if gre link already set or mtu did not change, do not set it */
+ if (gre_zif->link && gre_zif->link == ifp_link && mtu == ifp->mtu)
+ return;
+
+ dplane_gre_set(ifp, ifp_link, mtu, gre_info);
+
+ stream_failure:
+ return;
+}
+
static void zsend_error_msg(struct zserv *client, enum zebra_error_types error,
struct zmsghdr *bad_hdr)
{
[ZEBRA_NHRP_NEIGH_REGISTER] = zebra_neigh_register,
[ZEBRA_NHRP_NEIGH_UNREGISTER] = zebra_neigh_unregister,
[ZEBRA_CONFIGURE_ARP] = zebra_configure_arp,
+ [ZEBRA_GRE_GET] = zebra_gre_get,
+ [ZEBRA_GRE_SOURCE_SET] = zebra_gre_source_set,
};
/*
struct dplane_ctx_rule old;
};
+struct dplane_gre_ctx {
+ uint32_t link_ifindex;
+ unsigned int mtu;
+ struct zebra_l2info_gre info;
+};
/*
* The context block used to exchange info about route updates across
* the boundary between the zebra main context (and pthread) and the
struct zebra_pbr_ipset_info info;
} ipset_entry;
struct dplane_neigh_table neightable;
+ struct dplane_gre_ctx gre;
} u;
/* Namespace info, used especially for netlink kernel communication */
_Atomic uint32_t dg_neightable_in;
_Atomic uint32_t dg_neightable_errors;
+ _Atomic uint32_t dg_gre_set_in;
+ _Atomic uint32_t dg_gre_set_errors;
+
/* Dataplane pthread */
struct frr_pthread *dg_pthread;
}
list_delete(&ctx->u.iptable.interface_name_list);
}
+ break;
+ case DPLANE_OP_GRE_SET:
+ break;
}
}
case DPLANE_OP_NEIGH_TABLE_UPDATE:
ret = "NEIGH_TABLE_UPDATE";
break;
+
+ case DPLANE_OP_GRE_SET:
+ ret = "GRE_SET";
+ break;
}
return ret;
return ctx->u.neigh.update_flags;
}
+/* Accessor for GRE set */
+uint32_t
+dplane_ctx_gre_get_link_ifindex(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.gre.link_ifindex;
+}
+
+unsigned int
+dplane_ctx_gre_get_mtu(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.gre.mtu;
+}
+
+const struct zebra_l2info_gre *
+dplane_ctx_gre_get_info(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return &ctx->u.gre.info;
+}
+
/* Accessors for PBR rule information */
int dplane_ctx_rule_get_sock(const struct zebra_dplane_ctx *ctx)
{
return ipset_entry_update_internal(DPLANE_OP_IPSET_ENTRY_DELETE, ipset);
}
+/*
+ * Common helper api for GRE set
+ */
+enum zebra_dplane_result
+dplane_gre_set(struct interface *ifp, struct interface *ifp_link,
+ unsigned int mtu, const struct zebra_l2info_gre *gre_info)
+{
+ enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
+ struct zebra_dplane_ctx *ctx;
+ enum dplane_op_e op = DPLANE_OP_GRE_SET;
+ int ret;
+ struct zebra_ns *zns;
+
+ ctx = dplane_ctx_alloc();
+
+ if (!ifp)
+ return result;
+
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
+ zlog_debug("init dplane ctx %s: if %s link %s%s",
+ dplane_op2str(op), ifp->name,
+ ifp_link ? "set" : "unset", ifp_link ?
+ ifp_link->name : "");
+ }
+
+ ctx->zd_op = op;
+ ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
+ zns = zebra_ns_lookup(ifp->vrf_id);
+ if (!zns)
+ return result;
+ dplane_ctx_ns_init(ctx, zns, false);
+
+ dplane_ctx_set_ifname(ctx, ifp->name);
+ ctx->zd_vrf_id = ifp->vrf_id;
+ ctx->zd_ifindex = ifp->ifindex;
+ if (ifp_link)
+ ctx->u.gre.link_ifindex = ifp_link->ifindex;
+ else
+ ctx->u.gre.link_ifindex = 0;
+ if (gre_info)
+ memcpy(&ctx->u.gre.info, gre_info, sizeof(ctx->u.gre.info));
+ ctx->u.gre.mtu = mtu;
+
+ ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
+
+ /* Enqueue context for processing */
+ ret = dplane_update_enqueue(ctx);
+
+ /* Update counter */
+ atomic_fetch_add_explicit(&zdplane_info.dg_gre_set_in, 1,
+ memory_order_relaxed);
+
+ if (ret == AOK)
+ result = ZEBRA_DPLANE_REQUEST_QUEUED;
+ else {
+ atomic_fetch_add_explicit(
+ &zdplane_info.dg_gre_set_errors, 1,
+ memory_order_relaxed);
+ if (ctx)
+ dplane_ctx_free(&ctx);
+ result = ZEBRA_DPLANE_REQUEST_FAILURE;
+ }
+ return result;
+}
+
/*
* Handler for 'show dplane'
*/
memory_order_relaxed);
vty_out(vty, "Neighbor Table updates: %"PRIu64"\n", incoming);
vty_out(vty, "Neighbor Table errors: %"PRIu64"\n", errs);
+
+ incoming = atomic_load_explicit(&zdplane_info.dg_gre_set_in,
+ memory_order_relaxed);
+ errs = atomic_load_explicit(&zdplane_info.dg_gre_set_errors,
+ memory_order_relaxed);
+ vty_out(vty, "GRE set updates: %"PRIu64"\n", incoming);
+ vty_out(vty, "GRE set errors: %"PRIu64"\n", errs);
return CMD_SUCCESS;
}
dplane_ctx_get_ifname(ctx),
family2str(dplane_ctx_neightable_get_family(ctx)));
break;
+ case DPLANE_OP_GRE_SET:
+ zlog_debug("Dplane gre set op %s, ifp %s, link %u",
+ dplane_op2str(dplane_ctx_get_op(ctx)),
+ dplane_ctx_get_ifname(ctx),
+ ctx->u.gre.link_ifindex);
+ break;
}
}
memory_order_relaxed);
break;
+ case DPLANE_OP_GRE_SET:
+ if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
+ atomic_fetch_add_explicit(
+ &zdplane_info.dg_gre_set_errors, 1,
+ memory_order_relaxed);
+ break;
/* Ignore 'notifications' - no-op */
case DPLANE_OP_SYS_ROUTE_ADD:
case DPLANE_OP_SYS_ROUTE_DELETE:
DPLANE_OP_NEIGH_IP_DELETE,
DPLANE_OP_NEIGH_TABLE_UPDATE,
+ DPLANE_OP_GRE_SET,
};
/*
uint32_t
dplane_ctx_neightable_get_ucast_probes(const struct zebra_dplane_ctx *ctx);
+/* Accessor for GRE set */
+uint32_t
+dplane_ctx_gre_get_link_ifindex(const struct zebra_dplane_ctx *ctx);
+unsigned int
+dplane_ctx_gre_get_mtu(const struct zebra_dplane_ctx *ctx);
+const struct zebra_l2info_gre *
+dplane_ctx_gre_get_info(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);
const uint32_t ucast_probes,
const uint32_t mcast_probes);
+/*
+ * Enqueue a GRE set
+ */
+enum zebra_dplane_result
+dplane_gre_set(struct interface *ifp, struct interface *ifp_link,
+ unsigned int mtu, const struct zebra_l2info_gre *gre_info);
+
/* Forward ref of zebra_pbr_rule */
struct zebra_pbr_rule;
EC_ZEBRA_DUPLICATE_NHG_MESSAGE,
EC_ZEBRA_VRF_MISCONFIGURED,
EC_ZEBRA_ES_CREATE,
+ EC_ZEBRA_GRE_SET_UPDATE,
};
void zebra_error_init(void);
*/
zebra_evpn_t *zebra_evpn_add(vni_t vni)
{
+ char buffer[80];
struct zebra_vrf *zvrf;
zebra_evpn_t tmp_zevpn;
zebra_evpn_t *zevpn = NULL;
zebra_evpn_es_evi_init(zevpn);
+ snprintf(buffer, sizeof(buffer), "Zebra EVPN MAC Table vni: %u", vni);
/* Create hash table for MAC */
- zevpn->mac_table = zebra_mac_db_create("Zebra EVPN MAC Table");
+ zevpn->mac_table = zebra_mac_db_create(buffer);
+ snprintf(buffer, sizeof(buffer), "Zebra EVPN Neighbor Table vni: %u",
+ vni);
/* Create hash table for neighbors */
- zevpn->neigh_table = zebra_neigh_db_create("Zebra EVPN Neighbor Table");
+ zevpn->neigh_table = zebra_neigh_db_create(buffer);
return zevpn;
}
*/
struct hash *zebra_mac_db_create(const char *desc)
{
- return hash_create(mac_hash_keymake, mac_cmp, desc);
+ return hash_create_size(8, mac_hash_keymake, mac_cmp, desc);
}
/* program sync mac flags in the dataplane */
memset(&esi, 0, sizeof(esi_t));
s = msg;
- stream_get(&esi, s, sizeof(esi_t));
- vtep_ip.s_addr = stream_get_ipv4(s);
+ STREAM_GET(&esi, s, sizeof(esi_t));
+ STREAM_GET(&vtep_ip.s_addr, s, sizeof(vtep_ip.s_addr));
if (hdr->command == ZEBRA_REMOTE_ES_VTEP_ADD) {
uint32_t zapi_flags;
uint16_t df_pref;
bool esr_rxed;
- zapi_flags = stream_getl(s);
+ STREAM_GETL(s, zapi_flags);
esr_rxed = (zapi_flags & ZAPI_ES_VTEP_FLAG_ESR_RXED) ? true
: false;
- df_alg = stream_getc(s);
- df_pref = stream_getw(s);
+ STREAM_GETC(s, df_alg);
+ STREAM_GETW(s, df_pref);
zebra_evpn_remote_es_add(&esi, vtep_ip, esr_rxed, df_alg,
df_pref);
} else {
zebra_evpn_remote_es_del(&esi, vtep_ip);
}
+
+stream_failure:
+ return;
}
void zebra_evpn_es_mac_deref_entry(zebra_mac_t *mac)
struct hash *zebra_neigh_db_create(const char *desc)
{
- return hash_create(neigh_hash_keymake, neigh_cmp, desc);
+ return hash_create_size(8, neigh_hash_keymake, neigh_cmp, desc);
}
uint32_t num_dup_detected_neighs(zebra_evpn_t *zevpn)
#include "thread.h"
#include "network.h"
#include "command.h"
-#include "version.h"
+#include "lib/version.h"
#include "jhash.h"
#include "zebra/rib.h"
memcpy(&zif->l2info.vl, vlan_info, sizeof(*vlan_info));
}
+/*
+ * Update L2 info for a GRE interface. This is called upon interface
+ * addition as well as update. Upon add/update, need to inform
+ * clients about GRE information.
+ */
+void zebra_l2_greif_add_update(struct interface *ifp,
+ struct zebra_l2info_gre *gre_info, int add)
+{
+ struct zebra_if *zif;
+ struct in_addr old_vtep_ip;
+
+ zif = ifp->info;
+ assert(zif);
+
+ if (add) {
+ memcpy(&zif->l2info.gre, gre_info, sizeof(*gre_info));
+ return;
+ }
+
+ old_vtep_ip = zif->l2info.gre.vtep_ip;
+ if (IPV4_ADDR_SAME(&old_vtep_ip, &gre_info->vtep_ip))
+ return;
+
+ zif->l2info.gre.vtep_ip = gre_info->vtep_ip;
+}
+
/*
* Update L2 info for a VxLAN interface. This is called upon interface
* addition as well as update. Upon add, need to invoke the VNI create
vlanid_t vid; /* VLAN id */
};
+/* zebra L2 interface information - GRE interface */
+struct zebra_l2info_gre {
+ struct in_addr vtep_ip; /* IFLA_GRE_LOCAL */
+ struct in_addr vtep_ip_remote; /* IFLA_GRE_REMOTE */
+ uint32_t ikey;
+ uint32_t okey;
+ ifindex_t ifindex_link; /* Interface index of interface
+ * linked with GRE
+ */
+ ns_id_t link_nsid;
+};
+
/* zebra L2 interface information - VXLAN interface */
struct zebra_l2info_vxlan {
vni_t vni; /* VNI */
struct zebra_l2info_bridge br;
struct zebra_l2info_vlan vl;
struct zebra_l2info_vxlan vxl;
+ struct zebra_l2info_gre gre;
};
/* NOTE: These macros are to be invoked only in the "correct" context.
extern void zebra_l2_bridge_del(struct interface *ifp);
extern void zebra_l2_vlanif_update(struct interface *ifp,
struct zebra_l2info_vlan *vlan_info);
+extern void zebra_l2_greif_add_update(struct interface *ifp,
+ struct zebra_l2info_gre *vxlan_info,
+ int add);
extern void zebra_l2_vxlanif_add_update(struct interface *ifp,
struct zebra_l2info_vxlan *vxlan_info,
int add);
extern void zebra_l2_vxlanif_update_access_vlan(struct interface *ifp,
vlanid_t access_vlan);
+extern void zebra_l2_greif_del(struct interface *ifp);
extern void zebra_l2_vxlanif_del(struct interface *ifp);
extern void zebra_l2if_update_bridge_slave(struct interface *ifp,
ifindex_t bridge_ifindex,
#include "thread.h"
#include "frr_pthread.h"
#include "libfrr.h"
-#include "version.h"
+#include "lib/version.h"
#include "network.h"
#include "lib/stream.h"
int start_count = 0, end_count = 0; /* Installed counts */
bool changed_p = false;
bool is_debug = (IS_ZEBRA_DEBUG_DPLANE | IS_ZEBRA_DEBUG_MPLS);
+ enum zebra_sr_policy_update_label_mode update_mode;
if (is_debug)
zlog_debug("LSP dplane notif, in-label %u",
if (end_count > 0) {
SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
+ /* SR-TE update too */
+ if (start_count == 0)
+ update_mode = ZEBRA_SR_POLICY_LABEL_CREATED;
+ else
+ update_mode = ZEBRA_SR_POLICY_LABEL_UPDATED;
+ zebra_sr_policy_label_update(lsp->ile.in_label, update_mode);
+
if (changed_p)
dplane_lsp_notif_update(lsp, DPLANE_OP_LSP_UPDATE, ctx);
} else {
+ /* SR-TE update too */
+ zebra_sr_policy_label_update(lsp->ile.in_label,
+ ZEBRA_SR_POLICY_LABEL_REMOVED);
+
UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
clear_nhlfe_installed(lsp);
}
*/
void zebra_mpls_init_tables(struct zebra_vrf *zvrf)
{
+ char buffer[80];
+
if (!zvrf)
return;
- zvrf->slsp_table =
- hash_create(label_hash, label_cmp, "ZEBRA SLSP table");
- zvrf->lsp_table = hash_create(label_hash, label_cmp, "ZEBRA LSP table");
+
+ snprintf(buffer, sizeof(buffer), "ZEBRA SLSP table: %s",
+ zvrf->vrf->name);
+ zvrf->slsp_table = hash_create_size(8, label_hash, label_cmp, buffer);
+
+ snprintf(buffer, sizeof(buffer), "ZEBRA LSP table: %s",
+ zvrf->vrf->name);
+ zvrf->lsp_table = hash_create_size(8, label_hash, label_cmp, buffer);
zvrf->fec_table[AFI_IP] = route_table_init();
zvrf->fec_table[AFI_IP6] = route_table_init();
zvrf->mpls_flags = 0;
stream_put_in_addr(s, &mroute.sg.src);
stream_put_in_addr(s, &mroute.sg.grp);
stream_put(s, &mroute.lastused, sizeof(mroute.lastused));
- stream_putl(s, suc);
+ stream_putl(s, (uint32_t)suc);
stream_putw_at(s, 0, stream_get_endp(s));
zserv_send_message(client, s);
SET_FLAG(backup_nhe->flags, NEXTHOP_GROUP_RECURSIVE);
done:
+ /* Reset time since last update */
+ (*nhe)->uptime = monotime(NULL);
return created;
}
return new;
}
-static void nhg_ctx_free(struct nhg_ctx **ctx)
+void nhg_ctx_free(struct nhg_ctx **ctx)
{
struct nexthop *nh;
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
zlog_debug("%s: nhe %p (%u) is new", __func__, nhe, nhe->id);
+ /*
+ * If daemon nhg from the kernel, add a refcnt here to indicate the
+ * daemon owns it.
+ */
+ if (PROTO_OWNED(nhe))
+ zebra_nhg_increment_ref(nhe);
+
SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
if (nhg_ctx_get_status(ctx) == NHG_CTX_QUEUED)
return 0;
- if (rib_queue_nhg_add(ctx)) {
+ if (rib_queue_nhg_ctx_add(ctx)) {
nhg_ctx_set_status(ctx, NHG_CTX_FAILURE);
return -1;
}
int i, j, idx;
const struct nexthop *bnh;
struct nexthop *nh, *newnh;
+ mpls_label_t labels[MPLS_MAX_LABELS];
+ uint8_t num_labels;
assert(nexthop->backup_num <= NEXTHOP_MAX_BACKUPS);
- if (resolve_nhe->backup_info->nhe == NULL)
- resolve_nhe->backup_info->nhe = zebra_nhg_alloc();
-
/* Locate backups from the original nexthop's backup index and nhe */
for (i = 0; i < nexthop->backup_num; i++) {
idx = nexthop->backup_idx[i];
map->map[j].new_idx;
resolved->backup_num++;
+ SET_FLAG(resolved->flags, NEXTHOP_FLAG_HAS_BACKUP);
+
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug("%s: found map idx orig %d, new %d",
__func__, map->map[j].orig_idx,
if (bnh == NULL)
continue;
+ if (resolve_nhe->backup_info == NULL)
+ resolve_nhe->backup_info = zebra_nhg_backup_alloc();
+
/* Update backup info in the resolving nexthop and its nhe */
newnh = nexthop_dup_no_recurse(bnh, NULL);
+ /* We may need some special handling for mpls labels: the new
+ * backup needs to carry the recursive nexthop's labels,
+ * if any: they may be vrf labels e.g.
+ * The original/inner labels are in the stack of 'resolve_nhe',
+ * if that is longer than the stack in 'nexthop'.
+ */
+ if (newnh->nh_label && resolved->nh_label &&
+ nexthop->nh_label) {
+ if (resolved->nh_label->num_labels >
+ nexthop->nh_label->num_labels) {
+ /* Prepare new label stack */
+ num_labels = 0;
+ for (j = 0; j < newnh->nh_label->num_labels;
+ j++) {
+ labels[j] = newnh->nh_label->label[j];
+ num_labels++;
+ }
+
+ /* Include inner labels */
+ for (j = nexthop->nh_label->num_labels;
+ j < resolved->nh_label->num_labels;
+ j++) {
+ labels[num_labels] =
+ resolved->nh_label->label[j];
+ num_labels++;
+ }
+
+ /* Replace existing label stack in the backup */
+ nexthop_del_labels(newnh);
+ nexthop_add_labels(newnh, bnh->nh_label_type,
+ num_labels, labels);
+ }
+ }
+
/* Need to compute the new backup index in the new
* backup list, and add to map struct.
*/
}
nh->next = newnh;
+ j++;
} else /* First one */
resolve_nhe->backup_info->nhe->nhg.nexthop = newnh;
resolved->backup_idx[resolved->backup_num] = j;
resolved->backup_num++;
+ SET_FLAG(resolved->flags, NEXTHOP_FLAG_HAS_BACKUP);
+
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug("%s: added idx orig %d, new %d",
__func__, idx, j);
struct nhg_hash_entry *curr_nhe;
uint32_t curr_active = 0, backup_active = 0;
- if (re->nhe->id >= ZEBRA_NHG_PROTO_LOWER)
+ if (PROTO_OWNED(re->nhe))
return proto_nhg_nexthop_active_update(&re->nhe->nhg);
afi_t rt_afi = family2afi(rn->p.family);
zebra_nhg_handle_install(nhe);
/* If daemon nhg, send it an update */
- if (nhe->id >= ZEBRA_NHG_PROTO_LOWER)
+ if (PROTO_OWNED(nhe))
zsend_nhg_notify(nhe->type, nhe->zapi_instance,
nhe->zapi_session, nhe->id,
ZAPI_NHG_INSTALLED);
} else {
/* If daemon nhg, send it an update */
- if (nhe->id >= ZEBRA_NHG_PROTO_LOWER)
+ if (PROTO_OWNED(nhe))
zsend_nhg_notify(nhe->type, nhe->zapi_instance,
nhe->zapi_session, nhe->id,
ZAPI_NHG_FAIL_INSTALL);
case DPLANE_OP_IPSET_ENTRY_ADD:
case DPLANE_OP_IPSET_ENTRY_DELETE:
case DPLANE_OP_NEIGH_TABLE_UPDATE:
+ case DPLANE_OP_GRE_SET:
break;
}
nhe = (struct nhg_hash_entry *)bucket->data;
- /* If its being ref'd, just let it be uninstalled via a route removal */
+ /*
+ * same logic as with routes.
+ *
+ * If older than startup time, we know we read them in from the
+ * kernel and have not gotten and update for them since startup
+ * from an upper level proto.
+ */
+ if (zrouter.startup_time < nhe->uptime)
+ return;
+
+ /*
+ * If it's proto-owned and not being used by a route, remove it since
+ * we haven't gotten an update about it from the proto since startup.
+ * This means that either the config for it was removed or the daemon
+ * didn't get started. This handles graceful restart & retain scenario.
+ */
+ if (PROTO_OWNED(nhe) && nhe->refcnt == 1) {
+ zebra_nhg_decrement_ref(nhe);
+ return;
+ }
+
+ /*
+ * If its being ref'd by routes, just let it be uninstalled via a route
+ * removal.
+ */
if (ZEBRA_NHG_CREATED(nhe) && nhe->refcnt <= 0)
zebra_nhg_uninstall_kernel(nhe);
}
iter = arg;
/* Needs to match type and outside zebra ID space */
- if (nhe->type == iter->type && nhe->id >= ZEBRA_NHG_PROTO_LOWER) {
+ if (nhe->type == iter->type && PROTO_OWNED(nhe)) {
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
zlog_debug(
"%s: found nhe %p (%u), vrf %d, type %s after client disconnect",
afi_t afi;
vrf_id_t vrf_id;
+ /* Time since last update */
+ time_t uptime;
+
/* Source protocol - zebra or another daemon */
int type;
/* Is this an NHE owned by zebra and not an upper level protocol? */
#define ZEBRA_OWNED(NHE) (NHE->type == ZEBRA_ROUTE_NHG)
+#define PROTO_OWNED(NHE) (NHE->id >= ZEBRA_NHG_PROTO_LOWER)
+
/*
* Backup nexthops: this is a group object itself, so
* that the backup nexthops can use the same code as a normal object.
* the rib meta queue.
*/
extern int nhg_ctx_process(struct nhg_ctx *ctx);
+void nhg_ctx_free(struct nhg_ctx **ctx);
/* Find via kernel nh creation */
extern int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh,
#include "ptm_lib.h"
#include "rib.h"
#include "stream.h"
-#include "version.h"
+#include "lib/version.h"
#include "vrf.h"
#include "vty.h"
#include "lib_errors.h"
DEFINE_MTYPE(ZEBRA, RE, "Route Entry");
DEFINE_MTYPE_STATIC(ZEBRA, RIB_DEST, "RIB destination");
DEFINE_MTYPE_STATIC(ZEBRA, RIB_UPDATE_CTX, "Rib update context object");
+DEFINE_MTYPE_STATIC(ZEBRA, WQ_NHG_WRAPPER, "WQ nhg wrapper");
/*
* Event, list, and mutex for delivery of dataplane results
/* no entry/default: 150 */
};
+/* Wrapper struct for nhg workqueue items; a 'ctx' is an incoming update
+ * from the OS, and an 'nhe' is a nhe update.
+ */
+struct wq_nhg_wrapper {
+ int type;
+ union {
+ struct nhg_ctx *ctx;
+ struct nhg_hash_entry *nhe;
+ } u;
+};
+
+#define WQ_NHG_WRAPPER_TYPE_CTX 0x01
+#define WQ_NHG_WRAPPER_TYPE_NHG 0x02
+
static void PRINTFRR(5, 6)
_rnode_zlog(const char *_func, vrf_id_t vrf_id, struct route_node *rn,
int priority, const char *msgfmt, ...)
if (nh_active) {
if (IS_ZEBRA_DEBUG_RIB) {
char buf[SRCDEST2STR_BUFFER];
+
srcdest_rnode2str(rn, buf, sizeof(buf));
if (new != old)
zlog_debug(
return current;
}
-/* Core function for processing nexthop group contexts's off metaq */
-static void rib_nhg_process(struct nhg_ctx *ctx)
-{
- nhg_ctx_process(ctx);
-}
-
/* Core function for processing routing information base. */
static void rib_process(struct route_node *rn)
{
dplane_ctx_fini(&ctx);
}
+/*
+ * Process the nexthop-group workqueue subqueue
+ */
static void process_subq_nhg(struct listnode *lnode)
{
- struct nhg_ctx *ctx = NULL;
+ struct nhg_ctx *ctx;
+ struct nhg_hash_entry *nhe, *newnhe;
+ struct wq_nhg_wrapper *w;
uint8_t qindex = route_info[ZEBRA_ROUTE_NHG].meta_q_map;
- ctx = listgetdata(lnode);
+ w = listgetdata(lnode);
- if (!ctx)
+ if (!w)
return;
- if (IS_ZEBRA_DEBUG_RIB_DETAILED)
- zlog_debug("NHG Context id=%u dequeued from sub-queue %u",
- ctx->id, qindex);
+ /* Two types of object - an update from the local kernel, or
+ * an nhg update from a daemon.
+ */
+ if (w->type == WQ_NHG_WRAPPER_TYPE_CTX) {
+ ctx = w->u.ctx;
+
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+ zlog_debug(
+ "NHG Context id=%u dequeued from sub-queue %u",
+ ctx->id, qindex);
+
+
+ /* Process nexthop group updates coming 'up' from the OS */
+ nhg_ctx_process(ctx);
- rib_nhg_process(ctx);
+ } else if (w->type == WQ_NHG_WRAPPER_TYPE_NHG) {
+ nhe = w->u.nhe;
+
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+ zlog_debug("NHG %u dequeued from sub-queue %u",
+ nhe->id, qindex);
+
+ /* Process incoming nhg update, probably from a proto daemon */
+ newnhe = zebra_nhg_proto_add(nhe->id, nhe->type,
+ nhe->zapi_instance,
+ nhe->zapi_session,
+ &nhe->nhg, 0);
+
+ /* Report error to daemon via ZAPI */
+ if (newnhe == NULL)
+ zsend_nhg_notify(nhe->type, nhe->zapi_instance,
+ nhe->zapi_session, nhe->id,
+ ZAPI_NHG_FAIL_INSTALL);
+
+ /* Free temp nhe - we own that memory. */
+ zebra_nhg_free(nhe);
+ }
+
+ XFREE(MTYPE_WQ_NHG_WRAPPER, w);
}
static void process_subq_route(struct listnode *lnode, uint8_t qindex)
srcdest_rnode2str(rnode, buf, sizeof(buf));
zlog_debug("%s(%u:%u):%s: rn %p dequeued from sub-queue %u",
- zvrf_name(zvrf), zvrf_id(zvrf), re ? re->table : 0, buf,
- rnode, qindex);
+ zvrf_name(zvrf), zvrf_id(zvrf), re ? re->table : 0,
+ buf, rnode, qindex);
}
if (rnode->info)
/* Dispatch the meta queue by picking, processing and unlocking the next RN from
* a non-empty sub-queue with lowest priority. wq is equal to zebra->ribq and
- * data
- * is pointed to the meta queue structure.
+ * data is pointed to the meta queue structure.
*/
static wq_item_status meta_queue_process(struct work_queue *dummy, void *data)
{
return 0;
}
-static int rib_meta_queue_nhg_add(struct meta_queue *mq, void *data)
+static int rib_meta_queue_nhg_ctx_add(struct meta_queue *mq, void *data)
{
struct nhg_ctx *ctx = NULL;
uint8_t qindex = route_info[ZEBRA_ROUTE_NHG].meta_q_map;
+ struct wq_nhg_wrapper *w;
ctx = (struct nhg_ctx *)data;
if (!ctx)
return -1;
- listnode_add(mq->subq[qindex], ctx);
+ w = XCALLOC(MTYPE_WQ_NHG_WRAPPER, sizeof(struct wq_nhg_wrapper));
+
+ w->type = WQ_NHG_WRAPPER_TYPE_CTX;
+ w->u.ctx = ctx;
+
+ listnode_add(mq->subq[qindex], w);
mq->size++;
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
return 0;
}
+static int rib_meta_queue_nhg_add(struct meta_queue *mq, void *data)
+{
+ struct nhg_hash_entry *nhe = NULL;
+ uint8_t qindex = route_info[ZEBRA_ROUTE_NHG].meta_q_map;
+ struct wq_nhg_wrapper *w;
+
+ nhe = (struct nhg_hash_entry *)data;
+
+ if (!nhe)
+ return -1;
+
+ w = XCALLOC(MTYPE_WQ_NHG_WRAPPER, sizeof(struct wq_nhg_wrapper));
+
+ w->type = WQ_NHG_WRAPPER_TYPE_NHG;
+ w->u.nhe = nhe;
+
+ listnode_add(mq->subq[qindex], w);
+ mq->size++;
+
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+ zlog_debug("NHG id=%u queued into sub-queue %u",
+ nhe->id, qindex);
+
+ return 0;
+}
+
static int mq_add_handler(void *data,
int (*mq_add_func)(struct meta_queue *mq, void *data))
{
return -1;
}
- return mq_add_handler(rn, &rib_meta_queue_add);
+ return mq_add_handler(rn, rib_meta_queue_add);
}
-int rib_queue_nhg_add(struct nhg_ctx *ctx)
+/*
+ * Enqueue incoming nhg info from OS for processing
+ */
+int rib_queue_nhg_ctx_add(struct nhg_ctx *ctx)
{
assert(ctx);
- return mq_add_handler(ctx, &rib_meta_queue_nhg_add);
+ return mq_add_handler(ctx, rib_meta_queue_nhg_ctx_add);
+}
+
+/*
+ * Enqueue incoming nhg from proto daemon for processing
+ */
+int rib_queue_nhe_add(struct nhg_hash_entry *nhe)
+{
+ if (nhe == NULL)
+ return -1;
+
+ return mq_add_handler(nhe, rib_meta_queue_nhg_add);
+}
+
+/* Clean up the nhg meta-queue list */
+static void nhg_meta_queue_free(struct list *l)
+{
+ struct wq_nhg_wrapper *w;
+ struct listnode *node;
+
+ /* Free the node wrapper object, and the struct it wraps */
+ while ((node = listhead(l)) != NULL) {
+ w = node->data;
+ node->data = NULL;
+
+ if (w->type == WQ_NHG_WRAPPER_TYPE_CTX)
+ nhg_ctx_free(&w->u.ctx);
+ else if (w->type == WQ_NHG_WRAPPER_TYPE_NHG)
+ zebra_nhg_free(w->u.nhe);
+
+ XFREE(MTYPE_WQ_NHG_WRAPPER, w);
+
+ list_delete_node(l, node);
+ }
}
/* Create new meta queue.
{
unsigned i;
- for (i = 0; i < MQ_SIZE; i++)
+ for (i = 0; i < MQ_SIZE; i++) {
+ /* Some subqueues may need cleanup - nhgs for example */
+ if (i == route_info[ZEBRA_ROUTE_NHG].meta_q_map)
+ nhg_meta_queue_free(mq->subq[i]);
+
list_delete(&mq->subq[i]);
+ }
XFREE(MTYPE_WORK_QUEUE, mq);
}
char backup_str[50];
char wgt_str[50];
char temp_str[10];
+ char label_str[MPLS_LABEL_STRLEN];
int i;
struct interface *ifp;
struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id);
break;
}
+ /* Label stack */
+ label_str[0] = '\0';
+ if (nexthop->nh_label && nexthop->nh_label->num_labels > 0) {
+ mpls_label2str(nexthop->nh_label->num_labels,
+ nexthop->nh_label->label, label_str,
+ sizeof(label_str), 0 /*pretty*/);
+ strlcat(label_str, ", ", sizeof(label_str));
+ }
+
backup_str[0] = '\0';
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
snprintf(backup_str, sizeof(backup_str), "backup ");
if (nexthop->weight)
snprintf(wgt_str, sizeof(wgt_str), "wgt %d,", nexthop->weight);
- zlog_debug("%s: %s %s[%u] vrf %s(%u) %s%s with flags %s%s%s%s%s%s%s%s",
+ zlog_debug("%s: %s %s[%u] %svrf %s(%u) %s%s with flags %s%s%s%s%s%s%s%s",
straddr, (nexthop->rparent ? " NH" : "NH"), nhname,
- nexthop->ifindex, vrf ? vrf->name : "Unknown",
+ nexthop->ifindex, label_str, vrf ? vrf->name : "Unknown",
nexthop->vrf_id,
wgt_str, backup_str,
(CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)
case DPLANE_OP_NEIGH_DISCOVER:
case DPLANE_OP_BR_PORT_UPDATE:
case DPLANE_OP_NEIGH_TABLE_UPDATE:
+ case DPLANE_OP_GRE_SET:
case DPLANE_OP_NONE:
/* Don't expect this: just return the struct? */
dplane_ctx_fini(&ctx);
#include "plist.h"
#include "nexthop.h"
#include "northbound_cli.h"
-#include "route_types.h"
+#include "lib/route_types.h"
#include "vrf.h"
#include "frrstr.h"
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <zebra.h>
+
#include "northbound.h"
#include "libfrr.h"
#include "zebra_routemap_nb.h"
#include "vrf.h"
#include "hook.h"
#include "libfrr.h"
-#include "version.h"
+#include "lib/version.h"
#include "zebra/rib.h"
#include "zebra/zserv.h"
if (IS_ZEBRA_DEBUG_EVENT)
zlog_debug("VRF %s created, id %u", vrf->name, vrf->vrf_id);
- zvrf = zebra_vrf_alloc();
- vrf->info = zvrf;
- zvrf->vrf = vrf;
+ zvrf = zebra_vrf_alloc(vrf);
if (!vrf_is_backend_netns())
zvrf->zns = zebra_ns_lookup(NS_DEFAULT);
}
/* Allocate new zebra VRF. */
-struct zebra_vrf *zebra_vrf_alloc(void)
+struct zebra_vrf *zebra_vrf_alloc(struct vrf *vrf)
{
struct zebra_vrf *zvrf;
zvrf = XCALLOC(MTYPE_ZEBRA_VRF, sizeof(struct zebra_vrf));
+ zvrf->vrf = vrf;
+ vrf->info = zvrf;
+
zebra_vxlan_init_tables(zvrf);
zebra_mpls_init_tables(zvrf);
zebra_pw_init(zvrf);
extern void zebra_vrf_update_all(struct zserv *client);
extern struct zebra_vrf *zebra_vrf_lookup_by_id(vrf_id_t vrf_id);
extern struct zebra_vrf *zebra_vrf_lookup_by_name(const char *);
-extern struct zebra_vrf *zebra_vrf_alloc(void);
+extern struct zebra_vrf *zebra_vrf_alloc(struct vrf *vrf);
extern struct route_table *zebra_vrf_table(afi_t, safi_t, vrf_id_t);
extern void zebra_vrf_init(void);
}
}
+static void uptime2str(time_t uptime, char *buf, size_t bufsize)
+{
+ time_t cur;
+
+ cur = monotime(NULL);
+ cur -= uptime;
+
+ frrtime_to_interval(cur, buf, bufsize);
+}
+
/* New RIB. Detailed information for IPv4 route. */
static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
int mcast, bool use_fib, bool show_ng)
vty_out(vty, ", best");
vty_out(vty, "\n");
- time_t uptime;
-
- uptime = monotime(NULL);
- uptime -= re->uptime;
-
- frrtime_to_interval(uptime, buf, sizeof(buf));
+ uptime2str(re->uptime, buf, sizeof(buf));
vty_out(vty, " Last update %s ago\n", buf);
json_object *json_nexthops = NULL;
json_object *json_nexthop = NULL;
json_object *json_route = NULL;
- time_t uptime;
const rib_dest_t *dest = rib_dest_from_rnode(rn);
const struct nexthop_group *nhg;
char up_str[MONOTIME_STRLEN];
bool first_p = true;
bool nhg_from_backup = false;
- uptime = monotime(NULL);
- uptime -= re->uptime;
-
- frrtime_to_interval(uptime, up_str, sizeof(up_str));
+ uptime2str(re->uptime, up_str, sizeof(up_str));
/* If showing fib information, use the fib view of the
* nexthops.
struct nexthop *nexthop = NULL;
struct nhg_connected *rb_node_dep = NULL;
struct nexthop_group *backup_nhg;
+ char up_str[MONOTIME_STRLEN];
+
+ uptime2str(nhe->uptime, up_str, sizeof(up_str));
vty_out(vty, "ID: %u (%s)\n", nhe->id, zebra_route_string(nhe->type));
- vty_out(vty, " RefCnt: %d\n", nhe->refcnt);
+ vty_out(vty, " RefCnt: %u\n", nhe->refcnt);
+ vty_out(vty, " Uptime: %s\n", up_str);
vty_out(vty, " VRF: %s\n", vrf_id_to_name(nhe->vrf_id));
if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID)) {
memset(ip, 0, sizeof(*ip));
STREAM_GETL(s, *vni);
STREAM_GET(macaddr->octet, s, ETH_ALEN);
- STREAM_GETL(s, *ipa_len);
+ STREAM_GETW(s, *ipa_len);
if (*ipa_len) {
if (*ipa_len == IPV4_MAX_BYTELEN)
*/
void zebra_vxlan_init_tables(struct zebra_vrf *zvrf)
{
+ char buffer[80];
+
if (!zvrf)
return;
- zvrf->evpn_table =
- hash_create(zebra_evpn_hash_keymake, zebra_evpn_hash_cmp,
- "Zebra VRF EVPN Table");
- zvrf->vxlan_sg_table = hash_create(zebra_vxlan_sg_hash_key_make,
- zebra_vxlan_sg_hash_eq, "Zebra VxLAN SG Table");
+
+ snprintf(buffer, sizeof(buffer), "Zebra VRF EVPN Table: %s",
+ zvrf->vrf->name);
+ zvrf->evpn_table = hash_create_size(8, zebra_evpn_hash_keymake,
+ zebra_evpn_hash_cmp, buffer);
+
+ snprintf(buffer, sizeof(buffer), "Zebra VxLAN SG Table: %s",
+ zvrf->vrf->name);
+ zvrf->vxlan_sg_table = hash_create_size(8, zebra_vxlan_sg_hash_key_make,
+ zebra_vxlan_sg_hash_eq, buffer);
}
/* Cleanup EVPN info, but don't free the table. */
#include "lib/thread.h" /* for thread (ptr only), THREAD_ARG, ... */
#include "lib/vrf.h" /* for vrf_info_lookup, VRF_DEFAULT */
#include "lib/vty.h" /* for vty_out, vty (ptr only) */
-#include "lib/zassert.h" /* for assert */
#include "lib/zclient.h" /* for zmsghdr, ZEBRA_HEADER_SIZE, ZEBRA... */
#include "lib/frr_pthread.h" /* for frr_pthread_new, frr_pthread_stop... */
#include "lib/frratomic.h" /* for atomic_load_explicit, atomic_stor... */