diff options
45 files changed, 552 insertions, 239 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_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_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_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/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/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/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/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/zapi_msg.c b/zebra/zapi_msg.c index 72c7071502..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; } 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)); |
