summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_attr.c6
-rw-r--r--bgpd/bgp_attr.h6
-rw-r--r--bgpd/bgp_evpn_vty.c11
-rw-r--r--bgpd/bgp_route.c7
-rw-r--r--bgpd/bgp_route.h5
-rw-r--r--bgpd/bgp_rpki.c27
-rw-r--r--bgpd/bgp_updgrp_adv.c24
-rw-r--r--bgpd/bgp_vty.c24
-rw-r--r--bgpd/bgp_zebra.c33
-rw-r--r--doc/developer/cli.rst5
-rw-r--r--doc/developer/topotests.rst42
-rw-r--r--doc/user/rpki.rst8
-rw-r--r--isisd/isis_snmp.c21
-rw-r--r--lib/command.c1
-rw-r--r--lib/command_graph.c4
-rw-r--r--lib/command_graph.h1
-rw-r--r--lib/command_lex.l1
-rw-r--r--lib/command_match.c25
-rw-r--r--lib/command_parse.y16
-rw-r--r--lib/command_py.c39
-rw-r--r--lib/nexthop.c5
-rw-r--r--lib/nexthop.h3
-rw-r--r--lib/routemap.c17
-rw-r--r--lib/routemap.h9
-rw-r--r--ospf6d/ospf6_abr.c13
-rw-r--r--ospf6d/ospf6_area.h14
-rw-r--r--ospf6d/ospf6_asbr.c21
-rw-r--r--ospf6d/ospf6_interface.h22
-rw-r--r--ospf6d/ospf6_intra.c20
-rw-r--r--ospf6d/ospf6_intra.h10
-rw-r--r--ospf6d/ospf6_lsa.h19
-rw-r--r--ospf6d/ospf6_neighbor.h32
-rw-r--r--ospf6d/ospf6_nssa.h10
-rw-r--r--ospf6d/ospf6_route.h8
-rw-r--r--ospf6d/ospf6_zebra.h19
-rw-r--r--ospfd/ospf_vty.c32
-rw-r--r--pathd/path_cli.c9
-rw-r--r--tests/lib/cli/test_cli.c4
-rw-r--r--tests/lib/cli/test_cli.in17
-rw-r--r--tests/lib/cli/test_cli.refout.in96
-rw-r--r--tests/lib/test_nexthop.c6
-rw-r--r--tests/topotests/bgp_default_route_route_map_match_set/test_bgp_default-originate_route-map_match_set.py8
-rw-r--r--tests/topotests/bgp_evpn_overlay_index_gateway/host2/zebra.conf2
-rwxr-xr-xtests/topotests/conftest.py70
-rw-r--r--tests/topotests/example_test/r1/zebra.conf8
-rw-r--r--tests/topotests/example_test/r2/zebra.conf4
-rw-r--r--tests/topotests/example_test/test_template.py140
-rw-r--r--tests/topotests/lib/micronet.py12
-rw-r--r--tests/topotests/lib/topotest.py12
-rw-r--r--tests/zebra/test_lm_plugin.c6
-rw-r--r--tools/permutations.c16
-rw-r--r--zebra/router-id.c15
-rw-r--r--zebra/zapi_msg.c17
-rw-r--r--zebra/zebra_evpn_neigh.c2
-rw-r--r--zebra/zebra_vty.c14
55 files changed, 697 insertions, 321 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index f1c953f21d..eeb0ac5c6a 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -691,6 +691,8 @@ unsigned int attrhash_key_make(const void *p)
key = jhash(attr->mp_nexthop_local.s6_addr, IPV6_MAX_BYTELEN, key);
MIX3(attr->nh_ifindex, attr->nh_lla_ifindex, attr->distance);
MIX(attr->rmap_table_id);
+ MIX(attr->nh_type);
+ MIX(attr->bh_type);
return key;
}
@@ -747,7 +749,9 @@ bool attrhash_cmp(const void *p1, const void *p2)
&& attr1->distance == attr2->distance
&& srv6_l3vpn_same(attr1->srv6_l3vpn, attr2->srv6_l3vpn)
&& srv6_vpn_same(attr1->srv6_vpn, attr2->srv6_vpn)
- && attr1->srte_color == attr2->srte_color)
+ && attr1->srte_color == attr2->srte_color
+ && attr1->nh_type == attr2->nh_type
+ && attr1->bh_type == attr2->bh_type)
return true;
}
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index a583581030..6c49cf509f 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -307,6 +307,12 @@ struct attr {
/* EVPN DF preference and algorithm for DF election on local ESs */
uint16_t df_pref;
uint8_t df_alg;
+
+ /* Nexthop type */
+ enum nexthop_types_t nh_type;
+
+ /* If NEXTHOP_TYPE_BLACKHOLE, then blackhole type */
+ enum blackhole_type bh_type;
};
/* rmap_change_flags definition */
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index 2bda5dbf9a..867efb6099 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -396,8 +396,6 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf,
originator_ip, sizeof(originator_ip)));
json_object_string_add(json, "advertiseGatewayMacip", "n/a");
json_object_string_add(json, "advertiseSviMacIp", "n/a");
- json_object_to_json_string_ext(json,
- JSON_C_TO_STRING_NOSLASHESCAPE);
json_object_string_add(json, "advertisePip",
bgp_vrf->evpn_info->advertise_pip ?
"Enabled" : "Disabled");
@@ -967,8 +965,6 @@ static void show_l3vni_entry(struct vty *vty, struct bgp *bgp,
json_object_string_add(json_vni, "advertiseGatewayMacip",
"n/a");
json_object_string_add(json_vni, "advertiseSviMacIp", "n/a");
- json_object_to_json_string_ext(json_vni,
- JSON_C_TO_STRING_NOSLASHESCAPE);
json_object_string_add(
json_vni, "advertisePip",
bgp->evpn_info->advertise_pip ? "Enabled" : "Disabled");
@@ -4413,8 +4409,11 @@ DEFUN(show_bgp_l2vpn_evpn_vni,
}
if (uj) {
- vty_out(vty, "%s\n", json_object_to_json_string_ext(
- json, JSON_C_TO_STRING_PRETTY));
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json,
+ JSON_C_TO_STRING_PRETTY
+ | JSON_C_TO_STRING_NOSLASHESCAPE));
json_object_free(json);
}
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index b164d710a5..db0ee58e72 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -8066,8 +8066,9 @@ DEFPY(aggregate_addressv6, aggregate_addressv6_cmd,
void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
const union g_addr *nexthop, ifindex_t ifindex,
enum nexthop_types_t nhtype, uint8_t distance,
- uint32_t metric, uint8_t type,
- unsigned short instance, route_tag_t tag)
+ enum blackhole_type bhtype, uint32_t metric,
+ uint8_t type, unsigned short instance,
+ route_tag_t tag)
{
struct bgp_path_info *new;
struct bgp_path_info *bpi;
@@ -8109,8 +8110,10 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL;
break;
}
+ attr.bh_type = bhtype;
break;
}
+ attr.nh_type = nhtype;
attr.nh_ifindex = ifindex;
attr.med = metric;
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index 75da2723e6..d052a3f408 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -642,8 +642,9 @@ extern bool bgp_maximum_prefix_overflow(struct peer *, afi_t, safi_t, int);
extern void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
const union g_addr *nexthop, ifindex_t ifindex,
enum nexthop_types_t nhtype, uint8_t distance,
- uint32_t metric, uint8_t type,
- unsigned short instance, route_tag_t tag);
+ enum blackhole_type bhtype, uint32_t metric,
+ uint8_t type, unsigned short instance,
+ route_tag_t tag);
extern void bgp_redistribute_delete(struct bgp *, struct prefix *, uint8_t,
unsigned short);
extern void bgp_redistribute_withdraw(struct bgp *, afi_t, int, unsigned short);
diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c
index 648456ac49..6a89a7195c 100644
--- a/bgpd/bgp_rpki.c
+++ b/bgpd/bgp_rpki.c
@@ -923,25 +923,25 @@ static int config_write(struct vty *vty)
#endif
case TCP:
tcp_config = cache->tr_config.tcp_config;
- vty_out(vty, " rpki cache %s%s%s %s ", tcp_config->host,
- tcp_config->bindaddr ? " source " : "",
- tcp_config->bindaddr ? tcp_config->bindaddr
- : "",
+ vty_out(vty, " rpki cache %s %s ", tcp_config->host,
tcp_config->port);
+ if (tcp_config->bindaddr)
+ vty_out(vty, "source %s ",
+ tcp_config->bindaddr);
break;
#if defined(FOUND_SSH)
case SSH:
ssh_config = cache->tr_config.ssh_config;
- vty_out(vty, " rpki cache %s%s%s %u %s %s %s ",
- ssh_config->host,
- ssh_config->bindaddr ? "source " : "",
- ssh_config->bindaddr ? ssh_config->bindaddr
- : "",
- ssh_config->port, ssh_config->username,
+ vty_out(vty, " rpki cache %s %u %s %s %s ",
+ ssh_config->host, ssh_config->port,
+ ssh_config->username,
ssh_config->client_privkey_path,
ssh_config->server_hostkey_path != NULL
? ssh_config->server_hostkey_path
: " ");
+ if (ssh_config->bindaddr)
+ vty_out(vty, "source %s ",
+ ssh_config->bindaddr);
break;
#endif
default:
@@ -1067,19 +1067,18 @@ DEFUN (no_rpki_retry_interval,
}
DEFPY(rpki_cache, rpki_cache_cmd,
- "rpki cache <A.B.C.D|WORD> [source <A.B.C.D>$bindaddr] "
- "<TCPPORT|(1-65535)$sshport SSH_UNAME SSH_PRIVKEY SSH_PUBKEY [SERVER_PUBKEY]> preference (1-255)",
+ "rpki cache <A.B.C.D|WORD> <TCPPORT|(1-65535)$sshport SSH_UNAME SSH_PRIVKEY SSH_PUBKEY [SERVER_PUBKEY]> [source <A.B.C.D>$bindaddr] preference (1-255)",
RPKI_OUTPUT_STRING
"Install a cache server to current group\n"
"IP address of cache server\n Hostname of cache server\n"
- "Configure source IP address of RPKI connection\n"
- "Define a Source IP Address\n"
"TCP port number\n"
"SSH port number\n"
"SSH user name\n"
"Path to own SSH private key\n"
"Path to own SSH public key\n"
"Path to Public key of cache server\n"
+ "Configure source IP address of RPKI connection\n"
+ "Define a Source IP Address\n"
"Preference of the cache server\n"
"Preference value\n")
{
diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c
index 9c2288cba3..3b7ee8b0b6 100644
--- a/bgpd/bgp_updgrp_adv.c
+++ b/bgpd/bgp_updgrp_adv.c
@@ -812,6 +812,10 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw)
}
if (peer->default_rmap[afi][safi].name) {
+ struct bgp_path_info tmp_pi = {0};
+
+ tmp_pi.peer = bgp->peer_self;
+
SET_FLAG(bgp->peer_self->rmap_type, PEER_RMAP_TYPE_DEFAULT);
/* Iterate over the RIB to see if we can announce
@@ -825,24 +829,16 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw)
for (pi = bgp_dest_get_bgp_path_info(dest); pi;
pi = pi->next) {
- struct attr tmp_attr;
- struct bgp_path_info tmp_pi;
- struct bgp_path_info_extra tmp_pie;
+ struct attr tmp_attr = attr;
- tmp_attr = *pi->attr;
- tmp_attr.aspath = attr.aspath;
+ tmp_pi.attr = &tmp_attr;
- prep_for_rmap_apply(&tmp_pi, &tmp_pie, dest, pi,
- pi->peer, &tmp_attr);
-
- ret = route_map_apply(
+ ret = route_map_apply_ext(
peer->default_rmap[afi][safi].map,
- bgp_dest_get_prefix(dest), &tmp_pi);
+ bgp_dest_get_prefix(dest), pi, &tmp_pi);
if (ret == RMAP_DENYMATCH) {
- /* The aspath belongs to 'attr' */
- tmp_attr.aspath = NULL;
- bgp_attr_flush(&tmp_attr);
+ bgp_attr_undup(&tmp_attr, &attr);
continue;
} else {
new_attr = bgp_attr_intern(&tmp_attr);
@@ -939,6 +935,8 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw)
subgroup_default_update_packet(subgrp, new_attr, from);
}
}
+
+ aspath_unintern(&attr.aspath);
}
/*
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 6e427c0b7c..2f9b8b86cf 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -9974,21 +9974,12 @@ static void bgp_show_failed_summary(struct vty *vty, struct bgp *bgp,
}
}
-/* If the peer's description includes whitespaces
- * then return the first occurrence. Also strip description
- * to the given size if needed.
- */
+/* Strip peer's description to the given size. */
static char *bgp_peer_description_stripped(char *desc, uint32_t size)
{
static char stripped[BUFSIZ];
- char *pnt;
uint32_t len = size > strlen(desc) ? strlen(desc) : size;
- pnt = strchr(desc, ' ');
- if (pnt)
- len = size > (uint32_t)(pnt - desc) ? (uint32_t)(pnt - desc)
- : size;
-
strlcpy(stripped, desc, len + 1);
return stripped;
@@ -10020,7 +10011,15 @@ static bool bgp_show_summary_is_peer_filtered(struct peer *peer,
return false;
}
-/* Show BGP peer's summary information. */
+/* Show BGP peer's summary information.
+ *
+ * Peer's description is stripped according to if `wide` option is given
+ * or not.
+ *
+ * When adding new columns to `show bgp summary` output, please make
+ * sure `Desc` is the lastest column to show because it can contain
+ * whitespaces and the whole output will be tricky.
+ */
static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
struct peer *fpeer, int as_type, as_t as,
uint16_t show_flags)
@@ -10685,6 +10684,9 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
vty_out(vty, " %8u", 0);
}
+ /* Make sure `Desc` column is the lastest in
+ * the output.
+ */
if (peer->desc)
vty_out(vty, " %s",
bgp_peer_description_stripped(
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 5ef49e5108..b0d0c844f3 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -472,8 +472,9 @@ static int bgp_interface_vrf_update(ZAPI_CALLBACK_ARGS)
static int zebra_read_route(ZAPI_CALLBACK_ARGS)
{
enum nexthop_types_t nhtype;
+ enum blackhole_type bhtype = BLACKHOLE_UNSPEC;
struct zapi_route api;
- union g_addr nexthop;
+ union g_addr nexthop = {};
ifindex_t ifindex;
int add, i;
struct bgp *bgp;
@@ -494,10 +495,16 @@ static int zebra_read_route(ZAPI_CALLBACK_ARGS)
&& IN6_IS_ADDR_LINKLOCAL(&api.prefix.u.prefix6))
return 0;
- nexthop = api.nexthops[0].gate;
ifindex = api.nexthops[0].ifindex;
nhtype = api.nexthops[0].type;
+ /* api_nh structure has union of gate and bh_type */
+ if (nhtype == NEXTHOP_TYPE_BLACKHOLE) {
+ /* bh_type is only applicable if NEXTHOP_TYPE_BLACKHOLE*/
+ bhtype = api.nexthops[0].bh_type;
+ } else
+ nexthop = api.nexthops[0].gate;
+
add = (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD);
if (add) {
/*
@@ -517,8 +524,8 @@ static int zebra_read_route(ZAPI_CALLBACK_ARGS)
/* Now perform the add/update. */
bgp_redistribute_add(bgp, &api.prefix, &nexthop, ifindex,
- nhtype, api.distance, api.metric, api.type,
- api.instance, api.tag);
+ nhtype, bhtype, api.distance, api.metric,
+ api.type, api.instance, api.tag);
} else {
bgp_redistribute_delete(bgp, &api.prefix, api.type,
api.instance);
@@ -1076,8 +1083,10 @@ static bool update_ipv4nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp,
* a VRF (which are programmed as onlink on l3-vni SVI) as well as
* connected routes leaked into a VRF.
*/
- if (is_evpn) {
-
+ if (attr->nh_type == NEXTHOP_TYPE_BLACKHOLE) {
+ api_nh->type = attr->nh_type;
+ api_nh->bh_type = attr->bh_type;
+ } else if (is_evpn) {
/*
* If the nexthop is EVPN overlay index gateway IP,
* treat the nexthop as NEXTHOP_TYPE_IPV4
@@ -1090,8 +1099,7 @@ static bool update_ipv4nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp,
SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK);
api_nh->ifindex = nh_bgp->l3vni_svi_ifindex;
}
- } else if (nh_othervrf &&
- api_nh->gate.ipv4.s_addr == INADDR_ANY) {
+ } else if (nh_othervrf && api_nh->gate.ipv4.s_addr == INADDR_ANY) {
api_nh->type = NEXTHOP_TYPE_IFINDEX;
api_nh->ifindex = attr->nh_ifindex;
} else
@@ -1113,8 +1121,10 @@ static bool update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp,
attr = pi->attr;
api_nh->vrf_id = nh_bgp->vrf_id;
- if (is_evpn) {
-
+ if (attr->nh_type == NEXTHOP_TYPE_BLACKHOLE) {
+ api_nh->type = attr->nh_type;
+ api_nh->bh_type = attr->bh_type;
+ } else if (is_evpn) {
/*
* If the nexthop is EVPN overlay index gateway IP,
* treat the nexthop as NEXTHOP_TYPE_IPV4
@@ -1169,7 +1179,8 @@ static bool update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp,
api_nh->ifindex = 0;
}
}
- if (nexthop)
+ /* api_nh structure has union of gate and bh_type */
+ if (nexthop && api_nh->type != NEXTHOP_TYPE_BLACKHOLE)
api_nh->gate.ipv6 = *nexthop;
return true;
diff --git a/doc/developer/cli.rst b/doc/developer/cli.rst
index edabe61d92..a24a4ecb7e 100644
--- a/doc/developer/cli.rst
+++ b/doc/developer/cli.rst
@@ -139,6 +139,7 @@ by the parser.
selector: "<" `selector_seq_seq` ">" `varname_token`
: "{" `selector_seq_seq` "}" `varname_token`
: "[" `selector_seq_seq` "]" `varname_token`
+ : "![" `selector_seq_seq` "]" `varname_token`
selector_seq_seq: `selector_seq_seq` "|" `selector_token_seq`
: `selector_token_seq`
selector_token_seq: `selector_token_seq` `selector_token`
@@ -218,6 +219,10 @@ one-or-more selection and repetition.
provide mutual exclusion. User input matches at most one option.
- ``[square brackets]`` -- Contains sequences of tokens that can be omitted.
``[<a|b>]`` can be shortened to ``[a|b]``.
+- ``![exclamation square brackets]`` -- same as ``[square brackets]``, but
+ only allow skipping the contents if the command input starts with ``no``.
+ (For cases where the positive command needs a parameter, but the parameter
+ is optional for the negative case.)
- ``{curly|braces}`` -- similar to angle brackets, but instead of mutual
exclusion, curly braces indicate that one or more of the pipe-separated
sequences may be provided in any order.
diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst
index fa6a1ba660..c52d210ee5 100644
--- a/doc/developer/topotests.rst
+++ b/doc/developer/topotests.rst
@@ -983,22 +983,20 @@ Writing Tests
"""""""""""""
Test topologies should always be bootstrapped from
-:file:`tests/topotests/example-test/test_template.py` because it contains
+:file:`tests/topotests/example_test/test_template.py` because it contains
important boilerplate code that can't be avoided, like:
Example:
.. code:: py
- # For all registered routers, load the zebra configuration file
- CWD = os.path.dirname(os.path.realpath(__file__))
- for rname, router in router_list.items():
- router.load_config(
- TopoRouter.RD_ZEBRA,
- os.path.join(CWD, '{}/zebra.conf'.format(rname))
- )
- # os.path.join() joins the CWD string with arguments adding the necessary
- # slashes ('/'). Arguments must not begin with '/'.
+ # For all routers arrange for:
+ # - starting zebra using config file from <rtrname>/zebra.conf
+ # - starting ospfd using an empty config file.
+ for rname, router in router_list.items():
+ router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf")
+ router.load_config(TopoRouter.RD_OSPF)
+
- The topology definition or build function
@@ -1013,27 +1011,31 @@ Example:
# topology build code
...
-- pytest ``setup_module()`` and ``teardown_module()`` to start the topology
+- pytest setup/teardown fixture to start the topology and supply `tgen` argument
+ to tests.
.. code:: py
- def setup_module(module):
+
+ @pytest.fixture(scope="module")
+ def tgen(request):
+ "Setup/Teardown the environment and provide tgen argument to tests"
+
tgen = Topogen(topodef, module.__name__)
# or
tgen = Topogen(build_topo, module.__name__)
- tgen.start_topology('debug')
+ ...
- def teardown_module(_m):
- tgen = get_topogen()
- tgen.stop_topology()
+ # Start and configure the router daemons
+ tgen.start_router()
-- ``__main__`` initialization code (to support running the script directly)
+ # Provide tgen as argument to each test function
+ yield tgen
-.. code:: py
+ # Teardown after last test runs
+ tgen.stop_topology()
- if __name__ == '__main__':
- sys.exit(pytest.main(["-s"]))
Requirements:
diff --git a/doc/user/rpki.rst b/doc/user/rpki.rst
index 8d836bfc4b..235df56528 100644
--- a/doc/user/rpki.rst
+++ b/doc/user/rpki.rst
@@ -109,7 +109,7 @@ The following commands are independent of a specific cache server.
The following commands configure one or multiple cache servers.
-.. clicmd:: rpki cache (A.B.C.D|WORD) [source A.B.C.D] PORT [SSH_USERNAME] [SSH_PRIVKEY_PATH] [SSH_PUBKEY_PATH] [KNOWN_HOSTS_PATH] PREFERENCE
+.. clicmd:: rpki cache (A.B.C.D|WORD) PORT [SSH_USERNAME] [SSH_PRIVKEY_PATH] [SSH_PUBKEY_PATH] [KNOWN_HOSTS_PATH] [source A.B.C.D] PREFERENCE
Add a cache server to the socket. By default, the connection between router
@@ -120,9 +120,6 @@ The following commands are independent of a specific cache server.
A.B.C.D|WORD
Address of the cache server.
- source A.B.C.D
- Source address of the RPKI connection to access cache server.
-
PORT
Port number to connect to the cache server
@@ -143,6 +140,9 @@ The following commands are independent of a specific cache server.
on the configuration of the operating system environment, usually
:file:`~/.ssh/known_hosts`.
+ source A.B.C.D
+ Source address of the RPKI connection to access cache server.
+
.. _validating-bgp-updates:
diff --git a/isisd/isis_snmp.c b/isisd/isis_snmp.c
index d530faa151..c530eb9169 100644
--- a/isisd/isis_snmp.c
+++ b/isisd/isis_snmp.c
@@ -283,13 +283,6 @@ SNMP_LOCAL_VARIABLES
*
* 2. I could be replaced in unit test environment
*/
-#ifndef ISIS_SNMP_HAVE_TIME_FUNC
-static uint32_t isis_snmp_time(void)
-{
- return (uint32_t)time(NULL);
-}
-
-#endif
/* ISIS-MIB instances. */
static oid isis_oid[] = {ISIS_MIB};
@@ -2083,7 +2076,7 @@ static uint8_t *isis_snmp_find_circ(struct variable *v, oid *name,
struct isis_circuit *circuit;
uint32_t up_ticks;
uint32_t delta_ticks;
- uint32_t now_time;
+ time_t now_time;
int res;
*write_method = NULL;
@@ -2191,7 +2184,7 @@ static uint8_t *isis_snmp_find_circ(struct variable *v, oid *name,
return SNMP_INTEGER(0);
up_ticks = (uint32_t)netsnmp_get_agent_uptime();
- now_time = isis_snmp_time();
+ now_time = time(NULL);
if (circuit->last_uptime >= now_time)
return SNMP_INTEGER(up_ticks);
@@ -2501,11 +2494,11 @@ static uint8_t *isis_snmp_find_isadj(struct variable *v, oid *name,
oid *oid_idx;
size_t oid_idx_len;
int res;
- uint32_t val;
+ time_t val;
struct isis_adjacency *adj;
uint32_t up_ticks;
uint32_t delta_ticks;
- uint32_t now_time;
+ time_t now_time;
*write_method = NULL;
@@ -2577,7 +2570,7 @@ static uint8_t *isis_snmp_find_isadj(struct variable *v, oid *name,
* It seems that we want remaining timer
*/
if (adj->last_upd != 0) {
- val = isis_snmp_time();
+ val = time(NULL);
if (val < (adj->last_upd + adj->hold_time))
return SNMP_INTEGER(adj->last_upd
+ adj->hold_time - val);
@@ -2594,7 +2587,7 @@ static uint8_t *isis_snmp_find_isadj(struct variable *v, oid *name,
up_ticks = (uint32_t)netsnmp_get_agent_uptime();
- now_time = isis_snmp_time();
+ now_time = time(NULL);
if (adj->last_flap >= now_time)
return SNMP_INTEGER(up_ticks);
@@ -2853,7 +2846,7 @@ static int isis_snmp_trap_throttle(oid trap_id)
if (isis == NULL || !isis->snmp_notifications || !smux_enabled())
return 0;
- time_now = isis_snmp_time();
+ time_now = time(NULL);
if ((isis_snmp_trap_timestamp[trap_id] + 5) > time_now)
/* Throttle trap rate at 1 in 5 secs */
diff --git a/lib/command.c b/lib/command.c
index fcaf466c65..53aa064705 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -74,6 +74,7 @@ const struct message tokennames[] = {
item(JOIN_TKN),
item(START_TKN),
item(END_TKN),
+ item(NEG_ONLY_TKN),
{0},
};
/* clang-format on */
diff --git a/lib/command_graph.c b/lib/command_graph.c
index c6c3840455..15c8302e63 100644
--- a/lib/command_graph.c
+++ b/lib/command_graph.c
@@ -388,6 +388,7 @@ static void cmd_node_names(struct graph_node *gn, struct graph_node *join,
case START_TKN:
case JOIN_TKN:
+ case NEG_ONLY_TKN:
/* "<foo|bar> WORD" -> word is not "bar" or "foo" */
prevname = NULL;
break;
@@ -511,6 +512,9 @@ void cmd_graph_node_print_cb(struct graph_node *gn, struct buffer *buf)
case JOIN_TKN:
color = "#ddaaff";
break;
+ case NEG_ONLY_TKN:
+ color = "#ffddaa";
+ break;
case WORD_TKN:
color = "#ffffff";
break;
diff --git a/lib/command_graph.h b/lib/command_graph.h
index 2754dca67d..c20c9874c2 100644
--- a/lib/command_graph.h
+++ b/lib/command_graph.h
@@ -64,6 +64,7 @@ enum cmd_token_type {
JOIN_TKN, // marks subgraph end
START_TKN, // first token in line
END_TKN, // last token in line
+ NEG_ONLY_TKN, // filter token, match if "no ..." command
SPECIAL_TKN = FORK_TKN,
};
diff --git a/lib/command_lex.l b/lib/command_lex.l
index 9c096995f5..ec366ce7e1 100644
--- a/lib/command_lex.l
+++ b/lib/command_lex.l
@@ -82,6 +82,7 @@ RANGE \({NUMBER}[ ]?\-[ ]?{NUMBER}\)
{VARIABLE} {yylval->string = XSTRDUP(MTYPE_LEX, yytext); return VARIABLE;}
{WORD} {yylval->string = XSTRDUP(MTYPE_LEX, yytext); return WORD;}
{RANGE} {yylval->string = XSTRDUP(MTYPE_LEX, yytext); return RANGE;}
+!\[ {yylval->string = NULL; return EXCL_BRACKET;}
. {return yytext[0];}
%%
diff --git a/lib/command_match.c b/lib/command_match.c
index 5703510148..56a7ae422b 100644
--- a/lib/command_match.c
+++ b/lib/command_match.c
@@ -42,7 +42,7 @@ DEFINE_MTYPE_STATIC(LIB, CMD_MATCHSTACK, "Command Match Stack");
/* matcher helper prototypes */
static int add_nexthops(struct list *, struct graph_node *,
- struct graph_node **, size_t);
+ struct graph_node **, size_t, bool);
static enum matcher_rv command_match_r(struct graph_node *, vector,
unsigned int, struct graph_node **,
@@ -79,6 +79,13 @@ static enum match_type match_variable(struct cmd_token *, const char *);
static enum match_type match_mac(const char *, bool);
+static bool is_neg(vector vline, size_t idx)
+{
+ if (idx >= vector_active(vline))
+ return false;
+ return !strcmp(vector_slot(vline, idx), "no");
+}
+
enum matcher_rv command_match(struct graph *cmdgraph, vector vline,
struct list **argv, const struct cmd_element **el)
{
@@ -248,7 +255,7 @@ static enum matcher_rv command_match_r(struct graph_node *start, vector vline,
// get all possible nexthops
struct list *next = list_new();
- add_nexthops(next, start, NULL, 0);
+ add_nexthops(next, start, NULL, 0, is_neg(vline, 1));
// determine the best match
for (ALL_LIST_ELEMENTS_RO(next, ln, gn)) {
@@ -349,6 +356,7 @@ enum matcher_rv command_complete(struct graph *graph, vector vline,
{
// pointer to next input token to match
char *input_token;
+ bool neg = is_neg(vline, 0);
struct list *
current =
@@ -363,7 +371,7 @@ enum matcher_rv command_complete(struct graph *graph, vector vline,
// add all children of start node to list
struct graph_node *start = vector_slot(graph->nodes, 0);
- add_nexthops(next, start, &start, 0);
+ add_nexthops(next, start, &start, 0, neg);
unsigned int idx;
for (idx = 0; idx < vector_active(vline) && next->count > 0; idx++) {
@@ -428,7 +436,7 @@ enum matcher_rv command_complete(struct graph *graph, vector vline,
listnode_add(next, newstack);
} else if (matchtype >= minmatch)
add_nexthops(next, gstack[0], gstack,
- idx + 1);
+ idx + 1, neg);
break;
default:
trace_matcher("no_match\n");
@@ -478,7 +486,7 @@ enum matcher_rv command_complete(struct graph *graph, vector vline,
* output, instead of direct node pointers!
*/
static int add_nexthops(struct list *list, struct graph_node *node,
- struct graph_node **stack, size_t stackpos)
+ struct graph_node **stack, size_t stackpos, bool neg)
{
int added = 0;
struct graph_node *child;
@@ -494,8 +502,13 @@ static int add_nexthops(struct list *list, struct graph_node *node,
if (j != stackpos)
continue;
}
+
+ if (token->type == NEG_ONLY_TKN && !neg)
+ continue;
+
if (token->type >= SPECIAL_TKN && token->type != END_TKN) {
- added += add_nexthops(list, child, stack, stackpos);
+ added +=
+ add_nexthops(list, child, stack, stackpos, neg);
} else {
if (stack) {
nextstack = XMALLOC(
diff --git a/lib/command_parse.y b/lib/command_parse.y
index f5e42cc304..3e2cdc79af 100644
--- a/lib/command_parse.y
+++ b/lib/command_parse.y
@@ -105,6 +105,9 @@
%token <string> MAC
%token <string> MAC_PREFIX
+/* special syntax, value is irrelevant */
+%token <string> EXCL_BRACKET
+
/* union types for parsed rules */
%type <node> start
%type <node> literal_token
@@ -372,6 +375,19 @@ selector: '[' selector_seq_seq ']' varname_token
}
;
+/* ![option] productions */
+selector: EXCL_BRACKET selector_seq_seq ']' varname_token
+{
+ struct graph_node *neg_only = new_token_node (ctx, NEG_ONLY_TKN, NULL, NULL);
+
+ $$ = $2;
+ graph_add_edge ($$.start, neg_only);
+ graph_add_edge (neg_only, $$.end);
+ cmd_token_varname_set ($2.end->data, $4);
+ XFREE (MTYPE_LEX, $4);
+}
+;
+
%%
#undef scanner
diff --git a/lib/command_py.c b/lib/command_py.c
index 7f19008fbf..90344ae1e5 100644
--- a/lib/command_py.c
+++ b/lib/command_py.c
@@ -197,21 +197,30 @@ static PyObject *graph_to_pyobj(struct wrap_graph *wgraph,
if (gn->data) {
struct cmd_token *tok = gn->data;
switch (tok->type) {
-#define item(x) case x: wrap->type = #x; break;
- item(WORD_TKN) // words
- item(VARIABLE_TKN) // almost anything
- item(RANGE_TKN) // integer range
- item(IPV4_TKN) // IPV4 addresses
- item(IPV4_PREFIX_TKN) // IPV4 network prefixes
- item(IPV6_TKN) // IPV6 prefixes
- item(IPV6_PREFIX_TKN) // IPV6 network prefixes
- item(MAC_TKN) // MAC address
- item(MAC_PREFIX_TKN) // MAC address with mask
-
- /* plumbing types */
- item(FORK_TKN) item(JOIN_TKN) item(START_TKN)
- item(END_TKN) default
- : wrap->type = "???";
+#define item(x) \
+ case x: \
+ wrap->type = #x; \
+ break /* no semicolon */
+
+ item(WORD_TKN); // words
+ item(VARIABLE_TKN); // almost anything
+ item(RANGE_TKN); // integer range
+ item(IPV4_TKN); // IPV4 addresses
+ item(IPV4_PREFIX_TKN); // IPV4 network prefixes
+ item(IPV6_TKN); // IPV6 prefixes
+ item(IPV6_PREFIX_TKN); // IPV6 network prefixes
+ item(MAC_TKN); // MAC address
+ item(MAC_PREFIX_TKN); // MAC address with mask
+
+ /* plumbing types */
+ item(FORK_TKN);
+ item(JOIN_TKN);
+ item(START_TKN);
+ item(END_TKN);
+ item(NEG_ONLY_TKN);
+#undef item
+ default:
+ wrap->type = "???";
}
wrap->deprecated = (tok->attr == CMD_ATTR_DEPRECATED);
diff --git a/lib/nexthop.c b/lib/nexthop.c
index 23e3a2b733..98409c76c5 100644
--- a/lib/nexthop.c
+++ b/lib/nexthop.c
@@ -519,12 +519,13 @@ struct nexthop *nexthop_from_ipv6_ifindex(const struct in6_addr *ipv6,
return nexthop;
}
-struct nexthop *nexthop_from_blackhole(enum blackhole_type bh_type)
+struct nexthop *nexthop_from_blackhole(enum blackhole_type bh_type,
+ vrf_id_t nh_vrf_id)
{
struct nexthop *nexthop;
nexthop = nexthop_new();
- nexthop->vrf_id = VRF_DEFAULT;
+ nexthop->vrf_id = nh_vrf_id;
nexthop->type = NEXTHOP_TYPE_BLACKHOLE;
nexthop->bh_type = bh_type;
diff --git a/lib/nexthop.h b/lib/nexthop.h
index dd65509aec..320b46315e 100644
--- a/lib/nexthop.h
+++ b/lib/nexthop.h
@@ -182,7 +182,8 @@ struct nexthop *nexthop_from_ipv6(const struct in6_addr *ipv6,
vrf_id_t vrf_id);
struct nexthop *nexthop_from_ipv6_ifindex(const struct in6_addr *ipv6,
ifindex_t ifindex, vrf_id_t vrf_id);
-struct nexthop *nexthop_from_blackhole(enum blackhole_type bh_type);
+struct nexthop *nexthop_from_blackhole(enum blackhole_type bh_type,
+ vrf_id_t nh_vrf_id);
/*
* Hash a nexthop. Suitable for use with hash tables.
diff --git a/lib/routemap.c b/lib/routemap.c
index 594dcf97cb..5c60b7d1c6 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -2488,8 +2488,9 @@ void route_map_notify_pentry_dependencies(const char *affected_name,
We need to make sure our route-map processing matches the above
*/
-route_map_result_t route_map_apply(struct route_map *map,
- const struct prefix *prefix, void *object)
+route_map_result_t route_map_apply_ext(struct route_map *map,
+ const struct prefix *prefix,
+ void *match_object, void *set_object)
{
static int recursion = 0;
enum route_map_cmd_result_t match_ret = RMAP_NOMATCH;
@@ -2516,7 +2517,7 @@ route_map_result_t route_map_apply(struct route_map *map,
if ((!map->optimization_disabled)
&& (map->ipv4_prefix_table || map->ipv6_prefix_table)) {
- index = route_map_get_index(map, prefix, object,
+ index = route_map_get_index(map, prefix, match_object,
(uint8_t *)&match_ret);
if (index) {
index->applied++;
@@ -2551,7 +2552,7 @@ route_map_result_t route_map_apply(struct route_map *map,
index->applied++;
/* Apply this index. */
match_ret = route_map_apply_match(&index->match_list,
- prefix, object);
+ prefix, match_object);
if (rmap_debug) {
zlog_debug(
"Route-map: %s, sequence: %d, prefix: %pFX, result: %s",
@@ -2610,7 +2611,7 @@ route_map_result_t route_map_apply(struct route_map *map,
* return code.
*/
(void)(*set->cmd->func_apply)(
- set->value, prefix, object);
+ set->value, prefix, set_object);
/* Call another route-map if available */
if (index->nextrm) {
@@ -2622,8 +2623,10 @@ route_map_result_t route_map_apply(struct route_map *map,
jump to it */
{
recursion++;
- ret = route_map_apply(
- nextrm, prefix, object);
+ ret = route_map_apply_ext(
+ nextrm, prefix,
+ match_object,
+ set_object);
recursion--;
}
diff --git a/lib/routemap.h b/lib/routemap.h
index b356dbf52e..2c8eb24537 100644
--- a/lib/routemap.h
+++ b/lib/routemap.h
@@ -443,9 +443,12 @@ extern struct route_map *route_map_lookup_by_name(const char *name);
struct route_map *route_map_lookup_warn_noexist(struct vty *vty, const char *name);
/* Apply route map to the object. */
-extern route_map_result_t route_map_apply(struct route_map *map,
- const struct prefix *prefix,
- void *object);
+extern route_map_result_t route_map_apply_ext(struct route_map *map,
+ const struct prefix *prefix,
+ void *match_object,
+ void *set_object);
+#define route_map_apply(map, prefix, object) \
+ route_map_apply_ext(map, prefix, object, object)
extern void route_map_add_hook(void (*func)(const char *));
extern void route_map_delete_hook(void (*func)(const char *));
diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c
index aa85475678..fe1845907f 100644
--- a/ospf6d/ospf6_abr.c
+++ b/ospf6d/ospf6_abr.c
@@ -1201,9 +1201,16 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
__func__, &prefix, listcount(old->paths));
}
for (old_route = old; old_route; old_route = old_route->next) {
- if (!ospf6_route_is_same(old_route, route) ||
- (old_route->type != route->type) ||
- (old_route->path.type != route->path.type))
+
+ /* The route linked-list is grouped in batches of prefix.
+ * If the new prefix is not the same as the one of interest
+ * then we have walked over the end of the batch and so we
+ * should break rather than continuing unnecessarily.
+ */
+ if (!ospf6_route_is_same(old_route, route))
+ break;
+ if ((old_route->type != route->type)
+ || (old_route->path.type != route->path.type))
continue;
if ((ospf6_route_cmp(route, old_route) != 0)) {
diff --git a/ospf6d/ospf6_area.h b/ospf6d/ospf6_area.h
index b2a275d745..aed9589bfb 100644
--- a/ospf6d/ospf6_area.h
+++ b/ospf6d/ospf6_area.h
@@ -149,16 +149,18 @@ extern void area_id2str(char *buf, int len, uint32_t area_id, int area_id_fmt);
extern int ospf6_area_cmp(void *va, void *vb);
-extern struct ospf6_area *ospf6_area_create(uint32_t, struct ospf6 *, int);
-extern void ospf6_area_delete(struct ospf6_area *);
-extern struct ospf6_area *ospf6_area_lookup(uint32_t, struct ospf6 *);
+extern struct ospf6_area *ospf6_area_create(uint32_t area_id,
+ struct ospf6 *ospf6, int df);
+extern void ospf6_area_delete(struct ospf6_area *oa);
+extern struct ospf6_area *ospf6_area_lookup(uint32_t area_id,
+ struct ospf6 *ospf6);
extern struct ospf6_area *ospf6_area_lookup_by_area_id(uint32_t area_id);
extern void ospf6_area_stub_unset(struct ospf6 *ospf6, struct ospf6_area *area);
-extern void ospf6_area_enable(struct ospf6_area *);
-extern void ospf6_area_disable(struct ospf6_area *);
+extern void ospf6_area_enable(struct ospf6_area *oa);
+extern void ospf6_area_disable(struct ospf6_area *oa);
-extern void ospf6_area_show(struct vty *, struct ospf6_area *,
+extern void ospf6_area_show(struct vty *vty, struct ospf6_area *oa,
json_object *json_areas, bool use_json);
extern void ospf6_area_plist_update(struct prefix_list *plist, int add);
diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c
index b5bf81c213..90c9fdf23a 100644
--- a/ospf6d/ospf6_asbr.c
+++ b/ospf6d/ospf6_asbr.c
@@ -262,8 +262,14 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
next_route = old_route->next;
- if (!ospf6_route_is_same(old_route, route)
- || (old_route->path.type != route->path.type))
+ /* The route linked-list is grouped in batches of prefix.
+ * If the new prefix is not the same as the one of interest
+ * then we have walked over the end of the batch and so we
+ * should break rather than continuing unnecessarily.
+ */
+ if (!ospf6_route_is_same(old_route, route))
+ break;
+ if (old_route->path.type != route->path.type)
continue;
/* Current and New route has same origin,
@@ -367,11 +373,14 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
/* Add new route */
for (old_route = old; old_route; old_route = old_route->next) {
- /* Current and New Route prefix or route type
- * is not same skip this current node.
+ /* The route linked-list is grouped in batches of prefix.
+ * If the new prefix is not the same as the one of interest
+ * then we have walked over the end of the batch and so we
+ * should break rather than continuing unnecessarily.
*/
- if (!ospf6_route_is_same(old_route, route)
- || (old_route->path.type != route->path.type))
+ if (!ospf6_route_is_same(old_route, route))
+ break;
+ if (old_route->path.type != route->path.type)
continue;
/* Old Route and New Route have Equal Cost, Merge NHs */
diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h
index ccdf8b1c8f..ee24b989bd 100644
--- a/ospf6d/ospf6_interface.h
+++ b/ospf6d/ospf6_interface.h
@@ -193,23 +193,23 @@ extern void ospf6_interface_stop(struct ospf6_interface *oi);
extern struct ospf6_interface *
ospf6_interface_lookup_by_ifindex(ifindex_t, vrf_id_t vrf_id);
-extern struct ospf6_interface *ospf6_interface_create(struct interface *);
-extern void ospf6_interface_delete(struct ospf6_interface *);
+extern struct ospf6_interface *ospf6_interface_create(struct interface *ifp);
+extern void ospf6_interface_delete(struct ospf6_interface *oi);
-extern void ospf6_interface_enable(struct ospf6_interface *);
-extern void ospf6_interface_disable(struct ospf6_interface *);
+extern void ospf6_interface_enable(struct ospf6_interface *oi);
+extern void ospf6_interface_disable(struct ospf6_interface *oi);
-extern void ospf6_interface_state_update(struct interface *);
-extern void ospf6_interface_connected_route_update(struct interface *);
+extern void ospf6_interface_state_update(struct interface *ifp);
+extern void ospf6_interface_connected_route_update(struct interface *ifp);
extern struct in6_addr *
ospf6_interface_get_global_address(struct interface *ifp);
/* interface event */
-extern int interface_up(struct thread *);
-extern int interface_down(struct thread *);
-extern int wait_timer(struct thread *);
-extern int backup_seen(struct thread *);
-extern int neighbor_change(struct thread *);
+extern int interface_up(struct thread *thread);
+extern int interface_down(struct thread *thread);
+extern int wait_timer(struct thread *thread);
+extern int backup_seen(struct thread *thread);
+extern int neighbor_change(struct thread *thread);
extern void ospf6_interface_init(void);
extern void ospf6_interface_clear(struct interface *ifp);
diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c
index e4db8f3a02..06a950156b 100644
--- a/ospf6d/ospf6_intra.c
+++ b/ospf6d/ospf6_intra.c
@@ -1470,8 +1470,14 @@ void ospf6_intra_prefix_route_ecmp_path(struct ospf6_area *oa,
for (old_route = old; old_route; old_route = old_route->next) {
bool route_updated = false;
- if (!ospf6_route_is_same(old_route, route) ||
- (old_route->path.type != route->path.type))
+ /* The route linked-list is grouped in batches of prefix.
+ * If the new prefix is not the same as the one of interest
+ * then we have walked over the end of the batch and so we
+ * should break rather than continuing unnecessarily.
+ */
+ if (!ospf6_route_is_same(old_route, route))
+ break;
+ if (old_route->path.type != route->path.type)
continue;
/* Current and New route has same origin,
@@ -1569,8 +1575,14 @@ void ospf6_intra_prefix_route_ecmp_path(struct ospf6_area *oa,
for (old_route = old; old_route; old_route = old_route->next) {
- if (!ospf6_route_is_same(old_route, route) ||
- (old_route->path.type != route->path.type))
+ /* The route linked-list is grouped in batches of prefix.
+ * If the new prefix is not the same as the one of interest
+ * then we have walked over the end of the batch and so we
+ * should break rather than continuing unnecessarily.
+ */
+ if (!ospf6_route_is_same(old_route, route))
+ break;
+ if (old_route->path.type != route->path.type)
continue;
/* Old Route and New Route have Equal Cost, Merge NHs */
diff --git a/ospf6d/ospf6_intra.h b/ospf6d/ospf6_intra.h
index 9c29681dee..4031ffe689 100644
--- a/ospf6d/ospf6_intra.h
+++ b/ospf6d/ospf6_intra.h
@@ -221,11 +221,11 @@ extern char *ospf6_network_lsdesc_lookup(uint32_t router_id,
struct ospf6_lsa *lsa);
extern int ospf6_router_is_stub_router(struct ospf6_lsa *lsa);
-extern int ospf6_router_lsa_originate(struct thread *);
-extern int ospf6_network_lsa_originate(struct thread *);
-extern int ospf6_link_lsa_originate(struct thread *);
-extern int ospf6_intra_prefix_lsa_originate_transit(struct thread *);
-extern int ospf6_intra_prefix_lsa_originate_stub(struct thread *);
+extern int ospf6_router_lsa_originate(struct thread *thread);
+extern int ospf6_network_lsa_originate(struct thread *thread);
+extern int ospf6_link_lsa_originate(struct thread *thread);
+extern int ospf6_intra_prefix_lsa_originate_transit(struct thread *thread);
+extern int ospf6_intra_prefix_lsa_originate_stub(struct thread *thread);
extern void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa);
extern void ospf6_intra_prefix_lsa_remove(struct ospf6_lsa *lsa);
extern int ospf6_orig_as_external_lsa(struct thread *thread);
diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h
index a8ed9132dd..c271965fe7 100644
--- a/ospf6d/ospf6_lsa.h
+++ b/ospf6d/ospf6_lsa.h
@@ -231,10 +231,11 @@ extern int metric_type(struct ospf6 *ospf6, int type, uint8_t instance);
extern int metric_value(struct ospf6 *ospf6, int type, uint8_t instance);
extern int ospf6_lsa_is_differ(struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2);
extern int ospf6_lsa_is_changed(struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2);
-extern uint16_t ospf6_lsa_age_current(struct ospf6_lsa *);
-extern void ospf6_lsa_age_update_to_send(struct ospf6_lsa *, uint32_t);
-extern void ospf6_lsa_premature_aging(struct ospf6_lsa *);
-extern int ospf6_lsa_compare(struct ospf6_lsa *, struct ospf6_lsa *);
+extern uint16_t ospf6_lsa_age_current(struct ospf6_lsa *lsa);
+extern void ospf6_lsa_age_update_to_send(struct ospf6_lsa *lsa,
+ uint32_t transdelay);
+extern void ospf6_lsa_premature_aging(struct ospf6_lsa *lsa);
+extern int ospf6_lsa_compare(struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2);
extern char *ospf6_lsa_printbuf(struct ospf6_lsa *lsa, char *buf, int size);
extern void ospf6_lsa_header_print_raw(struct ospf6_lsa_header *header);
@@ -254,16 +255,16 @@ extern struct ospf6_lsa *ospf6_lsa_create(struct ospf6_lsa_header *header);
extern struct ospf6_lsa *
ospf6_lsa_create_headeronly(struct ospf6_lsa_header *header);
extern void ospf6_lsa_delete(struct ospf6_lsa *lsa);
-extern struct ospf6_lsa *ospf6_lsa_copy(struct ospf6_lsa *);
+extern struct ospf6_lsa *ospf6_lsa_copy(struct ospf6_lsa *lsa);
extern struct ospf6_lsa *ospf6_lsa_lock(struct ospf6_lsa *lsa);
extern struct ospf6_lsa *ospf6_lsa_unlock(struct ospf6_lsa *lsa);
-extern int ospf6_lsa_expire(struct thread *);
-extern int ospf6_lsa_refresh(struct thread *);
+extern int ospf6_lsa_expire(struct thread *thread);
+extern int ospf6_lsa_refresh(struct thread *thread);
-extern unsigned short ospf6_lsa_checksum(struct ospf6_lsa_header *);
-extern int ospf6_lsa_checksum_valid(struct ospf6_lsa_header *);
+extern unsigned short ospf6_lsa_checksum(struct ospf6_lsa_header *lsah);
+extern int ospf6_lsa_checksum_valid(struct ospf6_lsa_header *lsah);
extern int ospf6_lsa_prohibited_duration(uint16_t type, uint32_t id,
uint32_t adv_router, void *scope);
diff --git a/ospf6d/ospf6_neighbor.h b/ospf6d/ospf6_neighbor.h
index a229897226..30e044da4b 100644
--- a/ospf6d/ospf6_neighbor.h
+++ b/ospf6d/ospf6_neighbor.h
@@ -183,24 +183,24 @@ extern const char *const ospf6_neighbor_state_str[];
int ospf6_neighbor_cmp(void *va, void *vb);
void ospf6_neighbor_dbex_init(struct ospf6_neighbor *on);
-struct ospf6_neighbor *ospf6_neighbor_lookup(uint32_t,
- struct ospf6_interface *);
-struct ospf6_neighbor *ospf6_neighbor_create(uint32_t,
- struct ospf6_interface *);
-void ospf6_neighbor_delete(struct ospf6_neighbor *);
+struct ospf6_neighbor *ospf6_neighbor_lookup(uint32_t router_id,
+ struct ospf6_interface *oi);
+struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id,
+ struct ospf6_interface *oi);
+void ospf6_neighbor_delete(struct ospf6_neighbor *on);
/* Neighbor event */
-extern int hello_received(struct thread *);
-extern int twoway_received(struct thread *);
-extern int negotiation_done(struct thread *);
-extern int exchange_done(struct thread *);
-extern int loading_done(struct thread *);
-extern int adj_ok(struct thread *);
-extern int seqnumber_mismatch(struct thread *);
-extern int bad_lsreq(struct thread *);
-extern int oneway_received(struct thread *);
-extern int inactivity_timer(struct thread *);
-extern void ospf6_check_nbr_loading(struct ospf6_neighbor *);
+extern int hello_received(struct thread *thread);
+extern int twoway_received(struct thread *thread);
+extern int negotiation_done(struct thread *thread);
+extern int exchange_done(struct thread *thread);
+extern int loading_done(struct thread *thread);
+extern int adj_ok(struct thread *thread);
+extern int seqnumber_mismatch(struct thread *thread);
+extern int bad_lsreq(struct thread *thread);
+extern int oneway_received(struct thread *thread);
+extern int inactivity_timer(struct thread *thread);
+extern void ospf6_check_nbr_loading(struct ospf6_neighbor *on);
extern void ospf6_neighbor_init(void);
extern int config_write_ospf6_debug_neighbor(struct vty *vty);
diff --git a/ospf6d/ospf6_nssa.h b/ospf6d/ospf6_nssa.h
index 454bdd7fe2..631503edc6 100644
--- a/ospf6d/ospf6_nssa.h
+++ b/ospf6d/ospf6_nssa.h
@@ -52,11 +52,11 @@ int ospf6_area_nssa_unset(struct ospf6 *ospf6, struct ospf6_area *area);
int ospf6_area_nssa_set(struct ospf6 *ospf6, struct ospf6_area *area);
extern void ospf6_nssa_lsa_flush(struct ospf6 *ospf6, struct prefix_ipv6 *p);
-extern struct ospf6_lsa *ospf6_translated_nssa_refresh(struct ospf6_area *,
- struct ospf6_lsa *,
- struct ospf6_lsa *);
-extern struct ospf6_lsa *ospf6_translated_nssa_originate(struct ospf6_area *,
- struct ospf6_lsa *);
+extern struct ospf6_lsa *ospf6_translated_nssa_refresh(struct ospf6_area *oa,
+ struct ospf6_lsa *type7,
+ struct ospf6_lsa *type5);
+extern struct ospf6_lsa *
+ospf6_translated_nssa_originate(struct ospf6_area *oa, struct ospf6_lsa *type7);
extern void ospf6_asbr_nssa_redist_task(struct ospf6 *ospf6);
diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h
index 991720ec2e..54baaee638 100644
--- a/ospf6d/ospf6_route.h
+++ b/ospf6d/ospf6_route.h
@@ -343,7 +343,7 @@ extern int ospf6_route_get_first_nh_index(struct ospf6_route *route);
ospf6_add_nexthop(route->nh_list, ifindex, addr)
extern struct ospf6_route *ospf6_route_create(struct ospf6 *ospf6);
-extern void ospf6_route_delete(struct ospf6_route *);
+extern void ospf6_route_delete(struct ospf6_route *route);
extern struct ospf6_route *ospf6_route_copy(struct ospf6_route *route);
extern int ospf6_route_cmp(struct ospf6_route *ra, struct ospf6_route *rb);
@@ -384,8 +384,10 @@ extern void ospf6_route_show_detail(struct vty *vty, struct ospf6_route *route,
json_object *json, bool use_json);
-extern int ospf6_route_table_show(struct vty *, int, int, struct cmd_token **,
- struct ospf6_route_table *, bool use_json);
+extern int ospf6_route_table_show(struct vty *vty, int argc_start, int argc,
+ struct cmd_token **argv,
+ struct ospf6_route_table *table,
+ bool use_json);
extern int ospf6_linkstate_table_show(struct vty *vty, int idx_ipv4, int argc,
struct cmd_token **argv,
struct ospf6_route_table *table);
diff --git a/ospf6d/ospf6_zebra.h b/ospf6d/ospf6_zebra.h
index a3ccc3d38d..e25f6bf80d 100644
--- a/ospf6d/ospf6_zebra.h
+++ b/ospf6d/ospf6_zebra.h
@@ -54,20 +54,23 @@ extern void ospf6_zebra_redistribute(int, vrf_id_t vrf_id);
extern void ospf6_zebra_no_redistribute(int, vrf_id_t vrf_id);
#define ospf6_zebra_is_redistribute(type, vrf_id) \
vrf_bitmap_check(zclient->redist[AFI_IP6][type], vrf_id)
-extern void ospf6_zebra_init(struct thread_master *);
+extern void ospf6_zebra_init(struct thread_master *tm);
extern void ospf6_zebra_add_discard(struct ospf6_route *request,
struct ospf6 *ospf6);
extern void ospf6_zebra_delete_discard(struct ospf6_route *request,
struct ospf6 *ospf6);
-extern void ospf6_distance_reset(struct ospf6 *);
-extern uint8_t ospf6_distance_apply(struct prefix_ipv6 *, struct ospf6_route *,
- struct ospf6 *);
+extern void ospf6_distance_reset(struct ospf6 *ospf6);
+extern uint8_t ospf6_distance_apply(struct prefix_ipv6 *p,
+ struct ospf6_route * or,
+ struct ospf6 *ospf6);
-extern int ospf6_distance_set(struct vty *, struct ospf6 *, const char *,
- const char *, const char *);
-extern int ospf6_distance_unset(struct vty *, struct ospf6 *, const char *,
- const char *, const char *);
+extern int ospf6_distance_set(struct vty *vty, struct ospf6 *ospf6,
+ const char *distance_str, const char *ip_str,
+ const char *access_list_str);
+extern int ospf6_distance_unset(struct vty *vty, struct ospf6 *ospf6,
+ const char *distance_str, const char *ip_str,
+ const char *access_list_str);
extern int config_write_ospf6_debug_zebra(struct vty *vty);
extern void install_element_ospf6_debug_zebra(void);
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index 1d4aa65355..3ae9707f5f 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -10607,11 +10607,9 @@ static void show_ip_ospf_route_network(struct vty *vty, struct ospf *ospf,
prefix2str(&rn->p, buf1, sizeof(buf1));
- json_route = json_object_new_object();
if (json) {
+ json_route = json_object_new_object();
json_object_object_add(json, buf1, json_route);
- json_object_to_json_string_ext(
- json, JSON_C_TO_STRING_NOSLASHESCAPE);
}
switch (or->path_type) {
@@ -10733,8 +10731,6 @@ static void show_ip_ospf_route_network(struct vty *vty, struct ospf *ospf,
}
}
}
- if (!json)
- json_object_free(json_route);
}
if (!json)
vty_out(vty, "\n");
@@ -10762,8 +10758,8 @@ static void show_ip_ospf_route_router(struct vty *vty, struct ospf *ospf,
continue;
int flag = 0;
- json_route = json_object_new_object();
if (json) {
+ json_route = json_object_new_object();
json_object_object_add(
json, inet_ntop(AF_INET, &rn->p.u.prefix4,
buf, sizeof(buf)),
@@ -10878,8 +10874,6 @@ static void show_ip_ospf_route_router(struct vty *vty, struct ospf *ospf,
}
}
}
- if (!json)
- json_object_free(json_route);
}
if (!json)
vty_out(vty, "\n");
@@ -10908,11 +10902,9 @@ static void show_ip_ospf_route_external(struct vty *vty, struct ospf *ospf,
char buf1[19];
snprintfrr(buf1, sizeof(buf1), "%pFX", &rn->p);
- json_route = json_object_new_object();
if (json) {
+ json_route = json_object_new_object();
json_object_object_add(json, buf1, json_route);
- json_object_to_json_string_ext(
- json, JSON_C_TO_STRING_NOSLASHESCAPE);
}
switch (er->path_type) {
@@ -11010,8 +11002,6 @@ static void show_ip_ospf_route_external(struct vty *vty, struct ospf *ospf,
}
}
}
- if (!json)
- json_object_free(json_route);
}
if (!json)
vty_out(vty, "\n");
@@ -11224,7 +11214,9 @@ DEFUN (show_ip_ospf_route,
if (uj) {
/* Keep Non-pretty format */
vty_out(vty, "%s\n",
- json_object_to_json_string(json));
+ json_object_to_json_string_ext(
+ json,
+ JSON_C_TO_STRING_NOSLASHESCAPE));
json_object_free(json);
} else if (!ospf_output)
vty_out(vty, "%% OSPF instance not found\n");
@@ -11236,7 +11228,9 @@ DEFUN (show_ip_ospf_route,
if (uj) {
vty_out(vty, "%s\n",
json_object_to_json_string_ext(
- json, JSON_C_TO_STRING_PRETTY));
+ json,
+ JSON_C_TO_STRING_PRETTY
+ | JSON_C_TO_STRING_NOSLASHESCAPE));
json_object_free(json);
} else
vty_out(vty, "%% OSPF instance not found\n");
@@ -11250,7 +11244,9 @@ DEFUN (show_ip_ospf_route,
if (uj) {
vty_out(vty, "%s\n",
json_object_to_json_string_ext(
- json, JSON_C_TO_STRING_PRETTY));
+ json,
+ JSON_C_TO_STRING_PRETTY
+ | JSON_C_TO_STRING_NOSLASHESCAPE));
json_object_free(json);
} else
vty_out(vty, "%% OSPF instance not found\n");
@@ -11263,7 +11259,9 @@ DEFUN (show_ip_ospf_route,
ret = show_ip_ospf_route_common(vty, ospf, json, use_vrf);
/* Keep Non-pretty format */
if (uj)
- vty_out(vty, "%s\n", json_object_to_json_string(json));
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_NOSLASHESCAPE));
}
if (uj)
diff --git a/pathd/path_cli.c b/pathd/path_cli.c
index bd629a2b70..46242fd05a 100644
--- a/pathd/path_cli.c
+++ b/pathd/path_cli.c
@@ -352,7 +352,16 @@ static int segment_list_has_src_dst(
nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
"ipv6_adjacency");
node_src_id = adj_src_ipv6_str;
+ } else {
+ /*
+ * This is just to make the compiler happy about
+ * node_src_id not being initialized. This
+ * should never happen unless we change the cli
+ * function.
+ */
+ assert(!"We must have a adj_src_ipv4_str or a adj_src_ipv6_str");
}
+
/* addresses */
snprintf(xpath, XPATH_MAXLEN, "./segment[index='%s']/nai/local-address",
index_str);
diff --git a/tests/lib/cli/test_cli.c b/tests/lib/cli/test_cli.c
index 8dba1e29f0..f8d74018dd 100644
--- a/tests/lib/cli/test_cli.c
+++ b/tests/lib/cli/test_cli.c
@@ -40,6 +40,8 @@ DUMMY_DEFUN(cmd12, "alt a A.B.C.D");
DUMMY_DEFUN(cmd13, "alt a X:X::X:X");
DUMMY_DEFUN(cmd14,
"pat g { foo A.B.C.D$foo|foo|bar X:X::X:X$bar| baz } [final]");
+DUMMY_DEFUN(cmd15, "no pat g ![ WORD ]");
+DUMMY_DEFUN(cmd16, "[no] pat h {foo ![A.B.C.D$foo]|bar X:X::X:X$bar} final");
#include "tests/lib/cli/test_cli_clippy.c"
@@ -81,5 +83,7 @@ void test_init(int argc, char **argv)
install_element(ENABLE_NODE, &cmd13_cmd);
}
install_element(ENABLE_NODE, &cmd14_cmd);
+ install_element(ENABLE_NODE, &cmd15_cmd);
+ install_element(ENABLE_NODE, &cmd16_cmd);
install_element(ENABLE_NODE, &magic_test_cmd);
}
diff --git a/tests/lib/cli/test_cli.in b/tests/lib/cli/test_cli.in
index 5c146ef984..bd685a6231 100644
--- a/tests/lib/cli/test_cli.in
+++ b/tests/lib/cli/test_cli.in
@@ -74,6 +74,23 @@ pat f
pat f foo
pat f key
+no pat g
+no pat g test
+no pat g test more
+
+pat h foo ?1.2.3.4 final
+no pat h foo ?1.2.3.4 final
+pat h foo final
+no pat h foo final
+pat h bar final
+no pat h bar final
+pat h bar 1::2 final
+no pat h bar 1::2 final
+pat h bar 1::2 foo final
+no pat h bar 1::2 foo final
+pat h bar 1::2 foo 1.2.3.4 final
+no pat h bar 1::2 foo 1.2.3.4 final
+
alt a a?b
alt a 1 .2?.3.4
alt a 1 :2? ::?3
diff --git a/tests/lib/cli/test_cli.refout.in b/tests/lib/cli/test_cli.refout.in
index 1f38e08b20..84365810d5 100644
--- a/tests/lib/cli/test_cli.refout.in
+++ b/tests/lib/cli/test_cli.refout.in
@@ -147,7 +147,7 @@ test# papat
% Command incomplete.
test# pat
a b c d e f
-g
+g h
test# pat
% Command incomplete.
test#
@@ -263,6 +263,100 @@ cmd10 with 3 args.
[01] f@(null): f
[02] key@(null): key
test#
+test# no pat g
+cmd15 with 3 args.
+[00] no@(null): no
+[01] pat@(null): pat
+[02] g@(null): g
+test# no pat g test
+cmd15 with 4 args.
+[00] no@(null): no
+[01] pat@(null): pat
+[02] g@(null): g
+[03] WORD@g: test
+test# no pat g test more
+% [NONE] Unknown command: no pat g test more
+test#
+test# pat h foo
+ A.B.C.D 04
+test# pat h foo 1.2.3.4 final
+cmd16 with 5 args.
+[00] pat@(null): pat
+[01] h@(null): h
+[02] foo@(null): foo
+[03] A.B.C.D@foo: 1.2.3.4
+[04] final@(null): final
+test# no pat h foo
+ A.B.C.D 04
+ bar 05
+ final 07
+test# no pat h foo 1.2.3.4 final
+cmd16 with 6 args.
+[00] no@no: no
+[01] pat@(null): pat
+[02] h@(null): h
+[03] foo@(null): foo
+[04] A.B.C.D@foo: 1.2.3.4
+[05] final@(null): final
+test# pat h foo final
+% [NONE] Unknown command: pat h foo final
+test# no pat h foo final
+cmd16 with 5 args.
+[00] no@no: no
+[01] pat@(null): pat
+[02] h@(null): h
+[03] foo@(null): foo
+[04] final@(null): final
+test# pat h bar final
+% [NONE] Unknown command: pat h bar final
+test# no pat h bar final
+% [NONE] Unknown command: no pat h bar final
+test# pat h bar 1::2 final
+cmd16 with 5 args.
+[00] pat@(null): pat
+[01] h@(null): h
+[02] bar@(null): bar
+[03] X:X::X:X@bar: 1::2
+[04] final@(null): final
+test# no pat h bar 1::2 final
+cmd16 with 6 args.
+[00] no@no: no
+[01] pat@(null): pat
+[02] h@(null): h
+[03] bar@(null): bar
+[04] X:X::X:X@bar: 1::2
+[05] final@(null): final
+test# pat h bar 1::2 foo final
+% [NONE] Unknown command: pat h bar 1::2 foo final
+test# no pat h bar 1::2 foo final
+cmd16 with 7 args.
+[00] no@no: no
+[01] pat@(null): pat
+[02] h@(null): h
+[03] bar@(null): bar
+[04] X:X::X:X@bar: 1::2
+[05] foo@(null): foo
+[06] final@(null): final
+test# pat h bar 1::2 foo 1.2.3.4 final
+cmd16 with 7 args.
+[00] pat@(null): pat
+[01] h@(null): h
+[02] bar@(null): bar
+[03] X:X::X:X@bar: 1::2
+[04] foo@(null): foo
+[05] A.B.C.D@foo: 1.2.3.4
+[06] final@(null): final
+test# no pat h bar 1::2 foo 1.2.3.4 final
+cmd16 with 8 args.
+[00] no@no: no
+[01] pat@(null): pat
+[02] h@(null): h
+[03] bar@(null): bar
+[04] X:X::X:X@bar: 1::2
+[05] foo@(null): foo
+[06] A.B.C.D@foo: 1.2.3.4
+[07] final@(null): final
+test#
test# alt a
test# alt a a
WORD 02
diff --git a/tests/lib/test_nexthop.c b/tests/lib/test_nexthop.c
index 659d207b4e..7cf687dffe 100644
--- a/tests/lib/test_nexthop.c
+++ b/tests/lib/test_nexthop.c
@@ -112,15 +112,15 @@ static void test_run_first(void)
nexthop_free(nh2);
/* Blackhole */
- nh1 = nexthop_from_blackhole(BLACKHOLE_REJECT);
- nh2 = nexthop_from_blackhole(BLACKHOLE_REJECT);
+ nh1 = nexthop_from_blackhole(BLACKHOLE_REJECT, 0);
+ nh2 = nexthop_from_blackhole(BLACKHOLE_REJECT, 0);
ret = nexthop_cmp_basic(nh1, nh2);
assert(ret == 0);
nexthop_free(nh2);
- nh2 = nexthop_from_blackhole(BLACKHOLE_NULL);
+ nh2 = nexthop_from_blackhole(BLACKHOLE_NULL, 0);
ret = nexthop_cmp_basic(nh1, nh2);
assert(ret != 0);
diff --git a/tests/topotests/bgp_default_route_route_map_match_set/test_bgp_default-originate_route-map_match_set.py b/tests/topotests/bgp_default_route_route_map_match_set/test_bgp_default-originate_route-map_match_set.py
index 27451ec7b3..c890b0d7dc 100644
--- a/tests/topotests/bgp_default_route_route_map_match_set/test_bgp_default-originate_route-map_match_set.py
+++ b/tests/topotests/bgp_default_route_route_map_match_set/test_bgp_default-originate_route-map_match_set.py
@@ -92,7 +92,13 @@ def test_bgp_default_originate_route_map():
def _bgp_default_route_has_metric(router):
output = json.loads(router.vtysh_cmd("show ip bgp 0.0.0.0/0 json"))
expected = {
- "paths": [{"aspath": {"string": "65000 65000 65000 65000"}, "metric": 123}]
+ "paths": [
+ {
+ "aspath": {"string": "65000 65000 65000 65000"},
+ "metric": 123,
+ "community": None,
+ }
+ ]
}
return topotest.json_cmp(output, expected)
diff --git a/tests/topotests/bgp_evpn_overlay_index_gateway/host2/zebra.conf b/tests/topotests/bgp_evpn_overlay_index_gateway/host2/zebra.conf
index 9135545c58..b9f80f112d 100644
--- a/tests/topotests/bgp_evpn_overlay_index_gateway/host2/zebra.conf
+++ b/tests/topotests/bgp_evpn_overlay_index_gateway/host2/zebra.conf
@@ -1,4 +1,4 @@
!
-int host1-eth0
+int host2-eth0
ip address 50.0.1.21/24
ipv6 address 50:0:1::21/48
diff --git a/tests/topotests/conftest.py b/tests/topotests/conftest.py
index ed55490c09..7fe6a5aea1 100755
--- a/tests/topotests/conftest.py
+++ b/tests/topotests/conftest.py
@@ -6,13 +6,14 @@ import glob
import os
import pdb
import re
+import subprocess
import sys
import time
import pytest
import lib.fixtures
from lib import topolog
-from lib.micronet import Commander
+from lib.micronet import Commander, proc_error
from lib.micronet_cli import cli
from lib.micronet_compat import Mininet, cleanup_current, cleanup_previous
from lib.topogen import diagnose_env, get_topogen
@@ -256,6 +257,23 @@ def pytest_configure(config):
if cli_level is not None:
config.option.log_cli_level = cli_level
+ have_tmux = bool(os.getenv("TMUX", ""))
+ have_screen = not have_tmux and bool(os.getenv("STY", ""))
+ have_xterm = not have_tmux and not have_screen and bool(os.getenv("DISPLAY", ""))
+ have_windows = have_tmux or have_screen or have_xterm
+ have_windows_pause = have_tmux or have_xterm
+ xdist_no_windows = is_xdist and not is_worker and not have_windows_pause
+
+ def assert_feature_windows(b, feature):
+ if b and xdist_no_windows:
+ pytest.exit(
+ "{} use requires byobu/TMUX/XTerm under dist {}".format(
+ feature, os.environ["PYTEST_XDIST_MODE"]
+ )
+ )
+ elif b and not is_xdist and not have_windows:
+ pytest.exit("{} use requires byobu/TMUX/SCREEN/XTerm".format(feature))
+
# ---------------------------------------
# Record our options in global dictionary
# ---------------------------------------
@@ -272,6 +290,7 @@ def pytest_configure(config):
gdb_daemons = config.getoption("--gdb-daemons")
gdb_daemons = gdb_daemons.split(",") if gdb_daemons else []
topotest_extra_config["gdb_daemons"] = gdb_daemons
+ assert_feature_windows(gdb_routers or gdb_daemons, "GDB")
gdb_breakpoints = config.getoption("--gdb-breakpoints")
gdb_breakpoints = gdb_breakpoints.split(",") if gdb_breakpoints else []
@@ -279,31 +298,40 @@ def pytest_configure(config):
cli_on_error = config.getoption("--cli-on-error")
topotest_extra_config["cli_on_error"] = cli_on_error
+ assert_feature_windows(cli_on_error, "--cli-on-error")
shell = config.getoption("--shell")
topotest_extra_config["shell"] = shell.split(",") if shell else []
+ assert_feature_windows(shell, "--shell")
strace = config.getoption("--strace-daemons")
topotest_extra_config["strace_daemons"] = strace.split(",") if strace else []
shell_on_error = config.getoption("--shell-on-error")
topotest_extra_config["shell_on_error"] = shell_on_error
+ assert_feature_windows(shell_on_error, "--shell-on-error")
topotest_extra_config["valgrind_extra"] = config.getoption("--valgrind-extra")
topotest_extra_config["valgrind_memleaks"] = config.getoption("--valgrind-memleaks")
vtysh = config.getoption("--vtysh")
topotest_extra_config["vtysh"] = vtysh.split(",") if vtysh else []
+ assert_feature_windows(vtysh, "--vtysh")
vtysh_on_error = config.getoption("--vtysh-on-error")
topotest_extra_config["vtysh_on_error"] = vtysh_on_error
+ assert_feature_windows(vtysh_on_error, "--vtysh-on-error")
pause_on_error = vtysh or shell or config.getoption("--pause-on-error")
if config.getoption("--no-pause-on-error"):
pause_on_error = False
topotest_extra_config["pause_on_error"] = pause_on_error
- topotest_extra_config["pause"] = config.getoption("--pause")
+ assert_feature_windows(pause_on_error, "--pause-on-error")
+
+ pause = config.getoption("--pause")
+ topotest_extra_config["pause"] = pause
+ assert_feature_windows(pause, "--pause")
topotest_extra_config["topology_only"] = config.getoption("--topology-only")
@@ -403,20 +431,27 @@ def pytest_runtest_makereport(item, call):
error_cmd = os.getenv("SHELL", commander.get_exec_path(["bash"]))
if error_cmd:
- # Really would like something better than using this global here.
- # Not all tests use topogen though so get_topogen() won't work.
+ is_tmux = bool(os.getenv("TMUX", ""))
+ is_screen = not is_tmux and bool(os.getenv("STY", ""))
+ is_xterm = not is_tmux and not is_screen and bool(os.getenv("DISPLAY", ""))
+
+ channel = None
win_info = None
wait_for_channels = []
+ wait_for_procs = []
+ # Really would like something better than using this global here.
+ # Not all tests use topogen though so get_topogen() won't work.
for node in Mininet.g_mnet_inst.hosts.values():
pause = True
- channel = (
- "{}-{}".format(os.getpid(), Commander.tmux_wait_gen)
- if not isatty
- else None
- )
- Commander.tmux_wait_gen += 1
- wait_for_channels.append(channel)
+ if is_tmux:
+ channel = (
+ "{}-{}".format(os.getpid(), Commander.tmux_wait_gen)
+ if not isatty
+ else None
+ )
+ Commander.tmux_wait_gen += 1
+ wait_for_channels.append(channel)
pane_info = node.run_in_window(
error_cmd,
@@ -427,13 +462,22 @@ def pytest_runtest_makereport(item, call):
tmux_target=win_info,
wait_for=channel,
)
- if win_info is None:
- win_info = pane_info
+ if is_tmux:
+ if win_info is None:
+ win_info = pane_info
+ elif is_xterm:
+ assert isinstance(pane_info, subprocess.Popen)
+ wait_for_procs.append(pane_info)
# Now wait on any channels
for channel in wait_for_channels:
logger.debug("Waiting on TMUX channel %s", channel)
commander.cmd_raises([commander.get_exec_path("tmux"), "wait", channel])
+ for p in wait_for_procs:
+ logger.debug("Waiting on TMUX xterm process %s", p)
+ o, e = p.communicate()
+ if p.wait():
+ logger.warning("xterm proc failed: %s:", proc_error(p, o, e))
if error and topotest_extra_config["cli_on_error"]:
# Really would like something better than using this global here.
diff --git a/tests/topotests/example_test/r1/zebra.conf b/tests/topotests/example_test/r1/zebra.conf
new file mode 100644
index 0000000000..b733b7b03c
--- /dev/null
+++ b/tests/topotests/example_test/r1/zebra.conf
@@ -0,0 +1,8 @@
+interface r1-eth0
+ ip address 192.168.1.1/24
+
+interface r1-eth1
+ ip address 192.168.2.1/24
+
+interface r1-eth2
+ ip address 192.168.3.1/24 \ No newline at end of file
diff --git a/tests/topotests/example_test/r2/zebra.conf b/tests/topotests/example_test/r2/zebra.conf
new file mode 100644
index 0000000000..c0921f54c9
--- /dev/null
+++ b/tests/topotests/example_test/r2/zebra.conf
@@ -0,0 +1,4 @@
+interface r2-eth0
+ ip address 192.168.1.2/24
+interface r2-eth1
+ ip address 192.168.3.2/24
diff --git a/tests/topotests/example_test/test_template.py b/tests/topotests/example_test/test_template.py
index e94bb905a5..4c073f259c 100644
--- a/tests/topotests/example_test/test_template.py
+++ b/tests/topotests/example_test/test_template.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-
+# -*- coding: utf-8 eval: (blacken-mode 1) -*-
#
# <template>.py
# Part of NetDEF Topology Tests
@@ -29,54 +29,69 @@
import sys
import pytest
-# Import topogen and topotest helpers
-from lib.topogen import Topogen, TopoRouter, get_topogen
-
+from lib.topogen import Topogen, TopoRouter
+from lib.topolog import logger
# TODO: select markers based on daemons used during test
# pytest module level markers
-"""
-pytestmark = pytest.mark.bfdd # single marker
pytestmark = [
- pytest.mark.bgpd,
- pytest.mark.ospfd,
- pytest.mark.ospf6d
-] # multiple markers
-"""
-
-
+ # pytest.mark.babeld,
+ # pytest.mark.bfdd,
+ # pytest.mark.bgpd,
+ # pytest.mark.eigrpd,
+ # pytest.mark.isisd,
+ # pytest.mark.ldpd,
+ # pytest.mark.nhrpd,
+ # pytest.mark.ospf6d,
+ pytest.mark.ospfd,
+ # pytest.mark.pathd,
+ # pytest.mark.pbrd,
+ # pytest.mark.pimd,
+ # pytest.mark.ripd,
+ # pytest.mark.ripngd,
+ # pytest.mark.sharpd,
+ # pytest.mark.staticd,
+ # pytest.mark.vrrpd,
+]
+
+# Function we pass to Topogen to create the topology
def build_topo(tgen):
"Build function"
# Create 2 routers
- for routern in range(1, 3):
- tgen.add_router("r{}".format(routern))
+ r1 = tgen.add_router("r1")
+ r2 = tgen.add_router("r2")
- # Create a switch with just one router connected to it to simulate a
- # empty network.
+ # Create a p2p connection between r1 and r2
+ tgen.add_link(r1, r2)
+
+ # Create a switch with one router connected to it to simulate a empty network.
switch = tgen.add_switch("s1")
- switch.add_link(tgen.gears["r1"])
+ switch.add_link(r1)
- # Create a connection between r1 and r2
+ # Create a p2p connection between r1 and r2
switch = tgen.add_switch("s2")
- switch.add_link(tgen.gears["r1"])
- switch.add_link(tgen.gears["r2"])
+ switch.add_link(r1)
+ switch.add_link(r2)
-def setup_module(mod):
- "Sets up the pytest environment"
+# New form of setup/teardown using pytest fixture
+@pytest.fixture(scope="module")
+def tgen(request):
+ "Setup/Teardown the environment and provide tgen argument to tests"
# This function initiates the topology build with Topogen...
- tgen = Topogen(build_topo, mod.__name__)
+ tgen = Topogen(build_topo, request.module.__name__)
- # The basic topology above could also have be more easily specified using a
- # dictionary, remove the build_topo function and use the following instead:
+ # A basic topology similar to the above could also have be more easily specified
+ # using a # dictionary, remove the build_topo function and use the following
+ # instead:
#
# topodef = {
# "s1": "r1"
# "s2": ("r1", "r2")
# }
- # tgen = Topogen(topodef, mod.__name__)
+ # tgen = Topogen(topodef, request.module.__name__)
# ... and here it calls initialization functions.
tgen.start_topology()
@@ -84,42 +99,69 @@ def setup_module(mod):
# This is a sample of configuration loading.
router_list = tgen.routers()
- # For all registred routers, load the zebra configuration file
- # CWD = os.path.dirname(os.path.realpath(__file__))
+ # For all routers arrange for:
+ # - starting zebra using config file from <rtrname>/zebra.conf
+ # - starting ospfd using an empty config file.
for rname, router in router_list.items():
- router.load_config(
- TopoRouter.RD_ZEBRA,
- # Uncomment next line to load configuration from ./router/zebra.conf
- # os.path.join(CWD, '{}/zebra.conf'.format(rname))
- )
+ router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf")
+ router.load_config(TopoRouter.RD_OSPF)
- # After loading the configurations, this function loads configured daemons.
+ # Start and configure the router daemons
tgen.start_router()
+ # Provide tgen as argument to each test function
+ yield tgen
-def teardown_module(mod):
- "Teardown the pytest environment"
- tgen = get_topogen()
-
- # This function tears down the whole topology.
+ # Teardown after last test runs
tgen.stop_topology()
-def test_call_cli():
- "Dummy test that just calls tgen.cli() so we can interact with the build."
- tgen = get_topogen()
- # Don't run this test if we have any failure.
+# Fixture that executes before each test
+@pytest.fixture(autouse=True)
+def skip_on_failure(tgen):
if tgen.routers_have_failure():
- pytest.skip(tgen.errors)
+ pytest.skip("skipped because of previous test failure")
+
+
+# ===================
+# The tests functions
+# ===================
+
- # logger.info("calling CLI")
- # tgen.cli()
+def test_get_version(tgen):
+ "Test the logs the FRR version"
+
+ r1 = tgen.gears["r1"]
+ version = r1.vtysh_cmd("show version")
+ logger.info("FRR version is: " + version)
+
+
+def test_connectivity(tgen):
+ "Test the logs the FRR version"
+
+ r1 = tgen.gears["r1"]
+ r2 = tgen.gears["r2"]
+ output = r1.cmd_raises("ping -c1 192.168.1.2")
+ output = r2.cmd_raises("ping -c1 192.168.3.1")
+
+
+@pytest.mark.xfail
+def test_expect_failure(tgen):
+ "A test that is current expected to fail but should be fixed"
+
+ assert False, "Example of temporary expected failure that will eventually be fixed"
+
+
+@pytest.mark.skip
+def test_will_be_skipped(tgen):
+ "A test that will be skipped"
+ assert False
# Memory leak test template
-def test_memory_leak():
+def test_memory_leak(tgen):
"Run the memory leak test and report results."
- tgen = get_topogen()
+
if not tgen.is_memleak_enabled():
pytest.skip("Memory leak test/report is disabled")
diff --git a/tests/topotests/lib/micronet.py b/tests/topotests/lib/micronet.py
index 0416c53c48..8567bd3b4b 100644
--- a/tests/topotests/lib/micronet.py
+++ b/tests/topotests/lib/micronet.py
@@ -369,13 +369,13 @@ class Commander(object): # pylint: disable=R0205
cmd = [self.get_exec_path("xterm")]
if "SUDO_USER" in os.environ:
cmd = [self.get_exec_path("sudo"), "-u", os.environ["SUDO_USER"]] + cmd
- # if title:
- # cmd.append("-T")
- # cmd.append(title)
+ if title:
+ cmd.append("-T")
+ cmd.append(title)
cmd.append("-e")
cmd.append(sudo_path)
cmd.extend(self.pre_cmd)
- cmd.append(user_cmd)
+ cmd.extend(["bash", "-c", user_cmd])
# if channel:
# return self.cmd_raises(cmd, skip_pre_cmd=True)
# else:
@@ -384,13 +384,11 @@ class Commander(object): # pylint: disable=R0205
skip_pre_cmd=True,
stdin=None,
shell=False,
- # stdout=open("/dev/null", "w"),
- # stderr=open("/dev/null", "w"),
)
time_mod.sleep(2)
if p.poll() is not None:
self.logger.error("%s: Failed to launch xterm: %s", self, comm_error(p))
- return ""
+ return p
else:
self.logger.error(
"DISPLAY, STY, and TMUX not in environment, can't open window"
diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py
index 7541d506cb..b98698185c 100644
--- a/tests/topotests/lib/topotest.py
+++ b/tests/topotests/lib/topotest.py
@@ -1616,10 +1616,6 @@ class Router(Node):
if "all" in shell_routers or self.name in shell_routers:
self.run_in_window(os.getenv("SHELL", "bash"))
- vtysh_routers = g_extra_config["vtysh"]
- if "all" in vtysh_routers or self.name in vtysh_routers:
- self.run_in_window("vtysh")
-
if self.daemons["eigrpd"] == 1:
eigrpd_path = os.path.join(self.daemondir, "eigrpd")
if not os.path.isfile(eigrpd_path):
@@ -1632,7 +1628,13 @@ class Router(Node):
logger.info("BFD Test, but no bfdd compiled or installed")
return "BFD Test, but no bfdd compiled or installed"
- return self.startRouterDaemons(tgen=tgen)
+ status = self.startRouterDaemons(tgen=tgen)
+
+ vtysh_routers = g_extra_config["vtysh"]
+ if "all" in vtysh_routers or self.name in vtysh_routers:
+ self.run_in_window("vtysh")
+
+ return status
def getStdErr(self, daemon):
return self.getLog("err", daemon)
diff --git a/tests/zebra/test_lm_plugin.c b/tests/zebra/test_lm_plugin.c
index 4a9344fee4..ecfb085793 100644
--- a/tests/zebra/test_lm_plugin.c
+++ b/tests/zebra/test_lm_plugin.c
@@ -77,7 +77,7 @@ static int lm_release_chunk_pi(struct zserv *client, uint32_t start,
/* use external allocations */
-static void lp_plugin_init()
+static void lp_plugin_init(void)
{
/* register our own hooks */
hook_register(lm_client_connect, test_client_connect);
@@ -86,7 +86,7 @@ static void lp_plugin_init()
hook_register(lm_release_chunk, lm_release_chunk_pi);
}
-static void lp_plugin_cleanup()
+static void lp_plugin_cleanup(void)
{
/* register our own hooks */
hook_unregister(lm_client_connect, test_client_connect);
@@ -98,7 +98,7 @@ static void lp_plugin_cleanup()
/* tests */
-static void test_lp_plugin()
+static void test_lp_plugin(void)
{
struct label_manager_chunk *lmc;
diff --git a/tools/permutations.c b/tools/permutations.c
index f51d4a4ec9..b280cc15b1 100644
--- a/tools/permutations.c
+++ b/tools/permutations.c
@@ -61,9 +61,22 @@ void permute(struct graph_node *start)
struct cmd_token *stok = start->data;
struct graph_node *gnn;
struct listnode *ln;
+ bool is_neg = false;
// recursive dfs
listnode_add(position, start);
+
+ for (ALL_LIST_ELEMENTS_RO(position, ln, gnn)) {
+ struct cmd_token *tok = gnn->data;
+
+ if (tok->type == WORD_TKN && !strcmp(tok->text, "no")) {
+ is_neg = true;
+ break;
+ }
+ if (tok->type < SPECIAL_TKN)
+ break;
+ }
+
for (unsigned int i = 0; i < vector_active(start->to); i++) {
struct graph_node *gn = vector_slot(start->to, i);
struct cmd_token *tok = gn->data;
@@ -82,6 +95,9 @@ void permute(struct graph_node *start)
fprintf(stdout, "\n");
} else {
bool skip = false;
+
+ if (tok->type == NEG_ONLY_TKN && !is_neg)
+ continue;
if (stok->type == FORK_TKN && tok->type != FORK_TKN)
for (ALL_LIST_ELEMENTS_RO(position, ln, gnn))
if (gnn == gn) {
diff --git a/zebra/router-id.c b/zebra/router-id.c
index 689b9787ee..ac81d537d0 100644
--- a/zebra/router-id.c
+++ b/zebra/router-id.c
@@ -120,10 +120,12 @@ int router_id_get(afi_t afi, struct prefix *p, struct zebra_vrf *zvrf)
static int router_id_set(afi_t afi, struct prefix *p, struct zebra_vrf *zvrf)
{
- struct prefix p2;
+ struct prefix after, before;
struct listnode *node;
struct zserv *client;
+ router_id_get(afi, &before, zvrf);
+
switch (afi) {
case AFI_IP:
zvrf->rid_user_assigned.u.prefix4.s_addr = p->u.prefix4.s_addr;
@@ -135,10 +137,17 @@ static int router_id_set(afi_t afi, struct prefix *p, struct zebra_vrf *zvrf)
return -1;
}
- router_id_get(afi, &p2, zvrf);
+ router_id_get(afi, &after, zvrf);
+
+ /*
+ * If we've been told that the router-id is exactly the same
+ * do we need to really do anything here?
+ */
+ if (prefix_same(&before, &after))
+ return 0;
for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client))
- zsend_router_id_update(client, afi, &p2, zvrf->vrf->vrf_id);
+ zsend_router_id_update(client, afi, &after, zvrf->vrf->vrf_id);
return 0;
}
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index 6666b3525e..9ffbcc9223 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -1611,7 +1611,8 @@ static struct nexthop *nexthop_from_zapi(const struct zapi_nexthop *api_nh,
zlog_debug("%s: nh blackhole %d",
__func__, api_nh->bh_type);
- nexthop = nexthop_from_blackhole(api_nh->bh_type);
+ nexthop =
+ nexthop_from_blackhole(api_nh->bh_type, api_nh->vrf_id);
break;
}
@@ -2221,8 +2222,8 @@ stream_failure:
static void zread_router_id_add(ZAPI_HANDLER_ARGS)
{
afi_t afi;
-
struct prefix p;
+ struct prefix zero;
STREAM_GETW(msg, afi);
@@ -2238,6 +2239,18 @@ static void zread_router_id_add(ZAPI_HANDLER_ARGS)
router_id_get(afi, &p, zvrf);
+ /*
+ * If we have not officially setup a router-id let's not
+ * tell the upper level protocol about it yet.
+ */
+ memset(&zero, 0, sizeof(zero));
+ if ((p.family == AF_INET && p.u.prefix4.s_addr == INADDR_ANY)
+ || (p.family == AF_INET6
+ && memcmp(&p.u.prefix6, &zero.u.prefix6,
+ sizeof(struct in6_addr))
+ == 0))
+ return;
+
zsend_router_id_update(client, afi, &p, zvrf_id(zvrf));
stream_failure:
diff --git a/zebra/zebra_evpn_neigh.c b/zebra/zebra_evpn_neigh.c
index 08ff7011e2..af46ea6d7a 100644
--- a/zebra/zebra_evpn_neigh.c
+++ b/zebra/zebra_evpn_neigh.c
@@ -2113,12 +2113,12 @@ void zebra_evpn_neigh_remote_macip_add(struct zebra_evpn *zevpn,
"sync->remote neigh vni %u ip %pIA mac %pEA seq %d f0x%x",
n->zevpn->vni, &n->ip, &n->emac,
seq, n->flags);
- zebra_evpn_neigh_clear_sync_info(n);
if (IS_ZEBRA_NEIGH_ACTIVE(n))
zebra_evpn_neigh_send_del_to_client(
zevpn->vni, &n->ip, &n->emac,
n->flags, n->state,
false /*force*/);
+ zebra_evpn_neigh_clear_sync_info(n);
}
if (memcmp(&n->emac, &mac->macaddr,
sizeof(struct ethaddr))
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index b204b30ca7..1c8a1ad09a 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -357,9 +357,11 @@ static void show_nexthop_detail_helper(struct vty *vty,
break;
}
- if ((re->vrf_id != nexthop->vrf_id)
- && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE))
- vty_out(vty, "(vrf %s)", vrf_id_to_name(nexthop->vrf_id));
+ if (re->vrf_id != nexthop->vrf_id) {
+ struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id);
+
+ vty_out(vty, "(vrf %s)", VRF_LOGNAME(vrf));
+ }
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE))
vty_out(vty, " (duplicate nexthop removed)");
@@ -607,8 +609,7 @@ static void show_route_nexthop_helper(struct vty *vty,
break;
}
- if ((re == NULL || (nexthop->vrf_id != re->vrf_id))
- && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE))
+ if ((re == NULL || (nexthop->vrf_id != re->vrf_id)))
vty_out(vty, " (vrf %s)", vrf_id_to_name(nexthop->vrf_id));
if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
@@ -780,8 +781,7 @@ static void show_nexthop_json_helper(json_object *json_nexthop,
break;
}
- if ((nexthop->vrf_id != re->vrf_id)
- && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE))
+ if (nexthop->vrf_id != re->vrf_id)
json_object_string_add(json_nexthop, "vrf",
vrf_id_to_name(nexthop->vrf_id));