summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--alpine/APKBUILD.in8
-rw-r--r--bgpd/bgp_attr.c5
-rw-r--r--bgpd/bgp_evpn.c3
-rw-r--r--bgpd/bgp_evpn_vty.c21
-rw-r--r--bgpd/bgp_label.c3
-rw-r--r--bgpd/bgp_mac.c4
-rw-r--r--bgpd/bgp_mplsvpn.c3
-rw-r--r--bgpd/bgp_rd.c7
-rw-r--r--bgpd/bgp_route.c34
-rw-r--r--bgpd/bgp_vty.c22
-rwxr-xr-xconfigure.ac4
-rw-r--r--debian/README.Debian2
-rw-r--r--doc/user/pim.rst7
-rw-r--r--docker/alpine/Dockerfile1
-rwxr-xr-xdocker/centos-8/build.sh2
-rw-r--r--isisd/isisd.c7
-rw-r--r--lib/if.c7
-rw-r--r--lib/ipaddr.h6
-rw-r--r--lib/yang.c1
-rw-r--r--lib/zclient.c11
-rw-r--r--pimd/pim_cmd.c40
-rw-r--r--pimd/pim_igmp.c6
-rw-r--r--pimd/pim_instance.h8
-rw-r--r--pimd/pim_msdp.c4
-rw-r--r--pimd/pim_nht.c5
-rw-r--r--pimd/pim_oil.c53
-rw-r--r--pimd/pim_oil.h9
-rw-r--r--pimd/pim_rp.c14
-rw-r--r--pimd/pim_upstream.c68
-rw-r--r--pimd/pim_upstream.h8
-rw-r--r--pimd/pim_zebra.c5
-rw-r--r--redhat/frr.spec.in2
-rw-r--r--vrrpd/subdir.am4
-rw-r--r--vrrpd/vrrp.c103
-rw-r--r--vrrpd/vrrp.h28
-rw-r--r--vrrpd/vrrp_main.c6
-rw-r--r--vrrpd/vrrp_northbound.c804
-rw-r--r--vrrpd/vrrp_vty.c335
-rw-r--r--vrrpd/vrrp_vty.h15
-rw-r--r--yang/frr-isisd.yang6
-rw-r--r--yang/frr-vrrpd.yang260
-rw-r--r--yang/subdir.am4
-rw-r--r--zebra/debug.c30
-rw-r--r--zebra/debug.h9
-rw-r--r--zebra/if_netlink.c6
-rw-r--r--zebra/kernel_netlink.c20
-rw-r--r--zebra/rt_netlink.c32
-rw-r--r--zebra/rtadv.c17
-rw-r--r--zebra/zapi_msg.c79
-rw-r--r--zebra/zebra_pbr.c13
-rw-r--r--zebra/zebra_ptm.c41
-rw-r--r--zebra/zebra_rib.c14
-rw-r--r--zebra/zebra_vty.c3
-rw-r--r--zebra/zebra_vxlan.c99
-rw-r--r--zebra/zebra_vxlan_private.h6
55 files changed, 1709 insertions, 605 deletions
diff --git a/alpine/APKBUILD.in b/alpine/APKBUILD.in
index 1c579a8e72..f740a34583 100644
--- a/alpine/APKBUILD.in
+++ b/alpine/APKBUILD.in
@@ -17,7 +17,7 @@ makedepends="ncurses-dev net-snmp-dev gawk texinfo perl
linux-headers lzip lzo m4 make mkinitfs mpc1 mpfr4 mtools musl-dev
ncurses-libs ncurses-terminfo ncurses-terminfo-base patch pax-utils pcre
perl pkgconf python2 python2-dev readline readline-dev sqlite-libs
- squashfs-tools sudo tar texinfo xorriso xz-libs py-pip py-sphinx rtrlib
+ squashfs-tools sudo tar texinfo xorriso xz-libs py-pip rtrlib
rtrlib-dev"
checkdepends="pytest py-setuptools"
install="$pkgname.pre-install $pkgname.pre-deinstall $pkgname.post-deinstall"
@@ -34,6 +34,12 @@ _user=frr
build() {
cd "$builddir"
+
+ _localpythondir=$PWD/.python
+ pip2 install --prefix $_localpythondir sphinx
+ export PATH=${_localpythondir}/bin:$PATH
+ export PYTHONPATH=${_localpythondir}/lib/python2.7/site-packages
+
./configure \
--prefix=/usr \
--sbindir=$_sbindir \
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index c8fdaf404d..16de59b72c 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -152,8 +152,9 @@ static bool cluster_hash_cmp(const void *p1, const void *p2)
const struct cluster_list *cluster2 = p2;
return (cluster1->length == cluster2->length
- && memcmp(cluster1->list, cluster2->list, cluster1->length)
- == 0);
+ && (cluster1->list == cluster2->list
+ || memcmp(cluster1->list, cluster2->list, cluster1->length)
+ == 0));
}
static void cluster_free(struct cluster_list *cluster)
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index b8798a7ced..79a8fae530 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -5100,7 +5100,8 @@ int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
if (pnt + BGP_ADDPATH_ID_LEN > lim)
return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW;
- addpath_id = ntohl(*((uint32_t *)pnt));
+ memcpy(&addpath_id, pnt, BGP_ADDPATH_ID_LEN);
+ addpath_id = ntohl(addpath_id);
pnt += BGP_ADDPATH_ID_LEN;
}
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index d316a28dcb..3049a00ce3 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -5620,19 +5620,24 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
if (!bgp->evpn_info->advertise_pip)
vty_out(vty, " no advertise-pip\n");
if (bgp->evpn_info->advertise_pip) {
- if (bgp->evpn_info->pip_ip_static.s_addr != INADDR_ANY)
+ if (bgp->evpn_info->pip_ip_static.s_addr
+ != INADDR_ANY) {
vty_out(vty, " advertise-pip ip %s",
inet_ntop(AF_INET,
&bgp->evpn_info->pip_ip_static,
buf2, INET_ADDRSTRLEN));
- if (!is_zero_mac(&(bgp->evpn_info->pip_rmac_static))) {
- char buf[ETHER_ADDR_STRLEN];
-
- vty_out(vty, " mac %s",
- prefix_mac2str(&bgp->evpn_info->pip_rmac,
- buf, sizeof(buf)));
+ if (!is_zero_mac(&(
+ bgp->evpn_info->pip_rmac_static))) {
+ char buf[ETHER_ADDR_STRLEN];
+
+ vty_out(vty, " mac %s",
+ prefix_mac2str(
+ &bgp->evpn_info
+ ->pip_rmac,
+ buf, sizeof(buf)));
+ }
+ vty_out(vty, "\n");
}
- vty_out(vty, "\n");
}
}
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_RD_CFGD))
diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c
index 489ac6ea9f..ff1ab1a37d 100644
--- a/bgpd/bgp_label.c
+++ b/bgpd/bgp_label.c
@@ -368,7 +368,8 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr,
if (pnt + BGP_ADDPATH_ID_LEN > lim)
return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW;
- addpath_id = ntohl(*((uint32_t *)pnt));
+ memcpy(&addpath_id, pnt, BGP_ADDPATH_ID_LEN);
+ addpath_id = ntohl(addpath_id);
pnt += BGP_ADDPATH_ID_LEN;
}
diff --git a/bgpd/bgp_mac.c b/bgpd/bgp_mac.c
index 61c7b4080c..537bb45455 100644
--- a/bgpd/bgp_mac.c
+++ b/bgpd/bgp_mac.c
@@ -284,11 +284,13 @@ static void bgp_mac_remove_ifp_internal(struct bgp_self_mac *bsm, char *ifname,
}
if (bsm->ifp_list->count == 0) {
+ struct ethaddr mac = *macaddr;
+
hash_release(bm->self_mac_hash, bsm);
list_delete(&bsm->ifp_list);
XFREE(MTYPE_BSM, bsm);
- bgp_mac_rescan_all_evpn_tables(macaddr);
+ bgp_mac_rescan_all_evpn_tables(&mac);
}
}
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index 59ed433e58..86c04b71f0 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -142,7 +142,8 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
if (pnt + BGP_ADDPATH_ID_LEN > lim)
return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW;
- addpath_id = ntohl(*((uint32_t *)pnt));
+ memcpy(&addpath_id, pnt, BGP_ADDPATH_ID_LEN);
+ addpath_id = ntohl(addpath_id);
pnt += BGP_ADDPATH_ID_LEN;
}
diff --git a/bgpd/bgp_rd.c b/bgpd/bgp_rd.c
index 571139a49a..be950dfa51 100644
--- a/bgpd/bgp_rd.c
+++ b/bgpd/bgp_rd.c
@@ -174,15 +174,16 @@ char *prefix_rd2str(struct prefix_rd *prd, char *buf, size_t size)
if (type == RD_TYPE_AS) {
decode_rd_as(pnt + 2, &rd_as);
- snprintf(buf, size, "%u:%d", rd_as.as, rd_as.val);
+ snprintf(buf, size, "%u:%" PRIu32, rd_as.as, rd_as.val);
return buf;
} else if (type == RD_TYPE_AS4) {
decode_rd_as4(pnt + 2, &rd_as);
- snprintf(buf, size, "%u:%d", rd_as.as, rd_as.val);
+ snprintf(buf, size, "%u:%" PRIu32, rd_as.as, rd_as.val);
return buf;
} else if (type == RD_TYPE_IP) {
decode_rd_ip(pnt + 2, &rd_ip);
- snprintf(buf, size, "%s:%d", inet_ntoa(rd_ip.ip), rd_ip.val);
+ snprintf(buf, size, "%s:%" PRIu16, inet_ntoa(rd_ip.ip),
+ rd_ip.val);
return buf;
}
#if ENABLE_BGP_VNC
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 64d7ce9e9f..5f4486b800 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -4515,7 +4515,8 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr,
if (pnt + BGP_ADDPATH_ID_LEN >= lim)
return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW;
- addpath_id = ntohl(*((uint32_t *)pnt));
+ memcpy(&addpath_id, pnt, BGP_ADDPATH_ID_LEN);
+ addpath_id = ntohl(addpath_id);
pnt += BGP_ADDPATH_ID_LEN;
}
@@ -9147,7 +9148,8 @@ static int bgp_show_prefix_longer(struct vty *vty, struct bgp *bgp,
const char *prefix, afi_t afi, safi_t safi,
enum bgp_show_type type);
static int bgp_show_regexp(struct vty *vty, struct bgp *bgp, const char *regstr,
- afi_t afi, safi_t safi, enum bgp_show_type type);
+ afi_t afi, safi_t safi, enum bgp_show_type type,
+ bool use_json);
static int bgp_show_community(struct vty *vty, struct bgp *bgp,
const char *comstr, int exact, afi_t afi,
safi_t safi, bool use_json);
@@ -9438,7 +9440,8 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
vty_out(vty, ",\"%s\": ", buf2);
}
vty_out(vty, "%s",
- json_object_to_json_string(json_paths));
+ json_object_to_json_string_ext(
+ json_paths, JSON_C_TO_STRING_PRETTY));
json_object_free(json_paths);
json_paths = NULL;
first = 0;
@@ -10464,7 +10467,7 @@ DEFUN (show_ip_bgp_route,
DEFUN (show_ip_bgp_regexp,
show_ip_bgp_regexp_cmd,
- "show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]] regexp REGEX...",
+ "show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]] regexp REGEX [json]",
SHOW_STR
IP_STR
BGP_STR
@@ -10472,11 +10475,14 @@ DEFUN (show_ip_bgp_regexp,
BGP_AFI_HELP_STR
BGP_SAFI_WITH_LABEL_HELP_STR
"Display routes matching the AS path regular expression\n"
- "A regular-expression (1234567890_^|[,{}() ]$*+.?-\\) to match the BGP AS paths\n")
+ "A regular-expression (1234567890_^|[,{}() ]$*+.?-\\) to match the BGP AS paths\n"
+ JSON_STR)
{
afi_t afi = AFI_IP6;
safi_t safi = SAFI_UNICAST;
struct bgp *bgp = NULL;
+ bool uj = use_json(argc, argv);
+ char *regstr = NULL;
int idx = 0;
bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
@@ -10485,14 +10491,11 @@ DEFUN (show_ip_bgp_regexp,
return CMD_WARNING;
// get index of regex
- argv_find(argv, argc, "regexp", &idx);
- idx++;
+ if (argv_find(argv, argc, "REGEX", &idx))
+ regstr = argv[idx]->arg;
- char *regstr = argv_concat(argv, argc, idx);
- int rc = bgp_show_regexp(vty, bgp, (const char *)regstr, afi, safi,
- bgp_show_type_regexp);
- XFREE(MTYPE_TMP, regstr);
- return rc;
+ return bgp_show_regexp(vty, bgp, (const char *)regstr, afi, safi,
+ bgp_show_type_regexp, uj);
}
DEFUN (show_ip_bgp_instance_all,
@@ -10525,13 +10528,14 @@ DEFUN (show_ip_bgp_instance_all,
}
static int bgp_show_regexp(struct vty *vty, struct bgp *bgp, const char *regstr,
- afi_t afi, safi_t safi, enum bgp_show_type type)
+ afi_t afi, safi_t safi, enum bgp_show_type type,
+ bool use_json)
{
regex_t *regex;
int rc;
if (!config_bgp_aspath_validate(regstr)) {
- vty_out(vty, "Invalid character in as-path access-list %s\n",
+ vty_out(vty, "Invalid character in REGEX %s\n",
regstr);
return CMD_WARNING_CONFIG_FAILED;
}
@@ -10542,7 +10546,7 @@ static int bgp_show_regexp(struct vty *vty, struct bgp *bgp, const char *regstr,
return CMD_WARNING;
}
- rc = bgp_show(vty, bgp, afi, safi, type, regex, 0);
+ rc = bgp_show(vty, bgp, afi, safi, type, regex, use_json);
bgp_regex_free(regex);
return rc;
}
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index e875c41119..53d9732956 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -2692,7 +2692,7 @@ DEFUN (bgp_listen_limit,
"bgp listen limit (1-5000)",
"BGP specific commands\n"
"BGP Dynamic Neighbors listen commands\n"
- "maximum number of BGP Dynamic Neighbors that can be created\n"
+ "Maximum number of BGP Dynamic Neighbors that can be created\n"
"Configure Dynamic Neighbors listen limit value\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
@@ -2712,8 +2712,7 @@ DEFUN (no_bgp_listen_limit,
NO_STR
"BGP specific commands\n"
"BGP Dynamic Neighbors listen commands\n"
- "unset maximum number of BGP Dynamic Neighbors that can be created\n"
- "Configure Dynamic Neighbors listen limit value to default\n"
+ "Maximum number of BGP Dynamic Neighbors that can be created\n"
"Configure Dynamic Neighbors listen limit value\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
@@ -9712,23 +9711,6 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
uptime -= p->uptime;
epoch_tbuf = time(NULL) - uptime;
-#if CONFDATE > 20200101
- CPP_NOTICE(
- "bgpTimerUp should be deprecated and can be removed now");
-#endif
- /*
- * bgpTimerUp was miliseconds that was accurate
- * up to 1 day, then the value returned
- * became garbage. So in order to provide
- * some level of backwards compatability,
- * we still provde the data, but now
- * we are returning the correct value
- * and also adding a new bgpTimerUpMsec
- * which will allow us to deprecate
- * this eventually
- */
- json_object_int_add(json_neigh, "bgpTimerUp",
- uptime * 1000);
json_object_int_add(json_neigh, "bgpTimerUpMsec",
uptime * 1000);
json_object_string_add(json_neigh, "bgpTimerUpString",
diff --git a/configure.ac b/configure.ac
index a9784842e4..0694e3ed2c 100755
--- a/configure.ac
+++ b/configure.ac
@@ -331,14 +331,14 @@ if test "$enable_memory_sanitizer" = "yes"; then
AC_C_FLAG([-fsanitize=memory -fPIE -pie], [
AC_MSG_ERROR([$CC does not support Memory Sanitizer.])
], [
- SAN_FLAGS="-fsanitize=memory -fPIE -pie"
+ SAN_FLAGS="$SAN_FLAGS -fsanitize=memory -fPIE -pie"
])
fi
if test "$enable_undefined_sanitizer" = "yes"; then
AC_C_FLAG([-fsanitize=undefined], [
AC_MSG_ERROR([$CC does not support UndefinedBehaviorSanitizer.])
], [
- SAN_FLAGS="-fsanitize=undefined"
+ SAN_FLAGS="$SAN_FLAGS -fsanitize=undefined"
])
fi
AC_SUBST([SAN_FLAGS])
diff --git a/debian/README.Debian b/debian/README.Debian
index 47a353310d..cbd70f82f6 100644
--- a/debian/README.Debian
+++ b/debian/README.Debian
@@ -61,7 +61,7 @@ OpenSSL now is not compatible with the GNU GENERAL PUBLIC LICENSE (GPL)
licence that FRR is distributed under. For more explanation read:
http://www.gnome.org/~markmc/openssl-and-the-gpl.html
http://www.gnu.org/licenses/gpl-faq.html#GPLIncompatibleLibs
-Updating the licence to explecitly allow linking against OpenSSL
+Updating the licence to explicitly allow linking against OpenSSL
would requite the affirmation of all people that ever contributed
a significant part to Zebra / Quagga or FRR and thus are the collective
"copyright holder". That's too much work. Using a shrinked down
diff --git a/doc/user/pim.rst b/doc/user/pim.rst
index 9267095b3e..6bda692607 100644
--- a/doc/user/pim.rst
+++ b/doc/user/pim.rst
@@ -11,6 +11,13 @@ vrf aware and can work within the context of vrf's in order to
do S,G mrouting. Additionally PIM can be used in the EVPN underlay
network for optimizing forwarding of overlay BUM traffic.
+.. note::
+
+ On Linux for PIM-SM operation you *must* have kernel version 4.18 or greater.
+ To use PIM for EVPN BUM forwarding, kernels 5.0 or greater are required.
+ OpenBSD has no multicast support and FreeBSD, NetBSD and Solaris only
+ have support for SSM.
+
.. _starting-and-stopping-pimd:
Starting and Stopping pimd
diff --git a/docker/alpine/Dockerfile b/docker/alpine/Dockerfile
index 88c8f88f81..ed6453e2b1 100644
--- a/docker/alpine/Dockerfile
+++ b/docker/alpine/Dockerfile
@@ -42,6 +42,7 @@ USER builder
RUN cd /dist \
&& abuild-keygen -a -n \
&& abuild checksum \
+ && git init \
&& abuild -r -P /pkgs/apk
# This stage installs frr from the apk
diff --git a/docker/centos-8/build.sh b/docker/centos-8/build.sh
index 968d5fe6c4..4a9918486c 100755
--- a/docker/centos-8/build.sh
+++ b/docker/centos-8/build.sh
@@ -17,7 +17,7 @@ docker build \
.
# Copy RPM package from container to host
-CONTAINER_ID="$(docker create "frr:centos-builder-8-$GITREV")"
+CONTAINER_ID="$(docker create "frr:centos-8-builder-$GITREV")"
docker cp "${CONTAINER_ID}:/rpmbuild/RPMS/x86_64/" docker/centos-8/pkgs
docker rm "${CONTAINER_ID}"
diff --git a/isisd/isisd.c b/isisd/isisd.c
index f15d7a9c7e..47d2e9faab 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -107,13 +107,10 @@ struct isis_area *isis_area_create(const char *area_tag)
/*
* Fabricd runs only as level-2.
- * For IS-IS, the first instance is level-1-2 rest are level-1,
- * unless otherwise configured
+ * For IS-IS, the default is level-1-2
*/
- if (fabricd) {
+ if (fabricd)
area->is_type = IS_LEVEL_2;
- } else if (listcount(isis->area_list) == 0)
- area->is_type = IS_LEVEL_1_AND_2;
else
area->is_type = yang_get_default_enum(
"/frr-isisd:isis/instance/is-type");
diff --git a/lib/if.c b/lib/if.c
index c91407084e..7332dceb45 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -137,7 +137,12 @@ static int if_cmp_func(const struct interface *ifp1,
static int if_cmp_index_func(const struct interface *ifp1,
const struct interface *ifp2)
{
- return ifp1->ifindex - ifp2->ifindex;
+ if (ifp1->ifindex == ifp2->ifindex)
+ return 0;
+ else if (ifp1->ifindex > ifp2->ifindex)
+ return 1;
+ else
+ return -1;
}
static void ifp_connected_free(void *arg)
diff --git a/lib/ipaddr.h b/lib/ipaddr.h
index ec08fc09a2..6bd614044c 100644
--- a/lib/ipaddr.h
+++ b/lib/ipaddr.h
@@ -119,6 +119,12 @@ static inline void ipv4_mapped_ipv6_to_ipv4(struct in6_addr *in6,
memcpy(in, (char *)in6 + 12, sizeof(struct in_addr));
}
+static inline bool ipaddr_isset(struct ipaddr *ip)
+{
+ static struct ipaddr a = {};
+ return (0 == memcmp(&a, ip, sizeof(struct ipaddr)));
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/yang.c b/lib/yang.c
index d153f75530..93e6db3055 100644
--- a/lib/yang.c
+++ b/lib/yang.c
@@ -77,6 +77,7 @@ static const char *const frr_native_modules[] = {
"frr-ripd",
"frr-ripngd",
"frr-isisd",
+ "frr-vrrpd",
};
/* Generate the yang_modules tree. */
diff --git a/lib/zclient.c b/lib/zclient.c
index 6982d287a2..fd1b181e58 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -2679,6 +2679,17 @@ int zapi_labels_decode(struct stream *s, struct zapi_labels *zl)
}
STREAM_GETW(s, zl->nexthop_num);
+
+ if (zl->nexthop_num > MULTIPATH_NUM) {
+ flog_warn(
+ EC_LIB_ZAPI_ENCODE,
+ "%s: Prefix %pFX has %d nexthops, but we can only use the first %d",
+ __func__, &zl->route.prefix, zl->nexthop_num,
+ MULTIPATH_NUM);
+ }
+
+ zl->nexthop_num = MIN(MULTIPATH_NUM, zl->nexthop_num);
+
for (int i = 0; i < zl->nexthop_num; i++) {
znh = &zl->nexthops[i];
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index d165cca086..01bebebd29 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -914,7 +914,6 @@ static void pim_show_interfaces_single(struct pim_instance *pim,
struct in_addr ifaddr;
struct interface *ifp;
struct listnode *neighnode;
- struct listnode *upnode;
struct pim_interface *pim_ifp;
struct pim_neighbor *neigh;
struct pim_upstream *up;
@@ -1052,8 +1051,7 @@ static void pim_show_interfaces_single(struct pim_instance *pim,
pim_ifp->pim_dr_election_changes);
// FHR
- for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode,
- up)) {
+ frr_each (rb_pim_upstream, &pim->upstream_head, up) {
if (ifp != up->rpf.source_nexthop.interface)
continue;
@@ -1215,8 +1213,7 @@ static void pim_show_interfaces_single(struct pim_instance *pim,
// FHR
print_header = 1;
- for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode,
- up)) {
+ frr_each (rb_pim_upstream, &pim->upstream_head, up) {
if (!up->rpf.source_nexthop.interface)
continue;
@@ -1386,7 +1383,6 @@ static void pim_show_interfaces(struct pim_instance *pim, struct vty *vty,
bool uj)
{
struct interface *ifp;
- struct listnode *upnode;
struct pim_interface *pim_ifp;
struct pim_upstream *up;
int fhr = 0;
@@ -1408,7 +1404,7 @@ static void pim_show_interfaces(struct pim_instance *pim, struct vty *vty,
pim_ifchannels = pim_if_ifchannel_count(pim_ifp);
fhr = 0;
- for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up))
+ frr_each (rb_pim_upstream, &pim->upstream_head, up)
if (ifp == up->rpf.source_nexthop.interface)
if (up->flags & PIM_UPSTREAM_FLAG_MASK_FHR)
fhr++;
@@ -1975,7 +1971,6 @@ static void pim_show_state(struct pim_instance *pim, struct vty *vty,
const char *src_or_group, const char *group, bool uj)
{
struct channel_oil *c_oil;
- struct listnode *node;
json_object *json = NULL;
json_object *json_group = NULL;
json_object *json_ifp_in = NULL;
@@ -1994,7 +1989,7 @@ static void pim_show_state(struct pim_instance *pim, struct vty *vty,
"\nActive Source Group RPT IIF OIL\n");
}
- for (ALL_LIST_ELEMENTS_RO(pim->channel_oil_list, node, c_oil)) {
+ frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil) {
char grp_str[INET_ADDRSTRLEN];
char src_str[INET_ADDRSTRLEN];
char in_ifname[INTERFACE_NAMSIZ + 1];
@@ -2429,7 +2424,6 @@ static const char *pim_reg_state2brief_str(enum pim_reg_state reg_state,
static void pim_show_upstream(struct pim_instance *pim, struct vty *vty,
struct prefix_sg *sg, bool uj)
{
- struct listnode *upnode;
struct pim_upstream *up;
time_t now;
json_object *json = NULL;
@@ -2444,7 +2438,7 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty,
vty_out(vty,
"Iif Source Group State Uptime JoinTimer RSTimer KATimer RefCnt\n");
- for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) {
+ frr_each (rb_pim_upstream, &pim->upstream_head, up) {
char src_str[INET_ADDRSTRLEN];
char grp_str[INET_ADDRSTRLEN];
char uptime[10];
@@ -2716,7 +2710,6 @@ static void pim_show_join_desired_helper(struct pim_instance *pim,
static void pim_show_join_desired(struct pim_instance *pim, struct vty *vty,
bool uj)
{
- struct listnode *upnode;
struct pim_upstream *up;
json_object *json = NULL;
@@ -2727,7 +2720,7 @@ static void pim_show_join_desired(struct pim_instance *pim, struct vty *vty,
vty_out(vty,
"Source Group EvalJD\n");
- for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) {
+ frr_each (rb_pim_upstream, &pim->upstream_head, up) {
/* scan all interfaces */
pim_show_join_desired_helper(pim, vty, up,
json, uj);
@@ -2743,7 +2736,6 @@ static void pim_show_join_desired(struct pim_instance *pim, struct vty *vty,
static void pim_show_upstream_rpf(struct pim_instance *pim, struct vty *vty,
bool uj)
{
- struct listnode *upnode;
struct pim_upstream *up;
json_object *json = NULL;
json_object *json_group = NULL;
@@ -2755,7 +2747,7 @@ static void pim_show_upstream_rpf(struct pim_instance *pim, struct vty *vty,
vty_out(vty,
"Source Group RpfIface RibNextHop RpfAddress \n");
- for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) {
+ frr_each (rb_pim_upstream, &pim->upstream_head, up) {
char src_str[INET_ADDRSTRLEN];
char grp_str[INET_ADDRSTRLEN];
char rpf_nexthop_str[PREFIX_STRLEN];
@@ -2876,7 +2868,6 @@ static void show_scan_oil_stats(struct pim_instance *pim, struct vty *vty,
static void pim_show_rpf(struct pim_instance *pim, struct vty *vty, bool uj)
{
- struct listnode *up_node;
struct pim_upstream *up;
time_t now = pim_time_monotonic_sec();
json_object *json = NULL;
@@ -2893,7 +2884,7 @@ static void pim_show_rpf(struct pim_instance *pim, struct vty *vty, bool uj)
"Source Group RpfIface RpfAddress RibNextHop Metric Pref\n");
}
- for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, up_node, up)) {
+ frr_each (rb_pim_upstream, &pim->upstream_head, up) {
char src_str[INET_ADDRSTRLEN];
char grp_str[INET_ADDRSTRLEN];
char rpf_addr_str[PREFIX_STRLEN];
@@ -3933,11 +3924,8 @@ static void clear_mroute(struct pim_instance *pim)
}
/* clean up all upstreams*/
- if (pim->upstream_list) {
- while (pim->upstream_list->count) {
- up = listnode_head(pim->upstream_list);
- pim_upstream_del(pim, up, __PRETTY_FUNCTION__);
- }
+ while ((up = rb_pim_upstream_first(&pim->upstream_head))) {
+ pim_upstream_del(pim, up, __PRETTY_FUNCTION__);
}
}
@@ -5420,7 +5408,7 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty,
now = pim_time_monotonic_sec();
/* print list of PIM and IGMP routes */
- for (ALL_LIST_ELEMENTS_RO(pim->channel_oil_list, node, c_oil)) {
+ frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil) {
found_oif = 0;
first = 1;
if (!c_oil->installed && !uj)
@@ -5828,7 +5816,7 @@ DEFUN (clear_ip_mroute_count,
return CMD_WARNING;
pim = vrf->info;
- for (ALL_LIST_ELEMENTS_RO(pim->channel_oil_list, node, c_oil)) {
+ frr_each(rb_pim_oil, &pim->channel_oil_head, c_oil) {
if (!c_oil->installed)
continue;
@@ -5863,7 +5851,7 @@ static void show_mroute_count(struct pim_instance *pim, struct vty *vty)
"Source Group LastUsed Packets Bytes WrongIf \n");
/* Print PIM and IGMP route counts */
- for (ALL_LIST_ELEMENTS_RO(pim->channel_oil_list, node, c_oil)) {
+ frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil) {
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
@@ -5968,7 +5956,7 @@ static void show_mroute_summary(struct pim_instance *pim, struct vty *vty)
vty_out(vty, "Mroute Type Installed/Total\n");
- for (ALL_LIST_ELEMENTS_RO(pim->channel_oil_list, node, c_oil)) {
+ frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil) {
if (!c_oil->installed) {
if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY)
starg_sw_mroute_cnt++;
diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c
index 54ad17a991..39ef706f79 100644
--- a/pimd/pim_igmp.c
+++ b/pimd/pim_igmp.c
@@ -1113,8 +1113,10 @@ struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp,
}
if (pim_is_group_224_0_0_0_24(group_addr)) {
- zlog_warn("%s: Group specified is part of 224.0.0.0/24",
- __PRETTY_FUNCTION__);
+ if (PIM_DEBUG_IGMP_TRACE)
+ zlog_debug(
+ "%s: Group specified %s is part of 224.0.0.0/24",
+ __PRETTY_FUNCTION__, inet_ntoa(group_addr));
return NULL;
}
/*
diff --git a/pimd/pim_instance.h b/pimd/pim_instance.h
index dd3ac8fcb0..da0c75decb 100644
--- a/pimd/pim_instance.h
+++ b/pimd/pim_instance.h
@@ -28,6 +28,8 @@
#include "pim_assert.h"
#include "pim_bsm.h"
#include "pim_vxlan_instance.h"
+#include "pim_oil.h"
+#include "pim_upstream.h"
#if defined(HAVE_LINUX_MROUTE_H)
#include <linux/mroute.h>
@@ -107,8 +109,7 @@ struct pim_instance {
struct list *static_routes;
// Upstream vrf specific information
- struct list *upstream_list;
- struct hash *upstream_hash;
+ struct rb_pim_upstream_head upstream_head;
struct timer_wheel *upstream_sg_wheel;
/*
@@ -119,8 +120,7 @@ struct pim_instance {
int iface_vif_index[MAXVIFS];
- struct list *channel_oil_list;
- struct hash *channel_oil_hash;
+ struct rb_pim_oil_head channel_oil_head;
struct pim_msdp msdp;
struct pim_vxlan_instance vxlan;
diff --git a/pimd/pim_msdp.c b/pimd/pim_msdp.c
index 8a18594fd7..58ebc6ce67 100644
--- a/pimd/pim_msdp.c
+++ b/pimd/pim_msdp.c
@@ -565,11 +565,9 @@ void pim_msdp_sa_local_update(struct pim_upstream *up)
static void pim_msdp_sa_local_setup(struct pim_instance *pim)
{
struct pim_upstream *up;
- struct listnode *up_node;
- for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, up_node, up)) {
+ frr_each (rb_pim_upstream, &pim->upstream_head, up)
pim_msdp_sa_local_update(up);
- }
}
/* whenever the RP changes we need to re-evaluate the "local" SA-cache */
diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c
index bd8424b3e4..5cb9492ec3 100644
--- a/pimd/pim_nht.c
+++ b/pimd/pim_nht.c
@@ -177,7 +177,6 @@ void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr,
struct pim_nexthop_cache *pnc = NULL;
struct pim_nexthop_cache lookup;
struct zclient *zclient = NULL;
- struct listnode *upnode = NULL;
struct pim_upstream *upstream = NULL;
zclient = pim_zebra_zclient_get();
@@ -190,8 +189,8 @@ void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr,
/* Release the (*, G)upstream from pnc->upstream_hash,
* whose Group belongs to the RP getting deleted
*/
- for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode,
- upstream)) {
+ frr_each (rb_pim_upstream, &pim->upstream_head,
+ upstream) {
struct prefix grp;
struct rp_info *trp_info;
diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c
index 65c6bdd2bc..598988f88f 100644
--- a/pimd/pim_oil.c
+++ b/pimd/pim_oil.c
@@ -64,8 +64,8 @@ char *pim_channel_oil_dump(struct channel_oil *c_oil, char *buf, size_t size)
return buf;
}
-static int pim_channel_oil_compare(struct channel_oil *c1,
- struct channel_oil *c2)
+int pim_channel_oil_compare(const struct channel_oil *c1,
+ const struct channel_oil *c2)
{
if (ntohl(c1->oil.mfcc_mcastgrp.s_addr)
< ntohl(c2->oil.mfcc_mcastgrp.s_addr))
@@ -86,48 +86,19 @@ static int pim_channel_oil_compare(struct channel_oil *c1,
return 0;
}
-static bool pim_oil_equal(const void *arg1, const void *arg2)
-{
- const struct channel_oil *c1 = (const struct channel_oil *)arg1;
- const struct channel_oil *c2 = (const struct channel_oil *)arg2;
-
- if ((c1->oil.mfcc_mcastgrp.s_addr == c2->oil.mfcc_mcastgrp.s_addr)
- && (c1->oil.mfcc_origin.s_addr == c2->oil.mfcc_origin.s_addr))
- return true;
-
- return false;
-}
-
-static unsigned int pim_oil_hash_key(const void *arg)
-{
- const struct channel_oil *oil = arg;
-
- return jhash_2words(oil->oil.mfcc_mcastgrp.s_addr,
- oil->oil.mfcc_origin.s_addr, 0);
-}
-
void pim_oil_init(struct pim_instance *pim)
{
- char hash_name[64];
-
- snprintf(hash_name, 64, "PIM %s Oil Hash", pim->vrf->name);
- pim->channel_oil_hash = hash_create_size(8192, pim_oil_hash_key,
- pim_oil_equal, hash_name);
-
- pim->channel_oil_list = list_new();
- pim->channel_oil_list->del = (void (*)(void *))pim_channel_oil_free;
- pim->channel_oil_list->cmp =
- (int (*)(void *, void *))pim_channel_oil_compare;
+ rb_pim_oil_init(&pim->channel_oil_head);
}
void pim_oil_terminate(struct pim_instance *pim)
{
- if (pim->channel_oil_list)
- list_delete(&pim->channel_oil_list);
+ struct channel_oil *c_oil;
+
+ while ((c_oil = rb_pim_oil_pop(&pim->channel_oil_head)))
+ pim_channel_oil_free(c_oil);
- if (pim->channel_oil_hash)
- hash_free(pim->channel_oil_hash);
- pim->channel_oil_hash = NULL;
+ rb_pim_oil_fini(&pim->channel_oil_head);
}
void pim_channel_oil_free(struct channel_oil *c_oil)
@@ -144,7 +115,7 @@ struct channel_oil *pim_find_channel_oil(struct pim_instance *pim,
lookup.oil.mfcc_mcastgrp = sg->grp;
lookup.oil.mfcc_origin = sg->src;
- c_oil = hash_lookup(pim->channel_oil_hash, &lookup);
+ c_oil = rb_pim_oil_find(&pim->channel_oil_head, &lookup);
return c_oil;
}
@@ -187,7 +158,6 @@ struct channel_oil *pim_channel_oil_add(struct pim_instance *pim,
c_oil->oil.mfcc_mcastgrp = sg->grp;
c_oil->oil.mfcc_origin = sg->src;
- c_oil = hash_get(pim->channel_oil_hash, c_oil, hash_alloc_intern);
c_oil->oil.mfcc_parent = MAXVIFS;
c_oil->oil_ref_count = 1;
@@ -195,7 +165,7 @@ struct channel_oil *pim_channel_oil_add(struct pim_instance *pim,
c_oil->up = pim_upstream_find(pim, sg);
c_oil->pim = pim;
- listnode_add_sort(pim->channel_oil_list, c_oil);
+ rb_pim_oil_add(&pim->channel_oil_head, c_oil);
if (PIM_DEBUG_MROUTE)
zlog_debug("%s(%s): c_oil %s add",
@@ -224,8 +194,7 @@ struct channel_oil *pim_channel_oil_del(struct channel_oil *c_oil,
* called by list_delete_all_node()
*/
c_oil->up = NULL;
- listnode_delete(c_oil->pim->channel_oil_list, c_oil);
- hash_release(c_oil->pim->channel_oil_hash, c_oil);
+ rb_pim_oil_del(&c_oil->pim->channel_oil_head, c_oil);
pim_channel_oil_free(c_oil);
return NULL;
diff --git a/pimd/pim_oil.h b/pimd/pim_oil.h
index de7fde05da..788ddaa16c 100644
--- a/pimd/pim_oil.h
+++ b/pimd/pim_oil.h
@@ -90,10 +90,13 @@ struct channel_counts {
installed: indicate if this entry is installed in the kernel.
*/
+PREDECL_RBTREE_UNIQ(rb_pim_oil)
struct channel_oil {
struct pim_instance *pim;
+ struct rb_pim_oil_item oil_rb;
+
struct mfcctl oil;
int installed;
int oil_inherited_rescan;
@@ -106,6 +109,12 @@ struct channel_oil {
time_t mroute_creation;
};
+extern int pim_channel_oil_compare(const struct channel_oil *c1,
+ const struct channel_oil *c2);
+DECLARE_RBTREE_UNIQ(rb_pim_oil, struct channel_oil, oil_rb,
+ pim_channel_oil_compare)
+
+
extern struct list *pim_channel_oil_list;
void pim_oil_init(struct pim_instance *pim);
diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c
index bd295b0fef..2db39bac4b 100644
--- a/pimd/pim_rp.c
+++ b/pimd/pim_rp.c
@@ -446,7 +446,6 @@ int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr,
struct prefix nht_p;
struct route_node *rn;
struct pim_upstream *up;
- struct listnode *upnode;
if (rp_addr.s_addr == INADDR_ANY ||
rp_addr.s_addr == INADDR_NONE)
@@ -554,8 +553,7 @@ int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr,
__PRETTY_FUNCTION__, buf, buf1);
}
- for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode,
- up)) {
+ frr_each (rb_pim_upstream, &pim->upstream_head, up) {
/* Find (*, G) upstream whose RP is not
* configured yet
*/
@@ -650,7 +648,7 @@ int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr,
rn->lock);
}
- for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) {
+ frr_each (rb_pim_upstream, &pim->upstream_head, up) {
if (up->sg.src.s_addr == INADDR_ANY) {
struct prefix grp;
struct rp_info *trp_info;
@@ -723,7 +721,6 @@ int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr,
bool was_plist = false;
struct rp_info *trp_info;
struct pim_upstream *up;
- struct listnode *upnode;
struct bsgrp_node *bsgrp = NULL;
struct bsm_rpinfo *bsrp = NULL;
char grp_str[PREFIX2STR_BUFFER];
@@ -800,7 +797,7 @@ int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr,
rp_all = pim_rp_find_match_group(pim, &g_all);
if (rp_all == rp_info) {
- for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) {
+ frr_each (rb_pim_upstream, &pim->upstream_head, up) {
/* Find the upstream (*, G) whose upstream address is
* same as the deleted RP
*/
@@ -852,7 +849,7 @@ int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr,
pim_rp_refresh_group_to_rp_mapping(pim);
- for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) {
+ frr_each (rb_pim_upstream, &pim->upstream_head, up) {
/* Find the upstream (*, G) whose upstream address is same as
* the deleted RP
*/
@@ -893,7 +890,6 @@ int pim_rp_change(struct pim_instance *pim, struct in_addr new_rp_addr,
int result = 0;
struct rp_info *rp_info = NULL;
struct pim_upstream *up;
- struct listnode *upnode;
rn = route_node_lookup(pim->rp_table, &group);
if (!rn) {
@@ -942,7 +938,7 @@ int pim_rp_change(struct pim_instance *pim, struct in_addr new_rp_addr,
listnode_add_sort(pim->rp_list, rp_info);
- for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) {
+ frr_each (rb_pim_upstream, &pim->upstream_head, up) {
if (up->sg.src.s_addr == INADDR_ANY) {
struct prefix grp;
struct rp_info *trp_info;
diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c
index a0387cdd4a..afd10bd3db 100644
--- a/pimd/pim_upstream.c
+++ b/pimd/pim_upstream.c
@@ -98,7 +98,6 @@ static void pim_upstream_find_new_children(struct pim_instance *pim,
struct pim_upstream *up)
{
struct pim_upstream *child;
- struct listnode *ch_node;
if ((up->sg.src.s_addr != INADDR_ANY)
&& (up->sg.grp.s_addr != INADDR_ANY))
@@ -108,7 +107,7 @@ static void pim_upstream_find_new_children(struct pim_instance *pim,
&& (up->sg.grp.s_addr == INADDR_ANY))
return;
- for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, ch_node, child)) {
+ frr_each (rb_pim_upstream, &pim->upstream_head, child) {
if ((up->sg.grp.s_addr != INADDR_ANY)
&& (child->sg.grp.s_addr == up->sg.grp.s_addr)
&& (child != up)) {
@@ -191,9 +190,8 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim,
return up;
if (PIM_DEBUG_TRACE)
- zlog_debug(
- "pim_upstream free vrf:%s %s flags 0x%x",
- pim->vrf->name, up->sg_str, up->flags);
+ zlog_debug("pim_upstream free vrf:%s %s flags 0x%x",
+ pim->vrf->name, up->sg_str, up->flags);
THREAD_OFF(up->t_ka_timer);
THREAD_OFF(up->t_rs_timer);
@@ -235,8 +233,7 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim,
listnode_delete(up->parent->sources, up);
up->parent = NULL;
- listnode_delete(pim->upstream_list, up);
- hash_release(pim->upstream_hash, up);
+ rb_pim_upstream_del(&pim->upstream_head, up);
if (notify_msdp) {
pim_msdp_up_del(pim, &up->sg);
@@ -533,10 +530,9 @@ static int pim_upstream_could_register(struct pim_upstream *up)
* we re-revaluate register setup for existing upstream entries */
void pim_upstream_register_reevaluate(struct pim_instance *pim)
{
- struct listnode *upnode;
struct pim_upstream *up;
- for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) {
+ frr_each (rb_pim_upstream, &pim->upstream_head, up) {
/* If FHR is set CouldRegister is True. Also check if the flow
* is actually active; if it is not kat setup will trigger
* source
@@ -639,9 +635,8 @@ void pim_upstream_update_use_rpt(struct pim_upstream *up,
void pim_upstream_reeval_use_rpt(struct pim_instance *pim)
{
struct pim_upstream *up;
- struct listnode *node;
- for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, node, up)) {
+ frr_each (rb_pim_upstream, &pim->upstream_head, up) {
if (up->sg.src.s_addr == INADDR_ANY)
continue;
@@ -756,11 +751,9 @@ void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up,
}
}
-int pim_upstream_compare(void *arg1, void *arg2)
+int pim_upstream_compare(const struct pim_upstream *up1,
+ const struct pim_upstream *up2)
{
- const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
- const struct pim_upstream *up2 = (const struct pim_upstream *)arg2;
-
if (ntohl(up1->sg.grp.s_addr) < ntohl(up2->sg.grp.s_addr))
return -1;
@@ -811,7 +804,7 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim,
if (ch)
ch->upstream = up;
- up = hash_get(pim->upstream_hash, up, hash_alloc_intern);
+ rb_pim_upstream_add(&pim->upstream_head, up);
/* Set up->upstream_addr as INADDR_ANY, if RP is not
* configured and retain the upstream data structure
*/
@@ -825,7 +818,8 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim,
up->parent = pim_upstream_find_parent(pim, up);
if (up->sg.src.s_addr == INADDR_ANY) {
up->sources = list_new();
- up->sources->cmp = pim_upstream_compare;
+ up->sources->cmp =
+ (int (*)(void *, void *))pim_upstream_compare;
} else
up->sources = NULL;
@@ -889,8 +883,6 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim,
}
}
- listnode_add_sort(pim->upstream_list, up);
-
if (PIM_DEBUG_PIM_TRACE) {
zlog_debug(
"%s: Created Upstream %s upstream_addr %s ref count %d increment",
@@ -908,7 +900,7 @@ struct pim_upstream *pim_upstream_find(struct pim_instance *pim,
struct pim_upstream *up = NULL;
lookup.sg = *sg;
- up = hash_lookup(pim->upstream_hash, &lookup);
+ up = rb_pim_upstream_find(&pim->upstream_head, &lookup);
return up;
}
@@ -1168,15 +1160,12 @@ void pim_upstream_update_join_desired(struct pim_instance *pim,
void pim_upstream_rpf_genid_changed(struct pim_instance *pim,
struct in_addr neigh_addr)
{
- struct listnode *up_node;
- struct listnode *up_nextnode;
struct pim_upstream *up;
/*
* Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
*/
- for (ALL_LIST_ELEMENTS(pim->upstream_list, up_node, up_nextnode, up)) {
-
+ frr_each (rb_pim_upstream, &pim->upstream_head, up) {
if (PIM_DEBUG_PIM_TRACE) {
char neigh_str[INET_ADDRSTRLEN];
char rpf_addr_str[PREFIX_STRLEN];
@@ -1788,8 +1777,6 @@ int pim_upstream_empty_inherited_olist(struct pim_upstream *up)
*/
void pim_upstream_find_new_rpf(struct pim_instance *pim)
{
- struct listnode *up_node;
- struct listnode *up_nextnode;
struct pim_upstream *up;
struct pim_rpf old;
enum pim_rpf_result rpf_result;
@@ -1797,7 +1784,7 @@ void pim_upstream_find_new_rpf(struct pim_instance *pim)
/*
* Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
*/
- for (ALL_LIST_ELEMENTS(pim->upstream_list, up_node, up_nextnode, up)) {
+ frr_each (rb_pim_upstream, &pim->upstream_head, up) {
if (up->upstream_addr.s_addr == INADDR_ANY) {
if (PIM_DEBUG_PIM_TRACE)
zlog_debug(
@@ -1837,18 +1824,11 @@ void pim_upstream_terminate(struct pim_instance *pim)
{
struct pim_upstream *up;
- if (pim->upstream_list) {
- while (pim->upstream_list->count) {
- up = listnode_head(pim->upstream_list);
- pim_upstream_del(pim, up, __PRETTY_FUNCTION__);
- }
-
- list_delete(&pim->upstream_list);
+ while ((up = rb_pim_upstream_first(&pim->upstream_head))) {
+ pim_upstream_del(pim, up, __PRETTY_FUNCTION__);
}
- if (pim->upstream_hash)
- hash_free(pim->upstream_hash);
- pim->upstream_hash = NULL;
+ rb_pim_upstream_fini(&pim->upstream_head);
if (pim->upstream_sg_wheel)
wheel_delete(pim->upstream_sg_wheel);
@@ -1991,9 +1971,8 @@ static void pim_upstream_sg_running(void *arg)
void pim_upstream_add_lhr_star_pimreg(struct pim_instance *pim)
{
struct pim_upstream *up;
- struct listnode *node;
- for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, node, up)) {
+ frr_each (rb_pim_upstream, &pim->upstream_head, up) {
if (up->sg.src.s_addr != INADDR_ANY)
continue;
@@ -2031,7 +2010,6 @@ void pim_upstream_remove_lhr_star_pimreg(struct pim_instance *pim,
const char *nlist)
{
struct pim_upstream *up;
- struct listnode *node;
struct prefix_list *np;
struct prefix g;
enum prefix_list_type apply_new;
@@ -2041,7 +2019,7 @@ void pim_upstream_remove_lhr_star_pimreg(struct pim_instance *pim,
g.family = AF_INET;
g.prefixlen = IPV4_MAX_PREFIXLEN;
- for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, node, up)) {
+ frr_each (rb_pim_upstream, &pim->upstream_head, up) {
if (up->sg.src.s_addr != INADDR_ANY)
continue;
@@ -2075,11 +2053,5 @@ void pim_upstream_init(struct pim_instance *pim)
wheel_init(router->master, 31000, 100, pim_upstream_hash_key,
pim_upstream_sg_running, name);
- snprintf(name, 64, "PIM %s Upstream Hash",
- pim->vrf->name);
- pim->upstream_hash = hash_create_size(8192, pim_upstream_hash_key,
- pim_upstream_equal, name);
-
- pim->upstream_list = list_new();
- pim->upstream_list->cmp = pim_upstream_compare;
+ rb_pim_upstream_init(&pim->upstream_head);
}
diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h
index ab50820518..1eb2052bb3 100644
--- a/pimd/pim_upstream.h
+++ b/pimd/pim_upstream.h
@@ -169,6 +169,7 @@ enum pim_upstream_sptbit {
PIM_UPSTREAM_SPTBIT_TRUE
};
+PREDECL_RBTREE_UNIQ(rb_pim_upstream);
/*
Upstream (S,G) channel in Joined state
(S,G) in the "Not Joined" state is not represented
@@ -198,6 +199,7 @@ enum pim_upstream_sptbit {
*/
struct pim_upstream {
struct pim_instance *pim;
+ struct rb_pim_upstream_item upstream_rb;
struct pim_upstream *parent;
struct in_addr upstream_addr; /* Who we are talking to */
struct in_addr upstream_register; /*Who we received a register from*/
@@ -326,7 +328,11 @@ void pim_upstream_init(struct pim_instance *pim);
void pim_upstream_terminate(struct pim_instance *pim);
void join_timer_start(struct pim_upstream *up);
-int pim_upstream_compare(void *arg1, void *arg2);
+int pim_upstream_compare(const struct pim_upstream *up1,
+ const struct pim_upstream *up2);
+DECLARE_RBTREE_UNIQ(rb_pim_upstream, struct pim_upstream, upstream_rb,
+ pim_upstream_compare)
+
void pim_upstream_register_reevaluate(struct pim_instance *pim);
void pim_upstream_add_lhr_star_pimreg(struct pim_instance *pim);
diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c
index 0417d0d063..06507b1f4c 100644
--- a/pimd/pim_zebra.c
+++ b/pimd/pim_zebra.c
@@ -392,16 +392,13 @@ static void pim_zebra_vxlan_replay(void)
void pim_scan_oil(struct pim_instance *pim)
{
- struct listnode *node;
- struct listnode *nextnode;
struct channel_oil *c_oil;
pim->scan_oil_last = pim_time_monotonic_sec();
++pim->scan_oil_events;
- for (ALL_LIST_ELEMENTS(pim->channel_oil_list, node, nextnode, c_oil)) {
+ frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil)
pim_upstream_mroute_iif_update(c_oil, __func__);
- }
}
static int on_rpf_cache_refresh(struct thread *t)
diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in
index be3b83bf80..670bc6f4c9 100644
--- a/redhat/frr.spec.in
+++ b/redhat/frr.spec.in
@@ -444,7 +444,7 @@ zebra_spec_add_service ()
{
# Add port /etc/services entry if it isn't already there
if [ -f %{_sysconfdir}/services ] && \
- ! %__sed -e 's/#.*$//' %{_sysconfdir}/services | %__grep -wq $1 ; then
+ ! %__sed -e 's/#.*$//' %{_sysconfdir}/services 2>/dev/null | %__grep -wq $1 ; then
echo "$1 $2 # $3" >> %{_sysconfdir}/services
fi
}
diff --git a/vrrpd/subdir.am b/vrrpd/subdir.am
index 57eec108cb..d81594ad93 100644
--- a/vrrpd/subdir.am
+++ b/vrrpd/subdir.am
@@ -15,6 +15,7 @@ vrrpd_libvrrp_a_SOURCES = \
vrrpd/vrrp_arp.c \
vrrpd/vrrp_debug.c \
vrrpd/vrrp_ndisc.c \
+ vrrpd/vrrp_northbound.c \
vrrpd/vrrp_packet.c \
vrrpd/vrrp_vty.c \
vrrpd/vrrp_zebra.c \
@@ -35,3 +36,6 @@ vrrpd/vrrp_vty.$(OBJEXT): vrrpd/vrrp_vty_clippy.c
vrrpd_vrrpd_SOURCES = vrrpd/vrrp_main.c
vrrpd_vrrpd_LDADD = vrrpd/libvrrp.a lib/libfrr.la @LIBCAP@
+nodist_vrrpd_vrrpd_SOURCES = \
+ yang/frr-vrrpd.yang.c \
+ # end
diff --git a/vrrpd/vrrp.c b/vrrpd/vrrp.c
index 2acf985893..03a08dd86b 100644
--- a/vrrpd/vrrp.c
+++ b/vrrpd/vrrp.c
@@ -406,9 +406,10 @@ static bool vrrp_has_ip(struct vrrp_vrouter *vr, struct ipaddr *ip)
return false;
}
-int vrrp_add_ip(struct vrrp_router *r, struct ipaddr *ip)
+int vrrp_add_ip(struct vrrp_vrouter *vr, struct ipaddr *ip)
{
- int af = (ip->ipa_type == IPADDR_V6) ? AF_INET6 : AF_INET;
+ struct vrrp_router *r = IS_IPADDR_V4(ip) ? vr->v4 : vr->v6;
+ int af = r->family;
assert(r->family == af);
assert(!(r->vr->version == 2 && ip->ipa_type == IPADDR_V6));
@@ -452,7 +453,7 @@ int vrrp_add_ipv4(struct vrrp_vrouter *vr, struct in_addr v4)
ip.ipa_type = IPADDR_V4;
ip.ipaddr_v4 = v4;
- return vrrp_add_ip(vr->v4, &ip);
+ return vrrp_add_ip(vr, &ip);
}
int vrrp_add_ipv6(struct vrrp_vrouter *vr, struct in6_addr v6)
@@ -463,15 +464,17 @@ int vrrp_add_ipv6(struct vrrp_vrouter *vr, struct in6_addr v6)
ip.ipa_type = IPADDR_V6;
ip.ipaddr_v6 = v6;
- return vrrp_add_ip(vr->v6, &ip);
+ return vrrp_add_ip(vr, &ip);
}
-int vrrp_del_ip(struct vrrp_router *r, struct ipaddr *ip)
+int vrrp_del_ip(struct vrrp_vrouter *vr, struct ipaddr *ip)
{
struct listnode *ln, *nn;
struct ipaddr *iter;
int ret = 0;
+ struct vrrp_router *r = IS_IPADDR_V4(ip) ? vr->v4 : vr->v6;
+
if (!vrrp_has_ip(r->vr, ip))
return 0;
@@ -497,7 +500,7 @@ int vrrp_del_ipv6(struct vrrp_vrouter *vr, struct in6_addr v6)
ip.ipa_type = IPADDR_V6;
ip.ipaddr_v6 = v6;
- return vrrp_del_ip(vr->v6, &ip);
+ return vrrp_del_ip(vr, &ip);
}
int vrrp_del_ipv4(struct vrrp_vrouter *vr, struct in_addr v4)
@@ -506,7 +509,7 @@ int vrrp_del_ipv4(struct vrrp_vrouter *vr, struct in_addr v4)
ip.ipa_type = IPADDR_V4;
ip.ipaddr_v4 = v4;
- return vrrp_del_ip(vr->v4, &ip);
+ return vrrp_del_ip(vr, &ip);
}
@@ -659,12 +662,12 @@ void vrrp_vrouter_destroy(struct vrrp_vrouter *vr)
XFREE(MTYPE_VRRP_RTR, vr);
}
-struct vrrp_vrouter *vrrp_lookup(struct interface *ifp, uint8_t vrid)
+struct vrrp_vrouter *vrrp_lookup(const struct interface *ifp, uint8_t vrid)
{
struct vrrp_vrouter vr;
vr.vrid = vrid;
- vr.ifp = ifp;
+ vr.ifp = (struct interface *)ifp;
return hash_lookup(vrrp_vrouters_hash, &vr);
}
@@ -1445,7 +1448,7 @@ static void vrrp_change_state_initialize(struct vrrp_router *r)
r->ndisc_pending = false;
/* Disable ND Router Advertisements */
- if (r->family == AF_INET6)
+ if (r->family == AF_INET6 && r->mvl_ifp)
vrrp_zebra_radv_set(r, false);
}
@@ -1653,7 +1656,8 @@ static int vrrp_shutdown(struct vrrp_router *r)
THREAD_OFF(r->t_write);
/* Protodown macvlan */
- vrrp_zclient_send_interface_protodown(r->mvl_ifp, true);
+ if (r->mvl_ifp)
+ vrrp_zclient_send_interface_protodown(r->mvl_ifp, true);
/* Throw away our source address */
memset(&r->src, 0x00, sizeof(r->src));
@@ -2295,71 +2299,6 @@ void vrrp_if_address_del(struct interface *ifp)
/* Other ------------------------------------------------------------------- */
-int vrrp_config_write_interface(struct vty *vty)
-{
- struct list *vrs = hash_to_list(vrrp_vrouters_hash);
- struct listnode *ln, *ipln;
- struct vrrp_vrouter *vr;
- int writes = 0;
-
- for (ALL_LIST_ELEMENTS_RO(vrs, ln, vr)) {
- vty_frame(vty, "interface %s\n", vr->ifp->name);
- ++writes;
-
- vty_out(vty, " vrrp %" PRIu8 "%s\n", vr->vrid,
- vr->version == 2 ? " version 2" : "");
- ++writes;
-
- if (vr->shutdown != vd.shutdown && ++writes)
- vty_out(vty, " %svrrp %" PRIu8 " shutdown\n",
- vr->shutdown ? "" : "no ", vr->vrid);
-
- if (vr->preempt_mode != vd.preempt_mode && ++writes)
- vty_out(vty, " %svrrp %" PRIu8 " preempt\n",
- vr->preempt_mode ? "" : "no ", vr->vrid);
-
- if (vr->accept_mode != vd.accept_mode && ++writes)
- vty_out(vty, " %svrrp %" PRIu8 " accept\n",
- vr->accept_mode ? "" : "no ", vr->vrid);
-
- if (vr->advertisement_interval != vd.advertisement_interval
- && ++writes)
- vty_out(vty,
- " vrrp %" PRIu8
- " advertisement-interval %d\n",
- vr->vrid, vr->advertisement_interval * CS2MS);
-
- if (vr->priority != vd.priority && ++writes)
- vty_out(vty, " vrrp %" PRIu8 " priority %" PRIu8 "\n",
- vr->vrid, vr->priority);
-
- struct ipaddr *ip;
-
- for (ALL_LIST_ELEMENTS_RO(vr->v4->addrs, ipln, ip)) {
- char ipbuf[INET6_ADDRSTRLEN];
-
- ipaddr2str(ip, ipbuf, sizeof(ipbuf));
- vty_out(vty, " vrrp %" PRIu8 " ip %s\n", vr->vrid,
- ipbuf);
- ++writes;
- }
-
- for (ALL_LIST_ELEMENTS_RO(vr->v6->addrs, ipln, ip)) {
- char ipbuf[INET6_ADDRSTRLEN];
-
- ipaddr2str(ip, ipbuf, sizeof(ipbuf));
- vty_out(vty, " vrrp %" PRIu8 " ipv6 %s\n", vr->vrid,
- ipbuf);
- ++writes;
- }
- vty_endframe(vty, "!\n");
- }
-
- list_delete(&vrs);
-
- return writes;
-}
-
int vrrp_config_write_global(struct vty *vty)
{
unsigned int writes = 0;
@@ -2368,6 +2307,7 @@ int vrrp_config_write_global(struct vty *vty)
vty_out(vty, "vrrp autoconfigure%s\n",
vrrp_autoconfig_version == 2 ? " version 2" : "");
+ /* FIXME: needs to be udpated for full YANG conversion. */
if (vd.priority != VRRP_DEFAULT_PRIORITY && ++writes)
vty_out(vty, "vrrp default priority %" PRIu8 "\n", vd.priority);
@@ -2417,10 +2357,13 @@ static bool vrrp_hash_cmp(const void *arg1, const void *arg2)
void vrrp_init(void)
{
/* Set default defaults */
- vd.priority = VRRP_DEFAULT_PRIORITY;
- vd.advertisement_interval = VRRP_DEFAULT_ADVINT;
- vd.preempt_mode = VRRP_DEFAULT_PREEMPT;
- vd.accept_mode = VRRP_DEFAULT_ACCEPT;
+ vd.version = yang_get_default_uint8("%s/version", VRRP_XPATH_FULL);
+ vd.priority = yang_get_default_uint8("%s/priority", VRRP_XPATH_FULL);
+ vd.advertisement_interval = yang_get_default_uint16(
+ "%s/advertisement-interval", VRRP_XPATH_FULL);
+ vd.preempt_mode = yang_get_default_bool("%s/preempt", VRRP_XPATH_FULL);
+ vd.accept_mode =
+ yang_get_default_bool("%s/accept-mode", VRRP_XPATH_FULL);
vd.shutdown = VRRP_DEFAULT_SHUTDOWN;
vrrp_autoconfig_version = 3;
diff --git a/vrrpd/vrrp.h b/vrrpd/vrrp.h
index 79283bbb10..502d7b82b6 100644
--- a/vrrpd/vrrp.h
+++ b/vrrpd/vrrp.h
@@ -28,6 +28,7 @@
#include "lib/hook.h"
#include "lib/if.h"
#include "lib/linklist.h"
+#include "lib/northbound.h"
#include "lib/privs.h"
#include "lib/stream.h"
#include "lib/thread.h"
@@ -46,6 +47,8 @@
#define VRRP_LOGPFX_FAM "[%s] "
/* Default defaults */
+#define VRRP_XPATH_FULL "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group"
+#define VRRP_XPATH "./frr-vrrpd:vrrp/vrrp-group"
#define VRRP_DEFAULT_PRIORITY 100
#define VRRP_DEFAULT_ADVINT 100
#define VRRP_DEFAULT_PREEMPT true
@@ -57,8 +60,12 @@
DECLARE_MGROUP(VRRPD)
+/* Northbound */
+extern const struct frr_yang_module_info frr_vrrpd_info;
+
/* Configured defaults */
struct vrrp_defaults {
+ uint8_t version;
uint8_t priority;
uint16_t advertisement_interval;
bool preempt_mode;
@@ -340,7 +347,7 @@ void vrrp_set_advertisement_interval(struct vrrp_vrouter *vr,
/*
* Add an IPvX address to a VRRP Virtual Router.
*
- * r
+ * vr
* Virtual Router to add IPvx address to
*
* ip
@@ -354,7 +361,7 @@ void vrrp_set_advertisement_interval(struct vrrp_vrouter *vr,
* -1 on error
* 0 otherwise
*/
-int vrrp_add_ip(struct vrrp_router *r, struct ipaddr *ip);
+int vrrp_add_ip(struct vrrp_vrouter *vr, struct ipaddr *ip);
/*
* Add an IPv4 address to a VRRP Virtual Router.
@@ -397,7 +404,7 @@ int vrrp_add_ipv6(struct vrrp_vrouter *vr, struct in6_addr v6);
/*
* Remove an IP address from a VRRP Virtual Router.
*
- * r
+ * vr
* Virtual Router to remove IP address from
*
* ip
@@ -413,7 +420,7 @@ int vrrp_add_ipv6(struct vrrp_vrouter *vr, struct in6_addr v6);
* -1 on error
* 0 otherwise
*/
-int vrrp_del_ip(struct vrrp_router *r, struct ipaddr *ip);
+int vrrp_del_ip(struct vrrp_vrouter *vr, struct ipaddr *ip);
/*
* Remove an IPv4 address from a VRRP Virtual Router.
@@ -543,17 +550,6 @@ void vrrp_if_address_del(struct interface *ifp);
/* Other ------------------------------------------------------------------- */
/*
- * Write interface block-level configuration to vty.
- *
- * vty
- * vty to write config to
- *
- * Returns:
- * # of lines written
- */
-int vrrp_config_write_interface(struct vty *vty);
-
-/*
* Write global level configuration to vty.
*
* vty
@@ -567,6 +563,6 @@ int vrrp_config_write_global(struct vty *vty);
/*
* Find VRRP Virtual Router by Virtual Router ID
*/
-struct vrrp_vrouter *vrrp_lookup(struct interface *ifp, uint8_t vrid);
+struct vrrp_vrouter *vrrp_lookup(const struct interface *ifp, uint8_t vrid);
#endif /* __VRRP_H__ */
diff --git a/vrrpd/vrrp_main.c b/vrrpd/vrrp_main.c
index fface1718f..95b3cfad8f 100644
--- a/vrrpd/vrrp_main.c
+++ b/vrrpd/vrrp_main.c
@@ -33,6 +33,7 @@
#include "lib/sigevent.h"
#include "lib/thread.h"
#include "lib/vrf.h"
+#include "lib/vty.h"
#include "vrrp.h"
#include "vrrp_debug.h"
@@ -64,10 +65,14 @@ struct option longopts[] = { {0} };
/* Master of threads. */
struct thread_master *master;
+static struct frr_daemon_info vrrpd_di;
+
/* SIGHUP handler. */
static void sighup(void)
{
zlog_info("SIGHUP received");
+
+ vty_read_config(NULL, vrrpd_di.config_file, config_default);
}
/* SIGINT / SIGTERM handler. */
@@ -107,6 +112,7 @@ struct quagga_signal_t vrrp_signals[] = {
static const struct frr_yang_module_info *const vrrp_yang_modules[] = {
&frr_interface_info,
+ &frr_vrrpd_info,
};
#define VRRP_VTY_PORT 2619
diff --git a/vrrpd/vrrp_northbound.c b/vrrpd/vrrp_northbound.c
new file mode 100644
index 0000000000..feaea6c038
--- /dev/null
+++ b/vrrpd/vrrp_northbound.c
@@ -0,0 +1,804 @@
+/*
+ * VRRP northbound bindings.
+ * Copyright (C) 2019 Cumulus Networks, Inc.
+ * Quentin Young
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "log.h"
+#include "prefix.h"
+#include "table.h"
+#include "command.h"
+#include "northbound.h"
+#include "libfrr.h"
+#include "vrrp.h"
+#include "vrrp_vty.h"
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group
+ */
+static int lib_interface_vrrp_vrrp_group_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct interface *ifp;
+ uint8_t vrid;
+ uint8_t version = 3;
+ struct vrrp_vrouter *vr;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ifp = nb_running_get_entry(dnode, NULL, true);
+ vrid = yang_dnode_get_uint8(dnode, "./virtual-router-id");
+ version = yang_dnode_get_enum(dnode, "./version");
+ vr = vrrp_vrouter_create(ifp, vrid, version);
+ nb_running_set_entry(dnode, vr);
+
+ return NB_OK;
+}
+
+static int lib_interface_vrrp_vrrp_group_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct vrrp_vrouter *vr;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ vr = nb_running_unset_entry(dnode);
+ vrrp_vrouter_destroy(vr);
+
+ return NB_OK;
+}
+
+static const void *
+lib_interface_vrrp_vrrp_group_get_next(const void *parent_list_entry,
+ const void *list_entry)
+{
+ struct list *l = hash_to_list(vrrp_vrouters_hash);
+ struct listnode *ln;
+ const struct vrrp_vrouter *curr;
+ const struct interface *ifp = parent_list_entry;
+
+ /*
+ * If list_entry is null, we return the first vrrp instance with a
+ * matching interface
+ */
+ bool nextone = list_entry ? false : true;
+
+ for (ALL_LIST_ELEMENTS_RO(l, ln, curr)) {
+ if (curr == list_entry) {
+ nextone = true;
+ continue;
+ }
+
+ if (nextone && curr->ifp == ifp)
+ goto done;
+ }
+
+ curr = NULL;
+
+done:
+ list_delete(&l);
+ return curr;
+}
+
+static int lib_interface_vrrp_vrrp_group_get_keys(const void *list_entry,
+ struct yang_list_keys *keys)
+{
+ const struct vrrp_vrouter *vr = list_entry;
+
+ keys->num = 1;
+ snprintf(keys->key[0], sizeof(keys->key[0]), "%" PRIu32, vr->vrid);
+
+ return NB_OK;
+}
+
+static const void *
+lib_interface_vrrp_vrrp_group_lookup_entry(const void *parent_list_entry,
+ const struct yang_list_keys *keys)
+{
+ uint32_t vrid = strtoul(keys->key[0], NULL, 10);
+ const struct interface *ifp = parent_list_entry;
+
+ return vrrp_lookup(ifp, vrid);
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/version
+ */
+static int
+lib_interface_vrrp_vrrp_group_version_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ struct vrrp_vrouter *vr;
+ uint8_t version;
+
+ vr = nb_running_get_entry(dnode, NULL, true);
+ vrrp_event(vr->v4, VRRP_EVENT_SHUTDOWN);
+ vrrp_event(vr->v6, VRRP_EVENT_SHUTDOWN);
+ version = yang_dnode_get_enum(dnode, NULL);
+ vr->version = version;
+
+ vrrp_check_start(vr);
+
+ return NB_OK;
+}
+
+/*
+ * Helper function for address list OP_MODIFY callbacks.
+ */
+static void vrrp_yang_add_del_virtual_address(const struct lyd_node *dnode,
+ bool add)
+{
+ struct vrrp_vrouter *vr;
+ struct ipaddr ip;
+
+ vr = nb_running_get_entry(dnode, NULL, true);
+ yang_dnode_get_ip(&ip, dnode, NULL);
+ if (add)
+ vrrp_add_ip(vr, &ip);
+ else
+ vrrp_del_ip(vr, &ip);
+
+ vrrp_check_start(vr);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/virtual-address
+ */
+static int lib_interface_vrrp_vrrp_group_v4_virtual_address_create(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ vrrp_yang_add_del_virtual_address(dnode, true);
+
+ return NB_OK;
+}
+
+static int lib_interface_vrrp_vrrp_group_v4_virtual_address_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ vrrp_yang_add_del_virtual_address(dnode, false);
+
+ return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/current-priority
+ */
+static struct yang_data *
+lib_interface_vrrp_vrrp_group_v4_current_priority_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct vrrp_vrouter *vr = list_entry;
+
+ return yang_data_new_uint8(xpath, vr->v4->priority);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/vrrp-interface
+ */
+static struct yang_data *
+lib_interface_vrrp_vrrp_group_v4_vrrp_interface_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ const struct vrrp_vrouter *vr = list_entry;
+
+ struct yang_data *val = NULL;
+
+ if (vr->v4->mvl_ifp)
+ val = yang_data_new_string(xpath, vr->v4->mvl_ifp->name);
+
+ return val;
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/source-address
+ */
+static struct yang_data *
+lib_interface_vrrp_vrrp_group_v4_source_address_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ const struct vrrp_vrouter *vr = list_entry;
+ struct yang_data *val = NULL;
+ struct ipaddr ip;
+
+ memset(&ip, 0x00, sizeof(ip));
+
+ if (memcmp(&vr->v4->src.ipaddr_v4, &ip.ipaddr_v4, sizeof(ip.ipaddr_v4)))
+ val = yang_data_new_ip(xpath, &vr->v4->src);
+
+ return val;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/state
+ */
+static struct yang_data *
+lib_interface_vrrp_vrrp_group_v4_state_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ const struct vrrp_vrouter *vr = list_entry;
+
+ return yang_data_new_enum(xpath, vr->v4->fsm.state);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/master-advertisement-interval
+ */
+static struct yang_data *
+lib_interface_vrrp_vrrp_group_v4_master_advertisement_interval_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct vrrp_vrouter *vr = list_entry;
+
+ return yang_data_new_uint16(xpath, vr->v4->master_adver_interval);
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/skew-time
+ */
+static struct yang_data *
+lib_interface_vrrp_vrrp_group_v4_skew_time_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ const struct vrrp_vrouter *vr = list_entry;
+
+ return yang_data_new_uint16(xpath, vr->v4->skew_time);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/counter/state-transition
+ */
+static struct yang_data *
+lib_interface_vrrp_vrrp_group_v4_counter_state_transition_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct vrrp_vrouter *vr = list_entry;
+
+ return yang_data_new_uint32(xpath, vr->v4->stats.trans_cnt);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/counter/tx/advertisement
+ */
+static struct yang_data *
+lib_interface_vrrp_vrrp_group_v4_counter_tx_advertisement_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct vrrp_vrouter *vr = list_entry;
+
+ return yang_data_new_uint32(xpath, vr->v4->stats.adver_tx_cnt);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/counter/tx/gratuitous-arp
+ */
+static struct yang_data *
+lib_interface_vrrp_vrrp_group_v4_counter_tx_gratuitous_arp_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct vrrp_vrouter *vr = list_entry;
+
+ return yang_data_new_uint32(xpath, vr->v4->stats.garp_tx_cnt);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/counter/rx/advertisement
+ */
+static struct yang_data *
+lib_interface_vrrp_vrrp_group_v4_counter_rx_advertisement_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct vrrp_vrouter *vr = list_entry;
+
+ return yang_data_new_uint32(xpath, vr->v4->stats.adver_rx_cnt);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/virtual-address
+ */
+static int lib_interface_vrrp_vrrp_group_v6_virtual_address_create(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ vrrp_yang_add_del_virtual_address(dnode, true);
+
+ return NB_OK;
+}
+
+static int lib_interface_vrrp_vrrp_group_v6_virtual_address_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ vrrp_yang_add_del_virtual_address(dnode, false);
+
+ return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/current-priority
+ */
+static struct yang_data *
+lib_interface_vrrp_vrrp_group_v6_current_priority_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct vrrp_vrouter *vr = list_entry;
+
+ return yang_data_new_uint8(xpath, vr->v6->priority);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/vrrp-interface
+ */
+static struct yang_data *
+lib_interface_vrrp_vrrp_group_v6_vrrp_interface_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ const struct vrrp_vrouter *vr = list_entry;
+ struct yang_data *val = NULL;
+
+ if (vr->v6->mvl_ifp)
+ val = yang_data_new_string(xpath, vr->v6->mvl_ifp->name);
+
+ return val;
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/source-address
+ */
+static struct yang_data *
+lib_interface_vrrp_vrrp_group_v6_source_address_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ const struct vrrp_vrouter *vr = list_entry;
+ struct yang_data *val = NULL;
+
+ if (ipaddr_isset(&vr->v6->src))
+ val = yang_data_new_ip(xpath, &vr->v6->src);
+
+ return val;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/state
+ */
+static struct yang_data *
+lib_interface_vrrp_vrrp_group_v6_state_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ const struct vrrp_vrouter *vr = list_entry;
+
+ return yang_data_new_enum(xpath, vr->v6->fsm.state);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/master-advertisement-interval
+ */
+static struct yang_data *
+lib_interface_vrrp_vrrp_group_v6_master_advertisement_interval_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct vrrp_vrouter *vr = list_entry;
+
+ return yang_data_new_uint16(xpath, vr->v6->master_adver_interval);
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/skew-time
+ */
+static struct yang_data *
+lib_interface_vrrp_vrrp_group_v6_skew_time_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ const struct vrrp_vrouter *vr = list_entry;
+
+ return yang_data_new_uint16(xpath, vr->v6->skew_time);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/counter/state-transition
+ */
+static struct yang_data *
+lib_interface_vrrp_vrrp_group_v6_counter_state_transition_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct vrrp_vrouter *vr = list_entry;
+
+ return yang_data_new_uint32(xpath, vr->v6->stats.trans_cnt);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/counter/tx/advertisement
+ */
+static struct yang_data *
+lib_interface_vrrp_vrrp_group_v6_counter_tx_advertisement_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct vrrp_vrouter *vr = list_entry;
+
+ return yang_data_new_uint32(xpath, vr->v6->stats.adver_tx_cnt);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/counter/tx/neighbor-advertisement
+ */
+static struct yang_data *
+lib_interface_vrrp_vrrp_group_v6_counter_tx_neighbor_advertisement_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/counter/rx/advertisement
+ */
+static struct yang_data *
+lib_interface_vrrp_vrrp_group_v6_counter_rx_advertisement_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ /* TODO: implement me. */
+ return NULL;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/priority
+ */
+static int
+lib_interface_vrrp_vrrp_group_priority_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ struct vrrp_vrouter *vr;
+ uint8_t priority;
+
+ vr = nb_running_get_entry(dnode, NULL, true);
+ priority = yang_dnode_get_uint8(dnode, NULL);
+ vrrp_set_priority(vr, priority);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/preempt
+ */
+static int
+lib_interface_vrrp_vrrp_group_preempt_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ struct vrrp_vrouter *vr;
+ bool preempt;
+
+ vr = nb_running_get_entry(dnode, NULL, true);
+ preempt = yang_dnode_get_bool(dnode, NULL);
+ vr->preempt_mode = preempt;
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/accept-mode
+ */
+static int
+lib_interface_vrrp_vrrp_group_accept_mode_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ struct vrrp_vrouter *vr;
+ bool accept;
+
+ vr = nb_running_get_entry(dnode, NULL, true);
+ accept = yang_dnode_get_bool(dnode, NULL);
+ vr->accept_mode = accept;
+
+ return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/advertisement-interval
+ */
+static int lib_interface_vrrp_vrrp_group_advertisement_interval_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ struct vrrp_vrouter *vr;
+ uint16_t advert_int;
+
+ vr = nb_running_get_entry(dnode, NULL, true);
+ advert_int = yang_dnode_get_uint16(dnode, NULL);
+ vrrp_set_advertisement_interval(vr, advert_int);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/shutdown
+ */
+static int
+lib_interface_vrrp_vrrp_group_shutdown_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ struct vrrp_vrouter *vr;
+ bool shutdown;
+
+ vr = nb_running_get_entry(dnode, NULL, true);
+ shutdown = yang_dnode_get_bool(dnode, NULL);
+
+ vr->shutdown = shutdown;
+
+ if (shutdown) {
+ vrrp_event(vr->v4, VRRP_EVENT_SHUTDOWN);
+ vrrp_event(vr->v6, VRRP_EVENT_SHUTDOWN);
+ } else {
+ vrrp_check_start(vr);
+ }
+
+ return NB_OK;
+}
+
+/* clang-format off */
+const struct frr_yang_module_info frr_vrrpd_info = {
+ .name = "frr-vrrpd",
+ .nodes = {
+ {
+ .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group",
+ .cbs = {
+ .create = lib_interface_vrrp_vrrp_group_create,
+ .destroy = lib_interface_vrrp_vrrp_group_destroy,
+ .get_next = lib_interface_vrrp_vrrp_group_get_next,
+ .get_keys = lib_interface_vrrp_vrrp_group_get_keys,
+ .lookup_entry = lib_interface_vrrp_vrrp_group_lookup_entry,
+ .cli_show = cli_show_vrrp,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/version",
+ .cbs = {
+ .modify = lib_interface_vrrp_vrrp_group_version_modify,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/priority",
+ .cbs = {
+ .modify = lib_interface_vrrp_vrrp_group_priority_modify,
+ .cli_show = cli_show_priority,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/preempt",
+ .cbs = {
+ .modify = lib_interface_vrrp_vrrp_group_preempt_modify,
+ .cli_show = cli_show_preempt,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/accept-mode",
+ .cbs = {
+ .modify = lib_interface_vrrp_vrrp_group_accept_mode_modify,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/advertisement-interval",
+ .cbs = {
+ .modify = lib_interface_vrrp_vrrp_group_advertisement_interval_modify,
+ .cli_show = cli_show_advertisement_interval,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/shutdown",
+ .cbs = {
+ .modify = lib_interface_vrrp_vrrp_group_shutdown_modify,
+ .cli_show = cli_show_shutdown,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/virtual-address",
+ .cbs = {
+ .create = lib_interface_vrrp_vrrp_group_v4_virtual_address_create,
+ .destroy = lib_interface_vrrp_vrrp_group_v4_virtual_address_destroy,
+ .cli_show = cli_show_ip,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/current-priority",
+ .cbs = {
+ .get_elem = lib_interface_vrrp_vrrp_group_v4_current_priority_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/vrrp-interface",
+ .cbs = {
+ .get_elem = lib_interface_vrrp_vrrp_group_v4_vrrp_interface_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/source-address",
+ .cbs = {
+ .get_elem = lib_interface_vrrp_vrrp_group_v4_source_address_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/state",
+ .cbs = {
+ .get_elem = lib_interface_vrrp_vrrp_group_v4_state_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/master-advertisement-interval",
+ .cbs = {
+ .get_elem = lib_interface_vrrp_vrrp_group_v4_master_advertisement_interval_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/skew-time",
+ .cbs = {
+ .get_elem = lib_interface_vrrp_vrrp_group_v4_skew_time_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/counter/state-transition",
+ .cbs = {
+ .get_elem = lib_interface_vrrp_vrrp_group_v4_counter_state_transition_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/counter/tx/advertisement",
+ .cbs = {
+ .get_elem = lib_interface_vrrp_vrrp_group_v4_counter_tx_advertisement_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/counter/tx/gratuitous-arp",
+ .cbs = {
+ .get_elem = lib_interface_vrrp_vrrp_group_v4_counter_tx_gratuitous_arp_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/counter/rx/advertisement",
+ .cbs = {
+ .get_elem = lib_interface_vrrp_vrrp_group_v4_counter_rx_advertisement_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/virtual-address",
+ .cbs = {
+ .create = lib_interface_vrrp_vrrp_group_v6_virtual_address_create,
+ .destroy = lib_interface_vrrp_vrrp_group_v6_virtual_address_destroy,
+ .cli_show = cli_show_ipv6,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/current-priority",
+ .cbs = {
+ .get_elem = lib_interface_vrrp_vrrp_group_v6_current_priority_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/vrrp-interface",
+ .cbs = {
+ .get_elem = lib_interface_vrrp_vrrp_group_v6_vrrp_interface_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/source-address",
+ .cbs = {
+ .get_elem = lib_interface_vrrp_vrrp_group_v6_source_address_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/state",
+ .cbs = {
+ .get_elem = lib_interface_vrrp_vrrp_group_v6_state_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/master-advertisement-interval",
+ .cbs = {
+ .get_elem = lib_interface_vrrp_vrrp_group_v6_master_advertisement_interval_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/skew-time",
+ .cbs = {
+ .get_elem = lib_interface_vrrp_vrrp_group_v6_skew_time_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/counter/state-transition",
+ .cbs = {
+ .get_elem = lib_interface_vrrp_vrrp_group_v6_counter_state_transition_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/counter/tx/advertisement",
+ .cbs = {
+ .get_elem = lib_interface_vrrp_vrrp_group_v6_counter_tx_advertisement_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/counter/tx/neighbor-advertisement",
+ .cbs = {
+ .get_elem = lib_interface_vrrp_vrrp_group_v6_counter_tx_neighbor_advertisement_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/counter/rx/advertisement",
+ .cbs = {
+ .get_elem = lib_interface_vrrp_vrrp_group_v6_counter_rx_advertisement_get_elem,
+ }
+ },
+ {
+ .xpath = NULL,
+ },
+ }
+};
diff --git a/vrrpd/vrrp_vty.c b/vrrpd/vrrp_vty.c
index 239b02ee7f..892c8dadd4 100644
--- a/vrrpd/vrrp_vty.c
+++ b/vrrpd/vrrp_vty.c
@@ -23,9 +23,11 @@
#include "lib/if.h"
#include "lib/ipaddr.h"
#include "lib/json.h"
+#include "lib/northbound_cli.h"
#include "lib/prefix.h"
#include "lib/termtable.h"
#include "lib/vty.h"
+#include "lib/vrf.h"
#include "vrrp.h"
#include "vrrp_debug.h"
@@ -40,22 +42,16 @@
#define VRRP_VRID_STR "Virtual Router ID\n"
#define VRRP_PRIORITY_STR "Virtual Router Priority\n"
#define VRRP_ADVINT_STR "Virtual Router Advertisement Interval\n"
-#define VRRP_IP_STR "Virtual Router IPv4 address\n"
+#define VRRP_IP_STR "Virtual Router IP address\n"
#define VRRP_VERSION_STR "VRRP protocol version\n"
-#define VROUTER_GET_VTY(_vty, _ifp, _vrid, _vr) \
- do { \
- _vr = vrrp_lookup(_ifp, _vrid); \
- if (!_vr) { \
- vty_out(_vty, \
- "%% Please configure VRRP instance %u\n", \
- (unsigned int)_vrid); \
- return CMD_WARNING_CONFIG_FAILED; \
- } \
- } while (0)
+#define VRRP_XPATH_ENTRY VRRP_XPATH "[virtual-router-id='%ld']"
/* clang-format off */
+/*
+ * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group
+ */
DEFPY(vrrp_vrid,
vrrp_vrid_cmd,
"[no] vrrp (1-255)$vrid [version (2-3)]",
@@ -65,27 +61,34 @@ DEFPY(vrrp_vrid,
VRRP_VERSION_STR
VRRP_VERSION_STR)
{
- VTY_DECLVAR_CONTEXT(interface, ifp);
+ char valbuf[20];
- struct vrrp_vrouter *vr = vrrp_lookup(ifp, vrid);
+ snprintf(valbuf, sizeof(valbuf), "%ld", version ? version : vd.version);
- if (version == 0)
- version = 3;
+ if (no)
+ nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
+ else {
+ nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL);
+ nb_cli_enqueue_change(vty, "./version", NB_OP_MODIFY, valbuf);
+ }
- if (no && vr)
- vrrp_vrouter_destroy(vr);
- else if (no && !vr)
- vty_out(vty, "%% VRRP instance %ld does not exist on %s\n",
- vrid, ifp->name);
- else if (!vr)
- vrrp_vrouter_create(ifp, vrid, version);
- else if (vr)
- vty_out(vty, "%% VRRP instance %ld already exists on %s\n",
- vrid, ifp->name);
+ return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid);
+}
- return CMD_SUCCESS;
+void cli_show_vrrp(struct vty *vty, struct lyd_node *dnode, bool show_defaults)
+{
+ const char *vrid = yang_dnode_get_string(dnode, "./virtual-router-id");
+ const char *ver = yang_dnode_get_string(dnode, "./version");
+
+ vty_out(vty, " vrrp %s", vrid);
+ if (show_defaults || !yang_dnode_is_default(dnode, "./version"))
+ vty_out(vty, " version %s", ver);
+ vty_out(vty, "\n");
}
+/*
+ * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/shutdown
+ */
DEFPY(vrrp_shutdown,
vrrp_shutdown_cmd,
"[no] vrrp (1-255)$vrid shutdown",
@@ -94,74 +97,114 @@ DEFPY(vrrp_shutdown,
VRRP_VRID_STR
"Force VRRP router into administrative shutdown\n")
{
- VTY_DECLVAR_CONTEXT(interface, ifp);
+ nb_cli_enqueue_change(vty, "./shutdown", NB_OP_MODIFY,
+ no ? "false" : "true");
- struct vrrp_vrouter *vr;
+ return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid);
+}
- VROUTER_GET_VTY(vty, ifp, vrid, vr);
-
- if (!no) {
- if (vr->v4->fsm.state != VRRP_STATE_INITIALIZE)
- vrrp_event(vr->v4, VRRP_EVENT_SHUTDOWN);
- if (vr->v6->fsm.state != VRRP_STATE_INITIALIZE)
- vrrp_event(vr->v6, VRRP_EVENT_SHUTDOWN);
- vr->shutdown = true;
- } else {
- vr->shutdown = false;
- vrrp_check_start(vr);
- }
+void cli_show_shutdown(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ const char *vrid = yang_dnode_get_string(dnode, "../virtual-router-id");
+ const bool shut = yang_dnode_get_bool(dnode, NULL);
- return CMD_SUCCESS;
+ vty_out(vty, " %svrrp %s shutdown\n", shut ? "" : "no ", vrid);
}
+/*
+ * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/priority
+ */
DEFPY(vrrp_priority,
vrrp_priority_cmd,
- "[no] vrrp (1-255)$vrid priority (1-254)",
- NO_STR
+ "vrrp (1-255)$vrid priority (1-254)",
VRRP_STR
VRRP_VRID_STR
VRRP_PRIORITY_STR
"Priority value")
{
- VTY_DECLVAR_CONTEXT(interface, ifp);
+ nb_cli_enqueue_change(vty, "./priority", NB_OP_MODIFY, priority_str);
- struct vrrp_vrouter *vr;
- uint8_t newprio = no ? vd.priority : priority;
+ return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid);
+}
- VROUTER_GET_VTY(vty, ifp, vrid, vr);
+/*
+ * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/priority
+ */
+DEFPY(no_vrrp_priority,
+ no_vrrp_priority_cmd,
+ "no vrrp (1-255)$vrid priority [(1-254)]",
+ NO_STR
+ VRRP_STR
+ VRRP_VRID_STR
+ VRRP_PRIORITY_STR
+ "Priority value")
+{
+ nb_cli_enqueue_change(vty, "./priority", NB_OP_MODIFY, NULL);
- vrrp_set_priority(vr, newprio);
+ return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid);
+}
- return CMD_SUCCESS;
+void cli_show_priority(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ const char *vrid = yang_dnode_get_string(dnode, "../virtual-router-id");
+ const char *prio = yang_dnode_get_string(dnode, NULL);
+
+ vty_out(vty, " vrrp %s priority %s\n", vrid, prio);
}
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/advertisement-interval
+ */
DEFPY(vrrp_advertisement_interval,
vrrp_advertisement_interval_cmd,
- "[no] vrrp (1-255)$vrid advertisement-interval (10-40950)",
- NO_STR VRRP_STR VRRP_VRID_STR VRRP_ADVINT_STR
+ "vrrp (1-255)$vrid advertisement-interval (10-40950)",
+ VRRP_STR VRRP_VRID_STR VRRP_ADVINT_STR
"Advertisement interval in milliseconds; must be multiple of 10")
{
- VTY_DECLVAR_CONTEXT(interface, ifp);
+ char val[20];
- struct vrrp_vrouter *vr;
- uint16_t newadvint =
- no ? vd.advertisement_interval * CS2MS : advertisement_interval;
+ /* all internal computations are in centiseconds */
+ advertisement_interval /= CS2MS;
+ snprintf(val, sizeof(val), "%ld", advertisement_interval);
+ nb_cli_enqueue_change(vty, "./advertisement-interval", NB_OP_MODIFY,
+ val);
- if (newadvint % CS2MS != 0) {
- vty_out(vty, "%% Value must be a multiple of %u\n",
- (unsigned int)CS2MS);
- return CMD_WARNING_CONFIG_FAILED;
- }
+ return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid);
+}
- /* all internal computations are in centiseconds */
- newadvint /= CS2MS;
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/advertisement-interval
+ */
+DEFPY(no_vrrp_advertisement_interval,
+ no_vrrp_advertisement_interval_cmd,
+ "no vrrp (1-255)$vrid advertisement-interval [(10-40950)]",
+ NO_STR VRRP_STR VRRP_VRID_STR VRRP_ADVINT_STR
+ "Advertisement interval in milliseconds; must be multiple of 10")
+{
+ nb_cli_enqueue_change(vty, "./advertisement-interval", NB_OP_MODIFY,
+ NULL);
- VROUTER_GET_VTY(vty, ifp, vrid, vr);
- vrrp_set_advertisement_interval(vr, newadvint);
+ return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid);
+}
- return CMD_SUCCESS;
+void cli_show_advertisement_interval(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ const char *vrid = yang_dnode_get_string(dnode, "../virtual-router-id");
+ uint16_t advint = yang_dnode_get_uint16(dnode, NULL);
+
+ vty_out(vty, " vrrp %s advertisement-interval %u\n", vrid,
+ advint * CS2MS);
}
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/virtual-address
+ */
DEFPY(vrrp_ip,
vrrp_ip_cmd,
"[no] vrrp (1-255)$vrid ip A.B.C.D",
@@ -171,51 +214,25 @@ DEFPY(vrrp_ip,
"Add IPv4 address\n"
VRRP_IP_STR)
{
- VTY_DECLVAR_CONTEXT(interface, ifp);
+ int op = no ? NB_OP_DESTROY : NB_OP_CREATE;
+ nb_cli_enqueue_change(vty, "./v4/virtual-address", op, ip_str);
- struct vrrp_vrouter *vr;
- bool deactivated = false;
- bool activated = false;
- bool failed = false;
- int ret = CMD_SUCCESS;
- int oldstate;
-
- VROUTER_GET_VTY(vty, ifp, vrid, vr);
-
- bool will_activate = (vr->v4->fsm.state == VRRP_STATE_INITIALIZE);
-
- if (no) {
- oldstate = vr->v4->fsm.state;
- failed = vrrp_del_ipv4(vr, ip);
- vrrp_check_start(vr);
- deactivated = (vr->v4->fsm.state == VRRP_STATE_INITIALIZE
- && oldstate != VRRP_STATE_INITIALIZE);
- } else {
- oldstate = vr->v4->fsm.state;
- failed = vrrp_add_ipv4(vr, ip);
- vrrp_check_start(vr);
- activated = (vr->v4->fsm.state != VRRP_STATE_INITIALIZE
- && oldstate == VRRP_STATE_INITIALIZE);
- }
+ return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid);
+}
- if (activated)
- vty_out(vty, "%% Activated IPv4 Virtual Router %ld\n", vrid);
- if (deactivated)
- vty_out(vty, "%% Deactivated IPv4 Virtual Router %ld\n", vrid);
- if (failed) {
- vty_out(vty, "%% Failed to %s virtual IP\n",
- no ? "remove" : "add");
- ret = CMD_WARNING_CONFIG_FAILED;
- if (will_activate && !activated) {
- vty_out(vty,
- "%% Failed to activate IPv4 Virtual Router %ld\n",
- vrid);
- }
- }
+void cli_show_ip(struct vty *vty, struct lyd_node *dnode, bool show_defaults)
+{
+ const char *vrid =
+ yang_dnode_get_string(dnode, "../../virtual-router-id");
+ const char *ipv4 = yang_dnode_get_string(dnode, NULL);
- return ret;
+ vty_out(vty, " vrrp %s ip %s\n", vrid, ipv4);
}
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/virtual-address
+ */
DEFPY(vrrp_ip6,
vrrp_ip6_cmd,
"[no] vrrp (1-255)$vrid ipv6 X:X::X:X",
@@ -225,57 +242,24 @@ DEFPY(vrrp_ip6,
"Add IPv6 address\n"
VRRP_IP_STR)
{
- VTY_DECLVAR_CONTEXT(interface, ifp);
-
- struct vrrp_vrouter *vr;
- bool deactivated = false;
- bool activated = false;
- bool failed = false;
- int ret = CMD_SUCCESS;
- int oldstate;
-
- VROUTER_GET_VTY(vty, ifp, vrid, vr);
-
- if (vr->version != 3) {
- vty_out(vty,
- "%% Cannot add IPv6 address to VRRPv2 virtual router\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
+ int op = no ? NB_OP_DESTROY : NB_OP_CREATE;
+ nb_cli_enqueue_change(vty, "./v6/virtual-address", op, ipv6_str);
- bool will_activate = (vr->v6->fsm.state == VRRP_STATE_INITIALIZE);
-
- if (no) {
- oldstate = vr->v6->fsm.state;
- failed = vrrp_del_ipv6(vr, ipv6);
- vrrp_check_start(vr);
- deactivated = (vr->v6->fsm.state == VRRP_STATE_INITIALIZE
- && oldstate != VRRP_STATE_INITIALIZE);
- } else {
- oldstate = vr->v6->fsm.state;
- failed = vrrp_add_ipv6(vr, ipv6);
- vrrp_check_start(vr);
- activated = (vr->v6->fsm.state != VRRP_STATE_INITIALIZE
- && oldstate == VRRP_STATE_INITIALIZE);
- }
+ return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid);
+}
- if (activated)
- vty_out(vty, "%% Activated IPv6 Virtual Router %ld\n", vrid);
- if (deactivated)
- vty_out(vty, "%% Deactivated IPv6 Virtual Router %ld\n", vrid);
- if (failed) {
- vty_out(vty, "%% Failed to %s virtual IP\n",
- no ? "remove" : "add");
- ret = CMD_WARNING_CONFIG_FAILED;
- if (will_activate && !activated) {
- vty_out(vty,
- "%% Failed to activate IPv6 Virtual Router %ld\n",
- vrid);
- }
- }
+void cli_show_ipv6(struct vty *vty, struct lyd_node *dnode, bool show_defaults)
+{
+ const char *vrid =
+ yang_dnode_get_string(dnode, "../../virtual-router-id");
+ const char *ipv6 = yang_dnode_get_string(dnode, NULL);
- return ret;
+ vty_out(vty, " vrrp %s ipv6 %s\n", vrid, ipv6);
}
+/*
+ * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/preempt
+ */
DEFPY(vrrp_preempt,
vrrp_preempt_cmd,
"[no] vrrp (1-255)$vrid preempt",
@@ -284,17 +268,22 @@ DEFPY(vrrp_preempt,
VRRP_VRID_STR
"Preempt mode\n")
{
- VTY_DECLVAR_CONTEXT(interface, ifp);
-
- struct vrrp_vrouter *vr;
+ nb_cli_enqueue_change(vty, "./preempt", NB_OP_MODIFY,
+ no ? "false" : "true");
- VROUTER_GET_VTY(vty, ifp, vrid, vr);
+ return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid);
+}
- vr->preempt_mode = !no;
+void cli_show_preempt(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ const char *vrid = yang_dnode_get_string(dnode, "../virtual-router-id");
+ const bool pre = yang_dnode_get_bool(dnode, NULL);
- return CMD_SUCCESS;
+ vty_out(vty, " %svrrp %s preempt\n", pre ? "" : "no ", vrid);
}
+/* XXX: yang conversion */
DEFPY(vrrp_autoconfigure,
vrrp_autoconfigure_cmd,
"[no] vrrp autoconfigure [version (2-3)]",
@@ -314,6 +303,7 @@ DEFPY(vrrp_autoconfigure,
return CMD_SUCCESS;
}
+/* XXX: yang conversion */
DEFPY(vrrp_default,
vrrp_default_cmd,
"[no] vrrp default <advertisement-interval$adv (10-40950)$advint|preempt$p|priority$prio (1-254)$prioval|shutdown$s>",
@@ -725,6 +715,35 @@ DEFUN_NOSH (show_debugging_vrrp,
/* clang-format on */
+/*
+ * Write per interface VRRP config.
+ */
+static int vrrp_config_write_interface(struct vty *vty)
+{
+ struct vrf *vrf;
+ int write = 0;
+
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ struct interface *ifp;
+
+ FOR_ALL_INTERFACES (vrf, ifp) {
+ struct lyd_node *dnode;
+
+ dnode = yang_dnode_get(
+ running_config->dnode,
+ "/frr-interface:lib/interface[name='%s'][vrf='%s']",
+ ifp->name, vrf->name);
+ if (dnode == NULL)
+ continue;
+
+ write = 1;
+ nb_cli_show_dnode_cmds(vty, dnode, false);
+ }
+ }
+
+ return write;
+}
+
static struct cmd_node interface_node = {INTERFACE_NODE, "%s(config-if)# ", 1};
static struct cmd_node debug_node = {DEBUG_NODE, "", 1};
static struct cmd_node vrrp_node = {VRRP_NODE, "", 1};
@@ -746,7 +765,9 @@ void vrrp_vty_init(void)
install_element(INTERFACE_NODE, &vrrp_vrid_cmd);
install_element(INTERFACE_NODE, &vrrp_shutdown_cmd);
install_element(INTERFACE_NODE, &vrrp_priority_cmd);
+ install_element(INTERFACE_NODE, &no_vrrp_priority_cmd);
install_element(INTERFACE_NODE, &vrrp_advertisement_interval_cmd);
+ install_element(INTERFACE_NODE, &no_vrrp_advertisement_interval_cmd);
install_element(INTERFACE_NODE, &vrrp_ip_cmd);
install_element(INTERFACE_NODE, &vrrp_ip6_cmd);
install_element(INTERFACE_NODE, &vrrp_preempt_cmd);
diff --git a/vrrpd/vrrp_vty.h b/vrrpd/vrrp_vty.h
index 377321ec4a..6c6eef0327 100644
--- a/vrrpd/vrrp_vty.h
+++ b/vrrpd/vrrp_vty.h
@@ -20,6 +20,21 @@
#ifndef __VRRP_VTY_H__
#define __VRRP_VTY_H__
+#include "lib/northbound.h"
+
void vrrp_vty_init(void);
+/* Northbound callbacks */
+void cli_show_vrrp(struct vty *vty, struct lyd_node *dnode, bool show_defaults);
+void cli_show_shutdown(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_priority(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_advertisement_interval(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ip(struct vty *vty, struct lyd_node *dnode, bool show_defaults);
+void cli_show_ipv6(struct vty *vty, struct lyd_node *dnode, bool show_defaults);
+void cli_show_preempt(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+
#endif /* __VRRP_VTY_H__ */
diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang
index faa880eff4..faab1e55b2 100644
--- a/yang/frr-isisd.yang
+++ b/yang/frr-isisd.yang
@@ -27,6 +27,10 @@ module frr-isisd {
description
"This module defines a model for managing FRR isisd daemon.";
+ revision 2019-12-17 {
+ description
+ "Changed default area is-type to level-1-2";
+ }
revision 2019-09-09 {
description
"Changed interface references to use
@@ -748,7 +752,7 @@ module frr-isisd {
leaf is-type {
type level;
- default "level-1";
+ default "level-1-2";
description
"Level of the IS-IS routing instance (OSI only).";
}
diff --git a/yang/frr-vrrpd.yang b/yang/frr-vrrpd.yang
new file mode 100644
index 0000000000..3d3a4138fa
--- /dev/null
+++ b/yang/frr-vrrpd.yang
@@ -0,0 +1,260 @@
+module frr-vrrpd {
+ yang-version 1.1;
+ namespace "http://frrouting.org/yang/vrrpd";
+ prefix frr-vrrpd;
+
+ import ietf-inet-types {
+ prefix inet;
+ }
+
+ import ietf-yang-types {
+ prefix yang;
+ }
+
+ import frr-interface {
+ prefix frr-interface;
+ }
+
+ organization
+ "Free Range Routing";
+ contact
+ "FRR Users List: <mailto:frog@lists.frrouting.org>
+ FRR Development List: <mailto:dev@lists.frrouting.org>";
+ description
+ "This module defines a model for managing FRR vrrpd daemon.";
+
+ revision 2019-09-09 {
+ description
+ "Initial revision.";
+ }
+
+ grouping ip-vrrp-config {
+ description
+ "Configuration data for VRRP on IP interfaces";
+ leaf virtual-router-id {
+ type uint8 {
+ range "1..255";
+ }
+ description
+ "Set the virtual router id for use by the VRRP group. This
+ usually also determines the virtual MAC address that is
+ generated for the VRRP group";
+ }
+
+ leaf version {
+ type enumeration {
+ enum "2" {
+ value 2;
+ description
+ "VRRP version 2.";
+ }
+ enum "3" {
+ value 3;
+ description
+ "VRRP version 3.";
+ }
+ }
+ default "3";
+ }
+
+ leaf priority {
+ type uint8 {
+ range "1..254";
+ }
+ default "100";
+ description
+ "Specifies the sending VRRP interface's priority
+ for the virtual router. Higher values equal higher
+ priority";
+ }
+
+ leaf preempt {
+ type boolean;
+ default "true";
+ description
+ "When set to true, enables preemption by a higher
+ priority backup router of a lower priority master router";
+ }
+
+ leaf accept-mode {
+ type boolean;
+ default "true";
+ description
+ "Configure whether packets destined for
+ virtual addresses are accepted even when the virtual
+ address is not owned by the router interface";
+ }
+
+ leaf advertisement-interval {
+ type uint16 {
+ range "1..4095";
+ }
+ units "centiseconds";
+ default "100";
+ description
+ "Sets the interval between successive VRRP
+ advertisements -- RFC 5798 defines this as a 12-bit
+ value expressed as 0.1 seconds, with default 100, i.e.,
+ 1 second. Several implementation express this in units of
+ seconds";
+ }
+
+ leaf shutdown {
+ type boolean;
+ default "false";
+ description
+ "Administrative shutdown for this VRRP group.";
+ }
+ }
+
+ grouping ip-vrrp-state {
+ description
+ "Grouping for operational state data for a virtual router";
+ leaf current-priority {
+ type uint8;
+ config false;
+ description
+ "Operational value of the priority for the
+ interface in the VRRP group.";
+ }
+
+ leaf vrrp-interface {
+ type frr-interface:interface-ref;
+ config false;
+ description
+ "The interface used to transmit VRRP traffic.";
+ }
+
+ leaf source-address {
+ type inet:ip-address;
+ config false;
+ description
+ "The source IP address used for VRRP advertisements.";
+ }
+
+ leaf state {
+ type enumeration {
+ enum "Initialize" {
+ description
+ "State when virtual router is waiting for a Startup event.";
+ }
+ enum "Master" {
+ description
+ "State when virtual router is functioning as the forwarding router
+ for the virtual addresses.";
+ }
+ enum "Backup" {
+ description
+ "State when virtual router is monitoring the availability and state
+ of the Master router.";
+ }
+ }
+ config false;
+ }
+
+ leaf master-advertisement-interval {
+ type uint16 {
+ range "0..4095";
+ }
+ units "centiseconds";
+ config false;
+ description
+ "Advertisement interval contained in advertisements received from the Master.";
+ }
+
+ leaf skew-time {
+ type uint16;
+ units "centiseconds";
+ config false;
+ description
+ "Time to skew Master_Down_Interval.";
+ }
+
+ container counter {
+ config false;
+ leaf state-transition {
+ type yang:zero-based-counter32;
+ description
+ "Number of state transitions the virtual router has experienced.";
+ }
+
+ container tx {
+ leaf advertisement {
+ type yang:zero-based-counter32;
+ description
+ "Number of sent VRRP advertisements.";
+ }
+ }
+
+ container rx {
+ leaf advertisement {
+ type yang:zero-based-counter32;
+ description
+ "Number of received VRRP advertisements.";
+ }
+ }
+ }
+ }
+
+ grouping ip-vrrp-top {
+ description
+ "Top-level grouping for Virtual Router Redundancy Protocol";
+ container vrrp {
+ description
+ "Enclosing container for VRRP groups handled by this
+ IP interface";
+ reference
+ "RFC 5798 - Virtual Router Redundancy Protocol
+ (VRRP) Version 3 for IPv4 and IPv6";
+ list vrrp-group {
+ key "virtual-router-id";
+ description
+ "List of VRRP groups, keyed by virtual router id";
+ uses ip-vrrp-config;
+
+ container v4 {
+ leaf-list virtual-address {
+ type inet:ipv4-address;
+ description
+ "Configure one or more IPv4 virtual addresses for the
+ VRRP group";
+ }
+
+ uses ip-vrrp-state {
+ augment "./counter/tx" {
+ leaf gratuitous-arp {
+ type yang:zero-based-counter32;
+ description
+ "Number of sent gratuitous ARP requests.";
+ }
+ }
+ }
+ }
+
+ container v6 {
+ when "../version = 3";
+ leaf-list virtual-address {
+ type inet:ipv6-address;
+ description
+ "Configure one or more IPv6 virtual addresses for the
+ VRRP group";
+ }
+
+ uses ip-vrrp-state {
+ augment "./counter/tx" {
+ leaf neighbor-advertisement {
+ type yang:zero-based-counter32;
+ description
+ "Number of sent unsolicited Neighbor Advertisements.";
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ augment "/frr-interface:lib/frr-interface:interface" {
+ uses ip-vrrp-top;
+ }
+}
diff --git a/yang/subdir.am b/yang/subdir.am
index b69239560f..cfaf1a6401 100644
--- a/yang/subdir.am
+++ b/yang/subdir.am
@@ -44,3 +44,7 @@ endif
if ISISD
dist_yangmodels_DATA += yang/frr-isisd.yang
endif
+
+if VRRPD
+dist_yangmodels_DATA += yang/frr-vrrpd.yang
+endif
diff --git a/zebra/debug.c b/zebra/debug.c
index 8e5fb0ea10..681dfb8753 100644
--- a/zebra/debug.c
+++ b/zebra/debug.c
@@ -39,6 +39,7 @@ unsigned long zebra_debug_vxlan;
unsigned long zebra_debug_pw;
unsigned long zebra_debug_dplane;
unsigned long zebra_debug_mlag;
+unsigned long zebra_debug_nexthop;
DEFINE_HOOK(zebra_debug_show_debugging, (struct vty *vty), (vty));
@@ -103,6 +104,10 @@ DEFUN_NOSH (show_debugging_zebra,
vty_out(vty, " Zebra dataplane debugging is on\n");
if (IS_ZEBRA_DEBUG_MLAG)
vty_out(vty, " Zebra mlag debugging is on\n");
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ vty_out(vty, "Zebra detailed nexthop debugging is on\n");
+ else if (IS_ZEBRA_DEBUG_NHG)
+ vty_out(vty, "Zebra nexthop debugging is on\n");
hook_call(zebra_debug_show_debugging, vty);
return CMD_SUCCESS;
@@ -443,6 +448,28 @@ DEFUN (no_debug_zebra_dplane,
return CMD_SUCCESS;
}
+DEFPY (debug_zebra_nexthop,
+ debug_zebra_nexthop_cmd,
+ "[no$no] debug zebra nexthop [detail$detail]",
+ NO_STR
+ DEBUG_STR
+ "Zebra configuration\n"
+ "Debug zebra nexthop events\n"
+ "Detailed information\n")
+{
+ if (no)
+ zebra_debug_nexthop = 0;
+ else {
+ SET_FLAG(zebra_debug_nexthop, ZEBRA_DEBUG_NHG);
+
+ if (detail)
+ SET_FLAG(zebra_debug_nexthop,
+ ZEBRA_DEBUG_NHG_DETAILED);
+ }
+
+ return CMD_SUCCESS;
+}
+
/* Debug node. */
struct cmd_node debug_node = {DEBUG_NODE, "", /* Debug node has no interface. */
1};
@@ -546,6 +573,7 @@ void zebra_debug_init(void)
zebra_debug_dplane = 0;
zebra_debug_mlag = 0;
zebra_debug_nht = 0;
+ zebra_debug_nexthop = 0;
install_node(&debug_node, config_write_debug);
@@ -563,6 +591,7 @@ void zebra_debug_init(void)
install_element(ENABLE_NODE, &debug_zebra_fpm_cmd);
install_element(ENABLE_NODE, &debug_zebra_dplane_cmd);
install_element(ENABLE_NODE, &debug_zebra_mlag_cmd);
+ install_element(ENABLE_NODE, &debug_zebra_nexthop_cmd);
install_element(ENABLE_NODE, &no_debug_zebra_events_cmd);
install_element(ENABLE_NODE, &no_debug_zebra_nht_cmd);
install_element(ENABLE_NODE, &no_debug_zebra_mpls_cmd);
@@ -585,6 +614,7 @@ void zebra_debug_init(void)
install_element(CONFIG_NODE, &debug_zebra_rib_cmd);
install_element(CONFIG_NODE, &debug_zebra_fpm_cmd);
install_element(CONFIG_NODE, &debug_zebra_dplane_cmd);
+ install_element(CONFIG_NODE, &debug_zebra_nexthop_cmd);
install_element(CONFIG_NODE, &no_debug_zebra_events_cmd);
install_element(CONFIG_NODE, &no_debug_zebra_nht_cmd);
install_element(CONFIG_NODE, &no_debug_zebra_mpls_cmd);
diff --git a/zebra/debug.h b/zebra/debug.h
index 176226f7ae..e513f8865d 100644
--- a/zebra/debug.h
+++ b/zebra/debug.h
@@ -59,6 +59,9 @@ extern "C" {
#define ZEBRA_DEBUG_MLAG 0x01
+#define ZEBRA_DEBUG_NHG 0x01
+#define ZEBRA_DEBUG_NHG_DETAILED 0x02
+
/* Debug related macro. */
#define IS_ZEBRA_DEBUG_EVENT (zebra_debug_event & ZEBRA_DEBUG_EVENT)
@@ -92,6 +95,11 @@ extern "C" {
#define IS_ZEBRA_DEBUG_MLAG (zebra_debug_mlag & ZEBRA_DEBUG_MLAG)
+#define IS_ZEBRA_DEBUG_NHG (zebra_debug_nexthop & ZEBRA_DEBUG_NHG)
+
+#define IS_ZEBRA_DEBUG_NHG_DETAIL \
+ (zebra_debug_nexthop & ZEBRA_DEBUG_NHG_DETAILED)
+
extern unsigned long zebra_debug_event;
extern unsigned long zebra_debug_packet;
extern unsigned long zebra_debug_kernel;
@@ -103,6 +111,7 @@ extern unsigned long zebra_debug_vxlan;
extern unsigned long zebra_debug_pw;
extern unsigned long zebra_debug_dplane;
extern unsigned long zebra_debug_mlag;
+extern unsigned long zebra_debug_nexthop;
extern void zebra_debug_init(void);
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index c09007bcb1..4731d1ed15 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -366,7 +366,7 @@ static void netlink_vrf_change(struct nlmsghdr *h, struct rtattr *tb,
}
}
-static int get_iflink_speed(struct interface *interface, int *error)
+static uint32_t get_iflink_speed(struct interface *interface, int *error)
{
struct ifreq ifdata;
struct ethtool_cmd ecmd;
@@ -419,7 +419,7 @@ static int get_iflink_speed(struct interface *interface, int *error)
close(sd);
- return (ecmd.speed_hi << 16) | ecmd.speed;
+ return ((uint32_t)ecmd.speed_hi << 16) | ecmd.speed;
}
uint32_t kernel_get_speed(struct interface *ifp, int *error)
@@ -1467,7 +1467,7 @@ int netlink_protodown(struct interface *ifp, bool down)
req.ifa.ifi_index = ifp->ifindex;
- addattr_l(&req.n, sizeof(req), IFLA_PROTO_DOWN, &down, 4);
+ addattr_l(&req.n, sizeof(req), IFLA_PROTO_DOWN, &down, sizeof(down));
addattr_l(&req.n, sizeof(req), IFLA_LINK, &ifp->ifindex, 4);
return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c
index 23f1a3bf86..c3d5bf8428 100644
--- a/zebra/kernel_netlink.c
+++ b/zebra/kernel_netlink.c
@@ -290,6 +290,18 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id,
return netlink_neigh_change(h, ns_id);
case RTM_DELNEIGH:
return netlink_neigh_change(h, ns_id);
+ case RTM_GETNEIGH:
+ /*
+ * Kernel in some situations when it expects
+ * user space to resolve arp entries, we will
+ * receive this notification. As we don't
+ * need this notification and as that
+ * we don't want to spam the log file with
+ * below messages, just ignore.
+ */
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("Received RTM_GETNEIGH, ignoring");
+ break;
case RTM_NEWRULE:
return netlink_rule_change(h, ns_id, startup);
case RTM_DELRULE:
@@ -1086,7 +1098,7 @@ int netlink_request(struct nlsock *nl, struct nlmsghdr *n)
netlink_socket (). */
void kernel_init(struct zebra_ns *zns)
{
- unsigned long groups;
+ uint32_t groups;
#if defined SOL_NETLINK
int one, ret;
#endif
@@ -1107,9 +1119,9 @@ void kernel_init(struct zebra_ns *zns)
RTMGRP_IPV6_IFADDR |
RTMGRP_IPV4_MROUTE |
RTMGRP_NEIGH |
- (1 << (RTNLGRP_IPV4_RULE - 1)) |
- (1 << (RTNLGRP_IPV6_RULE - 1)) |
- (1 << (RTNLGRP_NEXTHOP - 1));
+ ((uint32_t) 1 << (RTNLGRP_IPV4_RULE - 1)) |
+ ((uint32_t) 1 << (RTNLGRP_IPV6_RULE - 1)) |
+ ((uint32_t) 1 << (RTNLGRP_NEXTHOP - 1));
snprintf(zns->netlink.name, sizeof(zns->netlink.name),
"netlink-listen (NS %u)", zns->ns_id);
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index fff569c092..29a341abbd 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -787,34 +787,10 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
} else {
if (!tb[RTA_MULTIPATH]) {
struct nexthop nh;
- size_t sz = (afi == AFI_IP) ? 4 : 16;
-
- memset(&nh, 0, sizeof(nh));
- if (bh_type == BLACKHOLE_UNSPEC) {
- if (index && !gate)
- nh.type = NEXTHOP_TYPE_IFINDEX;
- else if (index && gate)
- nh.type =
- (afi == AFI_IP)
- ? NEXTHOP_TYPE_IPV4_IFINDEX
- : NEXTHOP_TYPE_IPV6_IFINDEX;
- else if (!index && gate)
- nh.type =
- (afi == AFI_IP)
- ? NEXTHOP_TYPE_IPV4
- : NEXTHOP_TYPE_IPV6;
- else {
- nh.type =
- NEXTHOP_TYPE_BLACKHOLE;
- nh.bh_type = BLACKHOLE_UNSPEC;
- }
- } else {
- nh.type = NEXTHOP_TYPE_BLACKHOLE;
- nh.bh_type = bh_type;
- }
- nh.ifindex = index;
- if (gate)
- memcpy(&nh.gate, gate, sz);
+
+ nh = parse_nexthop_unicast(
+ ns_id, rtm, tb, bh_type, index, prefsrc,
+ gate, afi, vrf_id);
rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0,
flags, &p, &src_p, &nh, 0, table,
metric, distance, true);
diff --git a/zebra/rtadv.c b/zebra/rtadv.c
index 5dd6012f62..e9a97d4b15 100644
--- a/zebra/rtadv.c
+++ b/zebra/rtadv.c
@@ -965,16 +965,25 @@ static void zebra_interface_radv_set(ZAPI_HANDLER_ARGS, int enable)
ifindex_t ifindex;
struct interface *ifp;
struct zebra_if *zif;
- int ra_interval;
+ int ra_interval_rxd;
s = msg;
/* Get interface index and RA interval. */
STREAM_GETL(s, ifindex);
- STREAM_GETL(s, ra_interval);
+ 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;
if (IS_ZEBRA_DEBUG_EVENT)
- zlog_debug("%u: IF %u RA %s from client %s, interval %ds",
+ zlog_debug("%u: IF %u RA %s from client %s, interval %ums",
zvrf_id(zvrf), ifindex,
enable ? "enable" : "disable",
zebra_route_string(client->proto), ra_interval);
@@ -1001,7 +1010,7 @@ static void zebra_interface_radv_set(ZAPI_HANDLER_ARGS, int enable)
SET_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED);
ipv6_nd_suppress_ra_set(ifp, RA_ENABLE);
if (ra_interval
- && (ra_interval * 1000) < zif->rtadv.MaxRtrAdvInterval
+ && (ra_interval * 1000) < (unsigned int) zif->rtadv.MaxRtrAdvInterval
&& !CHECK_FLAG(zif->rtadv.ra_configured,
VTY_RA_INTERVAL_CONFIGURED))
zif->rtadv.MaxRtrAdvInterval = ra_interval * 1000;
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index 1dbe41f462..5a63c1e4f6 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -2136,6 +2136,7 @@ static void zread_pseudowire(ZAPI_HANDLER_ARGS)
/* Get data. */
STREAM_GET(ifname, s, IF_NAMESIZE);
+ ifname[IF_NAMESIZE - 1] = '\0';
STREAM_GETL(s, ifindex);
STREAM_GETL(s, type);
STREAM_GETL(s, af);
@@ -2360,6 +2361,20 @@ static inline void zread_rule(ZAPI_HANDLER_ARGS)
if (zpr.rule.filter.fwmark)
zpr.rule.filter.filter_bm |= PBR_FILTER_FWMARK;
+ if (!(zpr.rule.filter.src_ip.family == AF_INET
+ || zpr.rule.filter.src_ip.family == AF_INET6)) {
+ zlog_warn("Unsupported PBR source IP family: %s\n",
+ family2str(zpr.rule.filter.src_ip.family));
+ return;
+ }
+ if (!(zpr.rule.filter.dst_ip.family == AF_INET
+ || zpr.rule.filter.dst_ip.family == AF_INET6)) {
+ zlog_warn("Unsupported PBR dest IP family: %s\n",
+ family2str(zpr.rule.filter.dst_ip.family));
+ return;
+ }
+
+
zpr.vrf_id = zvrf->vrf->vrf_id;
if (hdr->command == ZEBRA_RULE_ADD)
zebra_pbr_add_rule(&zpr);
@@ -2416,6 +2431,7 @@ static inline void zread_ipset_entry(ZAPI_HANDLER_ARGS)
zpi.sock = client->sock;
STREAM_GETL(s, zpi.unique);
STREAM_GET(&ipset.ipset_name, s, ZEBRA_IPSET_NAME_SIZE);
+ ipset.ipset_name[ZEBRA_IPSET_NAME_SIZE - 1] = '\0';
STREAM_GETC(s, zpi.src.family);
STREAM_GETC(s, zpi.src.prefixlen);
STREAM_GET(&zpi.src.u.prefix, s, prefix_blen(&zpi.src));
@@ -2447,6 +2463,13 @@ static inline void zread_ipset_entry(ZAPI_HANDLER_ARGS)
/* calculate backpointer */
zpi.backpointer =
zebra_pbr_lookup_ipset_pername(ipset.ipset_name);
+
+ if (!zpi.backpointer) {
+ zlog_warn("ipset name specified: %s does not exist",
+ ipset.ipset_name);
+ goto stream_failure;
+ }
+
if (hdr->command == ZEBRA_IPSET_ENTRY_ADD)
zebra_pbr_add_ipset_entry(&zpi);
else
@@ -2459,37 +2482,39 @@ stream_failure:
static inline void zread_iptable(ZAPI_HANDLER_ARGS)
{
- struct zebra_pbr_iptable zpi;
+ struct zebra_pbr_iptable *zpi =
+ XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_iptable));
struct stream *s;
s = msg;
- memset(&zpi, 0, sizeof(zpi));
-
- zpi.interface_name_list = list_new();
- zpi.sock = client->sock;
- zpi.vrf_id = zvrf->vrf->vrf_id;
- STREAM_GETL(s, zpi.unique);
- STREAM_GETL(s, zpi.type);
- STREAM_GETL(s, zpi.filter_bm);
- STREAM_GETL(s, zpi.action);
- STREAM_GETL(s, zpi.fwmark);
- STREAM_GET(&zpi.ipset_name, s, ZEBRA_IPSET_NAME_SIZE);
- STREAM_GETW(s, zpi.pkt_len_min);
- STREAM_GETW(s, zpi.pkt_len_max);
- STREAM_GETW(s, zpi.tcp_flags);
- STREAM_GETW(s, zpi.tcp_mask_flags);
- STREAM_GETC(s, zpi.dscp_value);
- STREAM_GETC(s, zpi.fragment);
- STREAM_GETC(s, zpi.protocol);
- STREAM_GETL(s, zpi.nb_interface);
- zebra_pbr_iptable_update_interfacelist(s, &zpi);
+ zpi->interface_name_list = list_new();
+ zpi->sock = client->sock;
+ zpi->vrf_id = zvrf->vrf->vrf_id;
+ STREAM_GETL(s, zpi->unique);
+ STREAM_GETL(s, zpi->type);
+ STREAM_GETL(s, zpi->filter_bm);
+ STREAM_GETL(s, zpi->action);
+ STREAM_GETL(s, zpi->fwmark);
+ STREAM_GET(&zpi->ipset_name, s, ZEBRA_IPSET_NAME_SIZE);
+ STREAM_GETW(s, zpi->pkt_len_min);
+ STREAM_GETW(s, zpi->pkt_len_max);
+ STREAM_GETW(s, zpi->tcp_flags);
+ STREAM_GETW(s, zpi->tcp_mask_flags);
+ STREAM_GETC(s, zpi->dscp_value);
+ STREAM_GETC(s, zpi->fragment);
+ STREAM_GETC(s, zpi->protocol);
+ STREAM_GETL(s, zpi->nb_interface);
+ zebra_pbr_iptable_update_interfacelist(s, zpi);
if (hdr->command == ZEBRA_IPTABLE_ADD)
- zebra_pbr_add_iptable(&zpi);
+ zebra_pbr_add_iptable(zpi);
else
- zebra_pbr_del_iptable(&zpi);
+ zebra_pbr_del_iptable(zpi);
+
stream_failure:
+ zebra_pbr_iptable_free(zpi);
+ zpi = NULL;
return;
}
@@ -2597,6 +2622,14 @@ void zserv_handle_commands(struct zserv *client, struct stream *msg)
struct zmsghdr hdr;
struct zebra_vrf *zvrf;
+ if (STREAM_READABLE(msg) > ZEBRA_MAX_PACKET_SIZ) {
+ if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV)
+ zlog_debug(
+ "ZAPI message is %zu bytes long but the maximum packet size is %u; dropping",
+ STREAM_READABLE(msg), ZEBRA_MAX_PACKET_SIZ);
+ return;
+ }
+
zapi_parse_header(msg, &hdr);
if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV)
diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c
index e24d2e2b42..0c3adcdfa1 100644
--- a/zebra/zebra_pbr.c
+++ b/zebra/zebra_pbr.c
@@ -345,11 +345,13 @@ void zebra_pbr_iptable_free(void *arg)
iptable = (struct zebra_pbr_iptable *)arg;
hook_call(zebra_pbr_iptable_update, 0, iptable);
- for (ALL_LIST_ELEMENTS(iptable->interface_name_list,
- node, nnode, name)) {
- XFREE(MTYPE_PBR_IPTABLE_IFNAME, name);
- list_delete_node(iptable->interface_name_list,
- node);
+ if (iptable->interface_name_list) {
+ for (ALL_LIST_ELEMENTS(iptable->interface_name_list, node,
+ nnode, name)) {
+ XFREE(MTYPE_PBR_IPTABLE_IFNAME, name);
+ list_delete_node(iptable->interface_name_list, node);
+ }
+ list_delete(&iptable->interface_name_list);
}
XFREE(MTYPE_TMP, iptable);
}
@@ -688,6 +690,7 @@ void zebra_pbr_del_iptable(struct zebra_pbr_iptable *iptable)
list_delete_node(iptable->interface_name_list,
node);
}
+ list_delete(&iptable->interface_name_list);
XFREE(MTYPE_TMP, lookup);
} else
zlog_debug("%s: IPTable being deleted we know nothing about",
diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c
index 46f1385520..b48756302a 100644
--- a/zebra/zebra_ptm.c
+++ b/zebra/zebra_ptm.c
@@ -1295,7 +1295,6 @@ static void zebra_ptm_send_bfdd(struct stream *msg)
}
stream_free(msgc);
- stream_free(msg);
}
static void zebra_ptm_send_clients(struct stream *msg)
@@ -1327,7 +1326,6 @@ static void zebra_ptm_send_clients(struct stream *msg)
}
stream_free(msgc);
- stream_free(msg);
}
static int _zebra_ptm_bfd_client_deregister(struct zserv *zs)
@@ -1402,37 +1400,25 @@ static void _zebra_ptm_reroute(struct zserv *zs, struct zebra_vrf *zvrf,
struct stream *msg, uint32_t command)
{
struct stream *msgc;
- size_t zmsglen, zhdrlen;
+ char buf[ZEBRA_MAX_PACKET_SIZ];
pid_t ppid;
- /*
- * Don't modify message in the zebra API. In order to do that we
- * need to allocate a new message stream and copy the message
- * provided by zebra.
- */
+ /* Create BFD header */
msgc = stream_new(ZEBRA_MAX_PACKET_SIZ);
- if (msgc == NULL) {
- zlog_debug("%s: not enough memory", __func__);
- return;
- }
-
- /* Calculate our header size plus the message contents. */
- zhdrlen = ZEBRA_HEADER_SIZE + sizeof(uint32_t);
- zmsglen = msg->endp - msg->getp;
- memcpy(msgc->data + zhdrlen, msg->data + msg->getp, zmsglen);
-
- /*
- * The message type will be BFD_DEST_REPLY so we can use only
- * one callback at the `bfdd` side, however the real command
- * number will be included right after the zebra header.
- */
zclient_create_header(msgc, ZEBRA_BFD_DEST_REPLAY, zvrf->vrf->vrf_id);
stream_putl(msgc, command);
- /* Update the data pointers. */
- msgc->getp = 0;
- msgc->endp = zhdrlen + zmsglen;
- stream_putw_at(msgc, 0, stream_get_endp(msgc));
+ if (STREAM_READABLE(msg) > STREAM_WRITEABLE(msgc)) {
+ zlog_warn("Cannot fit extended BFD header plus original message contents into ZAPI packet; dropping message");
+ goto stream_failure;
+ }
+
+ /* Copy original message, excluding header, into new message */
+ stream_get_from(buf, msg, stream_get_getp(msg), STREAM_READABLE(msg));
+ stream_put(msgc, buf, STREAM_READABLE(msg));
+
+ /* Update length field */
+ stream_putw_at(msgc, 0, STREAM_READABLE(msgc));
zebra_ptm_send_bfdd(msgc);
@@ -1443,6 +1429,7 @@ static void _zebra_ptm_reroute(struct zserv *zs, struct zebra_vrf *zvrf,
return;
stream_failure:
+ stream_free(msgc);
zlog_err("%s:%d failed to registrate client pid", __FILE__, __LINE__);
}
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 309b0f4301..051d7f5231 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -1898,11 +1898,6 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
/* Redistribute, lsp, and nht update */
redistribute_update(dest_pfx, src_pfx, re, NULL);
- zebra_rib_evaluate_rn_nexthops(
- rn, zebra_router_get_next_sequence());
-
- zebra_rib_evaluate_mpls(rn);
-
} else if (start_count > 0 && end_count == 0) {
if (debug_p)
zlog_debug("%u:%s un-installed transition from dplane notification",
@@ -1921,12 +1916,13 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
/* Redistribute, lsp, and nht update */
redistribute_delete(dest_pfx, src_pfx, re, NULL);
+ }
- zebra_rib_evaluate_rn_nexthops(
- rn, zebra_router_get_next_sequence());
+ /* Make any changes visible for lsp and nexthop-tracking processing */
+ zebra_rib_evaluate_rn_nexthops(
+ rn, zebra_router_get_next_sequence());
- zebra_rib_evaluate_mpls(rn);
- }
+ zebra_rib_evaluate_mpls(rn);
done:
if (rn)
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index b85bf83923..c8b96011dc 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -1351,9 +1351,10 @@ DEFPY (show_interface_nexthop_group,
DEFPY (show_nexthop_group,
show_nexthop_group_cmd,
- "show nexthop-group <(0-4294967295)$id|[<ip$v4|ipv6$v6>] [vrf <NAME$vrf_name|all$vrf_all>]>",
+ "show nexthop-group rib <(0-4294967295)$id|[<ip$v4|ipv6$v6>] [vrf <NAME$vrf_name|all$vrf_all>]>",
SHOW_STR
"Show Nexthop Groups\n"
+ "RIB information\n"
"Nexthop Group ID\n"
IP_STR
IP6_STR
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index 086b13d670..564573dcb3 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -7682,6 +7682,55 @@ int zebra_vxlan_handle_kernel_neigh_update(struct interface *ifp,
return zvni_remote_neigh_update(zvni, ifp, ip, macaddr, state);
}
+static int32_t
+zebra_vxlan_remote_macip_helper(bool add, struct stream *s, vni_t *vni,
+ struct ethaddr *macaddr, uint16_t *ipa_len,
+ struct ipaddr *ip, struct in_addr *vtep_ip,
+ uint8_t *flags, uint32_t *seq)
+{
+ uint16_t l = 0;
+
+ /*
+ * Obtain each remote MACIP and process.
+ * Message contains VNI, followed by MAC followed by IP (if any)
+ * followed by remote VTEP IP.
+ */
+ memset(ip, 0, sizeof(*ip));
+ STREAM_GETL(s, *vni);
+ STREAM_GET(macaddr->octet, s, ETH_ALEN);
+ STREAM_GETL(s, *ipa_len);
+
+ if (*ipa_len) {
+ if (*ipa_len == IPV4_MAX_BYTELEN)
+ ip->ipa_type = IPADDR_V4;
+ else if (*ipa_len == IPV6_MAX_BYTELEN)
+ ip->ipa_type = IPADDR_V6;
+ else {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "ipa_len *must* be %d or %d bytes in length not %d",
+ IPV4_MAX_BYTELEN, IPV6_MAX_BYTELEN,
+ *ipa_len);
+ goto stream_failure;
+ }
+
+ STREAM_GET(&ip->ip.addr, s, *ipa_len);
+ }
+ l += 4 + ETH_ALEN + 4 + *ipa_len;
+ STREAM_GET(&vtep_ip->s_addr, s, IPV4_MAX_BYTELEN);
+ l += IPV4_MAX_BYTELEN;
+
+ if (add) {
+ STREAM_GETC(s, *flags);
+ STREAM_GETL(s, *seq);
+ l += 5;
+ }
+
+ return l;
+
+stream_failure:
+ return -1;
+}
/*
* Handle message from client to delete a remote MACIP for a VNI.
@@ -7704,23 +7753,14 @@ void zebra_vxlan_remote_macip_del(ZAPI_HANDLER_ARGS)
s = msg;
while (l < hdr->length) {
- /* Obtain each remote MACIP and process. */
- /* Message contains VNI, followed by MAC followed by IP (if any)
- * followed by remote VTEP IP.
- */
- memset(&ip, 0, sizeof(ip));
- STREAM_GETL(s, vni);
- STREAM_GET(&macaddr.octet, s, ETH_ALEN);
- STREAM_GETL(s, ipa_len);
- if (ipa_len) {
- ip.ipa_type = (ipa_len == IPV4_MAX_BYTELEN) ? IPADDR_V4
- : IPADDR_V6;
- STREAM_GET(&ip.ip.addr, s, ipa_len);
- }
- l += 4 + ETH_ALEN + 4 + ipa_len;
- STREAM_GET(&vtep_ip.s_addr, s, IPV4_MAX_BYTELEN);
- l += IPV4_MAX_BYTELEN;
+ int res_length = zebra_vxlan_remote_macip_helper(
+ false, s, &vni, &macaddr, &ipa_len, &ip, &vtep_ip, NULL,
+ NULL);
+ if (res_length == -1)
+ goto stream_failure;
+
+ l += res_length;
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
"Recv MACIP DEL VNI %u MAC %s%s%s Remote VTEP %s from %s",
@@ -7769,29 +7809,14 @@ void zebra_vxlan_remote_macip_add(ZAPI_HANDLER_ARGS)
s = msg;
while (l < hdr->length) {
- /* Obtain each remote MACIP and process. */
- /* Message contains VNI, followed by MAC followed by IP (if any)
- * followed by remote VTEP IP.
- */
- memset(&ip, 0, sizeof(ip));
- STREAM_GETL(s, vni);
- STREAM_GET(&macaddr.octet, s, ETH_ALEN);
- STREAM_GETL(s, ipa_len);
- if (ipa_len) {
- ip.ipa_type = (ipa_len == IPV4_MAX_BYTELEN) ? IPADDR_V4
- : IPADDR_V6;
- STREAM_GET(&ip.ip.addr, s, ipa_len);
- }
- l += 4 + ETH_ALEN + 4 + ipa_len;
- STREAM_GET(&vtep_ip.s_addr, s, IPV4_MAX_BYTELEN);
- l += IPV4_MAX_BYTELEN;
+ int res_length = zebra_vxlan_remote_macip_helper(
+ true, s, &vni, &macaddr, &ipa_len, &ip, &vtep_ip,
+ &flags, &seq);
- /* Get flags - sticky mac and/or gateway mac */
- STREAM_GETC(s, flags);
- l++;
- STREAM_GETL(s, seq);
- l += 4;
+ if (res_length == -1)
+ goto stream_failure;
+ l += res_length;
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
"Recv MACIP ADD VNI %u MAC %s%s%s flags 0x%x seq %u VTEP %s from %s",
diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h
index 989ea464e7..100bb0e093 100644
--- a/zebra/zebra_vxlan_private.h
+++ b/zebra/zebra_vxlan_private.h
@@ -162,8 +162,7 @@ static inline const char *zl3vni_rmac2str(zebra_l3vni_t *zl3vni, char *buf,
char *ptr;
if (!buf)
- ptr = (char *)XMALLOC(MTYPE_TMP,
- ETHER_ADDR_STRLEN * sizeof(char));
+ ptr = XMALLOC(MTYPE_TMP, ETHER_ADDR_STRLEN * sizeof(char));
else {
assert(size >= ETHER_ADDR_STRLEN);
ptr = buf;
@@ -200,8 +199,7 @@ static inline const char *zl3vni_sysmac2str(zebra_l3vni_t *zl3vni, char *buf,
char *ptr;
if (!buf)
- ptr = (char *)XMALLOC(MTYPE_TMP,
- ETHER_ADDR_STRLEN * sizeof(char));
+ ptr = XMALLOC(MTYPE_TMP, ETHER_ADDR_STRLEN * sizeof(char));
else {
assert(size >= ETHER_ADDR_STRLEN);
ptr = buf;