diff options
| -rw-r--r-- | bgpd/bgp_evpn.c | 17 | ||||
| -rw-r--r-- | bgpd/bgp_nht.c | 2 | ||||
| -rw-r--r-- | bgpd/bgp_vty.c | 78 | ||||
| -rw-r--r-- | doc/Makefile.am | 7 | ||||
| -rw-r--r-- | doc/developer/.gitignore | 1 | ||||
| -rw-r--r-- | doc/developer/Makefile.am (renamed from doc/developer/Makefile.in) | 0 | ||||
| -rw-r--r-- | doc/manpages/.gitignore | 1 | ||||
| -rw-r--r-- | doc/manpages/Makefile.am (renamed from doc/manpages/Makefile.in) | 7 | ||||
| -rw-r--r-- | doc/user/.gitignore | 1 | ||||
| -rw-r--r-- | doc/user/Makefile.am (renamed from doc/user/Makefile.in) | 7 | ||||
| -rw-r--r-- | doc/user/routemap.rst | 12 | ||||
| -rw-r--r-- | ospf6d/ospf6_asbr.c | 113 | ||||
| -rw-r--r-- | ospf6d/ospf6_intra.c | 2 | ||||
| -rw-r--r-- | sharpd/sharp_main.c | 2 | ||||
| -rw-r--r-- | sharpd/sharp_vty.c | 17 | ||||
| -rw-r--r-- | sharpd/sharp_zebra.c | 6 | ||||
| -rw-r--r-- | sharpd/sharp_zebra.h | 4 | ||||
| -rw-r--r-- | tests/Makefile.am | 1 | ||||
| -rw-r--r-- | vtysh/vtysh.c | 78 | ||||
| -rw-r--r-- | vtysh/vtysh.h | 1 | ||||
| -rw-r--r-- | vtysh/vtysh_main.c | 11 | ||||
| -rw-r--r-- | zebra/redistribute.c | 4 | ||||
| -rw-r--r-- | zebra/rt_netlink.c | 15 | ||||
| -rw-r--r-- | zebra/zebra_rib.c | 2 | ||||
| -rw-r--r-- | zebra/zebra_routemap.c | 95 | ||||
| -rw-r--r-- | zebra/zebra_routemap.h | 16 |
26 files changed, 336 insertions, 164 deletions
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 74a4f66098..8394c3a7b7 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -327,6 +327,12 @@ static int evpn_route_target_cmp(struct ecommunity *ecom1, return strcmp(ecom1->str, ecom2->str); } +static void evpn_xxport_delete_ecomm(void *val) +{ + struct ecommunity *ecomm = val; + ecommunity_free(&ecomm); +} + /* * Mask off global-admin field of specified extended community (RT), * just retain the local-admin field. @@ -3240,8 +3246,6 @@ static void bgp_evpn_handle_export_rt_change_for_vrf(struct bgp *bgp_vrf) static void update_autort_vni(struct hash_backet *backet, struct bgp *bgp) { struct bgpevpn *vpn = backet->data; - struct listnode *node, *nnode; - struct ecommunity *ecom; if (!vpn) { zlog_warn("%s: VNI hash entry for VNI not found", __PRETTY_FUNCTION__); @@ -3252,16 +3256,12 @@ static void update_autort_vni(struct hash_backet *backet, struct bgp *bgp) if (is_vni_live(vpn)) bgp_evpn_uninstall_routes(bgp, vpn); bgp_evpn_unmap_vni_from_its_rts(bgp, vpn); - for (ALL_LIST_ELEMENTS(vpn->import_rtl, node, nnode, ecom)) - ecommunity_free(&ecom); list_delete_all_node(vpn->import_rtl); bgp_evpn_derive_auto_rt_import(bgp, vpn); if (is_vni_live(vpn)) bgp_evpn_install_routes(bgp, vpn); } if (!is_export_rt_configured(vpn)) { - for (ALL_LIST_ELEMENTS(vpn->export_rtl, node, nnode, ecom)) - ecommunity_free(&ecom); list_delete_all_node(vpn->export_rtl); bgp_evpn_derive_auto_rt_export(bgp, vpn); if (is_vni_live(vpn)) @@ -4100,8 +4100,10 @@ struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni, /* Initialize route-target import and export lists */ vpn->import_rtl = list_new(); vpn->import_rtl->cmp = (int (*)(void *, void *))evpn_route_target_cmp; + vpn->import_rtl->del = evpn_xxport_delete_ecomm; vpn->export_rtl = list_new(); vpn->export_rtl->cmp = (int (*)(void *, void *))evpn_route_target_cmp; + vpn->export_rtl->del = evpn_xxport_delete_ecomm; bf_assign_index(bm->rd_idspace, vpn->rd_id); derive_rd_rt_for_vni(bgp, vpn); @@ -4651,10 +4653,11 @@ void bgp_evpn_init(struct bgp *bgp) bgp->vrf_import_rtl = list_new(); bgp->vrf_import_rtl->cmp = (int (*)(void *, void *))evpn_route_target_cmp; - + bgp->vrf_import_rtl->del = evpn_xxport_delete_ecomm; bgp->vrf_export_rtl = list_new(); bgp->vrf_export_rtl->cmp = (int (*)(void *, void *))evpn_route_target_cmp; + bgp->vrf_export_rtl->del = evpn_xxport_delete_ecomm; bgp->l2vnis = list_new(); bgp->l2vnis->cmp = (int (*)(void *, void *))vni_hash_cmp; } diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 8b6ff3fa22..2c9e379299 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -88,7 +88,7 @@ int bgp_find_nexthop(struct bgp_info *path, int connected) static void bgp_unlink_nexthop_check(struct bgp_nexthop_cache *bnc) { - if (LIST_EMPTY(&(bnc->paths)) && !bnc->nht_info) { + if (LIST_EMPTY(&(bnc->paths)) && bnc->nht_info) { if (BGP_DEBUG(nht, NHT)) { char buf[PREFIX2STR_BUFFER]; zlog_debug("bgp_unlink_nexthop: freeing bnc %s", diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 35477ba164..f4f4e63264 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -553,39 +553,46 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, const char *arg) { int ret; + bool found = false; struct peer *peer; struct listnode *node, *nnode; /* Clear all neighbors. */ /* * Pass along pointer to next node to peer_clear() when walking all - * nodes - * on the BGP instance as that may get freed if it is a doppelganger + * nodes on the BGP instance as that may get freed if it is a + * doppelganger */ if (sort == clear_all) { for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { + if (!peer->afc[afi][safi]) + continue; + if (stype == BGP_CLEAR_SOFT_NONE) ret = peer_clear(peer, &nnode); - else if (peer->afc[afi][safi]) - ret = peer_clear_soft(peer, afi, safi, stype); else - ret = 0; + ret = peer_clear_soft(peer, afi, safi, stype); if (ret < 0) bgp_clear_vty_error(vty, peer, afi, safi, ret); + else + found = true; } /* This is to apply read-only mode on this clear. */ if (stype == BGP_CLEAR_SOFT_NONE) bgp->update_delay_over = 0; + if (!found) + vty_out(vty, "%%BGP: No %s peer configured", + afi_safi_print(afi, safi)); + return CMD_SUCCESS; } - /* Clear specified neighbors. */ + /* Clear specified neighbor. */ if (sort == clear_peer) { union sockunion su; - int ret; /* Make sockunion for lookup. */ ret = str2sockunion(arg, &su); @@ -610,7 +617,9 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, } } - if (stype == BGP_CLEAR_SOFT_NONE) + if (!peer->afc[afi][safi]) + ret = BGP_ERR_AF_UNCONFIGURED; + else if (stype == BGP_CLEAR_SOFT_NONE) ret = peer_clear(peer, NULL); else ret = peer_clear_soft(peer, afi, safi, stype); @@ -621,7 +630,7 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, return CMD_SUCCESS; } - /* Clear all peer-group members. */ + /* Clear all neighbors belonging to a specific peer-group. */ if (sort == clear_group) { struct peer_group *group; @@ -632,27 +641,37 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, } for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { - if (stype == BGP_CLEAR_SOFT_NONE) { - peer_clear(peer, NULL); - continue; - } - if (!peer->afc[afi][safi]) continue; - ret = peer_clear_soft(peer, afi, safi, stype); + if (stype == BGP_CLEAR_SOFT_NONE) + ret = peer_clear(peer, NULL); + else + ret = peer_clear_soft(peer, afi, safi, stype); if (ret < 0) bgp_clear_vty_error(vty, peer, afi, safi, ret); + else + found = true; } + + if (!found) + vty_out(vty, + "%%BGP: No %s peer belonging to peer-group %s is configured\n", + afi_safi_print(afi, safi), arg); + return CMD_SUCCESS; } + /* Clear all external (eBGP) neighbors. */ if (sort == clear_external) { for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { if (peer->sort == BGP_PEER_IBGP) continue; + if (!peer->afc[afi][safi]) + continue; + if (stype == BGP_CLEAR_SOFT_NONE) ret = peer_clear(peer, &nnode); else @@ -660,33 +679,44 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, if (ret < 0) bgp_clear_vty_error(vty, peer, afi, safi, ret); + else + found = true; } + + if (!found) + vty_out(vty, + "%%BGP: No external %s peer is configured\n", + afi_safi_print(afi, safi)); + return CMD_SUCCESS; } + /* Clear all neighbors belonging to a specific AS. */ if (sort == clear_as) { - as_t as; - int find = 0; - - as = strtoul(arg, NULL, 10); + as_t as = strtoul(arg, NULL, 10); for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { if (peer->as != as) continue; - find = 1; - if (stype == BGP_CLEAR_SOFT_NONE) + if (!peer->afc[afi][safi]) + ret = BGP_ERR_AF_UNCONFIGURED; + else if (stype == BGP_CLEAR_SOFT_NONE) ret = peer_clear(peer, &nnode); else ret = peer_clear_soft(peer, afi, safi, stype); if (ret < 0) bgp_clear_vty_error(vty, peer, afi, safi, ret); + else + found = true; } - if (!find) + + if (!found) vty_out(vty, - "%%BGP: No peer is configured with AS %s\n", - arg); + "%%BGP: No %s peer is configured with AS %s\n", + afi_safi_print(afi, safi), arg); + return CMD_SUCCESS; } diff --git a/doc/Makefile.am b/doc/Makefile.am index 19561c031d..a0ff314786 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -140,7 +140,7 @@ EXTRA_DIST = frr-sphinx.mk \ manpages/index.rst \ manpages/isisd.rst \ manpages/ldpd.rst \ - manpages/Makefile \ + manpages/Makefile.am \ manpages/mtracebis.rst \ manpages/nhrpd.rst \ manpages/ospf6d.rst \ @@ -182,7 +182,7 @@ EXTRA_DIST = frr-sphinx.mk \ developer/index.rst \ developer/ldpd-basic-test-setup.md \ developer/library.rst \ - developer/Makefile \ + developer/Makefile.in \ developer/memtypes.rst \ developer/modules.rst \ developer/next-hop-tracking.rst \ @@ -195,6 +195,7 @@ EXTRA_DIST = frr-sphinx.mk \ user/babeld.rst \ user/basic.rst \ user/bgp.rst \ + user/bugs.rst \ user/conf.py \ user/eigrpd.rst \ user/filter.rst \ @@ -205,7 +206,7 @@ EXTRA_DIST = frr-sphinx.mk \ user/ipv6.rst \ user/isisd.rst \ user/kernel.rst \ - user/Makefile \ + user/Makefile.am \ user/nhrpd.rst \ user/ospf6d.rst \ user/ospfd.rst \ diff --git a/doc/developer/.gitignore b/doc/developer/.gitignore index 2e7d8573f1..81c60dc0a3 100644 --- a/doc/developer/.gitignore +++ b/doc/developer/.gitignore @@ -1,3 +1,2 @@ /_templates /_build -!/Makefile.in diff --git a/doc/developer/Makefile.in b/doc/developer/Makefile.am index 76758f9242..76758f9242 100644 --- a/doc/developer/Makefile.in +++ b/doc/developer/Makefile.am diff --git a/doc/manpages/.gitignore b/doc/manpages/.gitignore index 2e7d8573f1..81c60dc0a3 100644 --- a/doc/manpages/.gitignore +++ b/doc/manpages/.gitignore @@ -1,3 +1,2 @@ /_templates /_build -!/Makefile.in diff --git a/doc/manpages/Makefile.in b/doc/manpages/Makefile.am index f28746cee6..009c723823 100644 --- a/doc/manpages/Makefile.in +++ b/doc/manpages/Makefile.am @@ -34,11 +34,6 @@ include @srcdir@/../frr-sphinx.mk # tags # ctags -# ignore these targets -EMPTY_AUTOMAKE_TARGETS = dvi pdf ps tags ctags distdir installdirs check installcheck install-dvi install-ps install-html install-pdf install-info install-exec -.PHONY: $(EMPTY_AUTOMAKE_TARGETS) -$(EMPTY_AUTOMAKE_TARGETS): - # These targets are automatically generated by Sphinx but conflict with # implicitly defined Automake rules, so we manually override them to nothing. # The other option is deleting the Sphinx-generated rules, which suppresses the @@ -51,5 +46,3 @@ all: man install-data: man install: install-data - -mostlyclean distclean maintainer-clean: clean diff --git a/doc/user/.gitignore b/doc/user/.gitignore index 2e7d8573f1..81c60dc0a3 100644 --- a/doc/user/.gitignore +++ b/doc/user/.gitignore @@ -1,3 +1,2 @@ /_templates /_build -!/Makefile.in diff --git a/doc/user/Makefile.in b/doc/user/Makefile.am index 77c6abf917..64af2ff145 100644 --- a/doc/user/Makefile.in +++ b/doc/user/Makefile.am @@ -34,11 +34,6 @@ include @srcdir@/../frr-sphinx.mk # tags # ctags -# ignore these targets -EMPTY_AUTOMAKE_TARGETS = dvi ps tags ctags distdir install-exec install-dvi install-ps installdirs check installcheck install-html install-pdf install-data install -.PHONY: $(EMPTY_AUTOMAKE_TARGETS) -$(EMPTY_AUTOMAKE_TARGETS): - # When building 'all', the logic is that we want to make docs that are easily # readable by the person that just built them. Technically the reST source is # readable in its own right, but we'll also build info and html because those @@ -58,5 +53,3 @@ install-info: info install-data: install-info install: install-data - -mostlyclean distclean maintainer-clean: clean diff --git a/doc/user/routemap.rst b/doc/user/routemap.rst index bddf2ba26d..8080e001f1 100644 --- a/doc/user/routemap.rst +++ b/doc/user/routemap.rst @@ -180,6 +180,18 @@ Route Map Match Command interface name specified if the neighbor was specified in this manner. +.. index:: match source-protocol PROTOCOL_NAME +.. clicmd:: match source-protocol PROTOCOL_NAME + + This is a ZEBRA specific match command. Matches the + originating protocol specified. + +.. index:: match source-instance NUMBER +.. clicmd:: match source-instance NUMBER + + This is a ZEBRA specific match command. The number is a range from (0-255). + Matches the originating protocols instance specified. + .. _route-map-set-command: Route Map Set Command diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 0fe0cada39..8bd0683f14 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -260,12 +260,12 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old, listnode_delete(old_route->nh_list, rnh); ospf6_nexthop_delete(rnh); - route_updated = true; } } listnode_delete(old_route->paths, o_path); ospf6_path_free(o_path); + route_updated = true; /* Current route's path (adv_router info) is similar * to route being added. @@ -273,6 +273,19 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old, * Update FIB with effective NHs. */ if (listcount(old_route->paths)) { + for (ALL_LIST_ELEMENTS(old_route->paths, + anode, anext, o_path)) { + ospf6_merge_nexthops( + old_route->nh_list, + o_path->nh_list); + } + /* Update RIB/FIB with effective + * nh_list + */ + if (ospf6->route_table->hook_add) + (*ospf6->route_table->hook_add) + (old_route); + if (old_route->path.origin.id == route->path.origin.id && old_route->path.origin.adv_router @@ -290,23 +303,7 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old, old_route->path.origin.adv_router = h_path->origin.adv_router; } - - if (route_updated) { - for (ALL_LIST_ELEMENTS(old_route->paths, - anode, anext, - o_path)) { - ospf6_merge_nexthops( - old_route->nh_list, - o_path->nh_list); - } - /* Update RIB/FIB with effective - * nh_list - */ - if (ospf6->route_table->hook_add) - (*ospf6->route_table->hook_add)( - old_route); - break; - } + break; } else { if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { prefix2str(&old_route->prefix, buf, @@ -374,13 +371,6 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old, /* Add a nh_list to new ecmp path */ ospf6_copy_nexthops(ecmp_path->nh_list, route->nh_list); - /* Merge nexthop to existing route's nh_list */ - ospf6_route_merge_nexthops(old_route, route); - - /* Update RIB/FIB */ - if (ospf6->route_table->hook_add) - (*ospf6->route_table->hook_add)( - old_route); /* Add the new path to route's path list */ listnode_add_sort(old_route->paths, ecmp_path); @@ -400,46 +390,52 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old, listcount(old_route->nh_list)); } } else { - for (ALL_LIST_ELEMENTS_RO(o_path->nh_list, - nnode, nh)) { - for (ALL_LIST_ELEMENTS( - old_route->nh_list, rnode, - rnext, rnh)) { - if (!ospf6_nexthop_is_same(rnh, - nh)) - continue; - - listnode_delete( - old_route->nh_list, - rnh); - ospf6_nexthop_delete(rnh); - } - } list_delete_all_node(o_path->nh_list); ospf6_copy_nexthops(o_path->nh_list, route->nh_list); + } - /* Merge nexthop to existing route's nh_list */ - ospf6_route_merge_nexthops(old_route, route); + /* Reset nexthop lists, rebuild from brouter table + * for each adv. router. + */ + list_delete_all_node(old_route->nh_list); - if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { - prefix2str(&route->prefix, buf, - sizeof(buf)); - zlog_debug( - "%s: existing route %s with effective nh count %u", - __PRETTY_FUNCTION__, buf, - old_route->nh_list - ? listcount( - old_route - ->nh_list) - : 0); + for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode, + o_path)) { + struct ospf6_route *asbr_entry; + + asbr_entry = ospf6_route_lookup( + &o_path->ls_prefix, + ospf6->brouter_table); + if (asbr_entry == NULL) { + if (IS_OSPF6_DEBUG_EXAMIN( + AS_EXTERNAL)) { + prefix2str(&old_route->prefix, + buf, sizeof(buf)); + zlog_debug("%s: ls_prfix %s asbr_entry not found.", + __PRETTY_FUNCTION__, + buf); + } + continue; } + ospf6_route_merge_nexthops(old_route, + asbr_entry); + } - /* Update RIB/FIB */ - if (ospf6->route_table->hook_add) - (*ospf6->route_table->hook_add)( - old_route); + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { + prefix2str(&route->prefix, buf, sizeof(buf)); + zlog_debug("%s: route %s with effective paths %u nh %u", + __PRETTY_FUNCTION__, buf, + old_route->paths ? + listcount(old_route->paths) : 0, + old_route->nh_list ? + listcount(old_route->nh_list) : 0); } + + /* Update RIB/FIB */ + if (ospf6->route_table->hook_add) + (*ospf6->route_table->hook_add)(old_route); + /* Delete the new route its info added to existing * route. */ @@ -509,8 +505,9 @@ void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa) route->path.origin.type = lsa->header->type; route->path.origin.id = lsa->header->id; route->path.origin.adv_router = lsa->header->adv_router; - route->path.prefix_options = external->prefix.prefix_options; + memcpy(&route->path.ls_prefix, &asbr_id, sizeof(struct prefix)); + if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_E)) { route->path.type = OSPF6_PATH_TYPE_EXTERNAL2; route->path.metric_type = 2; diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index 26e6deadae..d99541ebad 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -2037,6 +2037,8 @@ static void ospf6_brouter_debug_print(struct ospf6_route *brouter) zlog_info(" options: %s router-bits: %s metric-type: %d metric: %d/%d", options, capa, brouter->path.metric_type, brouter->path.cost, brouter->path.u.cost_e2); + zlog_info(" paths %u nh %u", listcount(brouter->paths), + listcount(brouter->nh_list)); } void ospf6_intra_brouter_calculation(struct ospf6_area *oa) diff --git a/sharpd/sharp_main.c b/sharpd/sharp_main.c index 1c80cf055a..a478b416bf 100644 --- a/sharpd/sharp_main.c +++ b/sharpd/sharp_main.c @@ -149,6 +149,8 @@ int main(int argc, char **argv, char **envp) vrf_init(NULL, NULL, NULL, NULL); + route_map_init(); + sharp_zebra_init(); /* Get configuration file. */ diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index 4d19484a64..956da9d4ed 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -81,14 +81,16 @@ DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd, DEFPY (install_routes, install_routes_cmd, - "sharp install routes A.B.C.D$start nexthop A.B.C.D$nexthop (1-1000000)$routes", + "sharp install routes A.B.C.D$start nexthop A.B.C.D$nexthop (1-1000000)$routes [instance (0-255)$instance]", "Sharp routing Protocol\n" "install some routes\n" "Routes to install\n" "Address to start /32 generation at\n" "Nexthop to use\n" "Nexthop address\n" - "How many to create\n") + "How many to create\n" + "Instance to use\n" + "Instance\n") { int i; struct prefix p; @@ -112,7 +114,7 @@ DEFPY (install_routes, temp = ntohl(p.u.prefix4.s_addr); for (i = 0; i < routes; i++) { - route_add(&p, &nhop); + route_add(&p, (uint8_t)instance, &nhop); p.u.prefix4.s_addr = htonl(++temp); } @@ -151,17 +153,18 @@ DEFPY(vrf_label, vrf_label_cmd, DEFPY (remove_routes, remove_routes_cmd, - "sharp remove routes A.B.C.D$start (1-1000000)$routes", + "sharp remove routes A.B.C.D$start (1-1000000)$routes [instance (0-255)$instance]", "Sharp Routing Protocol\n" "Remove some routes\n" "Routes to remove\n" "Starting spot\n" - "Routes to uniinstall\n") + "Routes to uniinstall\n" + "instance to use\n" + "Value of instance\n") { int i; struct prefix p; uint32_t temp; - total_routes = routes; removed_routes = 0; @@ -175,7 +178,7 @@ DEFPY (remove_routes, temp = ntohl(p.u.prefix4.s_addr); for (i = 0; i < routes; i++) { - route_delete(&p); + route_delete(&p, (uint8_t)instance); p.u.prefix4.s_addr = htonl(++temp); } diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index 999255e925..fcb555170b 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -176,7 +176,7 @@ void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label) zclient_send_vrf_label(zclient, vrf_id, afi, label, ZEBRA_LSP_SHARP); } -void route_add(struct prefix *p, struct nexthop *nh) +void route_add(struct prefix *p, uint8_t instance, struct nexthop *nh) { struct zapi_route api; struct zapi_nexthop *api_nh; @@ -184,6 +184,7 @@ void route_add(struct prefix *p, struct nexthop *nh) memset(&api, 0, sizeof(api)); api.vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_SHARP; + api.instance = instance; api.safi = SAFI_UNICAST; memcpy(&api.prefix, p, sizeof(*p)); @@ -200,7 +201,7 @@ void route_add(struct prefix *p, struct nexthop *nh) zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api); } -void route_delete(struct prefix *p) +void route_delete(struct prefix *p, uint8_t instance) { struct zapi_route api; @@ -208,6 +209,7 @@ void route_delete(struct prefix *p) api.vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_SHARP; api.safi = SAFI_UNICAST; + api.instance = instance; memcpy(&api.prefix, p, sizeof(*p)); zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); diff --git a/sharpd/sharp_zebra.h b/sharpd/sharp_zebra.h index 0c906fc4ff..58438ed01d 100644 --- a/sharpd/sharp_zebra.h +++ b/sharpd/sharp_zebra.h @@ -25,7 +25,7 @@ extern void sharp_zebra_init(void); extern void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label); -extern void route_add(struct prefix *p, struct nexthop *nh); -extern void route_delete(struct prefix *p); +extern void route_add(struct prefix *p, uint8_t instance, struct nexthop *nh); +extern void route_delete(struct prefix *p, uint8_t instance); extern void sharp_zebra_nexthop_watch(struct prefix *p, bool watch); #endif diff --git a/tests/Makefile.am b/tests/Makefile.am index 703c1d05fc..6a19325927 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -215,6 +215,7 @@ EXTRA_DIST = \ lib/test_ttable.refout \ lib/test_zlog.py \ lib/test_graph.py \ + lib/test_graph.refout \ ospf6d/test_lsdb.py \ ospf6d/test_lsdb.in \ ospf6d/test_lsdb.refout \ diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 4974e538ea..30de9d7711 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -846,27 +846,29 @@ int vtysh_config_from_file(struct vty *vty, FILE *fp) return (retcode); } -/* We don't care about the point of the cursor when '?' is typed. */ -static int vtysh_rl_describe(void) +/* + * Function processes cli commands terminated with '?' character when entered + * through either 'vtysh' or 'vtysh -c' interfaces. + */ +static int vtysh_process_questionmark(const char *input, int input_len) { - int ret; + int ret, width = 0; unsigned int i; - vector vline; - vector describe; - int width; + vector vline, describe; struct cmd_token *token; - vline = cmd_make_strvec(rl_line_buffer); + if (!input) + return 1; + + vline = cmd_make_strvec(input); /* In case of '> ?'. */ if (vline == NULL) { vline = vector_init(1); vector_set(vline, NULL); - } else if (rl_end && isspace((int)rl_line_buffer[rl_end - 1])) + } else if (input_len && isspace((int)input[input_len - 1])) vector_set(vline, NULL); - fprintf(stdout, "\n"); - describe = cmd_describe_command(vline, vty, &ret); /* Ambiguous and no match error. */ @@ -875,7 +877,6 @@ static int vtysh_rl_describe(void) cmd_free_strvec(vline); vector_free(describe); fprintf(stdout, "%% Ambiguous command.\n"); - rl_on_new_line(); return 0; break; case CMD_ERR_NO_MATCH: @@ -883,7 +884,6 @@ static int vtysh_rl_describe(void) if (describe) vector_free(describe); fprintf(stdout, "%% There is no matched command.\n"); - rl_on_new_line(); return 0; break; } @@ -933,9 +933,61 @@ static int vtysh_rl_describe(void) cmd_free_strvec(vline); vector_free(describe); + return 0; +} + +/* + * Entry point for user commands terminated with '?' character and typed through + * the usual vtysh's stdin interface. This is the function being registered with + * readline() api's. + */ +static int vtysh_rl_describe(void) +{ + int ret; + + fprintf(stdout, "\n"); + + ret = vtysh_process_questionmark(rl_line_buffer, rl_end); rl_on_new_line(); - return 0; + return ret; +} + +/* + * Function in charged of processing vtysh instructions terminating with '?' + * character and received through the 'vtysh -c' interface. If user's + * instruction is well-formatted, we will call the same processing routine + * utilized by the traditional vtysh's stdin interface. + */ +int vtysh_execute_command_questionmark(char *input) +{ + int input_len, qmark_count = 0; + const char *str; + + if (!(input && *input)) + return 1; + + /* Finding out question_mark count and strlen */ + for (str = input; *str; ++str) { + if (*str == '?') + qmark_count++; + } + input_len = str - input; + + /* + * Verify that user's input terminates in '?' and that patterns such as + * 'cmd ? subcmd ?' are prevented. + */ + if (qmark_count != 1 || input[input_len - 1] != '?') + return 1; + + /* + * Questionmark-processing function is not expecting to receive '?' + * character in input string. + */ + input[input_len - 1] = '\0'; + + return vtysh_process_questionmark(input, input_len - 1); } /* Result of cmd_complete_command() call will be stored here diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h index f3e58f309e..ccfdd6557b 100644 --- a/vtysh/vtysh.h +++ b/vtysh/vtysh.h @@ -71,6 +71,7 @@ void vtysh_user_init(void); int vtysh_execute(const char *); int vtysh_execute_no_pager(const char *); +int vtysh_execute_command_questionmark(char *input); char *vtysh_prompt(void); diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c index cd59d8094b..3dd70983bc 100644 --- a/vtysh/vtysh_main.c +++ b/vtysh/vtysh_main.c @@ -611,7 +611,16 @@ int main(int argc, char **argv, char **env) if (logfile) log_it(cmd->line); - ret = vtysh_execute_no_pager(cmd->line); + /* + * Parsing logic for regular commands will be different than + * for those commands requiring further processing, such as + * cli instructions terminating with question-mark character. + */ + if (!vtysh_execute_command_questionmark(cmd->line)) + ret = CMD_SUCCESS; + else + ret = vtysh_execute_no_pager(cmd->line); + if (!no_error && !(ret == CMD_SUCCESS || ret == CMD_SUCCESS_DAEMON || ret == CMD_WARNING)) diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 5a6565aec9..b1387815ba 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -539,8 +539,8 @@ int zebra_add_import_table_entry(struct route_node *rn, struct route_entry *re, afi = family2afi(rn->p.family); if (rmap_name) ret = zebra_import_table_route_map_check( - afi, re->type, &rn->p, re->ng.nexthop, re->vrf_id, - re->tag, rmap_name); + afi, re->type, re->instance, &rn->p, re->ng.nexthop, + re->vrf_id, re->tag, rmap_name); if (ret != RMAP_MATCH) { UNSET_FLAG(re->flags, ZEBRA_FLAG_SELECTED); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 9510a0e12c..2fd7bee056 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1308,8 +1308,7 @@ static int netlink_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla, struct zebra_ns *zns = zebra_ns_lookup(ns_id); - memset(&req.n, 0, sizeof(req.n)); - memset(&req.ndm, 0, sizeof(req.ndm)); + memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; @@ -1666,8 +1665,7 @@ int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in) struct zebra_ns *zns; zns = zvrf->zns; - memset(&req.n, 0, sizeof(req.n)); - memset(&req.ndm, 0, sizeof(req.ndm)); + memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; @@ -1759,8 +1757,7 @@ static int netlink_vxlan_flood_list_update(struct interface *ifp, struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id); zns = zvrf->zns; - memset(&req.n, 0, sizeof(req.n)); - memset(&req.ndm, 0, sizeof(req.ndm)); + memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; @@ -2075,8 +2072,7 @@ static int netlink_macfdb_update(struct interface *ifp, vlanid_t vid, return -1; } - memset(&req.n, 0, sizeof(req.n)); - memset(&req.ndm, 0, sizeof(req.ndm)); + memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; @@ -2392,8 +2388,7 @@ static int netlink_neigh_update2(struct interface *ifp, struct ipaddr *ip, struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id); zns = zvrf->zns; - memset(&req.n, 0, sizeof(req.n)); - memset(&req.ndm, 0, sizeof(req.ndm)); + memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 7ec640164a..dec4ed06a9 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -924,7 +924,7 @@ static unsigned nexthop_active_check(struct route_node *rn, memset(&nexthop->rmap_src.ipv6, 0, sizeof(union g_addr)); /* It'll get set if required inside */ - ret = zebra_route_map_check(family, re->type, p, nexthop, + ret = zebra_route_map_check(family, re->type, re->instance, p, nexthop, nexthop->vrf_id, re->tag); if (ret == RMAP_DENYMATCH) { if (IS_ZEBRA_DEBUG_RIB) { diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index 013e841a5c..10ba88880a 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -49,6 +49,7 @@ struct nh_rmap_obj { struct nexthop *nexthop; vrf_id_t vrf_id; uint32_t source_protocol; + uint8_t instance; int metric; route_tag_t tag; }; @@ -287,7 +288,7 @@ DEFUN (no_match_ip_nexthop_prefix_len, DEFUN (match_source_protocol, match_source_protocol_cmd, - "match source-protocol <bgp|ospf|rip|ripng|isis|ospf6|pim|nhrp|eigrp|babel|connected|system|kernel|static>", + "match source-protocol <bgp|ospf|rip|ripng|isis|ospf6|pim|nhrp|eigrp|babel|connected|system|kernel|static|sharp>", MATCH_STR "Match protocol via which the route was learnt\n" "BGP protocol\n" @@ -303,7 +304,8 @@ DEFUN (match_source_protocol, "Routes from directly connected peer\n" "Routes from system configuration\n" "Routes from kernel\n" - "Statically configured routes\n") + "Statically configured routes\n" + "SHARP process\n") { char *proto = argv[2]->text; int i; @@ -319,7 +321,7 @@ DEFUN (match_source_protocol, DEFUN (no_match_source_protocol, no_match_source_protocol_cmd, - "no match source-protocol [<bgp|ospf|rip|ripng|isis|ospf6|pim|nhrp|eigrp|babel|connected|system|kernel|static>]", + "no match source-protocol [<bgp|ospf|rip|ripng|isis|ospf6|pim|nhrp|eigrp|babel|connected|system|kernel|static|sharp>]", NO_STR MATCH_STR "No match protocol via which the route was learnt\n" @@ -336,13 +338,40 @@ DEFUN (no_match_source_protocol, "Routes from directly connected peer\n" "Routes from system configuration\n" "Routes from kernel\n" - "Statically configured routes\n") + "Statically configured routes\n" + "SHARP process\n") { char *proto = (argc == 4) ? argv[3]->text : NULL; return zebra_route_match_delete(vty, "source-protocol", proto, RMAP_EVENT_MATCH_DELETED); } +DEFUN (match_source_instance, + match_source_instance_cmd, + "match source-instance (0-255)", + MATCH_STR + "Match the protocol's instance number\n" + "The instance number\n") +{ + char *instance = argv[2]->arg; + + return zebra_route_match_add(vty, "source-instance", instance, + RMAP_EVENT_MATCH_ADDED); +} + +DEFUN (no_match_source_instance, + no_match_source_instance_cmd, + "no match source-instance [(0-255)]", + NO_STR MATCH_STR + "Match the protocol's instance number\n" + "The instance number\n") +{ + char *instance = (argc == 4) ? argv[3]->arg : NULL; + + return zebra_route_match_delete(vty, "source-instance", instance, + RMAP_EVENT_MATCH_ADDED); +} + /* set functions */ DEFUN (set_src, @@ -1172,6 +1201,47 @@ static struct route_map_rule_cmd route_match_source_protocol_cmd = { "source-protocol", route_match_source_protocol, route_match_source_protocol_compile, route_match_source_protocol_free}; +/* `source-instance` */ +static route_map_result_t route_match_source_instance(void *rule, + struct prefix *prefix, + route_map_object_t type, + void *object) +{ + uint8_t *instance = (uint8_t *)rule; + struct nh_rmap_obj *nh_data; + + if (type != RMAP_ZEBRA) + return RMAP_NOMATCH; + + nh_data = (struct nh_rmap_obj *)object; + if (!nh_data) + return RMAP_DENYMATCH; + + return (nh_data->instance == *instance) ? RMAP_MATCH : RMAP_NOMATCH; +} + +static void *route_match_source_instance_compile(const char *arg) +{ + uint8_t *instance; + int i; + + i = atoi(arg); + instance = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint8_t)); + + *instance = i; + + return instance; +} + +static void route_match_source_instance_free(void *rule) +{ + XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); +} + +static struct route_map_rule_cmd route_match_source_instance_cmd = { + "source-instance", route_match_source_instance, + route_match_source_instance_compile, route_match_source_instance_free}; + /* `set src A.B.C.D' */ /* Set src. */ @@ -1252,7 +1322,7 @@ void zebra_route_map_write_delay_timer(struct vty *vty) } route_map_result_t zebra_route_map_check(int family, int rib_type, - struct prefix *p, + uint8_t instance, struct prefix *p, struct nexthop *nexthop, vrf_id_t vrf_id, route_tag_t tag) { @@ -1263,6 +1333,7 @@ route_map_result_t zebra_route_map_check(int family, int rib_type, nh_obj.nexthop = nexthop; nh_obj.vrf_id = vrf_id; nh_obj.source_protocol = rib_type; + nh_obj.instance = instance; nh_obj.metric = 0; nh_obj.tag = tag; @@ -1296,9 +1367,10 @@ void zebra_del_import_table_route_map(afi_t afi, uint32_t table) } route_map_result_t -zebra_import_table_route_map_check(int family, int re_type, struct prefix *p, - struct nexthop *nexthop, vrf_id_t vrf_id, - route_tag_t tag, const char *rmap_name) +zebra_import_table_route_map_check(int family, int re_type, uint8_t instance, + struct prefix *p, struct nexthop *nexthop, + vrf_id_t vrf_id, route_tag_t tag, + const char *rmap_name) { struct route_map *rmap = NULL; route_map_result_t ret = RMAP_DENYMATCH; @@ -1307,6 +1379,7 @@ zebra_import_table_route_map_check(int family, int re_type, struct prefix *p, nh_obj.nexthop = nexthop; nh_obj.vrf_id = vrf_id; nh_obj.source_protocol = re_type; + nh_obj.instance = instance; nh_obj.metric = 0; nh_obj.tag = tag; @@ -1331,6 +1404,7 @@ route_map_result_t zebra_nht_route_map_check(int family, int client_proto, nh_obj.nexthop = nexthop; nh_obj.vrf_id = nexthop->vrf_id; nh_obj.source_protocol = re->type; + nh_obj.instance = re->instance; nh_obj.metric = re->metric; nh_obj.tag = re->tag; @@ -1471,6 +1545,8 @@ void zebra_route_map_init() route_map_install_match(&route_match_ipv6_address_prefix_len_cmd); route_map_install_match(&route_match_ip_nexthop_prefix_len_cmd); route_map_install_match(&route_match_source_protocol_cmd); + route_map_install_match(&route_match_source_instance_cmd); + /* */ route_map_install_set(&route_set_src_cmd); /* */ @@ -1482,6 +1558,9 @@ void zebra_route_map_init() install_element(RMAP_NODE, &no_match_ip_address_prefix_len_cmd); install_element(RMAP_NODE, &match_source_protocol_cmd); install_element(RMAP_NODE, &no_match_source_protocol_cmd); + install_element(RMAP_NODE, &match_source_instance_cmd); + install_element(RMAP_NODE, &no_match_source_instance_cmd); + /* */ install_element(RMAP_NODE, &set_src_cmd); install_element(RMAP_NODE, &no_set_src_cmd); diff --git a/zebra/zebra_routemap.h b/zebra/zebra_routemap.h index 14c7c58848..20d425a2bc 100644 --- a/zebra/zebra_routemap.h +++ b/zebra/zebra_routemap.h @@ -34,14 +34,14 @@ extern void zebra_del_import_table_route_map(afi_t afi, uint32_t table); extern void zebra_route_map_write_delay_timer(struct vty *); extern route_map_result_t -zebra_import_table_route_map_check(int family, int rib_type, struct prefix *p, - struct nexthop *nexthop, vrf_id_t vrf_id, - route_tag_t tag, const char *rmap_name); -extern route_map_result_t zebra_route_map_check(int family, int rib_type, - struct prefix *p, - struct nexthop *nexthop, - vrf_id_t vrf_id, - route_tag_t tag); +zebra_import_table_route_map_check(int family, int rib_type, uint8_t instance, + struct prefix *p, struct nexthop *nexthop, + vrf_id_t vrf_id, route_tag_t tag, + const char *rmap_name); +extern route_map_result_t +zebra_route_map_check(int family, int rib_type, uint8_t instance, + struct prefix *p, struct nexthop *nexthop, + vrf_id_t vrf_id, route_tag_t tag); extern route_map_result_t zebra_nht_route_map_check(int family, int client_proto, struct prefix *p, struct route_entry *, struct nexthop *nexthop); |
