summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--alpine/APKBUILD.in3
-rw-r--r--bgpd/bgp_aspath.c31
-rw-r--r--bgpd/bgp_aspath.h5
-rw-r--r--bgpd/bgp_attr.c22
-rw-r--r--bgpd/bgp_clist.c3
-rw-r--r--bgpd/bgp_community.c8
-rw-r--r--bgpd/bgp_dump.c2
-rw-r--r--bgpd/bgp_ecommunity.c22
-rw-r--r--bgpd/bgp_evpn.c2
-rw-r--r--bgpd/bgp_evpn_vty.c168
-rw-r--r--bgpd/bgp_filter.c2
-rw-r--r--bgpd/bgp_fsm.c36
-rw-r--r--bgpd/bgp_lcommunity.c12
-rw-r--r--bgpd/bgp_nexthop.c13
-rw-r--r--bgpd/bgp_packet.h3
-rw-r--r--bgpd/bgp_route.c131
-rw-r--r--bgpd/bgp_routemap.c439
-rw-r--r--bgpd/bgp_rpki.c36
-rw-r--r--bgpd/bgp_table.c14
-rw-r--r--bgpd/bgp_updgrp_adv.c2
-rw-r--r--bgpd/bgp_vpn.c4
-rw-r--r--bgpd/bgp_vty.c164
-rw-r--r--bgpd/bgpd.c58
-rw-r--r--bgpd/bgpd.h4
-rwxr-xr-xconfigure.ac14
-rw-r--r--debian/.gitignore13
-rw-r--r--doc/developer/building-frr-for-centos6.rst2
-rw-r--r--doc/developer/building-frr-for-centos7.rst2
-rw-r--r--doc/developer/building-frr-for-debian8.rst2
-rw-r--r--doc/developer/building-frr-for-debian9.rst2
-rw-r--r--doc/developer/building-frr-for-fedora.rst2
-rw-r--r--doc/developer/building-frr-for-ubuntu1404.rst2
-rw-r--r--doc/developer/building-frr-for-ubuntu1604.rst2
-rw-r--r--doc/developer/building-frr-for-ubuntu1804.rst2
-rw-r--r--doc/developer/cli.rst42
-rw-r--r--doc/developer/library.rst1
-rw-r--r--doc/developer/lists.rst32
-rw-r--r--doc/developer/rcu.rst269
-rw-r--r--doc/developer/subdir.am1
-rw-r--r--doc/figures/nodes.dot1
-rw-r--r--doc/user/bgp.rst30
-rw-r--r--doc/user/installation.rst14
-rw-r--r--doc/user/isisd.rst6
-rw-r--r--doc/user/ospf6d.rst2
-rw-r--r--doc/user/ospfd.rst19
-rw-r--r--doc/user/overview.rst9
-rw-r--r--doc/user/routemap.rst4
-rw-r--r--doc/user/sharp.rst2
-rw-r--r--doc/user/zebra.rst25
-rw-r--r--eigrpd/eigrp_cli.c920
-rw-r--r--eigrpd/eigrp_main.c9
-rw-r--r--eigrpd/eigrp_northbound.c1584
-rw-r--r--eigrpd/eigrp_routemap.c54
-rw-r--r--eigrpd/eigrp_vty.c1071
-rw-r--r--eigrpd/eigrp_vty.h1
-rw-r--r--eigrpd/eigrpd.h47
-rw-r--r--eigrpd/subdir.am10
-rw-r--r--isisd/isis_cli.c2
-rw-r--r--isisd/isis_misc.c6
-rw-r--r--isisd/isis_routemap.c25
-rw-r--r--isisd/isis_tlvs.c2
-rw-r--r--ldpd/lde.c39
-rw-r--r--ldpd/lde.h1
-rw-r--r--ldpd/lde_lib.c3
-rw-r--r--lib/atomlist.h10
-rw-r--r--lib/command.c12
-rw-r--r--lib/command.h1
-rw-r--r--lib/command_graph.c2
-rw-r--r--lib/command_match.c6
-rw-r--r--lib/compiler.h7
-rw-r--r--lib/ferr.c12
-rw-r--r--lib/ferr.h1
-rw-r--r--lib/filter.c1375
-rw-r--r--lib/frr_pthread.c15
-rw-r--r--lib/frr_pthread.h3
-rw-r--r--lib/frrcu.c527
-rw-r--r--lib/frrcu.h172
-rw-r--r--lib/frrstr.c2
-rw-r--r--lib/if.c75
-rw-r--r--lib/if.h3
-rw-r--r--lib/libfrr.c5
-rw-r--r--lib/log.c21
-rw-r--r--lib/logicalrouter.c158
-rw-r--r--lib/logicalrouter.h49
-rw-r--r--lib/netns_other.c2
-rw-r--r--lib/ns.h12
-rw-r--r--lib/plist.c2
-rw-r--r--lib/pqueue.c185
-rw-r--r--lib/pqueue.h54
-rw-r--r--lib/prefix.c50
-rw-r--r--lib/prefix.h14
-rw-r--r--lib/ptm_lib.c2
-rw-r--r--lib/routemap.c203
-rw-r--r--lib/routemap.h38
-rw-r--r--lib/seqlock.c190
-rw-r--r--lib/seqlock.h40
-rw-r--r--lib/sigevent.c42
-rw-r--r--lib/stream.c14
-rw-r--r--lib/stream.h3
-rw-r--r--lib/subdir.am7
-rw-r--r--lib/thread.c106
-rw-r--r--lib/thread.h7
-rw-r--r--lib/typerb.c5
-rw-r--r--lib/typerb.h23
-rw-r--r--lib/typesafe.c13
-rw-r--r--lib/typesafe.h51
-rw-r--r--lib/vty.c9
-rw-r--r--lib/zebra.h5
-rw-r--r--m4/ax_python.m46
-rw-r--r--ospf6d/ospf6_asbr.c26
-rw-r--r--ospf6d/ospf6_zebra.c2
-rw-r--r--ospfd/ospf_errors.c2
-rw-r--r--ospfd/ospf_flood.c25
-rw-r--r--ospfd/ospf_lsa.c160
-rw-r--r--ospfd/ospf_lsa.h4
-rw-r--r--ospfd/ospf_nsm.c28
-rw-r--r--ospfd/ospf_packet.c30
-rw-r--r--ospfd/ospf_routemap.c54
-rw-r--r--ospfd/ospf_vty.c17
-rw-r--r--ospfd/ospf_zebra.c137
-rw-r--r--ospfd/ospfd.c32
-rw-r--r--ospfd/ospfd.h2
-rw-r--r--pbrd/pbr_nht.c1
-rw-r--r--pbrd/pbrd.conf.sample16
-rw-r--r--pimd/pim_bsm.c4
-rw-r--r--pimd/pim_mroute.c31
-rw-r--r--pimd/pim_msg.h19
-rw-r--r--pimd/pim_neighbor.c5
-rw-r--r--pimd/pim_nht.c12
-rw-r--r--pimd/pim_oil.c40
-rw-r--r--pimd/pim_oil.h3
-rw-r--r--pimd/pim_rpf.c8
-rw-r--r--pimd/pim_static.c4
-rw-r--r--pimd/pim_upstream.c64
-rw-r--r--pimd/pim_upstream.h9
-rw-r--r--pimd/pim_zebra.c46
-rw-r--r--redhat/frr.spec.in2
-rw-r--r--ripd/rip_routemap.c61
-rw-r--r--ripd/ripd.c30
-rw-r--r--ripngd/ripng_routemap.c41
-rw-r--r--sharpd/sharp_vty.c41
-rw-r--r--sharpd/sharp_zebra.c2
-rw-r--r--sharpd/sharpd.conf.sample3
-rw-r--r--staticd/static_nht.c165
-rw-r--r--staticd/static_nht.h29
-rw-r--r--staticd/static_routes.c30
-rw-r--r--staticd/static_routes.h26
-rw-r--r--staticd/static_zebra.c22
-rw-r--r--staticd/static_zebra.h3
-rw-r--r--staticd/staticd.conf.sample4
-rw-r--r--tests/bgpd/test_bgp_table.c2
-rw-r--r--tests/bgpd/test_bgp_table.py2
-rw-r--r--tests/lib/cli/test_commands.c3
-rw-r--r--tests/lib/cxxcompat.c2
-rw-r--r--tests/lib/test_atomlist.c10
-rw-r--r--tests/lib/test_seqlock.c34
-rw-r--r--tests/lib/test_timer_correctness.c1
-rw-r--r--tests/lib/test_timer_performance.c1
-rw-r--r--tests/lib/test_typelist.h16
-rw-r--r--tests/topotests/all-protocol-startup/r1/ipv4_routes.ref6
-rw-r--r--tests/topotests/all-protocol-startup/r1/ipv6_routes.ref6
-rw-r--r--tests/topotests/all-protocol-startup/r1/zebra.conf17
-rw-r--r--tests/topotests/bfd-topo2/r1/ipv4_routes.json6
-rw-r--r--tests/topotests/bfd-topo2/r1/ipv6_routes.json6
-rw-r--r--tests/topotests/bfd-topo2/r2/ipv4_routes.json10
-rw-r--r--tests/topotests/bfd-topo2/r2/ipv6_routes.json6
-rw-r--r--tests/topotests/bfd-topo2/r3/ipv4_routes.json8
-rw-r--r--tests/topotests/bfd-topo2/r4/ipv4_routes.json2
-rw-r--r--tests/topotests/bfd-topo2/r4/ipv6_routes.json6
-rwxr-xr-xtests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py7
-rwxr-xr-xtests/topotests/bgp-prefix-list-topo1/test_prefix_lists.py16
-rw-r--r--tests/topotests/bgp_comm-list_delete/__init__.py0
-rw-r--r--tests/topotests/bgp_comm-list_delete/r1/bgpd.conf9
-rw-r--r--tests/topotests/bgp_comm-list_delete/r1/zebra.conf9
-rw-r--r--tests/topotests/bgp_comm-list_delete/r2/bgpd.conf11
-rw-r--r--tests/topotests/bgp_comm-list_delete/r2/zebra.conf6
-rw-r--r--tests/topotests/bgp_comm-list_delete/test_bgp_comm-list_delete.py105
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_down.py6
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_up.py16
-rw-r--r--tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv4_routes.json4
-rw-r--r--tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv6_routes.json4
-rw-r--r--tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/ipv4_routes.json4
-rw-r--r--tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/ipv6_routes.json2
-rw-r--r--tests/topotests/lib/bgp.py12
-rw-r--r--tests/topotests/lib/common_config.py25
-rwxr-xr-xtests/topotests/lib/lutil.py34
-rwxr-xr-xtests/topotests/lib/test/test_run_and_expect.py74
-rw-r--r--tests/topotests/lib/topotest.py48
-rw-r--r--tools/coccinelle/ctype_cast.cocci11
-rwxr-xr-xtools/frr-reload.py2
-rw-r--r--tools/gen_northbound_callbacks.c73
-rw-r--r--tools/start-stop-daemon.c2
-rw-r--r--vrrpd/vrrp.c29
-rw-r--r--vrrpd/vrrp_zebra.c12
-rwxr-xr-xvtysh/extract.pl.in6
-rw-r--r--vtysh/vtysh.c92
-rw-r--r--vtysh/vtysh.h1
-rw-r--r--vtysh/vtysh_config.c41
-rw-r--r--vtysh/vtysh_main.c5
-rw-r--r--yang/frr-bfdd.yang12
-rw-r--r--yang/frr-eigrpd.yang2
-rw-r--r--yang/frr-filter.yang353
-rw-r--r--yang/frr-isisd.yang22
-rw-r--r--yang/frr-route-map.yang404
-rw-r--r--yang/subdir.am4
-rw-r--r--zebra/connected.c31
-rw-r--r--zebra/if_netlink.c23
-rw-r--r--zebra/interface.c46
-rw-r--r--zebra/label_manager.c12
-rw-r--r--zebra/main.c4
-rw-r--r--zebra/redistribute.c18
-rw-r--r--zebra/rib.h13
-rw-r--r--zebra/rt_netlink.c13
-rw-r--r--zebra/zapi_msg.c15
-rw-r--r--zebra/zebra_dplane.c2
-rw-r--r--zebra/zebra_errors.c2
-rw-r--r--zebra/zebra_fpm_netlink.c2
-rw-r--r--zebra/zebra_l2.c11
-rw-r--r--zebra/zebra_l2.h2
-rw-r--r--zebra/zebra_nhg.c10
-rw-r--r--zebra/zebra_ns.c19
-rw-r--r--zebra/zebra_rib.c54
-rw-r--r--zebra/zebra_rnh.c17
-rw-r--r--zebra/zebra_routemap.c95
-rw-r--r--zebra/zebra_vty.c65
-rw-r--r--zebra/zebra_vxlan.c111
226 files changed, 8592 insertions, 3817 deletions
diff --git a/alpine/APKBUILD.in b/alpine/APKBUILD.in
index 0f56a427dd..e0b00f9782 100644
--- a/alpine/APKBUILD.in
+++ b/alpine/APKBUILD.in
@@ -19,7 +19,7 @@ makedepends="ncurses-dev net-snmp-dev gawk texinfo perl
mpfr3 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-sphinx"
+ py-sphinx rtrlib rtrlib-dev"
checkdepends="pytest py-setuptools"
install="$pkgname.pre-install $pkgname.pre-deinstall $pkgname.post-deinstall"
subpackages="$pkgname-dev $pkgname-doc $pkgname-dbg"
@@ -42,6 +42,7 @@ build() {
--libdir=$_libdir \
--localstatedir=$_localstatedir \
--enable-systemd=no \
+ --enable-rpki \
--enable-vtysh \
--enable-multipath=64 \
--enable-vty-group=frrvty \
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c
index 05577cb8bd..f5652b07c5 100644
--- a/bgpd/bgp_aspath.c
+++ b/bgpd/bgp_aspath.c
@@ -1232,7 +1232,8 @@ struct aspath *aspath_replace_specific_asn(struct aspath *aspath,
}
/* Replace all private ASNs with our own ASN */
-struct aspath *aspath_replace_private_asns(struct aspath *aspath, as_t asn)
+struct aspath *aspath_replace_private_asns(struct aspath *aspath, as_t asn,
+ as_t peer_asn)
{
struct aspath *new;
struct assegment *seg;
@@ -1244,7 +1245,9 @@ struct aspath *aspath_replace_private_asns(struct aspath *aspath, as_t asn)
int i;
for (i = 0; i < seg->length; i++) {
- if (BGP_AS_IS_PRIVATE(seg->as[i]))
+ /* Don't replace if public ASN or peer's ASN */
+ if (BGP_AS_IS_PRIVATE(seg->as[i])
+ && (seg->as[i] != peer_asn))
seg->as[i] = asn;
}
seg = seg->next;
@@ -1255,7 +1258,7 @@ struct aspath *aspath_replace_private_asns(struct aspath *aspath, as_t asn)
}
/* Remove all private ASNs */
-struct aspath *aspath_remove_private_asns(struct aspath *aspath)
+struct aspath *aspath_remove_private_asns(struct aspath *aspath, as_t peer_asn)
{
struct aspath *new;
struct assegment *seg;
@@ -1282,16 +1285,9 @@ struct aspath *aspath_remove_private_asns(struct aspath *aspath)
}
}
- // The entire segment is private so skip it
- if (!public) {
- seg = seg->next;
- continue;
- }
-
// The entire segment is public so copy it
- else if (public == seg->length) {
+ if (public == seg->length)
new_seg = assegment_dup(seg);
- }
// The segment is a mix of public and private ASNs. Copy as many
// spots as
@@ -1301,8 +1297,9 @@ struct aspath *aspath_remove_private_asns(struct aspath *aspath)
new_seg = assegment_new(seg->type, public);
j = 0;
for (i = 0; i < seg->length; i++) {
- // ASN is public
- if (!BGP_AS_IS_PRIVATE(seg->as[i])) {
+ // keep ASN if public or matches peer's ASN
+ if (!BGP_AS_IS_PRIVATE(seg->as[i])
+ || (seg->as[i] == peer_asn)) {
new_seg->as[j] = seg->as[i];
j++;
}
@@ -1469,7 +1466,7 @@ struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2)
/* Not reached */
}
-/* Iterate over AS_PATH segments and wipe all occurences of the
+/* Iterate over AS_PATH segments and wipe all occurrences of the
* listed AS numbers. Hence some segments may lose some or even
* all data on the way, the operation is implemented as a smarter
* version of aspath_dup(), which allocates memory to hold the new
@@ -1888,7 +1885,7 @@ static const char *aspath_gettoken(const char *buf, enum as_token *token,
const char *p = buf;
/* Skip seperators (space for sequences, ',' for sets). */
- while (isspace((int)*p) || *p == ',')
+ while (isspace((unsigned char)*p) || *p == ',')
p++;
/* Check the end of the string and type specify characters
@@ -1923,14 +1920,14 @@ static const char *aspath_gettoken(const char *buf, enum as_token *token,
}
/* Check actual AS value. */
- if (isdigit((int)*p)) {
+ if (isdigit((unsigned char)*p)) {
as_t asval;
*token = as_token_asval;
asval = (*p - '0');
p++;
- while (isdigit((int)*p)) {
+ while (isdigit((unsigned char)*p)) {
asval *= 10;
asval += (*p - '0');
p++;
diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h
index 6f3d94cdb3..f84b3740c9 100644
--- a/bgpd/bgp_aspath.h
+++ b/bgpd/bgp_aspath.h
@@ -112,8 +112,9 @@ extern struct aspath *aspath_replace_specific_asn(struct aspath *aspath,
as_t target_asn,
as_t our_asn);
extern struct aspath *aspath_replace_private_asns(struct aspath *aspath,
- as_t asn);
-extern struct aspath *aspath_remove_private_asns(struct aspath *aspath);
+ as_t asn, as_t peer_asn);
+extern struct aspath *aspath_remove_private_asns(struct aspath *aspath,
+ as_t peer_asn);
extern int aspath_firstas_check(struct aspath *, as_t);
extern int aspath_confed_check(struct aspath *);
extern int aspath_left_confed_check(struct aspath *);
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 35946444dd..e21c84355e 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -2956,7 +2956,8 @@ void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
addpath_encode, addpath_tx_id);
} else if (safi == SAFI_LABELED_UNICAST) {
/* Prefix write with label. */
- stream_put_labeled_prefix(s, p, label);
+ stream_put_labeled_prefix(s, p, label, addpath_encode,
+ addpath_tx_id);
} else if (safi == SAFI_FLOWSPEC) {
if (PSIZE (p->prefixlen)+2 < FLOWSPEC_NLRI_SIZELIMIT)
stream_putc(s, PSIZE (p->prefixlen)+2);
@@ -3215,6 +3216,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
/* Nexthop attribute. */
if (afi == AFI_IP && safi == SAFI_UNICAST
&& !peer_cap_enhe(peer, afi, safi)) {
+ afi_t nh_afi = BGP_NEXTHOP_AFI_FROM_NHLEN(attr->mp_nexthop_len);
+
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) {
stream_putc(s, BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_NEXT_HOP);
@@ -3222,17 +3225,18 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
attr);
stream_putc(s, 4);
stream_put_ipv4(s, attr->nexthop.s_addr);
- } else if (peer_cap_enhe(from, afi, safi)) {
+ } else if (peer_cap_enhe(from, afi, safi)
+ || (nh_afi == AFI_IP6)) {
/*
* Likely this is the case when an IPv4 prefix was
- * received with
- * Extended Next-hop capability and now being advertised
- * to
- * non-ENHE peers.
+ * received with Extended Next-hop capability in this
+ * or another vrf and is now being advertised to
+ * non-ENHE peers. Since peer_cap_enhe only checks
+ * peers in this vrf, also check the nh_afi to catch
+ * the case where the originator was in another vrf.
* Setting the mandatory (ipv4) next-hop attribute here
- * to enable
- * implicit next-hop self with correct (ipv4 address
- * family).
+ * to enable implicit next-hop self with correct A-F
+ * (ipv4 address family).
*/
stream_putc(s, BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_NEXT_HOP);
diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c
index ff2ea6f7cd..29e668d179 100644
--- a/bgpd/bgp_clist.c
+++ b/bgpd/bgp_clist.c
@@ -157,7 +157,7 @@ community_list_insert(struct community_list_handler *ch, const char *name,
/* If name is made by all digit character. We treat it as
number. */
for (number = 0, i = 0; i < strlen(name); i++) {
- if (isdigit((int)name[i]))
+ if (isdigit((unsigned char)name[i]))
number = (number * 10) + (name[i] - '0');
else
break;
@@ -823,6 +823,7 @@ struct community *community_list_match_delete(struct community *com,
/* Delete all of the communities we flagged for deletion */
for (i = delete_index - 1; i >= 0; i--) {
val = community_val_get(com, com_index_to_delete[i]);
+ val = htonl(val);
community_del_val(com, &val);
}
diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c
index 6fc52ff9e0..22d61f702d 100644
--- a/bgpd/bgp_community.c
+++ b/bgpd/bgp_community.c
@@ -651,7 +651,7 @@ community_gettoken(const char *buf, enum community_token *token, uint32_t *val)
const char *p = buf;
/* Skip white space. */
- while (isspace((int)*p))
+ while (isspace((unsigned char)*p))
p++;
/* Check the end of the line. */
@@ -659,7 +659,7 @@ community_gettoken(const char *buf, enum community_token *token, uint32_t *val)
return NULL;
/* Well known community string check. */
- if (isalpha((int)*p)) {
+ if (isalpha((unsigned char)*p)) {
if (strncmp(p, "internet", strlen("internet")) == 0) {
*val = COMMUNITY_INTERNET;
*token = community_token_no_export;
@@ -770,13 +770,13 @@ community_gettoken(const char *buf, enum community_token *token, uint32_t *val)
}
/* Community value. */
- if (isdigit((int)*p)) {
+ if (isdigit((unsigned char)*p)) {
int separator = 0;
int digit = 0;
uint32_t community_low = 0;
uint32_t community_high = 0;
- while (isdigit((int)*p) || *p == ':') {
+ while (isdigit((unsigned char)*p) || *p == ':') {
if (*p == ':') {
if (separator) {
*token = community_token_unknown;
diff --git a/bgpd/bgp_dump.c b/bgpd/bgp_dump.c
index 7ea6ae586b..535f36ab5e 100644
--- a/bgpd/bgp_dump.c
+++ b/bgpd/bgp_dump.c
@@ -584,7 +584,7 @@ static unsigned int bgp_dump_parse_time(const char *str)
len = strlen(str);
for (i = 0; i < len; i++) {
- if (isdigit((int)str[i])) {
+ if (isdigit((unsigned char)str[i])) {
time *= 10;
time += str[i] - '0';
} else if (str[i] == 'H' || str[i] == 'h') {
diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c
index 76bd0e815e..850b85aa6a 100644
--- a/bgpd/bgp_ecommunity.c
+++ b/bgpd/bgp_ecommunity.c
@@ -352,7 +352,7 @@ static const char *ecommunity_gettoken(const char *str,
char buf[INET_ADDRSTRLEN + 1];
/* Skip white space. */
- while (isspace((int)*p)) {
+ while (isspace((unsigned char)*p)) {
p++;
str++;
}
@@ -362,38 +362,38 @@ static const char *ecommunity_gettoken(const char *str,
return NULL;
/* "rt" and "soo" keyword parse. */
- if (!isdigit((int)*p)) {
+ if (!isdigit((unsigned char)*p)) {
/* "rt" match check. */
- if (tolower((int)*p) == 'r') {
+ if (tolower((unsigned char)*p) == 'r') {
p++;
- if (tolower((int)*p) == 't') {
+ if (tolower((unsigned char)*p) == 't') {
p++;
*token = ecommunity_token_rt;
return p;
}
- if (isspace((int)*p) || *p == '\0') {
+ if (isspace((unsigned char)*p) || *p == '\0') {
*token = ecommunity_token_rt;
return p;
}
goto error;
}
/* "soo" match check. */
- else if (tolower((int)*p) == 's') {
+ else if (tolower((unsigned char)*p) == 's') {
p++;
- if (tolower((int)*p) == 'o') {
+ if (tolower((unsigned char)*p) == 'o') {
p++;
- if (tolower((int)*p) == 'o') {
+ if (tolower((unsigned char)*p) == 'o') {
p++;
*token = ecommunity_token_soo;
return p;
}
- if (isspace((int)*p) || *p == '\0') {
+ if (isspace((unsigned char)*p) || *p == '\0') {
*token = ecommunity_token_soo;
return p;
}
goto error;
}
- if (isspace((int)*p) || *p == '\0') {
+ if (isspace((unsigned char)*p) || *p == '\0') {
*token = ecommunity_token_soo;
return p;
}
@@ -415,7 +415,7 @@ static const char *ecommunity_gettoken(const char *str,
* OPQR: Four byte value
*
*/
- while (isdigit((int)*p) || *p == ':' || *p == '.') {
+ while (isdigit((unsigned char)*p) || *p == ':' || *p == '.') {
if (*p == ':') {
if (separator)
goto error;
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index 94022ec1be..3bc3d74de6 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -4411,7 +4411,7 @@ void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi,
/* apply the route-map */
if (bgp_vrf->adv_cmd_rmap[afi][safi].map) {
- int ret = 0;
+ route_map_result_t ret;
ret = route_map_apply(
bgp_vrf->adv_cmd_rmap[afi][safi]
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index a22082c072..d031d34f1f 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -1069,11 +1069,9 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd,
pi = pi->next) {
total_count++;
if (type == bgp_show_type_neighbor) {
- union sockunion *su = output_arg;
+ struct peer *peer = output_arg;
- if (pi->peer->su_remote == NULL
- || !sockunion_same(
- pi->peer->su_remote, su))
+ if (peer_cmp(peer, pi->peer) != 0)
continue;
}
if (header) {
@@ -1292,29 +1290,41 @@ DEFUN(show_ip_bgp_l2vpn_evpn_rd_tags,
0);
}
-DEFUN(show_ip_bgp_l2vpn_evpn_all_neighbor_routes,
- show_ip_bgp_l2vpn_evpn_all_neighbor_routes_cmd,
- "show [ip] bgp l2vpn evpn all neighbors A.B.C.D routes [json]",
+DEFUN(show_ip_bgp_l2vpn_evpn_neighbor_routes,
+ show_ip_bgp_l2vpn_evpn_neighbor_routes_cmd,
+ "show [ip] bgp l2vpn evpn neighbors <A.B.C.D|X:X::X:X|WORD> routes [json]",
SHOW_STR
IP_STR
BGP_STR
L2VPN_HELP_STR
EVPN_HELP_STR
- "Display information about all EVPN NLRIs\n"
"Detailed information on TCP and BGP neighbor connections\n"
- "Neighbor to display information about\n"
+ "IPv4 Neighbor to display information about\n"
+ "IPv6 Neighbor to display information about\n"
+ "Neighbor on BGP configured interface\n"
"Display routes learned from neighbor\n" JSON_STR)
{
- int idx_ipv4 = 0;
- union sockunion su;
+ int idx = 0;
struct peer *peer;
- int ret;
+ char *peerstr = NULL;
bool uj = use_json(argc, argv);
+ afi_t afi = AFI_L2VPN;
+ safi_t safi = SAFI_EVPN;
+ struct bgp *bgp = NULL;
- argv_find(argv, argc, "A.B.C.D", &idx_ipv4);
+ bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
+ &bgp, uj);
+ if (!idx) {
+ vty_out(vty, "No index\n");
+ return CMD_WARNING;
+ }
+
+ /* neighbors <A.B.C.D|X:X::X:X|WORD> */
+ argv_find(argv, argc, "neighbors", &idx);
+ peerstr = argv[++idx]->arg;
- ret = str2sockunion(argv[idx_ipv4]->arg, &su);
- if (ret < 0) {
+ peer = peer_lookup_in_view(vty, bgp, peerstr, uj);
+ if (!peer) {
if (uj) {
json_object *json_no = NULL;
json_no = json_object_new_object();
@@ -1325,11 +1335,9 @@ DEFUN(show_ip_bgp_l2vpn_evpn_all_neighbor_routes,
json_object_free(json_no);
} else
vty_out(vty, "Malformed address: %s\n",
- argv[idx_ipv4]->arg);
+ argv[idx]->arg);
return CMD_WARNING;
}
-
- peer = peer_lookup(NULL, &su);
if (!peer || !peer->afc[AFI_L2VPN][SAFI_EVPN]) {
if (uj) {
json_object *json_no = NULL;
@@ -1345,13 +1353,13 @@ DEFUN(show_ip_bgp_l2vpn_evpn_all_neighbor_routes,
return CMD_WARNING;
}
- return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_neighbor, &su, 0,
+ return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_neighbor, peer, 0,
uj);
}
DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_routes,
show_ip_bgp_l2vpn_evpn_rd_neighbor_routes_cmd,
- "show [ip] bgp l2vpn evpn rd ASN:NN_OR_IP-ADDRESS:NN neighbors A.B.C.D routes [json]",
+ "show [ip] bgp l2vpn evpn rd ASN:NN_OR_IP-ADDRESS:NN neighbors <A.B.C.D|X:X::X:X|WORD> routes [json]",
SHOW_STR
IP_STR
BGP_STR
@@ -1360,20 +1368,30 @@ DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_routes,
"Display information for a route distinguisher\n"
"VPN Route Distinguisher\n"
"Detailed information on TCP and BGP neighbor connections\n"
- "Neighbor to display information about\n"
+ "IPv4 Neighbor to display information about\n"
+ "IPv6 Neighbor to display information about\n"
+ "Neighbor on BGP configured interface\n"
"Display routes learned from neighbor\n" JSON_STR)
{
int idx_ext_community = 0;
- int idx_ipv4 = 0;
+ int idx = 0;
int ret;
- union sockunion su;
struct peer *peer;
+ char *peerstr = NULL;
struct prefix_rd prd;
bool uj = use_json(argc, argv);
+ afi_t afi = AFI_L2VPN;
+ safi_t safi = SAFI_EVPN;
+ struct bgp *bgp = NULL;
- argv_find(argv, argc, "ASN:NN_OR_IP-ADDRESS:NN", &idx_ext_community);
- argv_find(argv, argc, "A.B.C.D", &idx_ipv4);
+ bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
+ &bgp, uj);
+ if (!idx) {
+ vty_out(vty, "No index\n");
+ return CMD_WARNING;
+ }
+ argv_find(argv, argc, "ASN:NN_OR_IP-ADDRESS:NN", &idx_ext_community);
ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
if (!ret) {
if (uj) {
@@ -1389,8 +1407,12 @@ DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_routes,
return CMD_WARNING;
}
- ret = str2sockunion(argv[idx_ipv4]->arg, &su);
- if (ret < 0) {
+ /* neighbors <A.B.C.D|X:X::X:X|WORD> */
+ argv_find(argv, argc, "neighbors", &idx);
+ peerstr = argv[++idx]->arg;
+
+ peer = peer_lookup_in_view(vty, bgp, peerstr, uj);
+ if (!peer) {
if (uj) {
json_object *json_no = NULL;
json_no = json_object_new_object();
@@ -1401,11 +1423,9 @@ DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_routes,
json_object_free(json_no);
} else
vty_out(vty, "Malformed address: %s\n",
- argv[idx_ext_community]->arg);
+ argv[idx]->arg);
return CMD_WARNING;
}
-
- peer = peer_lookup(NULL, &su);
if (!peer || !peer->afc[AFI_L2VPN][SAFI_EVPN]) {
if (uj) {
json_object *json_no = NULL;
@@ -1421,33 +1441,48 @@ DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_routes,
return CMD_WARNING;
}
- return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_neighbor, &su, 0,
+ return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_neighbor, peer, 0,
uj);
}
-DEFUN(show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes,
- show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes_cmd,
- "show [ip] bgp l2vpn evpn all neighbors A.B.C.D advertised-routes [json]",
+DEFUN(show_ip_bgp_l2vpn_evpn_neighbor_advertised_routes,
+ show_ip_bgp_l2vpn_evpn_neighbor_advertised_routes_cmd,
+ "show [ip] bgp l2vpn evpn neighbors <A.B.C.D|X:X::X:X|WORD> advertised-routes [json]",
SHOW_STR
IP_STR
BGP_STR
L2VPN_HELP_STR
EVPN_HELP_STR
- "Display information about all EVPN NLRIs\n"
"Detailed information on TCP and BGP neighbor connections\n"
- "Neighbor to display information about\n"
+ "IPv4 Neighbor to display information about\n"
+ "IPv6 Neighbor to display information about\n"
+ "Neighbor on BGP configured interface\n"
"Display the routes advertised to a BGP neighbor\n" JSON_STR)
{
- int idx_ipv4 = 0;
- int ret;
+ int idx = 0;
struct peer *peer;
- union sockunion su;
bool uj = use_json(argc, argv);
+ struct bgp *bgp = NULL;
+ afi_t afi = AFI_L2VPN;
+ safi_t safi = SAFI_EVPN;
+ char *peerstr = NULL;
+
+ if (uj)
+ argc--;
- argv_find(argv, argc, "A.B.C.D", &idx_ipv4);
+ bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
+ &bgp, uj);
+ if (!idx) {
+ vty_out(vty, "No index\n");
+ return CMD_WARNING;
+ }
+
+ /* neighbors <A.B.C.D|X:X::X:X|WORD> */
+ argv_find(argv, argc, "neighbors", &idx);
+ peerstr = argv[++idx]->arg;
- ret = str2sockunion(argv[idx_ipv4]->arg, &su);
- if (ret < 0) {
+ peer = peer_lookup_in_view(vty, bgp, peerstr, uj);
+ if (!peer) {
if (uj) {
json_object *json_no = NULL;
json_no = json_object_new_object();
@@ -1458,10 +1493,9 @@ DEFUN(show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes,
json_object_free(json_no);
} else
vty_out(vty, "Malformed address: %s\n",
- argv[idx_ipv4]->arg);
+ argv[idx]->arg);
return CMD_WARNING;
}
- peer = peer_lookup(NULL, &su);
if (!peer || !peer->afc[AFI_L2VPN][SAFI_EVPN]) {
if (uj) {
json_object *json_no = NULL;
@@ -1482,7 +1516,7 @@ DEFUN(show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes,
DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes,
show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes_cmd,
- "show [ip] bgp l2vpn evpn rd ASN:NN_OR_IP-ADDRESS:NN neighbors A.B.C.D advertised-routes [json]",
+ "show [ip] bgp l2vpn evpn rd ASN:NN_OR_IP-ADDRESS:NN neighbors <A.B.C.D|X:X::X:X|WORD> advertised-routes [json]",
SHOW_STR
IP_STR
BGP_STR
@@ -1491,22 +1525,43 @@ DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes,
"Display information for a route distinguisher\n"
"VPN Route Distinguisher\n"
"Detailed information on TCP and BGP neighbor connections\n"
- "Neighbor to display information about\n"
+ "IPv4 Neighbor to display information about\n"
+ "IPv6 Neighbor to display information about\n"
+ "Neighbor on BGP configured interface\n"
"Display the routes advertised to a BGP neighbor\n" JSON_STR)
{
int idx_ext_community = 0;
- int idx_ipv4 = 0;
+ int idx = 0;
int ret;
struct peer *peer;
struct prefix_rd prd;
- union sockunion su;
+ struct bgp *bgp = NULL;
bool uj = use_json(argc, argv);
+ char *peerstr = NULL;
+ afi_t afi = AFI_L2VPN;
+ safi_t safi = SAFI_EVPN;
+
+ if (uj)
+ argc--;
+
+ if (uj)
+ argc--;
+
+ bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
+ &bgp, uj);
+ if (!idx) {
+ vty_out(vty, "No index\n");
+ return CMD_WARNING;
+ }
argv_find(argv, argc, "ASN:NN_OR_IP-ADDRESS:NN", &idx_ext_community);
- argv_find(argv, argc, "A.B.C.D", &idx_ipv4);
- ret = str2sockunion(argv[idx_ipv4]->arg, &su);
- if (ret < 0) {
+ /* neighbors <A.B.C.D|X:X::X:X|WORD> */
+ argv_find(argv, argc, "neighbors", &idx);
+ peerstr = argv[++idx]->arg;
+
+ peer = peer_lookup_in_view(vty, bgp, peerstr, uj);
+ if (!peer) {
if (uj) {
json_object *json_no = NULL;
json_no = json_object_new_object();
@@ -1517,10 +1572,9 @@ DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes,
json_object_free(json_no);
} else
vty_out(vty, "Malformed address: %s\n",
- argv[idx_ext_community]->arg);
+ argv[idx]->arg);
return CMD_WARNING;
}
- peer = peer_lookup(NULL, &su);
if (!peer || !peer->afc[AFI_L2VPN][SAFI_EVPN]) {
if (uj) {
json_object *json_no = NULL;
@@ -1599,7 +1653,7 @@ DEFUN(show_ip_bgp_evpn_rd_overlay,
use_json(argc, argv));
}
-/* For testing purpose, static route of MPLS-VPN. */
+/* For testing purpose, static route of EVPN RT-5. */
DEFUN(evpnrt5_network,
evpnrt5_network_cmd,
"network <A.B.C.D/M|X:X::X:X/M> rd ASN:NN_OR_IP-ADDRESS:NN ethtag WORD label WORD esi WORD gwip <A.B.C.D|X:X::X:X> routermac WORD [route-map WORD]",
@@ -1638,7 +1692,7 @@ DEFUN(evpnrt5_network,
argv[idx_routermac]->arg);
}
-/* For testing purpose, static route of MPLS-VPN. */
+/* For testing purpose, static route of EVPN RT-5. */
DEFUN(no_evpnrt5_network,
no_evpnrt5_network_cmd,
"no network <A.B.C.D/M|X:X::X:X/M> rd ASN:NN_OR_IP-ADDRESS:NN ethtag WORD label WORD esi WORD gwip <A.B.C.D|X:X::X:X>",
@@ -5323,12 +5377,12 @@ void bgp_ethernetvpn_init(void)
install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_tags_cmd);
install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_tags_cmd);
install_element(VIEW_NODE,
- &show_ip_bgp_l2vpn_evpn_all_neighbor_routes_cmd);
+ &show_ip_bgp_l2vpn_evpn_neighbor_routes_cmd);
install_element(VIEW_NODE,
&show_ip_bgp_l2vpn_evpn_rd_neighbor_routes_cmd);
install_element(
VIEW_NODE,
- &show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes_cmd);
+ &show_ip_bgp_l2vpn_evpn_neighbor_advertised_routes_cmd);
install_element(
VIEW_NODE,
&show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes_cmd);
diff --git a/bgpd/bgp_filter.c b/bgpd/bgp_filter.c
index d4f608d40f..30a964a22c 100644
--- a/bgpd/bgp_filter.c
+++ b/bgpd/bgp_filter.c
@@ -193,7 +193,7 @@ static struct as_list *as_list_insert(const char *name)
/* If name is made by all digit character. We treat it as
number. */
for (number = 0, i = 0; i < strlen(name); i++) {
- if (isdigit((int)name[i]))
+ if (isdigit((unsigned char)name[i]))
number = (number * 10) + (name[i] - '0');
else
break;
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index 4348e6b240..c9c6fc157e 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -96,6 +96,21 @@ static int bgp_holdtime_timer(struct thread *);
/* BGP FSM functions. */
static int bgp_start(struct peer *);
+/* Register peer with NHT */
+static int bgp_peer_reg_with_nht(struct peer *peer)
+{
+ int connected = 0;
+
+ if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1
+ && !CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)
+ && !bgp_flag_check(peer->bgp, BGP_FLAG_DISABLE_NH_CONNECTED_CHK))
+ connected = 1;
+
+ return bgp_find_or_add_nexthop(
+ peer->bgp, peer->bgp, family2afi(peer->su.sa.sa_family),
+ NULL, peer, connected);
+}
+
static void peer_xfer_stats(struct peer *peer_dst, struct peer *peer_src)
{
/* Copy stats over. These are only the pre-established state stats */
@@ -293,6 +308,11 @@ static struct peer *peer_xfer_conn(struct peer *from_peer)
if (from_peer)
peer_xfer_stats(peer, from_peer);
+ /* Register peer for NHT. This is to allow RAs to be enabled when
+ * needed, even on a passive connection.
+ */
+ bgp_peer_reg_with_nht(peer);
+
bgp_reads_on(peer);
bgp_writes_on(peer);
thread_add_timer_msec(bm->master, bgp_process_packet, peer, 0,
@@ -1382,7 +1402,6 @@ static int bgp_connect_fail(struct peer *peer)
int bgp_start(struct peer *peer)
{
int status;
- int connected = 0;
bgp_peer_conf_if_to_su_update(peer);
@@ -1439,17 +1458,10 @@ int bgp_start(struct peer *peer)
return -1;
}
- /* Register to be notified on peer up */
- if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1
- && !CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)
- && !bgp_flag_check(peer->bgp, BGP_FLAG_DISABLE_NH_CONNECTED_CHK))
- connected = 1;
- else
- connected = 0;
-
- if (!bgp_find_or_add_nexthop(peer->bgp, peer->bgp,
- family2afi(peer->su.sa.sa_family), NULL,
- peer, connected)) {
+ /* Register peer for NHT. If next hop is already resolved, proceed
+ * with connection setup, else wait.
+ */
+ if (!bgp_peer_reg_with_nht(peer)) {
if (bgp_zebra_num_connects()) {
if (bgp_debug_neighbor_events(peer))
zlog_debug("%s [FSM] Waiting for NHT",
diff --git a/bgpd/bgp_lcommunity.c b/bgpd/bgp_lcommunity.c
index 098374fa9f..aeb290719a 100644
--- a/bgpd/bgp_lcommunity.c
+++ b/bgpd/bgp_lcommunity.c
@@ -359,7 +359,7 @@ static const char *lcommunity_gettoken(const char *str,
const char *p = str;
/* Skip white space. */
- while (isspace((int)*p)) {
+ while (isspace((unsigned char)*p)) {
p++;
str++;
}
@@ -369,14 +369,14 @@ static const char *lcommunity_gettoken(const char *str,
return NULL;
/* Community value. */
- if (isdigit((int)*p)) {
+ if (isdigit((unsigned char)*p)) {
int separator = 0;
int digit = 0;
uint32_t globaladmin = 0;
uint32_t localdata1 = 0;
uint32_t localdata2 = 0;
- while (isdigit((int)*p) || *p == ':') {
+ while (isdigit((unsigned char)*p) || *p == ':') {
if (*p == ':') {
if (separator == 2) {
*token = lcommunity_token_unknown;
@@ -439,7 +439,8 @@ struct lcommunity *lcommunity_str2com(const char *str)
enum lcommunity_token token = lcommunity_token_unknown;
struct lcommunity_val lval;
- while ((str = lcommunity_gettoken(str, &lval, &token))) {
+ do {
+ str = lcommunity_gettoken(str, &lval, &token);
switch (token) {
case lcommunity_token_val:
if (lcom == NULL)
@@ -452,7 +453,8 @@ struct lcommunity *lcommunity_str2com(const char *str)
lcommunity_free(&lcom);
return NULL;
}
- }
+ } while (str);
+
return lcom;
}
diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c
index a8c507832c..812f0ce16e 100644
--- a/bgpd/bgp_nexthop.c
+++ b/bgpd/bgp_nexthop.c
@@ -680,17 +680,23 @@ static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp, int detail,
continue;
for (rn = bgp_table_top(table[afi]); rn;
rn = bgp_route_next(rn)) {
+ struct peer *peer;
+
bnc = bgp_node_get_bgp_nexthop_info(rn);
if (!bnc)
continue;
+ peer = (struct peer *)bnc->nht_info;
if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)) {
vty_out(vty,
- " %s valid [IGP metric %d], #paths %d\n",
+ " %s valid [IGP metric %d], #paths %d",
inet_ntop(rn->p.family,
&rn->p.u.prefix, buf,
sizeof(buf)),
bnc->metric, bnc->path_count);
+ if (peer)
+ vty_out(vty, ", peer %s", peer->host);
+ vty_out(vty, "\n");
if (!detail)
continue;
@@ -698,10 +704,13 @@ static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp, int detail,
bgp_show_nexthops_detail(vty, bgp, bnc);
} else {
- vty_out(vty, " %s invalid\n",
+ vty_out(vty, " %s invalid",
inet_ntop(rn->p.family,
&rn->p.u.prefix, buf,
sizeof(buf)));
+ if (peer)
+ vty_out(vty, ", peer %s", peer->host);
+ vty_out(vty, "\n");
if (CHECK_FLAG(bnc->flags,
BGP_NEXTHOP_CONNECTED))
vty_out(vty, " Must be Connected\n");
diff --git a/bgpd/bgp_packet.h b/bgpd/bgp_packet.h
index e8eacee589..fc6fc66a4c 100644
--- a/bgpd/bgp_packet.h
+++ b/bgpd/bgp_packet.h
@@ -57,9 +57,6 @@ extern void bgp_notify_send_with_data(struct peer *, uint8_t, uint8_t,
extern void bgp_route_refresh_send(struct peer *, afi_t, safi_t, uint8_t,
uint8_t, int);
extern void bgp_capability_send(struct peer *, afi_t, safi_t, int, int);
-extern void bgp_default_update_send(struct peer *, struct attr *, afi_t, safi_t,
- struct peer *);
-extern void bgp_default_withdraw_send(struct peer *, afi_t, safi_t);
extern int bgp_capability_receive(struct peer *, bgp_size_t);
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index aa02cc3c63..183debddba 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -1243,10 +1243,12 @@ static int bgp_cluster_filter(struct peer *peer, struct attr *attr)
static int bgp_input_modifier(struct peer *peer, struct prefix *p,
struct attr *attr, afi_t afi, safi_t safi,
- const char *rmap_name)
+ const char *rmap_name, mpls_label_t *label,
+ uint32_t num_labels)
{
struct bgp_filter *filter;
- struct bgp_path_info rmap_path;
+ struct bgp_path_info rmap_path = { 0 };
+ struct bgp_path_info_extra extra = { 0 };
route_map_result_t ret;
struct route_map *rmap = NULL;
@@ -1276,6 +1278,11 @@ static int bgp_input_modifier(struct peer *peer, struct prefix *p,
/* Duplicate current value to new strucutre for modification. */
rmap_path.peer = peer;
rmap_path.attr = attr;
+ rmap_path.extra = &extra;
+ extra.num_labels = num_labels;
+ if (label && num_labels && num_labels <= BGP_MAX_LABELS)
+ memcpy(extra.label, label,
+ num_labels * sizeof(mpls_label_t));
SET_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN);
@@ -1366,7 +1373,7 @@ static void bgp_peer_remove_private_as(struct bgp *bgp, afi_t afi, safi_t safi,
peer, afi, safi,
PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE))
attr->aspath = aspath_replace_private_asns(
- attr->aspath, bgp->as);
+ attr->aspath, bgp->as, peer->as);
// The entire aspath consists of private ASNs so create
// an empty aspath
@@ -1377,7 +1384,7 @@ static void bgp_peer_remove_private_as(struct bgp *bgp, afi_t afi, safi_t safi,
// the private ASNs
else
attr->aspath = aspath_remove_private_asns(
- attr->aspath);
+ attr->aspath, peer->as);
}
// 'all' was not specified so the entire aspath must be private
@@ -1388,7 +1395,7 @@ static void bgp_peer_remove_private_as(struct bgp *bgp, afi_t afi, safi_t safi,
peer, afi, safi,
PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE))
attr->aspath = aspath_replace_private_asns(
- attr->aspath, bgp->as);
+ attr->aspath, bgp->as, peer->as);
else
attr->aspath = aspath_empty_get();
}
@@ -1465,7 +1472,7 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi,
struct bgp *bgp;
struct attr *piattr;
char buf[PREFIX_STRLEN];
- int ret;
+ route_map_result_t ret;
int transparent;
int reflect;
afi_t afi;
@@ -2544,12 +2551,12 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
/* apply the route-map */
if (bgp->adv_cmd_rmap[afi][safi].map) {
- int ret = 0;
+ route_map_result_t ret;
ret = route_map_apply(
bgp->adv_cmd_rmap[afi][safi].map,
&rn->p, RMAP_BGP, new_select);
- if (ret == RMAP_MATCH)
+ if (ret == RMAP_PERMITMATCH)
bgp_evpn_advertise_type5_route(
bgp, &rn->p, new_select->attr,
afi, safi);
@@ -3149,8 +3156,8 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id,
* commands, so we need bgp_attr_flush in the error paths, until we
* intern
* the attr (which takes over the memory references) */
- if (bgp_input_modifier(peer, p, &new_attr, afi, safi, NULL)
- == RMAP_DENY) {
+ if (bgp_input_modifier(peer, p, &new_attr, afi, safi, NULL,
+ label, num_labels) == RMAP_DENY) {
peer->stat_pfx_filter++;
reason = "route-map;";
bgp_attr_flush(&new_attr);
@@ -4593,7 +4600,7 @@ void bgp_static_update(struct bgp *bgp, struct prefix *p,
struct bgp_path_info rmap_path;
struct attr attr;
struct attr *attr_new;
- int ret;
+ route_map_result_t ret;
#if ENABLE_BGP_VNC
int vnc_implicit_withdraw = 0;
#endif
@@ -4941,7 +4948,7 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p,
if (bgp_static->rmap.name) {
struct attr attr_tmp = attr;
struct bgp_path_info rmap_path;
- int ret;
+ route_map_result_t ret;
rmap_path.peer = bgp->peer_self;
rmap_path.attr = &attr_tmp;
@@ -5325,6 +5332,13 @@ static void bgp_purge_af_static_redist_routes(struct bgp *bgp, afi_t afi,
struct bgp_node *rn;
struct bgp_path_info *pi;
+ /* Do not install the aggregate route if BGP is in the
+ * process of termination.
+ */
+ if (bgp_flag_check(bgp, BGP_FLAG_DELETE_IN_PROGRESS) ||
+ (bgp->peer_self == NULL))
+ return;
+
table = bgp->rib[afi][safi];
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) {
@@ -6620,7 +6634,7 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
struct attr attr;
struct attr *new_attr;
afi_t afi;
- int ret;
+ route_map_result_t ret;
struct bgp_redist *red;
/* Make default attribute. */
@@ -8151,20 +8165,25 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp,
json_nexthop_global = json_object_new_object();
}
- if (!json_paths && safi == SAFI_EVPN) {
+ if (!json_paths && path->extra) {
char tag_buf[30];
- bgp_evpn_route2str((struct prefix_evpn *)&bn->p,
- buf2, sizeof(buf2));
- vty_out(vty, " Route %s", buf2);
+ buf2[0] = '\0';
tag_buf[0] = '\0';
if (path->extra && path->extra->num_labels) {
bgp_evpn_label2str(path->extra->label,
path->extra->num_labels, tag_buf,
sizeof(tag_buf));
- vty_out(vty, " VNI %s", tag_buf);
}
- vty_out(vty, "\n");
+ if (safi == SAFI_EVPN) {
+ bgp_evpn_route2str((struct prefix_evpn *)&bn->p,
+ buf2, sizeof(buf2));
+ vty_out(vty, " Route %s", buf2);
+ if (tag_buf[0] != '\0')
+ vty_out(vty, " VNI %s", tag_buf);
+ vty_out(vty, "\n");
+ }
+
if (path->extra && path->extra->parent) {
struct bgp_path_info *parent_ri;
struct bgp_node *rn, *prn;
@@ -8173,11 +8192,14 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp,
rn = parent_ri->net;
if (rn && rn->prn) {
prn = rn->prn;
- vty_out(vty, " Imported from %s:%s\n",
- prefix_rd2str(
- (struct prefix_rd *)&prn->p,
- buf1, sizeof(buf1)),
- buf2);
+ prefix_rd2str((struct prefix_rd *)&prn->p,
+ buf1, sizeof(buf1));
+ if (is_pi_family_evpn(parent_ri)) {
+ bgp_evpn_route2str((struct prefix_evpn *)&rn->p,
+ buf2, sizeof(buf2));
+ vty_out(vty, " Imported from %s:%s, VNI %s\n", buf1, buf2, tag_buf);
+ } else
+ vty_out(vty, " Imported from %s:%s\n", buf1, buf2);
}
}
}
@@ -9139,7 +9161,7 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
struct route_map *rmap = output_arg;
struct bgp_path_info path;
struct attr dummy_attr;
- int ret;
+ route_map_result_t ret;
bgp_attr_dup(&dummy_attr, pi->attr);
@@ -10486,63 +10508,6 @@ static int bgp_show_prefix_longer(struct vty *vty, struct bgp *bgp,
return ret;
}
-static struct peer *peer_lookup_in_view(struct vty *vty, struct bgp *bgp,
- const char *ip_str, bool use_json)
-{
- int ret;
- struct peer *peer;
- union sockunion su;
-
- /* Get peer sockunion. */
- ret = str2sockunion(ip_str, &su);
- if (ret < 0) {
- peer = peer_lookup_by_conf_if(bgp, ip_str);
- if (!peer) {
- peer = peer_lookup_by_hostname(bgp, ip_str);
-
- if (!peer) {
- if (use_json) {
- json_object *json_no = NULL;
- json_no = json_object_new_object();
- json_object_string_add(
- json_no,
- "malformedAddressOrName",
- ip_str);
- vty_out(vty, "%s\n",
- json_object_to_json_string_ext(
- json_no,
- JSON_C_TO_STRING_PRETTY));
- json_object_free(json_no);
- } else
- vty_out(vty,
- "%% Malformed address or name: %s\n",
- ip_str);
- return NULL;
- }
- }
- return peer;
- }
-
- /* Peer structure lookup. */
- peer = peer_lookup(bgp, &su);
- if (!peer) {
- if (use_json) {
- json_object *json_no = NULL;
- json_no = json_object_new_object();
- json_object_string_add(json_no, "warning",
- "No such neighbor in this view/vrf");
- vty_out(vty, "%s\n",
- json_object_to_json_string_ext(
- json_no, JSON_C_TO_STRING_PRETTY));
- json_object_free(json_no);
- } else
- vty_out(vty, "No such neighbor in this view/vrf\n");
- return NULL;
- }
-
- return peer;
-}
-
enum bgp_stats {
BGP_STATS_MAXBITLEN = 0,
BGP_STATS_RIB,
@@ -11284,7 +11249,7 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi,
/* Filter prefix using route-map */
ret = bgp_input_modifier(peer, &rn->p, &attr,
- afi, safi, rmap_name);
+ afi, safi, rmap_name, NULL, 0);
if (type == bgp_show_adj_route_filtered &&
!route_filtered && ret != RMAP_DENY) {
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 1f90fa742a..7f1a9b71c1 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -62,6 +62,7 @@
#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_pbr.h"
#include "bgpd/bgp_flowspec_util.h"
+#include "bgpd/bgp_encap_types.h"
#if ENABLE_BGP_VNC
#include "bgpd/rfapi/bgp_rfapi_cfg.h"
@@ -239,10 +240,9 @@ struct bgp_match_peer_compiled {
/* Compares the peer specified in the 'match peer' clause with the peer
received in bgp_path_info->peer. If it is the same, or if the peer structure
received is a peer_group containing it, returns RMAP_MATCH. */
-static route_map_result_t route_match_peer(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_peer(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct bgp_match_peer_compiled *pc;
union sockunion *su;
@@ -335,10 +335,9 @@ struct route_map_rule_cmd route_match_peer_cmd = {"peer", route_match_peer,
route_match_peer_free};
#if defined(HAVE_LUA)
-static route_map_result_t route_match_command(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_command(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
int status = RMAP_NOMATCH;
u_int32_t locpref = 0;
@@ -434,10 +433,9 @@ struct route_map_rule_cmd route_match_command_cmd = {
/* Match function should return 1 if match is success else return
zero. */
-static route_map_result_t route_match_ip_address(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_ip_address(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct access_list *alist;
@@ -474,10 +472,9 @@ struct route_map_rule_cmd route_match_ip_address_cmd = {
/* `match ip next-hop IP_ADDRESS' */
/* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_ip_next_hop(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_ip_next_hop(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct access_list *alist;
struct bgp_path_info *path;
@@ -521,10 +518,9 @@ struct route_map_rule_cmd route_match_ip_next_hop_cmd = {
/* `match ip route-source ACCESS-LIST' */
/* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_ip_route_source(void *rule,
- const struct prefix *pfx,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_ip_route_source(void *rule, const struct prefix *pfx,
+ route_map_object_t type, void *object)
{
struct access_list *alist;
struct bgp_path_info *path;
@@ -571,9 +567,9 @@ struct route_map_rule_cmd route_match_ip_route_source_cmd = {
"ip route-source", route_match_ip_route_source,
route_match_ip_route_source_compile, route_match_ip_route_source_free};
-static route_map_result_t route_match_prefix_list_flowspec(afi_t afi,
- struct prefix_list *plist,
- const struct prefix *p)
+static enum route_map_cmd_result_t
+route_match_prefix_list_flowspec(afi_t afi, struct prefix_list *plist,
+ const struct prefix *p)
{
int ret;
struct bgp_pbr_entry_main api;
@@ -604,8 +600,7 @@ static route_map_result_t route_match_prefix_list_flowspec(afi_t afi,
return RMAP_NOMATCH;
}
-/* `match ip address prefix-list PREFIX_LIST' */
-static route_map_result_t
+static enum route_map_cmd_result_t
route_match_address_prefix_list(void *rule, afi_t afi,
const struct prefix *prefix,
route_map_object_t type, void *object)
@@ -626,7 +621,7 @@ route_match_address_prefix_list(void *rule, afi_t afi,
: RMAP_MATCH);
}
-static route_map_result_t
+static enum route_map_cmd_result_t
route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -651,7 +646,7 @@ struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = {
/* `match ip next-hop prefix-list PREFIX_LIST' */
-static route_map_result_t
+static enum route_map_cmd_result_t
route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -693,7 +688,7 @@ struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = {
/* `match ip next-hop type <blackhole>' */
-static route_map_result_t
+static enum route_map_cmd_result_t
route_match_ip_next_hop_type(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -702,7 +697,7 @@ route_match_ip_next_hop_type(void *rule, const struct prefix *prefix,
if (type == RMAP_BGP && prefix->family == AF_INET) {
path = (struct bgp_path_info *)object;
if (!path || !path->attr)
- return RMAP_DENYMATCH;
+ return RMAP_NOMATCH;
/* If nexthop interface's index can't be resolved and nexthop is
set to any address then mark it as type `blackhole`.
@@ -732,7 +727,7 @@ static struct route_map_rule_cmd route_match_ip_next_hop_type_cmd = {
/* `match ip route-source prefix-list PREFIX_LIST' */
-static route_map_result_t
+static enum route_map_cmd_result_t
route_match_ip_route_source_prefix_list(void *rule,
const struct prefix *prefix,
route_map_object_t type, void *object)
@@ -782,10 +777,9 @@ struct route_map_rule_cmd route_match_ip_route_source_prefix_list_cmd = {
/* `match evpn default-route' */
/* Match function should return 1 if match is success else 0 */
-static route_map_result_t route_match_evpn_default_route(void *rule,
- const struct prefix *p,
- route_map_object_t
- type, void *object)
+static enum route_map_cmd_result_t
+route_match_evpn_default_route(void *rule, const struct prefix *p,
+ route_map_object_t type, void *object)
{
if (type == RMAP_BGP && is_evpn_prefix_default(p))
return RMAP_MATCH;
@@ -801,10 +795,9 @@ struct route_map_rule_cmd route_match_evpn_default_route_cmd = {
/* Match function should return 1 if match is success else return
zero. */
-static route_map_result_t route_match_mac_address(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_mac_address(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct access_list *alist;
struct prefix p;
@@ -847,26 +840,51 @@ struct route_map_rule_cmd route_match_mac_address_cmd = {
"mac address", route_match_mac_address, route_match_mac_address_compile,
route_match_mac_address_free};
-/* `match vni' */
-
-/* Match function should return 1 if match is success else return
- zero. */
-static route_map_result_t route_match_vni(void *rule,
- const struct prefix *prefix,
- route_map_object_t type, void *object)
+/*
+ * Match function returns:
+ * ...RMAP_MATCH if match is found.
+ * ...RMAP_NOMATCH if match is not found.
+ * ...RMAP_NOOP to ignore this match check.
+ */
+static enum route_map_cmd_result_t
+route_match_vni(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
vni_t vni = 0;
+ unsigned int label_cnt = 0;
struct bgp_path_info *path = NULL;
+ struct prefix_evpn *evp = (struct prefix_evpn *) prefix;
if (type == RMAP_BGP) {
vni = *((vni_t *)rule);
path = (struct bgp_path_info *)object;
+ /*
+ * This rmap filter is valid for vxlan tunnel type only.
+ * For any other tunnel type, return noop to ignore
+ * this check.
+ */
+ if (path->attr && path->attr->encap_tunneltype !=
+ BGP_ENCAP_TYPE_VXLAN)
+ return RMAP_NOOP;
+
+ /*
+ * Apply filter to type 1, 2, 5 routes only.
+ * Other route types do not have vni label.
+ */
+ if (evp && (evp->prefix.route_type != BGP_EVPN_AD_ROUTE &&
+ evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE &&
+ evp->prefix.route_type != BGP_EVPN_IP_PREFIX_ROUTE))
+ return RMAP_NOOP;
+
if (path->extra == NULL)
return RMAP_NOMATCH;
- if (vni == label2vni(&path->extra->label[0]))
- return RMAP_MATCH;
+ for ( ; label_cnt < BGP_MAX_LABELS &&
+ label_cnt < path->extra->num_labels; label_cnt++) {
+ if (vni == label2vni(&path->extra->label[label_cnt]))
+ return RMAP_MATCH;
+ }
}
return RMAP_NOMATCH;
@@ -904,10 +922,9 @@ struct route_map_rule_cmd route_match_evpn_vni_cmd = {
/* Match function should return 1 if match is success else return
zero. */
-static route_map_result_t route_match_evpn_route_type(void *rule,
- const struct prefix *pfx,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_evpn_route_type(void *rule, const struct prefix *pfx,
+ route_map_object_t type, void *object)
{
uint8_t route_type = 0;
@@ -950,7 +967,7 @@ struct route_map_rule_cmd route_match_evpn_route_type_cmd = {
route_match_evpn_route_type_compile, route_match_evpn_route_type_free};
/* Route map commands for VRF route leak with source vrf matching */
-static route_map_result_t
+static enum route_map_cmd_result_t
route_match_vrl_source_vrf(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -999,10 +1016,9 @@ struct route_map_rule_cmd route_match_vrl_source_vrf_cmd = {
/* `match local-preference LOCAL-PREF' */
/* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_local_pref(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_local_pref(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
uint32_t *local_pref;
struct bgp_path_info *path;
@@ -1056,10 +1072,9 @@ struct route_map_rule_cmd route_match_local_pref_cmd = {
/* `match metric METRIC' */
/* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_metric(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_metric(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct rmap_value *rv;
struct bgp_path_info *path;
@@ -1080,10 +1095,9 @@ struct route_map_rule_cmd route_match_metric_cmd = {
/* `match as-path ASPATH' */
/* Match function for as-path match. I assume given object is */
-static route_map_result_t route_match_aspath(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_aspath(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct as_list *as_list;
@@ -1130,10 +1144,9 @@ struct rmap_community {
};
/* Match function for community match. */
-static route_map_result_t route_match_community(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_community(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct community_list *list;
struct bgp_path_info *path;
@@ -1200,10 +1213,9 @@ struct route_map_rule_cmd route_match_community_cmd = {
route_match_community_free};
/* Match function for lcommunity match. */
-static route_map_result_t route_match_lcommunity(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_lcommunity(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct community_list *list;
struct bgp_path_info *path;
@@ -1273,10 +1285,9 @@ struct route_map_rule_cmd route_match_lcommunity_cmd = {
/* Match function for extcommunity match. */
-static route_map_result_t route_match_ecommunity(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_ecommunity(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct community_list *list;
struct bgp_path_info *path;
@@ -1327,10 +1338,9 @@ struct route_map_rule_cmd route_match_ecommunity_cmd = {
and `address-family vpnv4'. */
/* `match origin' */
-static route_map_result_t route_match_origin(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_origin(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
uint8_t *origin;
struct bgp_path_info *path;
@@ -1375,10 +1385,9 @@ struct route_map_rule_cmd route_match_origin_cmd = {
/* match probability { */
-static route_map_result_t route_match_probability(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_probability(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
long r = random();
@@ -1430,10 +1439,9 @@ struct route_map_rule_cmd route_match_probability_cmd = {
/* `match interface IFNAME' */
/* Match function should return 1 if match is success else return
zero. */
-static route_map_result_t route_match_interface(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_interface(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct interface *ifp;
struct bgp_path_info *path;
@@ -1477,9 +1485,9 @@ struct route_map_rule_cmd route_match_interface_cmd = {
/* `set ip next-hop IP_ADDRESS' */
/* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_tag(void *rule,
- const struct prefix *prefix,
- route_map_object_t type, void *object)
+static enum route_map_cmd_result_t
+route_match_tag(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
route_tag_t *tag;
struct bgp_path_info *path;
@@ -1509,10 +1517,9 @@ struct rmap_ip_nexthop_set {
int unchanged;
};
-static route_map_result_t route_set_ip_nexthop(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_set_ip_nexthop(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct rmap_ip_nexthop_set *rins = rule;
struct bgp_path_info *path;
@@ -1615,10 +1622,9 @@ struct route_map_rule_cmd route_set_ip_nexthop_cmd = {
/* `set local-preference LOCAL_PREF' */
/* Set local preference. */
-static route_map_result_t route_set_local_pref(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_set_local_pref(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct rmap_value *rv;
struct bgp_path_info *path;
@@ -1650,10 +1656,9 @@ struct route_map_rule_cmd route_set_local_pref_cmd = {
/* `set weight WEIGHT' */
/* Set weight. */
-static route_map_result_t route_set_weight(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_set_weight(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct rmap_value *rv;
struct bgp_path_info *path;
@@ -1678,10 +1683,9 @@ struct route_map_rule_cmd route_set_weight_cmd = {
/* `set metric METRIC' */
/* Set metric to attribute. */
-static route_map_result_t route_set_metric(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_set_metric(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct rmap_value *rv;
struct bgp_path_info *path;
@@ -1709,10 +1713,9 @@ struct route_map_rule_cmd route_set_metric_cmd = {
/* `set as-path prepend ASPATH' */
/* For AS path prepend mechanism. */
-static route_map_result_t route_set_aspath_prepend(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_set_aspath_prepend(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct aspath *aspath;
struct aspath *new;
@@ -1772,10 +1775,9 @@ struct route_map_rule_cmd route_set_aspath_prepend_cmd = {
* one.
* Make a deep copy of existing AS_PATH, but for the first ASn only.
*/
-static route_map_result_t route_set_aspath_exclude(void *rule,
- const struct prefix *dummy,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_set_aspath_exclude(void *rule, const struct prefix *dummy,
+ route_map_object_t type, void *object)
{
struct aspath *new_path, *exclude_path;
struct bgp_path_info *path;
@@ -1807,10 +1809,9 @@ struct rmap_com_set {
};
/* For community set mechanism. */
-static route_map_result_t route_set_community(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_set_community(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct rmap_com_set *rcs;
struct bgp_path_info *path;
@@ -1923,10 +1924,9 @@ struct rmap_lcom_set {
/* For lcommunity set mechanism. */
-static route_map_result_t route_set_lcommunity(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_set_lcommunity(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct rmap_lcom_set *rcs;
struct bgp_path_info *path;
@@ -2036,10 +2036,9 @@ struct route_map_rule_cmd route_set_lcommunity_cmd = {
/* `set large-comm-list (<1-99>|<100-500>|WORD) delete' */
/* For large community set mechanism. */
-static route_map_result_t route_set_lcommunity_delete(void *rule,
- const struct prefix *pfx,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_set_lcommunity_delete(void *rule, const struct prefix *pfx,
+ route_map_object_t type, void *object)
{
struct community_list *list;
struct lcommunity *merge;
@@ -2092,12 +2091,19 @@ static route_map_result_t route_set_lcommunity_delete(void *rule,
static void *route_set_lcommunity_delete_compile(const char *arg)
{
struct rmap_community *rcom;
+ char **splits;
+ int num;
- rcom = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_community));
+ frrstr_split(arg, " ", &splits, &num);
- rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
+ rcom = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_community));
+ rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, splits[0]);
rcom->name_hash = bgp_clist_hash_key(rcom->name);
+ for (int i = 0; i < num; i++)
+ XFREE(MTYPE_TMP, splits[i]);
+ XFREE(MTYPE_TMP, splits);
+
return rcom;
}
@@ -2120,11 +2126,9 @@ struct route_map_rule_cmd route_set_lcommunity_delete_cmd = {
/* `set comm-list (<1-99>|<100-500>|WORD) delete' */
/* For community set mechanism. */
-static route_map_result_t route_set_community_delete(
- void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_set_community_delete(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct community_list *list;
struct community *merge;
@@ -2177,12 +2181,19 @@ static route_map_result_t route_set_community_delete(
static void *route_set_community_delete_compile(const char *arg)
{
struct rmap_community *rcom;
+ char **splits;
+ int num;
- rcom = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_community));
+ frrstr_split(arg, " ", &splits, &num);
- rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
+ rcom = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_community));
+ rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, splits[0]);
rcom->name_hash = bgp_clist_hash_key(rcom->name);
+ for (int i = 0; i < num; i++)
+ XFREE(MTYPE_TMP, splits[i]);
+ XFREE(MTYPE_TMP, splits);
+
return rcom;
}
@@ -2204,10 +2215,9 @@ struct route_map_rule_cmd route_set_community_delete_cmd = {
/* `set extcommunity rt COMMUNITY' */
/* For community set mechanism. Used by _rt and _soo. */
-static route_map_result_t route_set_ecommunity(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_set_ecommunity(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct ecommunity *ecom;
struct ecommunity *new_ecom;
@@ -2292,10 +2302,9 @@ struct route_map_rule_cmd route_set_ecommunity_soo_cmd = {
/* `set origin ORIGIN' */
/* For origin set. */
-static route_map_result_t route_set_origin(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_set_origin(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
uint8_t *origin;
struct bgp_path_info *path;
@@ -2342,10 +2351,9 @@ struct route_map_rule_cmd route_set_origin_cmd = {
/* `set atomic-aggregate' */
/* For atomic aggregate set. */
-static route_map_result_t route_set_atomic_aggregate(void *rule,
- const struct prefix *pfx,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_set_atomic_aggregate(void *rule, const struct prefix *pfx,
+ route_map_object_t type, void *object)
{
struct bgp_path_info *path;
@@ -2381,10 +2389,9 @@ struct aggregator {
struct in_addr address;
};
-static route_map_result_t route_set_aggregator_as(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_set_aggregator_as(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct bgp_path_info *path;
struct aggregator *aggregator;
@@ -2435,9 +2442,9 @@ struct route_map_rule_cmd route_set_aggregator_as_cmd = {
};
/* Set tag to object. object must be pointer to struct bgp_path_info */
-static route_map_result_t route_set_tag(void *rule,
- const struct prefix *prefix,
- route_map_object_t type, void *object)
+static enum route_map_cmd_result_t
+route_set_tag(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
route_tag_t *tag;
struct bgp_path_info *path;
@@ -2460,10 +2467,9 @@ static struct route_map_rule_cmd route_set_tag_cmd = {
};
/* Set label-index to object. object must be pointer to struct bgp_path_info */
-static route_map_result_t route_set_label_index(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_set_label_index(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct rmap_value *rv;
struct bgp_path_info *path;
@@ -2493,10 +2499,9 @@ static struct route_map_rule_cmd route_set_label_index_cmd = {
/* `match ipv6 address IP_ACCESS_LIST' */
-static route_map_result_t route_match_ipv6_address(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_ipv6_address(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct access_list *alist;
@@ -2529,10 +2534,9 @@ struct route_map_rule_cmd route_match_ipv6_address_cmd = {
/* `match ipv6 next-hop IP_ADDRESS' */
-static route_map_result_t route_match_ipv6_next_hop(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_ipv6_next_hop(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct in6_addr *addr = rule;
struct bgp_path_info *path;
@@ -2581,7 +2585,7 @@ struct route_map_rule_cmd route_match_ipv6_next_hop_cmd = {
/* `match ipv6 address prefix-list PREFIX_LIST' */
-static route_map_result_t
+static enum route_map_cmd_result_t
route_match_ipv6_address_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -2606,9 +2610,9 @@ struct route_map_rule_cmd route_match_ipv6_address_prefix_list_cmd = {
/* `match ipv6 next-hop type <TYPE>' */
-static route_map_result_t
+static enum route_map_cmd_result_t
route_match_ipv6_next_hop_type(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+ route_map_object_t type, void *object)
{
struct bgp_path_info *path;
struct in6_addr *addr = rule;
@@ -2616,7 +2620,7 @@ route_match_ipv6_next_hop_type(void *rule, const struct prefix *prefix,
if (type == RMAP_BGP && prefix->family == AF_INET6) {
path = (struct bgp_path_info *)object;
if (!path || !path->attr)
- return RMAP_DENYMATCH;
+ return RMAP_NOMATCH;
if (IPV6_ADDR_SAME(&path->attr->mp_nexthop_global, addr)
&& !path->attr->nh_ifindex)
@@ -2654,10 +2658,9 @@ struct route_map_rule_cmd route_match_ipv6_next_hop_type_cmd = {
/* `set ipv6 nexthop global IP_ADDRESS' */
/* Set nexthop to object. ojbect must be pointer to struct attr. */
-static route_map_result_t route_set_ipv6_nexthop_global(void *rule,
- const struct prefix *p,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_set_ipv6_nexthop_global(void *rule, const struct prefix *p,
+ route_map_object_t type, void *object)
{
struct in6_addr *address;
struct bgp_path_info *path;
@@ -2713,7 +2716,7 @@ struct route_map_rule_cmd route_set_ipv6_nexthop_global_cmd = {
route_set_ipv6_nexthop_global_free};
/* Set next-hop preference value. */
-static route_map_result_t
+static enum route_map_cmd_result_t
route_set_ipv6_nexthop_prefer_global(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -2767,10 +2770,9 @@ struct route_map_rule_cmd route_set_ipv6_nexthop_prefer_global_cmd = {
/* `set ipv6 nexthop local IP_ADDRESS' */
/* Set nexthop to object. ojbect must be pointer to struct attr. */
-static route_map_result_t route_set_ipv6_nexthop_local(void *rule,
- const struct prefix *p,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_set_ipv6_nexthop_local(void *rule, const struct prefix *p,
+ route_map_object_t type, void *object)
{
struct in6_addr *address;
struct bgp_path_info *path;
@@ -2830,10 +2832,9 @@ struct route_map_rule_cmd route_set_ipv6_nexthop_local_cmd = {
/* `set ipv6 nexthop peer-address' */
/* Set nexthop to object. ojbect must be pointer to struct attr. */
-static route_map_result_t route_set_ipv6_nexthop_peer(void *rule,
- const struct prefix *pfx,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_set_ipv6_nexthop_peer(void *rule, const struct prefix *pfx,
+ route_map_object_t type, void *object)
{
struct in6_addr peer_address;
struct bgp_path_info *path;
@@ -2908,10 +2909,9 @@ struct route_map_rule_cmd route_set_ipv6_nexthop_peer_cmd = {
/* `set ipv4 vpn next-hop A.B.C.D' */
-static route_map_result_t route_set_vpnv4_nexthop(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_set_vpnv4_nexthop(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct in_addr *address;
struct bgp_path_info *path;
@@ -2948,10 +2948,9 @@ static void *route_set_vpnv4_nexthop_compile(const char *arg)
/* `set ipv6 vpn next-hop A.B.C.D' */
-static route_map_result_t route_set_vpnv6_nexthop(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_set_vpnv6_nexthop(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct in6_addr *address;
struct bgp_path_info *path;
@@ -3004,10 +3003,9 @@ struct route_map_rule_cmd route_set_vpnv6_nexthop_cmd = {
/* `set originator-id' */
/* For origin set. */
-static route_map_result_t route_set_originator_id(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_set_originator_id(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct in_addr *address;
struct bgp_path_info *path;
@@ -3408,31 +3406,34 @@ int bgp_route_map_update_timer(struct thread *thread)
static void bgp_route_map_mark_update(const char *rmap_name)
{
- if (bm->t_rmap_update == NULL) {
- struct listnode *node, *nnode;
- struct bgp *bgp;
-
- /* rmap_update_timer of 0 means don't do route updates */
- if (bm->rmap_update_timer) {
- bm->t_rmap_update = NULL;
- thread_add_timer(bm->master, bgp_route_map_update_timer,
- NULL, bm->rmap_update_timer,
- &bm->t_rmap_update);
-
- /* Signal the groups that a route-map update event has
- * started */
- for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp))
- update_group_policy_update(bgp,
- BGP_POLICY_ROUTE_MAP,
- rmap_name, 1, 1);
- } else {
- for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp))
- bgp_route_map_process_update(bgp, rmap_name, 0);
+ struct listnode *node, *nnode;
+ struct bgp *bgp;
+
+ /* If new update is received before the current timer timed out,
+ * turn it off and start a new timer.
+ */
+ if (bm->t_rmap_update != NULL)
+ THREAD_OFF(bm->t_rmap_update);
+
+ /* rmap_update_timer of 0 means don't do route updates */
+ if (bm->rmap_update_timer) {
+ thread_add_timer(bm->master, bgp_route_map_update_timer,
+ NULL, bm->rmap_update_timer,
+ &bm->t_rmap_update);
+
+ /* Signal the groups that a route-map update event has
+ * started */
+ for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp))
+ update_group_policy_update(bgp,
+ BGP_POLICY_ROUTE_MAP,
+ rmap_name, 1, 1);
+ } else {
+ for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp))
+ bgp_route_map_process_update(bgp, rmap_name, 0);
#if ENABLE_BGP_VNC
- zlog_debug("%s: calling vnc_routemap_update", __func__);
- vnc_routemap_update(bgp, __func__);
+ zlog_debug("%s: calling vnc_routemap_update", __func__);
+ vnc_routemap_update(bgp, __func__);
#endif
- }
}
}
diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c
index 0637723990..22840d54c6 100644
--- a/bgpd/bgp_rpki.c
+++ b/bgpd/bgp_rpki.c
@@ -129,8 +129,10 @@ static void print_record(const struct pfx_record *record, struct vty *vty);
static int is_synchronized(void);
static int is_running(void);
static void route_match_free(void *rule);
-static route_map_result_t route_match(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object);
+static enum route_map_cmd_result_t route_match(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object);
static void *route_match_compile(const char *arg);
static void revalidate_bgp_node(struct bgp_node *bgp_node, afi_t afi,
safi_t safi);
@@ -140,7 +142,6 @@ static struct rtr_mgr_config *rtr_config;
static struct list *cache_list;
static int rtr_is_running;
static int rtr_is_stopping;
-static int rtr_is_starting;
static _Atomic int rtr_update_overflow;
static int rpki_debug;
static unsigned int polling_period;
@@ -213,8 +214,10 @@ static void ipv6_addr_to_host_byte_order(const uint32_t *src, uint32_t *dest)
dest[i] = ntohl(src[i]);
}
-static route_map_result_t route_match(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static enum route_map_cmd_result_t route_match(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
int *rpki_status = rule;
struct bgp_path_info *path;
@@ -474,7 +477,7 @@ static void rpki_update_cb_sync_rtr(struct pfx_table *p __attribute__((unused)),
const struct pfx_record rec,
const bool added __attribute__((unused)))
{
- if (rtr_is_stopping || rtr_is_starting
+ if (rtr_is_stopping
|| atomic_load_explicit(&rtr_update_overflow, memory_order_seq_cst))
return;
@@ -566,11 +569,9 @@ static int bgp_rpki_module_init(void)
static int start(void)
{
- unsigned int waiting_time = 0;
int ret;
rtr_is_stopping = 0;
- rtr_is_starting = 1;
rtr_update_overflow = 0;
if (list_isempty(cache_list)) {
@@ -599,23 +600,6 @@ static int start(void)
return ERROR;
}
rtr_is_running = 1;
- RPKI_DEBUG("Waiting for rtr connection to synchronize.");
- while (waiting_time++ <= initial_synchronisation_timeout) {
- if (rtr_mgr_conf_in_sync(rtr_config))
- break;
-
- sleep(1);
- }
- if (rtr_mgr_conf_in_sync(rtr_config)) {
- RPKI_DEBUG("Got synchronisation with at least one RPKI cache!");
- RPKI_DEBUG("Forcing revalidation.");
- rtr_is_starting = 0;
- revalidate_all_routes();
- } else {
- RPKI_DEBUG(
- "Timeout expired! Proceeding without RPKI validation data.");
- rtr_is_starting = 0;
- }
XFREE(MTYPE_BGP_RPKI_CACHE_GROUP, groups);
@@ -1196,7 +1180,7 @@ DEFPY (show_rpki_prefix,
{
if (!is_synchronized()) {
- vty_out(vty, "No Conection to RPKI cache server.\n");
+ vty_out(vty, "No Connection to RPKI cache server.\n");
return CMD_WARNING;
}
diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c
index ecde71279d..53175bfccf 100644
--- a/bgpd/bgp_table.c
+++ b/bgpd/bgp_table.c
@@ -156,8 +156,10 @@ void bgp_table_range_lookup(const struct bgp_table *table, struct prefix *p,
struct bgp_node *node = bgp_node_from_rnode(table->route_table->top);
struct bgp_node *matched = NULL;
- while (node && node->p.prefixlen <= p->prefixlen
- && prefix_match(&node->p, p)) {
+ if (node == NULL)
+ return;
+
+ while (node->p.prefixlen <= p->prefixlen && prefix_match(&node->p, p)) {
if (bgp_node_has_bgp_path_info_data(node)
&& node->p.prefixlen == p->prefixlen) {
matched = node;
@@ -167,10 +169,10 @@ void bgp_table_range_lookup(const struct bgp_table *table, struct prefix *p,
&p->u.prefix, node->p.prefixlen)]);
}
- if (node == NULL)
- return;
-
- if ((matched == NULL && node->p.prefixlen > maxlen) || !node->parent)
+ if (matched == NULL && node->p.prefixlen <= maxlen
+ && prefix_match(p, &node->p) && node->parent == NULL)
+ matched = node;
+ else if ((matched == NULL && node->p.prefixlen > maxlen) || !node->parent)
return;
else if (matched == NULL)
matched = node = bgp_node_from_rnode(node->parent);
diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c
index b64c51f341..21f1dff60d 100644
--- a/bgpd/bgp_updgrp_adv.c
+++ b/bgpd/bgp_updgrp_adv.c
@@ -716,7 +716,7 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw)
struct bgp_node *rn;
struct bgp_path_info *ri;
struct peer *peer;
- int ret = RMAP_DENYMATCH;
+ route_map_result_t ret = RMAP_DENYMATCH;
afi_t afi;
safi_t safi;
diff --git a/bgpd/bgp_vpn.c b/bgpd/bgp_vpn.c
index 54ca980cad..09b1cb429b 100644
--- a/bgpd/bgp_vpn.c
+++ b/bgpd/bgp_vpn.c
@@ -74,7 +74,7 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer,
json_object_string_add(json_ocode, "incomplete", "?");
}
- for (rn = bgp_table_top(bgp->rib[afi][SAFI_MPLS_VPN]); rn;
+ for (rn = bgp_table_top(bgp->rib[afi][safi]); rn;
rn = bgp_route_next(rn)) {
if (prd && memcmp(rn->p.u.val, prd->val, 8) != 0)
continue;
@@ -200,7 +200,7 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer,
json_array);
} else {
route_vty_out_tmp(vty, &rm->p, path->attr,
- SAFI_MPLS_VPN, use_json,
+ safi, use_json,
json_array);
}
}
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index d7f6b65384..4447c2ccf8 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -596,12 +596,61 @@ static void bgp_clear_vty_error(struct vty *vty, struct peer *peer, afi_t afi,
}
}
+static int bgp_peer_clear(struct peer *peer, afi_t afi, safi_t safi,
+ struct listnode *nnode, enum bgp_clear_type stype)
+{
+ int ret = 0;
+
+ /* if afi/.safi not specified, spin thru all of them */
+ if ((afi == AFI_UNSPEC) && (safi == SAFI_UNSPEC)) {
+ afi_t tmp_afi;
+ safi_t tmp_safi;
+
+ FOREACH_AFI_SAFI (tmp_afi, tmp_safi) {
+ if (!peer->afc[tmp_afi][tmp_safi])
+ continue;
+
+ if (stype == BGP_CLEAR_SOFT_NONE)
+ ret = peer_clear(peer, &nnode);
+ else
+ ret = peer_clear_soft(peer, tmp_afi, tmp_safi,
+ stype);
+ }
+ /* if afi specified and safi not, spin thru safis on this afi */
+ } else if (safi == SAFI_UNSPEC) {
+ safi_t tmp_safi;
+
+ for (tmp_safi = SAFI_UNICAST;
+ tmp_safi < SAFI_MAX; tmp_safi++) {
+ if (!peer->afc[afi][tmp_safi])
+ continue;
+
+ if (stype == BGP_CLEAR_SOFT_NONE)
+ ret = peer_clear(peer, &nnode);
+ else
+ ret = peer_clear_soft(peer, afi,
+ tmp_safi, stype);
+ }
+ /* both afi/safi specified, let the caller know if not defined */
+ } else {
+ if (!peer->afc[afi][safi])
+ return 1;
+
+ if (stype == BGP_CLEAR_SOFT_NONE)
+ ret = peer_clear(peer, &nnode);
+ else
+ ret = peer_clear_soft(peer, afi, safi, stype);
+ }
+
+ return ret;
+}
+
/* `clear ip bgp' functions. */
static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
enum clear_sort sort, enum bgp_clear_type stype,
const char *arg)
{
- int ret;
+ int ret = 0;
bool found = false;
struct peer *peer;
struct listnode *node, *nnode;
@@ -614,28 +663,17 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
*/
if (sort == clear_all) {
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
- if (!peer->afc[afi][safi])
- continue;
-
- if (stype == BGP_CLEAR_SOFT_NONE)
- ret = peer_clear(peer, &nnode);
- else
- ret = peer_clear_soft(peer, afi, safi, stype);
+ ret = bgp_peer_clear(peer, afi, safi, nnode,
+ stype);
if (ret < 0)
bgp_clear_vty_error(vty, peer, afi, safi, ret);
- else
- found = true;
}
/* This is to apply read-only mode on this clear. */
if (stype == BGP_CLEAR_SOFT_NONE)
bgp->update_delay_over = 0;
- if (!found)
- vty_out(vty, "%%BGP: No %s peer configured\n",
- afi_safi_print(afi, safi));
-
return CMD_SUCCESS;
}
@@ -666,12 +704,11 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
}
}
- if (!peer->afc[afi][safi])
+ ret = bgp_peer_clear(peer, afi, safi, NULL, stype);
+
+ /* if afi/safi not defined for this peer, let caller know */
+ if (ret == 1)
ret = BGP_ERR_AF_UNCONFIGURED;
- else if (stype == BGP_CLEAR_SOFT_NONE)
- ret = peer_clear(peer, NULL);
- else
- ret = peer_clear_soft(peer, afi, safi, stype);
if (ret < 0)
bgp_clear_vty_error(vty, peer, afi, safi, ret);
@@ -690,13 +727,7 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
}
for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- if (!peer->afc[afi][safi])
- continue;
-
- if (stype == BGP_CLEAR_SOFT_NONE)
- ret = peer_clear(peer, NULL);
- else
- ret = peer_clear_soft(peer, afi, safi, stype);
+ ret = bgp_peer_clear(peer, afi, safi, nnode, stype);
if (ret < 0)
bgp_clear_vty_error(vty, peer, afi, safi, ret);
@@ -718,13 +749,7 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
if (peer->sort == BGP_PEER_IBGP)
continue;
- if (!peer->afc[afi][safi])
- continue;
-
- if (stype == BGP_CLEAR_SOFT_NONE)
- ret = peer_clear(peer, &nnode);
- else
- ret = peer_clear_soft(peer, afi, safi, stype);
+ ret = bgp_peer_clear(peer, afi, safi, nnode, stype);
if (ret < 0)
bgp_clear_vty_error(vty, peer, afi, safi, ret);
@@ -748,12 +773,7 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
if (peer->as != as)
continue;
- if (!peer->afc[afi][safi])
- ret = BGP_ERR_AF_UNCONFIGURED;
- else if (stype == BGP_CLEAR_SOFT_NONE)
- ret = peer_clear(peer, &nnode);
- else
- ret = peer_clear_soft(peer, afi, safi, stype);
+ ret = bgp_peer_clear(peer, afi, safi, nnode, stype);
if (ret < 0)
bgp_clear_vty_error(vty, peer, afi, safi, ret);
@@ -6075,7 +6095,7 @@ DEFUN (neighbor_allowas_in,
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Accept as-path with my AS present in it\n"
- "Number of occurences of AS number\n"
+ "Number of occurrences of AS number\n"
"Only accept my AS in the as-path if the route was originated in my AS\n")
{
int idx_peer = 1;
@@ -6109,7 +6129,7 @@ ALIAS_HIDDEN(
"neighbor <A.B.C.D|X:X::X:X|WORD> allowas-in [<(1-10)|origin>]",
NEIGHBOR_STR NEIGHBOR_ADDR_STR2
"Accept as-path with my AS present in it\n"
- "Number of occurences of AS number\n"
+ "Number of occurrences of AS number\n"
"Only accept my AS in the as-path if the route was originated in my AS\n")
DEFUN (no_neighbor_allowas_in,
@@ -6119,7 +6139,7 @@ DEFUN (no_neighbor_allowas_in,
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"allow local ASN appears in aspath attribute\n"
- "Number of occurences of AS number\n"
+ "Number of occurrences of AS number\n"
"Only accept my AS in the as-path if the route was originated in my AS\n")
{
int idx_peer = 2;
@@ -6141,7 +6161,7 @@ ALIAS_HIDDEN(
"no neighbor <A.B.C.D|X:X::X:X|WORD> allowas-in [<(1-10)|origin>]",
NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
"allow local ASN appears in aspath attribute\n"
- "Number of occurences of AS number\n"
+ "Number of occurrences of AS number\n"
"Only accept my AS in the as-path if the route was originated in my AS\n")
DEFUN (neighbor_ttl_security,
@@ -7244,8 +7264,8 @@ DEFUN (clear_ip_bgp_all,
{
char *vrf = NULL;
- afi_t afi = AFI_IP6;
- safi_t safi = SAFI_UNICAST;
+ afi_t afi = AFI_UNSPEC;
+ safi_t safi = SAFI_UNSPEC;
enum clear_sort clr_sort = clear_peer;
enum bgp_clear_type clr_type;
char *clr_arg = NULL;
@@ -7287,6 +7307,9 @@ DEFUN (clear_ip_bgp_all,
} else if (argv_find(argv, argc, "PGNAME", &idx)) {
clr_sort = clear_peer;
clr_arg = argv[idx]->arg;
+ } else if (argv_find(argv, argc, "WORD", &idx)) {
+ clr_sort = clear_peer;
+ clr_arg = argv[idx]->arg;
} else if (argv_find(argv, argc, "(1-4294967295)", &idx)) {
clr_sort = clear_as;
clr_arg = argv[idx]->arg;
@@ -7773,7 +7796,7 @@ static void bgp_show_bestpath_json(struct bgp *bgp, json_object *json)
/* Show BGP peer's summary information. */
static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
- bool use_json, json_object *json)
+ bool use_json)
{
struct peer *peer;
struct listnode *node, *nnode;
@@ -7784,6 +7807,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
int len;
int max_neighbor_width = 0;
int pfx_rcd_safi;
+ json_object *json = NULL;
json_object *json_peer = NULL;
json_object *json_peers = NULL;
struct peer_af *paf;
@@ -7798,9 +7822,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
pfx_rcd_safi = safi;
if (use_json) {
- if (json == NULL)
- json = json_object_new_object();
-
+ json = json_object_new_object();
json_peers = json_object_new_object();
} else {
/* Loop over all neighbors that will be displayed to determine
@@ -8205,8 +8227,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
}
static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi,
- int safi, bool use_json,
- json_object *json)
+ int safi, bool use_json)
{
int is_first = 1;
int afi_wildcard = (afi == AFI_MAX);
@@ -8224,6 +8245,7 @@ static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi,
while (safi < SAFI_MAX) {
if (bgp_afi_safi_peer_exists(bgp, afi, safi)) {
nbr_output = true;
+
if (is_wildcard) {
/*
* So limit output to those afi/safi
@@ -8232,8 +8254,6 @@ static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi,
* them
*/
if (use_json) {
- json = json_object_new_object();
-
if (!is_first)
vty_out(vty, ",\n");
else
@@ -8248,8 +8268,7 @@ static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi,
safi));
}
}
- bgp_show_summary(vty, bgp, afi, safi, use_json,
- json);
+ bgp_show_summary(vty, bgp, afi, safi, use_json);
}
safi++;
if (!safi_wildcard)
@@ -8275,7 +8294,6 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi,
{
struct listnode *node, *nnode;
struct bgp *bgp;
- json_object *json = NULL;
int is_first = 1;
bool nbr_output = false;
@@ -8285,8 +8303,6 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi,
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
nbr_output = true;
if (use_json) {
- json = json_object_new_object();
-
if (!is_first)
vty_out(vty, ",\n");
else
@@ -8302,7 +8318,7 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi,
? VRF_DEFAULT_NAME
: bgp->name);
}
- bgp_show_summary_afi_safi(vty, bgp, afi, safi, use_json, json);
+ bgp_show_summary_afi_safi(vty, bgp, afi, safi, use_json);
}
if (use_json)
@@ -8333,8 +8349,8 @@ int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi,
return CMD_WARNING;
}
- bgp_show_summary_afi_safi(vty, bgp, afi, safi, use_json,
- NULL);
+ bgp_show_summary_afi_safi(vty, bgp, afi, safi,
+ use_json);
return CMD_SUCCESS;
}
}
@@ -8342,7 +8358,7 @@ int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi,
bgp = bgp_get_default();
if (bgp)
- bgp_show_summary_afi_safi(vty, bgp, afi, safi, use_json, NULL);
+ bgp_show_summary_afi_safi(vty, bgp, afi, safi, use_json);
else {
if (use_json)
vty_out(vty, "{}\n");
@@ -13199,20 +13215,44 @@ void bgp_vty_init(void)
install_element(BGP_NODE, &no_neighbor_nexthop_self_all_hidden_cmd);
install_element(BGP_IPV4_NODE, &neighbor_nexthop_self_force_cmd);
install_element(BGP_IPV4_NODE, &no_neighbor_nexthop_self_force_cmd);
+ install_element(BGP_IPV4_NODE, &neighbor_nexthop_self_all_hidden_cmd);
+ install_element(BGP_IPV4_NODE,
+ &no_neighbor_nexthop_self_all_hidden_cmd);
install_element(BGP_IPV4M_NODE, &neighbor_nexthop_self_force_cmd);
install_element(BGP_IPV4M_NODE, &no_neighbor_nexthop_self_force_cmd);
+ install_element(BGP_IPV4M_NODE, &neighbor_nexthop_self_all_hidden_cmd);
+ install_element(BGP_IPV4M_NODE,
+ &no_neighbor_nexthop_self_all_hidden_cmd);
install_element(BGP_IPV4L_NODE, &neighbor_nexthop_self_force_cmd);
install_element(BGP_IPV4L_NODE, &no_neighbor_nexthop_self_force_cmd);
+ install_element(BGP_IPV4L_NODE, &neighbor_nexthop_self_all_hidden_cmd);
+ install_element(BGP_IPV4L_NODE,
+ &no_neighbor_nexthop_self_all_hidden_cmd);
install_element(BGP_IPV6_NODE, &neighbor_nexthop_self_force_cmd);
install_element(BGP_IPV6_NODE, &no_neighbor_nexthop_self_force_cmd);
+ install_element(BGP_IPV6_NODE, &neighbor_nexthop_self_all_hidden_cmd);
+ install_element(BGP_IPV6_NODE,
+ &no_neighbor_nexthop_self_all_hidden_cmd);
install_element(BGP_IPV6M_NODE, &neighbor_nexthop_self_force_cmd);
install_element(BGP_IPV6M_NODE, &no_neighbor_nexthop_self_force_cmd);
+ install_element(BGP_IPV6M_NODE, &neighbor_nexthop_self_all_hidden_cmd);
+ install_element(BGP_IPV6M_NODE,
+ &no_neighbor_nexthop_self_all_hidden_cmd);
install_element(BGP_IPV6L_NODE, &neighbor_nexthop_self_force_cmd);
install_element(BGP_IPV6L_NODE, &no_neighbor_nexthop_self_force_cmd);
+ install_element(BGP_IPV6L_NODE, &neighbor_nexthop_self_all_hidden_cmd);
+ install_element(BGP_IPV6L_NODE,
+ &no_neighbor_nexthop_self_all_hidden_cmd);
install_element(BGP_VPNV4_NODE, &neighbor_nexthop_self_force_cmd);
install_element(BGP_VPNV4_NODE, &no_neighbor_nexthop_self_force_cmd);
+ install_element(BGP_VPNV4_NODE, &neighbor_nexthop_self_all_hidden_cmd);
+ install_element(BGP_VPNV4_NODE,
+ &no_neighbor_nexthop_self_all_hidden_cmd);
install_element(BGP_VPNV6_NODE, &neighbor_nexthop_self_force_cmd);
install_element(BGP_VPNV6_NODE, &no_neighbor_nexthop_self_force_cmd);
+ install_element(BGP_VPNV6_NODE, &neighbor_nexthop_self_all_hidden_cmd);
+ install_element(BGP_VPNV6_NODE,
+ &no_neighbor_nexthop_self_all_hidden_cmd);
/* "neighbor as-override" commands. */
install_element(BGP_NODE, &neighbor_as_override_hidden_cmd);
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index d79a68dcab..b5f267cc38 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -8047,3 +8047,61 @@ void bgp_terminate(void)
bgp_mac_finish();
}
+
+struct peer *peer_lookup_in_view(struct vty *vty, struct bgp *bgp,
+ const char *ip_str, bool use_json)
+{
+ int ret;
+ struct peer *peer;
+ union sockunion su;
+
+ /* Get peer sockunion. */
+ ret = str2sockunion(ip_str, &su);
+ if (ret < 0) {
+ peer = peer_lookup_by_conf_if(bgp, ip_str);
+ if (!peer) {
+ peer = peer_lookup_by_hostname(bgp, ip_str);
+
+ if (!peer) {
+ if (use_json) {
+ json_object *json_no = NULL;
+ json_no = json_object_new_object();
+ json_object_string_add(
+ json_no,
+ "malformedAddressOrName",
+ ip_str);
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json_no,
+ JSON_C_TO_STRING_PRETTY));
+ json_object_free(json_no);
+ } else
+ vty_out(vty,
+ "%% Malformed address or name: %s\n",
+ ip_str);
+ return NULL;
+ }
+ }
+ return peer;
+ }
+
+ /* Peer structure lookup. */
+ peer = peer_lookup(bgp, &su);
+ if (!peer) {
+ if (use_json) {
+ json_object *json_no = NULL;
+ json_no = json_object_new_object();
+ json_object_string_add(json_no, "warning",
+ "No such neighbor in this view/vrf");
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json_no, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json_no);
+ } else
+ vty_out(vty, "No such neighbor in this view/vrf\n");
+ return NULL;
+ }
+
+ return peer;
+}
+
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 777db0ce22..9e05fd5629 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -1927,4 +1927,8 @@ extern void bgp_unset_redist_vrf_bitmaps(struct bgp *, vrf_id_t);
/* For benefit of rfapi */
extern struct peer *peer_new(struct bgp *bgp);
+
+extern struct peer *peer_lookup_in_view(struct vty *vty, struct bgp *bgp,
+ const char *ip_str, bool use_json);
+
#endif /* _QUAGGA_BGPD_H */
diff --git a/configure.ac b/configure.ac
index 961336fbd0..134c8692d4 100755
--- a/configure.ac
+++ b/configure.ac
@@ -572,6 +572,20 @@ AC_ARG_ENABLE([thread-sanitizer],
AS_HELP_STRING([--enable-thread-sanitizer], [enable ThreadSanitizer support for detecting data races]))
AC_ARG_ENABLE([memory-sanitizer],
AS_HELP_STRING([--enable-memory-sanitizer], [enable MemorySanitizer support for detecting uninitialized memory reads]))
+AC_ARG_WITH([crypto],
+ AS_HELP_STRING([--with-crypto=<internal|openssl>], [choose between different implementations of cryptographic functions(default value is --with-crypto=internal)]))
+
+#if openssl, else use the internal
+AS_IF([test x"${with_crypto}" = x"openssl"], [
+AC_CHECK_LIB([crypto], [EVP_DigestInit], [LIBS="$LIBS -lcrypto"], [], [])
+if test $ac_cv_lib_crypto_EVP_DigestInit = no; then
+ AC_MSG_ERROR([build with openssl has been specified but openssl library was not found on your system])
+else
+ AC_DEFINE([CRYPTO_OPENSSL], [1], [Compile with openssl support])
+fi
+], [test x"${with_crypto}" = x"internal" || test x"${with_crypto}" = x"" ], [AC_DEFINE([CRYPTO_INTERNAL], [1], [Compile with internal cryptographic implementation])
+], [AC_MSG_ERROR([Unknown value for --with-crypto])]
+)
AS_IF([test "${enable_clippy_only}" != "yes"], [
AC_CHECK_HEADERS([json-c/json.h])
diff --git a/debian/.gitignore b/debian/.gitignore
new file mode 100644
index 0000000000..0b267c6f5c
--- /dev/null
+++ b/debian/.gitignore
@@ -0,0 +1,13 @@
+
+/.debhelper/
+/*/
+!/tests/
+!/source
+
+/*.log
+/*.substvars
+/*.debhelper
+/autoreconf.*
+/files
+/frr.init
+/frr.service
diff --git a/doc/developer/building-frr-for-centos6.rst b/doc/developer/building-frr-for-centos6.rst
index ee0ffc2bf7..3d9edbe3a1 100644
--- a/doc/developer/building-frr-for-centos6.rst
+++ b/doc/developer/building-frr-for-centos6.rst
@@ -45,7 +45,7 @@ Add packages:
sudo yum install git autoconf automake libtool make \
readline-devel texinfo net-snmp-devel groff pkgconfig \
- json-c-devel pam-devel flex epel-release c-ares-devel
+ json-c-devel pam-devel flex epel-release c-ares-devel libcap-devel
Install newer version of bison (CentOS 6 package source is too old) from CentOS
7:
diff --git a/doc/developer/building-frr-for-centos7.rst b/doc/developer/building-frr-for-centos7.rst
index 67f71bc3a5..cd90d41ffb 100644
--- a/doc/developer/building-frr-for-centos7.rst
+++ b/doc/developer/building-frr-for-centos7.rst
@@ -21,7 +21,7 @@ Add packages:
sudo yum install git autoconf automake libtool make \
readline-devel texinfo net-snmp-devel groff pkgconfig \
json-c-devel pam-devel bison flex pytest c-ares-devel \
- python-devel systemd-devel python-sphinx
+ python-devel systemd-devel python-sphinx libcap-devel
.. include:: building-libyang.rst
diff --git a/doc/developer/building-frr-for-debian8.rst b/doc/developer/building-frr-for-debian8.rst
index 76f927853d..c12bf46f8d 100644
--- a/doc/developer/building-frr-for-debian8.rst
+++ b/doc/developer/building-frr-for-debian8.rst
@@ -18,7 +18,7 @@ Add packages:
sudo apt-get install git autoconf automake libtool make \
libreadline-dev texinfo libjson-c-dev pkg-config bison flex python3-pip \
libc-ares-dev python3-dev python3-sphinx build-essential libsystemd-dev \
- libsnmp-dev
+ libsnmp-dev libcap-dev
Install newer pytest (>3.0) from pip
diff --git a/doc/developer/building-frr-for-debian9.rst b/doc/developer/building-frr-for-debian9.rst
index e58c59f451..f976b9f49a 100644
--- a/doc/developer/building-frr-for-debian9.rst
+++ b/doc/developer/building-frr-for-debian9.rst
@@ -11,7 +11,7 @@ Add packages:
sudo apt-get install git autoconf automake libtool make \
libreadline-dev texinfo libjson-c-dev pkg-config bison flex \
libc-ares-dev python3-dev python3-pytest python3-sphinx build-essential \
- libsnmp-dev libsystemd-dev
+ libsnmp-dev libsystemd-dev libcap-dev
.. include:: building-libyang.rst
diff --git a/doc/developer/building-frr-for-fedora.rst b/doc/developer/building-frr-for-fedora.rst
index 0bfd43e93c..d8405eb351 100644
--- a/doc/developer/building-frr-for-fedora.rst
+++ b/doc/developer/building-frr-for-fedora.rst
@@ -14,7 +14,7 @@ Installing Dependencies
sudo dnf install git autoconf automake libtool make \
readline-devel texinfo net-snmp-devel groff pkgconfig json-c-devel \
pam-devel python3-pytest bison flex c-ares-devel python3-devel \
- python3-sphinx perl-core patch systemd-devel
+ python3-sphinx perl-core patch systemd-devel libcap-devel
.. include:: building-libyang.rst
diff --git a/doc/developer/building-frr-for-ubuntu1404.rst b/doc/developer/building-frr-for-ubuntu1404.rst
index 569b3bded1..cc54415266 100644
--- a/doc/developer/building-frr-for-ubuntu1404.rst
+++ b/doc/developer/building-frr-for-ubuntu1404.rst
@@ -14,7 +14,7 @@ Installing Dependencies
git autoconf automake libtool make libreadline-dev texinfo \
pkg-config libpam0g-dev libjson-c-dev bison flex python3-pytest \
libc-ares-dev python3-dev python3-sphinx install-info build-essential \
- libsnmp-dev perl
+ libsnmp-dev perl libcap-dev
.. include:: building-libyang.rst
diff --git a/doc/developer/building-frr-for-ubuntu1604.rst b/doc/developer/building-frr-for-ubuntu1604.rst
index 03852a62aa..63c6f8648c 100644
--- a/doc/developer/building-frr-for-ubuntu1604.rst
+++ b/doc/developer/building-frr-for-ubuntu1604.rst
@@ -14,7 +14,7 @@ Installing Dependencies
git autoconf automake libtool make libreadline-dev texinfo \
pkg-config libpam0g-dev libjson-c-dev bison flex python3-pytest \
libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \
- install-info build-essential libsystemd-dev libsnmp-dev perl
+ install-info build-essential libsystemd-dev libsnmp-dev perl libcap-dev
.. include:: building-libyang.rst
diff --git a/doc/developer/building-frr-for-ubuntu1804.rst b/doc/developer/building-frr-for-ubuntu1804.rst
index 96c0efe02a..9d85957d88 100644
--- a/doc/developer/building-frr-for-ubuntu1804.rst
+++ b/doc/developer/building-frr-for-ubuntu1804.rst
@@ -14,7 +14,7 @@ Installing Dependencies
git autoconf automake libtool make libreadline-dev texinfo \
pkg-config libpam0g-dev libjson-c-dev bison flex python3-pytest \
libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \
- install-info build-essential libsystemd-dev libsnmp-dev perl
+ install-info build-essential libsystemd-dev libsnmp-dev perl libcap-dev
.. include:: building-libyang.rst
diff --git a/doc/developer/cli.rst b/doc/developer/cli.rst
index c0716a5c93..cf35b03f0c 100644
--- a/doc/developer/cli.rst
+++ b/doc/developer/cli.rst
@@ -160,27 +160,27 @@ parser, but this is merely a dumb copy job.
Here is a brief summary of the various token types along with examples.
-+-----------------+-----------------+-------------------------------------------------------------+
-| Token type | Syntax | Description |
-+=================+=================+=============================================================+
-| ``WORD`` | ``show ip bgp`` | Matches itself. In the given example every token is a WORD. |
-+-----------------+-----------------+-------------------------------------------------------------+
-| ``IPV4`` | ``A.B.C.D`` | Matches an IPv4 address. |
-+-----------------+-----------------+-------------------------------------------------------------+
-| ``IPV6`` | ``X:X::X:X`` | Matches an IPv6 address. |
-+-----------------+-----------------+-------------------------------------------------------------+
-| ``IPV4_PREFIX`` | ``A.B.C.D/M`` | Matches an IPv4 prefix in CIDR notation. |
-+-----------------+-----------------+-------------------------------------------------------------+
-| ``IPV6_PREFIX`` | ``X:X::X:X/M`` | Matches an IPv6 prefix in CIDR notation. |
-+-----------------+-----------------+-------------------------------------------------------------+
-| ``MAC`` | ``M:A:C`` | Matches a 48-bit mac address. |
-+-----------------+-----------------+-------------------------------------------------------------+
-| ``MAC_PREFIX`` | ``M:A:C/M`` | Matches a 48-bit mac address with a mask. |
-+-----------------+-----------------+-------------------------------------------------------------+
-| ``VARIABLE`` | ``FOOBAR`` | Matches anything. |
-+-----------------+-----------------+-------------------------------------------------------------+
-| ``RANGE`` | ``(X-Y)`` | Matches numbers in the range X..Y inclusive. |
-+-----------------+-----------------+-------------------------------------------------------------+
++-----------------+-------------------+-------------------------------------------------------------+
+| Token type | Syntax | Description |
++=================+===================+=============================================================+
+| ``WORD`` | ``show ip bgp`` | Matches itself. In the given example every token is a WORD. |
++-----------------+-------------------+-------------------------------------------------------------+
+| ``IPV4`` | ``A.B.C.D`` | Matches an IPv4 address. |
++-----------------+-------------------+-------------------------------------------------------------+
+| ``IPV6`` | ``X:X::X:X`` | Matches an IPv6 address. |
++-----------------+-------------------+-------------------------------------------------------------+
+| ``IPV4_PREFIX`` | ``A.B.C.D/M`` | Matches an IPv4 prefix in CIDR notation. |
++-----------------+-------------------+-------------------------------------------------------------+
+| ``IPV6_PREFIX`` | ``X:X::X:X/M`` | Matches an IPv6 prefix in CIDR notation. |
++-----------------+-------------------+-------------------------------------------------------------+
+| ``MAC`` | ``X:X:X:X:X:X`` | Matches a 48-bit mac address. |
++-----------------+-------------------+-------------------------------------------------------------+
+| ``MAC_PREFIX`` | ``X:X:X:X:X:X/M`` | Matches a 48-bit mac address with a mask. |
++-----------------+-------------------+-------------------------------------------------------------+
+| ``VARIABLE`` | ``FOOBAR`` | Matches anything. |
++-----------------+-------------------+-------------------------------------------------------------+
+| ``RANGE`` | ``(X-Y)`` | Matches numbers in the range X..Y inclusive. |
++-----------------+-------------------+-------------------------------------------------------------+
When presented with user input, the parser will search over all defined
commands in the current context to find a match. It is aware of the various
diff --git a/doc/developer/library.rst b/doc/developer/library.rst
index 4ba0c0ebc6..7cd493ccc4 100644
--- a/doc/developer/library.rst
+++ b/doc/developer/library.rst
@@ -8,6 +8,7 @@ Library Facilities (libfrr)
:maxdepth: 2
memtypes
+ rcu
lists
logging
hooks
diff --git a/doc/developer/lists.rst b/doc/developer/lists.rst
index fc47a67e42..5f020060ce 100644
--- a/doc/developer/lists.rst
+++ b/doc/developer/lists.rst
@@ -611,6 +611,38 @@ Head removal (pop) and deallocation:
* note nothing between wrlock() and unlock() */
XFREE(MTYPE_ITEM, i);
+FAQ
+---
+
+Why is the list head not ``const`` in the list APIs?
+ The semantics that a ``const`` list head would imply are not obvious. It
+ could mean any of the following:
+
+ * the list just shouldn't be allocated/deallocated, but may be modified.
+ This doesn't actually work since the list head needs to be modified for
+ inserting or deleting items.
+
+ * the list shouldn't be modified, but items can. This may make sense for
+ iterating, but it's not exactly consistent - an item might be on more
+ than one list, does it apply to all of them? If not, which one?
+
+ * neither the list nor the items should be modified. This is consistent,
+ but hard to do without creating a ``const`` copy of every single list
+ function. Ease of use trumps this.
+
+Why is there no "is this item on a/the list" test?
+ It's slow for several of the data structures, and the work of adding it
+ just hasn't been done. It can certainly be added if it's needed.
+
+Why is it ``PREDECL`` + ``DECLARE`` instead of ``DECLARE`` + ``DEFINE``?
+ The rule is that a ``DEFINE`` must be in a ``.c`` file, and linked exactly
+ once because it defines some kind of global symbol. This is not the case
+ for the data structure macros; they only define ``static`` symbols and it
+ is perfectly fine to include both ``PREDECL`` and ``DECLARE`` in a header
+ file. It is also perfectly fine to have the same ``DECLARE`` statement in
+ 2 ``.c`` files, but only **if the macro arguments are identical.** Maybe
+ don't do that unless you really need it.
+
FRR lists
---------
diff --git a/doc/developer/rcu.rst b/doc/developer/rcu.rst
new file mode 100644
index 0000000000..c2ddf93f53
--- /dev/null
+++ b/doc/developer/rcu.rst
@@ -0,0 +1,269 @@
+.. highlight:: c
+
+RCU
+===
+
+Introduction
+------------
+
+RCU (Read-Copy-Update) is, fundamentally, a paradigm of multithreaded
+operation (and not a set of APIs.) The core ideas are:
+
+* longer, complicated updates to structures are made only on private,
+ "invisible" copies. Other threads, when they access the structure, see an
+ older (but consistent) copy.
+
+* once done, the updated copy is swapped in in a single operation so that
+ other threads see either the old or the new data but no inconsistent state
+ between.
+
+* the old instance is only released after making sure that it is impossible
+ any other thread might still be reading it.
+
+For more information, please search for general or Linux kernel RCU
+documentation; there is no way this doc can be comprehensive in explaining the
+interactions:
+
+* https://en.wikipedia.org/wiki/Read-copy-update
+* https://www.kernel.org/doc/html/latest/kernel-hacking/locking.html#avoiding-locks-read-copy-update
+* https://lwn.net/Articles/262464/
+* http://www.rdrop.com/users/paulmck/RCU/rclock_OLS.2001.05.01c.pdf
+* http://lse.sourceforge.net/locking/rcupdate.html
+
+RCU, the TL;DR
+^^^^^^^^^^^^^^
+
+#. data structures are always consistent for reading. That's the "R" part.
+#. reading never blocks / takes a lock.
+#. rcu_read_lock is not a lock in the traditional sense. Think of it as a
+ "reservation"; it notes what the *oldest* possible thing the thread might
+ be seeing is, and which thus can't be deleted yet.
+#. you create some object, finish it up, and then publish it.
+#. publishing is an ``atomic_*`` call with ``memory_order_release``, which
+ tells the compiler to make sure prior memory writes have completed before
+ doing the atomic op.
+#. ``ATOMLIST_*`` ``add`` operations do the ``memory_order_release`` for you.
+#. you can't touch the object after it is published, except with atomic ops.
+#. because you can't touch it, if you want to change it you make a new copy,
+ work on that, and then publish the new copy. That's the "CU" part.
+#. deleting the object is also an atomic op.
+#. other threads that started working before you published / deleted an object
+ might not see the new object / still see the deleted object.
+#. because other threads may still see deleted objects, the ``free()`` needs
+ to be delayed. That's what :c:func:`rcu_free()` is for.
+
+
+When (not) to use RCU
+^^^^^^^^^^^^^^^^^^^^^
+
+RCU is designed for read-heavy workloads where objects are updated relatively
+rarely, but frequently accessed. Do *not* indiscriminately replace locking by
+RCU patterns.
+
+The "copy" part of RCU implies that, while updating, several copies of a given
+object exist in parallel. Even after the updated copy is swapped in, the old
+object remains queued for freeing until all other threads are guaranteed to
+not be accessing it anymore, due to passing a sequence point. In addition to
+the increased memory usage, there may be some bursted (due to batching) malloc
+contention when the RCU cleanup thread does its thing and frees memory.
+
+Other useful patterns
+^^^^^^^^^^^^^^^^^^^^^
+
+In addition to the full "copy object, apply changes, atomically update"
+approach, there are 2 "reduced" usage cases that can be done:
+
+* atomically updating single pieces of a particular object, e.g. some flags
+ or configuration piece
+
+* straight up read-only / immutable objects
+
+Both of these cases can be considered RCU "subsets". For example, when
+maintaining an atomic list of items, but these items only have a single
+integer value that needs to be updated, that value can be atomically updated
+without copying the entire object. However, the object still needs to be
+free'd through :c:func:`rcu_free()` since reading/updating and deleting might
+be happening concurrently. The same applies for immutable objects; deletion
+might still race with reading so they need to be free'd through RCU.
+
+FRR API
+-------
+
+Before diving into detail on the provided functions, it is important to note
+that the FRR RCU API covers the **cleanup part of RCU, not the read-copy-update
+paradigm itself**. These parts are handled by standard C11 atomic operations,
+and by extension through the atomic data structures (ATOMLIST, ATOMSORT & co.)
+
+The ``rcu_*`` functions only make sense in conjunction with these RCU access
+patterns. If you're calling the RCU API but not using these, something is
+wrong. The other way around is not necessarily true; it is possible to use
+atomic ops & datastructures with other types of locking, e.g. rwlocks.
+
+.. c:function:: void rcu_read_lock()
+.. c:function:: void rcu_read_unlock()
+
+ These functions acquire / release the RCU read-side lock. All access to
+ RCU-guarded data must be inside a block guarded by these. Any number of
+ threads may hold the RCU read-side lock at a given point in time, including
+ both no threads at all and all threads.
+
+ The functions implement a depth counter, i.e. can be nested. The nested
+ calls are cheap, since they only increment/decrement the counter.
+ Therefore, any place that uses RCU data and doesn't have a guarantee that
+ the caller holds RCU (e.g. ``lib/`` code) should just have its own
+ rcu_read_lock/rcu_read_unlock pair.
+
+ At the "root" level (e.g. un-nested), these calls can incur the cost of one
+ syscall (to ``futex()``). That puts them on about the same cost as a
+ mutex lock/unlock.
+
+ The ``thread_master`` code currently always holds RCU everywhere, except
+ while doing the actual ``poll()`` syscall. This is both an optimization as
+ well as an "easement" into getting RCU going. The current implementation
+ contract is that any ``struct thread *`` callback is called with a RCU
+ holding depth of 1, and that this is owned by the thread so it may (should)
+ drop and reacquire it when doing some longer-running work.
+
+ .. warning::
+
+ The RCU read-side lock must be held **continuously** for the entire time
+ any piece of RCU data is used. This includes any access to RCU data
+ after the initial ``atomic_load``. If the RCU read-side lock is
+ released, any RCU-protected pointers as well as the data they refer to
+ become invalid, as another thread may have called :c:func:`rcu_free` on
+ them.
+
+.. c:type:: struct rcu_head
+.. c:type:: struct rcu_head_close
+.. c:type:: struct rcu_action
+
+ The ``rcu_head`` structures are small (16-byte) bits that contain the
+ queueing machinery for the RCU sweeper/cleanup mechanisms.
+
+ Any piece of data that is cleaned up by RCU needs to have a matching
+ ``rcu_head`` embedded in it. If there is more than one cleanup operation
+ to be done (e.g. closing a file descriptor), more than one ``rcu_head`` may
+ be embedded.
+
+ .. warning::
+
+ It is not possible to reuse a ``rcu_head``. It is owned by the RCU code
+ as soon as ``rcu_*`` is called on it.
+
+ The ``_close`` variant carries an extra ``int fd`` field to store the fd to
+ be closed.
+
+ To minimize the amount of memory used for ``rcu_head``, details about the
+ RCU operation to be performed are moved into the ``rcu_action`` structure.
+ It contains e.g. the MTYPE for :c:func:`rcu_free` calls. The pointer to be
+ freed is stored as an offset relative to the ``rcu_head``, which means it
+ must be embedded as a struct field so the offset is constant.
+
+ The ``rcu_action`` structure is an implementation detail. Using
+ ``rcu_free`` or ``rcu_close`` will set it up correctly without further
+ code needed.
+
+ The ``rcu_head`` may be put in an union with other data if the other data
+ is only used during "life" of the data, since the ``rcu_head`` is used only
+ for the "death" of data. But note that other threads may still be reading
+ a piece of data while a thread is working to free it.
+
+.. c:function:: void rcu_free(struct memtype *mtype, struct X *ptr, field)
+
+ Free a block of memory after RCU has ensured no other thread can be
+ accessing it anymore. The pointer remains valid for any other thread that
+ has called :c:func:`rcu_read_lock` before the ``rcu_free`` call.
+
+ .. warning::
+
+ In some other RCU implementations, the pointer remains valid to the
+ *calling* thread if it is holding the RCU read-side lock. This is not
+ the case in FRR, particularly when running single-threaded. Enforcing
+ this rule also allows static analysis to find use-after-free issues.
+
+ ``mtype`` is the libfrr ``MTYPE_FOO`` allocation type to pass to
+ :c:func:`XFREE`.
+
+ ``field`` must be the name of a ``struct rcu_head`` member field in ``ptr``.
+ The offset of this field (which must be constant) is used to reduce the
+ memory size of ``struct rcu_head``.
+
+ .. note::
+
+ ``rcu_free`` (and ``rcu_close``) calls are more efficient if they are
+ put close to each other. When freeing several RCU'd resources, try to
+ move the calls next to each other (even if the data structures do not
+ directly point to each other.)
+
+ Having the calls bundled reduces the cost of adding the ``rcu_head`` to
+ the RCU queue; the RCU queue is an atomic data structure whose usage
+ will require the CPU to acquire an exclusive hold on relevant cache
+ lines.
+
+.. c:function:: void rcu_close(struct rcu_head_close *head, int fd)
+
+ Close a file descriptor after ensuring no other thread might be using it
+ anymore. Same as :c:func:`rcu_free`, except it calls ``close`` instead of
+ ``free``.
+
+Internals
+^^^^^^^^^
+
+.. c:type:: struct rcu_thread
+
+ Per-thread state maintained by the RCU code, set up by the following
+ functions. A pointer to a thread's own ``rcu_thread`` is saved in
+ thread-local storage.
+
+.. c:function:: struct rcu_thread *rcu_thread_prepare(void)
+.. c:function:: void rcu_thread_unprepare(struct rcu_thread *rcu_thread)
+.. c:function:: void rcu_thread_start(struct rcu_thread *rcu_thread)
+
+ Since the RCU code needs to have a list of all active threads, these
+ functions are used by the ``frr_pthread`` code to set up threads. Teardown
+ is automatic. It should not be necessary to call these functions.
+
+ Any thread that accesses RCU-protected data needs to be registered with
+ these functions. Threads that do not access RCU-protected data may call
+ these functions but do not need to.
+
+ Note that passing a pointer to RCU-protected data to some library which
+ accesses that pointer makes the library "access RCU-protected data". In
+ that case, either all of the library's threads must be registered for RCU,
+ or the code must instead pass a (non-RCU) copy of the data to the library.
+
+.. c:function:: void rcu_shutdown(void)
+
+ Stop the RCU sweeper thread and make sure all cleanup has finished.
+
+ This function is called on daemon exit by the libfrr code to ensure pending
+ RCU operations are completed. This is mostly to get a clean exit without
+ memory leaks from queued RCU operations. It should not be necessary to
+ call this function as libfrr handles this.
+
+FRR specifics and implementation details
+----------------------------------------
+
+The FRR RCU infrastructure has the following characteristics:
+
+* it is Epoch-based with a 32-bit wrapping counter. (This is somewhat
+ different from other Epoch-based approaches which may be designed to only
+ use 3 counter values, but works out to a simple implementation.)
+
+* instead of tracking CPUs as the Linux kernel does, threads are tracked. This
+ has exactly zero semantic impact, RCU just cares about "threads of
+ execution", which the kernel can optimize to CPUs but we can't. But it
+ really boils down to the same thing.
+
+* there are no ``rcu_dereference`` and ``rcu_assign_pointer`` - use
+ ``atomic_load`` and ``atomic_store`` instead. (These didn't exist when the
+ Linux RCU code was created.)
+
+* there is no ``synchronize_rcu``; this is a design choice but may be revisited
+ at a later point. ``synchronize_rcu`` blocks a thread until it is guaranteed
+ that no other threads might still be accessing data structures that they may
+ have access to at the beginning of the function call. This is a blocking
+ design and probably not appropriate for FRR. Instead, ``rcu_call`` can be
+ used to have the RCU sweeper thread make a callback after the same constraint
+ is fulfilled in an asynchronous way. Most needs should be covered by
+ ``rcu_free`` and ``rcu_close``.
diff --git a/doc/developer/subdir.am b/doc/developer/subdir.am
index 996f12d47f..1fc593e566 100644
--- a/doc/developer/subdir.am
+++ b/doc/developer/subdir.am
@@ -42,6 +42,7 @@ dev_RSTFILES = \
doc/developer/packaging-debian.rst \
doc/developer/packaging-redhat.rst \
doc/developer/packaging.rst \
+ doc/developer/rcu.rst \
doc/developer/testing.rst \
doc/developer/topotests-snippets.rst \
doc/developer/topotests.rst \
diff --git a/doc/figures/nodes.dot b/doc/figures/nodes.dot
index d0e234958f..b548b5529a 100644
--- a/doc/figures/nodes.dot
+++ b/doc/figures/nodes.dot
@@ -55,7 +55,6 @@ digraph climodes {
CONFIG_NODE -> KEYCHAIN_KEY_NODE [ label="key (0-2147483647)" ];
KEYCHAIN_NODE -> KEYCHAIN_KEY_NODE [ label="key (0-2147483647)" ];
KEYCHAIN_KEY_NODE -> KEYCHAIN_NODE [ label="no key (0-2147483647)" ];
- CONFIG_NODE -> LOGICALROUTER_NODE [ label="logical-router (1-65535) ns NAME" ];
CONFIG_NODE -> VRF_NODE [ label="vrf NAME" ];
CONFIG_NODE -> INTERFACE_NODE [ label="interface IFNAME vrf NAME" ];
INTERFACE_NODE -> LINK_PARAMS_NODE [ label="link-params" ];
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index f2b1328075..c329ab6d9f 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -2138,20 +2138,40 @@ Dumping Messages and Routing Tables
Other BGP Commands
------------------
+.. index:: clear bgp \*
+.. clicmd:: clear bgp \*
+
+ Clear all peers.
+
.. index:: clear bgp ipv4|ipv6 \*
.. clicmd:: clear bgp ipv4|ipv6 \*
- Clear all address family peers.
+ Clear all peers with this address-family activated.
+
+.. index:: clear bgp ipv4|ipv6 unicast \*
+.. clicmd:: clear bgp ipv4|ipv6 unicast \*
+
+ Clear all peers with this address-family and sub-address-family activated.
.. index:: clear bgp ipv4|ipv6 PEER
.. clicmd:: clear bgp ipv4|ipv6 PEER
- Clear peers which have addresses of X.X.X.X
+ Clear peers with address of X.X.X.X and this address-family activated.
+
+.. index:: clear bgp ipv4|ipv6 unicast PEER
+.. clicmd:: clear bgp ipv4|ipv6 unicast PEER
+
+ Clear peer with address of X.X.X.X and this address-family and sub-address-family activated.
+
+.. index:: clear bgp ipv4|ipv6 PEER soft|in|out
+.. clicmd:: clear bgp ipv4|ipv6 PEER soft|in|out
+
+ Clear peer using soft reconfiguration in this address-family.
-.. index:: clear bgp ipv4|ipv6 PEER soft in
-.. clicmd:: clear bgp ipv4|ipv6 PEER soft in
+.. index:: clear bgp ipv4|ipv6 unicast PEER soft|in|out
+.. clicmd:: clear bgp ipv4|ipv6 unicast PEER soft|in|out
- Clear peer using soft reconfiguration.
+ Clear peer using soft reconfiguration in this address-family and sub-address-family.
.. _bgp-displaying-bgp-information:
diff --git a/doc/user/installation.rst b/doc/user/installation.rst
index b45c83ca1c..45549dccad 100644
--- a/doc/user/installation.rst
+++ b/doc/user/installation.rst
@@ -149,6 +149,11 @@ options from the list below.
Turn off building of pimd. On some BSD platforms pimd will not build properly due
to lack of kernel support.
+.. option:: --disable-vrrpd
+
+ Turn off building of vrrpd. Linux is required for vrrpd support;
+ other platforms are not supported.
+
.. option:: --disable-pbrd
Turn off building of pbrd. This daemon currently requires linux in order to function
@@ -194,11 +199,6 @@ options from the list below.
Disable building of the example OSPF-API client.
-.. option:: --disable-ospf-ri
-
- Disable support for OSPF Router Information (RFC4970 & RFC5088) this
- requires support for Opaque LSAs and Traffic Engineering.
-
.. option:: --disable-isisd
Do not build isisd.
@@ -211,10 +211,6 @@ options from the list below.
Enable IS-IS topology generator.
-.. option:: --enable-isis-te
-
- Enable Traffic Engineering Extension for ISIS (RFC5305)
-
.. option:: --enable-realms
Enable the support of Linux Realms. Convert tag values from 1-255 into a
diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst
index f7607a54f7..6684a83e1f 100644
--- a/doc/user/isisd.rst
+++ b/doc/user/isisd.rst
@@ -423,6 +423,12 @@ Showing ISIS information
Traffic Engineering
===================
+.. note::
+
+ At this time, FRR offers partial support for some of the routing
+ protocol extensions that can be used with MPLS-TE. FRR does not
+ support a complete RSVP-TE solution currently.
+
.. index:: mpls-te on
.. clicmd:: mpls-te on
diff --git a/doc/user/ospf6d.rst b/doc/user/ospf6d.rst
index 6413c62995..2300cb0e19 100644
--- a/doc/user/ospf6d.rst
+++ b/doc/user/ospf6d.rst
@@ -195,7 +195,7 @@ Example of ospf6d configured on one interface and area:
ipv6 ospf6 instance-id 0
!
router ospf6
- router-id 212.17.55.53
+ ospf6 router-id 212.17.55.53
area 0.0.0.0 range 2001:770:105:2::/64
interface eth0 area 0.0.0.0
!
diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst
index 83e14d474f..3772cf9556 100644
--- a/doc/user/ospfd.rst
+++ b/doc/user/ospfd.rst
@@ -69,7 +69,7 @@ The instance number should be specified in the config when addressing a particul
.. code-block:: frr
router ospf 5
- router-id 1.2.3.4
+ ospf router-id 1.2.3.4
area 0.0.0.0 authentication message-digest
...
@@ -906,10 +906,13 @@ Opaque LSA
.. index:: no capability opaque
.. clicmd:: no capability opaque
- *ospfd* supports Opaque LSA (:rfc:`2370`) as fundamental for MPLS Traffic
- Engineering LSA. Prior to used MPLS TE, opaque-lsa must be enable in the
- configuration file. Alternate command could be "mpls-te on"
- (:ref:`ospf-traffic-engineering`).
+ *ospfd* supports Opaque LSA (:rfc:`2370`) as partial support for
+ MPLS Traffic Engineering LSAs. The opaque-lsa capability must be
+ enabled in the configuration. An alternate command could be
+ "mpls-te on" (:ref:`ospf-traffic-engineering`). Note that FRR
+ offers only partial support for some of the routing protocol
+ extensions that are used with MPLS-TE; it does not support a
+ complete RSVP-TE solution.
.. index:: show ip ospf database (opaque-link|opaque-area|opaque-external)
.. clicmd:: show ip ospf database (opaque-link|opaque-area|opaque-external)
@@ -936,6 +939,12 @@ Opaque LSA
Traffic Engineering
===================
+.. note::
+
+ At this time, FRR offers partial support for some of the routing
+ protocol extensions that can be used with MPLS-TE. FRR does not
+ support a complete RSVP-TE solution currently.
+
.. index:: mpls-te on
.. clicmd:: mpls-te on
diff --git a/doc/user/overview.rst b/doc/user/overview.rst
index 7f8ea392dc..5f9a7b937e 100644
--- a/doc/user/overview.rst
+++ b/doc/user/overview.rst
@@ -239,6 +239,15 @@ The indicators have the following semantics:
* :mark:`CP` - control plane only (i.e. BGP route server / route reflector)
* :mark:`N` - daemon/feature not supported by operating system
+
+Known Kernel Issues:
+====================
+
+- Linux
+ v6 Route Replacement - Linux kernels before 4.11 can cause issues with v6 route deletion when you
+ have ecmp routes installed into the kernel. This especially becomes apparent if the route is being
+ transformed from one ecmp path to another.
+
.. _supported-rfcs:
Supported RFCs
diff --git a/doc/user/routemap.rst b/doc/user/routemap.rst
index bac61cbc58..09cbd7c7b0 100644
--- a/doc/user/routemap.rst
+++ b/doc/user/routemap.rst
@@ -153,8 +153,8 @@ Route Map Match Command
Matches the specified `ipv4_addr`.
-.. index:: match aspath AS_PATH
-.. clicmd:: match aspath AS_PATH
+.. index:: match as-path AS_PATH
+.. clicmd:: match as-path AS_PATH
Matches the specified `as_path`.
diff --git a/doc/user/sharp.rst b/doc/user/sharp.rst
index 4568c2a901..111e9dc9e8 100644
--- a/doc/user/sharp.rst
+++ b/doc/user/sharp.rst
@@ -71,7 +71,7 @@ keyword. At present, no sharp commands will be preserved in the config.
be used for pop and forward operations when the specified label is seen.
.. index:: sharp watch
-.. clicmd:: [no] sharp watch <nexthop|import> <A.B.C.D|X:X::X:X> [connected]
+.. clicmd:: [no] sharp watch <nexthop <A.B.C.D|X:X::X:X>|import <A.B.C.D/M:X:X::X:X/M> [connected]
Instruct zebra to monitor and notify sharp when the specified nexthop is
changed. The notification from zebra is written into the debug log.
diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst
index eefc5802a2..50c518d456 100644
--- a/doc/user/zebra.rst
+++ b/doc/user/zebra.rst
@@ -193,18 +193,25 @@ Standard Commands
Link Parameters Commands
------------------------
+.. note::
+
+ At this time, FRR offers partial support for some of the routing
+ protocol extensions that can be used with MPLS-TE. FRR does not
+ support a complete RSVP-TE solution currently.
+
.. index:: link-params
.. clicmd:: link-params
.. index:: no link-param
.. clicmd:: no link-param
- Enter into the link parameters sub node. At least 'enable' must be set to
- activate the link parameters, and consequently Traffic Engineering on this
- interface. MPLS-TE must be enable at the OSPF
- (:ref:`ospf-traffic-engineering`) or ISIS (:ref:`isis-traffic-engineering`)
- router level in complement to this. Disable link parameters for this
- interface.
+ Enter into the link parameters sub node. At least 'enable' must be
+ set to activate the link parameters, and consequently routing
+ information that could be used as part of Traffic Engineering on
+ this interface. MPLS-TE must be enable at the OSPF
+ (:ref:`ospf-traffic-engineering`) or ISIS
+ (:ref:`isis-traffic-engineering`) router level in complement to
+ this. Disable link parameters for this interface.
Under link parameter statement, the following commands set the different TE values:
@@ -361,6 +368,12 @@ commands in relationship to VRF. Here is an extract of some of those commands:
will dump the routing table ``TABLENO`` of the *Linux network namespace*
``VRF``.
+.. index:: show ip route vrf VRF tables
+.. clicmd:: show ip route vrf VRF tables
+
+ This command will dump the routing tables within the vrf scope. If `vrf all`
+ is executed, all routing tables will be dumped.
+
By using the :option:`-n` option, the *Linux network namespace* will be mapped
over the *Zebra* VRF. One nice feature that is possible by handling *Linux
network namespace* is the ability to name default VRF. At startup, *Zebra*
diff --git a/eigrpd/eigrp_cli.c b/eigrpd/eigrp_cli.c
new file mode 100644
index 0000000000..ba657a7d5d
--- /dev/null
+++ b/eigrpd/eigrp_cli.c
@@ -0,0 +1,920 @@
+/*
+ * EIGRP daemon CLI implementation.
+ *
+ * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF")
+ * Rafael Zalamena
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <zebra.h>
+
+#include "lib/command.h"
+#include "lib/log.h"
+#include "lib/northbound_cli.h"
+
+#include "eigrp_structs.h"
+#include "eigrpd.h"
+#include "eigrp_zebra.h"
+
+#ifndef VTYSH_EXTRACT_PL
+#include "eigrpd/eigrp_cli_clippy.c"
+#endif /* VTYSH_EXTRACT_PL */
+
+/*
+ * XPath: /frr-eigrpd:eigrpd/instance
+ */
+DEFPY_NOSH(
+ router_eigrp,
+ router_eigrp_cmd,
+ "router eigrp (1-65535)$as",
+ ROUTER_STR
+ EIGRP_STR
+ AS_STR)
+{
+ char xpath[XPATH_MAXLEN];
+ int rv;
+
+ snprintf(xpath, sizeof(xpath),
+ "/frr-eigrpd:eigrpd/instance[asn='%s'][vrf='']",
+ as_str);
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ rv = nb_cli_apply_changes(vty, NULL);
+ if (rv == CMD_SUCCESS)
+ VTY_PUSH_XPATH(EIGRP_NODE, xpath);
+
+ return rv;
+}
+
+DEFPY_NOSH(
+ no_router_eigrp,
+ no_router_eigrp_cmd,
+ "no router eigrp (1-65535)$as",
+ NO_STR
+ ROUTER_STR
+ EIGRP_STR
+ AS_STR)
+{
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath),
+ "/frr-eigrpd:eigrpd/instance[asn='%s'][vrf='']",
+ as_str);
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void eigrp_cli_show_header(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ const char *asn = yang_dnode_get_string(dnode, "./asn");
+
+ vty_out(vty, "router eigrp %s\n", asn);
+}
+
+void eigrp_cli_show_end_header(struct vty *vty, struct lyd_node *dnode)
+{
+ vty_out(vty, "!\n");
+}
+
+/*
+ * XPath: /frr-eigrpd:eigrpd/instance/router-id
+ */
+DEFPY(
+ eigrp_router_id,
+ eigrp_router_id_cmd,
+ "eigrp router-id A.B.C.D$addr",
+ EIGRP_STR
+ "Router ID for this EIGRP process\n"
+ "EIGRP Router-ID in IP address format\n")
+{
+ nb_cli_enqueue_change(vty, "./router-id", NB_OP_MODIFY, addr_str);
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_eigrp_router_id,
+ no_eigrp_router_id_cmd,
+ "no eigrp router-id [A.B.C.D]",
+ NO_STR
+ EIGRP_STR
+ "Router ID for this EIGRP process\n"
+ "EIGRP Router-ID in IP address format\n")
+{
+ nb_cli_enqueue_change(vty, "./router-id", NB_OP_DESTROY, NULL);
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void eigrp_cli_show_router_id(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ const char *router_id = yang_dnode_get_string(dnode, NULL);
+
+ vty_out(vty, " eigrp router-id %s\n", router_id);
+}
+
+/*
+ * XPath: /frr-eigrpd:eigrpd/instance/passive-interface
+ */
+DEFPY(
+ eigrp_passive_interface,
+ eigrp_passive_interface_cmd,
+ "[no] passive-interface IFNAME",
+ NO_STR
+ "Suppress routing updates on an interface\n"
+ "Interface to suppress on\n")
+{
+ if (no)
+ nb_cli_enqueue_change(vty, "./passive-interface",
+ NB_OP_DESTROY, ifname);
+ else
+ nb_cli_enqueue_change(vty, "./passive-interface",
+ NB_OP_CREATE, ifname);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void eigrp_cli_show_passive_interface(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ const char *ifname = yang_dnode_get_string(dnode, NULL);
+
+ vty_out(vty, " passive-interface %s\n", ifname);
+}
+
+/*
+ * XPath: /frr-eigrpd:eigrpd/instance/active-time
+ */
+DEFPY(
+ eigrp_timers_active,
+ eigrp_timers_active_cmd,
+ "timers active-time <(1-65535)$timer|disabled$disabled>",
+ "Adjust routing timers\n"
+ "Time limit for active state\n"
+ "Active state time limit in seconds\n"
+ "Disable time limit for active state\n")
+{
+ if (disabled)
+ nb_cli_enqueue_change(vty, "./active-time", NB_OP_MODIFY, "0");
+ else
+ nb_cli_enqueue_change(vty, "./active-time",
+ NB_OP_MODIFY, timer_str);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_eigrp_timers_active,
+ no_eigrp_timers_active_cmd,
+ "no timers active-time [<(1-65535)|disabled>]",
+ NO_STR
+ "Adjust routing timers\n"
+ "Time limit for active state\n"
+ "Active state time limit in seconds\n"
+ "Disable time limit for active state\n")
+{
+ nb_cli_enqueue_change(vty, "./active-time", NB_OP_DESTROY, NULL);
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void eigrp_cli_show_active_time(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ const char *timer = yang_dnode_get_string(dnode, NULL);
+
+ vty_out(vty, " timers active-time %s\n", timer);
+}
+
+/*
+ * XPath: /frr-eigrpd:eigrpd/instance/variance
+ */
+DEFPY(
+ eigrp_variance,
+ eigrp_variance_cmd,
+ "variance (1-128)$variance",
+ "Control load balancing variance\n"
+ "Metric variance multiplier\n")
+{
+ nb_cli_enqueue_change(vty, "./variance", NB_OP_MODIFY, variance_str);
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_eigrp_variance,
+ no_eigrp_variance_cmd,
+ "no variance [(1-128)]",
+ NO_STR
+ "Control load balancing variance\n"
+ "Metric variance multiplier\n")
+{
+ nb_cli_enqueue_change(vty, "./variance", NB_OP_DESTROY, NULL);
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void eigrp_cli_show_variance(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ const char *variance = yang_dnode_get_string(dnode, NULL);
+
+ vty_out(vty, " variance %s\n", variance);
+}
+
+/*
+ * XPath: /frr-eigrpd:eigrpd/instance/maximum-paths
+ */
+DEFPY(
+ eigrp_maximum_paths,
+ eigrp_maximum_paths_cmd,
+ "maximum-paths (1-32)$maximum_paths",
+ "Forward packets over multiple paths\n"
+ "Number of paths\n")
+{
+ nb_cli_enqueue_change(vty, "./maximum-paths", NB_OP_MODIFY,
+ maximum_paths_str);
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_eigrp_maximum_paths,
+ no_eigrp_maximum_paths_cmd,
+ "no maximum-paths [(1-32)]",
+ NO_STR
+ "Forward packets over multiple paths\n"
+ "Number of paths\n")
+{
+ nb_cli_enqueue_change(vty, "./maximum-paths", NB_OP_DESTROY, NULL);
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void eigrp_cli_show_maximum_paths(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ const char *maximum_paths = yang_dnode_get_string(dnode, NULL);
+
+ vty_out(vty, " maximum-paths %s\n", maximum_paths);
+}
+
+/*
+ * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K1
+ * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K2
+ * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K3
+ * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K4
+ * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K5
+ * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K6
+ */
+DEFPY(
+ eigrp_metric_weights,
+ eigrp_metric_weights_cmd,
+ "metric weights (0-255)$k1 (0-255)$k2 (0-255)$k3 (0-255)$k4 (0-255)$k5 [(0-255)$k6]",
+ "Modify metrics and parameters for advertisement\n"
+ "Modify metric coefficients\n"
+ "K1\n"
+ "K2\n"
+ "K3\n"
+ "K4\n"
+ "K5\n"
+ "K6\n")
+{
+ nb_cli_enqueue_change(vty, "./metric-weights/K1", NB_OP_MODIFY, k1_str);
+ nb_cli_enqueue_change(vty, "./metric-weights/K2", NB_OP_MODIFY, k2_str);
+ nb_cli_enqueue_change(vty, "./metric-weights/K3", NB_OP_MODIFY, k3_str);
+ nb_cli_enqueue_change(vty, "./metric-weights/K4", NB_OP_MODIFY, k4_str);
+ nb_cli_enqueue_change(vty, "./metric-weights/K5", NB_OP_MODIFY, k5_str);
+ if (k6)
+ nb_cli_enqueue_change(vty, "./metric-weights/K6",
+ NB_OP_MODIFY, k6_str);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_eigrp_metric_weights,
+ no_eigrp_metric_weights_cmd,
+ "no metric weights [(0-255) (0-255) (0-255) (0-255) (0-255) (0-255)]",
+ NO_STR
+ "Modify metrics and parameters for advertisement\n"
+ "Modify metric coefficients\n"
+ "K1\n"
+ "K2\n"
+ "K3\n"
+ "K4\n"
+ "K5\n"
+ "K6\n")
+{
+ nb_cli_enqueue_change(vty, "./metric-weights/K1", NB_OP_DESTROY, NULL);
+ nb_cli_enqueue_change(vty, "./metric-weights/K2", NB_OP_DESTROY, NULL);
+ nb_cli_enqueue_change(vty, "./metric-weights/K3", NB_OP_DESTROY, NULL);
+ nb_cli_enqueue_change(vty, "./metric-weights/K4", NB_OP_DESTROY, NULL);
+ nb_cli_enqueue_change(vty, "./metric-weights/K5", NB_OP_DESTROY, NULL);
+ nb_cli_enqueue_change(vty, "./metric-weights/K6", NB_OP_DESTROY, NULL);
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void eigrp_cli_show_metrics(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ const char *k1, *k2, *k3, *k4, *k5, *k6;
+
+ k1 = yang_dnode_exists(dnode, "./K1") ?
+ yang_dnode_get_string(dnode, "./K1") : "0";
+ k2 = yang_dnode_exists(dnode, "./K2") ?
+ yang_dnode_get_string(dnode, "./K2") : "0";
+ k3 = yang_dnode_exists(dnode, "./K3") ?
+ yang_dnode_get_string(dnode, "./K3") : "0";
+ k4 = yang_dnode_exists(dnode, "./K4") ?
+ yang_dnode_get_string(dnode, "./K4") : "0";
+ k5 = yang_dnode_exists(dnode, "./K5") ?
+ yang_dnode_get_string(dnode, "./K5") : "0";
+ k6 = yang_dnode_exists(dnode, "./K6") ?
+ yang_dnode_get_string(dnode, "./K6") : "0";
+
+ vty_out(vty, " metric weights %s %s %s %s %s",
+ k1, k2, k3, k4, k5);
+ if (k6)
+ vty_out(vty, " %s", k6);
+ vty_out(vty, "\n");
+}
+
+/*
+ * XPath: /frr-eigrpd:eigrpd/instance/network
+ */
+DEFPY(
+ eigrp_network,
+ eigrp_network_cmd,
+ "[no] network A.B.C.D/M$prefix",
+ NO_STR
+ "Enable routing on an IP network\n"
+ "EIGRP network prefix\n")
+{
+ if (no)
+ nb_cli_enqueue_change(vty, "./network", NB_OP_DESTROY,
+ prefix_str);
+ else
+ nb_cli_enqueue_change(vty, "./network", NB_OP_CREATE,
+ prefix_str);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void eigrp_cli_show_network(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ const char *prefix = yang_dnode_get_string(dnode, NULL);
+
+ vty_out(vty, " network %s\n", prefix);
+}
+
+/*
+ * XPath: /frr-eigrpd:eigrpd/instance/neighbor
+ */
+DEFPY(
+ eigrp_neighbor,
+ eigrp_neighbor_cmd,
+ "[no] neighbor A.B.C.D$addr",
+ NO_STR
+ "Specify a neighbor router\n"
+ "Neighbor address\n")
+{
+ if (no)
+ nb_cli_enqueue_change(vty, "./neighbor", NB_OP_DESTROY,
+ addr_str);
+ else
+ nb_cli_enqueue_change(vty, "./neighbor", NB_OP_CREATE,
+ addr_str);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void eigrp_cli_show_neighbor(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ const char *prefix = yang_dnode_get_string(dnode, NULL);
+
+ vty_out(vty, " neighbor %s\n", prefix);
+}
+
+/*
+ * XPath: /frr-eigrpd:eigrpd/instance/redistribute
+ * XPath: /frr-eigrpd:eigrpd/instance/redistribute/route-map
+ * XPath: /frr-eigrpd:eigrpd/instance/redistribute/metrics/bandwidth
+ * XPath: /frr-eigrpd:eigrpd/instance/redistribute/metrics/delay
+ * XPath: /frr-eigrpd:eigrpd/instance/redistribute/metrics/reliability
+ * XPath: /frr-eigrpd:eigrpd/instance/redistribute/metrics/load
+ * XPath: /frr-eigrpd:eigrpd/instance/redistribute/metrics/mtu
+ */
+DEFPY(
+ eigrp_redistribute_source_metric,
+ eigrp_redistribute_source_metric_cmd,
+ "[no] redistribute " FRR_REDIST_STR_EIGRPD
+ "$proto [metric (1-4294967295)$bw (0-4294967295)$delay (0-255)$rlbt (1-255)$load (1-65535)$mtu]",
+ NO_STR
+ REDIST_STR
+ FRR_REDIST_HELP_STR_EIGRPD
+ "Metric for redistributed routes\n"
+ "Bandwidth metric in Kbits per second\n"
+ "EIGRP delay metric, in 10 microsecond units\n"
+ "EIGRP reliability metric where 255 is 100% reliable2 ?\n"
+ "EIGRP Effective bandwidth metric (Loading) where 255 is 100% loaded\n"
+ "EIGRP MTU of the path\n")
+{
+ char xpath[XPATH_MAXLEN], xpath_metric[XPATH_MAXLEN + 64];
+
+ snprintf(xpath, sizeof(xpath), "./redistribute[protocol='%s']", proto);
+
+ if (no) {
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+ return nb_cli_apply_changes(vty, NULL);
+ }
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ if (bw == 0 || delay == 0 || rlbt == 0 || load == 0 || mtu == 0)
+ return nb_cli_apply_changes(vty, NULL);
+
+ snprintf(xpath_metric, sizeof(xpath_metric), "%s/metrics/bandwidth",
+ xpath);
+ nb_cli_enqueue_change(vty, xpath_metric, NB_OP_MODIFY, bw_str);
+ snprintf(xpath_metric, sizeof(xpath_metric), "%s/metrics/delay", xpath);
+ nb_cli_enqueue_change(vty, xpath_metric, NB_OP_MODIFY, delay_str);
+ snprintf(xpath_metric, sizeof(xpath_metric), "%s/metrics/reliability",
+ xpath);
+ nb_cli_enqueue_change(vty, xpath_metric, NB_OP_MODIFY, rlbt_str);
+ snprintf(xpath_metric, sizeof(xpath_metric), "%s/metrics/load", xpath);
+ nb_cli_enqueue_change(vty, xpath_metric, NB_OP_MODIFY, load_str);
+ snprintf(xpath_metric, sizeof(xpath_metric), "%s/metrics/mtu", xpath);
+ nb_cli_enqueue_change(vty, xpath_metric, NB_OP_MODIFY, mtu_str);
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void eigrp_cli_show_redistribute(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ const char *proto = yang_dnode_get_string(dnode, "./protocol");
+ const char *bw, *delay, *load, *mtu, *rlbt;
+
+ bw = yang_dnode_exists(dnode, "./metrics/bandwidth") ?
+ yang_dnode_get_string(dnode, "./metrics/bandwidth") : NULL;
+ delay = yang_dnode_exists(dnode, "./metrics/delay") ?
+ yang_dnode_get_string(dnode, "./metrics/delay") : NULL;
+ rlbt = yang_dnode_exists(dnode, "./metrics/reliability") ?
+ yang_dnode_get_string(dnode, "./metrics/reliability") : NULL;
+ load = yang_dnode_exists(dnode, "./metrics/load") ?
+ yang_dnode_get_string(dnode, "./metrics/load") : NULL;
+ mtu = yang_dnode_exists(dnode, "./metrics/mtu") ?
+ yang_dnode_get_string(dnode, "./metrics/mtu") : NULL;
+
+ vty_out(vty, " redistribute %s", proto);
+ if (bw || rlbt || delay || load || mtu)
+ vty_out(vty, " metric %s %s %s %s %s", bw, delay, rlbt, load,
+ mtu);
+ vty_out(vty, "\n");
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/delay
+ */
+DEFPY(
+ eigrp_if_delay,
+ eigrp_if_delay_cmd,
+ "delay (1-16777215)$delay",
+ "Specify interface throughput delay\n"
+ "Throughput delay (tens of microseconds)\n")
+{
+ nb_cli_enqueue_change(vty, "./frr-eigrpd:eigrp/delay",
+ NB_OP_MODIFY, delay_str);
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_eigrp_if_delay,
+ no_eigrp_if_delay_cmd,
+ "no delay [(1-16777215)]",
+ NO_STR
+ "Specify interface throughput delay\n"
+ "Throughput delay (tens of microseconds)\n")
+{
+ nb_cli_enqueue_change(vty, "./frr-eigrpd:eigrp/delay",
+ NB_OP_DESTROY, NULL);
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void eigrp_cli_show_delay(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ const char *delay = yang_dnode_get_string(dnode, NULL);
+
+ vty_out(vty, " delay %s\n", delay);
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/bandwidth
+ */
+DEFPY(
+ eigrp_if_bandwidth,
+ eigrp_if_bandwidth_cmd,
+ "eigrp bandwidth (1-10000000)$bw",
+ EIGRP_STR
+ "Set bandwidth informational parameter\n"
+ "Bandwidth in kilobits\n")
+{
+ nb_cli_enqueue_change(vty, "./frr-eigrpd:eigrp/bandwidth",
+ NB_OP_MODIFY, bw_str);
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_eigrp_if_bandwidth,
+ no_eigrp_if_bandwidth_cmd,
+ "no eigrp bandwidth [(1-10000000)]",
+ NO_STR
+ EIGRP_STR
+ "Set bandwidth informational parameter\n"
+ "Bandwidth in kilobits\n")
+{
+ nb_cli_enqueue_change(vty, "./frr-eigrpd:eigrp/bandwidth",
+ NB_OP_DESTROY, NULL);
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void eigrp_cli_show_bandwidth(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ const char *bandwidth = yang_dnode_get_string(dnode, NULL);
+
+ vty_out(vty, " eigrp bandwidth %s\n", bandwidth);
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/hello-interval
+ */
+DEFPY(
+ eigrp_if_ip_hellointerval,
+ eigrp_if_ip_hellointerval_cmd,
+ "ip hello-interval eigrp (1-65535)$hello",
+ "Interface Internet Protocol config commands\n"
+ "Configures EIGRP hello interval\n"
+ EIGRP_STR
+ "Seconds between hello transmissions\n")
+{
+ nb_cli_enqueue_change(vty, "./frr-eigrpd:eigrp/hello-interval",
+ NB_OP_MODIFY, hello_str);
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_eigrp_if_ip_hellointerval,
+ no_eigrp_if_ip_hellointerval_cmd,
+ "no ip hello-interval eigrp [(1-65535)]",
+ NO_STR
+ "Interface Internet Protocol config commands\n"
+ "Configures EIGRP hello interval\n"
+ EIGRP_STR
+ "Seconds between hello transmissions\n")
+{
+ nb_cli_enqueue_change(vty, "./frr-eigrpd:eigrp/hello-interval",
+ NB_OP_DESTROY, NULL);
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+
+void eigrp_cli_show_hello_interval(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ const char *hello = yang_dnode_get_string(dnode, NULL);
+
+ vty_out(vty, " ip hello-interval eigrp %s\n", hello);
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/hold-time
+ */
+DEFPY(
+ eigrp_if_ip_holdinterval,
+ eigrp_if_ip_holdinterval_cmd,
+ "ip hold-time eigrp (1-65535)$hold",
+ "Interface Internet Protocol config commands\n"
+ "Configures EIGRP IPv4 hold time\n"
+ EIGRP_STR
+ "Seconds before neighbor is considered down\n")
+{
+ nb_cli_enqueue_change(vty, "./frr-eigrpd:eigrp/hold-time",
+ NB_OP_MODIFY, hold_str);
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_eigrp_if_ip_holdinterval,
+ no_eigrp_if_ip_holdinterval_cmd,
+ "no ip hold-time eigrp [(1-65535)]",
+ NO_STR
+ "Interface Internet Protocol config commands\n"
+ "Configures EIGRP IPv4 hold time\n"
+ EIGRP_STR
+ "Seconds before neighbor is considered down\n")
+{
+ nb_cli_enqueue_change(vty, "./frr-eigrpd:eigrp/hold-time",
+ NB_OP_DESTROY, NULL);
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void eigrp_cli_show_hold_time(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ const char *holdtime = yang_dnode_get_string(dnode, NULL);
+
+ vty_out(vty, " ip hold-time eigrp %s\n", holdtime);
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/split-horizon
+ */
+/* NOT implemented. */
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/instance
+ * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/instance/summarize-addresses
+ */
+DEFPY(
+ eigrp_ip_summary_address,
+ eigrp_ip_summary_address_cmd,
+ "ip summary-address eigrp (1-65535)$as A.B.C.D/M$prefix",
+ "Interface Internet Protocol config commands\n"
+ "Perform address summarization\n"
+ EIGRP_STR
+ AS_STR
+ "Summary <network>/<length>, e.g. 192.168.0.0/16\n")
+{
+ char xpath[XPATH_MAXLEN], xpath_auth[XPATH_MAXLEN + 64];
+
+ snprintf(xpath, sizeof(xpath), "./frr-eigrpd:eigrp/instance[asn='%s']",
+ as_str);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+
+ snprintf(xpath_auth, sizeof(xpath_auth), "%s/summarize-address", xpath);
+ nb_cli_enqueue_change(vty, xpath_auth, NB_OP_CREATE, prefix_str);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_eigrp_ip_summary_address,
+ no_eigrp_ip_summary_address_cmd,
+ "no ip summary-address eigrp (1-65535)$as A.B.C.D/M$prefix",
+ NO_STR
+ "Interface Internet Protocol config commands\n"
+ "Perform address summarization\n"
+ EIGRP_STR
+ AS_STR
+ "Summary <network>/<length>, e.g. 192.168.0.0/16\n")
+{
+ char xpath[XPATH_MAXLEN], xpath_auth[XPATH_MAXLEN + 64];
+
+ snprintf(xpath, sizeof(xpath), "./frr-eigrpd:eigrp/instance[asn='%s']",
+ as_str);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+
+ snprintf(xpath_auth, sizeof(xpath_auth), "%s/summarize-address", xpath);
+ nb_cli_enqueue_change(vty, xpath_auth, NB_OP_DESTROY, prefix_str);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void eigrp_cli_show_summarize_address(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ const struct eigrp_interface *eif = nb_running_get_entry(dnode, NULL,
+ true);
+ const char *summarize_address = yang_dnode_get_string(dnode, NULL);
+
+ vty_out(vty, " ip summary-address eigrp %d %s\n",
+ eif->eigrp->AS, summarize_address);
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/instance
+ * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/instance/authentication
+ */
+DEFPY(
+ eigrp_authentication_mode,
+ eigrp_authentication_mode_cmd,
+ "ip authentication mode eigrp (1-65535)$as <md5|hmac-sha-256>$crypt",
+ "Interface Internet Protocol config commands\n"
+ "Authentication subcommands\n"
+ "Mode\n"
+ EIGRP_STR
+ AS_STR
+ "Keyed message digest\n"
+ "HMAC SHA256 algorithm \n")
+{
+ char xpath[XPATH_MAXLEN], xpath_auth[XPATH_MAXLEN + 64];
+
+ snprintf(xpath, sizeof(xpath), "./frr-eigrpd:eigrp/instance[asn='%s']",
+ as_str);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+
+ snprintf(xpath_auth, sizeof(xpath_auth), "%s/authentication", xpath);
+ nb_cli_enqueue_change(vty, xpath_auth, NB_OP_MODIFY, crypt);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_eigrp_authentication_mode,
+ no_eigrp_authentication_mode_cmd,
+ "no ip authentication mode eigrp (1-65535)$as [<md5|hmac-sha-256>]",
+ NO_STR
+ "Interface Internet Protocol config commands\n"
+ "Authentication subcommands\n"
+ "Mode\n"
+ EIGRP_STR
+ AS_STR
+ "Keyed message digest\n"
+ "HMAC SHA256 algorithm \n")
+{
+ char xpath[XPATH_MAXLEN], xpath_auth[XPATH_MAXLEN + 64];
+
+ snprintf(xpath, sizeof(xpath), "./frr-eigrpd:eigrp/instance[asn='%s']",
+ as_str);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+
+ snprintf(xpath_auth, sizeof(xpath_auth), "%s/authentication", xpath);
+ nb_cli_enqueue_change(vty, xpath_auth, NB_OP_MODIFY, "none");
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void eigrp_cli_show_authentication(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ const struct eigrp_interface *eif = nb_running_get_entry(dnode, NULL,
+ true);
+ const char *crypt = yang_dnode_get_string(dnode, NULL);
+
+ vty_out(vty, " ip authentication mode eigrp %d %s\n",
+ eif->eigrp->AS, crypt);
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/instance
+ * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/instance/keychain
+ */
+DEFPY(
+ eigrp_authentication_keychain,
+ eigrp_authentication_keychain_cmd,
+ "ip authentication key-chain eigrp (1-65535)$as WORD$name",
+ "Interface Internet Protocol config commands\n"
+ "Authentication subcommands\n"
+ "Key-chain\n"
+ EIGRP_STR
+ AS_STR
+ "Name of key-chain\n")
+{
+ char xpath[XPATH_MAXLEN], xpath_auth[XPATH_MAXLEN + 64];
+
+ snprintf(xpath, sizeof(xpath), "./frr-eigrpd:eigrp/instance[asn='%s']",
+ as_str);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+
+ snprintf(xpath_auth, sizeof(xpath_auth), "%s/keychain", xpath);
+ nb_cli_enqueue_change(vty, xpath_auth, NB_OP_MODIFY, name);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+ no_eigrp_authentication_keychain,
+ no_eigrp_authentication_keychain_cmd,
+ "no ip authentication key-chain eigrp (1-65535)$as [WORD]",
+ NO_STR
+ "Interface Internet Protocol config commands\n"
+ "Authentication subcommands\n"
+ "Key-chain\n"
+ EIGRP_STR
+ AS_STR
+ "Name of key-chain\n")
+{
+ char xpath[XPATH_MAXLEN], xpath_auth[XPATH_MAXLEN + 64];
+
+ snprintf(xpath, sizeof(xpath), "./frr-eigrpd:eigrp/instance[asn='%s']",
+ as_str);
+ snprintf(xpath_auth, sizeof(xpath_auth), "%s/keychain", xpath);
+ nb_cli_enqueue_change(vty, xpath_auth, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void eigrp_cli_show_keychain(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ const struct eigrp_interface *eif = nb_running_get_entry(dnode, NULL,
+ true);
+ const char *keychain = yang_dnode_get_string(dnode, NULL);
+
+ vty_out(vty, " ip authentication key-chain eigrp %d %s\n",
+ eif->eigrp->AS, keychain);
+}
+
+
+/*
+ * CLI installation procedures.
+ */
+static struct cmd_node eigrp_node = {EIGRP_NODE, "%s(config-router)# ", 1};
+
+static int eigrp_config_write(struct vty *vty)
+{
+ struct lyd_node *dnode;
+ int written = 0;
+
+ dnode = yang_dnode_get(running_config->dnode, "/frr-eigrpd:eigrpd");
+ if (dnode) {
+ nb_cli_show_dnode_cmds(vty, dnode, false);
+ written = 1;
+ }
+
+ return written;
+}
+
+static struct cmd_node eigrp_interface_node = {INTERFACE_NODE,
+ "%s(config-if)# ", 1};
+
+
+static int eigrp_write_interface(struct vty *vty)
+{
+ struct lyd_node *dnode;
+ struct interface *ifp;
+ struct vrf *vrf;
+ int written = 0;
+
+ RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) {
+ FOR_ALL_INTERFACES(vrf, ifp) {
+ dnode = yang_dnode_get(
+ running_config->dnode,
+ "/frr-interface:lib/interface[name='%s'][vrf='%s']",
+ ifp->name, vrf->name);
+ if (dnode == NULL)
+ continue;
+
+ written = 1;
+ nb_cli_show_dnode_cmds(vty, dnode, false);
+ }
+ }
+
+ return written;
+}
+
+void
+eigrp_cli_init(void)
+{
+ install_element(CONFIG_NODE, &router_eigrp_cmd);
+ install_element(CONFIG_NODE, &no_router_eigrp_cmd);
+
+ install_node(&eigrp_node, eigrp_config_write);
+ install_default(EIGRP_NODE);
+
+ install_element(EIGRP_NODE, &eigrp_router_id_cmd);
+ install_element(EIGRP_NODE, &no_eigrp_router_id_cmd);
+ install_element(EIGRP_NODE, &eigrp_passive_interface_cmd);
+ install_element(EIGRP_NODE, &eigrp_timers_active_cmd);
+ install_element(EIGRP_NODE, &no_eigrp_timers_active_cmd);
+ install_element(EIGRP_NODE, &eigrp_variance_cmd);
+ install_element(EIGRP_NODE, &no_eigrp_variance_cmd);
+ install_element(EIGRP_NODE, &eigrp_maximum_paths_cmd);
+ install_element(EIGRP_NODE, &no_eigrp_maximum_paths_cmd);
+ install_element(EIGRP_NODE, &eigrp_metric_weights_cmd);
+ install_element(EIGRP_NODE, &no_eigrp_metric_weights_cmd);
+ install_element(EIGRP_NODE, &eigrp_network_cmd);
+ install_element(EIGRP_NODE, &eigrp_neighbor_cmd);
+ install_element(EIGRP_NODE, &eigrp_redistribute_source_metric_cmd);
+
+ install_node(&eigrp_interface_node, eigrp_write_interface);
+ if_cmd_init();
+
+ install_element(INTERFACE_NODE, &eigrp_if_delay_cmd);
+ install_element(INTERFACE_NODE, &no_eigrp_if_delay_cmd);
+ install_element(INTERFACE_NODE, &eigrp_if_bandwidth_cmd);
+ install_element(INTERFACE_NODE, &no_eigrp_if_bandwidth_cmd);
+ install_element(INTERFACE_NODE, &eigrp_if_ip_hellointerval_cmd);
+ install_element(INTERFACE_NODE, &no_eigrp_if_ip_hellointerval_cmd);
+ install_element(INTERFACE_NODE, &eigrp_if_ip_holdinterval_cmd);
+ install_element(INTERFACE_NODE, &no_eigrp_if_ip_holdinterval_cmd);
+ install_element(INTERFACE_NODE, &eigrp_ip_summary_address_cmd);
+ install_element(INTERFACE_NODE, &no_eigrp_ip_summary_address_cmd);
+ install_element(INTERFACE_NODE, &eigrp_authentication_mode_cmd);
+ install_element(INTERFACE_NODE, &no_eigrp_authentication_mode_cmd);
+ install_element(INTERFACE_NODE, &eigrp_authentication_keychain_cmd);
+ install_element(INTERFACE_NODE, &no_eigrp_authentication_keychain_cmd);
+}
diff --git a/eigrpd/eigrp_main.c b/eigrpd/eigrp_main.c
index 3db59a838b..1781a88173 100644
--- a/eigrpd/eigrp_main.c
+++ b/eigrpd/eigrp_main.c
@@ -90,10 +90,16 @@ struct option longopts[] = {{0}};
/* Master of threads. */
struct thread_master *master;
+/* Forward declaration of daemon info structure. */
+static struct frr_daemon_info eigrpd_di;
+
/* SIGHUP handler. */
static void sighup(void)
{
zlog_info("SIGHUP received");
+
+ /* Reload config file. */
+ vty_read_config(NULL, eigrpd_di.config_file, config_default);
}
/* SIGINT / SIGTERM handler. */
@@ -131,6 +137,7 @@ struct quagga_signal_t eigrp_signals[] = {
};
static const struct frr_yang_module_info *eigrpd_yang_modules[] = {
+ &frr_eigrpd_info,
&frr_interface_info,
};
@@ -187,7 +194,7 @@ int main(int argc, char **argv, char **envp)
eigrp_vty_init();
keychain_init();
eigrp_vty_show_init();
- eigrp_vty_if_init();
+ eigrp_cli_init();
#ifdef HAVE_SNMP
eigrp_snmp_init();
diff --git a/eigrpd/eigrp_northbound.c b/eigrpd/eigrp_northbound.c
new file mode 100644
index 0000000000..5f0c91809e
--- /dev/null
+++ b/eigrpd/eigrp_northbound.c
@@ -0,0 +1,1584 @@
+/*
+ * EIGRP daemon northbound implementation.
+ *
+ * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF")
+ * Rafael Zalamena
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <zebra.h>
+
+#include "lib/keychain.h"
+#include "lib/log.h"
+#include "lib/northbound.h"
+#include "lib/table.h"
+#include "lib/vrf.h"
+#include "lib/zclient.h"
+
+#include "eigrp_structs.h"
+#include "eigrpd.h"
+#include "eigrp_interface.h"
+#include "eigrp_network.h"
+#include "eigrp_zebra.h"
+
+/* Helper functions. */
+static void redistribute_get_metrics(const struct lyd_node *dnode,
+ struct eigrp_metrics *em)
+{
+ memset(em, 0, sizeof(*em));
+
+ if (yang_dnode_exists(dnode, "./bandwidth"))
+ em->bandwidth = yang_dnode_get_uint32(dnode, "./bandwidth");
+ if (yang_dnode_exists(dnode, "./delay"))
+ em->delay = yang_dnode_get_uint32(dnode, "./delay");
+#if 0 /* TODO: How does MTU work? */
+ if (yang_dnode_exists(dnode, "./mtu"))
+ em->mtu[0] = yang_dnode_get_uint32(dnode, "./mtu");
+#endif
+ if (yang_dnode_exists(dnode, "./load"))
+ em->load = yang_dnode_get_uint32(dnode, "./load");
+ if (yang_dnode_exists(dnode, "./reliability"))
+ em->reliability = yang_dnode_get_uint32(dnode, "./reliability");
+}
+
+static struct eigrp_interface *eigrp_interface_lookup(const struct eigrp *eigrp,
+ const char *ifname)
+{
+ struct eigrp_interface *eif;
+ struct listnode *ln;
+
+ for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, ln, eif)) {
+ if (strcmp(ifname, eif->ifp->name))
+ continue;
+
+ return eif;
+ }
+
+ return NULL;
+}
+
+/*
+ * XPath: /frr-eigrpd:eigrpd/instance
+ */
+static int eigrpd_instance_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct eigrp *eigrp;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ /* NOTHING */
+ break;
+ case NB_EV_PREPARE:
+ eigrp = eigrp_get(yang_dnode_get_string(dnode, "./asn"));
+ resource->ptr = eigrp;
+ break;
+ case NB_EV_ABORT:
+ eigrp_finish_final(resource->ptr);
+ break;
+ case NB_EV_APPLY:
+ nb_running_set_entry(dnode, resource->ptr);
+ break;
+ }
+
+ return NB_OK;
+}
+
+static int eigrpd_instance_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct eigrp *eigrp;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ eigrp = nb_running_unset_entry(dnode);
+ eigrp_finish_final(eigrp);
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-eigrpd:eigrpd/instance/router-id
+ */
+static int eigrpd_instance_router_id_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct eigrp *eigrp;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ eigrp = nb_running_get_entry(dnode, NULL, true);
+ yang_dnode_get_ipv4(&eigrp->router_id_static, dnode, NULL);
+ break;
+ }
+
+ return NB_OK;
+}
+
+static int eigrpd_instance_router_id_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct eigrp *eigrp;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ eigrp = nb_running_get_entry(dnode, NULL, true);
+ eigrp->router_id_static.s_addr = 0;
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-eigrpd:eigrpd/instance/passive-interface
+ */
+static int
+eigrpd_instance_passive_interface_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct eigrp_interface *eif;
+ struct eigrp *eigrp;
+ const char *ifname;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ eigrp = nb_running_get_entry(dnode, NULL, false);
+ if (eigrp == NULL) {
+ /*
+ * XXX: we can't verify if the interface exists
+ * and is active until EIGRP is up.
+ */
+ break;
+ }
+
+ ifname = yang_dnode_get_string(dnode, NULL);
+ eif = eigrp_interface_lookup(eigrp, ifname);
+ if (eif == NULL)
+ return NB_ERR_INCONSISTENCY;
+ break;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ eigrp = nb_running_get_entry(dnode, NULL, true);
+ ifname = yang_dnode_get_string(dnode, NULL);
+ eif = eigrp_interface_lookup(eigrp, ifname);
+ if (eif == NULL)
+ return NB_ERR_INCONSISTENCY;
+
+ eif->params.passive_interface = EIGRP_IF_PASSIVE;
+ break;
+ }
+
+ return NB_OK;
+}
+
+static int
+eigrpd_instance_passive_interface_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct eigrp_interface *eif;
+ struct eigrp *eigrp;
+ const char *ifname;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ eigrp = nb_running_get_entry(dnode, NULL, true);
+ ifname = yang_dnode_get_string(dnode, NULL);
+ eif = eigrp_interface_lookup(eigrp, ifname);
+ if (eif == NULL)
+ break;
+
+ eif->params.passive_interface = EIGRP_IF_ACTIVE;
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-eigrpd:eigrpd/instance/active-time
+ */
+static int eigrpd_instance_active_time_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ /* TODO: Not implemented. */
+ return NB_ERR_INCONSISTENCY;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* NOTHING */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-eigrpd:eigrpd/instance/variance
+ */
+static int eigrpd_instance_variance_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct eigrp *eigrp;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ eigrp = nb_running_get_entry(dnode, NULL, true);
+ eigrp->variance = yang_dnode_get_uint8(dnode, NULL);
+ break;
+ }
+
+ return NB_OK;
+}
+
+static int eigrpd_instance_variance_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct eigrp *eigrp;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ eigrp = nb_running_get_entry(dnode, NULL, true);
+ eigrp->variance = EIGRP_VARIANCE_DEFAULT;
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-eigrpd:eigrpd/instance/maximum-paths
+ */
+static int eigrpd_instance_maximum_paths_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct eigrp *eigrp;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ eigrp = nb_running_get_entry(dnode, NULL, true);
+ eigrp->max_paths = yang_dnode_get_uint8(dnode, NULL);
+ break;
+ }
+
+ return NB_OK;
+}
+
+static int eigrpd_instance_maximum_paths_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct eigrp *eigrp;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ eigrp = nb_running_get_entry(dnode, NULL, true);
+ eigrp->max_paths = EIGRP_MAX_PATHS_DEFAULT;
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K1
+ */
+static int
+eigrpd_instance_metric_weights_K1_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct eigrp *eigrp;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ eigrp = nb_running_get_entry(dnode, NULL, true);
+ eigrp->k_values[0] = yang_dnode_get_uint8(dnode, NULL);
+ break;
+ }
+
+ return NB_OK;
+}
+
+static int
+eigrpd_instance_metric_weights_K1_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct eigrp *eigrp;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ eigrp = nb_running_get_entry(dnode, NULL, true);
+ eigrp->k_values[0] = EIGRP_K1_DEFAULT;
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K2
+ */
+static int
+eigrpd_instance_metric_weights_K2_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct eigrp *eigrp;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ eigrp = nb_running_get_entry(dnode, NULL, true);
+ eigrp->k_values[1] = yang_dnode_get_uint8(dnode, NULL);
+ break;
+ }
+
+ return NB_OK;
+}
+
+static int
+eigrpd_instance_metric_weights_K2_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct eigrp *eigrp;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ eigrp = nb_running_get_entry(dnode, NULL, true);
+ eigrp->k_values[1] = EIGRP_K2_DEFAULT;
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K3
+ */
+static int
+eigrpd_instance_metric_weights_K3_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct eigrp *eigrp;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ eigrp = nb_running_get_entry(dnode, NULL, true);
+ eigrp->k_values[2] = yang_dnode_get_uint8(dnode, NULL);
+ break;
+ }
+
+ return NB_OK;
+}
+
+static int
+eigrpd_instance_metric_weights_K3_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct eigrp *eigrp;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ eigrp = nb_running_get_entry(dnode, NULL, true);
+ eigrp->k_values[2] = EIGRP_K3_DEFAULT;
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K4
+ */
+static int
+eigrpd_instance_metric_weights_K4_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct eigrp *eigrp;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ eigrp = nb_running_get_entry(dnode, NULL, true);
+ eigrp->k_values[3] = yang_dnode_get_uint8(dnode, NULL);
+ break;
+ }
+
+ return NB_OK;
+}
+
+static int
+eigrpd_instance_metric_weights_K4_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct eigrp *eigrp;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ eigrp = nb_running_get_entry(dnode, NULL, true);
+ eigrp->k_values[3] = EIGRP_K4_DEFAULT;
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K5
+ */
+static int
+eigrpd_instance_metric_weights_K5_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct eigrp *eigrp;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ eigrp = nb_running_get_entry(dnode, NULL, true);
+ eigrp->k_values[4] = yang_dnode_get_uint8(dnode, NULL);
+ break;
+ }
+
+ return NB_OK;
+}
+
+static int
+eigrpd_instance_metric_weights_K5_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct eigrp *eigrp;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ eigrp = nb_running_get_entry(dnode, NULL, true);
+ eigrp->k_values[4] = EIGRP_K5_DEFAULT;
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K6
+ */
+static int
+eigrpd_instance_metric_weights_K6_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct eigrp *eigrp;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ eigrp = nb_running_get_entry(dnode, NULL, true);
+ eigrp->k_values[5] = yang_dnode_get_uint8(dnode, NULL);
+ break;
+ }
+
+ return NB_OK;
+}
+
+static int
+eigrpd_instance_metric_weights_K6_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct eigrp *eigrp;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ eigrp = nb_running_get_entry(dnode, NULL, true);
+ eigrp->k_values[5] = EIGRP_K6_DEFAULT;
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-eigrpd:eigrpd/instance/network
+ */
+static int eigrpd_instance_network_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct route_node *rnode;
+ struct prefix prefix;
+ struct eigrp *eigrp;
+ int exists;
+
+ yang_dnode_get_ipv4p(&prefix, dnode, NULL);
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ eigrp = nb_running_get_entry(dnode, NULL, false);
+ /* If entry doesn't exist it means the list is empty. */
+ if (eigrp == NULL)
+ break;
+
+ rnode = route_node_get(eigrp->networks, &prefix);
+ exists = (rnode->info != NULL);
+ route_unlock_node(rnode);
+ if (exists)
+ return NB_ERR_INCONSISTENCY;
+ break;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ eigrp = nb_running_get_entry(dnode, NULL, true);
+ if (eigrp_network_set(eigrp, &prefix) == 0)
+ return NB_ERR_INCONSISTENCY;
+ break;
+ }
+
+ return NB_OK;
+}
+
+static int eigrpd_instance_network_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct route_node *rnode;
+ struct prefix prefix;
+ struct eigrp *eigrp;
+ int exists = 0;
+
+ yang_dnode_get_ipv4p(&prefix, dnode, NULL);
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ eigrp = nb_running_get_entry(dnode, NULL, false);
+ /* If entry doesn't exist it means the list is empty. */
+ if (eigrp == NULL)
+ break;
+
+ rnode = route_node_get(eigrp->networks, &prefix);
+ exists = (rnode->info != NULL);
+ route_unlock_node(rnode);
+ if (exists == 0)
+ return NB_ERR_INCONSISTENCY;
+ break;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ eigrp = nb_running_get_entry(dnode, NULL, true);
+ eigrp_network_unset(eigrp, &prefix);
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-eigrpd:eigrpd/instance/neighbor
+ */
+static int eigrpd_instance_neighbor_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ /* TODO: Not implemented. */
+ return NB_ERR_INCONSISTENCY;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* NOTHING */
+ break;
+ }
+
+ return NB_OK;
+}
+
+static int eigrpd_instance_neighbor_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ /* TODO: Not implemented. */
+ return NB_ERR_INCONSISTENCY;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* NOTHING */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-eigrpd:eigrpd/instance/redistribute
+ */
+static int eigrpd_instance_redistribute_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct eigrp_metrics metrics;
+ struct eigrp *eigrp;
+ uint32_t proto;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ proto = yang_dnode_get_enum(dnode, "./protocol");
+ if (vrf_bitmap_check(zclient->redist[AFI_IP][proto],
+ VRF_DEFAULT))
+ return NB_ERR_INCONSISTENCY;
+ break;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ eigrp = nb_running_get_entry(dnode, NULL, true);
+ proto = yang_dnode_get_enum(dnode, "./protocol");
+ redistribute_get_metrics(dnode, &metrics);
+ eigrp_redistribute_set(eigrp, proto, metrics);
+ break;
+ }
+
+ return NB_OK;
+}
+
+static int eigrpd_instance_redistribute_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct eigrp *eigrp;
+ uint32_t proto;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ eigrp = nb_running_get_entry(dnode, NULL, true);
+ proto = yang_dnode_get_enum(dnode, "./protocol");
+ eigrp_redistribute_unset(eigrp, proto);
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-eigrpd:eigrpd/instance/redistribute/route-map
+ */
+static int
+eigrpd_instance_redistribute_route_map_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ /* TODO: Not implemented. */
+ return NB_ERR_INCONSISTENCY;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* NOTHING */
+ break;
+ }
+
+ return NB_OK;
+}
+
+static int
+eigrpd_instance_redistribute_route_map_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ /* TODO: Not implemented. */
+ return NB_ERR_INCONSISTENCY;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* NOTHING */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-eigrpd:eigrpd/instance/redistribute/metrics/bandwidth
+ */
+static int eigrpd_instance_redistribute_metrics_bandwidth_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct eigrp_metrics metrics;
+ struct eigrp *eigrp;
+ uint32_t proto;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ eigrp = nb_running_get_entry(dnode, NULL, true);
+ proto = yang_dnode_get_enum(dnode, "../../protocol");
+ redistribute_get_metrics(dnode, &metrics);
+ eigrp_redistribute_set(eigrp, proto, metrics);
+ break;
+ }
+
+ return NB_OK;
+}
+
+static int eigrpd_instance_redistribute_metrics_bandwidth_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ struct eigrp_metrics metrics;
+ struct eigrp *eigrp;
+ uint32_t proto;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ eigrp = nb_running_get_entry(dnode, NULL, true);
+ proto = yang_dnode_get_enum(dnode, "../../protocol");
+ redistribute_get_metrics(dnode, &metrics);
+ eigrp_redistribute_set(eigrp, proto, metrics);
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-eigrpd:eigrpd/instance/redistribute/metrics/delay
+ */
+static int
+eigrpd_instance_redistribute_metrics_delay_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ return eigrpd_instance_redistribute_metrics_bandwidth_modify(event,
+ dnode,
+ resource);
+}
+
+static int
+eigrpd_instance_redistribute_metrics_delay_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ return eigrpd_instance_redistribute_metrics_bandwidth_destroy(event,
+ dnode);
+}
+
+/*
+ * XPath: /frr-eigrpd:eigrpd/instance/redistribute/metrics/reliability
+ */
+static int eigrpd_instance_redistribute_metrics_reliability_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ return eigrpd_instance_redistribute_metrics_bandwidth_modify(event,
+ dnode,
+ resource);
+}
+
+static int eigrpd_instance_redistribute_metrics_reliability_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ return eigrpd_instance_redistribute_metrics_bandwidth_destroy(event,
+ dnode);
+}
+
+/*
+ * XPath: /frr-eigrpd:eigrpd/instance/redistribute/metrics/load
+ */
+static int
+eigrpd_instance_redistribute_metrics_load_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ return eigrpd_instance_redistribute_metrics_bandwidth_modify(event,
+ dnode,
+ resource);
+}
+
+static int
+eigrpd_instance_redistribute_metrics_load_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ return eigrpd_instance_redistribute_metrics_bandwidth_destroy(event,
+ dnode);
+}
+
+/*
+ * XPath: /frr-eigrpd:eigrpd/instance/redistribute/metrics/mtu
+ */
+static int
+eigrpd_instance_redistribute_metrics_mtu_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ return eigrpd_instance_redistribute_metrics_bandwidth_modify(event,
+ dnode,
+ resource);
+}
+
+static int
+eigrpd_instance_redistribute_metrics_mtu_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ return eigrpd_instance_redistribute_metrics_bandwidth_destroy(event,
+ dnode);
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/delay
+ */
+static int lib_interface_eigrp_delay_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct eigrp_interface *ei;
+ struct interface *ifp;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ ifp = nb_running_get_entry(dnode, NULL, false);
+ if (ifp == NULL) {
+ /*
+ * XXX: we can't verify if the interface exists
+ * and is active until EIGRP is up.
+ */
+ break;
+ }
+
+ ei = ifp->info;
+ if (ei == NULL)
+ return NB_ERR_INCONSISTENCY;
+ break;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ ifp = nb_running_get_entry(dnode, NULL, true);
+ ei = ifp->info;
+ if (ei == NULL)
+ return NB_ERR_INCONSISTENCY;
+
+ ei->params.delay = yang_dnode_get_uint32(dnode, NULL);
+ eigrp_if_reset(ifp);
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/bandwidth
+ */
+static int lib_interface_eigrp_bandwidth_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct interface *ifp;
+ struct eigrp_interface *ei;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ ifp = nb_running_get_entry(dnode, NULL, false);
+ if (ifp == NULL) {
+ /*
+ * XXX: we can't verify if the interface exists
+ * and is active until EIGRP is up.
+ */
+ break;
+ }
+
+ ei = ifp->info;
+ if (ei == NULL)
+ return NB_ERR_INCONSISTENCY;
+ break;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ ifp = nb_running_get_entry(dnode, NULL, true);
+ ei = ifp->info;
+ if (ei == NULL)
+ return NB_ERR_INCONSISTENCY;
+
+ ei->params.bandwidth = yang_dnode_get_uint32(dnode, NULL);
+ eigrp_if_reset(ifp);
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/hello-interval
+ */
+static int
+lib_interface_eigrp_hello_interval_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct interface *ifp;
+ struct eigrp_interface *ei;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ ifp = nb_running_get_entry(dnode, NULL, false);
+ if (ifp == NULL) {
+ /*
+ * XXX: we can't verify if the interface exists
+ * and is active until EIGRP is up.
+ */
+ break;
+ }
+
+ ei = ifp->info;
+ if (ei == NULL)
+ return NB_ERR_INCONSISTENCY;
+ break;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ ifp = nb_running_get_entry(dnode, NULL, true);
+ ei = ifp->info;
+ if (ei == NULL)
+ return NB_ERR_INCONSISTENCY;
+
+ ei->params.v_hello = yang_dnode_get_uint16(dnode, NULL);
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/hold-time
+ */
+static int lib_interface_eigrp_hold_time_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct interface *ifp;
+ struct eigrp_interface *ei;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ ifp = nb_running_get_entry(dnode, NULL, false);
+ if (ifp == NULL) {
+ /*
+ * XXX: we can't verify if the interface exists
+ * and is active until EIGRP is up.
+ */
+ break;
+ }
+
+ ei = ifp->info;
+ if (ei == NULL)
+ return NB_ERR_INCONSISTENCY;
+ break;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ ifp = nb_running_get_entry(dnode, NULL, true);
+ ei = ifp->info;
+ if (ei == NULL)
+ return NB_ERR_INCONSISTENCY;
+
+ ei->params.v_wait = yang_dnode_get_uint16(dnode, NULL);
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/split-horizon
+ */
+static int
+lib_interface_eigrp_split_horizon_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ /* TODO: Not implemented. */
+ return NB_ERR_INCONSISTENCY;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* NOTHING */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/instance
+ */
+static int lib_interface_eigrp_instance_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct eigrp_interface *eif;
+ struct interface *ifp;
+ struct eigrp *eigrp;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ ifp = nb_running_get_entry(dnode, NULL, false);
+ if (ifp == NULL) {
+ /*
+ * XXX: we can't verify if the interface exists
+ * and is active until EIGRP is up.
+ */
+ break;
+ }
+
+ eigrp = eigrp_get(yang_dnode_get_string(dnode, "./asn"));
+ eif = eigrp_interface_lookup(eigrp, ifp->name);
+ if (eif == NULL)
+ return NB_ERR_INCONSISTENCY;
+ break;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ ifp = nb_running_get_entry(dnode, NULL, true);
+ eigrp = eigrp_get(yang_dnode_get_string(dnode, "./asn"));
+ eif = eigrp_interface_lookup(eigrp, ifp->name);
+ if (eif == NULL)
+ return NB_ERR_INCONSISTENCY;
+
+ nb_running_set_entry(dnode, eif);
+ break;
+ }
+
+ return NB_OK;
+}
+
+static int lib_interface_eigrp_instance_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ nb_running_unset_entry(dnode);
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-eigrpd:eigrp/instance/summarize-addresses
+ */
+static int lib_interface_eigrp_instance_summarize_addresses_create(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ /* TODO: Not implemented. */
+ return NB_ERR_INCONSISTENCY;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* NOTHING */
+ break;
+ }
+
+ return NB_OK;
+}
+
+static int lib_interface_eigrp_instance_summarize_addresses_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ /* TODO: Not implemented. */
+ return NB_ERR_INCONSISTENCY;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ /* NOTHING */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/instance/authentication
+ */
+static int
+lib_interface_eigrp_instance_authentication_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct eigrp_interface *eif;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ eif = nb_running_get_entry(dnode, NULL, true);
+ eif->params.auth_type = yang_dnode_get_enum(dnode, NULL);
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/instance/keychain
+ */
+static int
+lib_interface_eigrp_instance_keychain_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct eigrp_interface *eif;
+ struct keychain *keychain;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ keychain = keychain_lookup(yang_dnode_get_string(dnode, NULL));
+ if (keychain == NULL)
+ return NB_ERR_INCONSISTENCY;
+ break;
+ case NB_EV_PREPARE:
+ resource->ptr = strdup(yang_dnode_get_string(dnode, NULL));
+ if (resource->ptr == NULL)
+ return NB_ERR_RESOURCE;
+ break;
+ case NB_EV_ABORT:
+ free(resource->ptr);
+ resource->ptr = NULL;
+ break;
+ case NB_EV_APPLY:
+ eif = nb_running_get_entry(dnode, NULL, true);
+ if (eif->params.auth_keychain)
+ free(eif->params.auth_keychain);
+
+ eif->params.auth_keychain = resource->ptr;
+ break;
+ }
+
+ return NB_OK;
+}
+
+static int
+lib_interface_eigrp_instance_keychain_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct eigrp_interface *eif;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ eif = nb_running_get_entry(dnode, NULL, true);
+ if (eif->params.auth_keychain)
+ free(eif->params.auth_keychain);
+
+ eif->params.auth_keychain = NULL;
+ break;
+ }
+
+ return NB_OK;
+}
+
+/* clang-format off */
+const struct frr_yang_module_info frr_eigrpd_info = {
+ .name = "frr-eigrpd",
+ .nodes = {
+ {
+ .xpath = "/frr-eigrpd:eigrpd/instance",
+ .cbs = {
+ .create = eigrpd_instance_create,
+ .destroy = eigrpd_instance_destroy,
+ .cli_show = eigrp_cli_show_header,
+ .cli_show_end = eigrp_cli_show_end_header,
+ }
+ },
+ {
+ .xpath = "/frr-eigrpd:eigrpd/instance/router-id",
+ .cbs = {
+ .modify = eigrpd_instance_router_id_modify,
+ .destroy = eigrpd_instance_router_id_destroy,
+ .cli_show = eigrp_cli_show_router_id,
+ }
+ },
+ {
+ .xpath = "/frr-eigrpd:eigrpd/instance/passive-interface",
+ .cbs = {
+ .create = eigrpd_instance_passive_interface_create,
+ .destroy = eigrpd_instance_passive_interface_destroy,
+ .cli_show = eigrp_cli_show_passive_interface,
+ }
+ },
+ {
+ .xpath = "/frr-eigrpd:eigrpd/instance/active-time",
+ .cbs = {
+ .modify = eigrpd_instance_active_time_modify,
+ .cli_show = eigrp_cli_show_active_time,
+ }
+ },
+ {
+ .xpath = "/frr-eigrpd:eigrpd/instance/variance",
+ .cbs = {
+ .modify = eigrpd_instance_variance_modify,
+ .destroy = eigrpd_instance_variance_destroy,
+ .cli_show = eigrp_cli_show_variance,
+ }
+ },
+ {
+ .xpath = "/frr-eigrpd:eigrpd/instance/maximum-paths",
+ .cbs = {
+ .modify = eigrpd_instance_maximum_paths_modify,
+ .destroy = eigrpd_instance_maximum_paths_destroy,
+ .cli_show = eigrp_cli_show_maximum_paths,
+ }
+ },
+ {
+ .xpath = "/frr-eigrpd:eigrpd/instance/metric-weights",
+ .cbs = {
+ .cli_show = eigrp_cli_show_metrics,
+ }
+ },
+ {
+ .xpath = "/frr-eigrpd:eigrpd/instance/metric-weights/K1",
+ .cbs = {
+ .modify = eigrpd_instance_metric_weights_K1_modify,
+ .destroy = eigrpd_instance_metric_weights_K1_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-eigrpd:eigrpd/instance/metric-weights/K2",
+ .cbs = {
+ .modify = eigrpd_instance_metric_weights_K2_modify,
+ .destroy = eigrpd_instance_metric_weights_K2_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-eigrpd:eigrpd/instance/metric-weights/K3",
+ .cbs = {
+ .modify = eigrpd_instance_metric_weights_K3_modify,
+ .destroy = eigrpd_instance_metric_weights_K3_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-eigrpd:eigrpd/instance/metric-weights/K4",
+ .cbs = {
+ .modify = eigrpd_instance_metric_weights_K4_modify,
+ .destroy = eigrpd_instance_metric_weights_K4_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-eigrpd:eigrpd/instance/metric-weights/K5",
+ .cbs = {
+ .modify = eigrpd_instance_metric_weights_K5_modify,
+ .destroy = eigrpd_instance_metric_weights_K5_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-eigrpd:eigrpd/instance/metric-weights/K6",
+ .cbs = {
+ .modify = eigrpd_instance_metric_weights_K6_modify,
+ .destroy = eigrpd_instance_metric_weights_K6_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-eigrpd:eigrpd/instance/network",
+ .cbs = {
+ .create = eigrpd_instance_network_create,
+ .destroy = eigrpd_instance_network_destroy,
+ .cli_show = eigrp_cli_show_network,
+ }
+ },
+ {
+ .xpath = "/frr-eigrpd:eigrpd/instance/neighbor",
+ .cbs = {
+ .create = eigrpd_instance_neighbor_create,
+ .destroy = eigrpd_instance_neighbor_destroy,
+ .cli_show = eigrp_cli_show_neighbor,
+ }
+ },
+ {
+ .xpath = "/frr-eigrpd:eigrpd/instance/redistribute",
+ .cbs = {
+ .create = eigrpd_instance_redistribute_create,
+ .destroy = eigrpd_instance_redistribute_destroy,
+ .cli_show = eigrp_cli_show_redistribute,
+ }
+ },
+ {
+ .xpath = "/frr-eigrpd:eigrpd/instance/redistribute/route-map",
+ .cbs = {
+ .modify = eigrpd_instance_redistribute_route_map_modify,
+ .destroy = eigrpd_instance_redistribute_route_map_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-eigrpd:eigrpd/instance/redistribute/metrics/bandwidth",
+ .cbs = {
+ .modify = eigrpd_instance_redistribute_metrics_bandwidth_modify,
+ .destroy = eigrpd_instance_redistribute_metrics_bandwidth_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-eigrpd:eigrpd/instance/redistribute/metrics/delay",
+ .cbs = {
+ .modify = eigrpd_instance_redistribute_metrics_delay_modify,
+ .destroy = eigrpd_instance_redistribute_metrics_delay_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-eigrpd:eigrpd/instance/redistribute/metrics/reliability",
+ .cbs = {
+ .modify = eigrpd_instance_redistribute_metrics_reliability_modify,
+ .destroy = eigrpd_instance_redistribute_metrics_reliability_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-eigrpd:eigrpd/instance/redistribute/metrics/load",
+ .cbs = {
+ .modify = eigrpd_instance_redistribute_metrics_load_modify,
+ .destroy = eigrpd_instance_redistribute_metrics_load_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-eigrpd:eigrpd/instance/redistribute/metrics/mtu",
+ .cbs = {
+ .modify = eigrpd_instance_redistribute_metrics_mtu_modify,
+ .destroy = eigrpd_instance_redistribute_metrics_mtu_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-eigrpd:eigrp/delay",
+ .cbs = {
+ .modify = lib_interface_eigrp_delay_modify,
+ .cli_show = eigrp_cli_show_delay,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-eigrpd:eigrp/bandwidth",
+ .cbs = {
+ .modify = lib_interface_eigrp_bandwidth_modify,
+ .cli_show = eigrp_cli_show_bandwidth,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-eigrpd:eigrp/hello-interval",
+ .cbs = {
+ .modify = lib_interface_eigrp_hello_interval_modify,
+ .cli_show = eigrp_cli_show_hello_interval,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-eigrpd:eigrp/hold-time",
+ .cbs = {
+ .modify = lib_interface_eigrp_hold_time_modify,
+ .cli_show = eigrp_cli_show_hold_time,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-eigrpd:eigrp/split-horizon",
+ .cbs = {
+ .modify = lib_interface_eigrp_split_horizon_modify,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-eigrpd:eigrp/instance",
+ .cbs = {
+ .create = lib_interface_eigrp_instance_create,
+ .destroy = lib_interface_eigrp_instance_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-eigrpd:eigrp/instance/summarize-addresses",
+ .cbs = {
+ .create = lib_interface_eigrp_instance_summarize_addresses_create,
+ .destroy = lib_interface_eigrp_instance_summarize_addresses_destroy,
+ .cli_show = eigrp_cli_show_summarize_address,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-eigrpd:eigrp/instance/authentication",
+ .cbs = {
+ .modify = lib_interface_eigrp_instance_authentication_modify,
+ .cli_show = eigrp_cli_show_authentication,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-eigrpd:eigrp/instance/keychain",
+ .cbs = {
+ .modify = lib_interface_eigrp_instance_keychain_modify,
+ .destroy = lib_interface_eigrp_instance_keychain_destroy,
+ .cli_show = eigrp_cli_show_keychain,
+ }
+ },
+ {
+ .xpath = NULL,
+ },
+ }
+};
diff --git a/eigrpd/eigrp_routemap.c b/eigrpd/eigrp_routemap.c
index f080ba4876..bac7494774 100644
--- a/eigrpd/eigrp_routemap.c
+++ b/eigrpd/eigrp_routemap.c
@@ -251,9 +251,9 @@ void eigrp_route_map_update(const char *notused)
/* `match metric METRIC' */
/* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_metric(void *rule, struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_metric(void *rule, struct prefix *prefix, route_map_object_t type,
+ void *object)
{
// uint32_t *metric;
// uint32_t check;
@@ -311,10 +311,9 @@ struct route_map_rule_cmd route_match_metric_cmd = {
/* `match interface IFNAME' */
/* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_interface(void *rule,
- struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_interface(void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
{
// struct rip_info *rinfo;
// struct interface *ifp;
@@ -360,10 +359,9 @@ struct route_map_rule_cmd route_match_interface_cmd = {
/* `match ip next-hop IP_ACCESS_LIST' */
/* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_ip_next_hop(void *rule,
- struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_ip_next_hop(void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
{
// struct access_list *alist;
// struct rip_info *rinfo;
@@ -407,7 +405,7 @@ static struct route_map_rule_cmd route_match_ip_next_hop_cmd = {
/* `match ip next-hop prefix-list PREFIX_LIST' */
-static route_map_result_t
+static enum route_map_cmd_result_t
route_match_ip_next_hop_prefix_list(void *rule, struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -452,10 +450,9 @@ static struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = {
/* Match function should return 1 if match is success else return
zero. */
-static route_map_result_t route_match_ip_address(void *rule,
- struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_ip_address(void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct access_list *alist;
@@ -491,7 +488,7 @@ static struct route_map_rule_cmd route_match_ip_address_cmd = {
/* `match ip address prefix-list PREFIX_LIST' */
-static route_map_result_t
+static enum route_map_cmd_result_t
route_match_ip_address_prefix_list(void *rule, struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -526,8 +523,9 @@ static struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = {
/* `match tag TAG' */
/* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_tag(void *rule, struct prefix *prefix,
- route_map_object_t type, void *object)
+static enum route_map_cmd_result_t
+route_match_tag(void *rule, struct prefix *prefix, route_map_object_t type,
+ void *object)
{
// unsigned short *tag;
// struct rip_info *rinfo;
@@ -568,9 +566,9 @@ struct route_map_rule_cmd route_match_tag_cmd = {
"tag", route_match_tag, route_match_tag_compile, route_match_tag_free};
/* Set metric to attribute. */
-static route_map_result_t route_set_metric(void *rule, struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_set_metric(void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
{
// if (type == RMAP_RIP)
// {
@@ -662,10 +660,9 @@ static struct route_map_rule_cmd route_set_metric_cmd = {
/* `set ip next-hop IP_ADDRESS' */
/* Set nexthop to object. ojbect must be pointer to struct attr. */
-static route_map_result_t route_set_ip_nexthop(void *rule,
- struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_set_ip_nexthop(void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
{
// struct in_addr *address;
// struct rip_info *rinfo;
@@ -718,8 +715,9 @@ static struct route_map_rule_cmd route_set_ip_nexthop_cmd = {
/* `set tag TAG' */
/* Set tag to object. ojbect must be pointer to struct attr. */
-static route_map_result_t route_set_tag(void *rule, struct prefix *prefix,
- route_map_object_t type, void *object)
+static enum route_map_cmd_result_t
+route_set_tag(void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
{
// unsigned short *tag;
// struct rip_info *rinfo;
diff --git a/eigrpd/eigrp_vty.c b/eigrpd/eigrp_vty.c
index d51faaac59..207622e659 100644
--- a/eigrpd/eigrp_vty.c
+++ b/eigrpd/eigrp_vty.c
@@ -59,402 +59,6 @@
#include "eigrpd/eigrp_vty_clippy.c"
#endif
-static int config_write_network(struct vty *vty, struct eigrp *eigrp)
-{
- struct route_node *rn;
- int i;
-
- /* `network area' print. */
- for (rn = route_top(eigrp->networks); rn; rn = route_next(rn))
- if (rn->info) {
- /* Network print. */
- vty_out(vty, " network %s/%d \n",
- inet_ntoa(rn->p.u.prefix4), rn->p.prefixlen);
- }
-
- if (eigrp->max_paths != EIGRP_MAX_PATHS_DEFAULT)
- vty_out(vty, " maximum-paths %d\n", eigrp->max_paths);
-
- if (eigrp->variance != EIGRP_VARIANCE_DEFAULT)
- vty_out(vty, " variance %d\n", eigrp->variance);
-
- for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
- if (i != zclient->redist_default
- && vrf_bitmap_check(zclient->redist[AFI_IP][i],
- VRF_DEFAULT))
- vty_out(vty, " redistribute %s\n",
- zebra_route_string(i));
-
- /*Separate EIGRP configuration from the rest of the config*/
- vty_out(vty, "!\n");
-
- return 0;
-}
-
-static int config_write_interfaces(struct vty *vty, struct eigrp *eigrp)
-{
- struct eigrp_interface *ei;
- struct listnode *node;
-
- for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, ei)) {
- vty_frame(vty, "interface %s\n", ei->ifp->name);
-
- if (ei->params.auth_type == EIGRP_AUTH_TYPE_MD5) {
- vty_out(vty, " ip authentication mode eigrp %d md5\n",
- eigrp->AS);
- }
-
- if (ei->params.auth_type == EIGRP_AUTH_TYPE_SHA256) {
- vty_out(vty,
- " ip authentication mode eigrp %d hmac-sha-256\n",
- eigrp->AS);
- }
-
- if (ei->params.auth_keychain) {
- vty_out(vty,
- " ip authentication key-chain eigrp %d %s\n",
- eigrp->AS, ei->params.auth_keychain);
- }
-
- if (ei->params.v_hello != EIGRP_HELLO_INTERVAL_DEFAULT) {
- vty_out(vty, " ip hello-interval eigrp %d\n",
- ei->params.v_hello);
- }
-
- if (ei->params.v_wait != EIGRP_HOLD_INTERVAL_DEFAULT) {
- vty_out(vty, " ip hold-time eigrp %d\n",
- ei->params.v_wait);
- }
-
- /*Separate this EIGRP interface configuration from the others*/
- vty_endframe(vty, "!\n");
- }
-
- return 0;
-}
-
-static int eigrp_write_interface(struct vty *vty)
-{
- struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
- struct interface *ifp;
- struct eigrp_interface *ei;
-
- FOR_ALL_INTERFACES (vrf, ifp) {
- ei = ifp->info;
- if (!ei)
- continue;
-
- vty_frame(vty, "interface %s\n", ifp->name);
-
- if (ifp->desc)
- vty_out(vty, " description %s\n", ifp->desc);
-
- if (ei->params.bandwidth != EIGRP_BANDWIDTH_DEFAULT)
- vty_out(vty, " bandwidth %u\n", ei->params.bandwidth);
- if (ei->params.delay != EIGRP_DELAY_DEFAULT)
- vty_out(vty, " delay %u\n", ei->params.delay);
- if (ei->params.v_hello != EIGRP_HELLO_INTERVAL_DEFAULT)
- vty_out(vty, " ip hello-interval eigrp %u\n",
- ei->params.v_hello);
- if (ei->params.v_wait != EIGRP_HOLD_INTERVAL_DEFAULT)
- vty_out(vty, " ip hold-time eigrp %u\n",
- ei->params.v_wait);
-
- vty_endframe(vty, "!\n");
- }
-
- return 0;
-}
-
-/**
- * Writes distribute lists to config
- */
-static int config_write_eigrp_distribute(struct vty *vty, struct eigrp *eigrp)
-{
- int write = 0;
-
- /* Distribute configuration. */
- write += config_write_distribute(vty, eigrp->distribute_ctx);
-
- return write;
-}
-
-/**
- * Writes 'router eigrp' section to config
- */
-static int config_write_eigrp_router(struct vty *vty, struct eigrp *eigrp)
-{
- int write = 0;
-
- /* `router eigrp' print. */
- vty_out(vty, "router eigrp %d\n", eigrp->AS);
-
- write++;
-
- /* Router ID print. */
- if (eigrp->router_id_static.s_addr != 0) {
- vty_out(vty, " eigrp router-id %s\n",
- inet_ntoa(eigrp->router_id_static));
- }
-
- /* Network area print. */
- config_write_network(vty, eigrp);
-
- /* Distribute-list and default-information print. */
- config_write_eigrp_distribute(vty, eigrp);
-
- /*Separate EIGRP configuration from the rest of the config*/
- vty_out(vty, "!\n");
-
- return write;
-}
-
-DEFUN_NOSH (router_eigrp,
- router_eigrp_cmd,
- "router eigrp (1-65535)",
- "Enable a routing process\n"
- "Start EIGRP configuration\n"
- "AS Number to use\n")
-{
- struct eigrp *eigrp = eigrp_get(argv[2]->arg);
- VTY_PUSH_CONTEXT(EIGRP_NODE, eigrp);
-
- return CMD_SUCCESS;
-}
-
-DEFUN (no_router_eigrp,
- no_router_eigrp_cmd,
- "no router eigrp (1-65535)",
- NO_STR
- "Routing process\n"
- "EIGRP configuration\n"
- "AS number to use\n")
-{
- vty->node = CONFIG_NODE;
-
- struct eigrp *eigrp;
-
- eigrp = eigrp_lookup();
- if (eigrp == NULL) {
- vty_out(vty, " EIGRP Routing Process not enabled\n");
- return CMD_SUCCESS;
- }
-
- if (eigrp->AS != atoi(argv[3]->arg)) {
- vty_out(vty, "%% Attempting to deconfigure non-existent AS\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- eigrp_finish_final(eigrp);
-
- return CMD_SUCCESS;
-}
-
-DEFPY (eigrp_router_id,
- eigrp_router_id_cmd,
- "eigrp router-id A.B.C.D$addr",
- "EIGRP specific commands\n"
- "Router ID for this EIGRP process\n"
- "EIGRP Router-ID in IP address format\n")
-{
- VTY_DECLVAR_CONTEXT(eigrp, eigrp);
-
- eigrp->router_id_static = addr;
-
- return CMD_SUCCESS;
-}
-
-DEFPY (no_eigrp_router_id,
- no_eigrp_router_id_cmd,
- "no eigrp router-id [A.B.C.D$addr]",
- NO_STR
- "EIGRP specific commands\n"
- "Router ID for this EIGRP process\n"
- "EIGRP Router-ID in IP address format\n")
-{
- VTY_DECLVAR_CONTEXT(eigrp, eigrp);
-
- eigrp->router_id_static.s_addr = 0;
-
- return CMD_SUCCESS;
-}
-
-DEFUN (eigrp_passive_interface,
- eigrp_passive_interface_cmd,
- "passive-interface IFNAME",
- "Suppress routing updates on an interface\n"
- "Interface to suppress on\n")
-{
- VTY_DECLVAR_CONTEXT(eigrp, eigrp);
- struct eigrp_interface *ei;
- struct listnode *node;
- char *ifname = argv[1]->arg;
-
- for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, ei)) {
- if (strcmp(ifname, ei->ifp->name) == 0) {
- ei->params.passive_interface = EIGRP_IF_PASSIVE;
- return CMD_SUCCESS;
- }
- }
- return CMD_SUCCESS;
-}
-
-DEFUN (no_eigrp_passive_interface,
- no_eigrp_passive_interface_cmd,
- "no passive-interface IFNAME",
- NO_STR
- "Suppress routing updates on an interface\n"
- "Interface to suppress on\n")
-{
- VTY_DECLVAR_CONTEXT(eigrp, eigrp);
- struct eigrp_interface *ei;
- struct listnode *node;
- char *ifname = argv[2]->arg;
-
- for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, ei)) {
- if (strcmp(ifname, ei->ifp->name) == 0) {
- ei->params.passive_interface = EIGRP_IF_ACTIVE;
- return CMD_SUCCESS;
- }
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN (eigrp_timers_active,
- eigrp_timers_active_cmd,
- "timers active-time <(1-65535)|disabled>",
- "Adjust routing timers\n"
- "Time limit for active state\n"
- "Active state time limit in seconds\n"
- "Disable time limit for active state\n")
-{
- // struct eigrp *eigrp = vty->index;
- /*TODO: */
-
- return CMD_SUCCESS;
-}
-
-DEFUN (no_eigrp_timers_active,
- no_eigrp_timers_active_cmd,
- "no timers active-time <(1-65535)|disabled>",
- NO_STR
- "Adjust routing timers\n"
- "Time limit for active state\n"
- "Active state time limit in seconds\n"
- "Disable time limit for active state\n")
-{
- // struct eigrp *eigrp = vty->index;
- /*TODO: */
-
- return CMD_SUCCESS;
-}
-
-
-DEFUN (eigrp_metric_weights,
- eigrp_metric_weights_cmd,
- "metric weights (0-255) (0-255) (0-255) (0-255) (0-255) ",
- "Modify metrics and parameters for advertisement\n"
- "Modify metric coefficients\n"
- "K1\n"
- "K2\n"
- "K3\n"
- "K4\n"
- "K5\n")
-{
- // struct eigrp *eigrp = vty->index;
- /*TODO: */
-
- return CMD_SUCCESS;
-}
-
-DEFUN (no_eigrp_metric_weights,
- no_eigrp_metric_weights_cmd,
- "no metric weights (0-255) (0-255) (0-255) (0-255) (0-255)",
- NO_STR
- "Modify metrics and parameters for advertisement\n"
- "Modify metric coefficients\n"
- "K1\n"
- "K2\n"
- "K3\n"
- "K4\n"
- "K5\n")
-{
- // struct eigrp *eigrp = vty->index;
- /*TODO: */
-
- return CMD_SUCCESS;
-}
-
-
-DEFUN (eigrp_network,
- eigrp_network_cmd,
- "network A.B.C.D/M",
- "Enable routing on an IP network\n"
- "EIGRP network prefix\n")
-{
- VTY_DECLVAR_CONTEXT(eigrp, eigrp);
- struct prefix p;
- int ret;
-
- (void)str2prefix(argv[1]->arg, &p);
-
- ret = eigrp_network_set(eigrp, &p);
-
- if (ret == 0) {
- vty_out(vty, "There is already same network statement.\n");
- return CMD_WARNING;
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN (no_eigrp_network,
- no_eigrp_network_cmd,
- "no network A.B.C.D/M",
- NO_STR
- "Disable routing on an IP network\n"
- "EIGRP network prefix\n")
-{
- VTY_DECLVAR_CONTEXT(eigrp, eigrp);
- struct prefix p;
- int ret;
-
- (void)str2prefix(argv[2]->arg, &p);
-
- ret = eigrp_network_unset(eigrp, &p);
-
- if (ret == 0) {
- vty_out(vty, "Can't find specified network configuration.\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN (eigrp_neighbor,
- eigrp_neighbor_cmd,
- "neighbor A.B.C.D",
- "Specify a neighbor router\n"
- "Neighbor address\n")
-{
- // struct eigrp *eigrp = vty->index;
-
- return CMD_SUCCESS;
-}
-
-DEFUN (no_eigrp_neighbor,
- no_eigrp_neighbor_cmd,
- "no neighbor A.B.C.D",
- NO_STR
- "Specify a neighbor router\n"
- "Neighbor address\n")
-{
- // struct eigrp *eigrp = vty->index;
-
- return CMD_SUCCESS;
-}
-
static void eigrp_vty_display_prefix_entry(struct vty *vty,
struct eigrp *eigrp,
struct eigrp_prefix_entry *pe,
@@ -650,585 +254,6 @@ DEFUN (show_ip_eigrp_neighbors,
return CMD_SUCCESS;
}
-DEFUN (eigrp_if_delay,
- eigrp_if_delay_cmd,
- "delay (1-16777215)",
- "Specify interface throughput delay\n"
- "Throughput delay (tens of microseconds)\n")
-{
- VTY_DECLVAR_CONTEXT(interface, ifp);
- struct eigrp_interface *ei = ifp->info;
- struct eigrp *eigrp;
- uint32_t delay;
-
- eigrp = eigrp_lookup();
- if (eigrp == NULL) {
- vty_out(vty, " EIGRP Routing Process not enabled\n");
-
- return CMD_SUCCESS;
- }
-
- if (!ei) {
- vty_out(vty, " EIGRP not configured on this interface\n");
- return CMD_SUCCESS;
- }
- delay = atoi(argv[1]->arg);
-
- ei->params.delay = delay;
- eigrp_if_reset(ifp);
-
- return CMD_SUCCESS;
-}
-
-DEFUN (no_eigrp_if_delay,
- no_eigrp_if_delay_cmd,
- "no delay (1-16777215)",
- NO_STR
- "Specify interface throughput delay\n"
- "Throughput delay (tens of microseconds)\n")
-{
- VTY_DECLVAR_CONTEXT(interface, ifp);
- struct eigrp_interface *ei = ifp->info;
- struct eigrp *eigrp;
-
- eigrp = eigrp_lookup();
- if (eigrp == NULL) {
- vty_out(vty, " EIGRP Routing Process not enabled\n");
-
- return CMD_SUCCESS;
- }
- if (!ei) {
- vty_out(vty, " EIGRP not configured on this interface\n");
- return CMD_SUCCESS;
- }
-
- ei->params.delay = EIGRP_DELAY_DEFAULT;
- eigrp_if_reset(ifp);
-
- return CMD_SUCCESS;
-}
-
-DEFPY (eigrp_if_bandwidth,
- eigrp_if_bandwidth_cmd,
- "eigrp bandwidth (1-10000000)$bw",
- "EIGRP specific commands\n"
- "Set bandwidth informational parameter\n"
- "Bandwidth in kilobits\n")
-{
- VTY_DECLVAR_CONTEXT(interface, ifp);
- struct eigrp_interface *ei = ifp->info;
- struct eigrp *eigrp;
-
- eigrp = eigrp_lookup();
- if (eigrp == NULL) {
- vty_out(vty, " EIGRP Routing Process not enabled\n");
- return CMD_SUCCESS;
- }
-
- if (!ei) {
- vty_out(vty, " EIGRP not configured on this interface\n");
- return CMD_SUCCESS;
- }
-
- ei->params.bandwidth = bw;
- eigrp_if_reset(ifp);
-
- return CMD_SUCCESS;
-}
-
-DEFUN (no_eigrp_if_bandwidth,
- no_eigrp_if_bandwidth_cmd,
- "no eigrp bandwidth [(1-10000000)]",
- NO_STR
- "EIGRP specific commands\n"
- "Set bandwidth informational parameter\n"
- "Bandwidth in kilobits\n")
-{
- VTY_DECLVAR_CONTEXT(interface, ifp);
- struct eigrp_interface *ei = ifp->info;
- struct eigrp *eigrp;
-
- eigrp = eigrp_lookup();
- if (eigrp == NULL) {
- vty_out(vty, " EIGRP Routing Process not enabled\n");
- return CMD_SUCCESS;
- }
-
- if (!ei) {
- vty_out(vty, " EIGRP not configured on this interface\n");
- return CMD_SUCCESS;
- }
-
- ei->params.bandwidth = EIGRP_BANDWIDTH_DEFAULT;
- eigrp_if_reset(ifp);
-
- return CMD_SUCCESS;
-}
-
-DEFUN (eigrp_if_ip_hellointerval,
- eigrp_if_ip_hellointerval_cmd,
- "ip hello-interval eigrp (1-65535)",
- "Interface Internet Protocol config commands\n"
- "Configures EIGRP hello interval\n"
- "Enhanced Interior Gateway Routing Protocol (EIGRP)\n"
- "Seconds between hello transmissions\n")
-{
- VTY_DECLVAR_CONTEXT(interface, ifp);
- struct eigrp_interface *ei = ifp->info;
- uint32_t hello;
- struct eigrp *eigrp;
-
- eigrp = eigrp_lookup();
- if (eigrp == NULL) {
- vty_out(vty, " EIGRP Routing Process not enabled\n");
- return CMD_SUCCESS;
- }
-
- if (!ei) {
- vty_out(vty, " EIGRP not configured on this interface\n");
- return CMD_SUCCESS;
- }
-
- hello = atoi(argv[3]->arg);
-
- ei->params.v_hello = hello;
-
- return CMD_SUCCESS;
-}
-
-DEFUN (no_eigrp_if_ip_hellointerval,
- no_eigrp_if_ip_hellointerval_cmd,
- "no ip hello-interval eigrp [(1-65535)]",
- NO_STR
- "Interface Internet Protocol config commands\n"
- "Configures EIGRP hello interval\n"
- "Enhanced Interior Gateway Routing Protocol (EIGRP)\n"
- "Seconds between hello transmissions\n")
-{
- VTY_DECLVAR_CONTEXT(interface, ifp);
- struct eigrp_interface *ei = ifp->info;
- struct eigrp *eigrp;
-
- eigrp = eigrp_lookup();
- if (eigrp == NULL) {
- vty_out(vty, " EIGRP Routing Process not enabled\n");
- return CMD_SUCCESS;
- }
-
- if (!ei) {
- vty_out(vty, " EIGRP not configured on this interface\n");
- return CMD_SUCCESS;
- }
-
- ei->params.v_hello = EIGRP_HELLO_INTERVAL_DEFAULT;
-
- THREAD_TIMER_OFF(ei->t_hello);
- thread_add_timer(master, eigrp_hello_timer, ei, 1, &ei->t_hello);
-
- return CMD_SUCCESS;
-}
-
-DEFUN (eigrp_if_ip_holdinterval,
- eigrp_if_ip_holdinterval_cmd,
- "ip hold-time eigrp (1-65535)",
- "Interface Internet Protocol config commands\n"
- "Configures EIGRP IPv4 hold time\n"
- "Enhanced Interior Gateway Routing Protocol (EIGRP)\n"
- "Seconds before neighbor is considered down\n")
-{
- VTY_DECLVAR_CONTEXT(interface, ifp);
- struct eigrp_interface *ei = ifp->info;
- uint32_t hold;
- struct eigrp *eigrp;
-
- eigrp = eigrp_lookup();
- if (eigrp == NULL) {
- vty_out(vty, " EIGRP Routing Process not enabled\n");
- return CMD_SUCCESS;
- }
-
- if (!ei) {
- vty_out(vty, " EIGRP not configured on this interface\n");
- return CMD_SUCCESS;
- }
-
- hold = atoi(argv[3]->arg);
-
- ei->params.v_wait = hold;
-
- return CMD_SUCCESS;
-}
-
-DEFUN (eigrp_ip_summary_address,
- eigrp_ip_summary_address_cmd,
- "ip summary-address eigrp (1-65535) A.B.C.D/M",
- "Interface Internet Protocol config commands\n"
- "Perform address summarization\n"
- "Enhanced Interior Gateway Routing Protocol (EIGRP)\n"
- "AS number\n"
- "Summary <network>/<length>, e.g. 192.168.0.0/16\n")
-{
- // VTY_DECLVAR_CONTEXT(interface, ifp);
- // uint32_t AS;
- struct eigrp *eigrp;
-
- eigrp = eigrp_lookup();
- if (eigrp == NULL) {
- vty_out(vty, " EIGRP Routing Process not enabled\n");
- return CMD_SUCCESS;
- }
-
- // AS = atoi (argv[3]->arg);
-
- /*TODO: */
-
- return CMD_SUCCESS;
-}
-
-DEFUN (no_eigrp_ip_summary_address,
- no_eigrp_ip_summary_address_cmd,
- "no ip summary-address eigrp (1-65535) A.B.C.D/M",
- NO_STR
- "Interface Internet Protocol config commands\n"
- "Perform address summarization\n"
- "Enhanced Interior Gateway Routing Protocol (EIGRP)\n"
- "AS number\n"
- "Summary <network>/<length>, e.g. 192.168.0.0/16\n")
-{
- // VTY_DECLVAR_CONTEXT(interface, ifp);
- // uint32_t AS;
- struct eigrp *eigrp;
-
- eigrp = eigrp_lookup();
- if (eigrp == NULL) {
- vty_out(vty, " EIGRP Routing Process not enabled\n");
- return CMD_SUCCESS;
- }
-
- // AS = atoi (argv[4]->arg);
-
- /*TODO: */
-
- return CMD_SUCCESS;
-}
-
-DEFUN (no_eigrp_if_ip_holdinterval,
- no_eigrp_if_ip_holdinterval_cmd,
- "no ip hold-time eigrp",
- NO_STR
- "Interface Internet Protocol config commands\n"
- "Configures EIGRP hello interval\n"
- "Enhanced Interior Gateway Routing Protocol (EIGRP)\n")
-{
- VTY_DECLVAR_CONTEXT(interface, ifp);
- struct eigrp_interface *ei = ifp->info;
- struct eigrp *eigrp;
-
- eigrp = eigrp_lookup();
- if (eigrp == NULL) {
- vty_out(vty, " EIGRP Routing Process not enabled\n");
- return CMD_SUCCESS;
- }
-
- if (!ei) {
- vty_out(vty, " EIGRP not configured on this interface\n");
- return CMD_SUCCESS;
- }
-
- ei->params.v_wait = EIGRP_HOLD_INTERVAL_DEFAULT;
-
- return CMD_SUCCESS;
-}
-
-static int str2auth_type(const char *str, struct eigrp_interface *ei)
-{
- /* Sanity check. */
- if (str == NULL)
- return CMD_WARNING_CONFIG_FAILED;
-
- if (strncmp(str, "md5", 3) == 0) {
- ei->params.auth_type = EIGRP_AUTH_TYPE_MD5;
- return CMD_SUCCESS;
- } else if (strncmp(str, "hmac-sha-256", 12) == 0) {
- ei->params.auth_type = EIGRP_AUTH_TYPE_SHA256;
- return CMD_SUCCESS;
- }
-
- return CMD_WARNING_CONFIG_FAILED;
-}
-
-DEFUN (eigrp_authentication_mode,
- eigrp_authentication_mode_cmd,
- "ip authentication mode eigrp (1-65535) <md5|hmac-sha-256>",
- "Interface Internet Protocol config commands\n"
- "Authentication subcommands\n"
- "Mode\n"
- "Enhanced Interior Gateway Routing Protocol (EIGRP)\n"
- "Autonomous system number\n"
- "Keyed message digest\n"
- "HMAC SHA256 algorithm \n")
-{
- VTY_DECLVAR_CONTEXT(interface, ifp);
- struct eigrp_interface *ei = ifp->info;
- struct eigrp *eigrp;
-
- eigrp = eigrp_lookup();
- if (eigrp == NULL) {
- vty_out(vty, " EIGRP Routing Process not enabled\n");
- return CMD_SUCCESS;
- }
-
- if (!ei) {
- vty_out(vty, " EIGRP not configured on this interface\n");
- return CMD_SUCCESS;
- }
-
- // if(strncmp(argv[2], "md5",3))
- // IF_DEF_PARAMS (ifp)->auth_type = EIGRP_AUTH_TYPE_MD5;
- // else if(strncmp(argv[2], "hmac-sha-256",12))
- // IF_DEF_PARAMS (ifp)->auth_type = EIGRP_AUTH_TYPE_SHA256;
-
- return str2auth_type(argv[5]->arg, ei);
-}
-
-DEFUN (no_eigrp_authentication_mode,
- no_eigrp_authentication_mode_cmd,
- "no ip authentication mode eigrp (1-65535) <md5|hmac-sha-256>",
- "Disable\n"
- "Interface Internet Protocol config commands\n"
- "Authentication subcommands\n"
- "Mode\n"
- "Enhanced Interior Gateway Routing Protocol (EIGRP)\n"
- "Autonomous system number\n"
- "Keyed message digest\n"
- "HMAC SHA256 algorithm \n")
-{
- VTY_DECLVAR_CONTEXT(interface, ifp);
- struct eigrp_interface *ei = ifp->info;
- struct eigrp *eigrp;
-
- eigrp = eigrp_lookup();
- if (eigrp == NULL) {
- vty_out(vty, " EIGRP Routing Process not enabled\n");
- return CMD_SUCCESS;
- }
-
- if (!ei) {
- vty_out(vty, " EIGRP not configured on this interface\n");
- return CMD_SUCCESS;
- }
-
- ei->params.auth_type = EIGRP_AUTH_TYPE_NONE;
-
- return CMD_SUCCESS;
-}
-
-DEFPY (eigrp_authentication_keychain,
- eigrp_authentication_keychain_cmd,
- "[no] ip authentication key-chain eigrp (1-65535)$as WORD$name",
- NO_STR
- "Interface Internet Protocol config commands\n"
- "Authentication subcommands\n"
- "Key-chain\n"
- "Enhanced Interior Gateway Routing Protocol (EIGRP)\n"
- "Autonomous system number\n"
- "Name of key-chain\n")
-{
- VTY_DECLVAR_CONTEXT(interface, ifp);
- struct eigrp_interface *ei = ifp->info;
- struct eigrp *eigrp;
- struct keychain *keychain;
-
- eigrp = eigrp_lookup();
- if (eigrp == NULL) {
- vty_out(vty, "EIGRP Routing Process not enabled\n");
- return CMD_SUCCESS;
- }
-
- if (!ei) {
- vty_out(vty, " EIGRP not configured on this interface\n");
- return CMD_SUCCESS;
- }
-
- if (no) {
- if ((ei->params.auth_keychain != NULL)
- && (strcmp(ei->params.auth_keychain, name) == 0)) {
- free(ei->params.auth_keychain);
- ei->params.auth_keychain = NULL;
- } else
- vty_out(vty,
- "Key chain with specified name not configured on interface\n");
- return CMD_SUCCESS;
- }
-
- keychain = keychain_lookup(name);
- if (keychain != NULL) {
- if (ei->params.auth_keychain) {
- free(ei->params.auth_keychain);
- ei->params.auth_keychain = strdup(keychain->name);
- } else
- ei->params.auth_keychain = strdup(keychain->name);
- } else {
- vty_out(vty,
- "Key chain with specified name not found\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN (eigrp_redistribute_source_metric,
- eigrp_redistribute_source_metric_cmd,
- "redistribute " FRR_REDIST_STR_EIGRPD
- " [metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535)]",
- REDIST_STR
- FRR_REDIST_HELP_STR_EIGRPD
- "Metric for redistributed routes\n"
- "Bandwidth metric in Kbits per second\n"
- "EIGRP delay metric, in 10 microsecond units\n"
- "EIGRP reliability metric where 255 is 100% reliable2 ?\n"
- "EIGRP Effective bandwidth metric (Loading) where 255 is 100% loaded\n"
- "EIGRP MTU of the path\n")
-{
- VTY_DECLVAR_CONTEXT(eigrp, eigrp);
- struct eigrp_metrics metrics_from_command = {0};
- int source;
- int idx = 0;
-
- /* Get distribute source. */
- argv_find(argv, argc, "redistribute", &idx);
- source = proto_redistnum(AFI_IP, argv[idx + 1]->text);
- if (source < 0) {
- vty_out(vty, "%% Invalid route type\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- /* Get metrics values */
-
- return eigrp_redistribute_set(eigrp, source, metrics_from_command);
-}
-
-DEFUN (no_eigrp_redistribute_source_metric,
- no_eigrp_redistribute_source_metric_cmd,
- "no redistribute " FRR_REDIST_STR_EIGRPD
- " [metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535)]",
- "Disable\n"
- REDIST_STR
- FRR_REDIST_HELP_STR_EIGRPD
- "Metric for redistributed routes\n"
- "Bandwidth metric in Kbits per second\n"
- "EIGRP delay metric, in 10 microsecond units\n"
- "EIGRP reliability metric where 255 is 100% reliable2 ?\n"
- "EIGRP Effective bandwidth metric (Loading) where 255 is 100% loaded\n"
- "EIGRP MTU of the path\n")
-{
- VTY_DECLVAR_CONTEXT(eigrp, eigrp);
- int source;
- int idx = 0;
-
- /* Get distribute source. */
- argv_find(argv, argc, "redistribute", &idx);
- source = proto_redistnum(AFI_IP, argv[idx + 1]->text);
- if (source < 0) {
- vty_out(vty, "%% Invalid route type\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- /* Get metrics values */
-
- return eigrp_redistribute_unset(eigrp, source);
-}
-
-DEFUN (eigrp_variance,
- eigrp_variance_cmd,
- "variance (1-128)",
- "Control load balancing variance\n"
- "Metric variance multiplier\n")
-{
- struct eigrp *eigrp;
- uint8_t variance;
-
- eigrp = eigrp_lookup();
- if (eigrp == NULL) {
- vty_out(vty, "EIGRP Routing Process not enabled\n");
- return CMD_SUCCESS;
- }
- variance = atoi(argv[1]->arg);
-
- eigrp->variance = variance;
-
- /*TODO: */
-
- return CMD_SUCCESS;
-}
-
-DEFUN (no_eigrp_variance,
- no_eigrp_variance_cmd,
- "no variance (1-128)",
- "Disable\n"
- "Control load balancing variance\n"
- "Metric variance multiplier\n")
-{
- struct eigrp *eigrp;
- eigrp = eigrp_lookup();
- if (eigrp == NULL) {
- vty_out(vty, "EIGRP Routing Process not enabled\n");
- return CMD_SUCCESS;
- }
-
- eigrp->variance = EIGRP_VARIANCE_DEFAULT;
-
- /*TODO: */
-
- return CMD_SUCCESS;
-}
-
-DEFUN (eigrp_maximum_paths,
- eigrp_maximum_paths_cmd,
- "maximum-paths (1-32)",
- "Forward packets over multiple paths\n"
- "Number of paths\n")
-{
- struct eigrp *eigrp;
- uint8_t max;
-
- eigrp = eigrp_lookup();
- if (eigrp == NULL) {
- vty_out(vty, "EIGRP Routing Process not enabled\n");
- return CMD_SUCCESS;
- }
-
- max = atoi(argv[1]->arg);
-
- eigrp->max_paths = max;
-
- /*TODO: */
-
- return CMD_SUCCESS;
-}
-
-DEFUN (no_eigrp_maximum_paths,
- no_eigrp_maximum_paths_cmd,
- "no maximum-paths (1-32)",
- NO_STR
- "Forward packets over multiple paths\n"
- "Number of paths\n")
-{
- struct eigrp *eigrp;
-
- eigrp = eigrp_lookup();
- if (eigrp == NULL) {
- vty_out(vty, "EIGRP Routing Process not enabled\n");
- return CMD_SUCCESS;
- }
-
- eigrp->max_paths = EIGRP_MAX_PATHS_DEFAULT;
-
- /*TODO: */
-
- return CMD_SUCCESS;
-}
-
/*
* Execute hard restart for all neighbors
*/
@@ -1492,40 +517,6 @@ DEFUN (clear_ip_eigrp_neighbors_IP_soft,
return CMD_SUCCESS;
}
-static struct cmd_node eigrp_node = {EIGRP_NODE, "%s(config-router)# ", 1};
-
-/* Save EIGRP configuration */
-static int eigrp_config_write(struct vty *vty)
-{
- struct eigrp *eigrp;
-
- eigrp = eigrp_lookup();
- if (eigrp != NULL) {
- /* Writes 'router eigrp' section to config */
- config_write_eigrp_router(vty, eigrp);
-
- /* Interface config print */
- config_write_interfaces(vty, eigrp);
- //
- // /* static neighbor print. */
- // config_write_eigrp_nbr_nbma (vty, eigrp);
- //
- // /* Virtual-Link print. */
- // config_write_virtual_link (vty, eigrp);
- //
- // /* Default metric configuration. */
- // config_write_eigrp_default_metric (vty, eigrp);
- //
- // /* Distribute-list and default-information print. */
- // config_write_eigrp_distribute (vty, eigrp);
- //
- // /* Distance configuration. */
- // config_write_eigrp_distance (vty, eigrp)
- }
-
- return 0;
-}
-
void eigrp_vty_show_init(void)
{
install_element(VIEW_NODE, &show_ip_eigrp_interfaces_cmd);
@@ -1536,69 +527,9 @@ void eigrp_vty_show_init(void)
install_element(VIEW_NODE, &show_ip_eigrp_topology_all_cmd);
}
-/* eigrpd's interface node. */
-static struct cmd_node eigrp_interface_node = {INTERFACE_NODE,
- "%s(config-if)# ", 1};
-
-void eigrp_vty_if_init(void)
-{
- install_node(&eigrp_interface_node, eigrp_write_interface);
- if_cmd_init();
-
- /* Delay and bandwidth configuration commands*/
- install_element(INTERFACE_NODE, &eigrp_if_delay_cmd);
- install_element(INTERFACE_NODE, &no_eigrp_if_delay_cmd);
- install_element(INTERFACE_NODE, &eigrp_if_bandwidth_cmd);
- install_element(INTERFACE_NODE, &no_eigrp_if_bandwidth_cmd);
-
- /*Hello-interval and hold-time interval configuration commands*/
- install_element(INTERFACE_NODE, &eigrp_if_ip_holdinterval_cmd);
- install_element(INTERFACE_NODE, &no_eigrp_if_ip_holdinterval_cmd);
- install_element(INTERFACE_NODE, &eigrp_if_ip_hellointerval_cmd);
- install_element(INTERFACE_NODE, &no_eigrp_if_ip_hellointerval_cmd);
-
- /* "Authentication configuration commands */
- install_element(INTERFACE_NODE, &eigrp_authentication_mode_cmd);
- install_element(INTERFACE_NODE, &no_eigrp_authentication_mode_cmd);
- install_element(INTERFACE_NODE, &eigrp_authentication_keychain_cmd);
-
- /*EIGRP Summarization commands*/
- install_element(INTERFACE_NODE, &eigrp_ip_summary_address_cmd);
- install_element(INTERFACE_NODE, &no_eigrp_ip_summary_address_cmd);
-}
-
-static void eigrp_vty_zebra_init(void)
-{
- install_element(EIGRP_NODE, &eigrp_redistribute_source_metric_cmd);
- install_element(EIGRP_NODE, &no_eigrp_redistribute_source_metric_cmd);
-}
-
/* Install EIGRP related vty commands. */
void eigrp_vty_init(void)
{
- install_node(&eigrp_node, eigrp_config_write);
-
- install_default(EIGRP_NODE);
-
- install_element(CONFIG_NODE, &router_eigrp_cmd);
- install_element(CONFIG_NODE, &no_router_eigrp_cmd);
- install_element(EIGRP_NODE, &eigrp_network_cmd);
- install_element(EIGRP_NODE, &no_eigrp_network_cmd);
- install_element(EIGRP_NODE, &eigrp_variance_cmd);
- install_element(EIGRP_NODE, &no_eigrp_variance_cmd);
- install_element(EIGRP_NODE, &eigrp_router_id_cmd);
- install_element(EIGRP_NODE, &no_eigrp_router_id_cmd);
- install_element(EIGRP_NODE, &eigrp_passive_interface_cmd);
- install_element(EIGRP_NODE, &no_eigrp_passive_interface_cmd);
- install_element(EIGRP_NODE, &eigrp_timers_active_cmd);
- install_element(EIGRP_NODE, &no_eigrp_timers_active_cmd);
- install_element(EIGRP_NODE, &eigrp_metric_weights_cmd);
- install_element(EIGRP_NODE, &no_eigrp_metric_weights_cmd);
- install_element(EIGRP_NODE, &eigrp_maximum_paths_cmd);
- install_element(EIGRP_NODE, &no_eigrp_maximum_paths_cmd);
- install_element(EIGRP_NODE, &eigrp_neighbor_cmd);
- install_element(EIGRP_NODE, &no_eigrp_neighbor_cmd);
-
/* commands for manual hard restart */
install_element(ENABLE_NODE, &clear_ip_eigrp_neighbors_cmd);
install_element(ENABLE_NODE, &clear_ip_eigrp_neighbors_int_cmd);
@@ -1607,6 +538,4 @@ void eigrp_vty_init(void)
install_element(ENABLE_NODE, &clear_ip_eigrp_neighbors_soft_cmd);
install_element(ENABLE_NODE, &clear_ip_eigrp_neighbors_int_soft_cmd);
install_element(ENABLE_NODE, &clear_ip_eigrp_neighbors_IP_soft_cmd);
-
- eigrp_vty_zebra_init();
}
diff --git a/eigrpd/eigrp_vty.h b/eigrpd/eigrp_vty.h
index 3fbadf6dfb..ebbf503857 100644
--- a/eigrpd/eigrp_vty.h
+++ b/eigrpd/eigrp_vty.h
@@ -35,6 +35,5 @@
/* Prototypes. */
extern void eigrp_vty_init(void);
extern void eigrp_vty_show_init(void);
-extern void eigrp_vty_if_init(void);
#endif /* _Quagga_EIGRP_VTY_H_ */
diff --git a/eigrpd/eigrpd.h b/eigrpd/eigrpd.h
index de7c881ac0..3ef3a9c0cc 100644
--- a/eigrpd/eigrpd.h
+++ b/eigrpd/eigrpd.h
@@ -52,4 +52,51 @@ extern struct eigrp *eigrp_get(const char *);
extern struct eigrp *eigrp_lookup(void);
extern void eigrp_router_id_update(struct eigrp *);
+/* eigrp_cli.c */
+extern void eigrp_cli_show_header(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_show_end_header(struct vty *vty, struct lyd_node *dnode);
+extern void eigrp_cli_show_router_id(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_show_passive_interface(struct vty *vty,
+ struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_show_active_time(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_show_variance(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_show_maximum_paths(struct vty *vty,
+ struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_show_metrics(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_show_network(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_show_neighbor(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_show_redistribute(struct vty *vty,
+ struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_show_delay(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_show_bandwidth(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_show_hello_interval(struct vty *vty,
+ struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_show_hold_time(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_show_summarize_address(struct vty *vty,
+ struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_show_authentication(struct vty *vty,
+ struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_show_keychain(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_init(void);
+
+/* eigrp_northbound.c */
+extern const struct frr_yang_module_info frr_eigrpd_info;
+
#endif /* _ZEBRA_EIGRPD_H */
diff --git a/eigrpd/subdir.am b/eigrpd/subdir.am
index 4503030fdf..cc46766586 100644
--- a/eigrpd/subdir.am
+++ b/eigrpd/subdir.am
@@ -7,6 +7,7 @@ noinst_LIBRARIES += eigrpd/libeigrp.a
sbin_PROGRAMS += eigrpd/eigrpd
dist_examples_DATA += eigrpd/eigrpd.conf.sample
vtysh_scan += \
+ $(top_srcdir)/eigrpd/eigrp_cli.c \
$(top_srcdir)/eigrpd/eigrp_dump.c \
$(top_srcdir)/eigrpd/eigrp_vty.c \
# end
@@ -15,6 +16,7 @@ man8 += $(MANBUILD)/eigrpd.8
endif
eigrpd_libeigrp_a_SOURCES = \
+ eigrpd/eigrp_cli.c \
eigrpd/eigrp_dump.c \
eigrpd/eigrp_errors.c \
eigrpd/eigrp_filter.c \
@@ -24,6 +26,7 @@ eigrpd_libeigrp_a_SOURCES = \
eigrpd/eigrp_memory.c \
eigrpd/eigrp_neighbor.c \
eigrpd/eigrp_network.c \
+ eigrpd/eigrp_northbound.c \
eigrpd/eigrp_packet.c \
eigrpd/eigrp_query.c \
eigrpd/eigrp_reply.c \
@@ -47,6 +50,9 @@ eigrpdheader_HEADERS = \
eigrpd/eigrp_vty_clippy.c: $(CLIPPY_DEPS)
eigrpd/eigrp_vty.$(OBJEXT): eigrpd/eigrp_vty_clippy.c
+eigrpd/eigrp_cli_clippy.c: $(CLIPPY_DEPS)
+eigrpd/eigrp_cli.$(OBJEXT): eigrpd/eigrp_cli_clippy.c
+
noinst_HEADERS += \
eigrpd/eigrp_const.h \
eigrpd/eigrp_errors.h \
@@ -64,5 +70,9 @@ noinst_HEADERS += \
eigrpd/eigrp_zebra.h \
# end
+nodist_eigrpd_eigrpd_SOURCES = \
+ yang/frr-eigrpd.yang.c \
+ # end
+
eigrpd_eigrpd_SOURCES = eigrpd/eigrp_main.c
eigrpd_eigrpd_LDADD = eigrpd/libeigrp.a lib/libfrr.la $(LIBCAP)
diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c
index 4b43260773..bd06286755 100644
--- a/isisd/isis_cli.c
+++ b/isisd/isis_cli.c
@@ -363,7 +363,7 @@ void cli_show_ip_isis_bfd_monitoring(struct vty *vty, struct lyd_node *dnode,
if (!yang_dnode_get_bool(dnode, NULL))
vty_out(vty, " no");
- vty_out(vty, "isis bfd\n");
+ vty_out(vty, " isis bfd\n");
}
/*
diff --git a/isisd/isis_misc.c b/isisd/isis_misc.c
index 3ad8278e10..a7f491e87d 100644
--- a/isisd/isis_misc.c
+++ b/isisd/isis_misc.c
@@ -117,7 +117,8 @@ int dotformat2buff(uint8_t *buff, const char *dotted)
break;
}
- if ((isxdigit((int)*pos)) && (isxdigit((int)*(pos + 1)))) {
+ if ((isxdigit((unsigned char)*pos)) &&
+ (isxdigit((unsigned char)*(pos + 1)))) {
memcpy(number, pos, 2);
pos += 2;
} else {
@@ -157,7 +158,8 @@ int sysid2buff(uint8_t *buff, const char *dotted)
pos++;
continue;
}
- if ((isxdigit((int)*pos)) && (isxdigit((int)*(pos + 1)))) {
+ if ((isxdigit((unsigned char)*pos)) &&
+ (isxdigit((unsigned char)*(pos + 1)))) {
memcpy(number, pos, 2);
pos += 2;
} else {
diff --git a/isisd/isis_routemap.c b/isisd/isis_routemap.c
index d63676256b..eb9b661d37 100644
--- a/isisd/isis_routemap.c
+++ b/isisd/isis_routemap.c
@@ -48,10 +48,9 @@
#include "isis_zebra.h"
#include "isis_routemap.h"
-static route_map_result_t route_match_ip_address(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_ip_address(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct access_list *alist;
@@ -81,7 +80,7 @@ static struct route_map_rule_cmd route_match_ip_address_cmd = {
/* ------------------------------------------------------------*/
-static route_map_result_t
+static enum route_map_cmd_result_t
route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -114,10 +113,9 @@ struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = {
/* ------------------------------------------------------------*/
-static route_map_result_t route_match_ipv6_address(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_ipv6_address(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct access_list *alist;
@@ -147,7 +145,7 @@ static struct route_map_rule_cmd route_match_ipv6_address_cmd = {
/* ------------------------------------------------------------*/
-static route_map_result_t
+static enum route_map_cmd_result_t
route_match_ipv6_address_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -180,10 +178,9 @@ struct route_map_rule_cmd route_match_ipv6_address_prefix_list_cmd = {
/* ------------------------------------------------------------*/
-static route_map_result_t route_set_metric(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_set_metric(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
uint32_t *metric;
struct isis_ext_info *info;
diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c
index 6edfeb4c97..488dfedae4 100644
--- a/isisd/isis_tlvs.c
+++ b/isisd/isis_tlvs.c
@@ -1478,7 +1478,7 @@ static int unpack_tlv_dynamic_hostname(enum isis_tlv_context context,
bool sane = true;
for (uint8_t i = 0; i < tlv_len; i++) {
if ((unsigned char)tlvs->hostname[i] > 127
- || !isprint((int)tlvs->hostname[i])) {
+ || !isprint((unsigned char)tlvs->hostname[i])) {
sane = false;
tlvs->hostname[i] = '?';
}
diff --git a/ldpd/lde.c b/ldpd/lde.c
index 0ddf4f07d9..ac680b47a9 100644
--- a/ldpd/lde.c
+++ b/ldpd/lde.c
@@ -1654,6 +1654,19 @@ lde_del_label_chunk(void *val)
}
static int
+lde_release_label_chunk(uint32_t start, uint32_t end)
+{
+ int ret;
+
+ ret = lm_release_label_chunk(zclient_sync, start, end);
+ if (ret < 0) {
+ log_warnx("Error releasing label chunk!");
+ return (-1);
+ }
+ return (0);
+}
+
+static int
lde_get_label_chunk(void)
{
int ret;
@@ -1709,6 +1722,32 @@ on_get_label_chunk_response(uint32_t start, uint32_t end)
current_label_chunk = listtail(label_chunk_list);
}
+void
+lde_free_label(uint32_t label)
+{
+ struct listnode *node;
+ struct label_chunk *label_chunk;
+ uint64_t pos;
+
+ for (ALL_LIST_ELEMENTS_RO(label_chunk_list, node, label_chunk)) {
+ if (label <= label_chunk->end && label >= label_chunk->start) {
+ pos = 1ULL << (label - label_chunk->start);
+ label_chunk->used_mask &= ~pos;
+ /* if nobody is using this chunk and it's not current_label_chunk, then free it */
+ if (!label_chunk->used_mask && (current_label_chunk != node)) {
+ if (lde_release_label_chunk(label_chunk->start, label_chunk->end) != 0)
+ log_warnx("%s: Error releasing label chunk!", __func__);
+ else {
+ listnode_delete(label_chunk_list, label_chunk);
+ lde_del_label_chunk(label_chunk);
+ }
+ }
+ break;
+ }
+ }
+ return;
+}
+
static uint32_t
lde_get_next_label(void)
{
diff --git a/ldpd/lde.h b/ldpd/lde.h
index 94077d1631..0a7d0a58fe 100644
--- a/ldpd/lde.h
+++ b/ldpd/lde.h
@@ -147,6 +147,7 @@ void lde_imsg_compose_parent_sync(int, pid_t, void *, uint16_t);
int lde_imsg_compose_ldpe(int, uint32_t, pid_t, void *, uint16_t);
int lde_acl_check(char *, int, union ldpd_addr *, uint8_t);
uint32_t lde_update_label(struct fec_node *);
+void lde_free_label(uint32_t label);
void lde_send_change_klabel(struct fec_node *, struct fec_nh *);
void lde_send_delete_klabel(struct fec_node *, struct fec_nh *);
void lde_fec2map(struct fec *, struct map *);
diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c
index 28e455c7a5..0957a5455e 100644
--- a/ldpd/lde_lib.c
+++ b/ldpd/lde_lib.c
@@ -919,6 +919,9 @@ lde_gc_timer(struct thread *thread)
!RB_EMPTY(lde_map_head, &fn->upstream))
continue;
+ if (fn->local_label != NO_LABEL)
+ lde_free_label(fn->local_label);
+
fec_remove(&ft, &fn->fec);
free(fn);
count++;
diff --git a/lib/atomlist.h b/lib/atomlist.h
index e4098ccb54..621db6824f 100644
--- a/lib/atomlist.h
+++ b/lib/atomlist.h
@@ -135,8 +135,10 @@ macro_inline void prefix ## _add_tail(struct prefix##_head *h, type *item) \
macro_inline void prefix ## _del_hint(struct prefix##_head *h, type *item, \
_Atomic atomptr_t *hint) \
{ atomlist_del_hint(&h->ah, &item->field.ai, hint); } \
-macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \
-{ atomlist_del_hint(&h->ah, &item->field.ai, NULL); } \
+macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
+{ atomlist_del_hint(&h->ah, &item->field.ai, NULL); \
+ /* TODO: Return NULL if not found */ \
+ return item; } \
macro_inline type *prefix ## _pop(struct prefix##_head *h) \
{ char *p = (char *)atomlist_pop(&h->ah); \
return p ? (type *)(p - offsetof(type, field)) : NULL; } \
@@ -273,9 +275,11 @@ macro_inline void prefix ## _del_hint(struct prefix##_head *h, type *item, \
{ \
atomsort_del_hint(&h->ah, &item->field.ai, hint); \
} \
-macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \
+macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
{ \
atomsort_del_hint(&h->ah, &item->field.ai, NULL); \
+ /* TODO: Return NULL if not found */ \
+ return item; \
} \
macro_inline size_t prefix ## _count(struct prefix##_head *h) \
{ \
diff --git a/lib/command.c b/lib/command.c
index c8fbf22721..9dabc2af7e 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -89,7 +89,6 @@ const char *node_names[] = {
"aaa", // AAA_NODE,
"keychain", // KEYCHAIN_NODE,
"keychain key", // KEYCHAIN_KEY_NODE,
- "logical-router", // LOGICALROUTER_NODE,
"static ip", // IP_NODE,
"vrf", // VRF_NODE,
"interface", // INTERFACE_NODE,
@@ -290,7 +289,7 @@ vector cmd_make_strvec(const char *string)
const char *copy = string;
/* skip leading whitespace */
- while (isspace((int)*copy) && *copy != '\0')
+ while (isspace((unsigned char)*copy) && *copy != '\0')
copy++;
/* if the entire string was whitespace or a comment, return */
@@ -1456,7 +1455,6 @@ void cmd_exit(struct vty *vty)
break;
case INTERFACE_NODE:
case PW_NODE:
- case LOGICALROUTER_NODE:
case VRF_NODE:
case NH_GROUP_NODE:
case ZEBRA_NODE:
@@ -1936,7 +1934,7 @@ DEFUN(config_domainname,
{
struct cmd_token *word = argv[1];
- if (!isalpha((int)word->arg[0])) {
+ if (!isalpha((unsigned char)word->arg[0])) {
vty_out(vty, "Please specify string starting with alphabet\n");
return CMD_WARNING_CONFIG_FAILED;
}
@@ -1970,7 +1968,7 @@ DEFUN (config_hostname,
{
struct cmd_token *word = argv[1];
- if (!isalnum((int)word->arg[0])) {
+ if (!isalnum((unsigned char)word->arg[0])) {
vty_out(vty,
"Please specify string starting with alphabet or number\n");
return CMD_WARNING_CONFIG_FAILED;
@@ -2018,7 +2016,7 @@ DEFUN (config_password,
return CMD_SUCCESS;
}
- if (!isalnum((int)argv[idx_8]->arg[0])) {
+ if (!isalnum((unsigned char)argv[idx_8]->arg[0])) {
vty_out(vty,
"Please specify string starting with alphanumeric\n");
return CMD_WARNING_CONFIG_FAILED;
@@ -2098,7 +2096,7 @@ DEFUN (config_enable_password,
}
}
- if (!isalnum((int)argv[idx_8]->arg[0])) {
+ if (!isalnum((unsigned char)argv[idx_8]->arg[0])) {
vty_out(vty,
"Please specify string starting with alphanumeric\n");
return CMD_WARNING_CONFIG_FAILED;
diff --git a/lib/command.h b/lib/command.h
index 08d6128af4..8dc35a0fdc 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -98,7 +98,6 @@ enum node_type {
AAA_NODE, /* AAA node. */
KEYCHAIN_NODE, /* Key-chain node. */
KEYCHAIN_KEY_NODE, /* Key-chain key node. */
- LOGICALROUTER_NODE, /* Logical-Router node. */
IP_NODE, /* Static ip route node. */
VRF_NODE, /* VRF mode node. */
INTERFACE_NODE, /* Interface mode node. */
diff --git a/lib/command_graph.c b/lib/command_graph.c
index 4757fd951f..d30d9ab702 100644
--- a/lib/command_graph.c
+++ b/lib/command_graph.c
@@ -97,7 +97,7 @@ void cmd_token_varname_set(struct cmd_token *token, const char *varname)
token->varname[i] = '_';
break;
default:
- token->varname[i] = tolower((int)varname[i]);
+ token->varname[i] = tolower((unsigned char)varname[i]);
}
token->varname[len] = '\0';
}
diff --git a/lib/command_match.c b/lib/command_match.c
index 9456e1585a..26d763849d 100644
--- a/lib/command_match.c
+++ b/lib/command_match.c
@@ -714,7 +714,7 @@ static enum match_type match_ipv4(const char *str)
dots++;
break;
}
- if (!isdigit((int)*str))
+ if (!isdigit((unsigned char)*str))
return no_match;
str++;
@@ -765,7 +765,7 @@ static enum match_type match_ipv4_prefix(const char *str)
break;
}
- if (!isdigit((int)*str))
+ if (!isdigit((unsigned char)*str))
return no_match;
str++;
@@ -797,7 +797,7 @@ static enum match_type match_ipv4_prefix(const char *str)
sp = str;
while (*str != '\0') {
- if (!isdigit((int)*str))
+ if (!isdigit((unsigned char)*str))
return no_match;
str++;
diff --git a/lib/compiler.h b/lib/compiler.h
index 7c7f4ce294..6700ca9e8b 100644
--- a/lib/compiler.h
+++ b/lib/compiler.h
@@ -165,6 +165,13 @@ extern "C" {
_min_a < _min_b ? _min_a : _min_b; \
})
+#define numcmp(a, b) \
+ ({ \
+ typeof(a) _cmp_a = (a); \
+ typeof(b) _cmp_b = (b); \
+ (_cmp_a < _cmp_b) ? -1 : ((_cmp_a > _cmp_b) ? 1 : 0); \
+ })
+
#ifndef offsetof
#ifdef __compiler_offsetof
#define offsetof(TYPE, MEMBER) __compiler_offsetof(TYPE,MEMBER)
diff --git a/lib/ferr.c b/lib/ferr.c
index 65c0cf886d..8afc926c41 100644
--- a/lib/ferr.c
+++ b/lib/ferr.c
@@ -126,10 +126,8 @@ void log_ref_display(struct vty *vty, uint32_t code, bool json)
if (code) {
ref = log_ref_get(code);
- if (!ref) {
- vty_out(vty, "Code %"PRIu32" - Unknown\n", code);
+ if (!ref)
return;
- }
listnode_add(errlist, ref);
}
@@ -197,8 +195,6 @@ void log_ref_init(void)
"Error Reference Texts");
}
pthread_mutex_unlock(&refs_mtx);
-
- install_element(VIEW_NODE, &show_error_code_cmd);
}
void log_ref_fini(void)
@@ -212,6 +208,12 @@ void log_ref_fini(void)
pthread_mutex_unlock(&refs_mtx);
}
+void log_ref_vty_init(void)
+{
+ install_element(VIEW_NODE, &show_error_code_cmd);
+}
+
+
const struct ferr *ferr_get_last(ferr_r errval)
{
struct ferr *last_error = pthread_getspecific(errkey);
diff --git a/lib/ferr.h b/lib/ferr.h
index 93d0ced538..a89b595e87 100644
--- a/lib/ferr.h
+++ b/lib/ferr.h
@@ -158,6 +158,7 @@ void log_ref_display(struct vty *vty, uint32_t code, bool json);
*/
void log_ref_init(void);
void log_ref_fini(void);
+void log_ref_vty_init(void);
/* get error details.
*
diff --git a/lib/filter.c b/lib/filter.c
index 276df4b4d7..fe62ca1c13 100644
--- a/lib/filter.c
+++ b/lib/filter.c
@@ -60,6 +60,9 @@ struct filter {
/* Filter type information. */
enum filter_type type;
+ /* Sequence number */
+ int64_t seq;
+
/* Cisco access-list */
int cisco;
@@ -270,7 +273,7 @@ static struct access_list *access_list_insert(afi_t afi, const char *name)
/* If name is made by all digit character. We treat it as
number. */
for (number = 0, i = 0; i < strlen(name); i++) {
- if (isdigit((int)name[i]))
+ if (isdigit((unsigned char)name[i]))
number = (number * 10) + (name[i] - '0');
else
break;
@@ -406,23 +409,35 @@ void access_list_delete_hook(void (*func)(struct access_list *access))
access_master_mac.delete_hook = func;
}
-/* Add new filter to the end of specified access_list. */
-static void access_list_filter_add(struct access_list *access,
- struct filter *filter)
+/* Calculate new sequential number. */
+static int64_t filter_new_seq_get(struct access_list *access)
{
- filter->next = NULL;
- filter->prev = access->tail;
+ int64_t maxseq;
+ int64_t newseq;
+ struct filter *filter;
- if (access->tail)
- access->tail->next = filter;
- else
- access->head = filter;
- access->tail = filter;
+ maxseq = newseq = 0;
- /* Run hook function. */
- if (access->master->add_hook)
- (*access->master->add_hook)(access);
- route_map_notify_dependencies(access->name, RMAP_EVENT_FILTER_ADDED);
+ for (filter = access->head; filter; filter = filter->next) {
+ if (maxseq < filter->seq)
+ maxseq = filter->seq;
+ }
+
+ newseq = ((maxseq / 5) * 5) + 5;
+
+ return (newseq > UINT_MAX) ? UINT_MAX : newseq;
+}
+
+/* Return access list entry which has same seq number. */
+static struct filter *filter_seq_check(struct access_list *access,
+ int64_t seq)
+{
+ struct filter *filter;
+
+ for (filter = access->head; filter; filter = filter->next)
+ if (filter->seq == seq)
+ return filter;
+ return NULL;
}
/* If access_list has no filter then return 1. */
@@ -465,6 +480,58 @@ static void access_list_filter_delete(struct access_list *access,
access_list_delete(access);
}
+/* Add new filter to the end of specified access_list. */
+static void access_list_filter_add(struct access_list *access,
+ struct filter *filter)
+{
+ struct filter *replace;
+ struct filter *point;
+
+ /* Automatic asignment of seq no. */
+ if (filter->seq == -1)
+ filter->seq = filter_new_seq_get(access);
+
+ if (access->tail && filter->seq > access->tail->seq)
+ point = NULL;
+ else {
+ /* Is there any same seq access list filter? */
+ replace = filter_seq_check(access, filter->seq);
+ if (replace)
+ access_list_filter_delete(access, replace);
+
+ /* Check insert point. */
+ for (point = access->head; point; point = point->next)
+ if (point->seq >= filter->seq)
+ break;
+ }
+
+ /* In case of this is the first element of the list. */
+ filter->next = point;
+
+ if (point) {
+ if (point->prev)
+ point->prev->next = filter;
+ else
+ access->head = filter;
+
+ filter->prev = point->prev;
+ point->prev = filter;
+ } else {
+ if (access->tail)
+ access->tail->next = filter;
+ else
+ access->head = filter;
+
+ filter->prev = access->tail;
+ access->tail = filter;
+ }
+
+ /* Run hook function. */
+ if (access->master->add_hook)
+ (*access->master->add_hook)(access);
+ route_map_notify_dependencies(access->name, RMAP_EVENT_FILTER_ADDED);
+}
+
/*
deny Specify packets to reject
permit Specify packets to forward
@@ -553,12 +620,13 @@ static int vty_access_list_remark_unset(struct vty *vty, afi_t afi,
}
static int filter_set_cisco(struct vty *vty, const char *name_str,
- const char *type_str, const char *addr_str,
- const char *addr_mask_str, const char *mask_str,
- const char *mask_mask_str, int extended, int set)
+ const char *seq, const char *type_str,
+ const char *addr_str, const char *addr_mask_str,
+ const char *mask_str, const char *mask_mask_str,
+ int extended, int set)
{
int ret;
- enum filter_type type;
+ enum filter_type type = FILTER_DENY;
struct filter *mfilter;
struct filter_cisco *filter;
struct access_list *access;
@@ -566,15 +634,21 @@ static int filter_set_cisco(struct vty *vty, const char *name_str,
struct in_addr addr_mask;
struct in_addr mask;
struct in_addr mask_mask;
+ int64_t seqnum = -1;
+
+ if (seq)
+ seqnum = (int64_t)atol(seq);
/* Check of filter type. */
- if (strncmp(type_str, "p", 1) == 0)
- type = FILTER_PERMIT;
- else if (strncmp(type_str, "d", 1) == 0)
- type = FILTER_DENY;
- else {
- vty_out(vty, "%% filter type must be permit or deny\n");
- return CMD_WARNING_CONFIG_FAILED;
+ if (type_str) {
+ if (strncmp(type_str, "p", 1) == 0)
+ type = FILTER_PERMIT;
+ else if (strncmp(type_str, "d", 1) == 0)
+ type = FILTER_DENY;
+ else {
+ vty_out(vty, "%% filter type must be permit or deny\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
}
ret = inet_aton(addr_str, &addr);
@@ -606,6 +680,7 @@ static int filter_set_cisco(struct vty *vty, const char *name_str,
mfilter = filter_new();
mfilter->type = type;
mfilter->cisco = 1;
+ mfilter->seq = seqnum;
filter = &mfilter->u.cfilter;
filter->extended = extended;
filter->addr.s_addr = addr.s_addr & ~addr_mask.s_addr;
@@ -640,163 +715,311 @@ static int filter_set_cisco(struct vty *vty, const char *name_str,
/* Standard access-list */
DEFUN (access_list_standard,
access_list_standard_cmd,
- "access-list <(1-99)|(1300-1999)> <deny|permit> A.B.C.D A.B.C.D",
+ "access-list <(1-99)|(1300-1999)> [seq (1-4294967295)] <deny|permit> A.B.C.D A.B.C.D",
"Add an access list entry\n"
"IP standard access list\n"
"IP standard access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Address to match\n"
"Wildcard bits\n")
{
int idx_acl = 1;
- int idx_permit_deny = 2;
- int idx_ipv4 = 3;
- int idx_ipv4_2 = 4;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
- argv[idx_ipv4_2]->arg, NULL, NULL, 0, 1);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *address = NULL;
+ char *wildcard = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx) {
+ address = argv[idx]->arg;
+ wildcard = argv[idx + 1]->arg;
+ }
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
+ address, wildcard, NULL, NULL, 0, 1);
}
DEFUN (access_list_standard_nomask,
access_list_standard_nomask_cmd,
- "access-list <(1-99)|(1300-1999)> <deny|permit> A.B.C.D",
+ "access-list <(1-99)|(1300-1999)> [seq (1-4294967295)] <deny|permit> A.B.C.D",
"Add an access list entry\n"
"IP standard access list\n"
"IP standard access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Address to match\n")
{
int idx_acl = 1;
- int idx_permit_deny = 2;
- int idx_ipv4 = 3;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
- "0.0.0.0", NULL, NULL, 0, 1);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *address = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx)
+ address = argv[idx]->arg;
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
+ address, "0.0.0.0", NULL, NULL, 0, 1);
}
DEFUN (access_list_standard_host,
access_list_standard_host_cmd,
- "access-list <(1-99)|(1300-1999)> <deny|permit> host A.B.C.D",
+ "access-list <(1-99)|(1300-1999)> [seq (1-4294967295)] <deny|permit> host A.B.C.D",
"Add an access list entry\n"
"IP standard access list\n"
"IP standard access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"A single host address\n"
"Address to match\n")
{
int idx_acl = 1;
- int idx_permit_deny = 2;
- int idx_ipv4 = 4;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
- "0.0.0.0", NULL, NULL, 0, 1);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *address = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx)
+ address = argv[idx]->arg;
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
+ address, "0.0.0.0", NULL, NULL, 0, 1);
}
DEFUN (access_list_standard_any,
access_list_standard_any_cmd,
- "access-list <(1-99)|(1300-1999)> <deny|permit> any",
+ "access-list <(1-99)|(1300-1999)> [seq (1-4294967295)] <deny|permit> any",
"Add an access list entry\n"
"IP standard access list\n"
"IP standard access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any source host\n")
{
int idx_acl = 1;
- int idx_permit_deny = 2;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, "0.0.0.0",
- "255.255.255.255", NULL, NULL, 0, 1);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
+ "0.0.0.0", "255.255.255.255", NULL, NULL, 0, 1);
}
DEFUN (no_access_list_standard,
no_access_list_standard_cmd,
- "no access-list <(1-99)|(1300-1999)> <deny|permit> A.B.C.D A.B.C.D",
+ "no access-list <(1-99)|(1300-1999)> [seq (1-4294967295)] <deny|permit> A.B.C.D A.B.C.D",
NO_STR
"Add an access list entry\n"
"IP standard access list\n"
"IP standard access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Address to match\n"
"Wildcard bits\n")
{
- int idx_acl = 2;
- int idx_permit_deny = 3;
- int idx_ipv4 = 4;
- int idx_ipv4_2 = 5;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
- argv[idx_ipv4_2]->arg, NULL, NULL, 0, 0);
+ int idx_acl = 1;
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *address = NULL;
+ char *wildcard = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx) {
+ address = argv[idx]->arg;
+ wildcard = argv[idx + 1]->arg;
+ }
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
+ address, wildcard, NULL, NULL, 0, 0);
}
DEFUN (no_access_list_standard_nomask,
no_access_list_standard_nomask_cmd,
- "no access-list <(1-99)|(1300-1999)> <deny|permit> A.B.C.D",
+ "no access-list <(1-99)|(1300-1999)> [seq (1-4294967295)] <deny|permit> A.B.C.D",
NO_STR
"Add an access list entry\n"
"IP standard access list\n"
"IP standard access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Address to match\n")
{
int idx_acl = 2;
- int idx_permit_deny = 3;
- int idx_ipv4 = 4;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
- "0.0.0.0", NULL, NULL, 0, 0);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *address = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx)
+ address = argv[idx]->arg;
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
+ address, "0.0.0.0", NULL, NULL, 0, 0);
}
DEFUN (no_access_list_standard_host,
no_access_list_standard_host_cmd,
- "no access-list <(1-99)|(1300-1999)> <deny|permit> host A.B.C.D",
+ "no access-list <(1-99)|(1300-1999)> [seq (1-4294967295)] <deny|permit> host A.B.C.D",
NO_STR
"Add an access list entry\n"
"IP standard access list\n"
"IP standard access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"A single host address\n"
"Address to match\n")
{
int idx_acl = 2;
- int idx_permit_deny = 3;
- int idx_ipv4 = 5;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
- "0.0.0.0", NULL, NULL, 0, 0);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *address = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx)
+ address = argv[idx]->arg;
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
+ address, "0.0.0.0", NULL, NULL, 0, 0);
}
DEFUN (no_access_list_standard_any,
no_access_list_standard_any_cmd,
- "no access-list <(1-99)|(1300-1999)> <deny|permit> any",
+ "no access-list <(1-99)|(1300-1999)> [seq (1-4294967295)] <deny|permit> any",
NO_STR
"Add an access list entry\n"
"IP standard access list\n"
"IP standard access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any source host\n")
{
int idx_acl = 2;
- int idx_permit_deny = 3;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, "0.0.0.0",
- "255.255.255.255", NULL, NULL, 0, 0);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
+ "0.0.0.0", "255.255.255.255", NULL, NULL, 0, 0);
}
/* Extended access-list */
DEFUN (access_list_extended,
access_list_extended_cmd,
- "access-list <(100-199)|(2000-2699)> <deny|permit> ip A.B.C.D A.B.C.D A.B.C.D A.B.C.D",
+ "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip A.B.C.D A.B.C.D A.B.C.D A.B.C.D",
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -806,23 +1029,45 @@ DEFUN (access_list_extended,
"Destination Wildcard bits\n")
{
int idx_acl = 1;
- int idx_permit_deny = 2;
- int idx_ipv4 = 4;
- int idx_ipv4_2 = 5;
- int idx_ipv4_3 = 6;
- int idx_ipv4_4 = 7;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
- argv[idx_ipv4_2]->arg, argv[idx_ipv4_3]->arg,
- argv[idx_ipv4_4]->arg, 1, 1);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *src = NULL;
+ char *dst = NULL;
+ char *src_wildcard = NULL;
+ char *dst_wildcard = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx) {
+ src = argv[idx]->arg;
+ src_wildcard = argv[idx + 1]->arg;
+ dst = argv[idx + 2]->arg;
+ dst_wildcard = argv[idx + 3]->arg;
+ }
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
+ src_wildcard, dst, dst_wildcard, 1, 1);
}
DEFUN (access_list_extended_mask_any,
access_list_extended_mask_any_cmd,
- "access-list <(100-199)|(2000-2699)> <deny|permit> ip A.B.C.D A.B.C.D any",
+ "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip A.B.C.D A.B.C.D any",
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -831,21 +1076,42 @@ DEFUN (access_list_extended_mask_any,
"Any destination host\n")
{
int idx_acl = 1;
- int idx_permit_deny = 2;
- int idx_ipv4 = 4;
- int idx_ipv4_2 = 5;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
- argv[idx_ipv4_2]->arg, "0.0.0.0",
- "255.255.255.255", 1, 1);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *src = NULL;
+ char *src_wildcard = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx) {
+ src = argv[idx]->arg;
+ src_wildcard = argv[idx + 1]->arg;
+ }
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
+ src_wildcard, "0.0.0.0", "255.255.255.255", 1,
+ 1);
}
DEFUN (access_list_extended_any_mask,
access_list_extended_any_mask_cmd,
- "access-list <(100-199)|(2000-2699)> <deny|permit> ip any A.B.C.D A.B.C.D",
+ "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip any A.B.C.D A.B.C.D",
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -854,21 +1120,42 @@ DEFUN (access_list_extended_any_mask,
"Destination Wildcard bits\n")
{
int idx_acl = 1;
- int idx_permit_deny = 2;
- int idx_ipv4 = 5;
- int idx_ipv4_2 = 6;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, "0.0.0.0",
- "255.255.255.255", argv[idx_ipv4]->arg,
- argv[idx_ipv4_2]->arg, 1, 1);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *dst = NULL;
+ char *dst_wildcard = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx) {
+ dst = argv[idx]->arg;
+ dst_wildcard = argv[idx + 1]->arg;
+ }
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
+ "0.0.0.0", "255.255.255.255", dst, dst_wildcard,
+ 1, 1);
}
DEFUN (access_list_extended_any_any,
access_list_extended_any_any_cmd,
- "access-list <(100-199)|(2000-2699)> <deny|permit> ip any any",
+ "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip any any",
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -876,18 +1163,33 @@ DEFUN (access_list_extended_any_any,
"Any destination host\n")
{
int idx_acl = 1;
- int idx_permit_deny = 2;
- return filter_set_cisco(
- vty, argv[idx_acl]->arg, argv[idx_permit_deny]->arg, "0.0.0.0",
- "255.255.255.255", "0.0.0.0", "255.255.255.255", 1, 1);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
+ "0.0.0.0", "255.255.255.255", "0.0.0.0",
+ "255.255.255.255", 1, 1);
}
DEFUN (access_list_extended_mask_host,
access_list_extended_mask_host_cmd,
- "access-list <(100-199)|(2000-2699)> <deny|permit> ip A.B.C.D A.B.C.D host A.B.C.D",
+ "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip A.B.C.D A.B.C.D host A.B.C.D",
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -897,22 +1199,43 @@ DEFUN (access_list_extended_mask_host,
"Destination address\n")
{
int idx_acl = 1;
- int idx_permit_deny = 2;
- int idx_ipv4 = 4;
- int idx_ipv4_2 = 5;
- int idx_ipv4_3 = 7;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
- argv[idx_ipv4_2]->arg, argv[idx_ipv4_3]->arg,
- "0.0.0.0", 1, 1);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *src = NULL;
+ char *dst = NULL;
+ char *src_wildcard = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx) {
+ src = argv[idx]->arg;
+ src_wildcard = argv[idx + 1]->arg;
+ dst = argv[idx + 3]->arg;
+ }
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
+ src_wildcard, dst, "0.0.0.0", 1, 1);
}
DEFUN (access_list_extended_host_mask,
access_list_extended_host_mask_cmd,
- "access-list <(100-199)|(2000-2699)> <deny|permit> ip host A.B.C.D A.B.C.D A.B.C.D",
+ "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip host A.B.C.D A.B.C.D A.B.C.D",
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -922,22 +1245,43 @@ DEFUN (access_list_extended_host_mask,
"Destination Wildcard bits\n")
{
int idx_acl = 1;
- int idx_permit_deny = 2;
- int idx_ipv4 = 5;
- int idx_ipv4_2 = 6;
- int idx_ipv4_3 = 7;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
- "0.0.0.0", argv[idx_ipv4_2]->arg,
- argv[idx_ipv4_3]->arg, 1, 1);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *src = NULL;
+ char *dst = NULL;
+ char *dst_wildcard = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx) {
+ src = argv[idx]->arg;
+ dst = argv[idx + 1]->arg;
+ dst_wildcard = argv[idx + 2]->arg;
+ }
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
+ "0.0.0.0", dst, dst_wildcard, 1, 1);
}
DEFUN (access_list_extended_host_host,
access_list_extended_host_host_cmd,
- "access-list <(100-199)|(2000-2699)> <deny|permit> ip host A.B.C.D host A.B.C.D",
+ "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip host A.B.C.D host A.B.C.D",
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -947,21 +1291,41 @@ DEFUN (access_list_extended_host_host,
"Destination address\n")
{
int idx_acl = 1;
- int idx_permit_deny = 2;
- int idx_ipv4 = 5;
- int idx_ipv4_2 = 7;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
- "0.0.0.0", argv[idx_ipv4_2]->arg, "0.0.0.0", 1,
- 1);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *src = NULL;
+ char *dst = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx) {
+ src = argv[idx]->arg;
+ dst = argv[idx + 2]->arg;
+ }
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
+ "0.0.0.0", dst, "0.0.0.0", 1, 1);
}
DEFUN (access_list_extended_any_host,
access_list_extended_any_host_cmd,
- "access-list <(100-199)|(2000-2699)> <deny|permit> ip any host A.B.C.D",
+ "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip any host A.B.C.D",
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -970,19 +1334,39 @@ DEFUN (access_list_extended_any_host,
"Destination address\n")
{
int idx_acl = 1;
- int idx_permit_deny = 2;
- int idx_ipv4 = 6;
- return filter_set_cisco(
- vty, argv[idx_acl]->arg, argv[idx_permit_deny]->arg, "0.0.0.0",
- "255.255.255.255", argv[idx_ipv4]->arg, "0.0.0.0", 1, 1);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *dst = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx)
+ dst = argv[idx]->arg;
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
+ "0.0.0.0", "255.255.255.255", dst, "0.0.0.0", 1,
+ 1);
}
DEFUN (access_list_extended_host_any,
access_list_extended_host_any_cmd,
- "access-list <(100-199)|(2000-2699)> <deny|permit> ip host A.B.C.D any",
+ "access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip host A.B.C.D any",
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -991,20 +1375,39 @@ DEFUN (access_list_extended_host_any,
"Any destination host\n")
{
int idx_acl = 1;
- int idx_permit_deny = 2;
- int idx_ipv4 = 5;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *src = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx)
+ src = argv[idx]->arg;
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
"0.0.0.0", "0.0.0.0", "255.255.255.255", 1, 1);
}
DEFUN (no_access_list_extended,
no_access_list_extended_cmd,
- "no access-list <(100-199)|(2000-2699)> <deny|permit> ip A.B.C.D A.B.C.D A.B.C.D A.B.C.D",
+ "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip A.B.C.D A.B.C.D A.B.C.D A.B.C.D",
NO_STR
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -1014,24 +1417,46 @@ DEFUN (no_access_list_extended,
"Destination Wildcard bits\n")
{
int idx_acl = 2;
- int idx_permit_deny = 3;
- int idx_ipv4 = 5;
- int idx_ipv4_2 = 6;
- int idx_ipv4_3 = 7;
- int idx_ipv4_4 = 8;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
- argv[idx_ipv4_2]->arg, argv[idx_ipv4_3]->arg,
- argv[idx_ipv4_4]->arg, 1, 0);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *src = NULL;
+ char *dst = NULL;
+ char *src_wildcard = NULL;
+ char *dst_wildcard = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx) {
+ src = argv[idx]->arg;
+ src_wildcard = argv[idx + 1]->arg;
+ dst = argv[idx + 2]->arg;
+ dst_wildcard = argv[idx + 3]->arg;
+ }
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
+ src_wildcard, dst, dst_wildcard, 1, 0);
}
DEFUN (no_access_list_extended_mask_any,
no_access_list_extended_mask_any_cmd,
- "no access-list <(100-199)|(2000-2699)> <deny|permit> ip A.B.C.D A.B.C.D any",
+ "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip A.B.C.D A.B.C.D any",
NO_STR
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -1040,22 +1465,43 @@ DEFUN (no_access_list_extended_mask_any,
"Any destination host\n")
{
int idx_acl = 2;
- int idx_permit_deny = 3;
- int idx_ipv4 = 5;
- int idx_ipv4_2 = 6;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
- argv[idx_ipv4_2]->arg, "0.0.0.0",
- "255.255.255.255", 1, 0);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *src = NULL;
+ char *src_wildcard = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx) {
+ src = argv[idx]->arg;
+ src_wildcard = argv[idx + 1]->arg;
+ }
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
+ src_wildcard, "0.0.0.0", "255.255.255.255", 1,
+ 0);
}
DEFUN (no_access_list_extended_any_mask,
no_access_list_extended_any_mask_cmd,
- "no access-list <(100-199)|(2000-2699)> <deny|permit> ip any A.B.C.D A.B.C.D",
+ "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip any A.B.C.D A.B.C.D",
NO_STR
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -1064,22 +1510,43 @@ DEFUN (no_access_list_extended_any_mask,
"Destination Wildcard bits\n")
{
int idx_acl = 2;
- int idx_permit_deny = 3;
- int idx_ipv4 = 6;
- int idx_ipv4_2 = 7;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, "0.0.0.0",
- "255.255.255.255", argv[idx_ipv4]->arg,
- argv[idx_ipv4_2]->arg, 1, 0);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *dst = NULL;
+ char *dst_wildcard = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx) {
+ dst = argv[idx]->arg;
+ dst_wildcard = argv[idx + 1]->arg;
+ }
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
+ "0.0.0.0", "255.255.255.255", dst, dst_wildcard,
+ 1, 0);
}
DEFUN (no_access_list_extended_any_any,
no_access_list_extended_any_any_cmd,
- "no access-list <(100-199)|(2000-2699)> <deny|permit> ip any any",
+ "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip any any",
NO_STR
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -1087,19 +1554,34 @@ DEFUN (no_access_list_extended_any_any,
"Any destination host\n")
{
int idx_acl = 2;
- int idx_permit_deny = 3;
- return filter_set_cisco(
- vty, argv[idx_acl]->arg, argv[idx_permit_deny]->arg, "0.0.0.0",
- "255.255.255.255", "0.0.0.0", "255.255.255.255", 1, 0);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
+ "0.0.0.0", "255.255.255.255", "0.0.0.0",
+ "255.255.255.255", 1, 0);
}
DEFUN (no_access_list_extended_mask_host,
no_access_list_extended_mask_host_cmd,
- "no access-list <(100-199)|(2000-2699)> <deny|permit> ip A.B.C.D A.B.C.D host A.B.C.D",
+ "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip A.B.C.D A.B.C.D host A.B.C.D",
NO_STR
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -1109,23 +1591,44 @@ DEFUN (no_access_list_extended_mask_host,
"Destination address\n")
{
int idx_acl = 2;
- int idx_permit_deny = 3;
- int idx_ipv4 = 5;
- int idx_ipv4_2 = 6;
- int idx_ipv4_3 = 8;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
- argv[idx_ipv4_2]->arg, argv[idx_ipv4_3]->arg,
- "0.0.0.0", 1, 0);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *src = NULL;
+ char *dst = NULL;
+ char *src_wildcard = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx) {
+ src = argv[idx]->arg;
+ src_wildcard = argv[idx + 1]->arg;
+ dst = argv[idx + 3]->arg;
+ }
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
+ src_wildcard, dst, "0.0.0.0", 1, 0);
}
DEFUN (no_access_list_extended_host_mask,
no_access_list_extended_host_mask_cmd,
- "no access-list <(100-199)|(2000-2699)> <deny|permit> ip host A.B.C.D A.B.C.D A.B.C.D",
+ "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip host A.B.C.D A.B.C.D A.B.C.D",
NO_STR
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -1135,23 +1638,44 @@ DEFUN (no_access_list_extended_host_mask,
"Destination Wildcard bits\n")
{
int idx_acl = 2;
- int idx_permit_deny = 3;
- int idx_ipv4 = 6;
- int idx_ipv4_2 = 7;
- int idx_ipv4_3 = 8;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
- "0.0.0.0", argv[idx_ipv4_2]->arg,
- argv[idx_ipv4_3]->arg, 1, 0);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *src = NULL;
+ char *dst = NULL;
+ char *dst_wildcard = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx) {
+ src = argv[idx]->arg;
+ dst = argv[idx + 1]->arg;
+ dst_wildcard = argv[idx + 2]->arg;
+ }
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
+ "0.0.0.0", dst, dst_wildcard, 1, 0);
}
DEFUN (no_access_list_extended_host_host,
no_access_list_extended_host_host_cmd,
- "no access-list <(100-199)|(2000-2699)> <deny|permit> ip host A.B.C.D host A.B.C.D",
+ "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip host A.B.C.D host A.B.C.D",
NO_STR
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -1161,22 +1685,42 @@ DEFUN (no_access_list_extended_host_host,
"Destination address\n")
{
int idx_acl = 2;
- int idx_permit_deny = 3;
- int idx_ipv4 = 6;
- int idx_ipv4_2 = 8;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
- "0.0.0.0", argv[idx_ipv4_2]->arg, "0.0.0.0", 1,
- 0);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *src = NULL;
+ char *dst = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx) {
+ src = argv[idx]->arg;
+ dst = argv[idx + 2]->arg;
+ }
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
+ "0.0.0.0", dst, "0.0.0.0", 1, 0);
}
DEFUN (no_access_list_extended_any_host,
no_access_list_extended_any_host_cmd,
- "no access-list <(100-199)|(2000-2699)> <deny|permit> ip any host A.B.C.D",
+ "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip any host A.B.C.D",
NO_STR
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -1185,20 +1729,40 @@ DEFUN (no_access_list_extended_any_host,
"Destination address\n")
{
int idx_acl = 2;
- int idx_permit_deny = 3;
- int idx_ipv4 = 7;
- return filter_set_cisco(
- vty, argv[idx_acl]->arg, argv[idx_permit_deny]->arg, "0.0.0.0",
- "255.255.255.255", argv[idx_ipv4]->arg, "0.0.0.0", 1, 0);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *dst = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx)
+ dst = argv[idx]->arg;
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny,
+ "0.0.0.0", "255.255.255.255", dst, "0.0.0.0", 1,
+ 0);
}
DEFUN (no_access_list_extended_host_any,
no_access_list_extended_host_any_cmd,
- "no access-list <(100-199)|(2000-2699)> <deny|permit> ip host A.B.C.D any",
+ "no access-list <(100-199)|(2000-2699)> [seq (1-4294967295)] <deny|permit> ip host A.B.C.D any",
NO_STR
"Add an access list entry\n"
"IP extended access list\n"
"IP extended access list (expanded range)\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any Internet Protocol\n"
@@ -1207,23 +1771,41 @@ DEFUN (no_access_list_extended_host_any,
"Any destination host\n")
{
int idx_acl = 2;
- int idx_permit_deny = 3;
- int idx_ipv4 = 6;
- return filter_set_cisco(vty, argv[idx_acl]->arg,
- argv[idx_permit_deny]->arg, argv[idx_ipv4]->arg,
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *src = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ if (idx)
+ src = argv[idx]->arg;
+
+ return filter_set_cisco(vty, argv[idx_acl]->arg, seq, permit_deny, src,
"0.0.0.0", "0.0.0.0", "255.255.255.255", 1, 0);
}
static int filter_set_zebra(struct vty *vty, const char *name_str,
- const char *type_str, afi_t afi,
+ const char *seq, const char *type_str, afi_t afi,
const char *prefix_str, int exact, int set)
{
int ret;
- enum filter_type type;
+ enum filter_type type = FILTER_DENY;
struct filter *mfilter;
struct filter_zebra *filter;
struct access_list *access;
struct prefix p;
+ int64_t seqnum = -1;
if (strlen(name_str) > ACL_NAMSIZ) {
vty_out(vty,
@@ -1233,14 +1815,19 @@ static int filter_set_zebra(struct vty *vty, const char *name_str,
return CMD_WARNING_CONFIG_FAILED;
}
+ if (seq)
+ seqnum = (int64_t)atol(seq);
+
/* Check of filter type. */
- if (strncmp(type_str, "p", 1) == 0)
- type = FILTER_PERMIT;
- else if (strncmp(type_str, "d", 1) == 0)
- type = FILTER_DENY;
- else {
- vty_out(vty, "filter type must be [permit|deny]\n");
- return CMD_WARNING_CONFIG_FAILED;
+ if (type_str) {
+ if (strncmp(type_str, "p", 1) == 0)
+ type = FILTER_PERMIT;
+ else if (strncmp(type_str, "d", 1) == 0)
+ type = FILTER_DENY;
+ else {
+ vty_out(vty, "filter type must be [permit|deny]\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
}
/* Check string format of prefix and prefixlen. */
@@ -1269,6 +1856,7 @@ static int filter_set_zebra(struct vty *vty, const char *name_str,
mfilter = filter_new();
mfilter->type = type;
+ mfilter->seq = seqnum;
filter = &mfilter->u.zfilter;
prefix_copy(&filter->prefix, &p);
@@ -1298,67 +1886,145 @@ static int filter_set_zebra(struct vty *vty, const char *name_str,
DEFUN (mac_access_list,
mac_access_list_cmd,
- "mac access-list WORD <deny|permit> X:X:X:X:X:X",
+ "mac access-list WORD [seq (1-4294967295)] <deny|permit> X:X:X:X:X:X",
"Add a mac access-list\n"
"Add an access list entry\n"
"MAC zebra access-list name\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"MAC address to match. e.g. 00:01:00:01:00:01\n")
{
- return filter_set_zebra(vty, argv[2]->arg, argv[3]->arg, AFI_L2VPN,
- argv[4]->arg, 0, 1);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *mac = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "X:X:X:X:X:X", &idx);
+ if (idx)
+ mac = argv[idx]->arg;
+
+ return filter_set_zebra(vty, argv[2]->arg, seq, permit_deny, AFI_L2VPN,
+ mac, 0, 1);
}
DEFUN (no_mac_access_list,
no_mac_access_list_cmd,
- "no mac access-list WORD <deny|permit> X:X:X:X:X:X",
+ "no mac access-list WORD [seq (1-4294967295)] <deny|permit> X:X:X:X:X:X",
NO_STR
"Remove a mac access-list\n"
"Remove an access list entry\n"
"MAC zebra access-list name\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"MAC address to match. e.g. 00:01:00:01:00:01\n")
{
- return filter_set_zebra(vty, argv[3]->arg, argv[4]->arg, AFI_L2VPN,
- argv[5]->arg, 0, 0);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *mac = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "X:X:X:X:X:X", &idx);
+ if (idx)
+ mac = argv[idx]->arg;
+
+ return filter_set_zebra(vty, argv[2]->arg, seq, permit_deny, AFI_L2VPN,
+ mac, 0, 0);
}
DEFUN (mac_access_list_any,
mac_access_list_any_cmd,
- "mac access-list WORD <deny|permit> any",
+ "mac access-list WORD [seq (1-4294967295)] <deny|permit> any",
"Add a mac access-list\n"
"Add an access list entry\n"
"MAC zebra access-list name\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"MAC address to match. e.g. 00:01:00:01:00:01\n")
{
- return filter_set_zebra(vty, argv[2]->arg, argv[3]->arg, AFI_L2VPN,
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ return filter_set_zebra(vty, argv[2]->arg, seq, permit_deny, AFI_L2VPN,
"00:00:00:00:00:00", 0, 1);
}
DEFUN (no_mac_access_list_any,
no_mac_access_list_any_cmd,
- "no mac access-list WORD <deny|permit> any",
+ "no mac access-list WORD [seq (1-4294967295)] <deny|permit> any",
NO_STR
"Remove a mac access-list\n"
"Remove an access list entry\n"
"MAC zebra access-list name\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"MAC address to match. e.g. 00:01:00:01:00:01\n")
{
- return filter_set_zebra(vty, argv[3]->arg, argv[4]->arg, AFI_L2VPN,
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ return filter_set_zebra(vty, argv[2]->arg, seq, permit_deny, AFI_L2VPN,
"00:00:00:00:00:00", 0, 0);
}
DEFUN (access_list_exact,
access_list_exact_cmd,
- "access-list WORD <deny|permit> A.B.C.D/M [exact-match]",
+ "access-list WORD [seq (1-4294967295)] <deny|permit> A.B.C.D/M [exact-match]",
"Add an access list entry\n"
"IP zebra access-list name\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Prefix to match. e.g. 10.0.0.0/8\n"
@@ -1366,41 +2032,71 @@ DEFUN (access_list_exact,
{
int idx = 0;
int exact = 0;
- int idx_word = 1;
- int idx_permit_deny = 2;
- int idx_ipv4_prefixlen = 3;
- idx = idx_ipv4_prefixlen;
-
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *prefix = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D/M", &idx);
+ if (idx)
+ prefix = argv[idx]->arg;
+
+ idx = 0;
if (argv_find(argv, argc, "exact-match", &idx))
exact = 1;
- return filter_set_zebra(vty, argv[idx_word]->arg,
- argv[idx_permit_deny]->arg, AFI_IP,
- argv[idx_ipv4_prefixlen]->arg, exact, 1);
+ return filter_set_zebra(vty, argv[1]->arg, seq, permit_deny,
+ AFI_IP, prefix, exact, 1);
}
DEFUN (access_list_any,
access_list_any_cmd,
- "access-list WORD <deny|permit> any",
+ "access-list WORD [seq (1-4294967295)] <deny|permit> any",
"Add an access list entry\n"
"IP zebra access-list name\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Prefix to match. e.g. 10.0.0.0/8\n")
{
int idx_word = 1;
- int idx_permit_deny = 2;
- return filter_set_zebra(vty, argv[idx_word]->arg,
- argv[idx_permit_deny]->arg, AFI_IP, "0.0.0.0/0",
- 0, 1);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ return filter_set_zebra(vty, argv[idx_word]->arg, seq, permit_deny,
+ AFI_IP, "0.0.0.0/0", 0, 1);
}
DEFUN (no_access_list_exact,
no_access_list_exact_cmd,
- "no access-list WORD <deny|permit> A.B.C.D/M [exact-match]",
+ "no access-list WORD [seq (1-4294967295)] <deny|permit> A.B.C.D/M [exact-match]",
NO_STR
"Add an access list entry\n"
"IP zebra access-list name\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Prefix to match. e.g. 10.0.0.0/8\n"
@@ -1408,34 +2104,62 @@ DEFUN (no_access_list_exact,
{
int idx = 0;
int exact = 0;
- int idx_word = 2;
- int idx_permit_deny = 3;
- int idx_ipv4_prefixlen = 4;
- idx = idx_ipv4_prefixlen;
-
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *prefix = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "A.B.C.D/M", &idx);
+ if (idx)
+ prefix = argv[idx]->arg;
+
+ idx = 0;
if (argv_find(argv, argc, "exact-match", &idx))
exact = 1;
- return filter_set_zebra(vty, argv[idx_word]->arg,
- argv[idx_permit_deny]->arg, AFI_IP,
- argv[idx_ipv4_prefixlen]->arg, exact, 0);
+ return filter_set_zebra(vty, argv[2]->arg, seq, permit_deny,
+ AFI_IP, prefix, exact, 0);
}
DEFUN (no_access_list_any,
no_access_list_any_cmd,
- "no access-list WORD <deny|permit> any",
+ "no access-list WORD [seq (1-4294967295)] <deny|permit> any",
NO_STR
"Add an access list entry\n"
"IP zebra access-list name\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Prefix to match. e.g. 10.0.0.0/8\n")
{
- int idx_word = 2;
- int idx_permit_deny = 3;
- return filter_set_zebra(vty, argv[idx_word]->arg,
- argv[idx_permit_deny]->arg, AFI_IP, "0.0.0.0/0",
- 0, 0);
+ int idx_word = 1;
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ return filter_set_zebra(vty, argv[idx_word]->arg, seq, permit_deny,
+ AFI_IP, "0.0.0.0/0", 0, 0);
}
DEFUN (no_access_list_all,
@@ -1536,10 +2260,12 @@ DEFUN (no_access_list_remark_comment,
DEFUN (ipv6_access_list_exact,
ipv6_access_list_exact_cmd,
- "ipv6 access-list WORD <deny|permit> X:X::X:X/M [exact-match]",
+ "ipv6 access-list WORD [seq (1-4294967295)] <deny|permit> X:X::X:X/M [exact-match]",
IPV6_STR
"Add an access list entry\n"
"IPv6 zebra access-list\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"IPv6 prefix\n"
@@ -1548,41 +2274,73 @@ DEFUN (ipv6_access_list_exact,
int idx = 0;
int exact = 0;
int idx_word = 2;
- int idx_allow = 3;
- int idx_addr = 4;
- idx = idx_addr;
-
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *prefix = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "X:X::X:X/M", &idx);
+ if (idx)
+ prefix = argv[idx]->arg;
+
+ idx = 0;
if (argv_find(argv, argc, "exact-match", &idx))
exact = 1;
- return filter_set_zebra(vty, argv[idx_word]->arg, argv[idx_allow]->text,
- AFI_IP6, argv[idx_addr]->arg, exact, 1);
+ return filter_set_zebra(vty, argv[idx_word]->arg, seq, permit_deny,
+ AFI_IP6, prefix, exact, 1);
}
DEFUN (ipv6_access_list_any,
ipv6_access_list_any_cmd,
- "ipv6 access-list WORD <deny|permit> any",
+ "ipv6 access-list WORD [seq (1-4294967295)] <deny|permit> any",
IPV6_STR
"Add an access list entry\n"
"IPv6 zebra access-list\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any prefixi to match\n")
{
int idx_word = 2;
- int idx_permit_deny = 3;
- return filter_set_zebra(vty, argv[idx_word]->arg,
- argv[idx_permit_deny]->arg, AFI_IP6, "::/0", 0,
- 1);
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ return filter_set_zebra(vty, argv[idx_word]->arg, seq, permit_deny,
+ AFI_IP6, "::/0", 0, 1);
}
DEFUN (no_ipv6_access_list_exact,
no_ipv6_access_list_exact_cmd,
- "no ipv6 access-list WORD <deny|permit> X:X::X:X/M [exact-match]",
+ "no ipv6 access-list WORD [seq (1-4294967295)] <deny|permit> X:X::X:X/M [exact-match]",
NO_STR
IPV6_STR
"Add an access list entry\n"
"IPv6 zebra access-list\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Prefix to match. e.g. 3ffe:506::/32\n"
@@ -1590,35 +2348,64 @@ DEFUN (no_ipv6_access_list_exact,
{
int idx = 0;
int exact = 0;
- int idx_word = 3;
- int idx_permit_deny = 4;
- int idx_ipv6_prefixlen = 5;
- idx = idx_ipv6_prefixlen;
-
+ int idx_word = 2;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+ char *prefix = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "X:X::X:X/M", &idx);
+ if (idx)
+ prefix = argv[idx]->arg;
+
+ idx = 0;
if (argv_find(argv, argc, "exact-match", &idx))
exact = 1;
- return filter_set_zebra(vty, argv[idx_word]->arg,
- argv[idx_permit_deny]->arg, AFI_IP6,
- argv[idx_ipv6_prefixlen]->arg, exact, 0);
+ return filter_set_zebra(vty, argv[idx_word]->arg, seq, permit_deny,
+ AFI_IP6, prefix, exact, 0);
}
DEFUN (no_ipv6_access_list_any,
no_ipv6_access_list_any_cmd,
- "no ipv6 access-list WORD <deny|permit> any",
+ "no ipv6 access-list WORD [seq (1-4294967295)] <deny|permit> any",
NO_STR
IPV6_STR
"Add an access list entry\n"
"IPv6 zebra access-list\n"
+ "Sequence number of an entry\n"
+ "Sequence number\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"Any prefixi to match\n")
{
- int idx_word = 3;
- int idx_permit_deny = 4;
- return filter_set_zebra(vty, argv[idx_word]->arg,
- argv[idx_permit_deny]->arg, AFI_IP6, "::/0", 0,
- 0);
+ int idx_word = 2;
+ int idx = 0;
+ char *seq = NULL;
+ char *permit_deny = NULL;
+
+ argv_find(argv, argc, "(1-4294967295)", &idx);
+ if (idx)
+ seq = argv[idx]->arg;
+
+ idx = 0;
+ argv_find(argv, argc, "permit", &idx);
+ argv_find(argv, argc, "deny", &idx);
+ if (idx)
+ permit_deny = argv[idx]->arg;
+
+ return filter_set_zebra(vty, argv[idx_word]->arg, seq, permit_deny,
+ AFI_IP6, "::/0", 0, 0);
}
@@ -1748,7 +2535,8 @@ static int filter_show(struct vty *vty, const char *name, afi_t afi)
write = 0;
}
- vty_out(vty, " %s%s", filter_type_str(mfilter),
+ vty_out(vty, " seq %" PRId64, mfilter->seq);
+ vty_out(vty, " %s%s", filter_type_str(mfilter),
mfilter->type == FILTER_DENY ? " " : "");
if (!mfilter->cisco)
@@ -1795,7 +2583,8 @@ static int filter_show(struct vty *vty, const char *name, afi_t afi)
write = 0;
}
- vty_out(vty, " %s%s", filter_type_str(mfilter),
+ vty_out(vty, " seq %" PRId64, mfilter->seq);
+ vty_out(vty, " %s%s", filter_type_str(mfilter),
mfilter->type == FILTER_DENY ? " " : "");
if (!mfilter->cisco)
@@ -1978,11 +2767,12 @@ static int config_write_access(struct vty *vty, afi_t afi)
}
for (mfilter = access->head; mfilter; mfilter = mfilter->next) {
- vty_out(vty, "%saccess-list %s %s",
+ vty_out(vty, "%saccess-list %s seq %" PRId64 " %s",
(afi == AFI_IP) ? ("")
: ((afi == AFI_IP6) ? ("ipv6 ")
: ("mac ")),
- access->name, filter_type_str(mfilter));
+ access->name, mfilter->seq,
+ filter_type_str(mfilter));
if (mfilter->cisco)
config_write_access_cisco(vty, mfilter);
@@ -2004,11 +2794,12 @@ static int config_write_access(struct vty *vty, afi_t afi)
}
for (mfilter = access->head; mfilter; mfilter = mfilter->next) {
- vty_out(vty, "%saccess-list %s %s",
+ vty_out(vty, "%saccess-list %s seq %" PRId64 " %s",
(afi == AFI_IP) ? ("")
: ((afi == AFI_IP6) ? ("ipv6 ")
: ("mac ")),
- access->name, filter_type_str(mfilter));
+ access->name, mfilter->seq,
+ filter_type_str(mfilter));
if (mfilter->cisco)
config_write_access_cisco(vty, mfilter);
diff --git a/lib/frr_pthread.c b/lib/frr_pthread.c
index e588571c01..bdb6c2a397 100644
--- a/lib/frr_pthread.c
+++ b/lib/frr_pthread.c
@@ -133,18 +133,29 @@ int frr_pthread_set_name(struct frr_pthread *fpt)
return ret;
}
+static void *frr_pthread_inner(void *arg)
+{
+ struct frr_pthread *fpt = arg;
+
+ rcu_thread_start(fpt->rcu_thread);
+ return fpt->attr.start(fpt);
+}
+
int frr_pthread_run(struct frr_pthread *fpt, const pthread_attr_t *attr)
{
int ret;
- ret = pthread_create(&fpt->thread, attr, fpt->attr.start, fpt);
+ fpt->rcu_thread = rcu_thread_prepare();
+ ret = pthread_create(&fpt->thread, attr, frr_pthread_inner, fpt);
/*
* Per pthread_create(3), the contents of fpt->thread are undefined if
* pthread_create() did not succeed. Reset this value to zero.
*/
- if (ret < 0)
+ if (ret < 0) {
+ rcu_thread_unprepare(fpt->rcu_thread);
memset(&fpt->thread, 0x00, sizeof(fpt->thread));
+ }
return ret;
}
diff --git a/lib/frr_pthread.h b/lib/frr_pthread.h
index 3afe7ba966..6096a50370 100644
--- a/lib/frr_pthread.h
+++ b/lib/frr_pthread.h
@@ -23,6 +23,7 @@
#include <pthread.h>
#include "frratomic.h"
#include "memory.h"
+#include "frrcu.h"
#include "thread.h"
#ifdef __cplusplus
@@ -50,6 +51,8 @@ struct frr_pthread {
/* pthread id */
pthread_t thread;
+ struct rcu_thread *rcu_thread;
+
/* thread master for this pthread's thread.c event loop */
struct thread_master *master;
diff --git a/lib/frrcu.c b/lib/frrcu.c
new file mode 100644
index 0000000000..7e6475b648
--- /dev/null
+++ b/lib/frrcu.c
@@ -0,0 +1,527 @@
+/*
+ * Copyright (c) 2017-19 David Lamparter, for NetDEF, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* implementation notes: this is an epoch-based RCU implementation. rcu_seq
+ * (global variable) counts the current epoch. Threads hold a specific epoch
+ * in rcu_read_lock(). This is the oldest epoch a thread might be accessing
+ * data from.
+ *
+ * The rcu_seq global is only pushed forward on rcu_read_lock() and
+ * rcu_read_unlock() calls. This makes things a tad more efficient since
+ * those are the only places it matters:
+ * - on rcu_read_lock, we don't want to hold an old epoch pointlessly
+ * - on rcu_read_unlock, we want to make sure we're not stuck on an old epoch
+ * when heading into a long idle period where no thread holds RCU
+ *
+ * rcu_thread structures themselves are RCU-free'd.
+ *
+ * rcu_head structures are the most iffy; normally for an ATOMLIST we would
+ * need to make sure we use rcu_free or pthread_rwlock to deallocate old items
+ * to prevent ABA or use-after-free problems. However, our ATOMLIST code
+ * guarantees that if the list remains non-empty in all cases, we only need
+ * the "last" pointer to do an "add_tail()", i.e. we can't run into ABA/UAF
+ * issues - but we do need to keep at least 1 item on the list.
+ *
+ * (Search the atomlist code for all uses of "last")
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <pthread.h>
+#ifdef HAVE_PTHREAD_NP_H
+#include <pthread_np.h>
+#endif
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include "frrcu.h"
+#include "seqlock.h"
+#include "atomlist.h"
+
+DEFINE_MTYPE_STATIC(LIB, RCU_THREAD, "RCU thread")
+DEFINE_MTYPE_STATIC(LIB, RCU_NEXT, "RCU sequence barrier")
+
+DECLARE_ATOMLIST(rcu_heads, struct rcu_head, head)
+
+PREDECL_ATOMLIST(rcu_threads)
+struct rcu_thread {
+ struct rcu_threads_item head;
+
+ struct rcu_head rcu_head;
+
+ struct seqlock rcu;
+
+ /* only accessed by thread itself, not atomic */
+ unsigned depth;
+};
+DECLARE_ATOMLIST(rcu_threads, struct rcu_thread, head)
+
+static const struct rcu_action rcua_next = { .type = RCUA_NEXT };
+static const struct rcu_action rcua_end = { .type = RCUA_END };
+static const struct rcu_action rcua_close = { .type = RCUA_CLOSE };
+
+struct rcu_next {
+ struct rcu_head head_free;
+ struct rcu_head head_next;
+};
+
+#define rcu_free_internal(mtype, ptr, field) \
+ do { \
+ typeof(ptr) _ptr = (ptr); \
+ struct rcu_head *_rcu_head = &_ptr->field; \
+ static const struct rcu_action _rcu_action = { \
+ .type = RCUA_FREE, \
+ .u.free = { \
+ .mt = mtype, \
+ .offset = offsetof(typeof(*_ptr), field), \
+ }, \
+ }; \
+ _rcu_head->action = &_rcu_action; \
+ rcu_heads_add_tail(&rcu_heads, _rcu_head); \
+ } while (0)
+
+/* primary global RCU position */
+static struct seqlock rcu_seq;
+/* this is set to rcu_seq whenever something is added on the RCU queue.
+ * rcu_read_lock() and rcu_read_unlock() will then bump rcu_seq up one step.
+ */
+static _Atomic seqlock_val_t rcu_dirty;
+
+static struct rcu_threads_head rcu_threads;
+static struct rcu_heads_head rcu_heads;
+
+/* main thread & RCU sweeper have pre-setup rcu_thread structures. The
+ * reasons are different:
+ *
+ * - rcu_thread_main is there because the main thread isn't started like
+ * other threads, it's implicitly created when the program is started. So
+ * rcu_thread_main matches up implicitly.
+ *
+ * - rcu_thread_rcu isn't actually put on the rcu_threads list (makes no
+ * sense really), it only exists so we can call RCU-using functions from
+ * the RCU thread without special handling in rcu_read_lock/unlock.
+ */
+static struct rcu_thread rcu_thread_main;
+static struct rcu_thread rcu_thread_rcu;
+
+static pthread_t rcu_pthread;
+static pthread_key_t rcu_thread_key;
+static bool rcu_active;
+
+static void rcu_start(void);
+static void rcu_bump(void);
+
+/*
+ * preinitialization for main thread
+ */
+static void rcu_thread_end(void *rcu_thread);
+
+static void rcu_preinit(void) __attribute__((constructor));
+static void rcu_preinit(void)
+{
+ struct rcu_thread *rt;
+
+ rt = &rcu_thread_main;
+ rt->depth = 1;
+ seqlock_init(&rt->rcu);
+ seqlock_acquire_val(&rt->rcu, SEQLOCK_STARTVAL);
+
+ pthread_key_create(&rcu_thread_key, rcu_thread_end);
+ pthread_setspecific(rcu_thread_key, rt);
+
+ rcu_threads_add_tail(&rcu_threads, rt);
+
+ /* RCU sweeper's rcu_thread is a dummy, NOT added to rcu_threads */
+ rt = &rcu_thread_rcu;
+ rt->depth = 1;
+
+ seqlock_init(&rcu_seq);
+ seqlock_acquire_val(&rcu_seq, SEQLOCK_STARTVAL);
+}
+
+static struct rcu_thread *rcu_self(void)
+{
+ return (struct rcu_thread *)pthread_getspecific(rcu_thread_key);
+}
+
+/*
+ * thread management (for the non-main thread)
+ */
+struct rcu_thread *rcu_thread_prepare(void)
+{
+ struct rcu_thread *rt, *cur;
+
+ rcu_assert_read_locked();
+
+ if (!rcu_active)
+ rcu_start();
+
+ cur = rcu_self();
+ assert(cur->depth);
+
+ /* new thread always starts with rcu_read_lock held at depth 1, and
+ * holding the same epoch as the parent (this makes it possible to
+ * use RCU for things passed into the thread through its arg)
+ */
+ rt = XCALLOC(MTYPE_RCU_THREAD, sizeof(*rt));
+ rt->depth = 1;
+
+ seqlock_init(&rt->rcu);
+ seqlock_acquire(&rt->rcu, &cur->rcu);
+
+ rcu_threads_add_tail(&rcu_threads, rt);
+
+ return rt;
+}
+
+void rcu_thread_start(struct rcu_thread *rt)
+{
+ pthread_setspecific(rcu_thread_key, rt);
+}
+
+void rcu_thread_unprepare(struct rcu_thread *rt)
+{
+ if (rt == &rcu_thread_rcu)
+ return;
+
+ rt->depth = 1;
+ seqlock_acquire(&rt->rcu, &rcu_seq);
+
+ rcu_bump();
+ if (rt != &rcu_thread_main)
+ /* this free() happens after seqlock_release() below */
+ rcu_free_internal(MTYPE_RCU_THREAD, rt, rcu_head);
+
+ rcu_threads_del(&rcu_threads, rt);
+ seqlock_release(&rt->rcu);
+}
+
+static void rcu_thread_end(void *rtvoid)
+{
+ struct rcu_thread *rt = rtvoid;
+ rcu_thread_unprepare(rt);
+}
+
+/*
+ * main RCU control aspects
+ */
+
+static void rcu_bump(void)
+{
+ struct rcu_next *rn;
+
+ rn = XMALLOC(MTYPE_RCU_NEXT, sizeof(*rn));
+
+ /* note: each RCUA_NEXT item corresponds to exactly one seqno bump.
+ * This means we don't need to communicate which seqno is which
+ * RCUA_NEXT, since we really don't care.
+ */
+
+ /*
+ * Important race condition: while rcu_heads_add_tail is executing,
+ * there is an intermediate point where the rcu_heads "last" pointer
+ * already points to rn->head_next, but rn->head_next isn't added to
+ * the list yet. That means any other "add_tail" calls append to this
+ * item, which isn't fully on the list yet. Freeze this thread at
+ * that point and look at another thread doing a rcu_bump. It adds
+ * these two items and then does a seqlock_bump. But the rcu_heads
+ * list is still "interrupted" and there's no RCUA_NEXT on the list
+ * yet (from either the frozen thread or the second thread). So
+ * rcu_main() might actually hit the end of the list at the
+ * "interrupt".
+ *
+ * This situation is prevented by requiring that rcu_read_lock is held
+ * for any calls to rcu_bump, since if we're holding the current RCU
+ * epoch, that means rcu_main can't be chewing on rcu_heads and hit
+ * that interruption point. Only by the time the thread has continued
+ * to rcu_read_unlock() - and therefore completed the add_tail - the
+ * RCU sweeper gobbles up the epoch and can be sure to find at least
+ * the RCUA_NEXT and RCUA_FREE items on rcu_heads.
+ */
+ rn->head_next.action = &rcua_next;
+ rcu_heads_add_tail(&rcu_heads, &rn->head_next);
+
+ /* free rn that we allocated above.
+ *
+ * This is INTENTIONALLY not built into the RCUA_NEXT action. This
+ * ensures that after the action above is popped off the queue, there
+ * is still at least 1 item on the RCU queue. This means we never
+ * delete the last item, which is extremely important since it keeps
+ * the atomlist ->last pointer alive and well.
+ *
+ * If we were to "run dry" on the RCU queue, add_tail may run into the
+ * "last item is being deleted - start over" case, and then we may end
+ * up accessing old RCU queue items that are already free'd.
+ */
+ rcu_free_internal(MTYPE_RCU_NEXT, rn, head_free);
+
+ /* Only allow the RCU sweeper to run after these 2 items are queued.
+ *
+ * If another thread enqueues some RCU action in the intermediate
+ * window here, nothing bad happens - the queued action is associated
+ * with a larger seq# than strictly necessary. Thus, it might get
+ * executed a bit later, but that's not a problem.
+ *
+ * If another thread acquires the read lock in this window, it holds
+ * the previous epoch, but its RCU queue actions will be in the next
+ * epoch. This isn't a problem either, just a tad inefficient.
+ */
+ seqlock_bump(&rcu_seq);
+}
+
+static void rcu_bump_maybe(void)
+{
+ seqlock_val_t dirty;
+
+ dirty = atomic_load_explicit(&rcu_dirty, memory_order_relaxed);
+ /* no problem if we race here and multiple threads bump rcu_seq;
+ * bumping too much causes no issues while not bumping enough will
+ * result in delayed cleanup
+ */
+ if (dirty == seqlock_cur(&rcu_seq))
+ rcu_bump();
+}
+
+void rcu_read_lock(void)
+{
+ struct rcu_thread *rt = rcu_self();
+
+ assert(rt);
+ if (rt->depth++ > 0)
+ return;
+
+ seqlock_acquire(&rt->rcu, &rcu_seq);
+ /* need to hold RCU for bump ... */
+ rcu_bump_maybe();
+ /* ... but no point in holding the old epoch if we just bumped */
+ seqlock_acquire(&rt->rcu, &rcu_seq);
+}
+
+void rcu_read_unlock(void)
+{
+ struct rcu_thread *rt = rcu_self();
+
+ assert(rt && rt->depth);
+ if (--rt->depth > 0)
+ return;
+ rcu_bump_maybe();
+ seqlock_release(&rt->rcu);
+}
+
+void rcu_assert_read_locked(void)
+{
+ struct rcu_thread *rt = rcu_self();
+ assert(rt && rt->depth && seqlock_held(&rt->rcu));
+}
+
+void rcu_assert_read_unlocked(void)
+{
+ struct rcu_thread *rt = rcu_self();
+ assert(rt && !rt->depth && !seqlock_held(&rt->rcu));
+}
+
+/*
+ * RCU resource-release thread
+ */
+
+static void *rcu_main(void *arg);
+
+static void rcu_start(void)
+{
+ /* ensure we never handle signals on the RCU thread by blocking
+ * everything here (new thread inherits signal mask)
+ */
+ sigset_t oldsigs, blocksigs;
+
+ sigfillset(&blocksigs);
+ pthread_sigmask(SIG_BLOCK, &blocksigs, &oldsigs);
+
+ rcu_active = true;
+
+ assert(!pthread_create(&rcu_pthread, NULL, rcu_main, NULL));
+
+ pthread_sigmask(SIG_SETMASK, &oldsigs, NULL);
+
+#ifdef HAVE_PTHREAD_SETNAME_NP
+# ifdef GNU_LINUX
+ pthread_setname_np(rcu_pthread, "RCU sweeper");
+# elif defined(__NetBSD__)
+ pthread_setname_np(rcu_pthread, "RCU sweeper", NULL);
+# endif
+#elif defined(HAVE_PTHREAD_SET_NAME_NP)
+ pthread_set_name_np(rcu_pthread, "RCU sweeper");
+#endif
+}
+
+static void rcu_do(struct rcu_head *rh)
+{
+ struct rcu_head_close *rhc;
+ void *p;
+
+ switch (rh->action->type) {
+ case RCUA_FREE:
+ p = (char *)rh - rh->action->u.free.offset;
+ if (rh->action->u.free.mt)
+ qfree(rh->action->u.free.mt, p);
+ else
+ free(p);
+ break;
+ case RCUA_CLOSE:
+ rhc = container_of(rh, struct rcu_head_close,
+ rcu_head);
+ close(rhc->fd);
+ break;
+ case RCUA_CALL:
+ p = (char *)rh - rh->action->u.call.offset;
+ rh->action->u.call.fptr(p);
+ break;
+
+ case RCUA_INVALID:
+ case RCUA_NEXT:
+ case RCUA_END:
+ default:
+ assert(0);
+ }
+}
+
+static void rcu_watchdog(struct rcu_thread *rt)
+{
+#if 0
+ /* future work: print a backtrace for the thread that's holding up
+ * RCU. The only (good) way of doing that is to send a signal to the
+ * other thread, save away the backtrace in the signal handler, and
+ * block here until the signal is done processing.
+ *
+ * Just haven't implemented that yet.
+ */
+ fprintf(stderr, "RCU watchdog %p\n", rt);
+#endif
+}
+
+static void *rcu_main(void *arg)
+{
+ struct rcu_thread *rt;
+ struct rcu_head *rh = NULL;
+ bool end = false;
+ struct timespec maxwait;
+
+ seqlock_val_t rcuval = SEQLOCK_STARTVAL;
+
+ pthread_setspecific(rcu_thread_key, &rcu_thread_rcu);
+
+ while (!end) {
+ seqlock_wait(&rcu_seq, rcuval);
+
+ /* RCU watchdog timeout, TODO: configurable value */
+ clock_gettime(CLOCK_MONOTONIC, &maxwait);
+ maxwait.tv_nsec += 100 * 1000 * 1000;
+ if (maxwait.tv_nsec >= 1000000000) {
+ maxwait.tv_sec++;
+ maxwait.tv_nsec -= 1000000000;
+ }
+
+ frr_each (rcu_threads, &rcu_threads, rt)
+ if (!seqlock_timedwait(&rt->rcu, rcuval, &maxwait)) {
+ rcu_watchdog(rt);
+ seqlock_wait(&rt->rcu, rcuval);
+ }
+
+ while ((rh = rcu_heads_pop(&rcu_heads))) {
+ if (rh->action->type == RCUA_NEXT)
+ break;
+ else if (rh->action->type == RCUA_END)
+ end = true;
+ else
+ rcu_do(rh);
+ }
+
+ rcuval += SEQLOCK_INCR;
+ }
+
+ /* rcu_shutdown can only be called singlethreaded, and it does a
+ * pthread_join, so it should be impossible that anything ended up
+ * on the queue after RCUA_END
+ */
+#if 1
+ assert(!rcu_heads_first(&rcu_heads));
+#else
+ while ((rh = rcu_heads_pop(&rcu_heads)))
+ if (rh->action->type >= RCUA_FREE)
+ rcu_do(rh);
+#endif
+ return NULL;
+}
+
+void rcu_shutdown(void)
+{
+ static struct rcu_head rcu_head_end;
+ struct rcu_thread *rt = rcu_self();
+ void *retval;
+
+ if (!rcu_active)
+ return;
+
+ rcu_assert_read_locked();
+ assert(rcu_threads_count(&rcu_threads) == 1);
+
+ rcu_enqueue(&rcu_head_end, &rcua_end);
+
+ rt->depth = 0;
+ seqlock_release(&rt->rcu);
+ seqlock_release(&rcu_seq);
+ rcu_active = false;
+
+ /* clearing rcu_active is before pthread_join in case we hang in
+ * pthread_join & get a SIGTERM or something - in that case, just
+ * ignore the maybe-still-running RCU thread
+ */
+ if (pthread_join(rcu_pthread, &retval) == 0) {
+ seqlock_acquire_val(&rcu_seq, SEQLOCK_STARTVAL);
+ seqlock_acquire_val(&rt->rcu, SEQLOCK_STARTVAL);
+ rt->depth = 1;
+ }
+}
+
+/*
+ * RCU'd free functions
+ */
+
+void rcu_enqueue(struct rcu_head *rh, const struct rcu_action *action)
+{
+ /* refer to rcu_bump() for why we need to hold RCU when adding items
+ * to rcu_heads
+ */
+ rcu_assert_read_locked();
+
+ rh->action = action;
+
+ if (!rcu_active) {
+ rcu_do(rh);
+ return;
+ }
+ rcu_heads_add_tail(&rcu_heads, rh);
+ atomic_store_explicit(&rcu_dirty, seqlock_cur(&rcu_seq),
+ memory_order_relaxed);
+}
+
+void rcu_close(struct rcu_head_close *rhc, int fd)
+{
+ rhc->fd = fd;
+ rcu_enqueue(&rhc->rcu_head, &rcua_close);
+}
diff --git a/lib/frrcu.h b/lib/frrcu.h
new file mode 100644
index 0000000000..8f789303cc
--- /dev/null
+++ b/lib/frrcu.h
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2017-19 David Lamparter, for NetDEF, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _FRRCU_H
+#define _FRRCU_H
+
+#include "memory.h"
+#include "atomlist.h"
+#include "seqlock.h"
+
+/* quick RCU primer:
+ * There's a global sequence counter. Whenever a thread does a
+ * rcu_read_lock(), it is marked as holding the current sequence counter.
+ * When something is cleaned with RCU, the global sequence counter is
+ * increased and the item is queued for cleanup - *after* all threads are
+ * at a more recent sequence counter (or no sequence counter / unheld).
+ *
+ * So, by delaying resource cleanup, RCU ensures that things don't go away
+ * while another thread may hold a (stale) reference.
+ *
+ * Note that even if a thread is in rcu_read_lock(), it is invalid for that
+ * thread to access bits after rcu_free() & co on them. This is a design
+ * choice to allow no-op'ing out the entire RCU mechanism if we're running
+ * singlethreaded. (Also allows some optimization on the counter bumping.)
+ *
+ * differences from Linux Kernel RCU:
+ * - there's no rcu_synchronize(), if you really need to defer something
+ * use rcu_call() (and double check it's really necessary)
+ * - rcu_dereference() and rcu_assign_pointer() don't exist, use atomic_*
+ * instead (ATOM* list structures do the right thing)
+ */
+
+/* opaque */
+struct rcu_thread;
+
+/* called before new thread creation, sets up rcu thread info for new thread
+ * before it actually exits. This ensures possible RCU references are held
+ * for thread startup.
+ *
+ * return value must be passed into the new thread's call to rcu_thread_start()
+ */
+extern struct rcu_thread *rcu_thread_prepare(void);
+
+/* cleanup in case pthread_create() fails */
+extern void rcu_thread_unprepare(struct rcu_thread *rcu_thread);
+
+/* called early in the new thread, with the return value from the above.
+ * NB: new thread is initially in RCU-held state! (at depth 1)
+ *
+ * TBD: maybe inherit RCU state from rcu_thread_prepare()?
+ */
+extern void rcu_thread_start(struct rcu_thread *rcu_thread);
+
+/* thread exit is handled through pthread_key_create's destructor function */
+
+/* global RCU shutdown - must be called with only 1 active thread left. waits
+ * until remaining RCU actions are done & RCU thread has exited.
+ *
+ * This is mostly here to get a clean exit without memleaks.
+ */
+extern void rcu_shutdown(void);
+
+/* enter / exit RCU-held state. counter-based, so can be called nested. */
+extern void rcu_read_lock(void);
+extern void rcu_read_unlock(void);
+
+/* for debugging / safety checks */
+extern void rcu_assert_read_locked(void);
+extern void rcu_assert_read_unlocked(void);
+
+enum rcu_action_type {
+ RCUA_INVALID = 0,
+ /* used internally by the RCU code, shouldn't ever show up outside */
+ RCUA_NEXT,
+ RCUA_END,
+ /* normal RCU actions, for outside use */
+ RCUA_FREE,
+ RCUA_CLOSE,
+ RCUA_CALL,
+};
+
+/* since rcu_head is intended to be embedded into structs which may exist
+ * with lots of copies, rcu_head is shrunk down to its absolute minimum -
+ * the atomlist pointer + a pointer to this action struct.
+ */
+struct rcu_action {
+ enum rcu_action_type type;
+
+ union {
+ struct {
+ struct memtype *mt;
+ ptrdiff_t offset;
+ } free;
+
+ struct {
+ void (*fptr)(void *arg);
+ ptrdiff_t offset;
+ } call;
+ } u;
+};
+
+/* RCU cleanup function queue item */
+PREDECL_ATOMLIST(rcu_heads)
+struct rcu_head {
+ struct rcu_heads_item head;
+ const struct rcu_action *action;
+};
+
+/* special RCU head for delayed fd-close */
+struct rcu_head_close {
+ struct rcu_head rcu_head;
+ int fd;
+};
+
+/* enqueue RCU action - use the macros below to get the rcu_action set up */
+extern void rcu_enqueue(struct rcu_head *head, const struct rcu_action *action);
+
+/* RCU free() and file close() operations.
+ *
+ * freed memory / closed fds become _immediately_ unavailable to the calling
+ * thread, but will remain available for other threads until they have passed
+ * into RCU-released state.
+ */
+
+/* may be called with NULL mt to do non-MTYPE free() */
+#define rcu_free(mtype, ptr, field) \
+ do { \
+ typeof(ptr) _ptr = (ptr); \
+ struct rcu_head *_rcu_head = &_ptr->field; \
+ static const struct rcu_action _rcu_action = { \
+ .type = RCUA_FREE, \
+ .u.free = { \
+ .mt = mtype, \
+ .offset = offsetof(typeof(*_ptr), field), \
+ }, \
+ }; \
+ rcu_enqueue(_rcu_head, &_rcu_action); \
+ } while (0)
+
+/* use this sparingly, it runs on (and blocks) the RCU thread */
+#define rcu_call(func, ptr, field) \
+ do { \
+ typeof(ptr) _ptr = (ptr); \
+ void (*fptype)(typeof(ptr)); \
+ struct rcu_head *_rcu_head = &_ptr->field; \
+ static const struct rcu_action _rcu_action = { \
+ .type = RCUA_CALL, \
+ .u.call = { \
+ .fptr = (void *)func, \
+ .offset = offsetof(typeof(*_ptr), field), \
+ }, \
+ }; \
+ (void)(_fptype = func); \
+ rcu_enqueue(_rcu_head, &_rcu_action); \
+ } while (0)
+
+extern void rcu_close(struct rcu_head_close *head, int fd);
+
+#endif /* _FRRCU_H */
diff --git a/lib/frrstr.c b/lib/frrstr.c
index c575c0b568..8a72a35af0 100644
--- a/lib/frrstr.c
+++ b/lib/frrstr.c
@@ -209,7 +209,7 @@ bool frrstr_endswith(const char *str, const char *suffix)
int all_digit(const char *str)
{
for (; *str != '\0'; str++)
- if (!isdigit((int)*str))
+ if (!isdigit((unsigned char)*str))
return 0;
return 1;
}
diff --git a/lib/if.c b/lib/if.c
index f7a167f251..9ee2f02e62 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -132,18 +132,26 @@ static int if_cmp_index_func(const struct interface *ifp1,
}
/* Create new interface structure. */
-struct interface *if_create(const char *name, vrf_id_t vrf_id)
+static struct interface *if_create_backend(const char *name, ifindex_t ifindex,
+ vrf_id_t vrf_id)
{
struct vrf *vrf = vrf_get(vrf_id, NULL);
struct interface *ifp;
ifp = XCALLOC(MTYPE_IF, sizeof(struct interface));
- ifp->ifindex = IFINDEX_INTERNAL;
-
- assert(name);
- strlcpy(ifp->name, name, sizeof(ifp->name));
ifp->vrf_id = vrf_id;
- IFNAME_RB_INSERT(vrf, ifp);
+
+ if (name) {
+ strlcpy(ifp->name, name, sizeof(ifp->name));
+ IFNAME_RB_INSERT(vrf, ifp);
+ } else
+ ifp->name[0] = '\0';
+
+ if (ifindex != IFINDEX_INTERNAL)
+ if_set_index(ifp, ifindex);
+ else
+ ifp->ifindex = ifindex; /* doesn't add it to the list */
+
ifp->connected = list_new();
ifp->connected->del = (void (*)(void *))connected_free;
@@ -158,6 +166,16 @@ struct interface *if_create(const char *name, vrf_id_t vrf_id)
return ifp;
}
+struct interface *if_create(const char *name, vrf_id_t vrf_id)
+{
+ return if_create_backend(name, IFINDEX_INTERNAL, vrf_id);
+}
+
+struct interface *if_create_ifindex(ifindex_t ifindex, vrf_id_t vrf_id)
+{
+ return if_create_backend(NULL, ifindex, vrf_id);
+}
+
/* Create new interface structure. */
void if_update_to_new_vrf(struct interface *ifp, vrf_id_t vrf_id)
{
@@ -302,6 +320,23 @@ struct interface *if_lookup_by_name_all_vrf(const char *name)
return NULL;
}
+struct interface *if_lookup_by_index_all_vrf(ifindex_t ifindex)
+{
+ struct vrf *vrf;
+ struct interface *ifp;
+
+ if (ifindex == IFINDEX_INTERNAL)
+ return NULL;
+
+ RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
+ ifp = if_lookup_by_index(ifindex, vrf->vrf_id);
+ if (ifp)
+ return ifp;
+ }
+
+ return NULL;
+}
+
/* Lookup interface by IPv4 address. */
struct interface *if_lookup_exact_address(void *src, int family,
vrf_id_t vrf_id)
@@ -447,6 +482,34 @@ struct interface *if_get_by_name(const char *name, vrf_id_t vrf_id)
return NULL;
}
+struct interface *if_get_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id)
+{
+ struct interface *ifp;
+
+ switch (vrf_get_backend()) {
+ case VRF_BACKEND_UNKNOWN:
+ case VRF_BACKEND_NETNS:
+ ifp = if_lookup_by_index(ifindex, vrf_id);
+ if (ifp)
+ return ifp;
+ return if_create_ifindex(ifindex, vrf_id);
+ case VRF_BACKEND_VRF_LITE:
+ ifp = if_lookup_by_index_all_vrf(ifindex);
+ if (ifp) {
+ if (ifp->vrf_id == vrf_id)
+ return ifp;
+ /* If it came from the kernel or by way of zclient,
+ * believe it and update the ifp accordingly.
+ */
+ if_update_to_new_vrf(ifp, vrf_id);
+ return ifp;
+ }
+ return if_create_ifindex(ifindex, vrf_id);
+ }
+
+ return NULL;
+}
+
void if_set_index(struct interface *ifp, ifindex_t ifindex)
{
struct vrf *vrf;
diff --git a/lib/if.h b/lib/if.h
index 603c9c3780..871e319f29 100644
--- a/lib/if.h
+++ b/lib/if.h
@@ -478,7 +478,9 @@ extern int if_cmp_name_func(const char *p1, const char *p2);
*/
extern void if_update_to_new_vrf(struct interface *, vrf_id_t vrf_id);
extern struct interface *if_create(const char *name, vrf_id_t vrf_id);
+extern struct interface *if_create_ifindex(ifindex_t ifindex, vrf_id_t vrf_id);
extern struct interface *if_lookup_by_index(ifindex_t, vrf_id_t vrf_id);
+extern struct interface *if_lookup_by_index_all_vrf(ifindex_t);
extern struct interface *if_lookup_exact_address(void *matchaddr, int family,
vrf_id_t vrf_id);
extern struct connected *if_lookup_address(void *matchaddr, int family,
@@ -493,6 +495,7 @@ size_t if_lookup_by_hwaddr(const uint8_t *hw_addr, size_t addrsz,
extern struct interface *if_lookup_by_name_all_vrf(const char *ifname);
extern struct interface *if_lookup_by_name(const char *ifname, vrf_id_t vrf_id);
extern struct interface *if_get_by_name(const char *ifname, vrf_id_t vrf_id);
+extern struct interface *if_get_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id);
extern void if_set_index(struct interface *ifp, ifindex_t ifindex);
/* Delete the interface, but do not free the structure, and leave it in the
diff --git a/lib/libfrr.c b/lib/libfrr.c
index 3294a61295..4301dc20ad 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -41,6 +41,7 @@
#include "northbound_cli.h"
#include "northbound_db.h"
#include "debug.h"
+#include "frrcu.h"
DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm))
DEFINE_KOOH(frr_early_fini, (), ())
@@ -409,7 +410,7 @@ static int frr_opt(int opt)
}
if (di->zpathspace)
fprintf(stderr,
- "-N option overriden by -z for zebra named socket path\n");
+ "-N option overridden by -z for zebra named socket path\n");
if (strchr(optarg, '/') || strchr(optarg, '.')) {
fprintf(stderr,
@@ -681,6 +682,7 @@ struct thread_master *frr_init(void)
log_filter_cmd_init();
log_ref_init();
+ log_ref_vty_init();
lib_error_init();
yang_init();
@@ -1080,6 +1082,7 @@ void frr_fini(void)
master = NULL;
closezlog();
/* frrmod_init -> nothing needed / hooks */
+ rcu_shutdown();
if (!debug_memstats_at_exit)
return;
diff --git a/lib/log.c b/lib/log.c
index 48ee0f6adb..51a0ddd6b7 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -387,10 +387,8 @@ void vzlog(int priority, const char *format, va_list args)
/* If it doesn't match on a filter, do nothing with the debug log */
if ((priority == LOG_DEBUG) && zlog_filter_count
- && vzlog_filter(zl, &tsctl, proto_str, priority, msg)) {
- pthread_mutex_unlock(&loglock);
+ && vzlog_filter(zl, &tsctl, proto_str, priority, msg))
goto out;
- }
/* call external hook */
hook_call(zebra_ext_log, priority, format, args);
@@ -561,9 +559,7 @@ static void crash_write(struct fbuf *fb, char *msgstart)
void zlog_signal(int signo, const char *action, void *siginfo_v,
void *program_counter)
{
-#ifdef SA_SIGINFO
siginfo_t *siginfo = siginfo_v;
-#endif
time_t now;
char buf[sizeof("DEFAULT: Received signal S at T (si_addr 0xP, PC 0xP); aborting...")
+ 100];
@@ -577,7 +573,6 @@ void zlog_signal(int signo, const char *action, void *siginfo_v,
msgstart = fb.pos;
bprintfrr(&fb, "Received signal %d at %lld", signo, (long long)now);
-#ifdef SA_SIGINFO
if (program_counter)
bprintfrr(&fb, " (si_addr 0x%tx, PC 0x%tx)",
(ptrdiff_t)siginfo->si_addr,
@@ -585,7 +580,6 @@ void zlog_signal(int signo, const char *action, void *siginfo_v,
else
bprintfrr(&fb, " (si_addr 0x%tx)",
(ptrdiff_t)siginfo->si_addr);
-#endif /* SA_SIGINFO */
bprintfrr(&fb, "; %s\n", action);
crash_write(&fb, msgstart);
@@ -1271,6 +1265,7 @@ void zlog_hexdump(const void *mem, unsigned int len)
size_t bs = ((len / 8) + 1) * 53 + 1;
char buf[bs];
char *s = buf;
+ const unsigned char *memch = mem;
memset(buf, 0, sizeof(buf));
@@ -1279,12 +1274,11 @@ void zlog_hexdump(const void *mem, unsigned int len)
/* print offset */
if (i % columns == 0)
s += snprintf(s, bs - (s - buf),
- "0x%016lx: ", (unsigned long)mem + i);
+ "0x%016lx: ", (unsigned long)memch + i);
/* print hex data */
if (i < len)
- s += snprintf(s, bs - (s - buf), "%02x ",
- 0xFF & ((const char *)mem)[i]);
+ s += snprintf(s, bs - (s - buf), "%02x ", memch[i]);
/* end of block, just aligning for ASCII dump */
else
@@ -1296,10 +1290,9 @@ void zlog_hexdump(const void *mem, unsigned int len)
/* end of block not really printing */
if (j >= len)
s += snprintf(s, bs - (s - buf), " ");
- else if (isprint((int)((const char *)mem)[j]))
- s += snprintf(
- s, bs - (s - buf), "%c",
- 0xFF & ((const char *)mem)[j]);
+ else if (isprint(memch[j]))
+ s += snprintf(s, bs - (s - buf), "%c",
+ memch[j]);
else /* other char */
s += snprintf(s, bs - (s - buf), ".");
}
diff --git a/lib/logicalrouter.c b/lib/logicalrouter.c
deleted file mode 100644
index da69ae5312..0000000000
--- a/lib/logicalrouter.c
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Logical Router functions.
- * Copyright (C) 2018 6WIND S.A.
- *
- * 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 "ns.h"
-#include "log.h"
-#include "memory.h"
-
-#include "command.h"
-#include "vty.h"
-#include "logicalrouter.h"
-
-/* Comment that useless define to avoid compilation error
- * in order to use it, one could provide the kind of NETNS to NS backend
- * so that the allocation will match the logical router
- * DEFINE_MTYPE_STATIC(LIB, LOGICALROUTER, "LogicalRouter Context")
- */
-DEFINE_MTYPE_STATIC(LIB, LOGICALROUTER_NAME, "Logical Router Name")
-
-/* Logical Router node has no interface. */
-static struct cmd_node logicalrouter_node = {LOGICALROUTER_NODE, "", 1};
-
-static int logicalrouter_backend;
-
-/* Get a NS. If not found, create one. */
-static struct ns *logicalrouter_get(ns_id_t ns_id)
-{
- struct ns *ns;
-
- ns = ns_lookup(ns_id);
- if (ns)
- return (ns);
- ns = ns_get_created(ns, NULL, ns_id);
- return ns;
-}
-
-static int logicalrouter_is_backend_netns(void)
-{
- return (logicalrouter_backend == LOGICALROUTER_BACKEND_NETNS);
-}
-
-
-DEFUN_NOSH (logicalrouter,
- logicalrouter_cmd,
- "logical-router (1-65535) ns NAME",
- "Enable a logical-router\n"
- "Specify the logical-router indentifier\n"
- "The Name Space\n"
- "The file name in " NS_RUN_DIR ", or a full pathname\n")
-{
- int idx_number = 1;
- int idx_name = 3;
- ns_id_t ns_id;
- struct ns *ns = NULL;
- char *pathname = ns_netns_pathname(vty, argv[idx_name]->arg);
-
- if (!pathname)
- return CMD_WARNING_CONFIG_FAILED;
-
- ns_id = strtoul(argv[idx_number]->arg, NULL, 10);
- ns = logicalrouter_get(ns_id);
-
- if (ns->name && strcmp(ns->name, pathname) != 0) {
- vty_out(vty, "NS %u is already configured with NETNS %s\n",
- ns->ns_id, ns->name);
- return CMD_WARNING;
- }
-
- if (!ns->name)
- ns->name = XSTRDUP(MTYPE_LOGICALROUTER_NAME, pathname);
-
- if (!ns_enable(ns, NULL)) {
- vty_out(vty, "Can not associate NS %u with NETNS %s\n",
- ns->ns_id, ns->name);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN (no_logicalrouter,
- no_logicalrouter_cmd,
- "no logical-router (1-65535) ns NAME",
- NO_STR
- "Enable a Logical-Router\n"
- "Specify the Logical-Router identifier\n"
- "The Name Space\n"
- "The file name in " NS_RUN_DIR ", or a full pathname\n")
-{
- int idx_number = 2;
- int idx_name = 4;
- ns_id_t ns_id;
- struct ns *ns = NULL;
- char *pathname = ns_netns_pathname(vty, argv[idx_name]->arg);
-
- if (!pathname)
- return CMD_WARNING_CONFIG_FAILED;
-
- ns_id = strtoul(argv[idx_number]->arg, NULL, 10);
- ns = ns_lookup(ns_id);
-
- if (!ns) {
- vty_out(vty, "NS %u is not found\n", ns_id);
- return CMD_SUCCESS;
- }
-
- if (ns->name && strcmp(ns->name, pathname) != 0) {
- vty_out(vty, "Incorrect NETNS file name\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- ns_disable(ns);
-
- if (ns->name) {
- XFREE(MTYPE_LOGICALROUTER_NAME, ns->name);
- ns->name = NULL;
- }
-
- return CMD_SUCCESS;
-}
-
-/* Initialize NS module. */
-void logicalrouter_init(int (*writefunc)(struct vty *vty))
-{
- if (ns_have_netns() && logicalrouter_is_backend_netns()) {
- /* Install LogicalRouter commands. */
- install_node(&logicalrouter_node, writefunc);
- install_element(CONFIG_NODE, &logicalrouter_cmd);
- install_element(CONFIG_NODE, &no_logicalrouter_cmd);
- }
-}
-
-void logicalrouter_terminate(void)
-{
- ns_terminate();
-}
-
-void logicalrouter_configure_backend(int backend_netns)
-{
- logicalrouter_backend = backend_netns;
-}
diff --git a/lib/logicalrouter.h b/lib/logicalrouter.h
deleted file mode 100644
index d18832ef70..0000000000
--- a/lib/logicalrouter.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Logical Router related header.
- * Copyright (C) 2018 6WIND S.A.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef _ZEBRA_LOGICAL_ROUTER_H
-#define _ZEBRA_LOGICAL_ROUTER_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Logical Router Backend defines */
-#define LOGICALROUTER_BACKEND_OFF 0
-#define LOGICALROUTER_BACKEND_NETNS 1
-
-/*
- * Logical Router initializer/destructor
- */
-extern void logicalrouter_init(int (*writefunc)(struct vty *vty));
-extern void logicalrouter_terminate(void);
-
-/* used to configure backend for logical router
- * Currently, the whole NETNS feature is exclusively shared
- * between logical router and VRF backend NETNS
- * However, when logical router feature will be available,
- * one can think of having exclusivity only per NETNS
- */
-extern void logicalrouter_configure_backend(int backend_netns);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /*_ZEBRA_LOGICAL_ROUTER_H*/
diff --git a/lib/netns_other.c b/lib/netns_other.c
index 4c7be05fab..b0aae4f8df 100644
--- a/lib/netns_other.c
+++ b/lib/netns_other.c
@@ -82,7 +82,7 @@ const char *ns_get_name(struct ns *ns)
}
/* only called from vrf ( when removing netns from vrf)
- * or at VRF or logical router termination
+ * or at VRF termination
*/
void ns_delete(struct ns *ns)
{
diff --git a/lib/ns.h b/lib/ns.h
index f3ad837889..1963b8a359 100644
--- a/lib/ns.h
+++ b/lib/ns.h
@@ -41,7 +41,7 @@ typedef uint32_t ns_id_t;
#ifdef HAVE_NETNS
#define NS_DEFAULT_NAME "/proc/self/ns/net"
#else /* !HAVE_NETNS */
-#define NS_DEFAULT_NAME "Default-logical-router"
+#define NS_DEFAULT_NAME "default-netns"
#endif /* HAVE_NETNS */
struct ns {
@@ -82,10 +82,10 @@ extern struct ns_head ns_tree;
* NS hooks
*/
-#define NS_NEW_HOOK 0 /* a new logical-router is just created */
-#define NS_DELETE_HOOK 1 /* a logical-router is to be deleted */
-#define NS_ENABLE_HOOK 2 /* a logical-router is ready to use */
-#define NS_DISABLE_HOOK 3 /* a logical-router is to be unusable */
+#define NS_NEW_HOOK 0 /* a new netns is just created */
+#define NS_DELETE_HOOK 1 /* a netns is to be deleted */
+#define NS_ENABLE_HOOK 2 /* a netns is ready to use */
+#define NS_DISABLE_HOOK 3 /* a netns is to be unusable */
/*
* Add a specific hook ns module.
@@ -128,7 +128,7 @@ extern void ns_walk_func(int (*func)(struct ns *));
extern const char *ns_get_name(struct ns *ns);
/* only called from vrf ( when removing netns from vrf)
- * or at VRF or logical router termination
+ * or at VRF termination
*/
extern void ns_delete(struct ns *ns);
diff --git a/lib/plist.c b/lib/plist.c
index 1ba8982499..64571a05b7 100644
--- a/lib/plist.c
+++ b/lib/plist.c
@@ -218,7 +218,7 @@ static struct prefix_list *prefix_list_insert(afi_t afi, int orf,
/* If name is made by all digit character. We treat it as
number. */
for (number = 0, i = 0; i < strlen(name); i++) {
- if (isdigit((int)name[i]))
+ if (isdigit((unsigned char)name[i]))
number = (number * 10) + (name[i] - '0');
else
break;
diff --git a/lib/pqueue.c b/lib/pqueue.c
deleted file mode 100644
index 87b54a681a..0000000000
--- a/lib/pqueue.c
+++ /dev/null
@@ -1,185 +0,0 @@
-/* Priority queue functions.
- * Copyright (C) 2003 Yasuhiro Ohara
- *
- * This file is part of GNU Zebra.
- *
- * GNU Zebra is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * GNU Zebra 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 "memory.h"
-#include "pqueue.h"
-
-DEFINE_MTYPE_STATIC(LIB, PQUEUE, "Priority queue")
-DEFINE_MTYPE_STATIC(LIB, PQUEUE_DATA, "Priority queue data")
-
-/* priority queue using heap sort */
-
-/* pqueue->cmp() controls the order of sorting (i.e, ascending or
- descending). If you want the left node to move upper of the heap
- binary tree, make cmp() to return less than 0. for example, if cmp
- (10, 20) returns -1, the sorting is ascending order. if cmp (10,
- 20) returns 1, the sorting is descending order. if cmp (10, 20)
- returns 0, this library does not do sorting (which will not be what
- you want). To be brief, if the contents of cmp_func (left, right)
- is left - right, dequeue () returns the smallest node. Otherwise
- (if the contents is right - left), dequeue () returns the largest
- node. */
-
-#define DATA_SIZE (sizeof (void *))
-#define PARENT_OF(x) ((x - 1) / 2)
-#define LEFT_OF(x) (2 * x + 1)
-#define RIGHT_OF(x) (2 * x + 2)
-#define HAVE_CHILD(x,q) (x < (q)->size / 2)
-
-void trickle_up(int index, struct pqueue *queue)
-{
- void *tmp;
-
- /* Save current node as tmp node. */
- tmp = queue->array[index];
-
- /* Continue until the node reaches top or the place where the parent
- node should be upper than the tmp node. */
- while (index > 0
- && (*queue->cmp)(tmp, queue->array[PARENT_OF(index)]) < 0) {
- /* actually trickle up */
- queue->array[index] = queue->array[PARENT_OF(index)];
- if (queue->update != NULL)
- (*queue->update)(queue->array[index], index);
- index = PARENT_OF(index);
- }
-
- /* Restore the tmp node to appropriate place. */
- queue->array[index] = tmp;
- if (queue->update != NULL)
- (*queue->update)(tmp, index);
-}
-
-void trickle_down(int index, struct pqueue *queue)
-{
- void *tmp;
- int which;
-
- /* Save current node as tmp node. */
- tmp = queue->array[index];
-
- /* Continue until the node have at least one (left) child. */
- while (HAVE_CHILD(index, queue)) {
- /* If right child exists, and if the right child is more proper
- to be moved upper. */
- if (RIGHT_OF(index) < queue->size
- && (*queue->cmp)(queue->array[LEFT_OF(index)],
- queue->array[RIGHT_OF(index)])
- > 0)
- which = RIGHT_OF(index);
- else
- which = LEFT_OF(index);
-
- /* If the tmp node should be upper than the child, break. */
- if ((*queue->cmp)(queue->array[which], tmp) > 0)
- break;
-
- /* Actually trickle down the tmp node. */
- queue->array[index] = queue->array[which];
- if (queue->update != NULL)
- (*queue->update)(queue->array[index], index);
- index = which;
- }
-
- /* Restore the tmp node to appropriate place. */
- queue->array[index] = tmp;
- if (queue->update != NULL)
- (*queue->update)(tmp, index);
-}
-
-struct pqueue *pqueue_create(void)
-{
- struct pqueue *queue;
-
- queue = XCALLOC(MTYPE_PQUEUE, sizeof(struct pqueue));
-
- queue->array =
- XCALLOC(MTYPE_PQUEUE_DATA, DATA_SIZE * PQUEUE_INIT_ARRAYSIZE);
- queue->array_size = PQUEUE_INIT_ARRAYSIZE;
-
- /* By default we want nothing to happen when a node changes. */
- queue->update = NULL;
- return queue;
-}
-
-void pqueue_delete(struct pqueue *queue)
-{
- XFREE(MTYPE_PQUEUE_DATA, queue->array);
- XFREE(MTYPE_PQUEUE, queue);
-}
-
-static int pqueue_expand(struct pqueue *queue)
-{
- void **newarray;
-
- newarray =
- XCALLOC(MTYPE_PQUEUE_DATA, queue->array_size * DATA_SIZE * 2);
-
- memcpy(newarray, queue->array, queue->array_size * DATA_SIZE);
-
- XFREE(MTYPE_PQUEUE_DATA, queue->array);
- queue->array = newarray;
- queue->array_size *= 2;
-
- return 1;
-}
-
-void pqueue_enqueue(void *data, struct pqueue *queue)
-{
- if (queue->size + 2 >= queue->array_size && !pqueue_expand(queue))
- return;
-
- queue->array[queue->size] = data;
- if (queue->update != NULL)
- (*queue->update)(data, queue->size);
- trickle_up(queue->size, queue);
- queue->size++;
-}
-
-void *pqueue_dequeue(struct pqueue *queue)
-{
- void *data = queue->array[0];
- queue->array[0] = queue->array[--queue->size];
- trickle_down(0, queue);
- return data;
-}
-
-void pqueue_remove_at(int index, struct pqueue *queue)
-{
- queue->array[index] = queue->array[--queue->size];
-
- if (index > 0
- && (*queue->cmp)(queue->array[index],
- queue->array[PARENT_OF(index)])
- < 0) {
- trickle_up(index, queue);
- } else {
- trickle_down(index, queue);
- }
-}
-
-void pqueue_remove(void *data, struct pqueue *queue)
-{
- for (int i = 0; i < queue->size; i++)
- if (queue->array[i] == data)
- pqueue_remove_at(i, queue);
-}
diff --git a/lib/pqueue.h b/lib/pqueue.h
deleted file mode 100644
index 032ee9db4c..0000000000
--- a/lib/pqueue.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* Priority queue functions.
- * Copyright (C) 2003 Yasuhiro Ohara
- *
- * This file is part of GNU Zebra.
- *
- * GNU Zebra is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * GNU Zebra is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef _ZEBRA_PQUEUE_H
-#define _ZEBRA_PQUEUE_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct pqueue {
- void **array;
- int array_size;
- int size;
-
- int (*cmp)(void *, void *);
- void (*update)(void *node, int actual_position);
-};
-
-#define PQUEUE_INIT_ARRAYSIZE 32
-
-extern struct pqueue *pqueue_create(void);
-extern void pqueue_delete(struct pqueue *queue);
-
-extern void pqueue_enqueue(void *data, struct pqueue *queue);
-extern void *pqueue_dequeue(struct pqueue *queue);
-extern void pqueue_remove_at(int index, struct pqueue *queue);
-extern void pqueue_remove(void *data, struct pqueue *queue);
-
-extern void trickle_down(int index, struct pqueue *queue);
-extern void trickle_up(int index, struct pqueue *queue);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _ZEBRA_PQUEUE_H */
diff --git a/lib/prefix.c b/lib/prefix.c
index 7abeebcd09..1a4a914e05 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -628,8 +628,15 @@ int prefix_match_network_statement(const struct prefix *n,
return 1;
}
-void prefix_copy(struct prefix *dest, const struct prefix *src)
+#ifdef __clang_analyzer__
+#undef prefix_copy /* cf. prefix.h */
+#endif
+
+void prefix_copy(union prefixptr udest, union prefixconstptr usrc)
{
+ struct prefix *dest = udest.p;
+ const struct prefix *src = usrc.p;
+
dest->family = src->family;
dest->prefixlen = src->prefixlen;
@@ -674,8 +681,11 @@ void prefix_copy(struct prefix *dest, const struct prefix *src)
* the same. Note that this routine has the same return value sense
* as '==' (which is different from prefix_cmp).
*/
-int prefix_same(const struct prefix *p1, const struct prefix *p2)
+int prefix_same(union prefixconstptr up1, union prefixconstptr up2)
{
+ const struct prefix *p1 = up1.p;
+ const struct prefix *p2 = up2.p;
+
if ((p1 && !p2) || (!p1 && p2))
return 0;
@@ -712,57 +722,59 @@ int prefix_same(const struct prefix *p1, const struct prefix *p2)
}
/*
- * Return 0 if the network prefixes represented by the struct prefix
- * arguments are the same prefix, and 1 otherwise. Network prefixes
- * are considered the same if the prefix lengths are equal and the
- * network parts are the same. Host bits (which are considered masked
+ * Return -1/0/1 comparing the prefixes in a way that gives a full/linear
+ * order.
+ *
+ * Network prefixes are considered the same if the prefix lengths are equal
+ * and the network parts are the same. Host bits (which are considered masked
* by the prefix length) are not significant. Thus, 10.0.0.1/8 and
* 10.0.0.2/8 are considered equivalent by this routine. Note that
* this routine has the same return sense as strcmp (which is different
* from prefix_same).
*/
-int prefix_cmp(const struct prefix *p1, const struct prefix *p2)
+int prefix_cmp(union prefixconstptr up1, union prefixconstptr up2)
{
+ const struct prefix *p1 = up1.p;
+ const struct prefix *p2 = up2.p;
int offset;
int shift;
+ int i;
/* Set both prefix's head pointer. */
const uint8_t *pp1;
const uint8_t *pp2;
if (p1->family != p2->family)
- return 1;
+ return numcmp(p1->family, p2->family);
if (p1->family == AF_FLOWSPEC) {
pp1 = (const uint8_t *)p1->u.prefix_flowspec.ptr;
pp2 = (const uint8_t *)p2->u.prefix_flowspec.ptr;
if (p1->u.prefix_flowspec.prefixlen !=
p2->u.prefix_flowspec.prefixlen)
- return 1;
+ return numcmp(p1->u.prefix_flowspec.prefixlen,
+ p2->u.prefix_flowspec.prefixlen);
offset = p1->u.prefix_flowspec.prefixlen;
while (offset--)
if (pp1[offset] != pp2[offset])
- return 1;
+ return numcmp(pp1[offset], pp2[offset]);
return 0;
}
pp1 = p1->u.val;
pp2 = p2->u.val;
if (p1->prefixlen != p2->prefixlen)
- return 1;
+ return numcmp(p1->prefixlen, p2->prefixlen);
offset = p1->prefixlen / PNBBY;
shift = p1->prefixlen % PNBBY;
- if (shift)
- if (maskbit[shift] & (pp1[offset] ^ pp2[offset]))
- return 1;
-
- while (offset--)
- if (pp1[offset] != pp2[offset])
- return 1;
+ i = memcmp(pp1, pp2, offset);
+ if (i)
+ return i;
- return 0;
+ return numcmp(pp1[offset] & maskbit[shift],
+ pp2[offset] & maskbit[shift]);
}
/*
diff --git a/lib/prefix.h b/lib/prefix.h
index d57b43dac6..e338140f1a 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -410,12 +410,20 @@ extern const char *prefix2str(union prefixconstptr, char *, int);
extern int prefix_match(const struct prefix *, const struct prefix *);
extern int prefix_match_network_statement(const struct prefix *,
const struct prefix *);
-extern int prefix_same(const struct prefix *, const struct prefix *);
-extern int prefix_cmp(const struct prefix *, const struct prefix *);
+extern int prefix_same(union prefixconstptr, union prefixconstptr);
+extern int prefix_cmp(union prefixconstptr, union prefixconstptr);
extern int prefix_common_bits(const struct prefix *, const struct prefix *);
-extern void prefix_copy(struct prefix *dest, const struct prefix *src);
+extern void prefix_copy(union prefixptr, union prefixconstptr);
extern void apply_mask(struct prefix *);
+#ifdef __clang_analyzer__
+/* clang-SA doesn't understand transparent unions, making it think that the
+ * target of prefix_copy is uninitialized. So just memset the target.
+ * cf. https://bugs.llvm.org/show_bug.cgi?id=42811
+ */
+#define prefix_copy(a, b) ({ memset(a, 0, sizeof(*a)); prefix_copy(a, b); })
+#endif
+
extern struct prefix *sockunion2prefix(const union sockunion *dest,
const union sockunion *mask);
extern struct prefix *sockunion2hostprefix(const union sockunion *,
diff --git a/lib/ptm_lib.c b/lib/ptm_lib.c
index 7f868beda4..a2ce9a0e2f 100644
--- a/lib/ptm_lib.c
+++ b/lib/ptm_lib.c
@@ -125,7 +125,7 @@ static int _ptm_lib_decode_header(csv_t *csv, int *msglen, int *version,
}
/* remove leading spaces */
for (i = j = 0; i < csv_field_len(fld); i++) {
- if (!isspace((int)hdr[i])) {
+ if (!isspace((unsigned char)hdr[i])) {
client_name[j] = hdr[i];
j++;
}
diff --git a/lib/routemap.c b/lib/routemap.c
index 2fee3a479e..eca02e8366 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -927,15 +927,15 @@ static const char *route_map_type_str(enum route_map_type type)
return "";
}
-static const char *route_map_result_str(route_map_result_t res)
+static const char *route_map_cmd_result_str(enum route_map_cmd_result_t res)
{
switch (res) {
case RMAP_MATCH:
return "match";
- case RMAP_DENYMATCH:
- return "deny";
case RMAP_NOMATCH:
return "no match";
+ case RMAP_NOOP:
+ return "noop";
case RMAP_ERROR:
return "error";
case RMAP_OKAY:
@@ -945,6 +945,18 @@ static const char *route_map_result_str(route_map_result_t res)
return "invalid";
}
+static const char *route_map_result_str(route_map_result_t res)
+{
+ switch (res) {
+ case RMAP_DENYMATCH:
+ return "deny";
+ case RMAP_PERMITMATCH:
+ return "permit";
+ }
+
+ return "invalid";
+}
+
static int route_map_empty(struct route_map *map)
{
if (map->head == NULL && map->tail == NULL)
@@ -1558,20 +1570,98 @@ int route_map_delete_set(struct route_map_index *index, const char *set_name,
return 1;
}
+static enum route_map_cmd_result_t
+route_map_apply_match(struct route_map_rule_list *match_list,
+ const struct prefix *prefix, route_map_object_t type,
+ void *object)
+{
+ enum route_map_cmd_result_t ret = RMAP_NOMATCH;
+ struct route_map_rule *match;
+ bool is_matched = false;
+
+
+ /* Check all match rule and if there is no match rule, go to the
+ set statement. */
+ if (!match_list->head)
+ ret = RMAP_MATCH;
+ else {
+ for (match = match_list->head; match; match = match->next) {
+ /*
+ * Try each match statement. If any match does not
+ * return RMAP_MATCH or RMAP_NOOP, return.
+ * Otherwise continue on to next match statement.
+ * All match statements must MATCH for
+ * end-result to be a match.
+ * (Exception:If match stmts result in a mix of
+ * MATCH/NOOP, then also end-result is a match)
+ * If all result in NOOP, end-result is NOOP.
+ */
+ ret = (*match->cmd->func_apply)(match->value, prefix,
+ type, object);
+
+ /*
+ * If the consolidated result of func_apply is:
+ * -----------------------------------------------
+ * | MATCH | NOMATCH | NOOP | Final Result |
+ * ------------------------------------------------
+ * | yes | yes | yes | NOMATCH |
+ * | no | no | yes | NOOP |
+ * | yes | no | yes | MATCH |
+ * | no | yes | yes | NOMATCH |
+ * |-----------------------------------------------
+ *
+ * Traditionally, all rules within route-map
+ * should match for it to MATCH.
+ * If there are noops within the route-map rules,
+ * it follows the above matrix.
+ *
+ * Eg: route-map rm1 permit 10
+ * match rule1
+ * match rule2
+ * match rule3
+ * ....
+ * route-map rm1 permit 20
+ * match ruleX
+ * match ruleY
+ * ...
+ */
+
+ switch (ret) {
+ case RMAP_MATCH:
+ is_matched = true;
+ break;
+
+ case RMAP_NOMATCH:
+ return ret;
+
+ case RMAP_NOOP:
+ if (is_matched)
+ ret = RMAP_MATCH;
+ break;
+
+ default:
+ break;
+ }
+
+ }
+ }
+ return ret;
+}
+
/* Apply route map's each index to the object.
The matrix for a route-map looks like this:
(note, this includes the description for the "NEXT"
and "GOTO" frobs now
- Match | No Match
- |
- permit action | cont
- |
- ------------------+---------------
- |
- deny deny | cont
- |
+ | Match | No Match | No op
+ |-----------|--------------|-------
+ permit | action | cont | cont.
+ | | default:deny | default:permit
+ -------------------+-----------------------
+ | deny | cont | cont.
+ deny | | default:deny | default:permit
+ |-----------|--------------|--------
action)
-Apply Set statements, accept route
@@ -1604,45 +1694,13 @@ int route_map_delete_set(struct route_map_index *index, const char *set_name,
We need to make sure our route-map processing matches the above
*/
-
-static route_map_result_t
-route_map_apply_match(struct route_map_rule_list *match_list,
- const struct prefix *prefix, route_map_object_t type,
- void *object)
-{
- route_map_result_t ret = RMAP_NOMATCH;
- struct route_map_rule *match;
-
-
- /* Check all match rule and if there is no match rule, go to the
- set statement. */
- if (!match_list->head)
- ret = RMAP_MATCH;
- else {
- for (match = match_list->head; match; match = match->next) {
- /* Try each match statement in turn, If any do not
- return
- RMAP_MATCH, return, otherwise continue on to next
- match
- statement. All match statements must match for
- end-result
- to be a match. */
- ret = (*match->cmd->func_apply)(match->value, prefix,
- type, object);
- if (ret != RMAP_MATCH)
- return ret;
- }
- }
- return ret;
-}
-
-/* Apply route map to the object. */
route_map_result_t route_map_apply(struct route_map *map,
const struct prefix *prefix,
route_map_object_t type, void *object)
{
static int recursion = 0;
- int ret = 0;
+ enum route_map_cmd_result_t match_ret = RMAP_NOMATCH;
+ route_map_result_t ret = RMAP_PERMITMATCH;
struct route_map_index *index;
struct route_map_rule *set;
char buf[PREFIX_STRLEN];
@@ -1656,7 +1714,7 @@ route_map_result_t route_map_apply(struct route_map *map,
return RMAP_DENYMATCH;
}
- if (map == NULL) {
+ if (map == NULL || map->head == NULL) {
ret = RMAP_DENYMATCH;
goto route_map_apply_end;
}
@@ -1665,29 +1723,64 @@ route_map_result_t route_map_apply(struct route_map *map,
for (index = map->head; index; index = index->next) {
/* Apply this index. */
index->applied++;
- ret = route_map_apply_match(&index->match_list, prefix, type,
- object);
+ match_ret = route_map_apply_match(&index->match_list, prefix,
+ type, object);
if (rmap_debug) {
zlog_debug("Route-map: %s, sequence: %d, prefix: %s, result: %s",
map->name, index->pref,
prefix2str(prefix, buf, sizeof(buf)),
- route_map_result_str(ret));
+ route_map_cmd_result_str(match_ret));
}
/* Now we apply the matrix from above */
- if (ret == RMAP_NOMATCH)
- /* 'cont' from matrix - continue to next route-map
- * sequence */
+ if (match_ret == RMAP_NOOP)
+ /*
+ * Do not change the return value. Retain the previous
+ * return value. Previous values can be:
+ * 1)permitmatch (if a nomatch was never
+ * seen before in this route-map.)
+ * 2)denymatch (if a nomatch was seen earlier in one
+ * of the previous sequences)
+ */
+
+ /*
+ * 'cont' from matrix - continue to next route-map
+ * sequence
+ */
continue;
- else if (ret == RMAP_MATCH) {
+ else if (match_ret == RMAP_NOMATCH) {
+
+ /*
+ * The return value is now changed to denymatch.
+ * So from here on out, even if we see more noops,
+ * we retain this return value and return this
+ * eventually if there are no matches.
+ */
+ ret = RMAP_DENYMATCH;
+
+ /*
+ * 'cont' from matrix - continue to next route-map
+ * sequence
+ */
+ continue;
+ } else if (match_ret == RMAP_MATCH) {
if (index->type == RMAP_PERMIT)
/* 'action' */
{
+ /* Match succeeded, rmap is of type permit */
+ ret = RMAP_PERMITMATCH;
+
/* permit+match must execute sets */
for (set = index->set_list.head; set;
set = set->next)
- ret = (*set->cmd->func_apply)(
+ /*
+ * set cmds return RMAP_OKAY or
+ * RMAP_ERROR. We do not care if
+ * set succeeded or not. So, ignore
+ * return code.
+ */
+ (void) (*set->cmd->func_apply)(
set->value, prefix, type,
object);
@@ -1741,8 +1834,6 @@ route_map_result_t route_map_apply(struct route_map *map,
}
}
}
- /* Finally route-map does not match at all. */
- ret = RMAP_DENYMATCH;
route_map_apply_end:
if (rmap_debug) {
diff --git a/lib/routemap.h b/lib/routemap.h
index 90df1048ed..f9ad0f64a9 100644
--- a/lib/routemap.h
+++ b/lib/routemap.h
@@ -38,13 +38,35 @@ DECLARE_MTYPE(ROUTE_MAP_COMPILED)
enum route_map_type { RMAP_PERMIT, RMAP_DENY, RMAP_ANY };
typedef enum {
- RMAP_MATCH,
RMAP_DENYMATCH,
- RMAP_NOMATCH,
- RMAP_ERROR,
- RMAP_OKAY
+ RMAP_PERMITMATCH
} route_map_result_t;
+/*
+ * Route-map match or set result "Eg: match evpn vni xx"
+ * route-map match cmd always returns match/nomatch/noop
+ * match--> found a match
+ * nomatch--> didnt find a match
+ * noop--> not applicable
+ * route-map set retuns okay/error
+ * okay --> set was successful
+ * error --> set was not successful
+ */
+enum route_map_cmd_result_t {
+ /*
+ * route-map match cmd results
+ */
+ RMAP_MATCH,
+ RMAP_NOMATCH,
+ RMAP_NOOP,
+ /*
+ * route-map set cmd results
+ */
+ RMAP_OKAY,
+ RMAP_ERROR
+};
+
+
typedef enum {
RMAP_RIP,
RMAP_RIPNG,
@@ -91,10 +113,10 @@ struct route_map_rule_cmd {
const char *str;
/* Function for value set or match. */
- route_map_result_t (*func_apply)(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object);
+ enum route_map_cmd_result_t (*func_apply)(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object);
/* Compile argument and return result as void *. */
void *(*func_compile)(const char *);
diff --git a/lib/seqlock.c b/lib/seqlock.c
index 223d14952c..c05ec19db4 100644
--- a/lib/seqlock.c
+++ b/lib/seqlock.c
@@ -25,6 +25,7 @@
#include "config.h"
#endif
+#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <errno.h>
@@ -35,44 +36,75 @@
#include "seqlock.h"
+/****************************************
+ * OS specific synchronization wrappers *
+ ****************************************/
+
+/*
+ * Linux: sys_futex()
+ */
#ifdef HAVE_SYNC_LINUX_FUTEX
-/* Linux-specific - sys_futex() */
#include <sys/syscall.h>
#include <linux/futex.h>
-static long sys_futex(void *addr1, int op, int val1, struct timespec *timeout,
- void *addr2, int val3)
+static long sys_futex(void *addr1, int op, int val1,
+ const struct timespec *timeout, void *addr2, int val3)
{
return syscall(SYS_futex, addr1, op, val1, timeout, addr2, val3);
}
#define wait_once(sqlo, val) \
sys_futex((int *)&sqlo->pos, FUTEX_WAIT, (int)val, NULL, NULL, 0)
+#define wait_time(sqlo, val, time, reltime) \
+ sys_futex((int *)&sqlo->pos, FUTEX_WAIT_BITSET, (int)val, time, \
+ NULL, ~0U)
#define wait_poke(sqlo) \
sys_futex((int *)&sqlo->pos, FUTEX_WAKE, INT_MAX, NULL, NULL, 0)
+/*
+ * OpenBSD: sys_futex(), almost the same as on Linux
+ */
#elif defined(HAVE_SYNC_OPENBSD_FUTEX)
-/* OpenBSD variant of the above. untested, not upstream in OpenBSD. */
#include <sys/syscall.h>
#include <sys/futex.h>
+#define TIME_RELATIVE 1
+
#define wait_once(sqlo, val) \
futex((int *)&sqlo->pos, FUTEX_WAIT, (int)val, NULL, NULL, 0)
+#define wait_time(sqlo, val, time, reltime) \
+ futex((int *)&sqlo->pos, FUTEX_WAIT, (int)val, reltime, NULL, 0)
#define wait_poke(sqlo) \
futex((int *)&sqlo->pos, FUTEX_WAKE, INT_MAX, NULL, NULL, 0)
+/*
+ * FreeBSD: _umtx_op()
+ */
#elif defined(HAVE_SYNC_UMTX_OP)
-/* FreeBSD-specific: umtx_op() */
#include <sys/umtx.h>
#define wait_once(sqlo, val) \
_umtx_op((void *)&sqlo->pos, UMTX_OP_WAIT_UINT, val, NULL, NULL)
+static int wait_time(struct seqlock *sqlo, uint32_t val,
+ const struct timespec *abstime,
+ const struct timespec *reltime)
+{
+ struct _umtx_time t;
+ t._flags = UMTX_ABSTIME;
+ t._clockid = CLOCK_MONOTONIC;
+ memcpy(&t._timeout, abstime, sizeof(t._timeout));
+ return _umtx_op((void *)&sqlo->pos, UMTX_OP_WAIT_UINT, val,
+ (void *)(uintptr_t) sizeof(t), &t);
+}
#define wait_poke(sqlo) \
_umtx_op((void *)&sqlo->pos, UMTX_OP_WAKE, INT_MAX, NULL, NULL)
-#else
-/* generic version. used on *BSD, Solaris and OSX.
+/*
+ * generic version. used on NetBSD, Solaris and OSX. really shitty.
*/
+#else
+
+#define TIME_ABS_REALTIME 1
#define wait_init(sqlo) do { \
pthread_mutex_init(&sqlo->lock, NULL); \
@@ -80,6 +112,9 @@ static long sys_futex(void *addr1, int op, int val1, struct timespec *timeout,
} while (0)
#define wait_prep(sqlo) pthread_mutex_lock(&sqlo->lock)
#define wait_once(sqlo, val) pthread_cond_wait(&sqlo->wake, &sqlo->lock)
+#define wait_time(sqlo, val, time, reltime) \
+ pthread_cond_timedwait(&sqlo->wake, \
+ &sqlo->lock, time);
#define wait_done(sqlo) pthread_mutex_unlock(&sqlo->lock)
#define wait_poke(sqlo) do { \
pthread_mutex_lock(&sqlo->lock); \
@@ -103,18 +138,112 @@ void seqlock_wait(struct seqlock *sqlo, seqlock_val_t val)
seqlock_assert_valid(val);
wait_prep(sqlo);
- while (1) {
- cur = atomic_load_explicit(&sqlo->pos, memory_order_acquire);
- if (!(cur & 1))
+ cur = atomic_load_explicit(&sqlo->pos, memory_order_relaxed);
+
+ while (cur & SEQLOCK_HELD) {
+ cal = SEQLOCK_VAL(cur) - val - 1;
+ assert(cal < 0x40000000 || cal > 0xc0000000);
+ if (cal < 0x80000000)
break;
- cal = cur - val - 1;
+
+ if ((cur & SEQLOCK_WAITERS)
+ || atomic_compare_exchange_weak_explicit(
+ &sqlo->pos, &cur, cur | SEQLOCK_WAITERS,
+ memory_order_relaxed, memory_order_relaxed)) {
+ wait_once(sqlo, cur | SEQLOCK_WAITERS);
+ cur = atomic_load_explicit(&sqlo->pos,
+ memory_order_relaxed);
+ }
+ /* else: we failed to swap in cur because it just changed */
+ }
+ wait_done(sqlo);
+}
+
+bool seqlock_timedwait(struct seqlock *sqlo, seqlock_val_t val,
+ const struct timespec *abs_monotime_limit)
+{
+/*
+ * ABS_REALTIME - used on NetBSD, Solaris and OSX
+ */
+#if TIME_ABS_REALTIME
+#define time_arg1 &abs_rt
+#define time_arg2 NULL
+#define time_prep
+ struct timespec curmono, abs_rt;
+
+ clock_gettime(CLOCK_MONOTONIC, &curmono);
+ clock_gettime(CLOCK_REALTIME, &abs_rt);
+
+ abs_rt.tv_nsec += abs_monotime_limit->tv_nsec - curmono.tv_nsec;
+ if (abs_rt.tv_nsec < 0) {
+ abs_rt.tv_sec--;
+ abs_rt.tv_nsec += 1000000000;
+ } else if (abs_rt.tv_nsec >= 1000000000) {
+ abs_rt.tv_sec++;
+ abs_rt.tv_nsec -= 1000000000;
+ }
+ abs_rt.tv_sec += abs_monotime_limit->tv_sec - curmono.tv_sec;
+
+/*
+ * RELATIVE - used on OpenBSD (might get a patch to get absolute monotime)
+ */
+#elif TIME_RELATIVE
+ struct timespec reltime;
+
+#define time_arg1 abs_monotime_limit
+#define time_arg2 &reltime
+#define time_prep \
+ clock_gettime(CLOCK_MONOTONIC, &reltime); \
+ reltime.tv_sec = abs_monotime_limit.tv_sec - reltime.tv_sec; \
+ reltime.tv_nsec = abs_monotime_limit.tv_nsec - reltime.tv_nsec; \
+ if (reltime.tv_nsec < 0) { \
+ reltime.tv_sec--; \
+ reltime.tv_nsec += 1000000000; \
+ }
+/*
+ * FreeBSD & Linux: absolute time re. CLOCK_MONOTONIC
+ */
+#else
+#define time_arg1 abs_monotime_limit
+#define time_arg2 NULL
+#define time_prep
+#endif
+
+ bool ret = true;
+ seqlock_val_t cur, cal;
+
+ seqlock_assert_valid(val);
+
+ wait_prep(sqlo);
+ cur = atomic_load_explicit(&sqlo->pos, memory_order_relaxed);
+
+ while (cur & SEQLOCK_HELD) {
+ cal = SEQLOCK_VAL(cur) - val - 1;
assert(cal < 0x40000000 || cal > 0xc0000000);
if (cal < 0x80000000)
break;
- wait_once(sqlo, cur);
+ if ((cur & SEQLOCK_WAITERS)
+ || atomic_compare_exchange_weak_explicit(
+ &sqlo->pos, &cur, cur | SEQLOCK_WAITERS,
+ memory_order_relaxed, memory_order_relaxed)) {
+ int rv;
+
+ time_prep
+
+ rv = wait_time(sqlo, cur | SEQLOCK_WAITERS, time_arg1,
+ time_arg2);
+ if (rv) {
+ ret = false;
+ break;
+ }
+ cur = atomic_load_explicit(&sqlo->pos,
+ memory_order_relaxed);
+ }
}
wait_done(sqlo);
+
+ return ret;
}
bool seqlock_check(struct seqlock *sqlo, seqlock_val_t val)
@@ -123,26 +252,32 @@ bool seqlock_check(struct seqlock *sqlo, seqlock_val_t val)
seqlock_assert_valid(val);
- cur = atomic_load_explicit(&sqlo->pos, memory_order_acquire);
- if (!(cur & 1))
+ cur = atomic_load_explicit(&sqlo->pos, memory_order_relaxed);
+ if (!(cur & SEQLOCK_HELD))
return 1;
- cur -= val;
+ cur = SEQLOCK_VAL(cur) - val - 1;
assert(cur < 0x40000000 || cur > 0xc0000000);
return cur < 0x80000000;
}
void seqlock_acquire_val(struct seqlock *sqlo, seqlock_val_t val)
{
+ seqlock_val_t prev;
+
seqlock_assert_valid(val);
- atomic_store_explicit(&sqlo->pos, val, memory_order_release);
- wait_poke(sqlo);
+ prev = atomic_exchange_explicit(&sqlo->pos, val, memory_order_relaxed);
+ if (prev & SEQLOCK_WAITERS)
+ wait_poke(sqlo);
}
void seqlock_release(struct seqlock *sqlo)
{
- atomic_store_explicit(&sqlo->pos, 0, memory_order_release);
- wait_poke(sqlo);
+ seqlock_val_t prev;
+
+ prev = atomic_exchange_explicit(&sqlo->pos, 0, memory_order_relaxed);
+ if (prev & SEQLOCK_WAITERS)
+ wait_poke(sqlo);
}
void seqlock_init(struct seqlock *sqlo)
@@ -154,14 +289,23 @@ void seqlock_init(struct seqlock *sqlo)
seqlock_val_t seqlock_cur(struct seqlock *sqlo)
{
- return atomic_load_explicit(&sqlo->pos, memory_order_acquire);
+ return SEQLOCK_VAL(atomic_load_explicit(&sqlo->pos,
+ memory_order_relaxed));
}
seqlock_val_t seqlock_bump(struct seqlock *sqlo)
{
- seqlock_val_t val;
+ seqlock_val_t val, cur;
+
+ cur = atomic_load_explicit(&sqlo->pos, memory_order_relaxed);
+ seqlock_assert_valid(cur);
+
+ do {
+ val = SEQLOCK_VAL(cur) + SEQLOCK_INCR;
+ } while (!atomic_compare_exchange_weak_explicit(&sqlo->pos, &cur, val,
+ memory_order_relaxed, memory_order_relaxed));
- val = atomic_fetch_add_explicit(&sqlo->pos, 2, memory_order_release);
- wait_poke(sqlo);
+ if (cur & SEQLOCK_WAITERS)
+ wait_poke(sqlo);
return val;
}
diff --git a/lib/seqlock.h b/lib/seqlock.h
index eef05a4307..b551e3ffc4 100644
--- a/lib/seqlock.h
+++ b/lib/seqlock.h
@@ -54,12 +54,28 @@
*/
/* use sequentially increasing "ticket numbers". lowest bit will always
- * be 1 to have a 'cleared' indication (i.e., counts 1,3,5,7,etc. )
+ * be 1 to have a 'cleared' indication (i.e., counts 1,5,9,13,etc. )
+ * 2nd lowest bit is used to indicate we have waiters.
*/
typedef _Atomic uint32_t seqlock_ctr_t;
typedef uint32_t seqlock_val_t;
-#define seqlock_assert_valid(val) assert(val & 1)
+#define seqlock_assert_valid(val) assert((val) & SEQLOCK_HELD)
+/* NB: SEQLOCK_WAITERS is only allowed if SEQLOCK_HELD is also set; can't
+ * have waiters on an unheld seqlock
+ */
+#define SEQLOCK_HELD (1U << 0)
+#define SEQLOCK_WAITERS (1U << 1)
+#define SEQLOCK_VAL(n) ((n) & ~SEQLOCK_WAITERS)
+#define SEQLOCK_STARTVAL 1U
+#define SEQLOCK_INCR 4U
+
+/* TODO: originally, this was using "atomic_fetch_add", which is the reason
+ * bit 0 is used to indicate held state. With SEQLOCK_WAITERS added, there's
+ * no fetch_add anymore (cmpxchg loop instead), so we don't need to use bit 0
+ * for this anymore & can just special-case the value 0 for it and skip it in
+ * counting.
+ */
struct seqlock {
/* always used */
@@ -74,8 +90,16 @@ struct seqlock {
extern void seqlock_init(struct seqlock *sqlo);
-/* while (sqlo <= val) - wait until seqlock->pos > val, or seqlock unheld */
+/* basically: "while (sqlo <= val) wait();"
+ * returns when sqlo > val || !seqlock_held(sqlo)
+ */
extern void seqlock_wait(struct seqlock *sqlo, seqlock_val_t val);
+
+/* same, but time-limited (limit is an absolute CLOCK_MONOTONIC value) */
+extern bool seqlock_timedwait(struct seqlock *sqlo, seqlock_val_t val,
+ const struct timespec *abs_monotime_limit);
+
+/* one-shot test, returns true if seqlock_wait would return immediately */
extern bool seqlock_check(struct seqlock *sqlo, seqlock_val_t val);
static inline bool seqlock_held(struct seqlock *sqlo)
@@ -85,12 +109,20 @@ static inline bool seqlock_held(struct seqlock *sqlo)
/* sqlo - get seqlock position -- for the "counter" seqlock */
extern seqlock_val_t seqlock_cur(struct seqlock *sqlo);
-/* sqlo++ - note: like x++, returns previous value, before bumping */
+
+/* ++sqlo (but atomic & wakes waiters) - returns value that we bumped to.
+ *
+ * guarantees:
+ * - each seqlock_bump call bumps the position by exactly one SEQLOCK_INCR.
+ * There are no skipped/missed or multiple increments.
+ * - each return value is only returned from one seqlock_bump() call
+ */
extern seqlock_val_t seqlock_bump(struct seqlock *sqlo);
/* sqlo = val - can be used on held seqlock. */
extern void seqlock_acquire_val(struct seqlock *sqlo, seqlock_val_t val);
+
/* sqlo = ref - standard pattern: acquire relative to other seqlock */
static inline void seqlock_acquire(struct seqlock *sqlo, struct seqlock *ref)
{
diff --git a/lib/sigevent.c b/lib/sigevent.c
index d02b074223..fcd85d0d43 100644
--- a/lib/sigevent.c
+++ b/lib/sigevent.c
@@ -24,7 +24,6 @@
#include <memory.h>
#include <lib_errors.h>
-#ifdef SA_SIGINFO
#ifdef HAVE_UCONTEXT_H
#ifdef GNU_LINUX
/* get REG_EIP from ucontext.h */
@@ -34,7 +33,6 @@
#endif /* GNU_LINUX */
#include <ucontext.h>
#endif /* HAVE_UCONTEXT_H */
-#endif /* SA_SIGINFO */
/* master signals descriptor struct */
@@ -158,8 +156,6 @@ static int signal_set(int signo)
return 0;
}
-#ifdef SA_SIGINFO
-
/* XXX This function should be enhanced to support more platforms
(it currently works only on Linux/x86). */
static void *program_counter(void *context)
@@ -199,41 +195,19 @@ static void *program_counter(void *context)
return NULL;
}
-#endif /* SA_SIGINFO */
-
static void __attribute__((noreturn))
-exit_handler(int signo
-#ifdef SA_SIGINFO
- ,
- siginfo_t *siginfo, void *context
-#endif
- )
+exit_handler(int signo, siginfo_t *siginfo, void *context)
{
-#ifndef SA_SIGINFO
- void *siginfo = NULL;
- void *pc = NULL;
-#else
void *pc = program_counter(context);
-#endif
zlog_signal(signo, "exiting...", siginfo, pc);
_exit(128 + signo);
}
static void __attribute__((noreturn))
-core_handler(int signo
-#ifdef SA_SIGINFO
- ,
- siginfo_t *siginfo, void *context
-#endif
- )
+core_handler(int signo, siginfo_t *siginfo, void *context)
{
-#ifndef SA_SIGINFO
- void *siginfo = NULL;
- void *pc = NULL;
-#else
void *pc = program_counter(context);
-#endif
/* make sure we don't hang in here. default for SIGALRM is terminate.
* - if we're in backtrace for more than a second, abort. */
@@ -290,12 +264,7 @@ static void trap_default_signals(void)
static const struct {
const int *sigs;
unsigned int nsigs;
- void (*handler)(int signo
-#ifdef SA_SIGINFO
- ,
- siginfo_t *info, void *context
-#endif
- );
+ void (*handler)(int signo, siginfo_t *info, void *context);
} sigmap[] = {
{core_signals, array_size(core_signals), core_handler},
{exit_signals, array_size(exit_signals), exit_handler},
@@ -316,15 +285,10 @@ static void trap_default_signals(void)
act.sa_handler = SIG_IGN;
act.sa_flags = 0;
} else {
-#ifdef SA_SIGINFO
/* Request extra arguments to signal
* handler. */
act.sa_sigaction = sigmap[i].handler;
act.sa_flags = SA_SIGINFO;
-#else
- act.sa_handler = sigmap[i].handler;
- act.sa_flags = 0;
-#endif
#ifdef SA_RESETHAND
/* don't try to print backtraces
* recursively */
diff --git a/lib/stream.c b/lib/stream.c
index 6c187bd359..c67bc3c993 100644
--- a/lib/stream.c
+++ b/lib/stream.c
@@ -904,20 +904,30 @@ int stream_put_prefix(struct stream *s, struct prefix *p)
/* Put NLRI with label */
int stream_put_labeled_prefix(struct stream *s, struct prefix *p,
- mpls_label_t *label)
+ mpls_label_t *label, int addpath_encode,
+ uint32_t addpath_tx_id)
{
size_t psize;
+ size_t psize_with_addpath;
uint8_t *label_pnt = (uint8_t *)label;
STREAM_VERIFY_SANE(s);
psize = PSIZE(p->prefixlen);
+ psize_with_addpath = psize + (addpath_encode ? 4 : 0);
- if (STREAM_WRITEABLE(s) < (psize + 3)) {
+ if (STREAM_WRITEABLE(s) < (psize_with_addpath + 3)) {
STREAM_BOUND_WARN(s, "put");
return 0;
}
+ if (addpath_encode) {
+ s->data[s->endp++] = (uint8_t)(addpath_tx_id >> 24);
+ s->data[s->endp++] = (uint8_t)(addpath_tx_id >> 16);
+ s->data[s->endp++] = (uint8_t)(addpath_tx_id >> 8);
+ s->data[s->endp++] = (uint8_t)addpath_tx_id;
+ }
+
stream_putc(s, (p->prefixlen + 24));
stream_putc(s, label_pnt[0]);
stream_putc(s, label_pnt[1]);
diff --git a/lib/stream.h b/lib/stream.h
index 5341bfa40b..a903ec0ea5 100644
--- a/lib/stream.h
+++ b/lib/stream.h
@@ -199,7 +199,8 @@ extern int stream_put_prefix_addpath(struct stream *, struct prefix *,
uint32_t addpath_tx_id);
extern int stream_put_prefix(struct stream *, struct prefix *);
extern int stream_put_labeled_prefix(struct stream *, struct prefix *,
- mpls_label_t *);
+ mpls_label_t *, int addpath_encode,
+ uint32_t addpath_tx_id);
extern void stream_get(void *, struct stream *, size_t);
extern bool stream_get2(void *data, struct stream *s, size_t size);
extern void stream_get_from(void *, struct stream *, size_t, size_t);
diff --git a/lib/subdir.am b/lib/subdir.am
index aa89622028..2be7537bcc 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -21,6 +21,7 @@ lib_libfrr_la_SOURCES = \
lib/distribute.c \
lib/ferr.c \
lib/filter.c \
+ lib/frrcu.c \
lib/frrlua.c \
lib/frr_pthread.c \
lib/frrstr.c \
@@ -61,7 +62,6 @@ lib_libfrr_la_SOURCES = \
lib/openbsd-tree.c \
lib/pid_output.c \
lib/plist.c \
- lib/pqueue.c \
lib/prefix.c \
lib/privs.c \
lib/ptm_lib.c \
@@ -95,7 +95,6 @@ lib_libfrr_la_SOURCES = \
lib/yang_translator.c \
lib/yang_wrappers.c \
lib/zclient.c \
- lib/logicalrouter.c \
lib/printf/printf-pos.c \
lib/printf/vfprintf.c \
lib/printf/glue.c \
@@ -113,7 +112,6 @@ vtysh_scan += \
$(top_srcdir)/lib/if.c \
$(top_srcdir)/lib/if_rmap.c \
$(top_srcdir)/lib/keychain.c \
- $(top_srcdir)/lib/logicalrouter.c \
$(top_srcdir)/lib/nexthop_group.c \
$(top_srcdir)/lib/plist.c \
$(top_srcdir)/lib/routemap.c \
@@ -163,6 +161,7 @@ pkginclude_HEADERS += \
lib/frrlua.h \
lib/frr_pthread.h \
lib/frratomic.h \
+ lib/frrcu.h \
lib/frrstr.h \
lib/getopt.h \
lib/graph.h \
@@ -200,7 +199,6 @@ pkginclude_HEADERS += \
lib/openbsd-queue.h \
lib/openbsd-tree.h \
lib/plist.h \
- lib/pqueue.h \
lib/prefix.h \
lib/printfrr.h \
lib/privs.h \
@@ -241,7 +239,6 @@ pkginclude_HEADERS += \
lib/zassert.h \
lib/zclient.h \
lib/zebra.h \
- lib/logicalrouter.h \
lib/pbr.h \
# end
diff --git a/lib/thread.c b/lib/thread.c
index fc2de09df0..943b849ebf 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -25,9 +25,9 @@
#include "thread.h"
#include "memory.h"
+#include "frrcu.h"
#include "log.h"
#include "hash.h"
-#include "pqueue.h"
#include "command.h"
#include "sigevent.h"
#include "network.h"
@@ -42,6 +42,22 @@ DEFINE_MTYPE_STATIC(LIB, THREAD_STATS, "Thread stats")
DECLARE_LIST(thread_list, struct thread, threaditem)
+static int thread_timer_cmp(const struct thread *a, const struct thread *b)
+{
+ if (a->u.sands.tv_sec < b->u.sands.tv_sec)
+ return -1;
+ if (a->u.sands.tv_sec > b->u.sands.tv_sec)
+ return 1;
+ if (a->u.sands.tv_usec < b->u.sands.tv_usec)
+ return -1;
+ if (a->u.sands.tv_usec > b->u.sands.tv_usec)
+ return 1;
+ return 0;
+}
+
+DECLARE_HEAP(thread_timer_list, struct thread, timeritem,
+ thread_timer_cmp)
+
#if defined(__APPLE__)
#include <mach/mach.h>
#include <mach/mach_time.h>
@@ -401,25 +417,6 @@ void thread_cmd_init(void)
/* CLI end ------------------------------------------------------------------ */
-static int thread_timer_cmp(void *a, void *b)
-{
- struct thread *thread_a = a;
- struct thread *thread_b = b;
-
- if (timercmp(&thread_a->u.sands, &thread_b->u.sands, <))
- return -1;
- if (timercmp(&thread_a->u.sands, &thread_b->u.sands, >))
- return 1;
- return 0;
-}
-
-static void thread_timer_update(void *node, int actual_position)
-{
- struct thread *thread = node;
-
- thread->index = actual_position;
-}
-
static void cancelreq_del(void *cr)
{
XFREE(MTYPE_TMP, cr);
@@ -464,11 +461,7 @@ struct thread_master *thread_master_create(const char *name)
thread_list_init(&rv->event);
thread_list_init(&rv->ready);
thread_list_init(&rv->unuse);
-
- /* Initialize the timer queues */
- rv->timer = pqueue_create();
- rv->timer->cmp = thread_timer_cmp;
- rv->timer->update = thread_timer_update;
+ thread_timer_list_init(&rv->timer);
/* Initialize thread_fetch() settings */
rv->spin = true;
@@ -566,16 +559,6 @@ static void thread_array_free(struct thread_master *m,
XFREE(MTYPE_THREAD_POLL, thread_array);
}
-static void thread_queue_free(struct thread_master *m, struct pqueue *queue)
-{
- int i;
-
- for (i = 0; i < queue->size; i++)
- thread_free(m, queue->array[i]);
-
- pqueue_delete(queue);
-}
-
/*
* thread_master_free_unused
*
@@ -598,6 +581,8 @@ void thread_master_free_unused(struct thread_master *m)
/* Stop thread scheduler. */
void thread_master_free(struct thread_master *m)
{
+ struct thread *t;
+
pthread_mutex_lock(&masters_mtx);
{
listnode_delete(masters, m);
@@ -609,7 +594,8 @@ void thread_master_free(struct thread_master *m)
thread_array_free(m, m->read);
thread_array_free(m, m->write);
- thread_queue_free(m, m->timer);
+ while ((t = thread_timer_list_pop(&m->timer)))
+ thread_free(m, t);
thread_list_free(m, &m->event);
thread_list_free(m, &m->ready);
thread_list_free(m, &m->unuse);
@@ -683,7 +669,6 @@ static struct thread *thread_get(struct thread_master *m, uint8_t type,
thread->add_type = type;
thread->master = m;
thread->arg = arg;
- thread->index = -1;
thread->yield = THREAD_YIELD_TIME_SLOT; /* default */
thread->ref = NULL;
@@ -729,7 +714,7 @@ static int fd_poll(struct thread_master *m, struct pollfd *pfds, nfds_t pfdsize,
{
/* If timer_wait is null here, that means poll() should block
* indefinitely,
- * unless the thread_master has overriden it by setting
+ * unless the thread_master has overridden it by setting
* ->selectpoll_timeout.
* If the value is positive, it specifies the maximum number of
* milliseconds
@@ -753,6 +738,9 @@ static int fd_poll(struct thread_master *m, struct pollfd *pfds, nfds_t pfdsize,
< 0) // effect a poll (return immediately)
timeout = 0;
+ rcu_read_unlock();
+ rcu_assert_read_unlocked();
+
/* add poll pipe poker */
assert(count + 1 < pfdsize);
pfds[count].fd = m->io_pipe[0];
@@ -766,6 +754,8 @@ static int fd_poll(struct thread_master *m, struct pollfd *pfds, nfds_t pfdsize,
while (read(m->io_pipe[0], &trash, sizeof(trash)) > 0)
;
+ rcu_read_lock();
+
return num;
}
@@ -854,7 +844,6 @@ funcname_thread_add_timer_timeval(struct thread_master *m,
struct thread **t_ptr, debugargdef)
{
struct thread *thread;
- struct pqueue *queue;
assert(m != NULL);
@@ -870,7 +859,6 @@ funcname_thread_add_timer_timeval(struct thread_master *m,
return NULL;
}
- queue = m->timer;
thread = thread_get(m, type, func, arg, debugargpass);
pthread_mutex_lock(&thread->mtx);
@@ -878,7 +866,7 @@ funcname_thread_add_timer_timeval(struct thread_master *m,
monotime(&thread->u.sands);
timeradd(&thread->u.sands, time_relative,
&thread->u.sands);
- pqueue_enqueue(thread, queue);
+ thread_timer_list_add(&m->timer, thread);
if (t_ptr) {
*t_ptr = thread;
thread->ref = t_ptr;
@@ -1055,7 +1043,6 @@ static void thread_cancel_rw(struct thread_master *master, int fd, short state)
static void do_thread_cancel(struct thread_master *master)
{
struct thread_list_head *list = NULL;
- struct pqueue *queue = NULL;
struct thread **thread_array = NULL;
struct thread *thread;
@@ -1111,7 +1098,7 @@ static void do_thread_cancel(struct thread_master *master)
thread_array = master->write;
break;
case THREAD_TIMER:
- queue = master->timer;
+ thread_timer_list_del(&master->timer, thread);
break;
case THREAD_EVENT:
list = &master->event;
@@ -1124,16 +1111,10 @@ static void do_thread_cancel(struct thread_master *master)
break;
}
- if (queue) {
- assert(thread->index >= 0);
- assert(thread == queue->array[thread->index]);
- pqueue_remove_at(thread->index, queue);
- } else if (list) {
+ if (list) {
thread_list_del(list, thread);
} else if (thread_array) {
thread_array[thread->u.fd] = NULL;
- } else {
- assert(!"Thread should be either in queue or list or array!");
}
if (thread->ref)
@@ -1251,15 +1232,15 @@ void thread_cancel_async(struct thread_master *master, struct thread **thread,
}
/* ------------------------------------------------------------------------- */
-static struct timeval *thread_timer_wait(struct pqueue *queue,
+static struct timeval *thread_timer_wait(struct thread_timer_list_head *timers,
struct timeval *timer_val)
{
- if (queue->size) {
- struct thread *next_timer = queue->array[0];
- monotime_until(&next_timer->u.sands, timer_val);
- return timer_val;
- }
- return NULL;
+ if (!thread_timer_list_count(timers))
+ return NULL;
+
+ struct thread *next_timer = thread_timer_list_first(timers);
+ monotime_until(&next_timer->u.sands, timer_val);
+ return timer_val;
}
static struct thread *thread_run(struct thread_master *m, struct thread *thread,
@@ -1369,17 +1350,16 @@ static void thread_process_io(struct thread_master *m, unsigned int num)
}
/* Add all timers that have popped to the ready list. */
-static unsigned int thread_process_timers(struct pqueue *queue,
+static unsigned int thread_process_timers(struct thread_timer_list_head *timers,
struct timeval *timenow)
{
struct thread *thread;
unsigned int ready = 0;
- while (queue->size) {
- thread = queue->array[0];
+ while ((thread = thread_timer_list_first(timers))) {
if (timercmp(timenow, &thread->u.sands, <))
return ready;
- pqueue_dequeue(queue);
+ thread_timer_list_pop(timers);
thread->type = THREAD_READY;
thread_list_add_tail(&thread->master->ready, thread);
ready++;
@@ -1461,7 +1441,7 @@ struct thread *thread_fetch(struct thread_master *m, struct thread *fetch)
* once per loop to avoid starvation by events
*/
if (!thread_list_count(&m->ready))
- tw = thread_timer_wait(m->timer, &tv);
+ tw = thread_timer_wait(&m->timer, &tv);
if (thread_list_count(&m->ready) ||
(tw && !timercmp(tw, &zerotime, >)))
@@ -1506,7 +1486,7 @@ struct thread *thread_fetch(struct thread_master *m, struct thread *fetch)
/* Post timers to ready queue. */
monotime(&now);
- thread_process_timers(m->timer, &now);
+ thread_process_timers(&m->timer, &now);
/* Post I/O to ready queue. */
if (num > 0)
diff --git a/lib/thread.h b/lib/thread.h
index 7897265120..412a4d93bf 100644
--- a/lib/thread.h
+++ b/lib/thread.h
@@ -41,8 +41,7 @@ struct rusage_t {
#define GETRUSAGE(X) thread_getrusage(X)
PREDECL_LIST(thread_list)
-
-struct pqueue;
+PREDECL_HEAP(thread_timer_list)
struct fd_handler {
/* number of pfd that fit in the allocated space of pfds. This is a
@@ -73,7 +72,7 @@ struct thread_master {
struct thread **read;
struct thread **write;
- struct pqueue *timer;
+ struct thread_timer_list_head timer;
struct thread_list_head event, ready, unuse;
struct list *cancel_req;
bool canceled;
@@ -95,6 +94,7 @@ struct thread {
uint8_t type; /* thread type */
uint8_t add_type; /* thread type */
struct thread_list_item threaditem;
+ struct thread_timer_list_item timeritem;
struct thread **ref; /* external reference (if given) */
struct thread_master *master; /* pointer to the struct thread_master */
int (*func)(struct thread *); /* event function */
@@ -104,7 +104,6 @@ struct thread {
int fd; /* file descriptor in case of r/w */
struct timeval sands; /* rest of time sands value. */
} u;
- int index; /* queue position for timers */
struct timeval real;
struct cpu_thread_history *hist; /* cache pointer to cpu_history */
unsigned long yield; /* yield time in microseconds */
diff --git a/lib/typerb.c b/lib/typerb.c
index 4c48d6434f..3886fc678e 100644
--- a/lib/typerb.c
+++ b/lib/typerb.c
@@ -333,9 +333,10 @@ color:
return (old);
}
-void typed_rb_remove(struct rbt_tree *rbt, struct rb_entry *rbe)
+struct typed_rb_entry *typed_rb_remove(struct rbt_tree *rbt,
+ struct rb_entry *rbe)
{
- rbe_remove(rbt, rbe);
+ return rbe_remove(rbt, rbe);
}
struct typed_rb_entry *typed_rb_insert(struct rbt_tree *rbt,
diff --git a/lib/typerb.h b/lib/typerb.h
index ce8446f853..2d7b0ba637 100644
--- a/lib/typerb.h
+++ b/lib/typerb.h
@@ -38,29 +38,30 @@ struct typed_rb_root {
size_t count;
};
-struct typed_rb_entry *typed_rb_insert(struct typed_rb_root *,
+struct typed_rb_entry *typed_rb_insert(struct typed_rb_root *rbt,
struct typed_rb_entry *rbe,
int (*cmpfn)(
const struct typed_rb_entry *a,
const struct typed_rb_entry *b));
-void typed_rb_remove(struct typed_rb_root *, struct typed_rb_entry *rbe);
-struct typed_rb_entry *typed_rb_find(struct typed_rb_root *,
+struct typed_rb_entry *typed_rb_remove(struct typed_rb_root *rbt,
+ struct typed_rb_entry *rbe);
+struct typed_rb_entry *typed_rb_find(struct typed_rb_root *rbt,
const struct typed_rb_entry *rbe,
int (*cmpfn)(
const struct typed_rb_entry *a,
const struct typed_rb_entry *b));
-struct typed_rb_entry *typed_rb_find_gteq(struct typed_rb_root *,
+struct typed_rb_entry *typed_rb_find_gteq(struct typed_rb_root *rbt,
const struct typed_rb_entry *rbe,
int (*cmpfn)(
const struct typed_rb_entry *a,
const struct typed_rb_entry *b));
-struct typed_rb_entry *typed_rb_find_lt(struct typed_rb_root *,
+struct typed_rb_entry *typed_rb_find_lt(struct typed_rb_root *rbt,
const struct typed_rb_entry *rbe,
int (*cmpfn)(
const struct typed_rb_entry *a,
const struct typed_rb_entry *b));
-struct typed_rb_entry *typed_rb_min(struct typed_rb_root *);
-struct typed_rb_entry *typed_rb_next(struct typed_rb_entry *);
+struct typed_rb_entry *typed_rb_min(struct typed_rb_root *rbt);
+struct typed_rb_entry *typed_rb_next(struct typed_rb_entry *rbe);
#define _PREDECL_RBTREE(prefix) \
struct prefix ## _head { struct typed_rb_root rr; }; \
@@ -99,9 +100,11 @@ macro_inline type *prefix ## _find_lt(struct prefix##_head *h, \
re = typed_rb_find_lt(&h->rr, &item->field.re, cmpfn_nuq); \
return container_of_null(re, type, field.re); \
} \
-macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \
+macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
{ \
- typed_rb_remove(&h->rr, &item->field.re); \
+ struct typed_rb_entry *re; \
+ re = typed_rb_remove(&h->rr, &item->field.re); \
+ return container_of_null(re, type, field.re); \
} \
macro_inline type *prefix ## _pop(struct prefix##_head *h) \
{ \
@@ -130,7 +133,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
re = item ? typed_rb_next(&item->field.re) : NULL; \
return container_of_null(re, type, field.re); \
} \
-macro_pure size_t prefix ## _count(struct prefix##_head *h) \
+macro_pure size_t prefix ## _count(const struct prefix##_head *h) \
{ \
return h->rr.count; \
} \
diff --git a/lib/typesafe.c b/lib/typesafe.c
index f2ca67b7c6..7e5939d5b3 100644
--- a/lib/typesafe.c
+++ b/lib/typesafe.c
@@ -341,13 +341,14 @@ struct sskip_item *typesafe_skiplist_find_lt(struct sskip_head *head,
return best;
}
-void typesafe_skiplist_del(struct sskip_head *head, struct sskip_item *item,
- int (*cmpfn)(const struct sskip_item *a,
- const struct sskip_item *b))
+struct sskip_item *typesafe_skiplist_del(
+ struct sskip_head *head, struct sskip_item *item,
+ int (*cmpfn)(const struct sskip_item *a, const struct sskip_item *b))
{
size_t level = SKIPLIST_MAXDEPTH;
struct sskip_item *prev = &head->hitem, *next;
int cmpval;
+ bool found = false;
while (level) {
next = sl_level_get(prev, level - 1);
@@ -359,6 +360,7 @@ void typesafe_skiplist_del(struct sskip_head *head, struct sskip_item *item,
sl_level_set(prev, level - 1,
sl_level_get(item, level - 1));
level--;
+ found = true;
continue;
}
cmpval = cmpfn(next, item);
@@ -369,6 +371,9 @@ void typesafe_skiplist_del(struct sskip_head *head, struct sskip_item *item,
level--;
}
+ if (!found)
+ return NULL;
+
/* TBD: assert when trying to remove non-existing item? */
head->count--;
@@ -379,6 +384,8 @@ void typesafe_skiplist_del(struct sskip_head *head, struct sskip_item *item,
XFREE(MTYPE_SKIPLIST_OFLOW, oflow);
}
memset(item, 0, sizeof(*item));
+
+ return item;
}
struct sskip_item *typesafe_skiplist_pop(struct sskip_head *head)
diff --git a/lib/typesafe.h b/lib/typesafe.h
index 0a4ed69e4e..c30d73d1b3 100644
--- a/lib/typesafe.h
+++ b/lib/typesafe.h
@@ -109,17 +109,18 @@ macro_inline void prefix ## _add_after(struct prefix##_head *h, \
typesafe_list_add(&h->sh, nextp, &item->field.si); \
} \
/* TODO: del_hint */ \
-macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \
+macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
{ \
struct slist_item **iter = &h->sh.first; \
while (*iter && *iter != &item->field.si) \
iter = &(*iter)->next; \
if (!*iter) \
- return; \
+ return NULL; \
h->sh.count--; \
*iter = item->field.si.next; \
if (!item->field.si.next) \
h->sh.last_next = iter; \
+ return item; \
} \
macro_inline type *prefix ## _pop(struct prefix##_head *h) \
{ \
@@ -149,7 +150,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
sitem = &item->field.si; \
return container_of_null(sitem->next, type, field.si); \
} \
-macro_pure size_t prefix ## _count(struct prefix##_head *h) \
+macro_pure size_t prefix ## _count(const struct prefix##_head *h) \
{ \
return h->sh.count; \
} \
@@ -212,13 +213,14 @@ macro_inline void prefix ## _add_after(struct prefix##_head *h, \
prev = after ? &after->field.di : &h->dh.hitem; \
typesafe_dlist_add(&h->dh, prev, &item->field.di); \
} \
-macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \
+macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
{ \
struct dlist_item *ditem = &item->field.di; \
ditem->prev->next = ditem->next; \
ditem->next->prev = ditem->prev; \
h->dh.count--; \
ditem->prev = ditem->next = NULL; \
+ return item; \
} \
macro_inline type *prefix ## _pop(struct prefix##_head *h) \
{ \
@@ -250,7 +252,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
return NULL; \
return prefix ## _next(h, item); \
} \
-macro_pure size_t prefix ## _count(struct prefix##_head *h) \
+macro_pure size_t prefix ## _count(const struct prefix##_head *h) \
{ \
return h->dh.count; \
} \
@@ -308,7 +310,7 @@ macro_inline type *prefix ## _add(struct prefix##_head *h, type *item) \
h->hh.count++; \
return NULL; \
} \
-macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \
+macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
{ \
struct heap_item *other; \
uint32_t index = item->field.hi.index; \
@@ -321,6 +323,7 @@ macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \
typesafe_heap_pushdown(&h->hh, index, other, prefix ## __cmp); \
if (HEAP_RESIZE_TRESH_DN(h)) \
typesafe_heap_resize(&h->hh, false); \
+ return item; \
} \
macro_inline type *prefix ## _pop(struct prefix##_head *h) \
{ \
@@ -354,7 +357,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
return NULL; \
return prefix ## _next(h, item); \
} \
-macro_pure size_t prefix ## _count(struct prefix##_head *h) \
+macro_pure size_t prefix ## _count(const struct prefix##_head *h) \
{ \
return h->hh.count; \
} \
@@ -434,7 +437,7 @@ macro_inline type *prefix ## _find_gteq(struct prefix##_head *h, \
struct ssort_item *sitem = h->sh.first; \
int cmpval = 0; \
while (sitem && (cmpval = cmpfn_nuq( \
- container_of(sitem, type, field.si), item) < 0)) \
+ container_of(sitem, type, field.si), item)) < 0) \
sitem = sitem->next; \
return container_of_null(sitem, type, field.si); \
} \
@@ -444,20 +447,21 @@ macro_inline type *prefix ## _find_lt(struct prefix##_head *h, \
struct ssort_item *prev = NULL, *sitem = h->sh.first; \
int cmpval = 0; \
while (sitem && (cmpval = cmpfn_nuq( \
- container_of(sitem, type, field.si), item) < 0)) \
+ container_of(sitem, type, field.si), item)) < 0) \
sitem = (prev = sitem)->next; \
return container_of_null(prev, type, field.si); \
} \
/* TODO: del_hint */ \
-macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \
+macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
{ \
struct ssort_item **iter = &h->sh.first; \
while (*iter && *iter != &item->field.si) \
iter = &(*iter)->next; \
if (!*iter) \
- return; \
+ return NULL; \
h->sh.count--; \
*iter = item->field.si.next; \
+ return item; \
} \
macro_inline type *prefix ## _pop(struct prefix##_head *h) \
{ \
@@ -485,7 +489,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
sitem = &item->field.si; \
return container_of_null(sitem->next, type, field.si); \
} \
-macro_pure size_t prefix ## _count(struct prefix##_head *h) \
+macro_pure size_t prefix ## _count(const struct prefix##_head *h) \
{ \
return h->sh.count; \
} \
@@ -499,7 +503,7 @@ macro_inline type *prefix ## _find(struct prefix##_head *h, const type *item) \
struct ssort_item *sitem = h->sh.first; \
int cmpval = 0; \
while (sitem && (cmpval = cmpfn( \
- container_of(sitem, type, field.si), item) < 0)) \
+ container_of(sitem, type, field.si), item)) < 0) \
sitem = sitem->next; \
if (!sitem || cmpval > 0) \
return NULL; \
@@ -617,10 +621,10 @@ macro_inline type *prefix ## _find(struct prefix##_head *h, const type *item) \
} \
return NULL; \
} \
-macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \
+macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
{ \
if (!h->hh.tabshift) \
- return; \
+ return NULL; \
uint32_t hval = item->field.hi.hashval, hbits = HASH_KEY(h->hh, hval); \
struct thash_item **np = &h->hh.entries[hbits]; \
while (*np && (*np)->hashval < hval) \
@@ -628,12 +632,13 @@ macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \
while (*np && *np != &item->field.hi && (*np)->hashval == hval) \
np = &(*np)->next; \
if (*np != &item->field.hi) \
- return; \
+ return NULL; \
*np = item->field.hi.next; \
item->field.hi.next = NULL; \
h->hh.count--; \
if (HASH_SHRINK_THRESHOLD(h->hh)) \
typesafe_hash_shrink(&h->hh); \
+ return item; \
} \
macro_inline type *prefix ## _pop(struct prefix##_head *h) \
{ \
@@ -675,7 +680,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
return NULL; \
return prefix ## _next(h, item); \
} \
-macro_pure size_t prefix ## _count(struct prefix##_head *h) \
+macro_pure size_t prefix ## _count(const struct prefix##_head *h) \
{ \
return h->hh.count; \
} \
@@ -751,9 +756,11 @@ macro_inline type *prefix ## _find_lt(struct prefix##_head *h, \
&item->field.si, cmpfn_nuq); \
return container_of_null(sitem, type, field.si); \
} \
-macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \
+macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
{ \
- typesafe_skiplist_del(&h->sh, &item->field.si, cmpfn_uq); \
+ struct sskip_item *sitem = typesafe_skiplist_del(&h->sh, \
+ &item->field.si, cmpfn_uq); \
+ return container_of_null(sitem, type, field.si); \
} \
macro_inline type *prefix ## _pop(struct prefix##_head *h) \
{ \
@@ -776,7 +783,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
next = item ? item->field.si.next[0] : NULL; \
return container_of_null(next, type, field.si); \
} \
-macro_pure size_t prefix ## _count(struct prefix##_head *h) \
+macro_pure size_t prefix ## _count(const struct prefix##_head *h) \
{ \
return h->sh.count; \
} \
@@ -848,8 +855,8 @@ extern struct sskip_item *typesafe_skiplist_find_lt(struct sskip_head *head,
const struct sskip_item *item, int (*cmpfn)(
const struct sskip_item *a,
const struct sskip_item *b));
-extern void typesafe_skiplist_del(struct sskip_head *head,
- struct sskip_item *item, int (*cmpfn)(
+extern struct sskip_item *typesafe_skiplist_del(
+ struct sskip_head *head, struct sskip_item *item, int (*cmpfn)(
const struct sskip_item *a,
const struct sskip_item *b));
extern struct sskip_item *typesafe_skiplist_pop(struct sskip_head *head);
diff --git a/lib/vty.c b/lib/vty.c
index 18a449f647..c1535802cf 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -337,7 +337,8 @@ void vty_hello(struct vty *vty)
/* work backwards to ignore trailling isspace()
*/
for (s = buf + strlen(buf);
- (s > buf) && isspace((int)*(s - 1)); s--)
+ (s > buf) && isspace((unsigned char)s[-1]);
+ s--)
;
*s = '\0';
vty_out(vty, "%s\n", buf);
@@ -468,7 +469,7 @@ static int vty_command(struct vty *vty, char *buf)
cp = buf;
if (cp != NULL) {
/* Skip white spaces. */
- while (isspace((int)*cp) && *cp != '\0')
+ while (isspace((unsigned char)*cp) && *cp != '\0')
cp++;
}
if (cp != NULL && *cp != '\0') {
@@ -892,7 +893,7 @@ static void vty_complete_command(struct vty *vty)
return;
/* In case of 'help \t'. */
- if (isspace((int)vty->buf[vty->length - 1]))
+ if (isspace((unsigned char)vty->buf[vty->length - 1]))
vector_set(vline, NULL);
matched = cmd_complete_command(vline, vty, &ret);
@@ -1006,7 +1007,7 @@ static void vty_describe_command(struct vty *vty)
if (vline == NULL) {
vline = vector_init(1);
vector_set(vline, NULL);
- } else if (isspace((int)vty->buf[vty->length - 1]))
+ } else if (isspace((unsigned char)vty->buf[vty->length - 1]))
vector_set(vline, NULL);
describe = cmd_describe_command(vline, vty, &ret);
diff --git a/lib/zebra.h b/lib/zebra.h
index 22239f8e60..789a93a3c4 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -134,6 +134,10 @@ typedef unsigned char uint8_t;
#endif
#endif
+#ifdef CRYPTO_OPENSSL
+#include <openssl/evp.h>
+#endif
+
#include "openbsd-tree.h"
#include <netinet/in.h>
@@ -356,6 +360,7 @@ typedef enum {
/* Subsequent Address Family Identifier. */
typedef enum {
+ SAFI_UNSPEC = 0,
SAFI_UNICAST = 1,
SAFI_MULTICAST = 2,
SAFI_MPLS_VPN = 3,
diff --git a/m4/ax_python.m4 b/m4/ax_python.m4
index 32043c81ae..66338511a3 100644
--- a/m4/ax_python.m4
+++ b/m4/ax_python.m4
@@ -186,7 +186,11 @@ AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
AC_MSG_RESULT([yes])
PYTHON_CFLAGS="`\"$pycfg\" --includes`"
- PYTHON_LIBS="`\"$pycfg\" --ldflags`"
+ if test x"${py_ver}" == x"3.8" || test x"{py_ver}" == x"3.9"; then
+ PYTHON_LIBS="`\"$pycfg\" --ldflags --embed`"
+ else
+ PYTHON_LIBS="`\"$pycfg\" --ldflags`"
+ fi
AC_MSG_CHECKING([whether ${pycfg} provides a working build environment])
_FRR_PYTHON_DEVENV([$py_hex], [
diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c
index 946bbf8cc9..33b9f71b5f 100644
--- a/ospf6d/ospf6_asbr.c
+++ b/ospf6d/ospf6_asbr.c
@@ -1018,7 +1018,7 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
unsigned int nexthop_num,
struct in6_addr *nexthop, route_tag_t tag)
{
- int ret;
+ route_map_result_t ret;
struct ospf6_route troute;
struct ospf6_external_info tinfo;
struct ospf6_route *route, *match;
@@ -1355,7 +1355,7 @@ static void ospf6_redistribute_show_config(struct vty *vty)
/* Routemap Functions */
-static route_map_result_t
+static enum route_map_cmd_result_t
ospf6_routemap_rule_match_address_prefixlist(void *rule,
const struct prefix *prefix,
route_map_object_t type,
@@ -1395,7 +1395,7 @@ struct route_map_rule_cmd ospf6_routemap_rule_match_address_prefixlist_cmd = {
/* `match interface IFNAME' */
/* Match function should return 1 if match is success else return
zero. */
-static route_map_result_t
+static enum route_map_cmd_result_t
ospf6_routemap_rule_match_interface(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -1433,10 +1433,9 @@ struct route_map_rule_cmd ospf6_routemap_rule_match_interface_cmd = {
ospf6_routemap_rule_match_interface_free};
/* Match function for matching route tags */
-static route_map_result_t ospf6_routemap_rule_match_tag(void *rule,
- const struct prefix *p,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+ospf6_routemap_rule_match_tag(void *rule, const struct prefix *p,
+ route_map_object_t type, void *object)
{
route_tag_t *tag = rule;
struct ospf6_route *route = object;
@@ -1453,7 +1452,7 @@ static struct route_map_rule_cmd ospf6_routemap_rule_match_tag_cmd = {
route_map_rule_tag_free,
};
-static route_map_result_t
+static enum route_map_cmd_result_t
ospf6_routemap_rule_set_metric_type(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -1489,7 +1488,7 @@ struct route_map_rule_cmd ospf6_routemap_rule_set_metric_type_cmd = {
ospf6_routemap_rule_set_metric_type_free,
};
-static route_map_result_t
+static enum route_map_cmd_result_t
ospf6_routemap_rule_set_metric(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -1524,7 +1523,7 @@ struct route_map_rule_cmd ospf6_routemap_rule_set_metric_cmd = {
ospf6_routemap_rule_set_metric_free,
};
-static route_map_result_t
+static enum route_map_cmd_result_t
ospf6_routemap_rule_set_forwarding(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -1562,10 +1561,9 @@ struct route_map_rule_cmd ospf6_routemap_rule_set_forwarding_cmd = {
ospf6_routemap_rule_set_forwarding_free,
};
-static route_map_result_t ospf6_routemap_rule_set_tag(void *rule,
- const struct prefix *p,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+ospf6_routemap_rule_set_tag(void *rule, const struct prefix *p,
+ route_map_object_t type, void *object)
{
route_tag_t *tag = rule;
struct ospf6_route *route = object;
diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c
index af16c5aa7c..8454016b2e 100644
--- a/ospf6d/ospf6_zebra.c
+++ b/ospf6d/ospf6_zebra.c
@@ -258,7 +258,7 @@ DEFUN (show_zebra,
return CMD_SUCCESS;
}
- vty_out(vty, "Zebra Infomation\n");
+ vty_out(vty, "Zebra Information\n");
vty_out(vty, " fail: %d\n", zclient->fail);
vty_out(vty, " redistribute default: %d\n",
vrf_bitmap_check(zclient->default_information[AFI_IP6],
diff --git a/ospfd/ospf_errors.c b/ospfd/ospf_errors.c
index dd02160195..a985efc668 100644
--- a/ospfd/ospf_errors.c
+++ b/ospfd/ospf_errors.c
@@ -39,7 +39,7 @@ static struct log_ref ferr_ospf_warn[] = {
},
{
.code = EC_OSPF_PACKET,
- .title = "OSPF has detected packet information missmatch",
+ .title = "OSPF has detected packet information mismatch",
.description = "OSPF has detected that packet information received is incorrect",
.suggestion = "Ensure interface configuration is correct, gather log files from here and the peer and open an Issue",
},
diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c
index 6d1e44996e..1d85a04984 100644
--- a/ospfd/ospf_flood.c
+++ b/ospfd/ospf_flood.c
@@ -83,6 +83,9 @@ struct external_info *ospf_external_info_check(struct ospf *ospf,
struct as_external_lsa *al;
struct prefix_ipv4 p;
struct route_node *rn;
+ struct list *ext_list;
+ struct listnode *node;
+ struct ospf_external *ext;
int type;
al = (struct as_external_lsa *)lsa->data;
@@ -91,7 +94,7 @@ struct external_info *ospf_external_info_check(struct ospf *ospf,
p.prefix = lsa->data->id;
p.prefixlen = ip_masklen(al->mask);
- for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) {
+ for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
int redist_on = 0;
redist_on =
@@ -105,10 +108,6 @@ struct external_info *ospf_external_info_check(struct ospf *ospf,
ospf->vrf_id));
// Pending: check for MI above.
if (redist_on) {
- struct list *ext_list;
- struct listnode *node;
- struct ospf_external *ext;
-
ext_list = ospf->external[type];
if (!ext_list)
continue;
@@ -129,6 +128,22 @@ struct external_info *ospf_external_info_check(struct ospf *ospf,
}
}
+ if (is_prefix_default(&p) && ospf->external[DEFAULT_ROUTE]) {
+ ext_list = ospf->external[DEFAULT_ROUTE];
+
+ for (ALL_LIST_ELEMENTS_RO(ext_list, node, ext)) {
+ if (!ext->external_info)
+ continue;
+
+ rn = route_node_lookup(ext->external_info,
+ (struct prefix *)&p);
+ if (!rn)
+ continue;
+ route_unlock_node(rn);
+ if (rn->info != NULL)
+ return (struct external_info *)rn->info;
+ }
+ }
return NULL;
}
diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c
index bf46d22031..db41df7c47 100644
--- a/ospfd/ospf_lsa.c
+++ b/ospfd/ospf_lsa.c
@@ -1979,6 +1979,13 @@ struct ospf_lsa *ospf_external_lsa_originate(struct ospf *ospf,
*/
+ if (ospf->router_id.s_addr == 0) {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug("LSA[Type5:%pI4]: deferring AS-external-LSA origination, router ID is zero",
+ &ei->p.prefix);
+ return NULL;
+ }
+
/* Check the AS-external-LSA should be originated. */
if (!ospf_redistribute_check(ospf, ei, NULL))
return NULL;
@@ -2019,50 +2026,6 @@ struct ospf_lsa *ospf_external_lsa_originate(struct ospf *ospf,
return new;
}
-/* Originate AS-external-LSA from external info with initial flag. */
-int ospf_external_lsa_originate_timer(struct thread *thread)
-{
- struct ospf *ospf = THREAD_ARG(thread);
- struct route_node *rn;
- struct external_info *ei;
- struct route_table *rt;
- int type = THREAD_VAL(thread);
- struct list *ext_list;
- struct listnode *node;
- struct ospf_external *ext;
-
- ospf->t_external_lsa = NULL;
-
- ext_list = ospf->external[type];
- if (!ext_list)
- return 0;
-
- for (ALL_LIST_ELEMENTS_RO(ext_list, node, ext)) {
- /* Originate As-external-LSA from all type of distribute source.
- */
- rt = ext->external_info;
- if (!rt)
- continue;
-
- for (rn = route_top(rt); rn; rn = route_next(rn)) {
- ei = rn->info;
-
- if (!ei)
- continue;
-
- if (is_prefix_default((struct prefix_ipv4 *)&ei->p))
- continue;
-
- if (!ospf_external_lsa_originate(ospf, ei))
- flog_warn(
- EC_OSPF_LSA_INSTALL_FAILURE,
- "LSA: AS-external-LSA was not originated.");
- }
- }
-
- return 0;
-}
-
static struct external_info *ospf_default_external_info(struct ospf *ospf)
{
int type;
@@ -2102,31 +2065,52 @@ static struct external_info *ospf_default_external_info(struct ospf *ospf)
return NULL;
}
-int ospf_default_originate_timer(struct thread *thread)
+void ospf_external_lsa_rid_change(struct ospf *ospf)
{
- struct prefix_ipv4 p;
- struct in_addr nexthop;
struct external_info *ei;
- struct ospf *ospf;
+ int type;
- ospf = THREAD_ARG(thread);
+ for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
+ struct route_node *rn;
+ struct route_table *rt;
+ struct list *ext_list;
+ struct listnode *node;
+ struct ospf_external *ext;
- p.family = AF_INET;
- p.prefix.s_addr = 0;
- p.prefixlen = 0;
+ ext_list = ospf->external[type];
+ if (!ext_list)
+ continue;
- if (ospf->default_originate == DEFAULT_ORIGINATE_ALWAYS) {
- /* If there is no default route via redistribute,
- then originate AS-external-LSA with nexthop 0 (self). */
- nexthop.s_addr = 0;
- ospf_external_info_add(ospf, DEFAULT_ROUTE, 0, p, 0, nexthop,
- 0);
- }
+ for (ALL_LIST_ELEMENTS_RO(ext_list, node, ext)) {
+ /* Originate As-external-LSA from all type of
+ * distribute source.
+ */
+ rt = ext->external_info;
+ if (!rt)
+ continue;
- if ((ei = ospf_default_external_info(ospf)))
- ospf_external_lsa_originate(ospf, ei);
+ for (rn = route_top(rt); rn; rn = route_next(rn)) {
+ ei = rn->info;
- return 0;
+ if (!ei)
+ continue;
+
+ if (is_prefix_default(
+ (struct prefix_ipv4 *)&ei->p))
+ continue;
+
+ if (!ospf_external_lsa_originate(ospf, ei))
+ flog_warn(EC_OSPF_LSA_INSTALL_FAILURE,
+ "LSA: AS-external-LSA was not originated.");
+ }
+ }
+ }
+
+ ei = ospf_default_external_info(ospf);
+ if (ei && !ospf_external_lsa_originate(ospf, ei)) {
+ flog_warn(EC_OSPF_LSA_INSTALL_FAILURE,
+ "LSA: AS-external-LSA for default route was not originated.");
+ }
}
/* Flush any NSSA LSAs for given prefix */
@@ -2218,44 +2202,20 @@ void ospf_external_lsa_refresh_default(struct ospf *ospf)
ei = ospf_default_external_info(ospf);
lsa = ospf_external_info_find_lsa(ospf, &p);
- if (ei) {
- if (lsa) {
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug(
- "LSA[Type5:0.0.0.0]: Refresh AS-external-LSA %p",
- (void *)lsa);
- ospf_external_lsa_refresh(ospf, lsa, ei,
- LSA_REFRESH_FORCE);
- } else {
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug(
- "LSA[Type5:0.0.0.0]: Originate AS-external-LSA");
- ospf_external_lsa_originate(ospf, ei);
- }
- } else {
- if (lsa) {
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug(
- "LSA[Type5:0.0.0.0]: Flush AS-external-LSA");
- ospf_refresher_unregister_lsa(ospf, lsa);
- ospf_lsa_flush_as(ospf, lsa);
- }
- }
-}
-
-void ospf_default_originate_lsa_update(struct ospf *ospf)
-{
- struct prefix_ipv4 p;
- struct ospf_lsa *lsa;
-
- p.family = AF_INET;
- p.prefixlen = 0;
- p.prefix.s_addr = 0;
-
- lsa = ospf_external_info_find_lsa(ospf, &p);
- if (lsa && IS_LSA_MAXAGE(lsa)) {
- ospf_discard_from_db(ospf, lsa->lsdb, lsa);
- ospf_lsdb_delete(lsa->lsdb, lsa);
+ if (ei && lsa) {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug("LSA[Type5:0.0.0.0]: Refresh AS-external-LSA %p",
+ (void *)lsa);
+ ospf_external_lsa_refresh(ospf, lsa, ei, LSA_REFRESH_FORCE);
+ } else if (ei && !lsa) {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug(
+ "LSA[Type5:0.0.0.0]: Originate AS-external-LSA");
+ ospf_external_lsa_originate(ospf, ei);
+ } else if (lsa) {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug("LSA[Type5:0.0.0.0]: Flush AS-external-LSA");
+ ospf_external_lsa_flush(ospf, DEFAULT_ROUTE, &p, 0);
}
}
diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h
index 5e3dabc27a..4033659bff 100644
--- a/ospfd/ospf_lsa.h
+++ b/ospfd/ospf_lsa.h
@@ -275,8 +275,7 @@ extern struct in_addr ospf_get_ip_from_ifp(struct ospf_interface *);
extern struct ospf_lsa *ospf_external_lsa_originate(struct ospf *,
struct external_info *);
-extern int ospf_external_lsa_originate_timer(struct thread *);
-extern int ospf_default_originate_timer(struct thread *);
+extern void ospf_external_lsa_rid_change(struct ospf *ospf);
extern struct ospf_lsa *ospf_lsa_lookup(struct ospf *ospf, struct ospf_area *,
uint32_t, struct in_addr,
struct in_addr);
@@ -301,7 +300,6 @@ extern int ospf_lsa_maxage_walker(struct thread *);
extern struct ospf_lsa *ospf_lsa_refresh(struct ospf *, struct ospf_lsa *);
extern void ospf_external_lsa_refresh_default(struct ospf *);
-extern void ospf_default_originate_lsa_update(struct ospf *ospf);
extern void ospf_external_lsa_refresh_type(struct ospf *, uint8_t,
unsigned short, int);
diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c
index f7c73fee33..ee27ec0942 100644
--- a/ospfd/ospf_nsm.c
+++ b/ospfd/ospf_nsm.c
@@ -616,8 +616,6 @@ static void nsm_change_state(struct ospf_neighbor *nbr, int state)
struct ospf_interface *oi = nbr->oi;
struct ospf_area *vl_area = NULL;
uint8_t old_state;
- int x;
- int force = 1;
/* Preserve old status. */
old_state = nbr->state;
@@ -664,32 +662,6 @@ static void nsm_change_state(struct ospf_neighbor *nbr, int state)
if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area)
if (++vl_area->full_vls == 1)
ospf_schedule_abr_task(oi->ospf);
-
- /* kevinm: refresh any redistributions */
- for (x = ZEBRA_ROUTE_SYSTEM; x < ZEBRA_ROUTE_MAX; x++) {
- struct list *red_list;
- struct listnode *node;
- struct ospf_redist *red;
-
- if (x == ZEBRA_ROUTE_OSPF6)
- continue;
-
- red_list = oi->ospf->redist[x];
- if (!red_list)
- continue;
-
- for (ALL_LIST_ELEMENTS_RO(red_list, node, red))
- ospf_external_lsa_refresh_type(
- oi->ospf, x, red->instance,
- force);
- }
- /* XXX: Clearly some thing is wrong with refresh of
- * external LSAs
- * this added to hack around defaults not refreshing
- * after a timer
- * jump.
- */
- ospf_external_lsa_refresh_default(oi->ospf);
} else {
oi->full_nbrs--;
oi->area->full_nbrs--;
diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c
index 50c30a6fa0..62b0444796 100644
--- a/ospfd/ospf_packet.c
+++ b/ospfd/ospf_packet.c
@@ -33,7 +33,9 @@
#include "log.h"
#include "sockopt.h"
#include "checksum.h"
+#ifdef CRYPTO_INTERNAL
#include "md5.h"
+#endif
#include "vrf.h"
#include "lib_errors.h"
@@ -332,7 +334,11 @@ static unsigned int ospf_packet_max(struct ospf_interface *oi)
static int ospf_check_md5_digest(struct ospf_interface *oi,
struct ospf_header *ospfh)
{
+#ifdef CRYPTO_OPENSSL
+ EVP_MD_CTX *ctx;
+#elif CRYPTO_INTERNAL
MD5_CTX ctx;
+#endif
unsigned char digest[OSPF_AUTH_MD5_SIZE];
struct crypt_key *ck;
struct ospf_neighbor *nbr;
@@ -361,11 +367,21 @@ static int ospf_check_md5_digest(struct ospf_interface *oi,
}
/* Generate a digest for the ospf packet - their digest + our digest. */
+#ifdef CRYPTO_OPENSSL
+ unsigned int md5_size = OSPF_AUTH_MD5_SIZE;
+ ctx = EVP_MD_CTX_new();
+ EVP_DigestInit(ctx, EVP_md5());
+ EVP_DigestUpdate(ctx, ospfh, length);
+ EVP_DigestUpdate(ctx, ck->auth_key, OSPF_AUTH_MD5_SIZE);
+ EVP_DigestFinal(ctx, digest, &md5_size);
+ EVP_MD_CTX_free(ctx);
+#elif CRYPTO_INTERNAL
memset(&ctx, 0, sizeof(ctx));
MD5Init(&ctx);
MD5Update(&ctx, ospfh, length);
MD5Update(&ctx, ck->auth_key, OSPF_AUTH_MD5_SIZE);
MD5Final(digest, &ctx);
+#endif
/* compare the two */
if (memcmp((caddr_t)ospfh + length, digest, OSPF_AUTH_MD5_SIZE)) {
@@ -389,7 +405,11 @@ static int ospf_make_md5_digest(struct ospf_interface *oi,
{
struct ospf_header *ospfh;
unsigned char digest[OSPF_AUTH_MD5_SIZE] = {0};
+#ifdef CRYPTO_OPENSSL
+ EVP_MD_CTX *ctx;
+#elif CRYPTO_INTERNAL
MD5_CTX ctx;
+#endif
void *ibuf;
uint32_t t;
struct crypt_key *ck;
@@ -422,11 +442,21 @@ static int ospf_make_md5_digest(struct ospf_interface *oi,
}
/* Generate a digest for the entire packet + our secret key. */
+#ifdef CRYPTO_OPENSSL
+ unsigned int md5_size = OSPF_AUTH_MD5_SIZE;
+ ctx = EVP_MD_CTX_new();
+ EVP_DigestInit(ctx, EVP_md5());
+ EVP_DigestUpdate(ctx, ibuf, ntohs(ospfh->length));
+ EVP_DigestUpdate(ctx, auth_key, OSPF_AUTH_MD5_SIZE);
+ EVP_DigestFinal(ctx, digest, &md5_size);
+ EVP_MD_CTX_free(ctx);
+#elif CRYPTO_INTERNAL
memset(&ctx, 0, sizeof(ctx));
MD5Init(&ctx);
MD5Update(&ctx, ibuf, ntohs(ospfh->length));
MD5Update(&ctx, auth_key, OSPF_AUTH_MD5_SIZE);
MD5Final(digest, &ctx);
+#endif
/* Append md5 digest to the end of the stream. */
stream_put(op->s, digest, OSPF_AUTH_MD5_SIZE);
diff --git a/ospfd/ospf_routemap.c b/ospfd/ospf_routemap.c
index bb7e97bf7b..1669c817e6 100644
--- a/ospfd/ospf_routemap.c
+++ b/ospfd/ospf_routemap.c
@@ -126,10 +126,9 @@ static void ospf_route_map_event(const char *name)
/* `match ip netxthop ' */
/* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_ip_nexthop(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_ip_nexthop(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct access_list *alist;
struct external_info *ei = object;
@@ -171,7 +170,7 @@ struct route_map_rule_cmd route_match_ip_nexthop_cmd = {
/* `match ip next-hop prefix-list PREFIX_LIST' */
-static route_map_result_t
+static enum route_map_cmd_result_t
route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -212,7 +211,7 @@ struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = {
/* `match ip next-hop type <blackhole>' */
-static route_map_result_t
+static enum route_map_cmd_result_t
route_match_ip_next_hop_type(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -221,7 +220,7 @@ route_match_ip_next_hop_type(void *rule, const struct prefix *prefix,
if (type == RMAP_OSPF && prefix->family == AF_INET) {
ei = (struct external_info *)object;
if (!ei)
- return RMAP_DENYMATCH;
+ return RMAP_NOMATCH;
if (ei->nexthop.s_addr == INADDR_ANY && !ei->ifindex)
return RMAP_MATCH;
@@ -247,10 +246,9 @@ static struct route_map_rule_cmd route_match_ip_next_hop_type_cmd = {
/* `match ip address IP_ACCESS_LIST' */
/* Match function should return 1 if match is success else return
zero. */
-static route_map_result_t route_match_ip_address(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_ip_address(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct access_list *alist;
/* struct prefix_ipv4 match; */
@@ -286,7 +284,7 @@ struct route_map_rule_cmd route_match_ip_address_cmd = {
route_match_ip_address_free};
/* `match ip address prefix-list PREFIX_LIST' */
-static route_map_result_t
+static enum route_map_cmd_result_t
route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -322,10 +320,9 @@ struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = {
/* `match interface IFNAME' */
/* Match function should return 1 if match is success else return
zero. */
-static route_map_result_t route_match_interface(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_interface(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct interface *ifp;
struct external_info *ei;
@@ -361,9 +358,9 @@ struct route_map_rule_cmd route_match_interface_cmd = {
route_match_interface_free};
/* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_tag(void *rule,
- const struct prefix *prefix,
- route_map_object_t type, void *object)
+static enum route_map_cmd_result_t
+route_match_tag(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
route_tag_t *tag;
struct external_info *ei;
@@ -392,10 +389,9 @@ struct ospf_metric {
/* `set metric METRIC' */
/* Set metric to attribute. */
-static route_map_result_t route_set_metric(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_set_metric(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct ospf_metric *metric;
struct external_info *ei;
@@ -473,10 +469,9 @@ struct route_map_rule_cmd route_set_metric_cmd = {
/* `set metric-type TYPE' */
/* Set metric-type to attribute. */
-static route_map_result_t route_set_metric_type(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_set_metric_type(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
uint32_t *metric_type;
struct external_info *ei;
@@ -523,8 +518,9 @@ struct route_map_rule_cmd route_set_metric_type_cmd = {
route_set_metric_type_free,
};
-static route_map_result_t route_set_tag(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static enum route_map_cmd_result_t
+route_set_tag(void *rule, const struct prefix *prefix, route_map_object_t type,
+ void *object)
{
route_tag_t *tag;
struct external_info *ei;
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index 98ddd6a79e..2564c6f330 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -8487,22 +8487,8 @@ DEFUN (no_ospf_default_information_originate,
"Pointer to route-map entries\n")
{
VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
- struct prefix_ipv4 p;
- struct ospf_external *ext;
struct ospf_redist *red;
- p.family = AF_INET;
- p.prefix.s_addr = 0;
- p.prefixlen = 0;
-
- ospf_external_lsa_flush(ospf, DEFAULT_ROUTE, &p, 0);
-
- ext = ospf_external_lookup(ospf, DEFAULT_ROUTE, 0);
- if (ext && EXTERNAL_INFO(ext)) {
- ospf_external_info_delete(ospf, DEFAULT_ROUTE, 0, p);
- ospf_external_del(ospf, DEFAULT_ROUTE, 0);
- }
-
red = ospf_redist_lookup(ospf, DEFAULT_ROUTE, 0);
if (!red)
return CMD_SUCCESS;
@@ -8510,7 +8496,8 @@ DEFUN (no_ospf_default_information_originate,
ospf_routemap_unset(red);
ospf_redist_del(ospf, DEFAULT_ROUTE, 0);
- return ospf_redistribute_default_unset(ospf);
+ return ospf_redistribute_default_set(ospf, DEFAULT_ORIGINATE_NONE,
+ 0, 0);
}
DEFUN (ospf_default_metric,
diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c
index c178e367d3..b478832d84 100644
--- a/ospfd/ospf_zebra.c
+++ b/ospfd/ospf_zebra.c
@@ -744,10 +744,10 @@ int ospf_redistribute_unset(struct ospf *ospf, int type,
int ospf_redistribute_default_set(struct ospf *ospf, int originate, int mtype,
int mvalue)
{
- struct ospf_external *ext;
struct prefix_ipv4 p;
struct in_addr nexthop;
int cur_originate = ospf->default_originate;
+ const char *type_str = NULL;
nexthop.s_addr = 0;
p.family = AF_INET;
@@ -756,41 +756,7 @@ int ospf_redistribute_default_set(struct ospf *ospf, int originate, int mtype,
ospf->default_originate = originate;
- ospf_external_add(ospf, DEFAULT_ROUTE, 0);
-
- if (cur_originate == DEFAULT_ORIGINATE_NONE) {
- /* First time configuration */
- if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE))
- zlog_debug("Redistribute[DEFAULT]: Start Type[%d], Metric[%d]",
- metric_type(ospf, DEFAULT_ROUTE, 0),
- metric_value(ospf, DEFAULT_ROUTE, 0));
-
- if (ospf->router_id.s_addr == 0)
- ospf->external_origin |= (1 << DEFAULT_ROUTE);
- if ((originate == DEFAULT_ORIGINATE_ALWAYS)
- && (ospf->router_id.s_addr)) {
-
- /* always , so originate lsa even it doesn't
- * exist in RIB.
- */
- ospf_external_info_add(ospf, DEFAULT_ROUTE, 0,
- p, 0, nexthop, 0);
- ospf_external_lsa_refresh_default(ospf);
-
- } else if (originate == DEFAULT_ORIGINATE_ZEBRA) {
- /* Send msg to Zebra to validate default route
- * existance.
- */
- zclient_redistribute_default(
- ZEBRA_REDISTRIBUTE_DEFAULT_ADD, zclient, AFI_IP,
- ospf->vrf_id);
- }
-
- ospf_asbr_status_update(ospf, ++ospf->redistribute);
- return CMD_SUCCESS;
-
-
- } else if (originate == cur_originate) {
+ if (cur_originate == originate) {
/* Refresh the lsa since metric might different */
if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE))
zlog_debug(
@@ -800,67 +766,51 @@ int ospf_redistribute_default_set(struct ospf *ospf, int originate, int mtype,
metric_value(ospf, DEFAULT_ROUTE, 0));
ospf_external_lsa_refresh_default(ospf);
-
- } else {
- /* "default-info originate always" configured now,
- * where "default-info originate" configured previoulsly.
- */
- if (originate == DEFAULT_ORIGINATE_ALWAYS) {
-
- zclient_redistribute_default(
- ZEBRA_REDISTRIBUTE_DEFAULT_DELETE,
- zclient, AFI_IP, ospf->vrf_id);
- /* here , ex-info should be added since ex-info might
- * have not updated earlier if def route is not exist.
- * If ex-iinfo ex-info already exist , it will return
- * smoothly.
- */
- ospf_external_info_add(ospf, DEFAULT_ROUTE, 0,
- p, 0, nexthop, 0);
- ospf_external_lsa_refresh_default(ospf);
-
- } else {
- /* "default-info originate" configured now,where
- * "default-info originate always" configured
- * previoulsy.
- */
-
- ospf_external_lsa_flush(ospf, DEFAULT_ROUTE, &p, 0);
-
- ext = ospf_external_lookup(ospf, DEFAULT_ROUTE, 0);
- if (ext && EXTERNAL_INFO(ext))
- ospf_external_info_delete(ospf,
- DEFAULT_ROUTE, 0, p);
-
- zclient_redistribute_default(
- ZEBRA_REDISTRIBUTE_DEFAULT_ADD,
- zclient, AFI_IP, ospf->vrf_id);
- }
+ return CMD_SUCCESS;
}
- return CMD_SUCCESS;
-}
-int ospf_redistribute_default_unset(struct ospf *ospf)
-{
- if (ospf->default_originate == DEFAULT_ORIGINATE_ZEBRA) {
- if (!ospf_is_type_redistributed(ospf, DEFAULT_ROUTE, 0))
- return CMD_SUCCESS;
+ switch (cur_originate) {
+ case DEFAULT_ORIGINATE_NONE:
+ break;
+ case DEFAULT_ORIGINATE_ZEBRA:
zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_DELETE,
zclient, AFI_IP, ospf->vrf_id);
+ ospf->redistribute--;
+ break;
+ case DEFAULT_ORIGINATE_ALWAYS:
+ ospf_external_info_delete(ospf, DEFAULT_ROUTE, 0, p);
+ ospf_external_del(ospf, DEFAULT_ROUTE, 0);
+ ospf->redistribute--;
+ break;
}
- ospf->default_originate = DEFAULT_ORIGINATE_NONE;
+ switch (originate) {
+ case DEFAULT_ORIGINATE_NONE:
+ type_str = "none";
+ break;
+ case DEFAULT_ORIGINATE_ZEBRA:
+ type_str = "normal";
+ ospf->redistribute++;
+ zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD,
+ zclient, AFI_IP, ospf->vrf_id);
+ break;
+ case DEFAULT_ORIGINATE_ALWAYS:
+ type_str = "always";
+ ospf->redistribute++;
+ ospf_external_add(ospf, DEFAULT_ROUTE, 0);
+ ospf_external_info_add(ospf, DEFAULT_ROUTE, 0, p, 0, nexthop,
+ 0);
+ break;
+ }
if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE))
- zlog_debug("Redistribute[DEFAULT]: Stop");
-
- // Pending: how does the external_info cleanup work in this case?
-
- ospf_asbr_status_update(ospf, --ospf->redistribute);
-
- /* clean up maxage default originate external lsa */
- ospf_default_originate_lsa_update(ospf);
+ zlog_debug("Redistribute[DEFAULT]: %s Type[%d], Metric[%d]",
+ type_str,
+ metric_type(ospf, DEFAULT_ROUTE, 0),
+ metric_value(ospf, DEFAULT_ROUTE, 0));
+ ospf_external_lsa_refresh_default(ospf);
+ ospf_asbr_status_update(ospf, ospf->redistribute);
return CMD_SUCCESS;
}
@@ -943,7 +893,7 @@ int ospf_redistribute_check(struct ospf *ospf, struct external_info *ei,
/* apply route-map if needed */
red = ospf_redist_lookup(ospf, type, instance);
if (red && ROUTEMAP_NAME(red)) {
- int ret;
+ route_map_result_t ret;
ret = route_map_apply(ROUTEMAP(red), (struct prefix *)p,
RMAP_OSPF, ei);
@@ -1033,7 +983,8 @@ static int ospf_zebra_read_route(ZAPI_CALLBACK_ARGS)
char buf_prefix[PREFIX_STRLEN];
prefix2str(&api.prefix, buf_prefix, sizeof(buf_prefix));
- zlog_debug("%s: from client %s: vrf_id %d, p %s", __func__,
+ zlog_debug("%s: cmd %s from client %s: vrf_id %d, p %s",
+ __func__, zserv_command_string(cmd),
zebra_route_string(api.type), vrf_id, buf_prefix);
}
@@ -1067,11 +1018,7 @@ static int ospf_zebra_read_route(ZAPI_CALLBACK_ARGS)
/* Nothing has changed, so nothing to do; return */
return 0;
}
- if (ospf->router_id.s_addr == 0)
- /* Set flags to generate AS-external-LSA originate event
- for each redistributed protocols later. */
- ospf->external_origin |= (1 << rt_type);
- else {
+ if (ospf->router_id.s_addr != 0) {
if (ei) {
if (is_prefix_default(&p))
ospf_external_lsa_refresh_default(ospf);
diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c
index a64ddbc3b7..b91a55f635 100644
--- a/ospfd/ospfd.c
+++ b/ospfd/ospfd.c
@@ -91,7 +91,6 @@ void ospf_router_id_update(struct ospf *ospf)
struct ospf_interface *oi;
struct interface *ifp;
struct listnode *node;
- int type;
if (!ospf->oi_running) {
if (IS_DEBUG_OSPF_EVENT)
@@ -135,24 +134,6 @@ void ospf_router_id_update(struct ospf *ospf)
ospf_nbr_self_reset(oi, router_id);
}
- /* If AS-external-LSA is queued, then flush those LSAs. */
- if (router_id_old.s_addr == 0 && ospf->external_origin) {
- /* Originate each redistributed external route. */
- for (type = 0; type < ZEBRA_ROUTE_MAX; type++)
- if (ospf->external_origin & (1 << type))
- thread_add_event(
- master,
- ospf_external_lsa_originate_timer,
- ospf, type, NULL);
- /* Originate Deafult. */
- if (ospf->external_origin & (1 << ZEBRA_ROUTE_MAX))
- thread_add_event(master,
- ospf_default_originate_timer,
- ospf, 0, NULL);
-
- ospf->external_origin = 0;
- }
-
/* Flush (inline) all external LSAs based on the OSPF_LSA_SELF
* flag */
if (ospf->lsdb) {
@@ -196,20 +177,14 @@ void ospf_router_id_update(struct ospf *ospf)
}
}
- /* Originate each redistributed external route. */
- for (type = 0; type < ZEBRA_ROUTE_MAX; type++)
- thread_add_event(master,
- ospf_external_lsa_originate_timer,
- ospf, type, NULL);
- thread_add_event(master, ospf_default_originate_timer, ospf, 0,
- NULL);
-
/* update router-lsa's for each area */
ospf_router_lsa_update(ospf);
/* update ospf_interface's */
FOR_ALL_INTERFACES (vrf, ifp)
ospf_if_update(ospf, ifp);
+
+ ospf_external_lsa_rid_change(ospf);
}
}
@@ -633,7 +608,7 @@ static void ospf_finish_final(struct ospf *ospf)
ospf_redist_del(ospf, i, red->instance);
}
}
- ospf_redistribute_default_unset(ospf);
+ ospf_redistribute_default_set(ospf, DEFAULT_ORIGINATE_NONE, 0, 0);
for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area))
ospf_remove_vls_through_area(ospf, area);
@@ -702,7 +677,6 @@ static void ospf_finish_final(struct ospf *ospf)
/* Cancel all timers. */
OSPF_TIMER_OFF(ospf->t_read);
OSPF_TIMER_OFF(ospf->t_write);
- OSPF_TIMER_OFF(ospf->t_external_lsa);
OSPF_TIMER_OFF(ospf->t_spf_calc);
OSPF_TIMER_OFF(ospf->t_ase_calc);
OSPF_TIMER_OFF(ospf->t_maxage);
diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h
index cbea033b73..b31ad30375 100644
--- a/ospfd/ospfd.h
+++ b/ospfd/ospfd.h
@@ -202,7 +202,6 @@ struct ospf {
struct ospf_lsdb *lsdb;
/* Flags. */
- int external_origin; /* AS-external-LSA origin flag. */
int ase_calc; /* ASE calculation flag. */
struct list *opaque_lsa_self; /* Type-11 Opaque-LSAs */
@@ -233,7 +232,6 @@ struct ospf {
struct thread *t_distribute_update; /* Distirbute list update timer. */
struct thread *t_spf_calc; /* SPF calculation timer. */
struct thread *t_ase_calc; /* ASE calculation timer. */
- struct thread *t_external_lsa; /* AS-external-LSA origin timer. */
struct thread
*t_opaque_lsa_self; /* Type-11 Opaque-LSAs origin event. */
struct thread *t_sr_update; /* Segment Routing update timer */
diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c
index a69bb00848..57e8cf5742 100644
--- a/pbrd/pbr_nht.c
+++ b/pbrd/pbr_nht.c
@@ -227,7 +227,6 @@ void pbr_nhgroup_add_cb(const char *name)
DEBUGD(&pbr_dbg_nht, "%s: Added nexthop-group %s", __PRETTY_FUNCTION__,
name);
- pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg);
pbr_map_check_nh_group_change(name);
}
diff --git a/pbrd/pbrd.conf.sample b/pbrd/pbrd.conf.sample
index bb1c2edca8..c9e7dce01f 100644
--- a/pbrd/pbrd.conf.sample
+++ b/pbrd/pbrd.conf.sample
@@ -1,3 +1,19 @@
+! Sample pbrd configuration file
+!
+! A quick example of what a pbr configuration might look like
!
!
log stdout
+!
+! nexthop-group TEST
+! nexthop 4.5.6.7
+! nexthop 5.6.7.8
+! !
+! pbr-map BLUE seq 100
+! match dst-ip 9.9.9.0/24
+! match src-ip 10.10.10.0/24
+! set nexthop-group TEST
+! !
+! int swp1
+! pbr-policy BLUE
+!
diff --git a/pimd/pim_bsm.c b/pimd/pim_bsm.c
index 62f13b5b53..675092dbec 100644
--- a/pimd/pim_bsm.c
+++ b/pimd/pim_bsm.c
@@ -711,11 +711,11 @@ static bool pim_bsm_frag_send(uint8_t *buf, uint32_t len, struct interface *ifp,
/* MTU passed here is PIM MTU (IP MTU less IP Hdr) */
if (pim_mtu < (PIM_MIN_BSM_LEN)) {
zlog_warn(
- "%s: mtu(pim mtu: %d) size less than minimum bootsrap len",
+ "%s: mtu(pim mtu: %d) size less than minimum bootstrap len",
__PRETTY_FUNCTION__, pim_mtu);
if (PIM_DEBUG_BSM)
zlog_debug(
- "%s: mtu (pim mtu:%d) less than minimum bootsrap len",
+ "%s: mtu (pim mtu:%d) less than minimum bootstrap len",
__PRETTY_FUNCTION__, pim_mtu);
return false;
}
diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c
index b1c55c1f43..1c66007fbb 100644
--- a/pimd/pim_mroute.c
+++ b/pimd/pim_mroute.c
@@ -190,8 +190,6 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp,
sg.grp = msg->im_dst;
if (!(PIM_I_am_DR(pim_ifp))) {
- struct channel_oil *c_oil;
-
if (PIM_DEBUG_MROUTE_DETAIL)
zlog_debug("%s: Interface is not the DR blackholing incoming traffic for %s",
__PRETTY_FUNCTION__, pim_str_sg_dump(&sg));
@@ -206,10 +204,10 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp,
* that I see no way to get rid of. Just noting
* this for future reference.
*/
- c_oil = pim_channel_oil_add(pim_ifp->pim, &sg,
- pim_ifp->mroute_vif_index,
- __PRETTY_FUNCTION__);
- pim_mroute_add(c_oil, __PRETTY_FUNCTION__);
+ up = pim_upstream_find_or_add(
+ &sg, ifp, PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE,
+ __PRETTY_FUNCTION__);
+ pim_mroute_add(up->channel_oil, __PRETTY_FUNCTION__);
return 0;
}
@@ -238,7 +236,8 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp,
vif_index = pim_if_find_vifindex_by_ifindex(
pim_ifp->pim,
up->rpf.source_nexthop.interface->ifindex);
- up->channel_oil->oil.mfcc_parent = vif_index;
+ pim_channel_oil_change_iif(pim_ifp->pim, up->channel_oil,
+ vif_index, __PRETTY_FUNCTION__);
}
pim_register_join(up);
@@ -453,7 +452,6 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp,
struct pim_upstream *up;
struct prefix_sg star_g;
struct prefix_sg sg;
- struct channel_oil *oil;
pim_ifp = ifp->info;
@@ -517,11 +515,7 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp,
up->upstream_register);
up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
}
- if (!up->channel_oil)
- up->channel_oil = pim_channel_oil_add(
- pim_ifp->pim, &sg,
- pim_ifp->mroute_vif_index,
- __PRETTY_FUNCTION__);
+
pim_upstream_inherited_olist(pim_ifp->pim, up);
if (!up->channel_oil->installed)
pim_mroute_add(up->channel_oil,
@@ -546,10 +540,6 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp,
}
pim_ifp = ifp->info;
- oil = pim_channel_oil_add(pim_ifp->pim, &sg, pim_ifp->mroute_vif_index,
- __PRETTY_FUNCTION__);
- if (!oil->installed)
- pim_mroute_add(oil, __PRETTY_FUNCTION__);
if (pim_if_connected_to_source(ifp, sg.src)) {
up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
PIM_UPSTREAM_FLAG_MASK_FHR,
@@ -564,13 +554,18 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp,
PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
pim_upstream_keep_alive_timer_start(
up, pim_ifp->pim->keep_alive_time);
- up->channel_oil = oil;
up->channel_oil->cc.pktcnt++;
pim_register_join(up);
pim_upstream_inherited_olist(pim_ifp->pim, up);
// Send the packet to the RP
pim_mroute_msg_wholepkt(fd, ifp, buf);
+ } else {
+ up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
+ PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE,
+ __PRETTY_FUNCTION__, NULL);
+ if (!up->channel_oil->installed)
+ pim_mroute_add(up->channel_oil, __PRETTY_FUNCTION__);
}
return 0;
diff --git a/pimd/pim_msg.h b/pimd/pim_msg.h
index b6e2cada1f..2d69a4b03a 100644
--- a/pimd/pim_msg.h
+++ b/pimd/pim_msg.h
@@ -42,7 +42,7 @@ enum pim_msg_address_family {
};
/*
- * Network Order pim_msg_hdr
+ * pim_msg_hdr
* =========================
* PIM Header definition as per RFC 5059. N bit introduced to indicate
* do-not-forward option in PIM Boot strap Message.
@@ -53,10 +53,19 @@ enum pim_msg_address_family {
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
struct pim_msg_header {
+#if (BYTE_ORDER == LITTLE_ENDIAN)
uint8_t type : 4;
uint8_t ver : 4;
+ uint8_t reserved : 7;
+ uint8_t Nbit : 1; /* No Fwd Bit */
+#elif (BYTE_ORDER == BIG_ENDIAN)
+ uint8_t ver : 4;
+ uint8_t type : 4;
uint8_t Nbit : 1; /* No Fwd Bit */
uint8_t reserved : 7;
+#else
+#error"Please set byte order"
+#endif
uint16_t checksum;
} __attribute__((packed));
@@ -79,9 +88,17 @@ struct pim_encoded_ipv4_unicast {
struct pim_encoded_group_ipv4 {
uint8_t family;
uint8_t ne;
+#if (BYTE_ORDER == LITTLE_ENDIAN)
+ uint8_t sz : 1; /* scope zone bit */
+ uint8_t reserved : 6; /* Reserved */
+ uint8_t bidir : 1; /* Bidir bit */
+#elif (BYTE_ORDER == BIG_ENDIAN)
uint8_t bidir : 1; /* Bidir bit */
uint8_t reserved : 6; /* Reserved */
uint8_t sz : 1; /* scope zone bit */
+#else
+#error"Please set byte order"
+#endif
uint8_t mask;
struct in_addr addr;
} __attribute__((packed));
diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c
index a63b09fc1f..722ecb2a72 100644
--- a/pimd/pim_neighbor.c
+++ b/pimd/pim_neighbor.c
@@ -424,10 +424,11 @@ struct pim_neighbor *pim_neighbor_find_by_secondary(struct interface *ifp,
struct pim_neighbor *neigh;
struct prefix *p;
- pim_ifp = ifp->info;
- if (!pim_ifp)
+ if (!ifp || !ifp->info)
return NULL;
+ pim_ifp = ifp->info;
+
for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) {
for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, pnode, p)) {
if (prefix_same(p, src))
diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c
index 65ea858cb6..7900e39231 100644
--- a/pimd/pim_nht.c
+++ b/pimd/pim_nht.c
@@ -479,7 +479,7 @@ static int pim_update_upstream_nh_helper(struct hash_bucket *bucket, void *arg)
zlog_debug("%s: NHT upstream %s(%s) old ifp %s new ifp %s",
__PRETTY_FUNCTION__, up->sg_str, pim->vrf->name,
old.source_nexthop.interface
- ? old.source_nexthop.interface->name : "Unknwon",
+ ? old.source_nexthop.interface->name : "Unknown",
up->rpf.source_nexthop.interface->name);
}
@@ -842,6 +842,14 @@ int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS)
}
if (!ifp->info) {
+ /*
+ * Though Multicast is not enabled on this
+ * Interface store it in database otheriwse we
+ * may miss this update and this will not cause
+ * any issue, because while choosing the path we
+ * are ommitting the Interfaces which are not
+ * multicast enabled
+ */
if (PIM_DEBUG_PIM_NHT) {
char buf[NEXTHOP_STRLEN];
@@ -853,8 +861,6 @@ int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS)
nexthop2str(nexthop, buf,
sizeof(buf)));
}
- nexthop_free(nexthop);
- continue;
}
if (nhlist_tail) {
diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c
index d4fc03e20c..d142934916 100644
--- a/pimd/pim_oil.c
+++ b/pimd/pim_oil.c
@@ -146,6 +146,43 @@ struct channel_oil *pim_find_channel_oil(struct pim_instance *pim,
return c_oil;
}
+void pim_channel_oil_change_iif(struct pim_instance *pim,
+ struct channel_oil *c_oil,
+ int input_vif_index,
+ const char *name)
+{
+ int old_vif_index = c_oil->oil.mfcc_parent;
+ struct prefix_sg sg = {.src = c_oil->oil.mfcc_mcastgrp,
+ .grp = c_oil->oil.mfcc_origin};
+
+ if (c_oil->oil.mfcc_parent == input_vif_index) {
+ if (PIM_DEBUG_MROUTE_DETAIL)
+ zlog_debug("%s(%s): Existing channel oil %pSG4 already using %d as IIF",
+ __PRETTY_FUNCTION__, name, &sg,
+ input_vif_index);
+
+ return;
+ }
+
+ if (PIM_DEBUG_MROUTE_DETAIL)
+ zlog_debug("%s(%s): Changing channel oil %pSG4 IIF from %d to %d installed: %d",
+ __PRETTY_FUNCTION__, name, &sg,
+ c_oil->oil.mfcc_parent, input_vif_index,
+ c_oil->installed);
+
+ c_oil->oil.mfcc_parent = input_vif_index;
+ if (c_oil->installed) {
+ if (input_vif_index == MAXVIFS)
+ pim_mroute_del(c_oil, name);
+ else
+ pim_mroute_add(c_oil, name);
+ } else
+ if (old_vif_index == MAXVIFS)
+ pim_mroute_add(c_oil, name);
+
+ return;
+}
+
struct channel_oil *pim_channel_oil_add(struct pim_instance *pim,
struct prefix_sg *sg,
int input_vif_index, const char *name)
@@ -164,7 +201,8 @@ struct channel_oil *pim_channel_oil_add(struct pim_instance *pim,
c_oil->oil.mfcc_parent,
input_vif_index);
}
- c_oil->oil.mfcc_parent = input_vif_index;
+ pim_channel_oil_change_iif(pim, c_oil, input_vif_index,
+ name);
++c_oil->oil_ref_count;
/* channel might be present prior to upstream */
c_oil->up = pim_upstream_find(pim, sg);
diff --git a/pimd/pim_oil.h b/pimd/pim_oil.h
index 485299196d..319a1c91a3 100644
--- a/pimd/pim_oil.h
+++ b/pimd/pim_oil.h
@@ -114,6 +114,9 @@ struct channel_oil *pim_find_channel_oil(struct pim_instance *pim,
struct channel_oil *pim_channel_oil_add(struct pim_instance *pim,
struct prefix_sg *sg,
int input_vif_index, const char *name);
+void pim_channel_oil_change_iif(struct pim_instance *pim,
+ struct channel_oil *c_oil, int input_vif_index,
+ const char *name);
void pim_channel_oil_del(struct channel_oil *c_oil, const char *name);
int pim_channel_add_oif(struct channel_oil *c_oil, struct interface *oif,
diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c
index 7d263e99e3..357ad6ba46 100644
--- a/pimd/pim_rpf.c
+++ b/pimd/pim_rpf.c
@@ -307,11 +307,11 @@ void pim_upstream_rpf_clear(struct pim_instance *pim,
struct pim_upstream *up)
{
if (up->rpf.source_nexthop.interface) {
- if (up->channel_oil) {
- up->channel_oil->oil.mfcc_parent = MAXVIFS;
- pim_mroute_del(up->channel_oil, __PRETTY_FUNCTION__);
+ if (up->channel_oil)
+ pim_channel_oil_change_iif(pim, up->channel_oil,
+ MAXVIFS,
+ __PRETTY_FUNCTION__);
- }
pim_upstream_switch(pim, up, PIM_UPSTREAM_NOTJOINED);
up->rpf.source_nexthop.interface = NULL;
up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr =
diff --git a/pimd/pim_static.c b/pimd/pim_static.c
index 62c3216e86..e3138360c8 100644
--- a/pimd/pim_static.c
+++ b/pimd/pim_static.c
@@ -138,7 +138,9 @@ int pim_static_add(struct pim_instance *pim, struct interface *iif,
} else {
/* input interface changed */
s_route->iif = iif_index;
- s_route->c_oil.oil.mfcc_parent = iif_index;
+ pim_channel_oil_change_iif(pim, &s_route->c_oil,
+ iif_index,
+ __PRETTY_FUNCTION__);
#ifdef PIM_ENFORCE_LOOPFREE_MFC
/* check to make sure the new input was not an
diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c
index 50df2fdbf9..c0651561ac 100644
--- a/pimd/pim_upstream.c
+++ b/pimd/pim_upstream.c
@@ -716,7 +716,8 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim,
up->join_state = PIM_UPSTREAM_NOTJOINED;
up->reg_state = PIM_REG_NOINFO;
up->state_transition = pim_time_monotonic_sec();
- up->channel_oil = NULL;
+ up->channel_oil =
+ pim_channel_oil_add(pim, &up->sg, MAXVIFS, __PRETTY_FUNCTION__);
up->sptbit = PIM_UPSTREAM_SPTBIT_FALSE;
up->rpf.source_nexthop.interface = NULL;
@@ -736,52 +737,34 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim,
if (up->sg.src.s_addr != INADDR_ANY)
wheel_add_item(pim->upstream_sg_wheel, up);
- if (PIM_UPSTREAM_FLAG_TEST_STATIC_IIF(up->flags)) {
+ if (PIM_UPSTREAM_FLAG_TEST_STATIC_IIF(up->flags)
+ || PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up->flags)) {
pim_upstream_fill_static_iif(up, incoming);
pim_ifp = up->rpf.source_nexthop.interface->info;
assert(pim_ifp);
- up->channel_oil = pim_channel_oil_add(pim, &up->sg,
- pim_ifp->mroute_vif_index,
- __PRETTY_FUNCTION__);
- } else if (up->upstream_addr.s_addr == INADDR_ANY) {
- /* Create a dummmy channel oil with incoming ineterface MAXVIFS,
- * since RP is not configured
- */
- up->channel_oil = pim_channel_oil_add(pim, &up->sg, MAXVIFS,
- __PRETTY_FUNCTION__);
-
- } else {
+ pim_channel_oil_change_iif(pim, up->channel_oil,
+ pim_ifp->mroute_vif_index,
+ __PRETTY_FUNCTION__);
+
+ if (PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up->flags))
+ pim_upstream_keep_alive_timer_start(
+ up, pim->keep_alive_time);
+ } else if (up->upstream_addr.s_addr != INADDR_ANY) {
rpf_result = pim_rpf_update(pim, up, NULL);
if (rpf_result == PIM_RPF_FAILURE) {
if (PIM_DEBUG_TRACE)
zlog_debug(
"%s: Attempting to create upstream(%s), Unable to RPF for source",
__PRETTY_FUNCTION__, up->sg_str);
- /* Create a dummmy channel oil with incoming ineterface
- * MAXVIFS, since RP is not reachable
- */
- up->channel_oil = pim_channel_oil_add(
- pim, &up->sg, MAXVIFS, __PRETTY_FUNCTION__);
}
if (up->rpf.source_nexthop.interface) {
pim_ifp = up->rpf.source_nexthop.interface->info;
if (pim_ifp)
- up->channel_oil = pim_channel_oil_add(
- pim, &up->sg, pim_ifp->mroute_vif_index,
- __PRETTY_FUNCTION__);
- else {
- /*
- * Yeah this should not happen
- * but let's be sure that we are not
- * doing something stupid, all paths
- * through upstream creation will
- * create a channel oil
- */
- up->channel_oil = pim_channel_oil_add(
- pim, &up->sg, MAXVIFS,
+ pim_channel_oil_change_iif(
+ pim, up->channel_oil,
+ pim_ifp->mroute_vif_index,
__PRETTY_FUNCTION__);
- }
}
}
@@ -1201,6 +1184,13 @@ struct pim_upstream *pim_upstream_keep_alive_timer_proc(
if (!pim_upstream_del(pim, up, __PRETTY_FUNCTION__))
return NULL;
}
+ if (PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up->flags)) {
+ PIM_UPSTREAM_FLAG_UNSET_SRC_NOCACHE(up->flags);
+
+ if (!pim_upstream_del(pim, up, __PRETTY_FUNCTION__))
+ return NULL;
+ }
+
/* upstream reference would have been added to track the local
* membership if it is LHR. We have to clear it when KAT expires.
* Otherwise would result in stale entry with uncleared ref count.
@@ -1526,22 +1516,14 @@ int pim_upstream_inherited_olist_decide(struct pim_instance *pim,
struct pim_upstream *up)
{
struct interface *ifp;
- struct pim_interface *pim_ifp = NULL;
struct pim_ifchannel *ch, *starch;
struct pim_upstream *starup = up->parent;
int output_intf = 0;
- if (up->rpf.source_nexthop.interface)
- pim_ifp = up->rpf.source_nexthop.interface->info;
- else {
+ if (!up->rpf.source_nexthop.interface)
if (PIM_DEBUG_TRACE)
zlog_debug("%s: up %s RPF is not present",
__PRETTY_FUNCTION__, up->sg_str);
- }
- if (pim_ifp && !up->channel_oil)
- up->channel_oil = pim_channel_oil_add(pim, &up->sg,
- pim_ifp->mroute_vif_index,
- __PRETTY_FUNCTION__);
FOR_ALL_INTERFACES (pim->vrf, ifp) {
if (!ifp->info)
diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h
index 02ae998290..c6c9291eed 100644
--- a/pimd/pim_upstream.h
+++ b/pimd/pim_upstream.h
@@ -74,6 +74,13 @@
* blackholing the traffic pulled down to the LHR.
*/
#define PIM_UPSTREAM_FLAG_MASK_MLAG_NON_DF (1 << 17)
+/*
+ * We are creating a non-joined upstream data structure
+ * for this S,G as that we want to have a channel oil
+ * associated with an upstream
+ */
+#define PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE (1 << 19)
+
#define PIM_UPSTREAM_FLAG_ALL 0xFFFFFFFF
#define PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED)
@@ -95,6 +102,7 @@
#define PIM_UPSTREAM_FLAG_TEST_SRC_VXLAN(flags) ((flags) & (PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_ORIG | PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM))
#define PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_MLAG_VXLAN)
#define PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_MLAG_NON_DF)
+#define PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(flags) ((flags) &PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE)
#define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED)
#define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
@@ -133,6 +141,7 @@
#define PIM_UPSTREAM_FLAG_UNSET_SRC_VXLAN_TERM(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM)
#define PIM_UPSTREAM_FLAG_UNSET_MLAG_VXLAN(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_MLAG_VXLAN)
#define PIM_UPSTREAM_FLAG_UNSET_MLAG_NON_DF(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_MLAG_NON_DF)
+#define PIM_UPSTREAM_FLAG_UNSET_SRC_NOCACHE(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE)
enum pim_upstream_state {
PIM_UPSTREAM_NOTJOINED,
diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c
index 675e81f5a1..b0db23f54a 100644
--- a/pimd/pim_zebra.c
+++ b/pimd/pim_zebra.c
@@ -601,7 +601,6 @@ void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index)
{
struct in_addr vif_source;
int input_iface_vif_index;
- int old_vif_index;
pim_rp_set_upstream_addr(c_oil->pim, &vif_source,
c_oil->oil.mfcc_origin,
@@ -701,33 +700,9 @@ void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index)
}
/* update iif vif_index */
- old_vif_index = c_oil->oil.mfcc_parent;
- c_oil->oil.mfcc_parent = input_iface_vif_index;
-
- /* update kernel multicast forwarding cache (MFC) */
- if (pim_mroute_add(c_oil, __PRETTY_FUNCTION__)) {
- if (PIM_DEBUG_MROUTE) {
- /* just log warning */
- struct interface *old_iif = pim_if_find_by_vif_index(
- c_oil->pim, old_vif_index);
- struct interface *new_iif = pim_if_find_by_vif_index(
- c_oil->pim, input_iface_vif_index);
- char source_str[INET_ADDRSTRLEN];
- char group_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin,
- source_str, sizeof(source_str));
- pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp,
- group_str, sizeof(group_str));
- zlog_debug(
- "%s %s: (S,G)=(%s,%s) failure updating input interface from %s vif_index=%d to %s vif_index=%d",
- __FILE__, __PRETTY_FUNCTION__, source_str,
- group_str,
- old_iif ? old_iif->name : "<old_iif?>",
- c_oil->oil.mfcc_parent,
- new_iif ? new_iif->name : "<new_iif?>",
- input_iface_vif_index);
- }
- }
+ pim_channel_oil_change_iif(c_oil->pim, c_oil, input_iface_vif_index,
+ __PRETTY_FUNCTION__);
+ pim_mroute_add(c_oil, __PRETTY_FUNCTION__);
}
void pim_scan_oil(struct pim_instance *pim)
@@ -1256,14 +1231,15 @@ void pim_forward_start(struct pim_ifchannel *ch)
__FILE__, __PRETTY_FUNCTION__,
source_str);
}
- up->channel_oil = pim_channel_oil_add(
- pim, &up->sg, MAXVIFS, __PRETTY_FUNCTION__);
+ pim_channel_oil_change_iif(pim, up->channel_oil,
+ MAXVIFS,
+ __PRETTY_FUNCTION__);
}
else
- up->channel_oil = pim_channel_oil_add(
- pim, &up->sg, input_iface_vif_index,
- __PRETTY_FUNCTION__);
+ pim_channel_oil_change_iif(pim, up->channel_oil,
+ input_iface_vif_index,
+ __PRETTY_FUNCTION__);
if (PIM_DEBUG_TRACE) {
struct interface *in_intf = pim_if_find_by_vif_index(
@@ -1274,10 +1250,6 @@ void pim_forward_start(struct pim_ifchannel *ch)
in_intf ? in_intf->name : "Unknown",
input_iface_vif_index, up->sg_str);
}
-
- up->channel_oil =
- pim_channel_oil_add(pim, &up->sg, input_iface_vif_index,
- __PRETTY_FUNCTION__);
}
if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_IGMP)
diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in
index 27042e197c..014cae02ee 100644
--- a/redhat/frr.spec.in
+++ b/redhat/frr.spec.in
@@ -1,6 +1,6 @@
# configure options
#
-# Some can be overriden on rpmbuild commandline with:
+# Some can be overridden on rpmbuild commandline with:
# rpmbuild --define 'variable value'
# (use any value, ie 1 for flag "with_XXXX" definitions)
#
diff --git a/ripd/rip_routemap.c b/ripd/rip_routemap.c
index 85d83c61dc..459188fefd 100644
--- a/ripd/rip_routemap.c
+++ b/ripd/rip_routemap.c
@@ -42,10 +42,9 @@ struct rip_metric_modifier {
/* `match metric METRIC' */
/* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_metric(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_metric(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
uint32_t *metric;
uint32_t check;
@@ -95,10 +94,9 @@ struct route_map_rule_cmd route_match_metric_cmd = {
/* `match interface IFNAME' */
/* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_interface(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_interface(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct rip_info *rinfo;
struct interface *ifp;
@@ -143,10 +141,9 @@ struct route_map_rule_cmd route_match_interface_cmd = {
/* `match ip next-hop IP_ACCESS_LIST' */
/* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_ip_next_hop(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_ip_next_hop(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct access_list *alist;
struct rip_info *rinfo;
@@ -190,7 +187,7 @@ static struct route_map_rule_cmd route_match_ip_next_hop_cmd = {
/* `match ip next-hop prefix-list PREFIX_LIST' */
-static route_map_result_t
+static enum route_map_cmd_result_t
route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -233,7 +230,7 @@ static struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = {
/* `match ip next-hop type <blackhole>' */
-static route_map_result_t
+static enum route_map_cmd_result_t
route_match_ip_next_hop_type(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -242,7 +239,7 @@ route_match_ip_next_hop_type(void *rule, const struct prefix *prefix,
if (type == RMAP_RIP && prefix->family == AF_INET) {
rinfo = (struct rip_info *)object;
if (!rinfo)
- return RMAP_DENYMATCH;
+ return RMAP_NOMATCH;
if (rinfo->nh.type == NEXTHOP_TYPE_BLACKHOLE)
return RMAP_MATCH;
@@ -269,10 +266,9 @@ static struct route_map_rule_cmd route_match_ip_next_hop_type_cmd = {
/* Match function should return 1 if match is success else return
zero. */
-static route_map_result_t route_match_ip_address(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_ip_address(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct access_list *alist;
@@ -308,7 +304,7 @@ static struct route_map_rule_cmd route_match_ip_address_cmd = {
/* `match ip address prefix-list PREFIX_LIST' */
-static route_map_result_t
+static enum route_map_cmd_result_t
route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -343,8 +339,9 @@ static struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = {
/* `match tag TAG' */
/* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_tag(void *rule, const struct prefix *p,
- route_map_object_t type, void *object)
+static enum route_map_cmd_result_t
+route_match_tag(void *rule, const struct prefix *p, route_map_object_t type,
+ void *object)
{
route_tag_t *tag;
struct rip_info *rinfo;
@@ -373,10 +370,9 @@ static struct route_map_rule_cmd route_match_tag_cmd = {
/* `set metric METRIC' */
/* Set metric to attribute. */
-static route_map_result_t route_set_metric(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_set_metric(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
if (type == RMAP_RIP) {
struct rip_metric_modifier *mod;
@@ -472,10 +468,10 @@ static struct route_map_rule_cmd route_set_metric_cmd = {
/* `set ip next-hop IP_ADDRESS' */
/* Set nexthop to object. ojbect must be pointer to struct attr. */
-static route_map_result_t route_set_ip_nexthop(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t route_set_ip_nexthop(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct in_addr *address;
struct rip_info *rinfo;
@@ -525,8 +521,9 @@ static struct route_map_rule_cmd route_set_ip_nexthop_cmd = {
/* `set tag TAG' */
/* Set tag to object. ojbect must be pointer to struct attr. */
-static route_map_result_t route_set_tag(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static enum route_map_cmd_result_t
+route_set_tag(void *rule, const struct prefix *prefix, route_map_object_t type,
+ void *object)
{
route_tag_t *tag;
struct rip_info *rinfo;
diff --git a/ripd/ripd.c b/ripd/ripd.c
index e0ff0430f8..561fbcb52d 100644
--- a/ripd/ripd.c
+++ b/ripd/ripd.c
@@ -37,7 +37,9 @@
#include "if_rmap.h"
#include "plist.h"
#include "distribute.h"
+#ifdef CRYPTO_INTERNAL
#include "md5.h"
+#endif
#include "keychain.h"
#include "privs.h"
#include "lib_errors.h"
@@ -870,7 +872,11 @@ static int rip_auth_md5(struct rip_packet *packet, struct sockaddr_in *from,
struct rip_md5_data *md5data;
struct keychain *keychain;
struct key *key;
+#ifdef CRYPTO_OPENSSL
+ EVP_MD_CTX *ctx;
+#elif CRYPTO_INTERNAL
MD5_CTX ctx;
+#endif
uint8_t digest[RIP_AUTH_MD5_SIZE];
uint16_t packet_len;
char auth_str[RIP_AUTH_MD5_SIZE] = {};
@@ -934,11 +940,21 @@ static int rip_auth_md5(struct rip_packet *packet, struct sockaddr_in *from,
return 0;
/* MD5 digest authentication. */
+#ifdef CRYPTO_OPENSSL
+ unsigned int md5_size = RIP_AUTH_MD5_SIZE;
+ ctx = EVP_MD_CTX_new();
+ EVP_DigestInit(ctx, EVP_md5());
+ EVP_DigestUpdate(ctx, packet, packet_len + RIP_HEADER_SIZE);
+ EVP_DigestUpdate(ctx, auth_str, RIP_AUTH_MD5_SIZE);
+ EVP_DigestFinal(ctx, digest, &md5_size);
+ EVP_MD_CTX_free(ctx);
+#elif CRYPTO_INTERNAL
memset(&ctx, 0, sizeof(ctx));
MD5Init(&ctx);
MD5Update(&ctx, packet, packet_len + RIP_HEADER_SIZE);
MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE);
MD5Final(digest, &ctx);
+#endif
if (memcmp(md5data->digest, digest, RIP_AUTH_MD5_SIZE) == 0)
return packet_len;
@@ -1063,7 +1079,11 @@ static void rip_auth_md5_set(struct stream *s, struct rip_interface *ri,
size_t doff, char *auth_str, int authlen)
{
unsigned long len;
+#ifdef CRYPTO_OPENSSL
+ EVP_MD_CTX *ctx;
+#elif CRYPTO_INTERNAL
MD5_CTX ctx;
+#endif
unsigned char digest[RIP_AUTH_MD5_SIZE];
/* Make it sure this interface is configured as MD5
@@ -1092,11 +1112,21 @@ static void rip_auth_md5_set(struct stream *s, struct rip_interface *ri,
stream_putw(s, RIP_AUTH_DATA);
/* Generate a digest for the RIP packet. */
+#ifdef CRYPTO_OPENSSL
+ unsigned int md5_size = RIP_AUTH_MD5_SIZE;
+ ctx = EVP_MD_CTX_new();
+ EVP_DigestInit(ctx, EVP_md5());
+ EVP_DigestUpdate(ctx, STREAM_DATA(s), stream_get_endp(s));
+ EVP_DigestUpdate(ctx, auth_str, RIP_AUTH_MD5_SIZE);
+ EVP_DigestFinal(ctx, digest, &md5_size);
+ EVP_MD_CTX_free(ctx);
+#elif CRYPTO_INTERNAL
memset(&ctx, 0, sizeof(ctx));
MD5Init(&ctx);
MD5Update(&ctx, STREAM_DATA(s), stream_get_endp(s));
MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE);
MD5Final(digest, &ctx);
+#endif
/* Copy the digest to the packet. */
stream_write(s, digest, RIP_AUTH_MD5_SIZE);
diff --git a/ripngd/ripng_routemap.c b/ripngd/ripng_routemap.c
index 0604e272cd..d27ec76a56 100644
--- a/ripngd/ripng_routemap.c
+++ b/ripngd/ripng_routemap.c
@@ -38,10 +38,9 @@ struct rip_metric_modifier {
/* `match metric METRIC' */
/* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_metric(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_metric(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
uint32_t *metric;
struct ripng_info *rinfo;
@@ -86,10 +85,9 @@ static struct route_map_rule_cmd route_match_metric_cmd = {
/* `match interface IFNAME' */
/* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_interface(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_interface(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct ripng_info *rinfo;
struct interface *ifp;
@@ -129,9 +127,10 @@ static struct route_map_rule_cmd route_match_interface_cmd = {
/* `match tag TAG' */
/* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_tag(void *rule,
- const struct prefix *prefix,
- route_map_object_t type, void *object)
+static enum route_map_cmd_result_t route_match_tag(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
route_tag_t *tag;
struct ripng_info *rinfo;
@@ -159,10 +158,9 @@ static struct route_map_rule_cmd route_match_tag_cmd = {
/* `set metric METRIC' */
/* Set metric to attribute. */
-static route_map_result_t route_set_metric(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_set_metric(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
if (type == RMAP_RIPNG) {
struct rip_metric_modifier *mod;
@@ -256,10 +254,9 @@ static struct route_map_rule_cmd route_set_metric_cmd = {
/* `set ipv6 next-hop local IP_ADDRESS' */
/* Set nexthop to object. ojbect must be pointer to struct attr. */
-static route_map_result_t route_set_ipv6_nexthop_local(void *rule,
- const struct prefix *p,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_set_ipv6_nexthop_local(void *rule, const struct prefix *p,
+ route_map_object_t type, void *object)
{
struct in6_addr *address;
struct ripng_info *rinfo;
@@ -310,9 +307,9 @@ static struct route_map_rule_cmd route_set_ipv6_nexthop_local_cmd = {
/* `set tag TAG' */
/* Set tag to object. ojbect must be pointer to struct attr. */
-static route_map_result_t route_set_tag(void *rule,
- const struct prefix *prefix,
- route_map_object_t type, void *object)
+static enum route_map_cmd_result_t
+route_set_tag(void *rule, const struct prefix *prefix, route_map_object_t type,
+ void *object)
{
route_tag_t *tag;
struct ripng_info *rinfo;
diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c
index a7552547e9..60cfb2e486 100644
--- a/sharpd/sharp_vty.c
+++ b/sharpd/sharp_vty.c
@@ -39,14 +39,15 @@
#endif
DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd,
- "sharp watch [vrf NAME$name] <nexthop$n|import$import> X:X::X:X$nhop [connected$connected]",
+ "sharp watch [vrf NAME$name] <nexthop$n X:X::X:X$nhop|import$import X:X::X:X/M$inhop> [connected$connected]",
"Sharp routing Protocol\n"
"Watch for changes\n"
"The vrf we would like to watch if non-default\n"
"The NAME of the vrf\n"
"Watch for nexthop changes\n"
- "Watch for import check changes\n"
"The v6 nexthop to signal for watching\n"
+ "Watch for import check changes\n"
+ "The v6 prefix to signal for watching\n"
"Should the route be connected\n")
{
struct vrf *vrf;
@@ -62,16 +63,17 @@ DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd,
return CMD_WARNING;
}
- if (n)
- type_import = false;
- else
- type_import = true;
-
memset(&p, 0, sizeof(p));
- p.prefixlen = 128;
- memcpy(&p.u.prefix6, &nhop, 16);
- p.family = AF_INET6;
+ if (n) {
+ type_import = false;
+ p.prefixlen = 128;
+ memcpy(&p.u.prefix6, &nhop, 16);
+ p.family = AF_INET6;
+ } else {
+ type_import = true;
+ p = *(const struct prefix *)inhop;
+ }
sharp_nh_tracker_get(&p);
sharp_zebra_nexthop_watch(&p, vrf->vrf_id, type_import,
@@ -81,14 +83,15 @@ DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd,
}
DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd,
- "sharp watch [vrf NAME$name] <nexthop$n|import$import> A.B.C.D$nhop [connected$connected]",
+ "sharp watch [vrf NAME$name] <nexthop$n A.B.C.D$nhop|import$import A.B.C.D/M$inhop> [connected$connected]",
"Sharp routing Protocol\n"
"Watch for changes\n"
"The vrf we would like to watch if non-default\n"
"The NAME of the vrf\n"
"Watch for nexthop changes\n"
+ "The v4 address to signal for watching\n"
"Watch for import check changes\n"
- "The v4 nexthop to signal for watching\n"
+ "The v4 prefix for import check to watch\n"
"Should the route be connected\n")
{
struct vrf *vrf;
@@ -106,14 +109,16 @@ DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd,
memset(&p, 0, sizeof(p));
- if (n)
+ if (n) {
type_import = false;
- else
+ p.prefixlen = 32;
+ p.u.prefix4 = nhop;
+ p.family = AF_INET;
+ }
+ else {
type_import = true;
-
- p.prefixlen = 32;
- p.u.prefix4 = nhop;
- p.family = AF_INET;
+ p = *(const struct prefix *)inhop;
+ }
sharp_nh_tracker_get(&p);
sharp_zebra_nexthop_watch(&p, vrf->vrf_id, type_import,
diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c
index cd6f956580..6263f429ea 100644
--- a/sharpd/sharp_zebra.c
+++ b/sharpd/sharp_zebra.c
@@ -188,7 +188,7 @@ static void handle_repeated(bool installed)
sg.r.inst, sg.r.total_routes);
}
- if (installed) {
+ if (!installed) {
sg.r.installed_routes = 0;
sharp_install_routes_helper(&p, sg.r.vrf_id, sg.r.inst,
&sg.r.nhop_group,
diff --git a/sharpd/sharpd.conf.sample b/sharpd/sharpd.conf.sample
index bb1c2edca8..d1cc19a51f 100644
--- a/sharpd/sharpd.conf.sample
+++ b/sharpd/sharpd.conf.sample
@@ -1,3 +1,6 @@
+! Default sharpd configuration sample
!
+! There are no `default` configuration commands for sharpd
+! all commands are at the view or enable level.
!
log stdout
diff --git a/staticd/static_nht.c b/staticd/static_nht.c
index 2aa0db59f1..1a2ddd7f05 100644
--- a/staticd/static_nht.c
+++ b/staticd/static_nht.c
@@ -23,18 +23,48 @@
#include "table.h"
#include "vrf.h"
#include "nexthop.h"
+#include "srcdest_table.h"
#include "static_vrf.h"
#include "static_routes.h"
#include "static_zebra.h"
#include "static_nht.h"
-static void static_nht_update_safi(struct prefix *p, uint32_t nh_num,
- afi_t afi, safi_t safi, struct vrf *vrf,
- vrf_id_t nh_vrf_id)
+static void static_nht_update_rn(struct route_node *rn,
+ struct prefix *nhp, uint32_t nh_num,
+ vrf_id_t nh_vrf_id, struct vrf *vrf,
+ safi_t safi)
{
- struct route_table *stable;
struct static_route *si;
+
+ for (si = rn->info; si; si = si->next) {
+ if (si->nh_vrf_id != nh_vrf_id)
+ continue;
+
+ if (si->type != STATIC_IPV4_GATEWAY
+ && si->type != STATIC_IPV4_GATEWAY_IFNAME
+ && si->type != STATIC_IPV6_GATEWAY
+ && si->type != STATIC_IPV6_GATEWAY_IFNAME)
+ continue;
+
+ if (nhp->family == AF_INET
+ && nhp->u.prefix4.s_addr == si->addr.ipv4.s_addr)
+ si->nh_valid = !!nh_num;
+
+ if (nhp->family == AF_INET6
+ && memcmp(&nhp->u.prefix6, &si->addr.ipv6, 16) == 0)
+ si->nh_valid = !!nh_num;
+
+ if (si->state == STATIC_START)
+ static_zebra_route_add(rn, si, vrf->vrf_id, safi, true);
+ }
+}
+
+static void static_nht_update_safi(struct prefix *sp, struct prefix *nhp,
+ uint32_t nh_num, afi_t afi, safi_t safi,
+ struct vrf *vrf, vrf_id_t nh_vrf_id)
+{
+ struct route_table *stable;
struct static_vrf *svrf;
struct route_node *rn;
@@ -46,40 +76,129 @@ static void static_nht_update_safi(struct prefix *p, uint32_t nh_num,
if (!stable)
return;
+ if (sp) {
+ rn = srcdest_rnode_lookup(stable, sp, NULL);
+ if (rn) {
+ static_nht_update_rn(rn, nhp, nh_num, nh_vrf_id,
+ vrf, safi);
+ route_unlock_node(rn);
+ }
+ return;
+ }
+
+ for (rn = route_top(stable); rn; rn = route_next(rn))
+ static_nht_update_rn(rn, nhp, nh_num, nh_vrf_id, vrf, safi);
+
+}
+
+void static_nht_update(struct prefix *sp, struct prefix *nhp,
+ uint32_t nh_num, afi_t afi, vrf_id_t nh_vrf_id)
+{
+
+ struct vrf *vrf;
+
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ static_nht_update_safi(sp, nhp, nh_num, afi, SAFI_UNICAST,
+ vrf, nh_vrf_id);
+ static_nht_update_safi(sp, nhp, nh_num, afi, SAFI_MULTICAST,
+ vrf, nh_vrf_id);
+ }
+}
+
+static void static_nht_reset_start_safi(struct prefix *nhp, afi_t afi,
+ safi_t safi, struct vrf *vrf,
+ vrf_id_t nh_vrf_id)
+{
+ struct static_vrf *svrf;
+ struct route_table *stable;
+ struct static_route *si;
+ struct route_node *rn;
+
+ svrf = vrf->info;
+ if (!svrf)
+ return;
+
+ stable = static_vrf_static_table(afi, safi, svrf);
+ if (!stable)
+ return;
+
for (rn = route_top(stable); rn; rn = route_next(rn)) {
for (si = rn->info; si; si = si->next) {
if (si->nh_vrf_id != nh_vrf_id)
continue;
- if (si->type != STATIC_IPV4_GATEWAY
- && si->type != STATIC_IPV4_GATEWAY_IFNAME
- && si->type != STATIC_IPV6_GATEWAY
- && si->type != STATIC_IPV6_GATEWAY_IFNAME)
+ if (nhp->family == AF_INET
+ && nhp->u.prefix4.s_addr != si->addr.ipv4.s_addr)
continue;
- if (p->family == AF_INET
- && p->u.prefix4.s_addr == si->addr.ipv4.s_addr)
- si->nh_valid = !!nh_num;
-
- if (p->family == AF_INET6
- && memcmp(&p->u.prefix6, &si->addr.ipv6, 16) == 0)
- si->nh_valid = !!nh_num;
+ if (nhp->family == AF_INET6
+ && memcmp(&nhp->u.prefix6, &si->addr.ipv6, 16) != 0)
+ continue;
- static_zebra_route_add(rn, si, vrf->vrf_id, safi, true);
+ /*
+ * We've been told that a nexthop we depend
+ * on has changed in some manner, so reset
+ * the state machine to allow us to start
+ * over.
+ */
+ si->state = STATIC_START;
}
}
}
-void static_nht_update(struct prefix *p, uint32_t nh_num, afi_t afi,
- vrf_id_t nh_vrf_id)
+void static_nht_reset_start(struct prefix *nhp, afi_t afi, vrf_id_t nh_vrf_id)
{
-
struct vrf *vrf;
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
- static_nht_update_safi(p, nh_num, afi, SAFI_UNICAST,
- vrf, nh_vrf_id);
- static_nht_update_safi(p, nh_num, afi, SAFI_MULTICAST,
- vrf, nh_vrf_id);
+ static_nht_reset_start_safi(nhp, afi, SAFI_UNICAST,
+ vrf, nh_vrf_id);
+ static_nht_reset_start_safi(nhp, afi, SAFI_MULTICAST,
+ vrf, nh_vrf_id);
}
}
+
+static void static_nht_mark_state_safi(struct prefix *sp, afi_t afi,
+ safi_t safi, struct vrf *vrf,
+ enum static_install_states state)
+{
+ struct static_vrf *svrf;
+ struct route_table *stable;
+ struct static_route *si;
+ struct route_node *rn;
+
+ svrf = vrf->info;
+ if (!svrf)
+ return;
+
+ stable = static_vrf_static_table(afi, safi, svrf);
+ if (!stable)
+ return;
+
+ rn = srcdest_rnode_lookup(stable, sp, NULL);
+ if (!rn)
+ return;
+
+ for (si = rn->info; si; si = si->next)
+ si->state = state;
+
+ route_unlock_node(rn);
+}
+
+void static_nht_mark_state(struct prefix *sp, vrf_id_t vrf_id,
+ enum static_install_states state)
+{
+ struct vrf *vrf;
+
+ afi_t afi = AFI_IP;
+
+ if (sp->family == AF_INET6)
+ afi = AFI_IP6;
+
+ vrf = vrf_lookup_by_id(vrf_id);
+ if (!vrf || !vrf->info)
+ return;
+
+ static_nht_mark_state_safi(sp, afi, SAFI_UNICAST, vrf, state);
+ static_nht_mark_state_safi(sp, afi, SAFI_MULTICAST, vrf, state);
+}
diff --git a/staticd/static_nht.h b/staticd/static_nht.h
index f273c71bba..18bb9e39ca 100644
--- a/staticd/static_nht.h
+++ b/staticd/static_nht.h
@@ -20,6 +20,31 @@
#ifndef __STATIC_NHT_H__
#define __STATIC_NHT_H__
-extern void static_nht_update(struct prefix *p, uint32_t nh_num,
- afi_t afi, vrf_id_t vrf_id);
+/*
+ * When we get notification that nexthop tracking has an answer for
+ * us call this function to find the nexthop we are tracking so it
+ * can be installed or removed.
+ *
+ * sp -> The route we are looking at. If NULL then look at all
+ * routes.
+ * nhp -> The nexthop that is being tracked.
+ * nh_num -> number of valid nexthops.
+ * afi -> The afi we are working in.
+ * vrf_id -> The vrf the nexthop is in.
+ */
+extern void static_nht_update(struct prefix *sp, struct prefix *nhp,
+ uint32_t nh_num, afi_t afi, vrf_id_t vrf_id);
+
+/*
+ * For the given tracked nexthop, nhp, mark all routes that use
+ * this route as in starting state again.
+ */
+extern void static_nht_reset_start(struct prefix *nhp, afi_t afi,
+ vrf_id_t nh_vrf_id);
+
+/*
+ * For the given prefix, sp, mark it as in a particular state
+ */
+extern void static_nht_mark_state(struct prefix *sp, vrf_id_t vrf_id,
+ enum static_install_states state);
#endif
diff --git a/staticd/static_routes.c b/staticd/static_routes.c
index 5f9ecad694..34f58a98e2 100644
--- a/staticd/static_routes.c
+++ b/staticd/static_routes.c
@@ -39,7 +39,7 @@ static void static_install_route(struct route_node *rn,
struct static_route *si;
for (si = rn->info; si; si = si->next)
- static_zebra_nht_register(si, true);
+ static_zebra_nht_register(rn, si, true);
si = rn->info;
if (si)
@@ -73,6 +73,7 @@ int static_add_route(afi_t afi, safi_t safi, uint8_t type, struct prefix *p,
struct static_route *cp;
struct static_route *update = NULL;
struct route_table *stable = svrf->stable[afi][safi];
+ struct interface *ifp;
if (!stable)
return -1;
@@ -182,11 +183,26 @@ int static_add_route(afi_t afi, safi_t safi, uint8_t type, struct prefix *p,
si->next = cp;
/* check whether interface exists in system & install if it does */
- if (!ifname)
- static_install_route(rn, si, safi);
- else {
- struct interface *ifp;
+ switch (si->type) {
+ case STATIC_IPV4_GATEWAY:
+ case STATIC_IPV6_GATEWAY:
+ static_zebra_nht_register(rn, si, true);
+ break;
+ case STATIC_IPV4_GATEWAY_IFNAME:
+ case STATIC_IPV6_GATEWAY_IFNAME:
+ ifp = if_lookup_by_name(ifname, nh_svrf->vrf->vrf_id);
+ if (ifp && ifp->ifindex != IFINDEX_INTERNAL)
+ si->ifindex = ifp->ifindex;
+ else
+ zlog_warn("Static Route using %s interface not installed because the interface does not exist in specified vrf",
+ ifname);
+ static_zebra_nht_register(rn, si, true);
+ break;
+ case STATIC_BLACKHOLE:
+ static_install_route(rn, si, safi);
+ break;
+ case STATIC_IFNAME:
ifp = if_lookup_by_name(ifname, nh_svrf->vrf->vrf_id);
if (ifp && ifp->ifindex != IFINDEX_INTERNAL) {
si->ifindex = ifp->ifindex;
@@ -194,6 +210,8 @@ int static_add_route(afi_t afi, safi_t safi, uint8_t type, struct prefix *p,
} else
zlog_warn("Static Route using %s interface not installed because the interface does not exist in specified vrf",
ifname);
+
+ break;
}
return 1;
@@ -242,7 +260,7 @@ int static_delete_route(afi_t afi, safi_t safi, uint8_t type, struct prefix *p,
return 0;
}
- static_zebra_nht_register(si, false);
+ static_zebra_nht_register(rn, si, false);
/* Unlink static route from linked list. */
if (si->prev)
diff --git a/staticd/static_routes.h b/staticd/static_routes.h
index 6036bfe396..6414947b16 100644
--- a/staticd/static_routes.h
+++ b/staticd/static_routes.h
@@ -44,6 +44,26 @@ typedef enum {
STATIC_IPV6_GATEWAY_IFNAME,
} static_types;
+/*
+ * Route Creation gives us:
+ * START -> Initial State, only exit is when we send the route to
+ * zebra for installation
+ * When we send the route to Zebra move to SENT_TO_ZEBRA
+ * SENT_TO_ZEBRA -> A way to notice that we've sent the route to zebra
+ * But have not received a response on it's status yet
+ * After The response from zebra we move to INSTALLED or FAILED
+ * INSTALLED -> Route was accepted
+ * FAILED -> Route was rejected
+ * When we receive notification about a nexthop that a route uses
+ * We move the route back to START and initiate the process again.
+ */
+enum static_install_states {
+ STATIC_START,
+ STATIC_SENT_TO_ZEBRA,
+ STATIC_INSTALLED,
+ STATIC_NOT_INSTALLED,
+};
+
/* Static route information. */
struct static_route {
/* For linked list. */
@@ -55,6 +75,12 @@ struct static_route {
vrf_id_t nh_vrf_id;
char nh_vrfname[VRF_NAMSIZ + 1];
+ /*
+ * States that we walk the route through
+ * To know where we are.
+ */
+ enum static_install_states state;
+
/* Administrative distance. */
uint8_t distance;
diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c
index c6da00418b..13c04259d7 100644
--- a/staticd/static_zebra.c
+++ b/staticd/static_zebra.c
@@ -43,6 +43,8 @@
#include "static_nht.h"
#include "static_vty.h"
+bool debug;
+
/* Zebra structure to hold current status. */
struct zclient *zclient;
static struct hash *static_nht_hash;
@@ -154,18 +156,23 @@ static int route_notify_owner(ZAPI_CALLBACK_ARGS)
switch (note) {
case ZAPI_ROUTE_FAIL_INSTALL:
+ static_nht_mark_state(&p, vrf_id, STATIC_NOT_INSTALLED);
zlog_warn("%s: Route %s failed to install for table: %u",
__PRETTY_FUNCTION__, buf, table_id);
break;
case ZAPI_ROUTE_BETTER_ADMIN_WON:
+ static_nht_mark_state(&p, vrf_id, STATIC_NOT_INSTALLED);
zlog_warn("%s: Route %s over-ridden by better route for table: %u",
__PRETTY_FUNCTION__, buf, table_id);
break;
case ZAPI_ROUTE_INSTALLED:
+ static_nht_mark_state(&p, vrf_id, STATIC_INSTALLED);
break;
case ZAPI_ROUTE_REMOVED:
+ static_nht_mark_state(&p, vrf_id, STATIC_NOT_INSTALLED);
break;
case ZAPI_ROUTE_REMOVE_FAIL:
+ static_nht_mark_state(&p, vrf_id, STATIC_INSTALLED);
zlog_warn("%s: Route %s failure to remove for table: %u",
__PRETTY_FUNCTION__, buf, table_id);
break;
@@ -210,7 +217,8 @@ static int static_zebra_nexthop_update(ZAPI_CALLBACK_ARGS)
if (nhtd) {
nhtd->nh_num = nhr.nexthop_num;
- static_nht_update(&nhr.prefix, nhr.nexthop_num, afi,
+ static_nht_reset_start(&nhr.prefix, afi, nhtd->nh_vrf_id);
+ static_nht_update(NULL, &nhr.prefix, nhr.nexthop_num, afi,
nhtd->nh_vrf_id);
} else
zlog_err("No nhtd?");
@@ -267,7 +275,8 @@ static void static_nht_hash_free(void *data)
XFREE(MTYPE_TMP, nhtd);
}
-void static_zebra_nht_register(struct static_route *si, bool reg)
+void static_zebra_nht_register(struct route_node *rn,
+ struct static_route *si, bool reg)
{
struct static_nht_data *nhtd, lookup;
uint32_t cmd;
@@ -315,8 +324,11 @@ void static_zebra_nht_register(struct static_route *si, bool reg)
static_nht_hash_alloc);
nhtd->refcount++;
- if (nhtd->refcount > 1) {
- static_nht_update(nhtd->nh, nhtd->nh_num,
+ if (debug)
+ zlog_debug("Registered nexthop(%pFX) for %pRN %d", &p,
+ rn, nhtd->nh_num);
+ if (nhtd->refcount > 1 && nhtd->nh_num) {
+ static_nht_update(&rn->p, nhtd->nh, nhtd->nh_num,
afi, si->nh_vrf_id);
return;
}
@@ -389,6 +401,8 @@ extern void static_zebra_route_add(struct route_node *rn,
api_nh->vrf_id = si->nh_vrf_id;
api_nh->onlink = si->onlink;
+ si->state = STATIC_SENT_TO_ZEBRA;
+
switch (si->type) {
case STATIC_IFNAME:
if (si->ifindex == IFINDEX_INTERNAL)
diff --git a/staticd/static_zebra.h b/staticd/static_zebra.h
index a82eb162e1..15f5410b81 100644
--- a/staticd/static_zebra.h
+++ b/staticd/static_zebra.h
@@ -21,7 +21,8 @@
extern struct thread_master *master;
-extern void static_zebra_nht_register(struct static_route *si, bool reg);
+extern void static_zebra_nht_register(struct route_node *rn,
+ struct static_route *si, bool reg);
extern void static_zebra_route_add(struct route_node *rn,
struct static_route *si_changed,
diff --git a/staticd/staticd.conf.sample b/staticd/staticd.conf.sample
index bb1c2edca8..3b64eb9c90 100644
--- a/staticd/staticd.conf.sample
+++ b/staticd/staticd.conf.sample
@@ -1,3 +1,5 @@
-!
+! Default staticd configuration sample
!
log stdout
+!
+! ip route 4.5.6.7/32 10.10.10.10
diff --git a/tests/bgpd/test_bgp_table.c b/tests/bgpd/test_bgp_table.c
index 7b38df5f66..819c2d7282 100644
--- a/tests/bgpd/test_bgp_table.c
+++ b/tests/bgpd/test_bgp_table.c
@@ -183,7 +183,7 @@ static void test_range_lookup(void)
do_test(table, "16.0.0.0/8", 16, "16.0.0.0/16", NULL);
- do_test(table, "0.0.0.0/3", 21, "1.16.0.0/16", "1.16.128.0/18",
+ do_test(table, "0.0.0.0/2", 21, "1.16.0.0/16", "1.16.128.0/18",
"1.16.192.0/18", "1.16.64.0/19", "1.16.160.0/19",
"1.16.32.0/20", "1.16.32.0/21", "16.0.0.0/16", NULL);
}
diff --git a/tests/bgpd/test_bgp_table.py b/tests/bgpd/test_bgp_table.py
index 4423530fe0..4deaf08c22 100644
--- a/tests/bgpd/test_bgp_table.py
+++ b/tests/bgpd/test_bgp_table.py
@@ -3,5 +3,5 @@ import frrtest
class TestTable(frrtest.TestMultiOut):
program = './test_bgp_table'
-for i in range(6):
+for i in range(9):
TestTable.onesimple('Checks successfull')
diff --git a/tests/lib/cli/test_commands.c b/tests/lib/cli/test_commands.c
index ba46bdcea9..bbdc8b238d 100644
--- a/tests/lib/cli/test_commands.c
+++ b/tests/lib/cli/test_commands.c
@@ -243,7 +243,8 @@ static void test_run(struct prng *prng, struct vty *vty, const char *cmd,
(test_buf[0] != '\0') ? ", " : "",
test_buf);
- if (isspace((int)test_str[strlen(test_str) - 1])) {
+ if (isspace((unsigned char)test_str[
+ strlen(test_str) - 1])) {
vector_set(vline, NULL);
appended_null = 1;
}
diff --git a/tests/lib/cxxcompat.c b/tests/lib/cxxcompat.c
index 6624de7386..88126e84bc 100644
--- a/tests/lib/cxxcompat.c
+++ b/tests/lib/cxxcompat.c
@@ -55,7 +55,6 @@
#include "lib/libospf.h"
#include "lib/linklist.h"
#include "lib/log.h"
-#include "lib/logicalrouter.h"
#include "lib/md5.h"
#include "lib/memory.h"
#include "lib/memory_vty.h"
@@ -73,7 +72,6 @@
#include "lib/openbsd-tree.h"
#include "lib/pbr.h"
#include "lib/plist.h"
-#include "lib/pqueue.h"
#include "lib/prefix.h"
#include "lib/privs.h"
#include "lib/ptm_lib.h"
diff --git a/tests/lib/test_atomlist.c b/tests/lib/test_atomlist.c
index 249fff8edb..238ee9539e 100644
--- a/tests/lib/test_atomlist.c
+++ b/tests/lib/test_atomlist.c
@@ -253,7 +253,7 @@ static void *thr1func(void *arg)
struct testrun *tr;
for (tr = runs; tr; tr = tr->next) {
- sv = seqlock_bump(&p->sqlo);
+ sv = seqlock_bump(&p->sqlo) - SEQLOCK_INCR;
seqlock_wait(&sqlo, sv);
tr->func(offset);
@@ -288,14 +288,14 @@ static void run_tr(struct testrun *tr)
size_t c = 0, s = 0, n = 0;
struct item *item, *prev, dummy;
- printf("[%02u] %35s %s\n", seqlock_cur(&sqlo) >> 1, "", desc);
+ printf("[%02u] %35s %s\n", seqlock_cur(&sqlo) >> 2, "", desc);
fflush(stdout);
if (tr->prefill != NOCLEAR)
clear_list(tr->prefill);
monotime(&tv);
- sv = seqlock_bump(&sqlo);
+ sv = seqlock_bump(&sqlo) - SEQLOCK_INCR;
for (size_t i = 0; i < NTHREADS; i++) {
seqlock_wait(&thr[i].sqlo, seqlock_cur(&sqlo));
s += thr[i].counter;
@@ -325,7 +325,7 @@ static void run_tr(struct testrun *tr)
assert(c == alist_count(&ahead));
}
printf("\033[1A[%02u] %9"PRId64"us c=%5zu s=%5zu n=%5zu %s\n",
- sv >> 1, delta, c, s, n, desc);
+ sv >> 2, delta, c, s, n, desc);
}
#ifdef BASIC_TESTS
@@ -381,7 +381,7 @@ int main(int argc, char **argv)
basic_tests();
seqlock_init(&sqlo);
- seqlock_acquire_val(&sqlo, 1);
+ seqlock_acquire_val(&sqlo, SEQLOCK_STARTVAL);
for (i = 0; i < NTHREADS; i++) {
seqlock_init(&thr[i].sqlo);
diff --git a/tests/lib/test_seqlock.c b/tests/lib/test_seqlock.c
index 9cc6f80702..639c2bdc2b 100644
--- a/tests/lib/test_seqlock.c
+++ b/tests/lib/test_seqlock.c
@@ -66,20 +66,20 @@ static void *thr1func(void *arg)
seqlock_wait(&sqlo, 1);
writestr("thr1 @1\n");
- seqlock_wait(&sqlo, 3);
- writestr("thr1 @3\n");
-
seqlock_wait(&sqlo, 5);
writestr("thr1 @5\n");
- seqlock_wait(&sqlo, 7);
- writestr("thr1 @7\n");
-
seqlock_wait(&sqlo, 9);
writestr("thr1 @9\n");
- seqlock_wait(&sqlo, 11);
- writestr("thr1 @11\n");
+ seqlock_wait(&sqlo, 13);
+ writestr("thr1 @13\n");
+
+ seqlock_wait(&sqlo, 17);
+ writestr("thr1 @17\n");
+
+ seqlock_wait(&sqlo, 21);
+ writestr("thr1 @21\n");
return NULL;
}
@@ -95,11 +95,11 @@ int main(int argc, char **argv)
assert(seqlock_cur(&sqlo) == 1);
assert(seqlock_bump(&sqlo) == 1);
- assert(seqlock_cur(&sqlo) == 3);
- assert(seqlock_bump(&sqlo) == 3);
+ assert(seqlock_cur(&sqlo) == 5);
assert(seqlock_bump(&sqlo) == 5);
- assert(seqlock_bump(&sqlo) == 7);
- assert(seqlock_cur(&sqlo) == 9);
+ assert(seqlock_bump(&sqlo) == 9);
+ assert(seqlock_bump(&sqlo) == 13);
+ assert(seqlock_cur(&sqlo) == 17);
assert(seqlock_held(&sqlo));
seqlock_release(&sqlo);
@@ -108,16 +108,16 @@ int main(int argc, char **argv)
pthread_create(&thr1, NULL, thr1func, NULL);
sleep(1);
- writestr("main @3\n");
- seqlock_acquire_val(&sqlo, 3);
+ writestr("main @5\n");
+ seqlock_acquire_val(&sqlo, 5);
sleep(2);
- writestr("main @5\n");
+ writestr("main @9\n");
seqlock_bump(&sqlo);
sleep(1);
- writestr("main @9\n");
- seqlock_acquire_val(&sqlo, 9);
+ writestr("main @17\n");
+ seqlock_acquire_val(&sqlo, 17);
sleep(1);
writestr("main @release\n");
diff --git a/tests/lib/test_timer_correctness.c b/tests/lib/test_timer_correctness.c
index 43e79ba9d0..cbf9b05546 100644
--- a/tests/lib/test_timer_correctness.c
+++ b/tests/lib/test_timer_correctness.c
@@ -28,7 +28,6 @@
#include <unistd.h>
#include "memory.h"
-#include "pqueue.h"
#include "prng.h"
#include "thread.h"
diff --git a/tests/lib/test_timer_performance.c b/tests/lib/test_timer_performance.c
index d5f4badc85..2960e0d81e 100644
--- a/tests/lib/test_timer_performance.c
+++ b/tests/lib/test_timer_performance.c
@@ -28,7 +28,6 @@
#include <unistd.h>
#include "thread.h"
-#include "pqueue.h"
#include "prng.h"
#define SCHEDULE_TIMERS 1000000
diff --git a/tests/lib/test_typelist.h b/tests/lib/test_typelist.h
index b288f0bd8e..7ff210cae3 100644
--- a/tests/lib/test_typelist.h
+++ b/tests/lib/test_typelist.h
@@ -209,7 +209,7 @@ static void concat(test_, TYPE)(void)
assert(list_add(&head, &dummy) == &itm[j]);
else {
assert(list_add(&head, &dummy) == NULL);
- list_del(&head, &dummy);
+ assert(list_del(&head, &dummy) != NULL);
}
}
ts_hashx("add-dup", "a538546a6e6ab0484e925940aa8dd02fd934408bbaed8cb66a0721841584d838");
@@ -255,7 +255,7 @@ static void concat(test_, TYPE)(void)
list_first(&head) == &dummy);
} else if (list_next(&head, &dummy))
assert(list_next(&head, &dummy)->val > j);
- list_del(&head, &dummy);
+ assert(list_del(&head, &dummy) != NULL);
}
ts_hash("add-dup+find_{lt,gteq}", "a538546a6e6ab0484e925940aa8dd02fd934408bbaed8cb66a0721841584d838");
#endif
@@ -295,7 +295,7 @@ static void concat(test_, TYPE)(void)
(void)prng_rand(prng);
j = prng_rand(prng) % NITEM;
if (itm[j].scratchpad == 1) {
- list_del(&head, &itm[j]);
+ assert(list_del(&head, &itm[j]) != NULL);
itm[j].scratchpad = 0;
l++;
}
@@ -307,7 +307,7 @@ static void concat(test_, TYPE)(void)
assert(item->scratchpad != 0);
if (item->val & 1) {
- list_del(&head, item);
+ assert(list_del(&head, item) != NULL);
item->scratchpad = 0;
l++;
}
@@ -333,7 +333,7 @@ static void concat(test_, TYPE)(void)
for (i = 0; i < NITEM / 2; i++) {
j = prng_rand(prng) % NITEM;
if (itm[j].scratchpad == 1) {
- list_del(&head, &itm[j]);
+ assert(list_del(&head, &itm[j]) != NULL);
itm[j].scratchpad = 0;
k--;
}
@@ -371,7 +371,7 @@ static void concat(test_, TYPE)(void)
for (i = 0; i < NITEM / 2; i++) {
j = prng_rand(prng) % NITEM;
if (itm[j].scratchpad == 1) {
- list_del(&head, &itm[j]);
+ assert(list_del(&head, &itm[j]) != NULL);
itm[j].scratchpad = 0;
k--;
}
@@ -424,7 +424,7 @@ static void concat(test_, TYPE)(void)
item = &itm[j];
if (item->scratchpad == 0)
continue;
- list_del(&head, item);
+ assert(list_del(&head, item) != NULL);
}
item->scratchpad = 0;
k--;
@@ -469,7 +469,7 @@ static void concat(test_, TYPE)(void)
item = &itm[j];
if (item->scratchpad == 0)
continue;
- list_del(&head, item);
+ assert(list_del(&head, item) != NULL);
}
item->scratchpad = 0;
k--;
diff --git a/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref b/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref
index e75d896721..1fb70a0e2f 100644
--- a/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref
+++ b/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref
@@ -10,3 +10,9 @@ C>* 192.168.8.0/26 is directly connected, r1-eth8, XX:XX:XX
C>* 192.168.9.0/26 is directly connected, r1-eth9, XX:XX:XX
O 192.168.0.0/24 [110/10] is directly connected, r1-eth0, XX:XX:XX
O 192.168.3.0/26 [110/10] is directly connected, r1-eth3, XX:XX:XX
+S>* 4.5.6.10/32 [1/0] via 192.168.0.2, r1-eth0, XX:XX:XX
+S>* 4.5.6.11/32 [1/0] via 192.168.0.2, r1-eth0, XX:XX:XX
+S>* 4.5.6.12/32 [1/0] is directly connected, r1-eth0, XX:XX:XX
+S>* 4.5.6.7/32 [1/0] unreachable (blackhole), XX:XX:XX
+S>* 4.5.6.8/32 [1/0] unreachable (blackhole), XX:XX:XX
+S>* 4.5.6.9/32 [1/0] unreachable (ICMP unreachable), XX:XX:XX
diff --git a/tests/topotests/all-protocol-startup/r1/ipv6_routes.ref b/tests/topotests/all-protocol-startup/r1/ipv6_routes.ref
index 88cee964d6..6e3e9c87c1 100644
--- a/tests/topotests/all-protocol-startup/r1/ipv6_routes.ref
+++ b/tests/topotests/all-protocol-startup/r1/ipv6_routes.ref
@@ -20,3 +20,9 @@ C * fe80::/64 is directly connected, r1-eth7, XX:XX:XX
C * fe80::/64 is directly connected, r1-eth8, XX:XX:XX
C * fe80::/64 is directly connected, r1-eth9, XX:XX:XX
O fc00:0:0:4::/64 [110/10] is directly connected, r1-eth4, XX:XX:XX
+S>* 4:5::/32 [1/0] is directly connected, r1-eth0, XX:XX:XX
+S>* 4:5::6:10/128 [1/0] via fc00::2, r1-eth0, XX:XX:XX
+S>* 4:5::6:11/128 [1/0] via fc00::2, r1-eth0, XX:XX:XX
+S>* 4:5::6:7/128 [1/0] unreachable (blackhole), XX:XX:XX
+S>* 4:5::6:8/128 [1/0] unreachable (blackhole), XX:XX:XX
+S>* 4:5::6:9/128 [1/0] unreachable (ICMP unreachable), XX:XX:XX
diff --git a/tests/topotests/all-protocol-startup/r1/zebra.conf b/tests/topotests/all-protocol-startup/r1/zebra.conf
index 164104da7e..30e05f01e3 100644
--- a/tests/topotests/all-protocol-startup/r1/zebra.conf
+++ b/tests/topotests/all-protocol-startup/r1/zebra.conf
@@ -2,6 +2,23 @@ log file zebra.log
!
hostname r1
!
+# Create the various blackhole route types
+ip route 4.5.6.7/32 blackhole
+ipv6 route 4:5::6:7/128 blackhole
+ip route 4.5.6.8/32 Null0
+ipv6 route 4:5::6:8/128 Null0
+ip route 4.5.6.9/32 reject
+ipv6 route 4:5::6:9/128 reject
+# Create normal gateway routes
+ip route 4.5.6.10/32 192.168.0.2
+ipv6 route 4:5::6:10/128 fc00:0:0:0::2
+# Create normal gateway + interface routes
+ip route 4.5.6.11/32 192.168.0.2 r1-eth0
+ipv6 route 4:5::6:11/128 fc00:0:0:0::2 r1-eth0
+# Create ifname routes
+ip route 4.5.6.12/32 r1-eth0
+ipv6 route 4:5::6:12/32 r1-eth0
+!
interface r1-eth0
description to sw0 - no routing protocol
ip address 192.168.0.1/24
diff --git a/tests/topotests/bfd-topo2/r1/ipv4_routes.json b/tests/topotests/bfd-topo2/r1/ipv4_routes.json
index 8a2ec25baa..b0333de410 100644
--- a/tests/topotests/bfd-topo2/r1/ipv4_routes.json
+++ b/tests/topotests/bfd-topo2/r1/ipv4_routes.json
@@ -8,7 +8,7 @@
"selected": true,
"installed": true,
"prefix": "10.0.3.0/24",
- "internalStatus": 34,
+ "internalStatus": 16,
"nexthops": [
{
"interfaceName": "r1-eth0",
@@ -30,7 +30,7 @@
"selected": true,
"installed": true,
"prefix": "10.254.254.2/32",
- "internalStatus": 34,
+ "internalStatus": 16,
"nexthops": [
{
"interfaceName": "r1-eth0",
@@ -52,7 +52,7 @@
"selected": true,
"installed": true,
"prefix": "10.254.254.1/32",
- "internalStatus": 32,
+ "internalStatus": 16,
"nexthops": [
{
"directlyConnected": true,
diff --git a/tests/topotests/bfd-topo2/r1/ipv6_routes.json b/tests/topotests/bfd-topo2/r1/ipv6_routes.json
index 618853bd42..d09439a8a6 100644
--- a/tests/topotests/bfd-topo2/r1/ipv6_routes.json
+++ b/tests/topotests/bfd-topo2/r1/ipv6_routes.json
@@ -8,7 +8,7 @@
"selected": true,
"installed": true,
"prefix": "2001:db8:4::/64",
- "internalStatus": 34,
+ "internalStatus": 16,
"nexthops": [
{
"interfaceName": "r1-eth0",
@@ -27,7 +27,7 @@
"protocol": "bgp",
"internalFlags": 0,
"metric": 0,
- "internalStatus": 2,
+ "internalStatus": 0,
"prefix": "2001:db8:1::/64",
"nexthops": [
{
@@ -47,7 +47,7 @@
"selected": true,
"installed": true,
"prefix": "2001:db8:1::/64",
- "internalStatus": 32,
+ "internalStatus": 16,
"nexthops": [
{
"directlyConnected": true,
diff --git a/tests/topotests/bfd-topo2/r2/ipv4_routes.json b/tests/topotests/bfd-topo2/r2/ipv4_routes.json
index b9d8afb430..3c41e13434 100644
--- a/tests/topotests/bfd-topo2/r2/ipv4_routes.json
+++ b/tests/topotests/bfd-topo2/r2/ipv4_routes.json
@@ -5,7 +5,7 @@
"protocol": "ospf",
"internalFlags": 0,
"metric": 10,
- "internalStatus": 2,
+ "internalStatus": 0,
"prefix": "10.0.3.0/24",
"nexthops": [
{
@@ -25,7 +25,7 @@
"selected": true,
"installed": true,
"prefix": "10.0.3.0/24",
- "internalStatus": 32,
+ "internalStatus": 16,
"nexthops": [
{
"directlyConnected": true,
@@ -47,7 +47,7 @@
"selected": true,
"installed": true,
"prefix": "10.254.254.3/32",
- "internalStatus": 34,
+ "internalStatus": 16,
"nexthops": [
{
"interfaceName": "r2-eth1",
@@ -70,7 +70,7 @@
"selected": true,
"installed": true,
"prefix": "10.254.254.2/32",
- "internalStatus": 32,
+ "internalStatus": 16,
"nexthops": [
{
"directlyConnected": true,
@@ -92,7 +92,7 @@
"selected": true,
"installed": true,
"prefix": "10.254.254.1/32",
- "internalStatus": 34,
+ "internalStatus": 16,
"nexthops": [
{
"interfaceName": "r2-eth0",
diff --git a/tests/topotests/bfd-topo2/r2/ipv6_routes.json b/tests/topotests/bfd-topo2/r2/ipv6_routes.json
index 004e7588aa..bb45bbae52 100644
--- a/tests/topotests/bfd-topo2/r2/ipv6_routes.json
+++ b/tests/topotests/bfd-topo2/r2/ipv6_routes.json
@@ -5,7 +5,7 @@
"protocol": "ospf6",
"internalFlags": 0,
"metric": 10,
- "internalStatus": 2,
+ "internalStatus": 0,
"prefix": "2001:db8:4::/64",
"nexthops": [
{
@@ -25,7 +25,7 @@
"selected": true,
"installed": true,
"prefix": "2001:db8:4::/64",
- "internalStatus": 32,
+ "internalStatus": 16,
"nexthops": [
{
"directlyConnected": true,
@@ -47,7 +47,7 @@
"selected": true,
"installed": true,
"prefix": "2001:db8:1::/64",
- "internalStatus": 32,
+ "internalStatus": 16,
"nexthops": [
{
"directlyConnected": true,
diff --git a/tests/topotests/bfd-topo2/r3/ipv4_routes.json b/tests/topotests/bfd-topo2/r3/ipv4_routes.json
index 14dfc692fe..cbf116e687 100644
--- a/tests/topotests/bfd-topo2/r3/ipv4_routes.json
+++ b/tests/topotests/bfd-topo2/r3/ipv4_routes.json
@@ -25,7 +25,7 @@
"selected": true,
"installed": true,
"prefix": "10.0.3.0/24",
- "internalStatus": 32,
+ "internalStatus": 16,
"nexthops": [
{
"directlyConnected": true,
@@ -47,7 +47,7 @@
"selected": true,
"installed": true,
"prefix": "10.254.254.3/32",
- "internalStatus": 32,
+ "internalStatus": 16,
"nexthops": [
{
"directlyConnected": true,
@@ -69,7 +69,7 @@
"selected": true,
"installed": true,
"prefix": "10.254.254.2/32",
- "internalStatus": 34,
+ "internalStatus": 16,
"nexthops": [
{
"interfaceName": "r3-eth0",
@@ -92,7 +92,7 @@
"selected": true,
"installed": true,
"prefix": "10.254.254.1/32",
- "internalStatus": 34,
+ "internalStatus": 16,
"nexthops": [
{
"interfaceName": "r3-eth0",
diff --git a/tests/topotests/bfd-topo2/r4/ipv4_routes.json b/tests/topotests/bfd-topo2/r4/ipv4_routes.json
index ae1e97b017..b06184a44d 100644
--- a/tests/topotests/bfd-topo2/r4/ipv4_routes.json
+++ b/tests/topotests/bfd-topo2/r4/ipv4_routes.json
@@ -8,7 +8,7 @@
"selected": true,
"installed": true,
"prefix": "10.254.254.4/32",
- "internalStatus": 32,
+ "internalStatus": 16,
"nexthops": [
{
"directlyConnected": true,
diff --git a/tests/topotests/bfd-topo2/r4/ipv6_routes.json b/tests/topotests/bfd-topo2/r4/ipv6_routes.json
index 33608b45aa..a22c90cbba 100644
--- a/tests/topotests/bfd-topo2/r4/ipv6_routes.json
+++ b/tests/topotests/bfd-topo2/r4/ipv6_routes.json
@@ -5,7 +5,7 @@
"protocol": "ospf6",
"internalFlags": 0,
"metric": 10,
- "internalStatus": 2,
+ "internalStatus": 0,
"prefix": "2001:db8:4::/64",
"nexthops": [
{
@@ -25,7 +25,7 @@
"selected": true,
"installed": true,
"prefix": "2001:db8:4::/64",
- "internalStatus": 32,
+ "internalStatus": 16,
"nexthops": [
{
"directlyConnected": true,
@@ -47,7 +47,7 @@
"selected": true,
"installed": true,
"prefix": "2001:db8:1::/64",
- "internalStatus": 34,
+ "internalStatus": 16,
"nexthops": [
{
"interfaceName": "r4-eth0",
diff --git a/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py b/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py
index abd6b396d1..2b9c411ff2 100755
--- a/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py
+++ b/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py
@@ -218,11 +218,8 @@ def test_next_hop_attribute(request):
# Verifying RIB routes
dut = "r1"
protocol = "bgp"
- result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
- try:
- assert result is True
- except AssertionError:
- logger.info("Expected behaviour: %s", result)
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False)
+ assert result is not True
# Configure next-hop-self to bgp neighbor
input_dict_1 = {
diff --git a/tests/topotests/bgp-prefix-list-topo1/test_prefix_lists.py b/tests/topotests/bgp-prefix-list-topo1/test_prefix_lists.py
index 25a346f20d..d3892e9d07 100755
--- a/tests/topotests/bgp-prefix-list-topo1/test_prefix_lists.py
+++ b/tests/topotests/bgp-prefix-list-topo1/test_prefix_lists.py
@@ -385,7 +385,7 @@ def test_ip_prefix_lists_out_permit(request):
assert result is True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result)
- result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False)
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result)
write_test_footer(tc_name)
@@ -496,7 +496,7 @@ def test_ip_prefix_lists_in_deny_and_permit_any(request):
# Verifying RIB routes
dut = "r3"
protocol = "bgp"
- result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False)
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result)
@@ -713,7 +713,7 @@ def test_ip_prefix_lists_out_deny_and_permit_any(request):
# Verifying RIB routes
dut = "r4"
protocol = "bgp"
- result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False)
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result)
@@ -858,7 +858,7 @@ def test_modify_prefix_lists_in_permit_to_deny(request):
# Verifying RIB routes
dut = "r3"
protocol = "bgp"
- result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False)
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result)
@@ -971,7 +971,7 @@ def test_modify_prefix_lists_in_deny_to_permit(request):
# Verifying RIB routes
dut = "r3"
protocol = "bgp"
- result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False)
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result)
@@ -1151,7 +1151,7 @@ def test_modify_prefix_lists_out_permit_to_deny(request):
# Verifying RIB routes
dut = "r4"
protocol = "bgp"
- result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False)
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result)
@@ -1264,7 +1264,7 @@ def test_modify_prefix_lists_out_deny_to_permit(request):
# Verifying RIB routes
dut = "r4"
protocol = "bgp"
- result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False)
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result)
@@ -1438,7 +1438,7 @@ def test_ip_prefix_lists_implicit_deny(request):
# Verifying RIB routes
dut = "r4"
protocol = "bgp"
- result = verify_rib(tgen, "ipv4", dut, input_dict_1, protocol=protocol)
+ result = verify_rib(tgen, "ipv4", dut, input_dict_1, protocol=protocol, expected=False)
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result)
diff --git a/tests/topotests/bgp_comm-list_delete/__init__.py b/tests/topotests/bgp_comm-list_delete/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_comm-list_delete/__init__.py
diff --git a/tests/topotests/bgp_comm-list_delete/r1/bgpd.conf b/tests/topotests/bgp_comm-list_delete/r1/bgpd.conf
new file mode 100644
index 0000000000..6e1273f464
--- /dev/null
+++ b/tests/topotests/bgp_comm-list_delete/r1/bgpd.conf
@@ -0,0 +1,9 @@
+router bgp 65000
+ neighbor 192.168.255.2 remote-as 65001
+ address-family ipv4 unicast
+ redistribute connected route-map r2-out
+ exit-address-family
+!
+route-map r2-out permit 10
+ set community 111:111 222:222 333:333 444:444
+!
diff --git a/tests/topotests/bgp_comm-list_delete/r1/zebra.conf b/tests/topotests/bgp_comm-list_delete/r1/zebra.conf
new file mode 100644
index 0000000000..0a283c06d5
--- /dev/null
+++ b/tests/topotests/bgp_comm-list_delete/r1/zebra.conf
@@ -0,0 +1,9 @@
+!
+interface lo
+ ip address 172.16.255.254/32
+!
+interface r1-eth0
+ ip address 192.168.255.1/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_comm-list_delete/r2/bgpd.conf b/tests/topotests/bgp_comm-list_delete/r2/bgpd.conf
new file mode 100644
index 0000000000..3d354d56b1
--- /dev/null
+++ b/tests/topotests/bgp_comm-list_delete/r2/bgpd.conf
@@ -0,0 +1,11 @@
+router bgp 65001
+ neighbor 192.168.255.1 remote-as 65000
+ address-family ipv4
+ neighbor 192.168.255.1 route-map r1-in in
+ exit-address-family
+!
+bgp community-list standard r1 permit 333:333
+!
+route-map r1-in permit 10
+ set comm-list r1 delete
+!
diff --git a/tests/topotests/bgp_comm-list_delete/r2/zebra.conf b/tests/topotests/bgp_comm-list_delete/r2/zebra.conf
new file mode 100644
index 0000000000..606c17bec9
--- /dev/null
+++ b/tests/topotests/bgp_comm-list_delete/r2/zebra.conf
@@ -0,0 +1,6 @@
+!
+interface r2-eth0
+ ip address 192.168.255.2/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_comm-list_delete/test_bgp_comm-list_delete.py b/tests/topotests/bgp_comm-list_delete/test_bgp_comm-list_delete.py
new file mode 100644
index 0000000000..de6c35ba8f
--- /dev/null
+++ b/tests/topotests/bgp_comm-list_delete/test_bgp_comm-list_delete.py
@@ -0,0 +1,105 @@
+#!/usr/bin/env python
+
+#
+# bgp_comm-list_delete.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2019 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+bgp_comm-list_delete.py:
+
+Test if works the following commands:
+route-map test permit 10
+ set comm-list <arg> delete
+"""
+
+import os
+import sys
+import json
+import time
+import pytest
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../'))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+from mininet.topo import Topo
+
+class TemplateTopo(Topo):
+ def build(self, *_args, **_opts):
+ tgen = get_topogen(self)
+
+ for routern in range(1, 3):
+ tgen.add_router('r{}'.format(routern))
+
+ switch = tgen.add_switch('s1')
+ switch.add_link(tgen.gears['r1'])
+ switch.add_link(tgen.gears['r2'])
+
+def setup_module(mod):
+ tgen = Topogen(TemplateTopo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for i, (rname, router) in enumerate(router_list.iteritems(), 1):
+ router.load_config(
+ TopoRouter.RD_ZEBRA,
+ os.path.join(CWD, '{}/zebra.conf'.format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP,
+ os.path.join(CWD, '{}/bgpd.conf'.format(rname))
+ )
+
+ tgen.start_router()
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+def test_bgp_maximum_prefix_invalid():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ def _bgp_converge(router):
+ while True:
+ output = json.loads(tgen.gears[router].vtysh_cmd("show ip bgp neighbor 192.168.255.1 json"))
+ if output['192.168.255.1']['bgpState'] == 'Established':
+ if output['192.168.255.1']['addressFamilyInfo']['IPv4 Unicast']['acceptedPrefixCounter'] == 2:
+ return True
+
+ def _bgp_comm_list_delete(router):
+ output = json.loads(tgen.gears[router].vtysh_cmd("show ip bgp 172.16.255.254/32 json"))
+ if '333:333' in output['paths'][0]['community']['list']:
+ return False
+ return True
+
+ if _bgp_converge('r2'):
+ assert _bgp_comm_list_delete('r2') == True
+
+if __name__ == '__main__':
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_down.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_down.py
index db53c1aacd..0279e482ff 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_down.py
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_down.py
@@ -14,12 +14,12 @@ if ret != False and found != None:
luCommand('ce1', 'vtysh -c "sharp remove routes 10.0.0.0 {}"'.format(num),'.','none','Removing {} routes'.format(num))
luCommand('ce2', 'vtysh -c "sharp remove routes 10.0.0.0 {}"'.format(num),'.','none','Removing {} routes'.format(num))
for rtr in rtrs:
- luCommand(rtr, 'vtysh -c "show bgp ipv4 uni" | grep Display',' 10 route', 'wait', 'BGP routes removed', wait)
+ luCommand(rtr, 'vtysh -c "show bgp ipv4 uni" | grep Display',' 10 route', 'wait', 'BGP routes removed', wait, wait_time=10)
luCommand(rtr, 'vtysh -c "show bgp ipv4 uni"','.', 'none', 'BGP routes post remove')
for rtr in rtrs:
- luCommand(rtr, 'ip route show | grep -c \\^10\\.','^0$', 'wait', 'Linux routes removed', wait)
+ luCommand(rtr, 'ip route show | grep -c \\^10\\.','^0$', 'wait', 'Linux routes removed', wait, wait_time=10)
luCommand(rtr, 'ip route show','.', 'none', 'Linux routes post remove')
rtrs = ['r1', 'r3', 'r4']
for rtr in rtrs:
- luCommand(rtr, 'ip route show vrf {}-cust1 | grep -c \\^10\\.'.format(rtr),'^0$','wait','VRF route removed',wait)
+ luCommand(rtr, 'ip route show vrf {}-cust1 | grep -c \\^10\\.'.format(rtr),'^0$','wait','VRF route removed',wait, wait_time=10)
#done
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_up.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_up.py
index 3619cdf84f..21543ab78e 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_up.py
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_up.py
@@ -36,10 +36,10 @@ if doSharp == True:
luCommand('ce2', 'vtysh -c "sharp install routes 10.0.0.0 nexthop 99.0.0.2 {}"'.format(num),'','pass','Adding {} routes'.format(num))
rtrs = ['ce1', 'ce2', 'ce3']
for rtr in rtrs:
- luCommand(rtr, 'vtysh -c "show bgp ipv4 uni 10.{}.{}.{}"'.format(b,c,d), 'Last update:', 'wait', 'RXed last route, 10.{}.{}.{}'.format(b,c,d), wait)
- luCommand(rtr, 'vtysh -c "show bgp ipv4 uni" | grep -c 10\\.\\*/32', str(num), 'wait', 'See all sharp routes in BGP', wait)
- luCommand('r1', 'vtysh -c "show bgp vrf r1-cust1 ipv4 uni 10.{}.{}.{}"'.format(b,c,d),'99.0.0.1','wait','RXed -> 10.{}.{}.{} from CE1'.format(b,c,d), wait)
- luCommand('r3', 'vtysh -c "show bgp vrf r3-cust1 ipv4 uni 10.{}.{}.{}"'.format(b,c,d),'99.0.0.2','wait','RXed -> 10.{}.{}.{} from CE2'.format(b,c,d), wait)
+ luCommand(rtr, 'vtysh -c "show bgp ipv4 uni 10.{}.{}.{}"'.format(b,c,d), 'Last update:', 'wait', 'RXed last route, 10.{}.{}.{}'.format(b,c,d), wait, wait_time=10)
+ luCommand(rtr, 'vtysh -c "show bgp ipv4 uni" | grep -c 10\\.\\*/32', str(num), 'wait', 'See all sharp routes in BGP', wait, wait_time=10)
+ luCommand('r1', 'vtysh -c "show bgp vrf r1-cust1 ipv4 uni 10.{}.{}.{}"'.format(b,c,d),'99.0.0.1','wait','RXed -> 10.{}.{}.{} from CE1'.format(b,c,d), wait, wait_time=10)
+ luCommand('r3', 'vtysh -c "show bgp vrf r3-cust1 ipv4 uni 10.{}.{}.{}"'.format(b,c,d),'99.0.0.2','wait','RXed -> 10.{}.{}.{} from CE2'.format(b,c,d), wait, wait_time=10)
luCommand('r1', 'vtysh -c "show bgp ipv4 vpn 10.{}.{}.{}"'.format(b,c,d),'99.0.0.1','wait','see VPN safi -> 10.{}.{}.{} from CE1'.format(b,c,d))
luCommand('r3', 'vtysh -c "show bgp ipv4 vpn 10.{}.{}.{}"'.format(b,c,d),'99.0.0.2','wait','see VPN safi -> 10.{}.{}.{} from CE2'.format(b,c,d))
luCommand('r3', 'vtysh -c "show bgp ipv4 vpn 10.{}.{}.{}"'.format(b,c,d),'1.1.1.1','wait','see VPN safi -> 10.{}.{}.{} from CE1'.format(b,c,d))
@@ -48,13 +48,13 @@ if doSharp == True:
luCommand('r4', 'vtysh -c "show bgp ipv4 vpn 10.{}.{}.{}"'.format(b,c,d),'3.3.3.3','wait','see VPN safi -> 10.{}.{}.{} from CE2'.format(b,c,d))
rtrs = ['ce1', 'ce2', 'ce3']
for rtr in rtrs:
- luCommand(rtr, 'ip route get 10.{}.{}.{}'.format(b,c,d),'dev','wait','Route to 10.{}.{}.{} available'.format(b,c,d), wait)
- luCommand(rtr, 'ip route show | grep -c \\^10\\.', str(num), 'wait', 'See {} linux routes'.format(num), wait)
+ luCommand(rtr, 'ip route get 10.{}.{}.{}'.format(b,c,d),'dev','wait','Route to 10.{}.{}.{} available'.format(b,c,d), wait, wait_time=10)
+ luCommand(rtr, 'ip route show | grep -c \\^10\\.', str(num), 'wait', 'See {} linux routes'.format(num), wait, wait_time=10)
rtrs = ['r1', 'r3', 'r4']
for rtr in rtrs:
- luCommand(rtr, 'ip route get vrf {}-cust1 10.{}.{}.{}'.format(rtr,b,c,d),'dev','wait','VRF route available',wait)
- luCommand(rtr, 'ip route show vrf {}-cust1 | grep -c \\^10\\.'.format(rtr), str(num), 'wait','See {} linux routes'.format(num), wait)
+ luCommand(rtr, 'ip route get vrf {}-cust1 10.{}.{}.{}'.format(rtr,b,c,d),'dev','wait','VRF route available',wait, wait_time=10)
+ luCommand(rtr, 'ip route show vrf {}-cust1 | grep -c \\^10\\.'.format(rtr), str(num), 'wait','See {} linux routes'.format(num), wait, wait_time=10)
rtrs = ['ce1', 'ce2', 'ce3', 'r1', 'r2', 'r3', 'r4']
for rtr in rtrs:
ret = luCommand(rtr, 'vtysh -c "show memory"', 'zebra: System allocator statistics: Total heap allocated: *(\d*) ([A-Za-z]*) .*bgpd: System allocator statistics: Total heap allocated: *(\d*) ([A-Za-z]*)', 'none', 'collect bgpd memory stats')
diff --git a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv4_routes.json b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv4_routes.json
index e32c84b7d5..1649ade96d 100644
--- a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv4_routes.json
+++ b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv4_routes.json
@@ -9,7 +9,7 @@
"distance": 20,
"metric": 0,
"installed": true,
- "internalStatus": 34,
+ "internalStatus": 16,
"internalFlags": 8,
"nexthops": [
{
@@ -33,7 +33,7 @@
"distance": 0,
"metric": 0,
"installed": true,
- "internalStatus": 32,
+ "internalStatus": 16,
"internalFlags": 8,
"nexthops": [
{
diff --git a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv6_routes.json b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv6_routes.json
index 88e8c5cd83..1ca62094bd 100644
--- a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv6_routes.json
+++ b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv6_routes.json
@@ -6,7 +6,7 @@
"vrfId":3,
"distance": 20,
"metric": 0,
- "internalStatus": 2,
+ "internalStatus": 0,
"internalFlags": 0,
"nexthops": [
{
@@ -27,7 +27,7 @@
"distance": 0,
"metric": 0,
"installed": true,
- "internalStatus": 32,
+ "internalStatus": 16,
"internalFlags": 8,
"nexthops": [
{
diff --git a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/ipv4_routes.json b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/ipv4_routes.json
index 9d7c0e6e4f..eda4bed035 100644
--- a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/ipv4_routes.json
+++ b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/ipv4_routes.json
@@ -9,7 +9,7 @@
"distance": 0,
"metric": 0,
"installed": true,
- "internalStatus": 32,
+ "internalStatus": 16,
"internalFlags": 8,
"nexthops": [
{
@@ -33,7 +33,7 @@
"distance": 20,
"metric": 0,
"installed": true,
- "internalStatus": 34,
+ "internalStatus": 16,
"internalFlags": 8,
"nexthops": [
{
diff --git a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/ipv6_routes.json b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/ipv6_routes.json
index 230fe38748..45c1b76017 100644
--- a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/ipv6_routes.json
+++ b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/ipv6_routes.json
@@ -9,7 +9,7 @@
"distance": 0,
"metric": 0,
"installed": true,
- "internalStatus": 32,
+ "internalStatus": 16,
"internalFlags": 8,
"nexthops": [
{
diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py
index 13f8824976..2613f45f1c 100644
--- a/tests/topotests/lib/bgp.py
+++ b/tests/topotests/lib/bgp.py
@@ -932,7 +932,7 @@ def clear_bgp_and_verify(tgen, topo, router):
# Peer up time dictionary
peer_uptime_before_clear_bgp[bgp_neighbor] = \
- ipv4_data[neighbor_ip]["peerUptime"]
+ ipv4_data[neighbor_ip]["peerUptimeEstablishedEpoch"]
else:
ipv6_data = show_bgp_json["ipv6Unicast"][
"peers"]
@@ -940,7 +940,7 @@ def clear_bgp_and_verify(tgen, topo, router):
# Peer up time dictionary
peer_uptime_before_clear_bgp[bgp_neighbor] = \
- ipv6_data[neighbor_ip]["peerUptime"]
+ ipv6_data[neighbor_ip]["peerUptimeEstablishedEpoch"]
if nh_state == "Established":
no_of_peer += 1
@@ -953,6 +953,7 @@ def clear_bgp_and_verify(tgen, topo, router):
logger.warning("BGP is not yet Converged for router %s "
"before bgp clear", router)
+ logger.info(peer_uptime_before_clear_bgp)
# Clearing BGP
logger.info("Clearing BGP neighborship for router %s..", router)
for addr_type in bgp_addr_type.keys():
@@ -1010,14 +1011,14 @@ def clear_bgp_and_verify(tgen, topo, router):
"peers"]
nh_state = ipv4_data[neighbor_ip]["state"]
peer_uptime_after_clear_bgp[bgp_neighbor] = \
- ipv4_data[neighbor_ip]["peerUptime"]
+ ipv4_data[neighbor_ip]["peerUptimeEstablishedEpoch"]
else:
ipv6_data = show_bgp_json["ipv6Unicast"][
"peers"]
nh_state = ipv6_data[neighbor_ip]["state"]
# Peer up time dictionary
peer_uptime_after_clear_bgp[bgp_neighbor] = \
- ipv6_data[neighbor_ip]["peerUptime"]
+ ipv6_data[neighbor_ip]["peerUptimeEstablishedEpoch"]
if nh_state == "Established":
no_of_peer += 1
@@ -1030,7 +1031,8 @@ def clear_bgp_and_verify(tgen, topo, router):
logger.warning("BGP is not yet Converged for router %s after"
" bgp clear", router)
- # Compariung peerUptime dictionaries
+ logger.info(peer_uptime_after_clear_bgp)
+ # Comparing peerUptimeEstablishedEpoch dictionaries
if peer_uptime_before_clear_bgp != peer_uptime_after_clear_bgp:
logger.info("BGP neighborship is reset after clear BGP on router %s",
router)
diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py
index 628c198e1a..75880cfd28 100644
--- a/tests/topotests/lib/common_config.py
+++ b/tests/topotests/lib/common_config.py
@@ -30,6 +30,9 @@ import traceback
import socket
import ipaddr
+from lib import topotest
+
+from functools import partial
from lib.topolog import logger, logger_config
from lib.topogen import TopoRouter
@@ -1089,7 +1092,7 @@ def create_route_maps(tgen, input_dict, build=False):
#############################################
# Verification APIs
#############################################
-def verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None):
+def _verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None):
"""
Data will be read from input_dict or input JSON file, API will generate
same prefixes, which were redistributed by either create_static_routes() or
@@ -1258,6 +1261,26 @@ def verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None):
return True
+def verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None, expected=True):
+ """
+ Wrapper function for `_verify_rib` that tries multiple time to get results.
+
+ When the expected result is `False` we actually should expect for an string instead.
+ """
+
+ # Use currying to hide the parameters and create a test function.
+ test_func = partial(_verify_rib, tgen, addr_type, dut, input_dict, next_hop, protocol)
+
+ # Call the test function and expect it to return True, otherwise try it again.
+ if expected is True:
+ _, result = topotest.run_and_expect(test_func, True, count=20, wait=6)
+ else:
+ _, result = topotest.run_and_expect_type(test_func, str, count=20, wait=6)
+
+ # Return as normal.
+ return result
+
+
def verify_admin_distance_for_static_routes(tgen, input_dict):
"""
API to verify admin distance for static routes as defined in input_dict/
diff --git a/tests/topotests/lib/lutil.py b/tests/topotests/lib/lutil.py
index e58b4725eb..7c89ada013 100755
--- a/tests/topotests/lib/lutil.py
+++ b/tests/topotests/lib/lutil.py
@@ -22,6 +22,7 @@ import sys
import time
import datetime
import json
+import math
from topolog import logger
from mininet.net import Mininet
@@ -242,22 +243,27 @@ Total %-4d %-4d %d\n\
return js
return ret
- def wait(self, target, command, regexp, op, result, wait, returnJson):
- self.log('%s:%s WAIT:%s:%s:%s:%s:%s:%s:' % \
- (self.l_filename, self.l_line, target, command, regexp, op, result,wait))
- llevel = LUtil.l_level
+ def wait(self, target, command, regexp, op, result, wait, returnJson, wait_time=0.5):
+ self.log('%s:%s WAIT:%s:%s:%s:%s:%s:%s:%s:' % \
+ (self.l_filename, self.l_line, target, command, regexp, op, result,wait,wait_time))
found = False
n = 0
startt = time.time()
- delta = time.time() - startt
- while delta < wait and found is False:
+
+ # Calculate the amount of `sleep`s we are going to peform.
+ wait_count = int(math.ceil(wait / wait_time)) + 1
+
+ while wait_count > 0:
+ n += 1
found = self.command(target, command, regexp, op, result, returnJson)
- n+=1
- LUtil.l_level = 0
- delta = time.time() - startt
- if delta < wait and found is False:
- time.sleep (0.5)
- LUtil.l_level = llevel
+ if found is not False:
+ break
+
+ wait_count -= 1
+ if wait_count > 0:
+ time.sleep(wait_time)
+
+ delta = time.time() - startt
self.log('Done after %d loops, time=%s, Found=%s' % (n, delta, found))
found = self.command(target, command, regexp, 'pass', '%s +%4.2f secs' % (result, delta), returnJson)
return found
@@ -283,11 +289,11 @@ def luStart(baseScriptDir='.', baseLogDir='.', net='',
LUtil.l_dotall_experiment = False
LUtil.l_dotall_experiment = True
-def luCommand(target, command, regexp='.', op='none', result='', time=10, returnJson=False):
+def luCommand(target, command, regexp='.', op='none', result='', time=10, returnJson=False, wait_time=0.5):
if op != 'wait':
return LUtil.command(target, command, regexp, op, result, returnJson)
else:
- return LUtil.wait(target, command, regexp, op, result, time, returnJson)
+ return LUtil.wait(target, command, regexp, op, result, time, returnJson, wait_time)
def luLast(usenl=False):
if usenl:
diff --git a/tests/topotests/lib/test/test_run_and_expect.py b/tests/topotests/lib/test/test_run_and_expect.py
new file mode 100755
index 0000000000..3c22c20e7b
--- /dev/null
+++ b/tests/topotests/lib/test/test_run_and_expect.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python
+
+#
+# test_run_and_expect.py
+# Tests for library function: run_and_expect(_type)().
+#
+# Copyright (c) 2019 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+Tests for the `run_and_expect(_type)()` functions.
+"""
+
+import os
+import sys
+import pytest
+
+# Save the Current Working Directory to find lib files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../../'))
+
+# pylint: disable=C0413
+from lib.topotest import run_and_expect_type
+
+def test_run_and_expect_type():
+ "Test basic `run_and_expect_type` functionality."
+
+ def return_true():
+ "Test function that returns `True`."
+ return True
+
+ # Test value success.
+ success, value = run_and_expect_type(return_true, bool, count=1, wait=0, avalue=True)
+ assert success is True
+ assert value is True
+
+ # Test value failure.
+ success, value = run_and_expect_type(return_true, bool, count=1, wait=0, avalue=False)
+ assert success is False
+ assert value is True
+
+ # Test type success.
+ success, value = run_and_expect_type(return_true, bool, count=1, wait=0)
+ assert success is True
+ assert value is True
+
+ # Test type failure.
+ success, value = run_and_expect_type(return_true, str, count=1, wait=0)
+ assert success is False
+ assert value is True
+
+ # Test type failure, return correct type.
+ success, value = run_and_expect_type(return_true, str, count=1, wait=0, avalue=True)
+ assert success is False
+ assert value is True
+
+
+if __name__ == '__main__':
+ sys.exit(pytest.main())
diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py
index 867f9f2f03..9e1d344687 100644
--- a/tests/topotests/lib/topotest.py
+++ b/tests/topotests/lib/topotest.py
@@ -252,6 +252,54 @@ def run_and_expect(func, what, count=20, wait=3):
return (False, result)
+def run_and_expect_type(func, etype, count=20, wait=3, avalue=None):
+ """
+ Run `func` and compare the result with `etype`. Do it for `count` times
+ waiting `wait` seconds between tries. By default it tries 20 times with
+ 3 seconds delay between tries.
+
+ This function is used when you want to test the return type and,
+ optionally, the return value.
+
+ Returns (True, func-return) on success or
+ (False, func-return) on failure.
+ """
+ start_time = time.time()
+ func_name = "<unknown>"
+ if func.__class__ == functools.partial:
+ func_name = func.func.__name__
+ else:
+ func_name = func.__name__
+
+ logger.info(
+ "'{}' polling started (interval {} secs, maximum wait {} secs)".format(
+ func_name, wait, int(wait * count)))
+
+ while count > 0:
+ result = func()
+ if not isinstance(result, etype):
+ logger.debug("Expected result type '{}' got '{}' instead".format(etype, type(result)))
+ time.sleep(wait)
+ count -= 1
+ continue
+
+ if etype != type(None) and avalue != None and result != avalue:
+ logger.debug("Expected value '{}' got '{}' instead".format(avalue, result))
+ time.sleep(wait)
+ count -= 1
+ continue
+
+ end_time = time.time()
+ logger.info("'{}' succeeded after {:.2f} seconds".format(
+ func_name, end_time - start_time))
+ return (True, result)
+
+ end_time = time.time()
+ logger.error("'{}' failed after {:.2f} seconds".format(
+ func_name, end_time - start_time))
+ return (False, result)
+
+
def int2dpid(dpid):
"Converting Integer to DPID"
diff --git a/tools/coccinelle/ctype_cast.cocci b/tools/coccinelle/ctype_cast.cocci
new file mode 100644
index 0000000000..b0b00959da
--- /dev/null
+++ b/tools/coccinelle/ctype_cast.cocci
@@ -0,0 +1,11 @@
+
+@@
+identifier func =~ "^(to|is)(alnum|cntrl|print|xdigit|alpha|digit|punct|ascii|graph|space|blank|lower|upper)$";
+expression e;
+@@
+
+ func(
+- (int)
++ (unsigned char)
+ e)
+
diff --git a/tools/frr-reload.py b/tools/frr-reload.py
index 23e8f3000d..e182c77c78 100755
--- a/tools/frr-reload.py
+++ b/tools/frr-reload.py
@@ -393,8 +393,10 @@ end
# is not the main router bgp block, but enabling multi-instance
oneline_ctx_keywords = ("access-list ",
"agentx",
+ "allow-external-route-update",
"bgp ",
"debug ",
+ "domainname ",
"dump ",
"enable ",
"frr ",
diff --git a/tools/gen_northbound_callbacks.c b/tools/gen_northbound_callbacks.c
index f6c757f5d7..14f648e8da 100644
--- a/tools/gen_northbound_callbacks.c
+++ b/tools/gen_northbound_callbacks.c
@@ -28,7 +28,8 @@
static void __attribute__((noreturn)) usage(int status)
{
- fprintf(stderr, "usage: gen_northbound_callbacks [-h] MODULE\n");
+ extern const char *__progname;
+ fprintf(stderr, "usage: %s [-h] [-p path] MODULE\n", __progname);
exit(status);
}
@@ -152,6 +153,36 @@ static void generate_callback_name(struct lys_node *snode,
replace_hyphens_by_underscores(buffer);
}
+static void generate_callback(const struct nb_callback_info *ncinfo,
+ const char *cb_name)
+{
+ printf("static %s%s(%s)\n{\n",
+ ncinfo->return_type, cb_name, ncinfo->arguments);
+
+ switch (ncinfo->operation) {
+ case NB_OP_CREATE:
+ case NB_OP_MODIFY:
+ case NB_OP_DESTROY:
+ case NB_OP_MOVE:
+ printf("\tswitch (event) {\n"
+ "\tcase NB_EV_VALIDATE:\n"
+ "\tcase NB_EV_PREPARE:\n"
+ "\tcase NB_EV_ABORT:\n"
+ "\tcase NB_EV_APPLY:\n"
+ "\t\t/* TODO: implement me. */\n"
+ "\t\tbreak;\n"
+ "\t}\n\n"
+ );
+ break;
+
+ default:
+ printf("\t/* TODO: implement me. */\n");
+ break;
+ }
+
+ printf("\treturn %s;\n}\n\n", ncinfo->return_value);
+}
+
static int generate_callbacks(const struct lys_node *snode, void *arg)
{
bool first = true;
@@ -191,14 +222,7 @@ static int generate_callbacks(const struct lys_node *snode, void *arg)
generate_callback_name((struct lys_node *)snode, cb->operation,
cb_name, sizeof(cb_name));
- printf("static %s%s(%s)\n"
- "{\n"
- "\t/* TODO: implement me. */\n"
- "\treturn %s;\n"
- "}\n\n",
- nb_callbacks[cb->operation].return_type, cb_name,
- nb_callbacks[cb->operation].arguments,
- nb_callbacks[cb->operation].return_value);
+ generate_callback(cb, cb_name);
}
return YANG_ITER_CONTINUE;
@@ -237,32 +261,52 @@ static int generate_nb_nodes(const struct lys_node *snode, void *arg)
printf("\t\t{\n"
"\t\t\t.xpath = \"%s\",\n",
xpath);
+ printf("\t\t\t.cbs = {\n");
first = false;
}
generate_callback_name((struct lys_node *)snode, cb->operation,
cb_name, sizeof(cb_name));
- printf("\t\t\t.cbs.%s = %s,\n",
- nb_operation_name(cb->operation), cb_name);
+ printf("\t\t\t\t.%s = %s,\n", nb_operation_name(cb->operation),
+ cb_name);
}
- if (!first)
+ if (!first) {
+ printf("\t\t\t}\n");
printf("\t\t},\n");
+ }
return YANG_ITER_CONTINUE;
}
int main(int argc, char *argv[])
{
+ const char *search_path = NULL;
struct yang_module *module;
char module_name_underscores[64];
+ struct stat st;
int opt;
- while ((opt = getopt(argc, argv, "h")) != -1) {
+ while ((opt = getopt(argc, argv, "hp:")) != -1) {
switch (opt) {
case 'h':
usage(EXIT_SUCCESS);
/* NOTREACHED */
+ case 'p':
+ if (stat(optarg, &st) == -1) {
+ fprintf(stderr,
+ "error: invalid search path '%s': %s\n",
+ optarg, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ if (S_ISDIR(st.st_mode) == 0) {
+ fprintf(stderr,
+ "error: search path is not directory");
+ exit(EXIT_FAILURE);
+ }
+
+ search_path = optarg;
+ break;
default:
usage(EXIT_FAILURE);
/* NOTREACHED */
@@ -275,6 +319,9 @@ int main(int argc, char *argv[])
yang_init();
+ if (search_path)
+ ly_ctx_set_searchdir(ly_native_ctx, search_path);
+
/* Load all FRR native models to ensure all augmentations are loaded. */
yang_module_load_all();
module = yang_module_find(argv[0]);
diff --git a/tools/start-stop-daemon.c b/tools/start-stop-daemon.c
index 5903f8732f..c75306a959 100644
--- a/tools/start-stop-daemon.c
+++ b/tools/start-stop-daemon.c
@@ -401,7 +401,7 @@ static void parse_schedule_item(const char *string, struct schedule_item *item)
if (!strcmp(string, "forever")) {
item->type = sched_forever;
- } else if (isdigit((int)string[0])) {
+ } else if (isdigit((unsigned char)string[0])) {
item->type = sched_timeout;
if (parse_integer(string, &item->value) != 0)
badusage("invalid timeout value in schedule");
diff --git a/vrrpd/vrrp.c b/vrrpd/vrrp.c
index 5213b27d32..951ad3f58f 100644
--- a/vrrpd/vrrp.c
+++ b/vrrpd/vrrp.c
@@ -196,9 +196,20 @@ static struct vrrp_vrouter *vrrp_lookup_by_if_mvl(struct interface *mvl_ifp)
{
struct interface *p;
- if (!mvl_ifp || !mvl_ifp->link_ifindex
- || !vrrp_ifp_has_vrrp_mac(mvl_ifp))
+ if (!mvl_ifp || mvl_ifp->link_ifindex == 0
+ || !vrrp_ifp_has_vrrp_mac(mvl_ifp)) {
+ if (mvl_ifp && mvl_ifp->link_ifindex == 0)
+ DEBUGD(&vrrp_dbg_zebra,
+ VRRP_LOGPFX
+ "Interface %s has no parent ifindex; disregarding",
+ mvl_ifp->name);
+ if (mvl_ifp && !vrrp_ifp_has_vrrp_mac(mvl_ifp))
+ DEBUGD(&vrrp_dbg_zebra,
+ VRRP_LOGPFX
+ "Interface %s has a non-VRRP MAC; disregarding",
+ mvl_ifp->name);
return NULL;
+ }
p = if_lookup_by_index(mvl_ifp->link_ifindex, VRF_DEFAULT);
uint8_t vrid = mvl_ifp->hw_addr[5];
@@ -2028,9 +2039,19 @@ static void vrrp_bind_pending(struct interface *mvl_ifp)
{
struct vrrp_vrouter *vr;
+ DEBUGD(&vrrp_dbg_zebra,
+ VRRP_LOGPFX
+ "Searching for instances that could use interface %s",
+ mvl_ifp->name);
+
vr = vrrp_lookup_by_if_mvl(mvl_ifp);
if (vr) {
+ DEBUGD(&vrrp_dbg_zebra,
+ VRRP_LOGPFX VRRP_LOGPFX_VRID
+ "<-- This instance can probably use interface %s",
+ vr->vrid, mvl_ifp->name);
+
if (mvl_ifp->hw_addr[4] == 0x01 && !vr->v4->mvl_ifp)
vrrp_attach_interface(vr->v4);
else if (mvl_ifp->hw_addr[4] == 0x02 && !vr->v6->mvl_ifp)
@@ -2112,9 +2133,13 @@ void vrrp_if_down(struct interface *ifp)
struct listnode *ln;
struct list *vrs;
+ vrrp_bind_pending(ifp);
+
vrs = vrrp_lookup_by_if_any(ifp);
for (ALL_LIST_ELEMENTS_RO(vrs, ln, vr)) {
+ vrrp_check_start(vr);
+
if (vr->ifp == ifp || vr->v4->mvl_ifp == ifp
|| vr->v6->mvl_ifp == ifp) {
DEBUGD(&vrrp_dbg_auto,
diff --git a/vrrpd/vrrp_zebra.c b/vrrpd/vrrp_zebra.c
index c15c250bdf..72b77c1313 100644
--- a/vrrpd/vrrp_zebra.c
+++ b/vrrpd/vrrp_zebra.c
@@ -38,9 +38,11 @@ static void vrrp_zebra_debug_if_state(struct interface *ifp, vrf_id_t vrf_id,
const char *func)
{
DEBUGD(&vrrp_dbg_zebra,
- "%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d",
- func, ifp->name, ifp->ifindex, vrf_id, (long)ifp->flags,
- ifp->metric, ifp->mtu, if_is_operative(ifp));
+ "%s: %s index %d(%u) parent %d mac %02x:%02x:%02x:%02x:%02x:%02x flags %ld metric %d mtu %d operative %d",
+ func, ifp->name, vrf_id, ifp->link_ifindex, ifp->ifindex,
+ ifp->hw_addr[0], ifp->hw_addr[1], ifp->hw_addr[2],
+ ifp->hw_addr[3], ifp->hw_addr[4], ifp->hw_addr[5],
+ (long)ifp->flags, ifp->metric, ifp->mtu, if_is_operative(ifp));
}
static void vrrp_zebra_debug_if_dump_address(struct interface *ifp,
@@ -113,6 +115,8 @@ static int vrrp_zebra_if_del(int command, struct zclient *zclient,
vrrp_if_del(ifp);
+ if_set_index(ifp, IFINDEX_INTERNAL);
+
return 0;
}
@@ -208,8 +212,6 @@ static int vrrp_zebra_if_address_del(int command, struct zclient *client,
vrrp_if_address_del(c->ifp);
- if_set_index(c->ifp, IFINDEX_INTERNAL);
-
return 0;
}
diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in
index 4dc34d10ef..d0b0c701a7 100755
--- a/vtysh/extract.pl.in
+++ b/vtysh/extract.pl.in
@@ -96,18 +96,12 @@ sub scan_file {
elsif ($file =~ /lib\/if\.c$/) {
$protocol = "VTYSH_INTERFACE";
}
- elsif ($file =~ /lib\/logicalrouter\.c$/) {
- $protocol = "VTYSH_ALL";
- }
elsif ($file =~ /lib\/filter\.c$/) {
$protocol = "VTYSH_ALL";
}
elsif ($file =~ /lib\/agentx\.c$/) {
$protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA";
}
- elsif ($file =~ /lib\/ns\.c$/) {
- $protocol = "VTYSH_ZEBRA";
- }
elsif ($file =~ /lib\/nexthop_group\.c$/) {
$protocol = "VTYSH_PBRD | VTYSH_SHARPD";
}
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index 053848bfc3..fba754f626 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -46,6 +46,7 @@
#include "command_graph.h"
#include "frrstr.h"
#include "json.h"
+#include "ferr.h"
DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CMD, "Vtysh cmd copy")
@@ -667,11 +668,11 @@ static char *trim(char *s)
return s;
end = s + size - 1;
- while (end >= s && isspace((int)*end))
+ while (end >= s && isspace((unsigned char)*end))
end--;
*(end + 1) = '\0';
- while (*s && isspace((int)*s))
+ while (*s && isspace((unsigned char)*s))
s++;
return s;
@@ -851,11 +852,15 @@ int vtysh_mark_file(const char *filename)
return CMD_ERR_INCOMPLETE;
case CMD_SUCCESS:
vty_out(vty, "%s", vty->buf);
+ if (strmatch(vty_buf_trimmed, "exit-vrf"))
+ vty_out(vty, "end\n");
break;
case CMD_SUCCESS_DAEMON: {
int cmd_stat;
vty_out(vty, "%s", vty->buf);
+ if (strmatch(vty_buf_trimmed, "exit-vrf"))
+ vty_out(vty, "end\n");
cmd_stat = vtysh_client_execute(&vtysh_client[0],
vty->buf);
if (cmd_stat != CMD_SUCCESS)
@@ -978,7 +983,7 @@ static int vtysh_process_questionmark(const char *input, int input_len)
if (vline == NULL) {
vline = vector_init(1);
vector_set(vline, NULL);
- } else if (input_len && isspace((int)input[input_len - 1]))
+ } else if (input_len && isspace((unsigned char)input[input_len - 1]))
vector_set(vline, NULL);
describe = cmd_describe_command(vline, vty, &ret);
@@ -1126,7 +1131,8 @@ static char *command_generator(const char *text, int state)
if (vline == NULL)
return NULL;
- if (rl_end && isspace((int)rl_line_buffer[rl_end - 1]))
+ if (rl_end &&
+ isspace((unsigned char)rl_line_buffer[rl_end - 1]))
vector_set(vline, NULL);
matched = cmd_complete_command(vline, vty, &complete_status);
@@ -1187,10 +1193,6 @@ static struct cmd_node pw_node = {
PW_NODE, "%s(config-pw)# ",
};
-static struct cmd_node logicalrouter_node = {
- LOGICALROUTER_NODE, "%s(config-logical-router)# ",
-};
-
static struct cmd_node vrf_node = {
VRF_NODE, "%s(config-vrf)# ",
};
@@ -1797,7 +1799,6 @@ static int vtysh_exit(struct vty *vty)
break;
case INTERFACE_NODE:
case PW_NODE:
- case LOGICALROUTER_NODE:
case VRF_NODE:
case NH_GROUP_NODE:
case ZEBRA_NODE:
@@ -1927,7 +1928,7 @@ DEFUNSH(VTYSH_BGPD, rpki_quit, rpki_quit_cmd, "quit",
return rpki_exit(self, vty, argc, argv);
}
-DEFUNSH(VTYSH_PIMD|VTYSH_ZEBRA, exit_vrf_config, exit_vrf_config_cmd, "exit-vrf",
+DEFUNSH(VTYSH_VRF, exit_vrf_config, exit_vrf_config_cmd, "exit-vrf",
"Exit from VRF configuration mode\n")
{
if (vty->node == VRF_NODE)
@@ -2127,24 +2128,6 @@ DEFUNSH(VTYSH_ZEBRA, vtysh_pseudowire, vtysh_pseudowire_cmd,
return CMD_SUCCESS;
}
-DEFUNSH(VTYSH_ZEBRA, vtysh_logicalrouter, vtysh_logicalrouter_cmd,
- "logical-router (1-65535) ns NAME",
- "Enable a logical-router\n"
- "Specify the logical-router indentifier\n"
- "The Name Space\n"
- "The file name in " NS_RUN_DIR ", or a full pathname\n")
-{
- vty->node = LOGICALROUTER_NODE;
- return CMD_SUCCESS;
-}
-
-DEFSH(VTYSH_ZEBRA, vtysh_no_logicalrouter_cmd,
- "no logical-router (1-65535) ns NAME", NO_STR
- "Enable a Logical-Router\n"
- "Specify the Logical-Router identifier\n"
- "The Name Space\n"
- "The file name in " NS_RUN_DIR ", or a full pathname\n")
-
DEFUNSH(VTYSH_PBRD | VTYSH_SHARPD, vtysh_nexthop_group, vtysh_nexthop_group_cmd,
"nexthop-group NHGNAME",
"Nexthop Group configuration\n"
@@ -2179,20 +2162,6 @@ DEFSH(VTYSH_ZEBRA, vtysh_no_vrf_netns_cmd,
"Detach VRF from a Namespace\n"
"The file name in " NS_RUN_DIR ", or a full pathname\n")
-DEFUNSH(VTYSH_NS, vtysh_exit_logicalrouter,
- vtysh_exit_logicalrouter_cmd, "exit",
- "Exit current mode and down to previous mode\n")
-{
- return vtysh_exit(vty);
-}
-
-DEFUNSH(VTYSH_NS, vtysh_quit_logicalrouter,
- vtysh_quit_logicalrouter_cmd, "quit",
- "Exit current mode and down to previous mode\n")
-{
- return vtysh_exit_logicalrouter(self, vty, argc, argv);
-}
-
DEFUNSH(VTYSH_VRF, vtysh_exit_vrf, vtysh_exit_vrf_cmd, "exit",
"Exit current mode and down to previous mode\n")
{
@@ -2211,7 +2180,7 @@ DEFUNSH(VTYSH_PBRD | VTYSH_SHARPD, vtysh_exit_nexthop_group, vtysh_exit_nexthop_
return vtysh_exit(vty);
}
-DEFUNSH(VTYSH_VRF, vtysh_quit_nexthop_group, vtysh_quit_nexthop_group_cmd,
+DEFUNSH(VTYSH_PBRD | VTYSH_SHARPD, vtysh_quit_nexthop_group, vtysh_quit_nexthop_group_cmd,
"quit", "Exit current mode and down to previous mode\n")
{
return vtysh_exit_nexthop_group(self, vty, argc, argv);
@@ -2394,17 +2363,30 @@ DEFUN (vtysh_show_error_code,
"Information on all errors\n"
JSON_STR)
{
- char *fcmd = argv_concat(argv, argc, 0);
- char cmd[256];
- int rv;
+ uint32_t arg = 0;
+
+ if (!strmatch(argv[2]->text, "all"))
+ arg = strtoul(argv[2]->arg, NULL, 10);
- snprintf(cmd, sizeof(cmd), "do %s", fcmd);
+ /* If it's not a shared code, send it to all the daemons */
+ if (arg < LIB_FERR_START || arg > LIB_FERR_END) {
+ char *fcmd = argv_concat(argv, argc, 0);
+ char cmd[256];
- /* FIXME: Needs to determine which daemon to send to via code ranges */
- rv = show_per_daemon(cmd, "");
+ snprintf(cmd, sizeof(cmd), "do %s", fcmd);
+ show_per_daemon(cmd, "");
+ XFREE(MTYPE_TMP, fcmd);
+ /* Otherwise, print it ourselves to avoid duplication */
+ } else {
+ bool json = strmatch(argv[argc - 1]->text, "json");
- XFREE(MTYPE_TMP, fcmd);
- return rv;
+ if (!strmatch(argv[2]->text, "all"))
+ arg = strtoul(argv[2]->arg, NULL, 10);
+
+ log_ref_display(vty, arg, json);
+ }
+
+ return CMD_SUCCESS;
}
/* Memory */
@@ -3595,7 +3577,6 @@ void vtysh_init_vty(void)
install_node(&interface_node, NULL);
install_node(&pw_node, NULL);
install_node(&link_params_node, NULL);
- install_node(&logicalrouter_node, NULL);
install_node(&vrf_node, NULL);
install_node(&nh_group_node, NULL);
install_node(&rmap_node, NULL);
@@ -3805,13 +3786,6 @@ void vtysh_init_vty(void)
install_element(PW_NODE, &vtysh_exit_interface_cmd);
install_element(PW_NODE, &vtysh_quit_interface_cmd);
- install_element(LOGICALROUTER_NODE, &vtysh_end_all_cmd);
-
- install_element(CONFIG_NODE, &vtysh_logicalrouter_cmd);
- install_element(CONFIG_NODE, &vtysh_no_logicalrouter_cmd);
- install_element(LOGICALROUTER_NODE, &vtysh_exit_logicalrouter_cmd);
- install_element(LOGICALROUTER_NODE, &vtysh_quit_logicalrouter_cmd);
-
install_element(CONFIG_NODE, &vtysh_nexthop_group_cmd);
install_element(NH_GROUP_NODE, &vtysh_end_all_cmd);
install_element(NH_GROUP_NODE, &vtysh_exit_nexthop_group_cmd);
diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h
index 3b0b570a56..b16761b41a 100644
--- a/vtysh/vtysh.h
+++ b/vtysh/vtysh.h
@@ -54,7 +54,6 @@ DECLARE_MGROUP(MVTYSH)
#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_SHARPD|VTYSH_PBRD|VTYSH_STATICD|VTYSH_BFDD|VTYSH_FABRICD|VTYSH_VRRPD
#define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_SHARPD|VTYSH_FABRICD
#define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_PBRD|VTYSH_FABRICD|VTYSH_VRRPD
-#define VTYSH_NS VTYSH_ZEBRA
#define VTYSH_VRF VTYSH_ZEBRA|VTYSH_PIMD|VTYSH_STATICD
#define VTYSH_KEYS VTYSH_RIPD|VTYSH_EIGRPD
diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c
index 1e45e6f972..3ec2eb239d 100644
--- a/vtysh/vtysh_config.c
+++ b/vtysh/vtysh_config.c
@@ -23,6 +23,7 @@
#include "command.h"
#include "linklist.h"
#include "memory.h"
+#include "typesafe.h"
#include "vtysh/vtysh.h"
#include "vtysh/vtysh_user.h"
@@ -33,6 +34,8 @@ DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG_LINE, "Vtysh configuration line")
vector configvec;
+PREDECL_RBTREE_UNIQ(config_master);
+
struct config {
/* Configuration node name. */
char *name;
@@ -45,6 +48,9 @@ struct config {
/* Index of this config. */
uint32_t index;
+
+ /* Node entry for the typed Red-black tree */
+ struct config_master_item rbt_item;
};
struct list *config_top;
@@ -66,7 +72,7 @@ static struct config *config_new(void)
return config;
}
-static int config_cmp(struct config *c1, struct config *c2)
+static int config_cmp(const struct config *c1, const struct config *c2)
{
return strcmp(c1->name, c2->name);
}
@@ -78,28 +84,23 @@ static void config_del(struct config *config)
XFREE(MTYPE_VTYSH_CONFIG, config);
}
+DECLARE_RBTREE_UNIQ(config_master, struct config, rbt_item, config_cmp)
+
static struct config *config_get(int index, const char *line)
{
struct config *config;
- struct config *config_loop;
- struct list *master;
- struct listnode *node, *nnode;
-
- config = config_loop = NULL;
+ struct config_master_head *master;
master = vector_lookup_ensure(configvec, index);
if (!master) {
- master = list_new();
- master->del = (void (*)(void *))config_del;
- master->cmp = (int (*)(void *, void *))config_cmp;
+ master = XMALLOC(MTYPE_VTYSH_CONFIG, sizeof(struct config_master_head));
+ config_master_init(master);
vector_set_index(configvec, index, master);
}
- for (ALL_LIST_ELEMENTS(master, node, nnode, config_loop)) {
- if (strcmp(config_loop->name, line) == 0)
- config = config_loop;
- }
+ const struct config config_ref = { .name = (char *)line };
+ config = config_master_find(master, &config_ref);
if (!config) {
config = config_new();
@@ -108,7 +109,7 @@ static struct config *config_get(int index, const char *line)
config->line->cmp = (int (*)(void *, void *))line_cmp;
config->name = XSTRDUP(MTYPE_VTYSH_CONFIG_LINE, line);
config->index = index;
- listnode_add(master, config);
+ config_master_add(master, config);
}
return config;
}
@@ -263,7 +264,6 @@ void vtysh_config_parse_line(void *arg, const char *line)
config_add_line(config->line, line);
} else if (config->index == RMAP_NODE
|| config->index == INTERFACE_NODE
- || config->index == LOGICALROUTER_NODE
|| config->index == VTY_NODE
|| config->index == VRF_NODE
|| config->index == NH_GROUP_NODE)
@@ -278,8 +278,6 @@ void vtysh_config_parse_line(void *arg, const char *line)
config = config_get(INTERFACE_NODE, line);
else if (strncmp(line, "pseudowire", strlen("pseudowire")) == 0)
config = config_get(PW_NODE, line);
- else if (strncmp(line, "logical-router", strlen("logical-router")) == 0)
- config = config_get(LOGICALROUTER_NODE, line);
else if (strncmp(line, "vrf", strlen("vrf")) == 0)
config = config_get(VRF_NODE, line);
else if (strncmp(line, "nexthop-group", strlen("nexthop-group"))
@@ -435,7 +433,7 @@ void vtysh_config_dump(void)
struct listnode *node, *nnode;
struct listnode *mnode, *mnnode;
struct config *config;
- struct list *master;
+ struct config_master_head *master;
char *line;
unsigned int i;
@@ -446,7 +444,7 @@ void vtysh_config_dump(void)
for (i = 0; i < vector_active(configvec); i++)
if ((master = vector_slot(configvec, i)) != NULL) {
- for (ALL_LIST_ELEMENTS(master, node, nnode, config)) {
+ while ((config = config_master_pop(master))) {
/* Don't print empty sections for interface.
* Route maps on the
* other hand could have a legitimate empty
@@ -466,6 +464,8 @@ void vtysh_config_dump(void)
vty_out(vty, "%s\n", line);
if (!NO_DELIMITER(i))
vty_out(vty, "!\n");
+
+ config_del(config);
}
if (NO_DELIMITER(i))
vty_out(vty, "!\n");
@@ -473,7 +473,8 @@ void vtysh_config_dump(void)
for (i = 0; i < vector_active(configvec); i++)
if ((master = vector_slot(configvec, i)) != NULL) {
- list_delete(&master);
+ config_master_fini(master);
+ XFREE(MTYPE_VTYSH_CONFIG, master);
vector_slot(configvec, i) = NULL;
}
list_delete_all_node(config_top);
diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c
index 9667460189..d536263db0 100644
--- a/vtysh/vtysh_main.c
+++ b/vtysh/vtysh_main.c
@@ -47,6 +47,8 @@
#include "linklist.h"
#include "memory_vty.h"
#include "libfrr.h"
+#include "ferr.h"
+#include "lib_errors.h"
#include "vtysh/vtysh.h"
#include "vtysh/vtysh_user.h"
@@ -461,6 +463,9 @@ int main(int argc, char **argv, char **env)
vtysh_read_config(vtysh_config);
suid_off();
}
+ /* Error code library system */
+ log_ref_init();
+ lib_error_init();
if (markfile) {
if (!inputfile) {
diff --git a/yang/frr-bfdd.yang b/yang/frr-bfdd.yang
index 24ca8f68a8..f9ac2e43b0 100644
--- a/yang/frr-bfdd.yang
+++ b/yang/frr-bfdd.yang
@@ -264,22 +264,22 @@ module frr-bfdd {
leaf session-down-count {
type uint32;
- description "Amount of times the session went down";
+ description "Number of times the session went down";
}
leaf session-up-count {
type uint32;
- description "Amount of times the session went up";
+ description "Number of times the session went up";
}
leaf control-packet-input-count {
type uint64;
- description "Amount of control packets received";
+ description "Number of control packets received";
}
leaf control-packet-output-count {
type uint64;
- description "Amount of control packets sent";
+ description "Number of control packets sent";
}
/*
@@ -296,12 +296,12 @@ module frr-bfdd {
*/
leaf echo-packet-input-count {
type uint64;
- description "Amount of echo packets received";
+ description "Number of echo packets received";
}
leaf echo-packet-output-count {
type uint64;
- description "Amount of echo packets sent";
+ description "Number of echo packets sent";
}
}
diff --git a/yang/frr-eigrpd.yang b/yang/frr-eigrpd.yang
index 26de7a71ae..853d823880 100644
--- a/yang/frr-eigrpd.yang
+++ b/yang/frr-eigrpd.yang
@@ -57,7 +57,7 @@ module frr-eigrpd {
value 2;
}
- enum hmac-sha2 {
+ enum hmac-sha-256 {
description "HMAC SHA256 algorithm";
value 3;
}
diff --git a/yang/frr-filter.yang b/yang/frr-filter.yang
new file mode 100644
index 0000000000..e79ede87b7
--- /dev/null
+++ b/yang/frr-filter.yang
@@ -0,0 +1,353 @@
+module frr-filter {
+ yang-version 1.1;
+ namespace "http://frrouting.org/yang/filter";
+ prefix frr-filter;
+
+ import ietf-inet-types {
+ prefix inet;
+ }
+ import ietf-yang-types {
+ prefix yang;
+ }
+
+ 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 filter settings";
+
+ revision 2019-07-04 {
+ description "Initial revision";
+ }
+
+ /*
+ * Types.
+ */
+ typedef access-list-standard {
+ description "Standard IPv4 access list (any, host or a prefix)";
+ type uint16 {
+ range "1..99 | 1300..1999";
+ }
+ }
+
+ typedef access-list-extended {
+ description
+ "Extended IPv4 access list (source / destination any, hosts or prefixes)";
+ type uint16 {
+ range "100..199 | 2000..2699";
+ }
+ }
+
+ typedef access-list-legacy {
+ description "Standard/Extended IPv4 access list";
+ type uint16 {
+ range "1..199 | 1300..2699";
+ }
+ }
+
+ typedef access-list-name {
+ description "Access list name formatting";
+ type string;
+ }
+
+ typedef access-list-sequence {
+ description "Access list sequence number";
+ type uint32 {
+ range "1..4294967295";
+ }
+ }
+
+ typedef access-list-action {
+ description "Access list return action on match";
+ type enumeration {
+ enum deny {
+ description "Deny an entry";
+ value 0;
+ }
+ enum permit {
+ description "Accept an entry";
+ value 1;
+ }
+ }
+ }
+
+ /*
+ * Configuration data.
+ */
+ container filter-list {
+ list access-list-legacy {
+ description "Access list legacy instance";
+
+ key "number sequence";
+
+ leaf number {
+ description "Access list sequence value";
+ type access-list-legacy;
+ }
+
+ leaf sequence {
+ description "Access list sequence value";
+ type access-list-sequence;
+ }
+
+ leaf action {
+ description "Access list action on match";
+ type access-list-action;
+ mandatory true;
+ }
+
+ leaf remark {
+ description "Access list remark";
+ type string;
+ }
+
+ choice value {
+ description
+ "Standard access list: value to match.
+ Extended access list: source value to match.";
+ mandatory true;
+
+ leaf host {
+ description "Host to match";
+ type inet:ipv4-address;
+ }
+ leaf network {
+ description "Network to match";
+ type inet:ipv4-prefix;
+ }
+ leaf any {
+ description "Match any";
+ type empty;
+ }
+ }
+
+ choice extended-value {
+ when "./sequence >= 100 and ./sequence <= 199 or
+ ./sequence >= 2000 and ./sequence <= 2699";
+ description "Destination value to match";
+
+ leaf destination-host {
+ description "Host to match";
+ type inet:ipv4-address;
+ }
+ leaf destination-network {
+ description "Network to match";
+ type inet:ipv4-prefix;
+ }
+ leaf destination-any {
+ description "Match any";
+ type empty;
+ }
+ }
+ }
+
+ list access-list {
+ description "Access list instance";
+
+ key "type identifier sequence";
+
+ leaf type {
+ description "Access list content type";
+ type enumeration {
+ enum ipv4 {
+ description "Internet Protocol address version 4";
+ value 0;
+ }
+ enum ipv6 {
+ description "Internet Protocol address version 6";
+ value 1;
+ }
+ enum mac {
+ description "Media Access Control address";
+ value 2;
+ }
+
+ /*
+ * Protocol YANG models should augment the parent node to
+ * contain the routing protocol specific value. The protocol
+ * must also augment `value` leaf to include its specific
+ * values or expand the `when` statement on the existing cases.
+ */
+ enum custom {
+ description "Custom data type";
+ value 100;
+ }
+ }
+ }
+
+ leaf identifier {
+ description "Access list identifier";
+ type access-list-name;
+ }
+
+ leaf sequence {
+ description "Access list sequence value";
+ type access-list-sequence;
+ }
+
+ leaf action {
+ description "Access list action on match";
+ type access-list-action;
+ mandatory true;
+ }
+
+ leaf remark {
+ description "Access list remark";
+ type string;
+ }
+
+ choice value {
+ description "Access list value to match";
+ mandatory true;
+
+ case ipv4-prefix {
+ when "./type = 'ipv4'";
+
+ leaf ipv4-prefix {
+ description "Configure IPv4 prefix to match";
+ type inet:ipv4-prefix;
+ }
+
+ leaf ipv4-exact-match {
+ description "Exact match of prefix";
+ type boolean;
+ default false;
+ }
+ }
+ case ipv6-prefix {
+ when "./type = 'ipv6'";
+
+ leaf ipv6-prefix {
+ description "Configure IPv6 prefix to match";
+ type inet:ipv6-prefix;
+ }
+
+ leaf ipv6-exact-match {
+ description "Exact match of prefix";
+ type boolean;
+ default false;
+ }
+ }
+ case mac {
+ when "./type = 'mac'";
+
+ leaf mac {
+ description "Configure MAC address to match";
+ type yang:mac-address;
+ }
+ }
+ case any {
+ leaf any {
+ description "Match anything";
+ type empty;
+ }
+ }
+ }
+ }
+
+ list prefix-list {
+ description "Prefix list instance";
+
+ key "type name sequence";
+
+ leaf type {
+ description "Prefix list type";
+ type enumeration {
+ enum ipv4 {
+ description "Internet Protocol address version 4";
+ value 0;
+ }
+ enum ipv6 {
+ description "Internet Protocol address version 6";
+ value 1;
+ }
+ }
+ }
+
+ leaf name {
+ description "Prefix list name";
+ type access-list-name;
+ }
+
+ leaf sequence {
+ description "Access list sequence value";
+ type access-list-sequence;
+ }
+
+ leaf action {
+ description "Prefix list action on match";
+ type access-list-action;
+ mandatory true;
+ }
+
+ leaf description {
+ description "Prefix list user description";
+ type string;
+ }
+
+ choice value {
+ description "Prefix list value to match";
+ mandatory true;
+
+ case ipv4-prefix {
+ when "./type = 'ipv4'";
+
+ leaf ipv4-prefix {
+ description "Configure IPv4 prefix to match";
+ type inet:ipv4-prefix;
+ }
+
+ leaf ipv4-prefix-length-greater-or-equal {
+ description
+ "Specifies if matching prefixes with length greater than
+ or equal to value";
+ type uint8 {
+ range "0..32";
+ }
+ }
+
+ leaf ipv4-prefix-length-lesser-or-equal {
+ description
+ "Specifies if matching prefixes with length lesser than
+ or equal to value";
+ type uint8 {
+ range "0..32";
+ }
+ }
+ }
+ case ipv6-prefix {
+ when "./type = 'ipv6'";
+
+ leaf ipv6-prefix {
+ description "Configure IPv6 prefix to match";
+ type inet:ipv6-prefix;
+ }
+
+ leaf ipv6-prefix-length-greater-or-equal {
+ description
+ "Specifies if matching prefixes with length greater than
+ or equal to value";
+ type uint8 {
+ range "0..128";
+ }
+ }
+
+ leaf ipv6-prefix-length-lesser-or-equal {
+ description
+ "Specifies if matching prefixes with length lesser than
+ or equal to value";
+ type uint8 {
+ range "0..128";
+ }
+ }
+ }
+ case any {
+ leaf any {
+ description "Match anything";
+ type empty;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang
index 05a896a1db..9180b0c5f3 100644
--- a/yang/frr-isisd.yang
+++ b/yang/frr-isisd.yang
@@ -1024,7 +1024,7 @@ module frr-isisd {
"This notification is sent when we attempt to propagate
an LSP that is larger than the dataLinkBlockSize for the
circuit. The notification generation must be throttled
- with at least 5 seconds betweeen successive
+ with at least 5 seconds between successive
notifications.";
uses notification-instance-hdr;
@@ -1090,7 +1090,7 @@ module frr-isisd {
"This notification is sent when we receive a PDU
with a different value for the System ID length.
The notification generation must be throttled
- with at least 5 seconds betweeen successive
+ with at least 5 seconds between successive
notifications.";
uses notification-instance-hdr;
@@ -1114,7 +1114,7 @@ module frr-isisd {
"This notification is sent when we receive a PDU
with a different value for the Maximum Area Addresses.
The notification generation must be throttled
- with at least 5 seconds betweeen successive
+ with at least 5 seconds between successive
notifications.";
uses notification-instance-hdr;
@@ -1170,7 +1170,7 @@ module frr-isisd {
"This notification is sent when the system receives a
PDU with the wrong authentication type field.
The notification generation must be throttled
- with at least 5 seconds betweeen successive
+ with at least 5 seconds between successive
notifications.";
uses notification-instance-hdr;
@@ -1188,7 +1188,7 @@ module frr-isisd {
"This notification is sent when the system receives
a PDU with the wrong authentication information.
The notification generation must be throttled with
- with at least 5 seconds betweeen successive
+ with at least 5 seconds between successive
notifications.";
uses notification-instance-hdr;
@@ -1206,7 +1206,7 @@ module frr-isisd {
"This notification is sent when the system receives a
PDU with a different protocol version number.
The notification generation must be throttled
- with at least 5 seconds betweeen successive
+ with at least 5 seconds between successive
notifications.";
uses notification-instance-hdr;
@@ -1230,7 +1230,7 @@ module frr-isisd {
"This notification is sent when the system receives a
Hello PDU from an IS that does not share any area
address. The notification generation must be throttled
- with at least 5 seconds betweeen successive
+ with at least 5 seconds between successive
notifications.";
uses notification-instance-hdr;
@@ -1248,7 +1248,7 @@ module frr-isisd {
"This notification is sent when the system receives a
Hello PDU from an IS but does not establish an adjacency
for some reason. The notification generation must be
- throttled with at least 5 seconds betweeen successive
+ throttled with at least 5 seconds between successive
notifications.";
uses notification-instance-hdr;
@@ -1273,7 +1273,7 @@ module frr-isisd {
description
"This notification is sent when the system receives an
LSP with a parse error. The notification generation must
- be throttled with at least 5 seconds betweeen successive
+ be throttled with at least 5 seconds between successive
notifications.";
uses notification-instance-hdr;
@@ -1350,7 +1350,7 @@ module frr-isisd {
description
"This notification is sent when an LSP is received.
The notification generation must be throttled with at
- least 5 seconds betweeen successive notifications.";
+ least 5 seconds between successive notifications.";
uses notification-instance-hdr;
uses notification-interface-hdr;
@@ -1384,7 +1384,7 @@ module frr-isisd {
description
"This notification is sent when an LSP is regenerated.
The notification generation must be throttled with at
- least 5 seconds betweeen successive notifications.";
+ least 5 seconds between successive notifications.";
uses notification-instance-hdr;
leaf lsp-id {
diff --git a/yang/frr-route-map.yang b/yang/frr-route-map.yang
new file mode 100644
index 0000000000..0ce40b474b
--- /dev/null
+++ b/yang/frr-route-map.yang
@@ -0,0 +1,404 @@
+module frr-route-map {
+ yang-version 1.1;
+ namespace "http://frrouting.org/yang/route-map";
+ prefix frr-route-map;
+
+ import ietf-inet-types {
+ prefix inet;
+ }
+ import frr-filter {
+ prefix filter;
+ }
+
+ 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 route map settings";
+
+ revision 2019-07-01 {
+ description "Initial revision";
+ }
+
+ /*
+ * Types.
+ */
+ typedef route-map-sequence {
+ description "Route map valid sequence numbers";
+ type uint16 {
+ range "1..65535";
+ }
+ }
+
+ typedef route-map-name {
+ description "Route map name format";
+ type string;
+ }
+
+ /*
+ * Operational data.
+ */
+ container route-map {
+ list instance {
+ description "Route map instance";
+
+ key "name sequence";
+
+ leaf name {
+ description "Route map instance name";
+ type route-map-name;
+ }
+
+ leaf sequence {
+ description
+ "Route map instance priority (low number means higher priority)";
+ type route-map-sequence;
+ }
+
+ leaf description {
+ description "Route map description";
+ type string;
+ }
+
+ leaf action {
+ description
+ "Route map actions: permit (executes action), deny (quits evaluation)";
+ mandatory true;
+ type enumeration {
+ enum permit {
+ description
+ "Executes configured action and permits the prefix/route
+ if the conditions matched. An alternative exit action can
+ be configured to continue processing the route map list
+ or jump to process another route map.";
+ value 0;
+ }
+ enum deny {
+ description
+ "If all conditions are met the prefix/route is denied and
+ route map processing stops.";
+ value 1;
+ }
+ }
+ }
+
+ list match-condition {
+ description "Route map match conditions";
+
+ key "condition";
+
+ leaf condition {
+ description "Match condition";
+ type enumeration {
+ enum interface {
+ description "Match interface";
+ value 0;
+ }
+ enum ipv4-address-list {
+ description "Match an IPv4 access-list";
+ value 1;
+ }
+ enum ipv4-prefix-list {
+ description "Match an IPv4 prefix-list";
+ value 2;
+ }
+ enum ipv4-prefix-length {
+ description "Match an IPv4 prefix length";
+ value 3;
+ }
+ enum ipv4-next-hop-list {
+ description "Match an IPv4 next-hop";
+ value 4;
+ }
+ enum ipv4-next-hop-prefix-list {
+ description "Match an IPv4 next-hop prefix list";
+ value 5;
+ }
+ enum ipv4-next-hop-prefix-length {
+ description "Match an IPv4 next-hop prefix length";
+ value 6;
+ }
+ enum ipv4-next-hop-type {
+ description "Match an IPv4 next-hop type";
+ value 7;
+ }
+ enum ipv6-address-list {
+ description "Match an IPv6 access-list";
+ value 8;
+ }
+ enum ipv6-prefix-list {
+ description "Match an IPv6 prefix-list";
+ value 9;
+ }
+ enum ipv6-prefix-length {
+ description "Match an IPv6 prefix length";
+ value 10;
+ }
+ enum ipv6-next-hop {
+ description "Match an IPv6 next-hop";
+ value 11;
+ }
+ enum ipv6-next-hop-type {
+ description "Match an IPv6 next-hop type";
+ value 12;
+ }
+ enum metric {
+ description "Match a route metric";
+ value 13;
+ }
+ enum tag {
+ description "Match a route tag";
+ value 14;
+ }
+
+ /*
+ * Protocol YANG models should augment the parent node to
+ * contain the routing protocol specific value. The protocol
+ * must also augment `condition-value` to include its specific
+ * values or expand the `when` statement on the existing cases.
+ */
+ enum routing-protocol-specific {
+ description "Match a routing protocol specific type";
+ value 100;
+ }
+ }
+ }
+
+ choice condition-value {
+ description
+ "Value to match (interpretation depends on condition type)";
+ case access-list-num {
+ when "./condition = 'ipv4-address-list' or
+ ./condition = 'ipv4-next-hop-list'";
+ leaf access-list-num {
+ type filter:access-list-standard;
+ }
+ }
+ case access-list-num-extended {
+ when "./condition = 'ipv4-address-list' or
+ ./condition = 'ipv4-next-hop-list'";
+ leaf access-list-num-extended {
+ type filter:access-list-extended;
+ }
+ }
+ case list-name {
+ when "./condition = 'ipv4-address-list' or
+ ./condition = 'ipv4-prefix-list' or
+ ./condition = 'ipv4-next-hop-list' or
+ ./condition = 'ipv4-next-hop-prefix-list' or
+ ./condition = 'ipv6-address-list' or
+ ./condition = 'ipv6-prefix-list'";
+ leaf list-name {
+ type filter:access-list-name;
+ }
+ }
+ case ipv6-address {
+ when "./condition = 'ipv6-next-hop'";
+ leaf ipv6-address {
+ type inet:ipv6-address;
+ }
+ }
+ case ipv4-prefix-length {
+ when "./condition = 'ipv4-prefix-length' or
+ ./condition = 'ipv4-next-hop-prefix-length'";
+ leaf ipv4-prefix-length {
+ type uint8 {
+ range "0..32";
+ }
+ }
+ }
+ case ipv6-prefix-length {
+ when "./condition = 'ipv6-prefix-length'";
+ leaf ipv6-prefix-length {
+ type uint8 {
+ range "0..128";
+ }
+ }
+ }
+ case ipv4-next-hop-type {
+ when "./condition = 'ipv4-next-hop-type'";
+ leaf ipv4-next-hop-type {
+ type enumeration {
+ enum blackhole {
+ value 0;
+ }
+ }
+ }
+ }
+ case ipv6-next-hop-type {
+ when "./condition = 'ipv6-next-hop-type'";
+ leaf ipv6-next-hop-type {
+ type enumeration {
+ enum blackhole {
+ value 0;
+ }
+ }
+ }
+ }
+ case metric {
+ when "./condition = 'metric'";
+ leaf metric {
+ type uint32 {
+ range "1..4294967295";
+ }
+ }
+ }
+ case tag {
+ when "./condition = 'tag'";
+ leaf tag {
+ type uint32 {
+ range "1..4294967295";
+ }
+ }
+ }
+ }
+ }
+
+ list set-action {
+ description "Route map set actions";
+
+ key "action";
+
+ leaf action {
+ description "Action to do when the route map matches";
+ type enumeration {
+ enum ipv4-next-hop {
+ description "Set IPv4 address of the next hop";
+ value 0;
+ }
+ enum ipv6-next-hop {
+ description "Set IPv6 address of the next hop";
+ value 1;
+ }
+ enum metric {
+ description "Set prefix/route metric";
+ value 2;
+ }
+ enum tag {
+ description "Set tag";
+ value 3;
+ }
+
+ /*
+ * Protocol YANG models should augment the parent node to
+ * contain the routing protocol specific value. The protocol
+ * must also augment `action-value` to include its specific
+ * values or expand the `when` statement on the existing cases.
+ */
+ enum routing-protocol-specific {
+ description "Set a routing protocol specific action";
+ value 100;
+ }
+ }
+ }
+
+ choice action-value {
+ description
+ "Value to set (interpretation depends on action-type)";
+ case ipv4-address {
+ when "./action = 'ipv4-next-hop'";
+ leaf ipv4-address {
+ description "IPv4 address";
+ type inet:ipv4-address;
+ }
+ }
+ case ipv6-address {
+ when "./action = 'ipv6-next-hop'";
+ leaf ipv6-address {
+ description "IPv6 address";
+ type inet:ipv6-address;
+ }
+ }
+ case metric {
+ when "./action = 'metric'";
+ choice metric-value {
+ description "Metric to set or use";
+ case value {
+ leaf value {
+ description "Use the following metric value";
+ type uint32 {
+ range "0..4294967295";
+ }
+ }
+ }
+ case add-metric {
+ leaf add-metric {
+ description "Add unit to metric";
+ type boolean;
+ }
+ }
+ case subtract-metric {
+ leaf subtract-metric {
+ description "Subtract unit from metric";
+ type boolean;
+ }
+ }
+ case use-round-trip-time {
+ leaf use-round-trip-time {
+ description "Use the round trip time as metric";
+ type boolean;
+ }
+ }
+ case add-round-trip-time {
+ leaf add-round-trip-time {
+ description "Add round trip time to metric";
+ type boolean;
+ }
+ }
+ case subtract-round-trip-time {
+ leaf subtract-round-trip-time {
+ description "Subtract round trip time to metric";
+ type boolean;
+ }
+ }
+ }
+ }
+ case tag {
+ leaf tag {
+ description "Tag value";
+ type uint32 {
+ range "0..4294967295";
+ }
+ }
+ }
+ }
+ }
+
+ leaf call {
+ description
+ "Call another route map before calling `exit-policy`. If the
+ called route map returns deny then this route map will also
+ return deny";
+ type string;
+ }
+
+ leaf exit-policy {
+ description "What do to after route map successful match, set and call";
+ type enumeration {
+ enum permit-or-deny {
+ description "End route map evaluation and return";
+ value 0;
+ }
+ enum next {
+ description
+ "Proceed evaluating next route map entry per sequence";
+ value 1;
+ }
+ enum goto {
+ description
+ "Go to route map entry with the provided sequence number";
+ value 2;
+ }
+ }
+ default "permit-or-deny";
+ }
+
+ leaf goto-value {
+ when "../exit-policy = 'goto'";
+ description
+ "Sequence number to jump (when using `goto` exit policy)";
+ type route-map-sequence;
+ }
+ }
+ }
+}
diff --git a/yang/subdir.am b/yang/subdir.am
index 4b3baeea9d..18d2bf160c 100644
--- a/yang/subdir.am
+++ b/yang/subdir.am
@@ -28,6 +28,10 @@ if BFDD
dist_yangmodels_DATA += yang/frr-bfdd.yang
endif
+if EIGRPD
+dist_yangmodels_DATA += yang/frr-eigrpd.yang
+endif
+
if RIPD
dist_yangmodels_DATA += yang/frr-ripd.yang
endif
diff --git a/zebra/connected.c b/zebra/connected.c
index bba221c2cf..4101a4bf24 100644
--- a/zebra/connected.c
+++ b/zebra/connected.c
@@ -260,16 +260,6 @@ void connected_up(struct interface *ifp, struct connected *ifc)
rib_add(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT,
0, 0, &p, NULL, &nh, zvrf->table_id, metric, 0, 0, 0);
- if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
- char buf[PREFIX_STRLEN];
-
- zlog_debug(
- "%u: IF %s address %s add/up, scheduling RIB processing",
- ifp->vrf_id, ifp->name,
- prefix2str(&p, buf, sizeof(buf)));
- }
- rib_update(zvrf->vrf->vrf_id, RIB_UPDATE_IF_CHANGE);
-
/* Schedule LSP forwarding entries for processing, if appropriate. */
if (zvrf->vrf->vrf_id == VRF_DEFAULT) {
if (IS_ZEBRA_DEBUG_MPLS) {
@@ -433,17 +423,6 @@ void connected_down(struct interface *ifp, struct connected *ifc)
rib_delete(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT,
0, 0, &p, NULL, &nh, zvrf->table_id, 0, 0, false);
- if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
- char buf[PREFIX_STRLEN];
-
- zlog_debug(
- "%u: IF %s IP %s address down, scheduling RIB processing",
- zvrf->vrf->vrf_id, ifp->name,
- prefix2str(&p, buf, sizeof(buf)));
- }
-
- rib_update(zvrf->vrf->vrf_id, RIB_UPDATE_IF_CHANGE);
-
/* Schedule LSP forwarding entries for processing, if appropriate. */
if (zvrf->vrf->vrf_id == VRF_DEFAULT) {
if (IS_ZEBRA_DEBUG_MPLS) {
@@ -468,16 +447,6 @@ static void connected_delete_helper(struct connected *ifc, struct prefix *p)
connected_withdraw(ifc);
- if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
- char buf[PREFIX_STRLEN];
-
- zlog_debug(
- "%u: IF %s IP %s address del, scheduling RIB processing",
- ifp->vrf_id, ifp->name,
- prefix2str(p, buf, sizeof(buf)));
- }
- rib_update(ifp->vrf_id, RIB_UPDATE_IF_CHANGE);
-
/* Schedule LSP forwarding entries for processing, if appropriate. */
if (ifp->vrf_id == VRF_DEFAULT) {
if (IS_ZEBRA_DEBUG_MPLS) {
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index df8d4bfe15..2c536c5d1f 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -590,7 +590,7 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
char *kind = NULL;
char *desc = NULL;
char *slave_kind = NULL;
- struct zebra_ns *zns;
+ struct zebra_ns *zns = NULL;
vrf_id_t vrf_id = VRF_DEFAULT;
zebra_iftype_t zif_type = ZEBRA_IF_OTHER;
zebra_slave_iftype_t zif_slave_type = ZEBRA_IF_SLAVE_NONE;
@@ -598,6 +598,7 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
ifindex_t link_ifindex = IFINDEX_INTERNAL;
ifindex_t bond_ifindex = IFINDEX_INTERNAL;
struct zebra_if *zif;
+ struct vrf *vrf = NULL;
zns = zebra_ns_lookup(ns_id);
ifi = NLMSG_DATA(h);
@@ -681,9 +682,17 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
if (tb[IFLA_LINK])
link_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_LINK]);
- /* Add interface. */
- ifp = if_get_by_name(name, vrf_id);
- set_ifindex(ifp, ifi->ifi_index, zns);
+ vrf = vrf_get(vrf_id, NULL);
+ /* Add interface.
+ * We add by index first because in some cases such as the master
+ * interface, we have the index before we have the name. Fixing
+ * back references on the slave interfaces is painful if not done
+ * this way, i.e. by creating by ifindex.
+ */
+ ifp = if_get_by_ifindex(ifi->ifi_index, vrf_id);
+ set_ifindex(ifp, ifi->ifi_index, zns); /* add it to ns struct */
+ strlcpy(ifp->name, name, sizeof(ifp->name));
+ IFNAME_RB_INSERT(vrf, ifp);
ifp->flags = ifi->ifi_flags & 0x0000fffff;
ifp->mtu6 = ifp->mtu = *(uint32_t *)RTA_DATA(tb[IFLA_MTU]);
ifp->metric = 0;
@@ -1347,6 +1356,12 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
"Intf %s(%u) has come UP",
name, ifp->ifindex);
if_up(ifp);
+ } else {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug(
+ "Intf %s(%u) has gone DOWN",
+ name, ifp->ifindex);
+ if_down(ifp);
}
}
diff --git a/zebra/interface.c b/zebra/interface.c
index 4eec435f1c..a2f80aff4e 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -799,15 +799,6 @@ void if_handle_vrf_change(struct interface *ifp, vrf_id_t vrf_id)
/* Install connected routes (in new VRF). */
if (if_is_operative(ifp))
if_install_connected(ifp);
-
- /* Due to connected route change, schedule RIB processing for both old
- * and new VRF.
- */
- if (IS_ZEBRA_DEBUG_RIB_DETAILED)
- zlog_debug("%u: IF %s VRF change, scheduling RIB processing",
- ifp->vrf_id, ifp->name);
- rib_update(old_vrf_id, RIB_UPDATE_IF_CHANGE);
- rib_update(ifp->vrf_id, RIB_UPDATE_IF_CHANGE);
}
static void ipv6_ll_address_to_mac(struct in6_addr *address, uint8_t *mac)
@@ -950,11 +941,6 @@ void if_up(struct interface *ifp)
/* Install connected routes to the kernel. */
if_install_connected(ifp);
- if (IS_ZEBRA_DEBUG_RIB_DETAILED)
- zlog_debug("%u: IF %s up, scheduling RIB processing",
- ifp->vrf_id, ifp->name);
- rib_update(ifp->vrf_id, RIB_UPDATE_IF_CHANGE);
-
/* Handle interface up for specific types for EVPN. Non-VxLAN interfaces
* are checked to see if (remote) neighbor entries need to be installed
* on them for ARP suppression.
@@ -1008,11 +994,6 @@ void if_down(struct interface *ifp)
/* Uninstall connected routes from the kernel. */
if_uninstall_connected(ifp);
- if (IS_ZEBRA_DEBUG_RIB_DETAILED)
- zlog_debug("%u: IF %s down, scheduling RIB processing",
- ifp->vrf_id, ifp->name);
- rib_update(ifp->vrf_id, RIB_UPDATE_IF_CHANGE);
-
if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(ifp);
/* Delete all neighbor addresses learnt through IPv6 RA */
@@ -1401,26 +1382,35 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp)
struct zebra_l2info_brslave *br_slave;
br_slave = &zebra_if->brslave_info;
- if (br_slave->bridge_ifindex != IFINDEX_INTERNAL)
- vty_out(vty, " Master (bridge) ifindex %u\n",
- br_slave->bridge_ifindex);
+ if (br_slave->bridge_ifindex != IFINDEX_INTERNAL) {
+ if (br_slave->br_if)
+ vty_out(vty, " Master interface: %s\n",
+ br_slave->br_if->name);
+ else
+ vty_out(vty, " Master ifindex: %u\n",
+ br_slave->bridge_ifindex);
+ }
}
if (IS_ZEBRA_IF_BOND_SLAVE(ifp)) {
struct zebra_l2info_bondslave *bond_slave;
bond_slave = &zebra_if->bondslave_info;
- if (bond_slave->bond_ifindex != IFINDEX_INTERNAL)
- vty_out(vty, " Master (bond) ifindex %u\n",
- bond_slave->bond_ifindex);
+ if (bond_slave->bond_ifindex != IFINDEX_INTERNAL) {
+ if (bond_slave->bond_if)
+ vty_out(vty, " Master interface: %s\n",
+ bond_slave->bond_if->name);
+ else
+ vty_out(vty, " Master ifindex: %u\n",
+ bond_slave->bond_ifindex);
+ }
}
if (zebra_if->link_ifindex != IFINDEX_INTERNAL) {
- vty_out(vty, " Link ifindex %u", zebra_if->link_ifindex);
if (zebra_if->link)
- vty_out(vty, "(%s)\n", zebra_if->link->name);
+ vty_out(vty, " Parent interface: %s\n", zebra_if->link->name);
else
- vty_out(vty, "(Unknown)\n");
+ vty_out(vty, " Parent ifindex: %d\n", zebra_if->link_ifindex);
}
if (HAS_LINK_PARAMS(ifp)) {
diff --git a/zebra/label_manager.c b/zebra/label_manager.c
index 03cfa572db..6e58f4b925 100644
--- a/zebra/label_manager.c
+++ b/zebra/label_manager.c
@@ -39,6 +39,7 @@
#include "zebra/label_manager.h"
#include "zebra/zebra_errors.h"
#include "zebra/zapi_msg.h"
+#include "zebra/debug.h"
#define CONNECTION_DELAY 5
@@ -116,8 +117,9 @@ int release_daemon_label_chunks(uint8_t proto, unsigned short instance)
int count = 0;
int ret;
- zlog_debug("%s: Releasing chunks for client proto %s, instance %d",
- __func__, zebra_route_string(proto), instance);
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: Releasing chunks for client proto %s, instance %d",
+ __func__, zebra_route_string(proto), instance);
for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) {
if (lmc->proto == proto && lmc->instance == instance
@@ -129,7 +131,8 @@ int release_daemon_label_chunks(uint8_t proto, unsigned short instance)
}
}
- zlog_debug("%s: Released %d label chunks", __func__, count);
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug("%s: Released %d label chunks", __func__, count);
return count;
}
@@ -371,7 +374,8 @@ int release_label_chunk(uint8_t proto, unsigned short instance, uint32_t start,
int ret = -1;
/* check that size matches */
- zlog_debug("Releasing label chunk: %u - %u", start, end);
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug("Releasing label chunk: %u - %u", start, end);
/* find chunk and disown */
for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) {
if (lmc->start != start)
diff --git a/zebra/main.c b/zebra/main.c
index 84e83bc37e..657d1247e9 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -34,7 +34,6 @@
#include "privs.h"
#include "sigevent.h"
#include "vrf.h"
-#include "logicalrouter.h"
#include "libfrr.h"
#include "routemap.h"
#include "frr_pthread.h"
@@ -262,7 +261,6 @@ int main(int argc, char **argv)
graceful_restart = 0;
vrf_configure_backend(VRF_BACKEND_VRF_LITE);
- logicalrouter_configure_backend(LOGICALROUTER_BACKEND_NETNS);
frr_preinit(&zebra_di, argc, argv);
@@ -349,8 +347,6 @@ int main(int argc, char **argv)
break;
case 'n':
vrf_configure_backend(VRF_BACKEND_NETNS);
- logicalrouter_configure_backend(
- LOGICALROUTER_BACKEND_OFF);
break;
case OPTION_V6_RR_SEMANTICS:
v6_rr_semantics = true;
diff --git a/zebra/redistribute.c b/zebra/redistribute.c
index d56579ff4f..1ae2ba92b0 100644
--- a/zebra/redistribute.c
+++ b/zebra/redistribute.c
@@ -172,6 +172,13 @@ void redistribute_update(const struct prefix *p, const struct prefix *src_p,
__FUNCTION__);
return;
}
+ if (!zebra_check_addr(p)) {
+ if (IS_ZEBRA_DEBUG_RIB)
+ zlog_debug("Redist update filter prefix %s",
+ prefix2str(p, buf, sizeof(buf)));
+ return;
+ }
+
for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
send_redistribute = 0;
@@ -246,6 +253,13 @@ void redistribute_delete(const struct prefix *p, const struct prefix *src_p,
return;
}
+ if (!zebra_check_addr(p)) {
+ if (IS_ZEBRA_DEBUG_RIB)
+ zlog_debug("Redist delete filter prefix %s",
+ prefix2str(p, buf, sizeof(buf)));
+ return;
+ }
+
for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
if ((is_default_prefix(p)
&& vrf_bitmap_check(client->redist_default[afi],
@@ -574,7 +588,7 @@ int zebra_add_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn,
struct route_entry *newre;
struct route_entry *same;
struct prefix p;
- route_map_result_t ret = RMAP_MATCH;
+ route_map_result_t ret = RMAP_PERMITMATCH;
afi_t afi;
afi = family2afi(rn->p.family);
@@ -583,7 +597,7 @@ int zebra_add_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn,
afi, re->type, re->instance, &rn->p, re->ng.nexthop,
zvrf->vrf->vrf_id, re->tag, rmap_name);
- if (ret != RMAP_MATCH) {
+ if (ret != RMAP_PERMITMATCH) {
UNSET_FLAG(re->flags, ZEBRA_FLAG_SELECTED);
zebra_del_import_table_entry(zvrf, rn, re);
return 0;
diff --git a/zebra/rib.h b/zebra/rib.h
index 9d8cee8bf7..b82428e54c 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -124,18 +124,16 @@ struct route_entry {
/* RIB internal status */
uint32_t status;
#define ROUTE_ENTRY_REMOVED 0x1
-/* to simplify NHT logic when NHs change, instead of doing a NH by NH cmp */
-#define ROUTE_ENTRY_NEXTHOPS_CHANGED 0x2
/* The Route Entry has changed */
-#define ROUTE_ENTRY_CHANGED 0x4
+#define ROUTE_ENTRY_CHANGED 0x2
/* The Label has changed on the Route entry */
-#define ROUTE_ENTRY_LABELS_CHANGED 0x8
+#define ROUTE_ENTRY_LABELS_CHANGED 0x4
/* Route is queued for Installation into the Data Plane */
-#define ROUTE_ENTRY_QUEUED 0x10
+#define ROUTE_ENTRY_QUEUED 0x8
/* Route is installed into the Data Plane */
-#define ROUTE_ENTRY_INSTALLED 0x20
+#define ROUTE_ENTRY_INSTALLED 0x10
/* Route has Failed installation into the Data Plane in some manner */
-#define ROUTE_ENTRY_FAILED 0x40
+#define ROUTE_ENTRY_FAILED 0x20
/* Nexthop information. */
uint8_t nexthop_num;
@@ -303,7 +301,6 @@ typedef struct rib_tables_iter_t_ {
/* Events/reasons triggering a RIB update. */
typedef enum {
- RIB_UPDATE_IF_CHANGE,
RIB_UPDATE_RMAP_CHANGE,
RIB_UPDATE_OTHER
} rib_update_event_t;
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index e48ed9ef8b..3655763164 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -1833,6 +1833,19 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
if (p->family == AF_INET || v6_rr_semantics) {
/* Single 'replace' operation */
cmd = RTM_NEWROUTE;
+
+ /*
+ * With route replace semantics in place
+ * for v4 routes and the new route is a system
+ * route we do not install anything.
+ * The problem here is that the new system
+ * route should cause us to withdraw from
+ * the kernel the old non-system route
+ */
+ if (RSYSTEM_ROUTE(dplane_ctx_get_type(ctx)) &&
+ !RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx)))
+ (void)netlink_route_multipath(RTM_DELROUTE,
+ ctx);
} else {
/*
* So v6 route replace semantics are not in
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index 98bb2eda60..b6a8ee950c 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -1431,12 +1431,10 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
if (!CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)
|| api.nexthop_num == 0) {
- char buf_prefix[PREFIX_STRLEN];
-
- prefix2str(&api.prefix, buf_prefix, sizeof(buf_prefix));
flog_warn(EC_ZEBRA_RX_ROUTE_NO_NEXTHOPS,
- "%s: received a route without nexthops for prefix %s",
- __func__, buf_prefix);
+ "%s: received a route without nexthops for prefix %pFX from client %s",
+ __func__, &api.prefix,
+ zebra_route_string(client->proto));
XFREE(MTYPE_RE, re);
return;
}
@@ -1938,9 +1936,10 @@ static void zread_get_label_chunk(struct zserv *client, struct stream *msg,
"Unable to assign Label Chunk of size %u to %s instance %u",
size, zebra_route_string(proto), instance);
else
- zlog_debug("Assigned Label Chunk %u - %u to %s instance %u",
- lmc->start, lmc->end,
- zebra_route_string(proto), instance);
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug("Assigned Label Chunk %u - %u to %s instance %u",
+ lmc->start, lmc->end,
+ zebra_route_string(proto), instance);
stream_failure:
return;
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c
index 78127f8ce8..5414502fa3 100644
--- a/zebra/zebra_dplane.c
+++ b/zebra/zebra_dplane.c
@@ -3225,7 +3225,7 @@ void zebra_dplane_start(void)
/* Start dataplane pthread */
zdplane_info.dg_pthread = frr_pthread_new(&pattr, "Zebra dplane thread",
- "Zebra dplane");
+ "zebra_dplane");
zdplane_info.dg_master = zdplane_info.dg_pthread->master;
diff --git a/zebra/zebra_errors.c b/zebra/zebra_errors.c
index 5f0a9ec011..a7e5147af3 100644
--- a/zebra/zebra_errors.c
+++ b/zebra/zebra_errors.c
@@ -659,7 +659,7 @@ static struct log_ref ferr_zebra_err[] = {
{
.code = EC_ZEBRA_RTM_VERSION_MISMATCH,
.title =
- "Zebra received kernel message with uknown version",
+ "Zebra received kernel message with unknown version",
.description =
"Zebra received a message from the kernel with a message version that does not match Zebra's internal version. Depending on version compatibility, this may cause issues sending and receiving messages to the kernel.",
.suggestion =
diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c
index 822def318a..f347d3955c 100644
--- a/zebra/zebra_fpm_netlink.c
+++ b/zebra/zebra_fpm_netlink.c
@@ -238,7 +238,7 @@ static int netlink_route_info_add_nh(netlink_route_info_t *ri,
if (re && CHECK_FLAG(re->flags, ZEBRA_FLAG_EVPN_ROUTE)) {
nhi.encap_info.encap_type = FPM_NH_ENCAP_VXLAN;
- zl3vni = zl3vni_from_vrf(ri->rtm_table);
+ zl3vni = zl3vni_from_vrf(nexthop->vrf_id);
if (zl3vni && is_l3vni_oper_up(zl3vni)) {
/* Add VNI to VxLAN encap info */
diff --git a/zebra/zebra_l2.c b/zebra/zebra_l2.c
index ca37dd748e..e549d80a5c 100644
--- a/zebra/zebra_l2.c
+++ b/zebra/zebra_l2.c
@@ -99,15 +99,18 @@ void zebra_l2_unmap_slave_from_bridge(struct zebra_l2info_brslave *br_slave)
br_slave->br_if = NULL;
}
-void zebra_l2_map_slave_to_bond(struct zebra_l2info_bondslave *bond_slave)
+void zebra_l2_map_slave_to_bond(struct zebra_l2info_bondslave *bond_slave,
+ vrf_id_t vrf_id)
{
struct interface *bond_if;
/* TODO: Handle change of master */
- bond_if = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT),
- bond_slave->bond_ifindex);
+ bond_if = if_lookup_by_index_all_vrf(bond_slave->bond_ifindex);
if (bond_if)
bond_slave->bond_if = bond_if;
+ else
+ bond_slave->bond_if = if_create_ifindex(bond_slave->bond_ifindex,
+ vrf_id);
}
void zebra_l2_unmap_slave_from_bond(struct zebra_l2info_bondslave *bond_slave)
@@ -282,7 +285,7 @@ void zebra_l2if_update_bond_slave(struct interface *ifp, ifindex_t bond_ifindex)
/* Set up or remove link with master */
if (bond_ifindex != IFINDEX_INTERNAL)
- zebra_l2_map_slave_to_bond(&zif->bondslave_info);
+ zebra_l2_map_slave_to_bond(&zif->bondslave_info, ifp->vrf_id);
else if (old_bond_ifindex != IFINDEX_INTERNAL)
zebra_l2_unmap_slave_from_bond(&zif->bondslave_info);
}
diff --git a/zebra/zebra_l2.h b/zebra/zebra_l2.h
index 33aa2e3746..d9f0eec3f8 100644
--- a/zebra/zebra_l2.h
+++ b/zebra/zebra_l2.h
@@ -81,7 +81,7 @@ extern void zebra_l2_map_slave_to_bridge(struct zebra_l2info_brslave *br_slave);
extern void
zebra_l2_unmap_slave_from_bridge(struct zebra_l2info_brslave *br_slave);
extern void
-zebra_l2_map_slave_to_bond(struct zebra_l2info_bondslave *bond_slave);
+zebra_l2_map_slave_to_bond(struct zebra_l2info_bondslave *bond_slave, vrf_id_t);
extern void
zebra_l2_unmap_slave_from_bond(struct zebra_l2info_bondslave *bond_slave);
extern void zebra_l2_bridge_add_update(struct interface *ifp,
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index 4a88296051..f4b86f3cfe 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -87,7 +87,7 @@ static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop,
break;
case NEXTHOP_TYPE_BLACKHOLE:
resolved_hop->type = NEXTHOP_TYPE_BLACKHOLE;
- resolved_hop->bh_type = nexthop->bh_type;
+ resolved_hop->bh_type = newhop->bh_type;
break;
}
@@ -272,8 +272,6 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
SET_FLAG(nexthop->flags,
NEXTHOP_FLAG_RECURSIVE);
- SET_FLAG(re->status,
- ROUTE_ENTRY_NEXTHOPS_CHANGED);
nexthop_set_resolved(afi, newhop, nexthop);
resolved = 1;
}
@@ -339,7 +337,7 @@ static unsigned nexthop_active_check(struct route_node *rn,
struct nexthop *nexthop)
{
struct interface *ifp;
- route_map_result_t ret = RMAP_MATCH;
+ route_map_result_t ret = RMAP_PERMITMATCH;
int family;
char buf[SRCDEST2STR_BUFFER];
const struct prefix *p, *src_p;
@@ -501,10 +499,8 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re)
&& nexthop->type < NEXTHOP_TYPE_BLACKHOLE)
&& !(IPV6_ADDR_SAME(&prev_src.ipv6,
&nexthop->rmap_src.ipv6)))
- || CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED)) {
+ || CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED))
SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
- SET_FLAG(re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED);
- }
}
return re->nexthop_active_num;
diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c
index db4f9d0015..94918365a3 100644
--- a/zebra/zebra_ns.c
+++ b/zebra/zebra_ns.c
@@ -23,7 +23,6 @@
#include "lib/ns.h"
#include "lib/vrf.h"
-#include "lib/logicalrouter.h"
#include "lib/prefix.h"
#include "lib/memory.h"
@@ -45,7 +44,6 @@ DEFINE_MTYPE(ZEBRA, ZEBRA_NS, "Zebra Name Space")
static struct zebra_ns *dzns;
-static int logicalrouter_config_write(struct vty *vty);
static int zebra_ns_disable_internal(struct zebra_ns *zns, bool complete);
struct zebra_ns *zebra_ns_lookup(ns_id_t ns_id)
@@ -188,8 +186,6 @@ int zebra_ns_init(const char *optional_default_name)
ns_id_external = ns_map_nsid_with_external(ns_id, true);
ns_init_management(ns_id_external, ns_id);
- logicalrouter_init(logicalrouter_config_write);
-
/* Do any needed per-NS data structure allocation. */
dzns->if_table = route_table_init();
@@ -215,21 +211,6 @@ int zebra_ns_init(const char *optional_default_name)
return 0;
}
-static int logicalrouter_config_write(struct vty *vty)
-{
- struct ns *ns;
- int write = 0;
-
- RB_FOREACH (ns, ns_head, &ns_tree) {
- if (ns->ns_id == NS_DEFAULT || ns->name == NULL)
- continue;
- vty_out(vty, "logical-router %u netns %s\n", ns->ns_id,
- ns->name);
- write = 1;
- }
- return write;
-}
-
int zebra_ns_config_write(struct vty *vty, struct ns *ns)
{
if (ns && ns->name != NULL)
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index fa8b5d400a..335cc8294c 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -1128,8 +1128,6 @@ static void rib_process(struct route_node *rn)
re->status, re->flags, re->distance,
re->metric);
- UNSET_FLAG(re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED);
-
/* Currently selected re. */
if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) {
assert(old_selected == NULL);
@@ -1364,6 +1362,7 @@ static void zebra_rib_fixup_system(struct route_node *rn)
continue;
SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
+ UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED);
for (ALL_NEXTHOPS(re->ng, nhop)) {
if (CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_RECURSIVE))
@@ -1775,7 +1774,7 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
/* Redistribute */
redistribute_update(dest_pfx, src_pfx,
- re, NULL);
+ re, old_re);
}
/*
@@ -1927,6 +1926,9 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
goto done;
}
+ /* Ensure we clear the QUEUED flag */
+ UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED);
+
/* Is this a notification that ... matters? We only really care about
* the route that is currently selected for installation.
*/
@@ -1991,7 +1993,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
dplane_ctx_get_vrf(ctx), dest_str);
/* We expect this to be the selected route, so we want
- * to tell others about this transistion.
+ * to tell others about this transition.
*/
SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
@@ -2967,50 +2969,6 @@ void rib_update_table(struct route_table *table, rib_update_event_t event)
RIB_ROUTE_ANY_QUEUED))
continue;
switch (event) {
- case RIB_UPDATE_IF_CHANGE:
- /* Examine all routes that won't get processed by the
- * protocol or
- * triggered by nexthop evaluation (NHT). This would be
- * system,
- * kernel and certain static routes. Note that NHT will
- * get
- * triggered upon an interface event as connected routes
- * always
- * get queued for processing.
- */
- RNODE_FOREACH_RE_SAFE (rn, re, next) {
- struct nexthop *nh;
-
- if (re->type != ZEBRA_ROUTE_SYSTEM
- && re->type != ZEBRA_ROUTE_KERNEL
- && re->type != ZEBRA_ROUTE_CONNECT
- && re->type != ZEBRA_ROUTE_STATIC)
- continue;
-
- if (re->type != ZEBRA_ROUTE_STATIC) {
- SET_FLAG(re->status,
- ROUTE_ENTRY_CHANGED);
- rib_queue_add(rn);
- continue;
- }
-
- for (nh = re->ng.nexthop; nh; nh = nh->next)
- if (!(nh->type == NEXTHOP_TYPE_IPV4
- || nh->type == NEXTHOP_TYPE_IPV6))
- break;
-
- /* If we only have nexthops to a
- * gateway, NHT will
- * take care.
- */
- if (nh) {
- SET_FLAG(re->status,
- ROUTE_ENTRY_CHANGED);
- rib_queue_add(rn);
- }
- }
- break;
-
case RIB_UPDATE_RMAP_CHANGE:
case RIB_UPDATE_OTHER:
/* Right now, examine all routes. Can restrict to a
diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c
index 6f65f8ab7a..da2fe4a30c 100644
--- a/zebra/zebra_rnh.c
+++ b/zebra/zebra_rnh.c
@@ -403,7 +403,7 @@ static int zebra_rnh_apply_nht_rmap(afi_t afi, struct zebra_vrf *zvrf,
{
int at_least_one = 0;
struct nexthop *nexthop;
- int ret;
+ route_map_result_t ret;
if (prn && re) {
for (nexthop = re->ng.nexthop; nexthop;
@@ -465,6 +465,7 @@ zebra_rnh_resolve_import_entry(struct zebra_vrf *zvrf, afi_t afi,
RNODE_FOREACH_RE (rn, re) {
if (!CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)
&& CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)
+ && !CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED)
&& (re->type != ZEBRA_ROUTE_BGP))
break;
}
@@ -679,6 +680,14 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi,
continue;
}
+ if (CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED)) {
+ if (IS_ZEBRA_DEBUG_NHT_DETAILED)
+ zlog_debug(
+ "\tRoute Entry %s queued",
+ zebra_route_string(re->type));
+ continue;
+ }
+
/* Just being SELECTED isn't quite enough - must
* have an installed nexthop to be useful.
*/
@@ -859,10 +868,8 @@ static void zebra_rnh_clear_nhc_flag(struct zebra_vrf *zvrf, afi_t afi,
re = zebra_rnh_resolve_nexthop_entry(zvrf, afi, nrn, rnh,
&prn);
- if (re) {
- UNSET_FLAG(re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED);
+ if (re)
UNSET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
- }
}
/* Evaluate all tracked entries (nexthops or routes for import into BGP)
@@ -917,7 +924,7 @@ void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, struct vty *vty,
}
for (rn = route_top(table); rn; rn = route_next(rn)) {
- if (p && prefix_cmp(&rn->p, p) != 0)
+ if (p && !prefix_match(&rn->p, p))
continue;
if (rn->info)
diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c
index 2f7d50541e..cee2c8980f 100644
--- a/zebra/zebra_routemap.c
+++ b/zebra/zebra_routemap.c
@@ -136,9 +136,9 @@ static int zebra_route_match_delete(struct vty *vty, const char *command,
/* 'match tag TAG'
* Match function return 1 if match is success else return 0
*/
-static route_map_result_t route_match_tag(void *rule,
- const struct prefix *prefix,
- route_map_object_t type, void *object)
+static enum route_map_cmd_result_t
+route_match_tag(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
route_tag_t *tag;
struct nh_rmap_obj *nh_data;
@@ -162,10 +162,9 @@ static struct route_map_rule_cmd route_match_tag_cmd = {
/* `match interface IFNAME' */
/* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_interface(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_interface(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct nh_rmap_obj *nh_data;
char *ifname = rule;
@@ -1025,10 +1024,9 @@ DEFPY (show_ipv6_protocol_nht,
/* `match ip next-hop IP_ACCESS_LIST' */
/* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_ip_next_hop(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_ip_next_hop(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct access_list *alist;
struct nh_rmap_obj *nh_data;
@@ -1037,7 +1035,7 @@ static route_map_result_t route_match_ip_next_hop(void *rule,
if (type == RMAP_ZEBRA) {
nh_data = object;
if (!nh_data)
- return RMAP_DENYMATCH;
+ return RMAP_NOMATCH;
switch (nh_data->nexthop->type) {
case NEXTHOP_TYPE_IFINDEX:
@@ -1083,7 +1081,7 @@ static struct route_map_rule_cmd route_match_ip_next_hop_cmd = {
/* `match ip next-hop prefix-list PREFIX_LIST' */
-static route_map_result_t
+static enum route_map_cmd_result_t
route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -1094,7 +1092,7 @@ route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix,
if (type == RMAP_ZEBRA) {
nh_data = (struct nh_rmap_obj *)object;
if (!nh_data)
- return RMAP_DENYMATCH;
+ return RMAP_NOMATCH;
switch (nh_data->nexthop->type) {
case NEXTHOP_TYPE_IFINDEX:
@@ -1139,10 +1137,9 @@ static struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = {
/* Match function should return 1 if match is success else return
zero. */
-static route_map_result_t route_match_address(afi_t afi, void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_address(afi_t afi, void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct access_list *alist;
@@ -1158,19 +1155,16 @@ static route_map_result_t route_match_address(afi_t afi, void *rule,
return RMAP_NOMATCH;
}
-static route_map_result_t route_match_ip_address(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_ip_address(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
return route_match_address(AFI_IP, rule, prefix, type, object);
}
-static route_map_result_t route_match_ipv6_address(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
-
+static enum route_map_cmd_result_t
+route_match_ipv6_address(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
return route_match_address(AFI_IP6, rule, prefix, type, object);
}
@@ -1200,7 +1194,7 @@ static struct route_map_rule_cmd route_match_ipv6_address_cmd = {
/* `match ip address prefix-list PREFIX_LIST' */
-static route_map_result_t
+static enum route_map_cmd_result_t
route_match_address_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object, afi_t afi)
{
@@ -1218,7 +1212,7 @@ route_match_address_prefix_list(void *rule, const struct prefix *prefix,
return RMAP_NOMATCH;
}
-static route_map_result_t
+static enum route_map_cmd_result_t
route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -1241,7 +1235,7 @@ static struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = {
route_match_address_prefix_list_compile,
route_match_address_prefix_list_free};
-static route_map_result_t
+static enum route_map_cmd_result_t
route_match_ipv6_address_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -1256,7 +1250,7 @@ static struct route_map_rule_cmd route_match_ipv6_address_prefix_list_cmd = {
/* `match ipv6 next-hop type <TYPE>' */
-static route_map_result_t
+static enum route_map_cmd_result_t
route_match_ipv6_next_hop_type(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -1265,7 +1259,7 @@ route_match_ipv6_next_hop_type(void *rule, const struct prefix *prefix,
if (type == RMAP_ZEBRA && prefix->family == AF_INET6) {
nh_data = (struct nh_rmap_obj *)object;
if (!nh_data)
- return RMAP_DENYMATCH;
+ return RMAP_NOMATCH;
if (nh_data->nexthop->type == NEXTHOP_TYPE_BLACKHOLE)
return RMAP_MATCH;
@@ -1290,7 +1284,7 @@ struct route_map_rule_cmd route_match_ipv6_next_hop_type_cmd = {
/* `match ip address prefix-len PREFIXLEN' */
-static route_map_result_t
+static enum route_map_cmd_result_t
route_match_address_prefix_len(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -1341,7 +1335,7 @@ static struct route_map_rule_cmd route_match_ipv6_address_prefix_len_cmd = {
/* `match ip nexthop prefix-len PREFIXLEN' */
-static route_map_result_t
+static enum route_map_cmd_result_t
route_match_ip_nexthop_prefix_len(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -1352,7 +1346,7 @@ route_match_ip_nexthop_prefix_len(void *rule, const struct prefix *prefix,
if (type == RMAP_ZEBRA) {
nh_data = (struct nh_rmap_obj *)object;
if (!nh_data || !nh_data->nexthop)
- return RMAP_DENYMATCH;
+ return RMAP_NOMATCH;
switch (nh_data->nexthop->type) {
case NEXTHOP_TYPE_IFINDEX:
@@ -1381,7 +1375,7 @@ static struct route_map_rule_cmd route_match_ip_nexthop_prefix_len_cmd = {
/* `match ip next-hop type <blackhole>' */
-static route_map_result_t
+static enum route_map_cmd_result_t
route_match_ip_next_hop_type(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -1390,7 +1384,7 @@ route_match_ip_next_hop_type(void *rule, const struct prefix *prefix,
if (type == RMAP_ZEBRA && prefix->family == AF_INET) {
nh_data = (struct nh_rmap_obj *)object;
if (!nh_data)
- return RMAP_DENYMATCH;
+ return RMAP_NOMATCH;
if (nh_data->nexthop->type == NEXTHOP_TYPE_BLACKHOLE)
return RMAP_MATCH;
@@ -1415,10 +1409,9 @@ static struct route_map_rule_cmd route_match_ip_next_hop_type_cmd = {
/* `match source-protocol PROTOCOL' */
-static route_map_result_t route_match_source_protocol(void *rule,
- const struct prefix *p,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_source_protocol(void *rule, const struct prefix *p,
+ route_map_object_t type, void *object)
{
uint32_t *rib_type = (uint32_t *)rule;
struct nh_rmap_obj *nh_data;
@@ -1426,7 +1419,7 @@ static route_map_result_t route_match_source_protocol(void *rule,
if (type == RMAP_ZEBRA) {
nh_data = (struct nh_rmap_obj *)object;
if (!nh_data)
- return RMAP_DENYMATCH;
+ return RMAP_NOMATCH;
return ((nh_data->source_protocol == *rib_type) ? RMAP_MATCH
: RMAP_NOMATCH);
@@ -1457,10 +1450,9 @@ static struct route_map_rule_cmd route_match_source_protocol_cmd = {
route_match_source_protocol_compile, route_match_source_protocol_free};
/* `source-instance` */
-static route_map_result_t route_match_source_instance(void *rule,
- const struct prefix *p,
- route_map_object_t type,
- void *object)
+static enum route_map_cmd_result_t
+route_match_source_instance(void *rule, const struct prefix *p,
+ route_map_object_t type, void *object)
{
uint8_t *instance = (uint8_t *)rule;
struct nh_rmap_obj *nh_data;
@@ -1470,7 +1462,7 @@ static route_map_result_t route_match_source_instance(void *rule,
nh_data = (struct nh_rmap_obj *)object;
if (!nh_data)
- return RMAP_DENYMATCH;
+ return RMAP_NOMATCH;
return (nh_data->instance == *instance) ? RMAP_MATCH : RMAP_NOMATCH;
}
@@ -1500,8 +1492,9 @@ static struct route_map_rule_cmd route_match_source_instance_cmd = {
/* `set src A.B.C.D' */
/* Set src. */
-static route_map_result_t route_set_src(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static enum route_map_cmd_result_t
+route_set_src(void *rule, const struct prefix *prefix, route_map_object_t type,
+ void *object)
{
struct nh_rmap_obj *nh_data;
@@ -1767,7 +1760,7 @@ zebra_route_map_check(int family, int rib_type, uint8_t instance,
struct zebra_vrf *zvrf, route_tag_t tag)
{
struct route_map *rmap = NULL;
- route_map_result_t ret = RMAP_MATCH;
+ route_map_result_t ret = RMAP_PERMITMATCH;
struct nh_rmap_obj nh_obj;
nh_obj.nexthop = nexthop;
@@ -1839,7 +1832,7 @@ route_map_result_t zebra_nht_route_map_check(afi_t afi, int client_proto,
struct nexthop *nexthop)
{
struct route_map *rmap = NULL;
- route_map_result_t ret = RMAP_MATCH;
+ route_map_result_t ret = RMAP_PERMITMATCH;
struct nh_rmap_obj nh_obj;
nh_obj.nexthop = nexthop;
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 74baabbf24..5c0dc27380 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -448,6 +448,9 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
if (re->tag)
json_object_int_add(json_route, "tag", re->tag);
+ if (re->table)
+ json_object_int_add(json_route, "table", re->table);
+
json_object_int_add(json_route, "internalStatus",
re->status);
json_object_int_add(json_route, "internalFlags",
@@ -804,7 +807,8 @@ static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf,
bool use_fib, route_tag_t tag,
const struct prefix *longer_prefix_p,
bool supernets_only, int type,
- unsigned short ospf_instance_id, bool use_json)
+ unsigned short ospf_instance_id, bool use_json,
+ uint32_t tableid)
{
struct route_node *rn;
struct route_entry *re;
@@ -867,10 +871,12 @@ static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf,
vty_out(vty,
SHOW_ROUTE_V6_HEADER);
- if (zvrf_id(zvrf) != VRF_DEFAULT)
+ if (tableid && tableid != RT_TABLE_MAIN)
+ vty_out(vty, "\nVRF %s table %u:\n",
+ zvrf_name(zvrf), tableid);
+ else if (zvrf_id(zvrf) != VRF_DEFAULT)
vty_out(vty, "\nVRF %s:\n",
zvrf_name(zvrf));
-
first = 0;
}
}
@@ -927,7 +933,7 @@ static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi,
do_show_route_helper(vty, zvrf, table, afi, use_fib, tag,
longer_prefix_p, supernets_only, type,
- ospf_instance_id, use_json);
+ ospf_instance_id, use_json, 0);
return CMD_SUCCESS;
}
@@ -950,7 +956,7 @@ DEFPY (show_route_table,
t = zebra_router_find_table(zvrf, table, afi, SAFI_UNICAST);
if (t)
do_show_route_helper(vty, zvrf, t, afi, false, 0, false, false,
- 0, 0, !!json);
+ 0, 0, !!json, table);
return CMD_SUCCESS;
}
@@ -979,14 +985,50 @@ DEFPY (show_route_table_vrf,
t = zebra_router_find_table(zvrf, table, afi, SAFI_UNICAST);
if (t)
do_show_route_helper(vty, zvrf, t, afi, false, 0, false, false,
- 0, 0, !!json);
+ 0, 0, !!json, table);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (show_route_all_table_vrf,
+ show_route_all_table_vrf_cmd,
+ "show <ip$ipv4|ipv6$ipv6> route [vrf <NAME$vrf_name|all$vrf_all>] tables [json$json]",
+ SHOW_STR
+ IP_STR
+ IP6_STR
+ "IP routing table\n"
+ "Display all tables\n"
+ VRF_FULL_CMD_HELP_STR
+ JSON_STR)
+{
+ afi_t afi = ipv4 ? AFI_IP : AFI_IP6;
+ struct zebra_vrf *zvrf = NULL;
+ vrf_id_t vrf_id = VRF_UNKNOWN;
+ struct zebra_router_table *zrt;
+ if (vrf_name) {
+ VRF_GET_ID(vrf_id, vrf_name, !!json);
+ zvrf = zebra_vrf_lookup_by_id(vrf_id);
+ }
+
+ RB_FOREACH (zrt, zebra_router_table_head, &zrouter.tables) {
+ rib_table_info_t *info = route_table_get_info(zrt->table);
+
+ if (zvrf && zvrf != info->zvrf)
+ continue;
+ if (zrt->afi != afi || zrt->safi != SAFI_UNICAST)
+ continue;
+ if (zrt->table)
+ do_show_route_helper(vty, info->zvrf, zrt->table, afi,
+ false, 0, false, false,
+ 0, 0, !!json, zrt->tableid);
+ }
return CMD_SUCCESS;
}
DEFPY (show_ip_nht,
show_ip_nht_cmd,
- "show <ip$ipv4|ipv6$ipv6> <nht|import-check>$type [<A.B.C.D|X:X::X:X>$addr|vrf NAME$vrf_name <A.B.C.D|X:X::X:X>$addr|vrf all$vrf_all]",
+ "show <ip$ipv4|ipv6$ipv6> <nht|import-check>$type [<A.B.C.D|X:X::X:X>$addr|vrf NAME$vrf_name [<A.B.C.D|X:X::X:X>$addr]|vrf all$vrf_all]",
SHOW_STR
IP_STR
IP6_STR
@@ -2383,7 +2425,7 @@ DEFUN (show_pbr_iptable,
DEFPY (clear_evpn_dup_addr,
clear_evpn_dup_addr_cmd,
- "clear evpn dup-addr vni <all$vni_all |" CMD_VNI_RANGE"$vni [mac M:A:C$mac_val | ip <A.B.C.D|X:X::X:X>]>",
+ "clear evpn dup-addr vni <all$vni_all |" CMD_VNI_RANGE"$vni [mac X:X:X:X:X:X | ip <A.B.C.D|X:X::X:X>]>",
CLEAR_STR
"EVPN\n"
"Duplicate address \n"
@@ -2398,16 +2440,14 @@ DEFPY (clear_evpn_dup_addr,
{
struct zebra_vrf *zvrf;
struct ipaddr host_ip = {.ipa_type = IPADDR_NONE };
- struct ethaddr mac_addr;
int ret = CMD_SUCCESS;
zvrf = zebra_vrf_get_evpn();
if (vni_str) {
- if (mac_val) {
- prefix_str2mac(mac_val, &mac_addr);
+ if (!is_zero_mac(&mac->eth_addr)) {
ret = zebra_vxlan_clear_dup_detect_vni_mac(vty, zvrf,
vni,
- &mac_addr);
+ &mac->eth_addr);
} else if (ip) {
if (sockunion_family(ip) == AF_INET) {
host_ip.ipa_type = IPADDR_V4;
@@ -2991,6 +3031,7 @@ void zebra_vty_init(void)
install_element(VIEW_NODE, &show_route_table_cmd);
if (vrf_is_backend_netns())
install_element(VIEW_NODE, &show_route_table_vrf_cmd);
+ install_element(VIEW_NODE, &show_route_all_table_vrf_cmd);
install_element(VIEW_NODE, &show_route_detail_cmd);
install_element(VIEW_NODE, &show_route_summary_cmd);
install_element(VIEW_NODE, &show_ip_nht_cmd);
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index 24cd88b91f..bb31247b6a 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -2787,27 +2787,40 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni,
/* Set "local" forwarding info. */
SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
- SET_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW);
ZEBRA_NEIGH_SET_ACTIVE(n);
- /* Set Router flag (R-bit) */
- if (ip->ipa_type == IPADDR_V6)
- SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
memcpy(&n->emac, macaddr, ETH_ALEN);
n->ifindex = ifp->ifindex;
/* Only advertise in BGP if the knob is enabled */
- if (!advertise_gw_macip_enabled(zvni))
- return 0;
+ if (advertise_gw_macip_enabled(zvni)) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
+ SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW);
+ SET_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW);
+ /* Set Router flag (R-bit) */
+ if (ip->ipa_type == IPADDR_V6)
+ SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG);
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
"SVI %s(%u) L2-VNI %u, sending GW MAC %s IP %s add to BGP with flags 0x%x",
ifp->name, ifp->ifindex, zvni->vni,
prefix_mac2str(macaddr, buf, sizeof(buf)),
ipaddr2str(ip, buf2, sizeof(buf2)), n->flags);
- zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr,
- n->flags, n->loc_seq);
+ zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr,
+ n->flags, n->loc_seq);
+ } else if (advertise_svi_macip_enabled(zvni)) {
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "SVI %s(%u) L2-VNI %u, sending SVI MAC %s IP %s add to BGP with flags 0x%x",
+ ifp->name, ifp->ifindex, zvni->vni,
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ ipaddr2str(ip, buf2, sizeof(buf2)), n->flags);
+
+ zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr,
+ n->flags, n->loc_seq);
+ }
return 0;
}
@@ -3403,6 +3416,39 @@ static int zvni_mac_del(zebra_vni_t *zvni, zebra_mac_t *mac)
return 0;
}
+static bool zvni_check_mac_del_from_db(struct mac_walk_ctx *wctx,
+ zebra_mac_t *mac)
+{
+ if ((wctx->flags & DEL_LOCAL_MAC) &&
+ (mac->flags & ZEBRA_MAC_LOCAL))
+ return true;
+ else if ((wctx->flags & DEL_REMOTE_MAC) &&
+ (mac->flags & ZEBRA_MAC_REMOTE))
+ return true;
+ else if ((wctx->flags & DEL_REMOTE_MAC_FROM_VTEP) &&
+ (mac->flags & ZEBRA_MAC_REMOTE) &&
+ IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &wctx->r_vtep_ip))
+ return true;
+ else if ((wctx->flags & DEL_LOCAL_MAC) &&
+ (mac->flags & ZEBRA_MAC_AUTO) &&
+ !listcount(mac->neigh_list)) {
+ if (IS_ZEBRA_DEBUG_VXLAN) {
+ char buf[ETHER_ADDR_STRLEN];
+
+ zlog_debug("%s: Del MAC %s flags 0x%x",
+ __PRETTY_FUNCTION__,
+ prefix_mac2str(&mac->macaddr,
+ buf, sizeof(buf)),
+ mac->flags);
+ }
+ wctx->uninstall = 0;
+
+ return true;
+ }
+
+ return false;
+}
+
/*
* Free MAC hash entry (callback)
*/
@@ -3411,18 +3457,11 @@ static void zvni_mac_del_hash_entry(struct hash_bucket *bucket, void *arg)
struct mac_walk_ctx *wctx = arg;
zebra_mac_t *mac = bucket->data;
- if (((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_LOCAL))
- || ((wctx->flags & DEL_REMOTE_MAC)
- && (mac->flags & ZEBRA_MAC_REMOTE))
- || ((wctx->flags & DEL_REMOTE_MAC_FROM_VTEP)
- && (mac->flags & ZEBRA_MAC_REMOTE)
- && IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip,
- &wctx->r_vtep_ip))) {
+ if (zvni_check_mac_del_from_db(wctx, mac)) {
if (wctx->upd_client && (mac->flags & ZEBRA_MAC_LOCAL)) {
zvni_mac_send_del_to_client(wctx->zvni->vni,
&mac->macaddr);
}
-
if (wctx->uninstall)
zvni_mac_uninstall(wctx->zvni, mac);
@@ -5352,8 +5391,6 @@ static void process_remote_macip_add(vni_t vni,
if (ipa_len)
SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
} else {
- const char *mac_type;
-
/* When host moves but changes its (MAC,IP)
* binding, BGP may install a MACIP entry that
* corresponds to "older" location of the host
@@ -5362,16 +5399,14 @@ static void process_remote_macip_add(vni_t vni,
* the sequence number and ignore this update
* if appropriate.
*/
- if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
tmp_seq = mac->loc_seq;
- mac_type = "local";
- } else {
+ else
tmp_seq = mac->rem_seq;
- mac_type = "remote";
- }
+
if (seq < tmp_seq) {
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Ignore remote MACIP ADD VNI %u MAC %s%s%s as existing %s MAC has higher seq %u",
+ zlog_debug("Ignore remote MACIP ADD VNI %u MAC %s%s%s as existing MAC has higher seq %u flags 0x%x",
vni,
prefix_mac2str(macaddr,
buf, sizeof(buf)),
@@ -5379,8 +5414,7 @@ static void process_remote_macip_add(vni_t vni,
ipa_len ?
ipaddr2str(ipaddr,
buf1, sizeof(buf1)) : "",
- mac_type,
- tmp_seq);
+ tmp_seq, mac->flags);
return;
}
}
@@ -6758,7 +6792,7 @@ int zebra_vxlan_clear_dup_detect_vni_ip(struct vty *vty,
if (!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) {
vty_out(vty,
- "%% Requsted host IP %s is not duplicate detected\n",
+ "%% Requested host IP %s is not duplicate detected\n",
buf);
return CMD_WARNING;
}
@@ -7294,8 +7328,13 @@ int zebra_vxlan_handle_kernel_neigh_del(struct interface *ifp,
* of a VxLAN bridge.
*/
zvni = zvni_from_svi(ifp, link_if);
- if (!zvni)
+ if (!zvni) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("%s: Del neighbor %s VNI is not present for interface %s",
+ __PRETTY_FUNCTION__,
+ ipaddr2str(ip, buf, sizeof(buf)), ifp->name);
return 0;
+ }
if (!zvni->vxlan_if) {
zlog_debug(
@@ -7692,9 +7731,10 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if,
return 0;
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("DEL MAC %s intf %s(%u) VID %u -> VNI %u flags 0x%x",
+ zlog_debug("DEL MAC %s intf %s(%u) VID %u -> VNI %u seq %u flags 0x%x nbr count %u",
prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name,
- ifp->ifindex, vid, zvni->vni, mac->flags);
+ ifp->ifindex, vid, zvni->vni, mac->loc_seq,
+ mac->flags, listcount(mac->neigh_list));
/* Update all the neigh entries associated with this mac */
zvni_process_neigh_on_local_mac_del(zvni, mac);
@@ -9008,7 +9048,7 @@ void zebra_vxlan_advertise_svi_macip(ZAPI_HANDLER_ARGS)
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug("EVPN SVI-MACIP Adv %s, currently %s",
advertise ? "enabled" : "disabled",
- advertise_gw_macip_enabled(NULL)
+ advertise_svi_macip_enabled(NULL)
? "enabled"
: "disabled");
@@ -9739,8 +9779,9 @@ void zebra_vxlan_sg_replay(ZAPI_HANDLER_ARGS)
SET_FLAG(zvrf->flags, ZEBRA_PIM_SEND_VXLAN_SG);
if (!EVPN_ENABLED(zvrf)) {
- zlog_debug("VxLAN SG replay request on unexpected vrf %d",
- zvrf->vrf->vrf_id);
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("VxLAN SG replay request on unexpected vrf %d",
+ zvrf->vrf->vrf_id);
return;
}