diff options
269 files changed, 6522 insertions, 2018 deletions
diff --git a/Makefile.am b/Makefile.am index 7f7d7d6236..9e6c53d87c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,6 +4,8 @@ AUTOMAKE_OPTIONS = subdir-objects 1.12 ACLOCAL_AMFLAGS = -I m4 AM_CFLAGS = \ + $(LIBYANG_CFLAGS) \ + $(SQLITE3_CFLAGS) \ $(UNWIND_CFLAGS) \ $(SAN_FLAGS) \ $(WERROR) \ @@ -17,7 +19,6 @@ AM_LDFLAGS = \ $(SAN_FLAGS) \ # end DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -DCONFDATE=$(CONFDATE) -LIBCAP = @LIBCAP@ AR_FLAGS = @AR_FLAGS@ ARFLAGS = @ARFLAGS@ @@ -18,6 +18,8 @@ FRR currently supports the following protocols: * LDP * BFD * Babel +* PBR +* OpenFabric * EIGRP (alpha) * NHRP (alpha) diff --git a/babeld/subdir.am b/babeld/subdir.am index e1f2cb0a00..7081c730aa 100644 --- a/babeld/subdir.am +++ b/babeld/subdir.am @@ -51,4 +51,4 @@ noinst_HEADERS += \ # end babeld_babeld_SOURCES = babeld/babel_main.c -babeld_babeld_LDADD = babeld/libbabel.a lib/libfrr.la @LIBCAP@ +babeld_babeld_LDADD = babeld/libbabel.a lib/libfrr.la $(LIBCAP) diff --git a/bfdd/Makefile b/bfdd/Makefile new file mode 100644 index 0000000000..dfe78232c4 --- /dev/null +++ b/bfdd/Makefile @@ -0,0 +1,10 @@ +all: ALWAYS + @$(MAKE) -s -C .. bfdd/bfdd +%: ALWAYS + @$(MAKE) -s -C .. bfdd/$@ + +Makefile: + #nothing +ALWAYS: +.PHONY: ALWAYS makefiles +.SUFFIXES: diff --git a/bfdd/bfdd_vty.c b/bfdd/bfdd_vty.c index 8f8fff6b18..3476e16210 100644 --- a/bfdd/bfdd_vty.c +++ b/bfdd/bfdd_vty.c @@ -968,6 +968,18 @@ static void _bfdd_peer_write_config(struct hash_backet *hb, void *arg) vty_out(vty, " !\n"); } +DEFUN_NOSH(show_debugging_bfd, + show_debugging_bfd_cmd, + "show debugging [bfd]", + SHOW_STR + DEBUG_STR + "BFD daemon\n") +{ + vty_out(vty, "BFD debugging status:\n"); + + return CMD_SUCCESS; +} + static int bfdd_peer_write_config(struct vty *vty) { bfd_id_iterate(_bfdd_peer_write_config, vty); @@ -993,6 +1005,7 @@ void bfdd_vty_init(void) install_element(ENABLE_NODE, &bfd_show_peers_cmd); install_element(ENABLE_NODE, &bfd_show_peer_cmd); install_element(CONFIG_NODE, &bfd_enter_cmd); + install_element(ENABLE_NODE, &show_debugging_bfd_cmd); /* Install BFD node and commands. */ install_node(&bfd_node, bfdd_write_config); diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 4f756519ca..9521a9e912 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -1381,39 +1381,45 @@ static struct aspath *aspath_merge(struct aspath *as1, struct aspath *as2) /* Prepend as1 to as2. as2 should be uninterned aspath. */ struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2) { - struct assegment *seg1; - struct assegment *seg2; + struct assegment *as1segtail; + struct assegment *as2segtail; + struct assegment *as2seghead; if (!as1 || !as2) return NULL; - seg1 = as1->segments; - seg2 = as2->segments; - /* If as2 is empty, only need to dupe as1's chain onto as2 */ - if (seg2 == NULL) { + if (as2->segments == NULL) { as2->segments = assegment_dup_all(as1->segments); aspath_str_update(as2, false); return as2; } /* If as1 is empty AS, no prepending to do. */ - if (seg1 == NULL) + if (as1->segments == NULL) return as2; /* find the tail as1's segment chain. */ - while (seg1 && seg1->next) - seg1 = seg1->next; + as1segtail = as1->segments; + while (as1segtail && as1segtail->next) + as1segtail = as1segtail->next; /* Delete any AS_CONFED_SEQUENCE segment from as2. */ - if (seg1->type == AS_SEQUENCE && seg2->type == AS_CONFED_SEQUENCE) + if (as1segtail->type == AS_SEQUENCE + && as2->segments->type == AS_CONFED_SEQUENCE) as2 = aspath_delete_confed_seq(as2); + if (!as2->segments) { + as2->segments = assegment_dup_all(as1->segments); + aspath_str_update(as2, false); + return as2; + } + /* Compare last segment type of as1 and first segment type of as2. */ - if (seg1->type != seg2->type) + if (as1segtail->type != as2->segments->type) return aspath_merge(as1, as2); - if (seg1->type == AS_SEQUENCE) { + if (as1segtail->type == AS_SEQUENCE) { /* We have two chains of segments, as1->segments and seg2, * and we have to attach them together, merging the attaching * segments together into one. @@ -1423,23 +1429,28 @@ struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2) * 3. attach chain after seg2 */ + /* save as2 head */ + as2seghead = as2->segments; + /* dupe as1 onto as2's head */ - seg1 = as2->segments = assegment_dup_all(as1->segments); + as2segtail = as2->segments = assegment_dup_all(as1->segments); - /* refind the tail of as2, reusing seg1 */ - while (seg1 && seg1->next) - seg1 = seg1->next; + /* refind the tail of as2 */ + while (as2segtail && as2segtail->next) + as2segtail = as2segtail->next; /* merge the old head, seg2, into tail, seg1 */ - seg1 = assegment_append_asns(seg1, seg2->as, seg2->length); + assegment_append_asns(as2segtail, as2seghead->as, + as2seghead->length); - /* bypass the merged seg2, and attach any chain after it to - * chain descending from as2's head + /* + * bypass the merged seg2, and attach any chain after it + * to chain descending from as2's head */ - seg1->next = seg2->next; + as2segtail->next = as2seghead->next; - /* seg2 is now referenceless and useless*/ - assegment_free(seg2); + /* as2->segments is now referenceless and useless */ + assegment_free(as2seghead); /* we've now prepended as1's segment chain to as2, merging * the inbetween AS_SEQUENCE of seg2 in the process diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 39ba404f38..f476b16188 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -2123,67 +2123,6 @@ DEFUN_NOSH (show_debugging_bgp, return CMD_SUCCESS; } -/* return count of number of debug flags set */ -int bgp_debug_count(void) -{ - int ret = 0; - if (BGP_DEBUG(as4, AS4)) - ret++; - - if (BGP_DEBUG(as4, AS4_SEGMENT)) - ret++; - - if (BGP_DEBUG(bestpath, BESTPATH)) - ret++; - - if (BGP_DEBUG(keepalive, KEEPALIVE)) - ret++; - - if (BGP_DEBUG(neighbor_events, NEIGHBOR_EVENTS)) - ret++; - - if (BGP_DEBUG(nht, NHT)) - ret++; - - if (BGP_DEBUG(update_groups, UPDATE_GROUPS)) - ret++; - - if (BGP_DEBUG(update, UPDATE_PREFIX)) - ret++; - - if (BGP_DEBUG(update, UPDATE_IN)) - ret++; - - if (BGP_DEBUG(update, UPDATE_OUT)) - ret++; - - if (BGP_DEBUG(zebra, ZEBRA)) - ret++; - - if (BGP_DEBUG(allow_martians, ALLOW_MARTIANS)) - ret++; - - if (BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF)) - ret++; - if (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF)) - ret++; - if (BGP_DEBUG(vpn, VPN_LEAK_RMAP_EVENT)) - ret++; - if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) - ret++; - if (BGP_DEBUG(flowspec, FLOWSPEC)) - ret++; - if (BGP_DEBUG(labelpool, LABELPOOL)) - ret++; - - if (BGP_DEBUG(pbr, PBR)) - ret++; - if (BGP_DEBUG(pbr, PBR_ERROR)) - ret++; - - return ret; -} - static int bgp_config_write_debug(struct vty *vty) { int write = 0; diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h index d5d8fbb505..e05da37647 100644 --- a/bgpd/bgp_debug.h +++ b/bgpd/bgp_debug.h @@ -168,7 +168,6 @@ extern int bgp_debug_update(struct peer *peer, struct prefix *p, extern int bgp_debug_bestpath(struct prefix *p); extern int bgp_debug_zebra(struct prefix *p); -extern int bgp_debug_count(void); extern const char *bgp_debug_rdpfxpath2str(afi_t, safi_t, struct prefix_rd *, union prefixconstptr, mpls_label_t *, uint32_t, int, uint32_t, char *, diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index 43b1f05b3d..c7f2671b78 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -73,6 +73,9 @@ struct bgpevpn { * advertising subnet for this VNI */ uint8_t advertise_subnet; + /* Flag to indicate if we are advertising the svi mac ip for this VNI*/ + uint8_t advertise_svi_macip; + /* Id for deriving the RD * automatically for this VNI */ uint16_t rd_id; @@ -177,6 +180,10 @@ struct bgp_evpn_info { bool dad_freeze; /* Recovery time */ uint32_t dad_freeze_time; + + /* EVPN enable - advertise svi macip routes */ + int advertise_svi_macip; + }; static inline int is_vrf_rd_configured(struct bgp *bgp_vrf) diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 776f8f8ef7..a3d8b8a647 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -489,6 +489,8 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json) inet_ntoa(vpn->originator_ip)); vty_out(vty, " Advertise-gw-macip : %s\n", vpn->advertise_gw_macip ? "Yes" : "No"); + vty_out(vty, " Advertise-svi-macip : %s\n", + vpn->advertise_svi_macip ? "Yes" : "No"); } if (!json) @@ -2619,6 +2621,33 @@ static void evpn_show_all_vnis(struct vty *vty, struct bgp *bgp, } /* + * evpn - enable advertisement of svi MAC-IP + */ +static void evpn_set_advertise_svi_macip(struct bgp *bgp, struct bgpevpn *vpn, + uint32_t set) +{ + if (!vpn) { + if (set && bgp->evpn_info->advertise_svi_macip) + return; + else if (!set && !bgp->evpn_info->advertise_svi_macip) + return; + + bgp->evpn_info->advertise_svi_macip = set; + bgp_zebra_advertise_svi_macip(bgp, + bgp->evpn_info->advertise_svi_macip, 0); + } else { + if (set && vpn->advertise_svi_macip) + return; + else if (!set && !vpn->advertise_svi_macip) + return; + + vpn->advertise_svi_macip = set; + bgp_zebra_advertise_svi_macip(bgp, vpn->advertise_svi_macip, + vpn->vni); + } +} + +/* * evpn - enable advertisement of default g/w */ static void evpn_set_advertise_default_gw(struct bgp *bgp, struct bgpevpn *vpn) @@ -2798,6 +2827,9 @@ static void write_vni_config(struct vty *vty, struct bgpevpn *vpn) if (vpn->advertise_gw_macip) vty_out(vty, " advertise-default-gw\n"); + if (vpn->advertise_svi_macip) + vty_out(vty, " advertise-svi-ip\n"); + if (vpn->advertise_subnet) vty_out(vty, " advertise-subnet\n"); @@ -3151,6 +3183,54 @@ DEFPY (no_dup_addr_detection, return CMD_SUCCESS; } +DEFPY(bgp_evpn_advertise_svi_ip, + bgp_evpn_advertise_svi_ip_cmd, + "[no$no] advertise-svi-ip", + NO_STR + "Advertise svi mac-ip routes in EVPN\n") +{ + struct bgp *bgp = VTY_GET_CONTEXT(bgp); + + if (!bgp) + return CMD_WARNING; + + if (bgp->vrf_id != VRF_DEFAULT) { + vty_out(vty, + "This command is only supported under Default VRF\n"); + return CMD_WARNING; + } + + if (no) + evpn_set_advertise_svi_macip(bgp, NULL, 0); + else + evpn_set_advertise_svi_macip(bgp, NULL, 1); + + return CMD_SUCCESS; +} + +DEFPY(bgp_evpn_advertise_svi_ip_vni, + bgp_evpn_advertise_svi_ip_vni_cmd, + "[no$no] advertise-svi-ip", + NO_STR + "Advertise svi mac-ip routes in EVPN for a VNI\n") +{ + struct bgp *bgp = VTY_GET_CONTEXT(bgp); + VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn); + + if (!bgp) + return CMD_WARNING; + + if (!vpn) + return CMD_WARNING; + + if (no) + evpn_set_advertise_svi_macip(bgp, vpn, 0); + else + evpn_set_advertise_svi_macip(bgp, vpn, 1); + + return CMD_SUCCESS; +} + DEFUN_HIDDEN (bgp_evpn_advertise_vni_subnet, bgp_evpn_advertise_vni_subnet_cmd, "advertise-subnet", @@ -3260,6 +3340,8 @@ DEFUN (bgp_evpn_advertise_type5, if (bgp_vrf->adv_cmd_rmap[afi][safi].name) { XFREE(MTYPE_ROUTE_MAP_NAME, bgp_vrf->adv_cmd_rmap[afi][safi].name); + route_map_counter_decrement( + bgp_vrf->adv_cmd_rmap[afi][safi].map); bgp_vrf->adv_cmd_rmap[afi][safi].name = NULL; bgp_vrf->adv_cmd_rmap[afi][safi].map = NULL; } @@ -3271,6 +3353,8 @@ DEFUN (bgp_evpn_advertise_type5, XSTRDUP(MTYPE_ROUTE_MAP_NAME, argv[idx_rmap + 1]->arg); bgp_vrf->adv_cmd_rmap[afi][safi].map = route_map_lookup_by_name(argv[idx_rmap + 1]->arg); + route_map_counter_increment( + bgp_vrf->adv_cmd_rmap[afi][safi].map); } /* advertise type-5 routes */ @@ -3409,6 +3493,9 @@ DEFUN(show_bgp_l2vpn_evpn_vni, vty_out(vty, "Advertise Gateway Macip: %s\n", bgp_def->advertise_gw_macip ? "Enabled" : "Disabled"); + vty_out(vty, "Advertise SVI Macip: %s\n", + bgp_def->evpn_info->advertise_svi_macip ? "Enabled" + : "Disabled"); vty_out(vty, "Advertise All VNI flag: %s\n", is_evpn_enabled() ? "Enabled" : "Disabled"); vty_out(vty, "BUM flooding: %s\n", @@ -5071,6 +5158,9 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi, if (bgp->advertise_gw_macip) vty_out(vty, " advertise-default-gw\n"); + if (bgp->evpn_info->advertise_svi_macip) + vty_out(vty, " advertise-svi-ip\n"); + if (!bgp->evpn_info->dup_addr_detect) vty_out(vty, " no dup-addr-detection\n"); @@ -5181,6 +5271,7 @@ void bgp_ethernetvpn_init(void) install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_autort_rfc8365_cmd); install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_default_gw_cmd); install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_default_gw_cmd); + install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_svi_ip_cmd); install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_type5_cmd); install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_type5_cmd); install_element(BGP_EVPN_NODE, &bgp_evpn_default_originate_cmd); @@ -5237,6 +5328,7 @@ void bgp_ethernetvpn_init(void) install_element(BGP_NODE, &no_bgp_evpn_vrf_rd_without_val_cmd); install_element(BGP_EVPN_NODE, &bgp_evpn_vrf_rt_cmd); install_element(BGP_EVPN_NODE, &no_bgp_evpn_vrf_rt_cmd); + install_element(BGP_EVPN_VNI_NODE, &bgp_evpn_advertise_svi_ip_vni_cmd); install_element(BGP_EVPN_VNI_NODE, &bgp_evpn_advertise_default_gw_vni_cmd); install_element(BGP_EVPN_VNI_NODE, diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 99dc9d8124..59ca223a2d 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -4417,6 +4417,8 @@ static void bgp_static_free(struct bgp_static *bgp_static) { if (bgp_static->rmap.name) XFREE(MTYPE_ROUTE_MAP_NAME, bgp_static->rmap.name); + route_map_counter_decrement(bgp_static->rmap.map); + if (bgp_static->eth_s_id) XFREE(MTYPE_ATTR, bgp_static->eth_s_id); XFREE(MTYPE_BGP_STATIC, bgp_static); @@ -4981,14 +4983,20 @@ static int bgp_static_set(struct vty *vty, const char *negate, if (bgp_static->rmap.name) XFREE(MTYPE_ROUTE_MAP_NAME, bgp_static->rmap.name); + route_map_counter_decrement( + bgp_static->rmap.map); bgp_static->rmap.name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap); bgp_static->rmap.map = route_map_lookup_by_name(rmap); + route_map_counter_increment( + bgp_static->rmap.map); } else { if (bgp_static->rmap.name) XFREE(MTYPE_ROUTE_MAP_NAME, bgp_static->rmap.name); + route_map_counter_decrement( + bgp_static->rmap.map); bgp_static->rmap.name = NULL; bgp_static->rmap.map = NULL; bgp_static->valid = 0; @@ -5007,10 +5015,14 @@ static int bgp_static_set(struct vty *vty, const char *negate, if (bgp_static->rmap.name) XFREE(MTYPE_ROUTE_MAP_NAME, bgp_static->rmap.name); + route_map_counter_decrement( + bgp_static->rmap.map); bgp_static->rmap.name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap); bgp_static->rmap.map = route_map_lookup_by_name(rmap); + route_map_counter_increment( + bgp_static->rmap.map); } bgp_node_set_bgp_static_info(rn, bgp_static); } @@ -5289,10 +5301,12 @@ int bgp_static_set_safi(afi_t afi, safi_t safi, struct vty *vty, if (bgp_static->rmap.name) XFREE(MTYPE_ROUTE_MAP_NAME, bgp_static->rmap.name); + route_map_counter_decrement(bgp_static->rmap.map); bgp_static->rmap.name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_str); bgp_static->rmap.map = route_map_lookup_by_name(rmap_str); + route_map_counter_increment(bgp_static->rmap.map); } if (safi == SAFI_EVPN) { @@ -5395,11 +5409,14 @@ static int bgp_table_map_set(struct vty *vty, afi_t afi, safi_t safi, if (rmap_name) { if (rmap->name) XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name); + route_map_counter_decrement(rmap->map); rmap->name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_name); rmap->map = route_map_lookup_by_name(rmap_name); + route_map_counter_increment(rmap->map); } else { if (rmap->name) XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name); + route_map_counter_decrement(rmap->map); rmap->name = NULL; rmap->map = NULL; } @@ -5419,6 +5436,7 @@ static int bgp_table_map_unset(struct vty *vty, afi_t afi, safi_t safi, rmap = &bgp->table_map[afi][safi]; if (rmap->name) XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name); + route_map_counter_decrement(rmap->map); rmap->name = NULL; rmap->map = NULL; diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 4953032f97..e28acdfbae 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -3250,6 +3250,15 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name, if (bgp->table_map[afi][safi].name && (strcmp(rmap_name, bgp->table_map[afi][safi].name) == 0)) { + + /* bgp->table_map[afi][safi].map is NULL. + * i.e Route map creation event. + * So update applied_counter. + * If it is not NULL, i.e It may be routemap updation or + * deletion. so no need to update the counter. + */ + if (!bgp->table_map[afi][safi].map) + route_map_counter_increment(map); bgp->table_map[afi][safi].map = map; if (BGP_DEBUG(zebra, ZEBRA)) @@ -3272,6 +3281,9 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name, || (strcmp(rmap_name, bgp_static->rmap.name) != 0)) continue; + if (!bgp_static->rmap.map) + route_map_counter_increment(map); + bgp_static->rmap.map = map; if (route_update && !bgp_static->backdoor) { @@ -3303,6 +3315,9 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name, || (strcmp(rmap_name, red->rmap.name) != 0)) continue; + if (!red->rmap.map) + route_map_counter_increment(map); + red->rmap.map = map; if (!route_update) diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index b614e87d23..a38d78916c 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -1134,7 +1134,7 @@ DEFPY (no_rpki_cache, { struct cache *cache_p = find_cache(preference); - if (!cache) { + if (!cache_p) { vty_out(vty, "Could not find cache %ld\n", preference); return CMD_WARNING; } @@ -1190,9 +1190,23 @@ DEFUN (show_rpki_cache_server, struct cache *cache; for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) { - vty_out(vty, "host: %s port: %s\n", - cache->tr_config.tcp_config->host, - cache->tr_config.tcp_config->port); + if (cache->type == TCP) { + vty_out(vty, "host: %s port: %s\n", + cache->tr_config.tcp_config->host, + cache->tr_config.tcp_config->port); + + } else if (cache->type == SSH) { + vty_out(vty, + "host: %s port: %d username: %s " + "server_hostkey_path: %s client_privkey_path: %s\n", + cache->tr_config.ssh_config->host, + cache->tr_config.ssh_config->port, + cache->tr_config.ssh_config->username, + cache->tr_config.ssh_config + ->server_hostkey_path, + cache->tr_config.ssh_config + ->client_privkey_path); + } } return CMD_SUCCESS; diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index be6c06d236..93d89668e7 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -11650,11 +11650,11 @@ static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group) conf = group->conf; if (conf->as_type == AS_SPECIFIED || conf->as_type == AS_EXTERNAL) { - vty_out(vty, "\nBGP peer-group %s, remote AS %d\n", group->name, - conf->as); + vty_out(vty, "\nBGP peer-group %s, remote AS %" PRIu32 "\n", + group->name, conf->as); } else if (conf->as_type == AS_INTERNAL) { - vty_out(vty, "\nBGP peer-group %s, remote AS %d\n", group->name, - group->bgp->as); + vty_out(vty, "\nBGP peer-group %s, remote AS %" PRIu32 "\n", + group->name, group->bgp->as); } else { vty_out(vty, "\nBGP peer-group %s\n", group->name); } diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 75da038829..3f18d69a2d 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1683,8 +1683,13 @@ int bgp_redistribute_rmap_set(struct bgp_redist *red, const char *name, if (red->rmap.name) XFREE(MTYPE_ROUTE_MAP_NAME, red->rmap.name); + /* Decrement the count for existing routemap and + * increment the count for new route map. + */ + route_map_counter_decrement(red->rmap.map); red->rmap.name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, name); red->rmap.map = route_map; + route_map_counter_increment(red->rmap.map); return 1; } @@ -1792,6 +1797,7 @@ int bgp_redistribute_unset(struct bgp *bgp, afi_t afi, int type, /* Unset route-map. */ if (red->rmap.name) XFREE(MTYPE_ROUTE_MAP_NAME, red->rmap.name); + route_map_counter_decrement(red->rmap.map); red->rmap.name = NULL; red->rmap.map = NULL; @@ -1930,6 +1936,29 @@ int bgp_zebra_advertise_subnet(struct bgp *bgp, int advertise, vni_t vni) return zclient_send_message(zclient); } +int bgp_zebra_advertise_svi_macip(struct bgp *bgp, int advertise, vni_t vni) +{ + struct stream *s = NULL; + + /* Check socket. */ + if (!zclient || zclient->sock < 0) + return 0; + + /* Don't try to register if Zebra doesn't know of this instance. */ + if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) + return 0; + + s = zclient->obuf; + stream_reset(s); + + zclient_create_header(s, ZEBRA_ADVERTISE_SVI_MACIP, bgp->vrf_id); + stream_putc(s, advertise); + stream_putl(s, vni); + stream_putw_at(s, 0, stream_get_endp(s)); + + return zclient_send_message(zclient); +} + int bgp_zebra_advertise_gw_macip(struct bgp *bgp, int advertise, vni_t vni) { struct stream *s = NULL; diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index c6520c43e4..fc19c5e17f 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -72,6 +72,8 @@ extern struct interface *if_lookup_by_ipv6_exact(struct in6_addr *, ifindex_t, extern int bgp_zebra_advertise_subnet(struct bgp *bgp, int advertise, vni_t vni); extern int bgp_zebra_advertise_gw_macip(struct bgp *, int, vni_t); +extern int bgp_zebra_advertise_svi_macip(struct bgp *bgp, int advertise, + vni_t vni); extern int bgp_zebra_advertise_all_vni(struct bgp *, int); extern int bgp_zebra_dup_addr_detection(struct bgp *bgp); extern int bgp_zebra_vxlan_flood_control(struct bgp *bgp, diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 0ab9a0b921..0ff9d75781 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -4594,15 +4594,18 @@ int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi, XFREE(MTYPE_ROUTE_MAP_NAME, peer->default_rmap[afi][safi].name); + route_map_counter_decrement(peer->default_rmap[afi][safi].map); peer->default_rmap[afi][safi].name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap); peer->default_rmap[afi][safi].map = route_map; + route_map_counter_increment(route_map); } } else if (!rmap) { if (peer->default_rmap[afi][safi].name) XFREE(MTYPE_ROUTE_MAP_NAME, peer->default_rmap[afi][safi].name); + route_map_counter_decrement(peer->default_rmap[afi][safi].map); peer->default_rmap[afi][safi].name = NULL; peer->default_rmap[afi][safi].map = NULL; } @@ -4637,10 +4640,12 @@ int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi, if (member->default_rmap[afi][safi].name) XFREE(MTYPE_ROUTE_MAP_NAME, member->default_rmap[afi][safi].name); - + route_map_counter_decrement( + member->default_rmap[afi][safi].map); member->default_rmap[afi][safi].name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap); member->default_rmap[afi][safi].map = route_map; + route_map_counter_increment(route_map); } /* Update peer route announcements. */ @@ -4677,6 +4682,7 @@ int peer_default_originate_unset(struct peer *peer, afi_t afi, safi_t safi) if (peer->default_rmap[afi][safi].name) XFREE(MTYPE_ROUTE_MAP_NAME, peer->default_rmap[afi][safi].name); + route_map_counter_decrement(peer->default_rmap[afi][safi].map); peer->default_rmap[afi][safi].name = NULL; peer->default_rmap[afi][safi].map = NULL; } @@ -4710,6 +4716,7 @@ int peer_default_originate_unset(struct peer *peer, afi_t afi, safi_t safi) if (peer->default_rmap[afi][safi].name) XFREE(MTYPE_ROUTE_MAP_NAME, peer->default_rmap[afi][safi].name); + route_map_counter_decrement(peer->default_rmap[afi][safi].map); peer->default_rmap[afi][safi].name = NULL; peer->default_rmap[afi][safi].map = NULL; @@ -6118,8 +6125,10 @@ int peer_route_map_set(struct peer *peer, afi_t afi, safi_t safi, int direct, filter = &peer->filter[afi][safi]; if (filter->map[direct].name) XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name); + route_map_counter_decrement(filter->map[direct].map); filter->map[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name); filter->map[direct].map = route_map; + route_map_counter_increment(route_map); /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { @@ -6147,8 +6156,10 @@ int peer_route_map_set(struct peer *peer, afi_t afi, safi_t safi, int direct, filter = &member->filter[afi][safi]; if (filter->map[direct].name) XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name); + route_map_counter_decrement(filter->map[direct].map); filter->map[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name); filter->map[direct].map = route_map; + route_map_counter_increment(route_map); /* Process peer route updates. */ peer_on_policy_change(member, afi, safi, @@ -6182,6 +6193,7 @@ int peer_route_map_unset(struct peer *peer, afi_t afi, safi_t safi, int direct) filter = &peer->filter[afi][safi]; if (filter->map[direct].name) XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name); + route_map_counter_decrement(filter->map[direct].map); filter->map[direct].name = NULL; filter->map[direct].map = NULL; } @@ -6210,6 +6222,7 @@ int peer_route_map_unset(struct peer *peer, afi_t afi, safi_t safi, int direct) filter = &member->filter[afi][safi]; if (filter->map[direct].name) XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name); + route_map_counter_decrement(filter->map[direct].map); filter->map[direct].name = NULL; filter->map[direct].map = NULL; @@ -6233,8 +6246,10 @@ int peer_unsuppress_map_set(struct peer *peer, afi_t afi, safi_t safi, filter = &peer->filter[afi][safi]; if (filter->usmap.name) XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name); + route_map_counter_decrement(filter->usmap.map); filter->usmap.name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name); filter->usmap.map = route_map; + route_map_counter_increment(route_map); /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { @@ -6261,8 +6276,10 @@ int peer_unsuppress_map_set(struct peer *peer, afi_t afi, safi_t safi, filter = &member->filter[afi][safi]; if (filter->usmap.name) XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name); + route_map_counter_decrement(filter->usmap.map); filter->usmap.name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name); filter->usmap.map = route_map; + route_map_counter_increment(route_map); /* Process peer route updates. */ peer_on_policy_change(member, afi, safi, 1); @@ -6293,6 +6310,7 @@ int peer_unsuppress_map_unset(struct peer *peer, afi_t afi, safi_t safi) filter = &peer->filter[afi][safi]; if (filter->usmap.name) XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name); + route_map_counter_decrement(filter->usmap.map); filter->usmap.name = NULL; filter->usmap.map = NULL; } @@ -6320,6 +6338,7 @@ int peer_unsuppress_map_unset(struct peer *peer, afi_t afi, safi_t safi) filter = &member->filter[afi][safi]; if (filter->usmap.name) XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name); + route_map_counter_decrement(filter->usmap.map); filter->usmap.name = NULL; filter->usmap.map = NULL; @@ -7838,9 +7857,11 @@ void bgp_master_init(struct thread_master *master) */ static void bgp_if_finish(struct bgp *bgp) { - struct vrf *vrf = vrf_lookup_by_id(bgp->vrf_id); + struct vrf *vrf; struct interface *ifp; + vrf = bgp_vrf_lookup_by_instance_type(bgp); + if (bgp->inst_type == BGP_INSTANCE_TYPE_VIEW || !vrf) return; diff --git a/bgpd/rfapi/bgp_rfapi_cfg.c b/bgpd/rfapi/bgp_rfapi_cfg.c index 05e057f07f..d621d58e48 100644 --- a/bgpd/rfapi/bgp_rfapi_cfg.c +++ b/bgpd/rfapi/bgp_rfapi_cfg.c @@ -1164,9 +1164,16 @@ DEFUN (vnc_redist_bgpdirect_routemap, if (hc->routemap_redist_name[route_type]) free(hc->routemap_redist_name[route_type]); + + /* If the old route map config overwrite with new + * route map config , old routemap counter have to be + * reduced. + */ + route_map_counter_decrement(hc->routemap_redist[route_type]); hc->routemap_redist_name[route_type] = strdup(argv[4]->arg); hc->routemap_redist[route_type] = route_map_lookup_by_name(argv[4]->arg); + route_map_counter_increment(hc->routemap_redist[route_type]); vnc_redistribute_postchange(bgp); @@ -1285,6 +1292,8 @@ DEFUN (vnc_nve_group_redist_bgpdirect_no_routemap, if (rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT]) free(rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT]); + route_map_counter_decrement( + rfg->routemap_redist[ZEBRA_ROUTE_BGP_DIRECT]); rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT] = NULL; rfg->routemap_redist[ZEBRA_ROUTE_BGP_DIRECT] = NULL; @@ -1316,10 +1325,14 @@ DEFUN (vnc_nve_group_redist_bgpdirect_routemap, if (rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT]) free(rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT]); + route_map_counter_decrement( + rfg->routemap_redist[ZEBRA_ROUTE_BGP_DIRECT]); rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT] = strdup(argv[3]->arg); rfg->routemap_redist[ZEBRA_ROUTE_BGP_DIRECT] = route_map_lookup_by_name(argv[3]->arg); + route_map_counter_increment( + rfg->routemap_redist[ZEBRA_ROUTE_BGP_DIRECT]); vnc_redistribute_postchange(bgp); @@ -1741,6 +1754,7 @@ DEFUN (vnc_nve_group_export_no_routemap, rfg->routemap_export_bgp_name))) { if (rfg->routemap_export_bgp_name) free(rfg->routemap_export_bgp_name); + route_map_counter_decrement(rfg->routemap_export_bgp); rfg->routemap_export_bgp_name = NULL; rfg->routemap_export_bgp = NULL; @@ -1754,6 +1768,7 @@ DEFUN (vnc_nve_group_export_no_routemap, rfg->routemap_export_zebra_name))) { if (rfg->routemap_export_zebra_name) free(rfg->routemap_export_zebra_name); + route_map_counter_decrement(rfg->routemap_export_zebra); rfg->routemap_export_zebra_name = NULL; rfg->routemap_export_zebra = NULL; @@ -1800,17 +1815,21 @@ DEFUN (vnc_nve_group_export_routemap, if (is_bgp) { if (rfg->routemap_export_bgp_name) free(rfg->routemap_export_bgp_name); + route_map_counter_decrement(rfg->routemap_export_bgp); rfg->routemap_export_bgp_name = strdup(argv[idx]->arg); rfg->routemap_export_bgp = route_map_lookup_by_name(argv[idx]->arg); + route_map_counter_increment(rfg->routemap_export_bgp); vnc_direct_bgp_reexport_group_afi(bgp, rfg, AFI_IP); vnc_direct_bgp_reexport_group_afi(bgp, rfg, AFI_IP6); } else { if (rfg->routemap_export_zebra_name) free(rfg->routemap_export_zebra_name); + route_map_counter_decrement(rfg->routemap_export_zebra); rfg->routemap_export_zebra_name = strdup(argv[idx]->arg); rfg->routemap_export_zebra = route_map_lookup_by_name(argv[idx]->arg); + route_map_counter_increment(rfg->routemap_export_zebra); vnc_zebra_reexport_group_afi(bgp, rfg, AFI_IP); vnc_zebra_reexport_group_afi(bgp, rfg, AFI_IP6); } @@ -1937,6 +1956,7 @@ DEFUN (vnc_nve_export_no_routemap, || (argc <= 5)) { free(hc->routemap_export_bgp_name); + route_map_counter_decrement(hc->routemap_export_bgp); hc->routemap_export_bgp_name = NULL; hc->routemap_export_bgp = NULL; vnc_direct_bgp_reexport(bgp, AFI_IP); @@ -1948,6 +1968,7 @@ DEFUN (vnc_nve_export_no_routemap, || (argc <= 5)) { free(hc->routemap_export_zebra_name); + route_map_counter_decrement(hc->routemap_export_zebra); hc->routemap_export_zebra_name = NULL; hc->routemap_export_zebra = NULL; /* TBD vnc_zebra_rh_reexport(bgp, AFI_IP); */ @@ -1975,17 +1996,21 @@ DEFUN (vnc_nve_export_routemap, if (argv[2]->arg[0] == 'b') { if (hc->routemap_export_bgp_name) free(hc->routemap_export_bgp_name); + route_map_counter_decrement(hc->routemap_export_bgp); hc->routemap_export_bgp_name = strdup(argv[4]->arg); hc->routemap_export_bgp = route_map_lookup_by_name(argv[4]->arg); + route_map_counter_increment(hc->routemap_export_bgp); vnc_direct_bgp_reexport(bgp, AFI_IP); vnc_direct_bgp_reexport(bgp, AFI_IP6); } else { if (hc->routemap_export_zebra_name) free(hc->routemap_export_zebra_name); + route_map_counter_decrement(hc->routemap_export_zebra); hc->routemap_export_zebra_name = strdup(argv[4]->arg); hc->routemap_export_zebra = route_map_lookup_by_name(argv[4]->arg); + route_map_counter_increment(hc->routemap_export_zebra); /* TBD vnc_zebra_rh_reexport(bgp, AFI_IP); */ /* TBD vnc_zebra_rh_reexport(bgp, AFI_IP6); */ } @@ -2083,6 +2108,7 @@ void vnc_routemap_update(struct bgp *bgp, const char *unused) struct rfapi_nve_group_cfg *rfg; struct rfapi_cfg *hc; int i; + struct route_map *old = NULL; vnc_zlog_debug_verbose("%s(arg=%s)", __func__, unused); @@ -2104,18 +2130,36 @@ void vnc_routemap_update(struct bgp *bgp, const char *unused) rfg)) { if (rfg->routemap_export_bgp_name) { + old = rfg->routemap_export_bgp; rfg->routemap_export_bgp = route_map_lookup_by_name( rfg->routemap_export_bgp_name); + /* old is NULL. i.e Route map creation event. + * So update applied_counter. + * If Old is not NULL, i.e It may be routemap + * updation or deletion. + * So no need to update the counter. + */ + if (!old) + route_map_counter_increment( + rfg->routemap_export_bgp); } if (rfg->routemap_export_zebra_name) { + old = rfg->routemap_export_bgp; rfg->routemap_export_bgp = route_map_lookup_by_name( rfg->routemap_export_zebra_name); + if (!old) + route_map_counter_increment( + rfg->routemap_export_bgp); } for (i = 0; i < ZEBRA_ROUTE_MAX; ++i) { if (rfg->routemap_redist_name[i]) { + old = rfg->routemap_redist[i]; rfg->routemap_redist[i] = route_map_lookup_by_name( rfg->routemap_redist_name[i]); + if (!old) + route_map_counter_increment( + rfg->routemap_redist[i]); } } @@ -2128,17 +2172,27 @@ void vnc_routemap_update(struct bgp *bgp, const char *unused) * RH config, too */ if (hc->routemap_export_bgp_name) { + old = hc->routemap_export_bgp; hc->routemap_export_bgp = route_map_lookup_by_name(hc->routemap_export_bgp_name); + if (!old) + route_map_counter_increment(hc->routemap_export_bgp); } if (hc->routemap_export_zebra_name) { + old = hc->routemap_export_bgp; hc->routemap_export_bgp = route_map_lookup_by_name( hc->routemap_export_zebra_name); + if (!old) + route_map_counter_increment(hc->routemap_export_bgp); } for (i = 0; i < ZEBRA_ROUTE_MAX; ++i) { if (hc->routemap_redist_name[i]) { + old = hc->routemap_redist[i]; hc->routemap_redist[i] = route_map_lookup_by_name( hc->routemap_redist_name[i]); + if (!old) + route_map_counter_increment( + hc->routemap_redist[i]); } } diff --git a/bgpd/subdir.am b/bgpd/subdir.am index 7dd1d73f69..aed2939d3e 100644 --- a/bgpd/subdir.am +++ b/bgpd/subdir.am @@ -191,17 +191,20 @@ noinst_HEADERS += \ bgpd_bgpd_SOURCES = bgpd/bgp_main.c bgpd_bgp_btoa_SOURCES = bgpd/bgp_btoa.c +bgpd_bgpd_CFLAGS = $(AM_CFLAGS) +bgpd_bgp_btoa_CFLAGS = $(AM_CFLAGS) + if ENABLE_BGP_VNC bgpd_bgpd_SOURCES += bgpd/rfapi/rfapi_descriptor_rfp_utils.c -bgpd_bgpd_CFLAGS = -Irfapi -I@top_srcdir@/$(RFPINC) +bgpd_bgpd_CFLAGS += -Irfapi -I@top_srcdir@/$(RFPINC) bgpd_bgp_btoa_SOURCES += bgpd/rfapi/rfapi_descriptor_rfp_utils.c -bgpd_bgp_btoa_CFLAGS = -Irfapi -I@top_srcdir@/$(RFPINC) +bgpd_bgp_btoa_CFLAGS += -Irfapi -I@top_srcdir@/$(RFPINC) endif # RFPLDADD is set in bgpd/rfp-example/librfp/subdir.am -bgpd_bgpd_LDADD = bgpd/libbgp.a $(RFPLDADD) lib/libfrr.la @LIBCAP@ @LIBM@ -bgpd_bgp_btoa_LDADD = bgpd/libbgp.a $(RFPLDADD) lib/libfrr.la @LIBCAP@ @LIBM@ +bgpd_bgpd_LDADD = bgpd/libbgp.a $(RFPLDADD) lib/libfrr.la $(LIBCAP) $(LIBM) +bgpd_bgp_btoa_LDADD = bgpd/libbgp.a $(RFPLDADD) lib/libfrr.la $(LIBCAP) $(LIBM) bgpd_bgpd_snmp_la_SOURCES = bgpd/bgp_snmp.c bgpd_bgpd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu99 diff --git a/configure.ac b/configure.ac index afdc6336b0..936e1ccda6 100755 --- a/configure.ac +++ b/configure.ac @@ -147,7 +147,7 @@ dnl - specifically, options to control warnings AC_USE_SYSTEM_EXTENSIONS AC_DEFUN([AC_C_FLAG], [{ - m4_pushdef([cachename],[m4_translit([frr_cv_$1],[ =-],[___])]) + m4_pushdef([cachename],[m4_translit([frr_cv_$1],[ =-+],[____])]) AC_CACHE_CHECK([[whether $CC supports $1]], cachename, [ AC_LANG_PUSH([C]) ac_c_flag_save="$CFLAGS" @@ -261,6 +261,9 @@ fi AC_C_FLAG([-Wno-unused-parameter]) AC_C_FLAG([-Wno-missing-field-initializers]) +AC_C_FLAG([-Wc++-compat], [], [CXX_COMPAT_CFLAGS="-Wc++-compat"]) +AC_SUBST([CXX_COMPAT_CFLAGS]) + dnl ICC emits a broken warning for const char *x = a ? "b" : "c"; dnl for some reason the string consts get 'promoted' to char *, dnl triggering a const to non-const conversion warning. @@ -1600,18 +1603,21 @@ AC_SUBST([SNMP_CFLAGS]) dnl --------------- dnl libyang dnl --------------- -PKG_CHECK_MODULES([libyang], [libyang >= 0.16.7], , [ +PKG_CHECK_MODULES([LIBYANG], [libyang >= 0.16.7], , [ AC_MSG_ERROR([libyang (>= 0.16.7) was not found on your system.]) ]) +ac_cflags_save="$CFLAGS" +CFLAGS="$CFLAGS $LIBYANG_CFLAGS" AC_CHECK_MEMBER([struct lyd_node.priv], [], [ AC_MSG_ERROR([m4_normalize([ libyang needs to be compiled with ENABLE_LYD_PRIV=ON. See http://docs.frrouting.org/projects/dev-guide/en/latest/building-libyang.html for details.]) ]) ], [[#include <libyang/libyang.h>]]) +CFLAGS="$ac_cflags_save" -ac_ld_flag_save="$LDFLAGS" -LDFLAGS="$LDFLAGS $libyang_LIBS" +ac_libs_save="$LIBS" +LIBS="$LIBS $LIBYANG_LIBS" AC_CHECK_FUNC([ly_register_types], [ libyang_ext_builtin=true AC_DEFINE([LIBYANG_EXT_BUILTIN], [1], [have ly_register_types()]) @@ -1626,14 +1632,14 @@ AC_CHECK_FUNC([ly_register_types], [ AC_MSG_WARN([===== old libyang (before 0.16.74) detected =====]) ]) AM_CONDITIONAL([LIBYANG_EXT_BUILTIN], [$libyang_ext_builtin]) -LDFLAGS="$ac_ld_flag_save" +LIBS="$ac_libs_save" dnl --------------- dnl configuration rollbacks dnl --------------- SQLITE3=false if test "$enable_config_rollbacks" = "yes"; then - PKG_CHECK_MODULES([sqlite3], [sqlite3], [ + PKG_CHECK_MODULES([SQLITE3], [sqlite3], [ AC_DEFINE([HAVE_CONFIG_ROLLBACKS], [1], [Enable configuration rollbacks]) AC_DEFINE([HAVE_SQLITE3], [1], [Enable sqlite3 database]) SQLITE3=true @@ -1661,7 +1667,7 @@ dnl --------------- dnl sysrepo dnl --------------- if test "$enable_sysrepo" = "yes"; then - PKG_CHECK_MODULES([sysrepo], [libsysrepo], + PKG_CHECK_MODULES([SYSREPO], [libsysrepo], [AC_DEFINE([HAVE_SYSREPO], [1], [Enable sysrepo integration]) SYSREPO=true], [SYSREPO=false @@ -1735,7 +1741,8 @@ AC_CHECK_TYPES([ vifi_t, struct sioc_vif_req, struct igmpmsg, struct ifaliasreq, struct if6_aliasreq, struct in6_aliasreq, struct nd_opt_adv_interval, struct rt_addrinfo, - struct nd_opt_homeagent_info, struct nd_opt_adv_interval], + struct nd_opt_homeagent_info, struct nd_opt_adv_interval, + struct nd_opt_rdnss, struct nd_opt_dnssl], [], [], FRR_INCLUDES) AC_CHECK_MEMBERS([struct sockaddr.sa_len, diff --git a/doc/developer/conf.py b/doc/developer/conf.py index 254c9f6bfc..ad501ae39d 100644 --- a/doc/developer/conf.py +++ b/doc/developer/conf.py @@ -131,7 +131,7 @@ language = None # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = ['_build', 'building-libyang.rst'] +exclude_patterns = ['_build', 'building-libyang.rst', 'topotests-snippets.rst'] # The reST default role (used for this markup: `text`) to use for all # documents. diff --git a/doc/developer/index.rst b/doc/developer/index.rst index 9838e1098c..3a33d9a5ec 100644 --- a/doc/developer/index.rst +++ b/doc/developer/index.rst @@ -9,6 +9,7 @@ FRRouting Developer's Guide packaging process-architecture library + testing bgpd ospf zebra diff --git a/doc/developer/subdir.am b/doc/developer/subdir.am index 575722a805..19910e7627 100644 --- a/doc/developer/subdir.am +++ b/doc/developer/subdir.am @@ -38,6 +38,9 @@ dev_RSTFILES = \ doc/developer/ospf-api.rst \ doc/developer/ospf-sr.rst \ doc/developer/ospf.rst \ + doc/developer/testing.rst \ + doc/developer/topotests-snippets.rst \ + doc/developer/topotests.rst \ doc/developer/workflow.rst \ doc/developer/zebra.rst \ # end diff --git a/doc/developer/testing.rst b/doc/developer/testing.rst new file mode 100644 index 0000000000..6396faf9a6 --- /dev/null +++ b/doc/developer/testing.rst @@ -0,0 +1,10 @@ +.. _testing: + +******* +Testing +******* + +.. toctree:: + :maxdepth: 2 + + topotests diff --git a/doc/developer/topotests-snippets.rst b/doc/developer/topotests-snippets.rst new file mode 100644 index 0000000000..649229b433 --- /dev/null +++ b/doc/developer/topotests-snippets.rst @@ -0,0 +1,272 @@ +.. _topotests-snippets: + +Snippets +-------- + +This document will describe common snippets of code that are frequently needed +to perform some test checks. + +Checking for router / test failures +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following check uses the topogen API to check for software failure (e.g. +zebra died) and/or for errors manually set by ``Topogen.set_error()``. + +.. code:: py + + # Get the topology reference + tgen = get_topogen() + + # Check for errors in the topology + if tgen.routers_have_failure(): + # Skip the test with the topology errors as reason + pytest.skip(tgen.errors) + +Checking FRR routers version +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This code snippet is usually run after the topology setup to make sure all +routers instantiated in the topology have the correct software version. + +.. code:: py + + # Get the topology reference + tgen = get_topogen() + + # Get the router list + router_list = tgen.routers() + + # Run the check for all routers + for router in router_list.values(): + if router.has_version('<', '3'): + # Set topology error, so the next tests are skipped + tgen.set_error('unsupported version') + +A sample of this snippet in a test can be found `here +<ldp-vpls-topo1/test_ldp_vpls_topo1.py>`__. + +Interacting with equipment +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +You might want to interact with the topology equipments during the tests and +there are different ways to do so. + +Notes: + +1. When using the Topogen API, all the equipments code derive from ``Topogear`` + (`lib/topogen.py <lib/topogen.py>`__). If you feel brave you can look by + yourself how the abstractions that will be mentioned here works. + +2. When not using the ``Topogen`` API there is only one way to interact with + the equipments, which is by calling the ``mininet`` API functions directly + to spawn commands. + +Interacting with the Linux sandbox +"""""""""""""""""""""""""""""""""" + +Without ``Topogen``: + +.. code:: py + + global net + output = net['r1'].cmd('echo "foobar"') + print 'output is: {}'.format(output) + +With ``Topogen``: + +.. code:: py + + tgen = get_topogen() + output = tgen.gears['r1'].run('echo "foobar"') + print 'output is: {}'.format(output) + +Interacting with VTYSH +"""""""""""""""""""""" + +Without ``Topogen``: + +.. code:: py + + global net + output = net['r1'].cmd('vtysh "show ip route" 2>/dev/null') + print 'output is: {}'.format(output) + +With ``Topogen``: + +.. code:: py + + tgen = get_topogen() + output = tgen.gears['r1'].vtysh_cmd("show ip route") + print 'output is: {}'.format(output) + +``Topogen`` also supports sending multiple lines of command: + +.. code:: py + + tgen = get_topogen() + output = tgen.gears['r1'].vtysh_cmd(""" + configure terminal + router bgp 10 + bgp router-id 10.0.255.1 + neighbor 1.2.3.4 remote-as 10 + ! + router bgp 11 + bgp router-id 10.0.255.2 + ! + """) + print 'output is: {}'.format(output) + +You might also want to run multiple commands and get only the commands that +failed: + +.. code:: py + + tgen = get_topogen() + output = tgen.gears['r1'].vtysh_multicmd(""" + configure terminal + router bgp 10 + bgp router-id 10.0.255.1 + neighbor 1.2.3.4 remote-as 10 + ! + router bgp 11 + bgp router-id 10.0.255.2 + ! + """, pretty_output=false) + print 'output is: {}'.format(output) + +Translating vtysh JSON output into Python structures: + +.. code:: py + + tgen = get_topogen() + json_output = tgen.gears['r1'].vtysh_cmd("show ip route json", isjson=True) + output = json.dumps(json_output, indent=4) + print 'output is: {}'.format(output) + + # You can also access the data structure as normal. For example: + # protocol = json_output['1.1.1.1/32']['protocol'] + # assert protocol == "ospf", "wrong protocol" + +.. note:: + + ``vtysh_(multi)cmd`` is only available for router type of equipments. + +Invoking mininet CLI +^^^^^^^^^^^^^^^^^^^^ + +Without ``Topogen``: + +.. code:: py + + CLI(net) + +With ``Topogen``: + +.. code:: py + + tgen = get_topogen() + tgen.mininet_cli() + +Reading files +^^^^^^^^^^^^^ + +Loading a normal text file content in the current directory: + +.. code:: py + + # If you are using Topogen + # CURDIR = CWD + # + # Otherwise find the directory manually: + CURDIR = os.path.dirname(os.path.realpath(__file__)) + + file_name = '{}/r1/show_ip_route.txt'.format(CURDIR) + file_content = open(file_name).read() + +Loading JSON from a file: + +.. code:: py + + import json + + file_name = '{}/r1/show_ip_route.json'.format(CURDIR) + file_content = json.loads(open(file_name).read()) + +Comparing JSON output +^^^^^^^^^^^^^^^^^^^^^ + +After obtaining JSON output formated with Python data structures, you may use +it to assert a minimalist schema: + +.. code:: py + + tgen = get_topogen() + json_output = tgen.gears['r1'].vtysh_cmd("show ip route json", isjson=True) + + expect = { + '1.1.1.1/32': { + 'protocol': 'ospf' + } + } + + assertmsg = "route 1.1.1.1/32 was not learned through OSPF" + assert json_cmp(json_output, expect) is None, assertmsg + +``json_cmp`` function description (it might be outdated, you can find the +latest description in the source code at +:file:`tests/topotests/lib/topotest.py` + +.. code:: text + + JSON compare function. Receives two parameters: + * `d1`: json value + * `d2`: json subset which we expect + + Returns `None` when all keys that `d1` has matches `d2`, + otherwise a string containing what failed. + + Note: key absence can be tested by adding a key with value `None`. + +Pausing execution +^^^^^^^^^^^^^^^^^ + +Preferably, choose the ``sleep`` function that ``topotest`` provides, as it +prints a notice during the test execution to help debug topology test execution +time. + +.. code:: py + + # Using the topotest sleep + from lib import topotest + + topotest.sleep(10, 'waiting 10 seconds for bla') + # or just tell it the time: + # topotest.sleep(10) + # It will print 'Sleeping for 10 seconds'. + + # Or you can also use the Python sleep, but it won't show anything + from time import sleep + sleep(5) + +iproute2 Linux commands as JSON +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +``topotest`` has two helpers implemented that parses the output of ``ip route`` +commands to JSON. It might simplify your comparison needs by only needing to +provide a Python dictionary. + +.. code:: py + + from lib import topotest + + tgen = get_topogen() + routes = topotest.ip4_route(tgen.gears['r1']) + expected = { + '10.0.1.0/24': {}, + '10.0.2.0/24': { + 'dev': 'r1-eth0' + } + } + + assertmsg = "failed to find 10.0.1.0/24 and/or 10.0.2.0/24" + assert json_cmp(routes, expected) is None, assertmsg diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst new file mode 100644 index 0000000000..aa06c8dffd --- /dev/null +++ b/doc/developer/topotests.rst @@ -0,0 +1,927 @@ +.. _topotests: + +Topotests +========= + +Topotests is a suite of topology tests for FRR built on top of Mininet. + +Installation and Setup +---------------------- + +Only tested with Ubuntu 16.04 and Ubuntu 18.04 (which uses Mininet 2.2.x). + +Instructions are the same for all setups (i.e. ExaBGP is only used for BGP +tests). + +Installing Mininet Infrastructure +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code:: shell + + apt-get install mininet + apt-get install python-pip + apt-get install iproute + pip install ipaddr + pip install pytest + pip install exabgp==3.4.17 (Newer 4.0 version of exabgp is not yet + supported) + useradd -d /var/run/exabgp/ -s /bin/false exabgp + +Enable Coredumps +"""""""""""""""" + +Optional, will give better output. + +.. code:: shell + + apt-get install gdb + disable apport (which move core files) + +Set ``enabled=0`` in ``/etc/default/apport``. + +Next, update security limits by changing :file:`/etc/security/limits.conf` to:: + + #<domain> <type> <item> <value> + * soft core unlimited + root soft core unlimited + * hard core unlimited + root hard core unlimited + +Reboot for options to take effect. + +FRR Installation +^^^^^^^^^^^^^^^^ + +FRR needs to be installed separately. It is assume to be configured like the +standard Ubuntu Packages: + +- Binaries in :file:`/usr/lib/frr` +- State Directory :file:`/var/run/frr` +- Running under user ``frr``, group ``frr`` +- vtygroup: ``frrvty`` +- config directory: :file:`/etc/frr` +- For FRR Packages, install the dbg package as well for coredump decoding + +No FRR config needs to be done and no FRR daemons should be run ahead of the +test. They are all started as part of the test. + +Manual FRR build +"""""""""""""""" + +If you prefer to manually build FRR, then use the following suggested config: + +.. code:: shell + + ./configure \ + --prefix=/usr \ + --localstatedir=/var/run/frr \ + --sbindir=/usr/lib/frr \ + --sysconfdir=/etc/frr \ + --enable-vtysh \ + --enable-pimd \ + --enable-multipath=64 \ + --enable-user=frr \ + --enable-group=frr \ + --enable-vty-group=frrvty \ + --with-pkg-extra-version=-my-manual-build + +And create ``frr`` user and ``frrvty`` group as follows: + +.. code:: shell + + addgroup --system --gid 92 frr + addgroup --system --gid 85 frrvty + adduser --system --ingroup frr --home /var/run/frr/ \ + --gecos "FRRouting suite" --shell /bin/false frr + usermod -G frrvty frr + +Executing Tests +--------------- + +Execute all tests with output to console +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code:: shell + + py.test -s -v --tb=no + +All test\_\* scripts in subdirectories are detected and executed (unless +disabled in ``pytest.ini`` file). + +``--tb=no`` disables the python traceback which might be irrelevant unless the +test script itself is debugged. + +Execute single test +^^^^^^^^^^^^^^^^^^^ + +.. code:: shell + + cd test_to_be_run + ./test_to_be_run.py + +For further options, refer to pytest documentation. + +Test will set exit code which can be used with ``git bisect``. + +For the simulated topology, see the description in the python file. + +If you need to clear the mininet setup between tests (if it isn't cleanly +shutdown), then use the ``mn -c`` command to clean up the environment. + +StdErr log from daemos after exit +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To enable the reporting of any messages seen on StdErr after the daemons exit, +the following env variable can be set:: + + export TOPOTESTS_CHECK_STDERR=Yes + +(The value doesn't matter at this time. The check is if the env variable exists +or not) There is no pass/fail on this reporting. The Output will be reported to +the console:: + + export TOPOTESTS_CHECK_MEMLEAK="/home/mydir/memleak_" + +This will enable the check and output to console and the writing of the +information to files with the given prefix (followed by testname), ie +:file:`/home/mydir/memcheck_test_bgp_multiview_topo1.txt` in case of a memory +leak. + +Collect Memory Leak Information +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +FRR processes have the capabilities to report remaining memory allocations upon +exit. To enable the reporting of the memory, define an enviroment variable +``TOPOTESTS_CHECK_MEMLEAK`` with the file prefix, i.e.:: + + export TOPOTESTS_CHECK_MEMLEAK="/home/mydir/memleak_" + +This will enable the check and output to console and the writing of the +information to files with the given prefix (followed by testname), ie +:file:`/home/mydir/memcheck_test_bgp_multiview_topo1.txt` in case of a memory +leak. + +Running Topotests with AddressSanitizer +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Topotests can be run with AddressSanitizer. It requires GCC 4.8 or newer. +(Ubuntu 16.04 as suggested here is fine with GCC 5 as default). For more +information on AddressSanitizer, see +https://github.com/google/sanitizers/wiki/AddressSanitizer. + +The checks are done automatically in the library call of ``checkRouterRunning`` +(ie at beginning of tests when there is a check for all daemons running). No +changes or extra configuration for topotests is required beside compiling the +suite with AddressSanitizer enabled. + +If a daemon crashed, then the errorlog is checked for AddressSanitizer output. +If found, then this is added with context (calling test) to +:file:`/tmp/AddressSanitizer.txt` in Markdown compatible format. + +Compiling for GCC AddressSanitizer requires to use ``gcc`` as a linker as well +(instead of ``ld``). Here is a suggest way to compile frr with AddressSanitizer +for ``stable/3.0`` branch: + +.. code:: shell + + git clone https://github.com/FRRouting/frr.git + cd frr + git checkout stable/3.0 + ./bootstrap.sh + export CC=gcc + export CFLAGS="-O1 -g -fsanitize=address -fno-omit-frame-pointer" + export LD=gcc + export LDFLAGS="-g -fsanitize=address -ldl" + ./configure --enable-shared=no \ + --prefix=/usr/lib/frr --sysconfdir=/etc/frr \ + --localstatedir=/var/run/frr \ + --sbindir=/usr/lib/frr --bindir=/usr/lib/frr \ + --enable-exampledir=/usr/lib/frr/examples \ + --with-moduledir=/usr/lib/frr/modules \ + --enable-multipath=0 --enable-rtadv \ + --enable-tcp-zebra --enable-fpm --enable-pimd + make + sudo make install + # Create symlink for vtysh, so topotest finds it in /usr/lib/frr + sudo ln -s /usr/lib/frr/vtysh /usr/bin/ + +and create ``frr`` user and ``frrvty`` group as shown above. + +.. _topotests_docker: + +Running Tests with Docker +------------------------- + +There is a Docker image which allows to run topotests. + +Quickstart +^^^^^^^^^^ + +If you have Docker installed, you can run the topotests in Docker. The easiest +way to do this, is to use the make targets from this repository. + +Your current user needs to have access to the Docker daemon. Alternatively you +can run these commands as root. + +.. code:: console + + make topotests + +This command will pull the most recent topotests image from Dockerhub, compile +FRR inside of it, and run the topotests. + +Advanced Usage +^^^^^^^^^^^^^^ + +Internally, the topotests make target uses a shell script to pull the image and +spawn the Docker container. + +There are several environment variables which can be used to modify the +behavior of the script, these can be listed by calling it with ``-h``: + +.. code:: console + + ./tests/topotests/docker/frr-topotests.sh -h + +For example, a volume is used to cache build artifacts between multiple runs of +the image. If you need to force a complete recompile, you can set +``TOPOTEST_CLEAN``: + +.. code:: console + + TOPOTEST_CLEAN=1 ./tests/topotests/docker/frr-topotests.sh + +By default, ``frr-topotests.sh`` will build frr and run pytest. If you append +arguments and the first one starts with ``/`` or ``./``, they will replace the +call to pytest. If the appended arguments do not match this patttern, they will +be provided to pytest as arguments. So, to run a specific test with more +verbose logging: + +.. code:: console + + ./tests/topotests/docker/frr-topotests.sh -vv -s all-protocol-startup/test_all_protocol_startup.py + +And to compile FRR but drop into a shell instead of running pytest: + +.. code:: console + + ./tests/topotests/docker/frr-topotests.sh /bin/bash + +Development +^^^^^^^^^^^ + +The Docker image just includes all the components to run the topotests, but not +the topotests themselves. So if you just want to write tests and don't want to +make changes to the environment provided by the Docker image. You don't need to +build your own Docker image if you do not want to. + +When developing new tests, there is one caveat though: The startup script of +the container will run a ``git-clean`` on its copy of the FRR tree to avoid any +pollution of the container with build artefacts from the host. This will also +result in your newly written tests being unavailable in the container unless at +least added to the index with ``git-add``. + +If you do want to test changes to the Docker image, you can locally build the +image and run the tests without pulling from the registry using the following +commands: + +.. code:: console + + make topotests-build + TOPOTEST_PULL=0 make topotests + + +.. _topotests-guidelines: + +Guidelines +---------- + +Executing Tests +^^^^^^^^^^^^^^^ + +To run the whole suite of tests the following commands must be executed at the +top level directory of topotest: + +.. code:: shell + + $ # Change to the top level directory of topotests. + $ cd path/to/topotests + $ # Tests must be run as root, since Mininet requires it. + $ sudo pytest + +In order to run a specific test, you can use the following command: + +.. code:: shell + + $ # running a specific topology + $ sudo pytest ospf-topo1/ + $ # or inside the test folder + $ cd ospf-topo1 + $ sudo pytest # to run all tests inside the directory + $ sudo pytest test_ospf_topo1.py # to run a specific test + $ # or outside the test folder + $ cd .. + $ sudo pytest ospf-topo1/test_ospf_topo1.py # to run a specific one + +The output of the tested daemons will be available at the temporary folder of +your machine: + +.. code:: shell + + $ ls /tmp/topotest/ospf-topo1.test_ospf-topo1/r1 + ... + zebra.err # zebra stderr output + zebra.log # zebra log file + zebra.out # zebra stdout output + ... + +You can also run memory leak tests to get reports: + +.. code:: shell + + $ # Set the environment variable to apply to a specific test... + $ sudo env TOPOTESTS_CHECK_MEMLEAK="/tmp/memleak_report_" pytest ospf-topo1/test_ospf_topo1.py + $ # ...or apply to all tests adding this line to the configuration file + $ echo 'memleak_path = /tmp/memleak_report_' >> pytest.ini + $ # You can also use your editor + $ $EDITOR pytest.ini + $ # After running tests you should see your files: + $ ls /tmp/memleak_report_* + memleak_report_test_ospf_topo1.txt + +Writing a New Test +^^^^^^^^^^^^^^^^^^ + +This section will guide you in all recommended steps to produce a standard +topology test. + +This is the recommended test writing routine: + +- Write a topology (Graphviz recommended) +- Obtain configuration files +- Write the test itself +- Create a Pull Request + +Topotest File Hierarchy +""""""""""""""""""""""" + +Before starting to write any tests one must know the file hierarchy. The +repository hierarchy looks like this: + +.. code:: shell + + $ cd path/to/topotest + $ find ./* + ... + ./README.md # repository read me + ./GUIDELINES.md # this file + ./conftest.py # test hooks - pytest related functions + ./example-test # example test folder + ./example-test/__init__.py # python package marker - must always exist. + ./example-test/test_template.jpg # generated topology picture - see next section + ./example-test/test_template.dot # Graphviz dot file + ./example-test/test_template.py # the topology plus the test + ... + ./ospf-topo1 # the ospf topology test + ./ospf-topo1/r1 # router 1 configuration files + ./ospf-topo1/r1/zebra.conf # zebra configuration file + ./ospf-topo1/r1/ospfd.conf # ospf configuration file + ./ospf-topo1/r1/ospfroute.txt # 'show ip ospf' output reference file + # removed other for shortness sake + ... + ./lib # shared test/topology functions + ./lib/topogen.py # topogen implementation + ./lib/topotest.py # topotest implementation + +Guidelines for creating/editing topotest: + +- New topologies that don't fit the existing directories should create its own +- Always remember to add the ``__init__.py`` to new folders, this makes auto + complete engines and pylint happy +- Router (Quagga/FRR) specific code should go on topotest.py +- Generic/repeated router actions should have an abstraction in + topogen.TopoRouter. +- Generic/repeated non-router code should go to topotest.py +- pytest related code should go to conftest.py (e.g. specialized asserts) + +Defining the Topology +""""""""""""""""""""" + +The first step to write a new test is to define the topology. This step can be +done in many ways, but the recommended is to use Graphviz to generate a drawing +of the topology. It allows us to see the topology graphically and to see the +names of equipments, links and addresses. + +Here is an example of Graphviz dot file that generates the template topology +:file:`tests/topotests/example-test/test_template.dot` (the inlined code might +get outdated, please see the linked file):: + + graph template { + label="template"; + + # Routers + r1 [ + shape=doubleoctagon, + label="r1", + fillcolor="#f08080", + style=filled, + ]; + r2 [ + shape=doubleoctagon, + label="r2", + fillcolor="#f08080", + style=filled, + ]; + + # Switches + s1 [ + shape=oval, + label="s1\n192.168.0.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + s2 [ + shape=oval, + label="s2\n192.168.1.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + + # Connections + r1 -- s1 [label="eth0\n.1"]; + + r1 -- s2 [label="eth1\n.100"]; + r2 -- s2 [label="eth0\n.1"]; + } + +Here is the produced graph: + +.. graphviz:: + + graph template { + label="template"; + + # Routers + r1 [ + shape=doubleoctagon, + label="r1", + fillcolor="#f08080", + style=filled, + ]; + r2 [ + shape=doubleoctagon, + label="r2", + fillcolor="#f08080", + style=filled, + ]; + + # Switches + s1 [ + shape=oval, + label="s1\n192.168.0.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + s2 [ + shape=oval, + label="s2\n192.168.1.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + + # Connections + r1 -- s1 [label="eth0\n.1"]; + + r1 -- s2 [label="eth1\n.100"]; + r2 -- s2 [label="eth0\n.1"]; + } + +Generating / Obtaining Configuration Files +"""""""""""""""""""""""""""""""""""""""""" + +In order to get the configuration files or command output for each router, we +need to run the topology and execute commands in ``vtysh``. The quickest way to +achieve that is writing the topology building code and running the topology. + +To bootstrap your test topology, do the following steps: + +- Copy the template test + +.. code:: shell + + $ mkdir new-topo/ + $ touch new-topo/__init__.py + $ cp example-test/test_template.py new-topo/test_new_topo.py + +- Modify the template according to your dot file + +Here is the template topology described in the previous section in python code: + +.. code:: py + + class TemplateTopo(Topo): + "Test topology builder" + def build(self, *_args, **_opts): + "Build function" + tgen = get_topogen(self) + + # Create 2 routers + for routern in range(1, 3): + tgen.add_router('r{}'.format(routern)) + + # Create a switch with just one router connected to it to simulate a + # empty network. + switch = tgen.add_switch('s1') + switch.add_link(tgen.gears['r1']) + + # Create a connection between r1 and r2 + switch = tgen.add_switch('s2') + switch.add_link(tgen.gears['r1']) + switch.add_link(tgen.gears['r2']) + +- Run the topology + +Topogen allows us to run the topology without running any tests, you can do +that using the following example commands: + +.. code:: shell + + $ # Running your bootstraped topology + $ sudo pytest -s --topology-only new-topo/test_new_topo.py + $ # Running the test_template.py topology + $ sudo pytest -s --topology-only example-test/test_template.py + $ # Running the ospf_topo1.py topology + $ sudo pytest -s --topology-only ospf-topo1/test_ospf_topo1.py + +Parameters explanation: + +.. program:: pytest + +.. option:: -s + + Actives input/output capture. This is required by mininet in order to show + the interactive shell. + +.. option:: --topology-only + + Don't run any tests, just build the topology. + +After executing the commands above, you should get the following terminal +output: + +.. code:: shell + + === test session starts === + platform linux2 -- Python 2.7.12, pytest-3.1.2, py-1.4.34, pluggy-0.4.0 + rootdir: /media/sf_src/topotests, inifile: pytest.ini + collected 3 items + + ospf-topo1/test_ospf_topo1.py *** Starting controller + + *** Starting 6 switches + switch1 switch2 switch3 switch4 switch5 switch6 ... + r2: frr zebra started + r2: frr ospfd started + r3: frr zebra started + r3: frr ospfd started + r1: frr zebra started + r1: frr ospfd started + r4: frr zebra started + r4: frr ospfd started + *** Starting CLI: + mininet> + +The last line shows us that we are now using the Mininet CLI (Command Line +Interface), from here you can call your router ``vtysh`` or even bash. + +Here are some commands example: + +.. code:: shell + + mininet> r1 ping 10.0.3.1 + PING 10.0.3.1 (10.0.3.1) 56(84) bytes of data. + 64 bytes from 10.0.3.1: icmp_seq=1 ttl=64 time=0.576 ms + 64 bytes from 10.0.3.1: icmp_seq=2 ttl=64 time=0.083 ms + 64 bytes from 10.0.3.1: icmp_seq=3 ttl=64 time=0.088 ms + ^C + --- 10.0.3.1 ping statistics --- + 3 packets transmitted, 3 received, 0% packet loss, time 1998ms + rtt min/avg/max/mdev = 0.083/0.249/0.576/0.231 ms + + + + mininet> r1 ping 10.0.3.3 + PING 10.0.3.3 (10.0.3.3) 56(84) bytes of data. + 64 bytes from 10.0.3.3: icmp_seq=1 ttl=64 time=2.87 ms + 64 bytes from 10.0.3.3: icmp_seq=2 ttl=64 time=0.080 ms + 64 bytes from 10.0.3.3: icmp_seq=3 ttl=64 time=0.091 ms + ^C + --- 10.0.3.3 ping statistics --- + 3 packets transmitted, 3 received, 0% packet loss, time 2003ms + rtt min/avg/max/mdev = 0.080/1.014/2.872/1.313 ms + + + + mininet> r3 vtysh + + Hello, this is FRRouting (version 3.1-devrzalamena-build). + Copyright 1996-2005 Kunihiro Ishiguro, et al. + + frr-1# show running-config + Building configuration... + + Current configuration: + ! + frr version 3.1-devrzalamena-build + frr defaults traditional + hostname r3 + no service integrated-vtysh-config + ! + log file zebra.log + ! + log file ospfd.log + ! + interface r3-eth0 + ip address 10.0.3.1/24 + ! + interface r3-eth1 + ip address 10.0.10.1/24 + ! + interface r3-eth2 + ip address 172.16.0.2/24 + ! + router ospf + ospf router-id 10.0.255.3 + redistribute kernel + redistribute connected + redistribute static + network 10.0.3.0/24 area 0 + network 10.0.10.0/24 area 0 + network 172.16.0.0/24 area 1 + ! + line vty + ! + end + frr-1# + +After you successfully configured your topology, you can obtain the +configuration files (per-daemon) using the following commands: + +.. code:: shell + + mininet> r3 vtysh -d ospfd + + Hello, this is FRRouting (version 3.1-devrzalamena-build). + Copyright 1996-2005 Kunihiro Ishiguro, et al. + + frr-1# show running-config + Building configuration... + + Current configuration: + ! + frr version 3.1-devrzalamena-build + frr defaults traditional + no service integrated-vtysh-config + ! + log file ospfd.log + ! + router ospf + ospf router-id 10.0.255.3 + redistribute kernel + redistribute connected + redistribute static + network 10.0.3.0/24 area 0 + network 10.0.10.0/24 area 0 + network 172.16.0.0/24 area 1 + ! + line vty + ! + end + frr-1# + +Writing Tests +""""""""""""" + +Test topologies should always be bootstrapped from +:file:`tests/topotests/example-test/test_template.py` because it contains +important boilerplate code that can't be avoided, like: + +- imports: os, sys, pytest, topotest/topogen and mininet topology class +- The global variable CWD (Current Working directory): which is most likely + going to be used to reference the routers configuration file location + +Example: + +.. code:: py + + # For all registered routers, load the zebra configuration file + for rname, router in router_list.iteritems(): + 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 '/'. + +- The topology class that inherits from Mininet Topo class: + +.. code:: py + + class TemplateTopo(Topo): + def build(self, *_args, **_opts): + tgen = get_topogen(self) + # topology build code + +- pytest ``setup_module()`` and ``teardown_module()`` to start the topology + +.. code:: py + + def setup_module(_m): + tgen = Topogen(TemplateTopo) + tgen.start_topology('debug') + + def teardown_module(_m): + tgen = get_topogen() + tgen.stop_topology() + +- ``__main__`` initialization code (to support running the script directly) + +.. code:: py + + if __name__ == '__main__': + sys.exit(pytest.main(["-s"])) + +Requirements: + +- Test code should always be declared inside functions that begin with the + ``test_`` prefix. Functions beginning with different prefixes will not be run + by pytest. +- Configuration files and long output commands should go into separated files + inside folders named after the equipment. +- Tests must be able to run without any interaction. To make sure your test + conforms with this, run it without the :option:`-s` parameter. + +Tips: + +- Keep results in stack variables, so people inspecting code with ``pdb`` can + easily print their values. + +Don't do this: + +.. code:: py + + assert foobar(router1, router2) + +Do this instead: + +.. code:: py + + result = foobar(router1, router2) + assert result + +- Use ``assert`` messages to indicate where the test failed. + +Example: + +.. code:: py + + for router in router_list: + # ... + assert condition, 'Router "{}" condition failed'.format(router.name) + +Debugging Execution +^^^^^^^^^^^^^^^^^^^ + +The most effective ways to inspect topology tests are: + +- Run pytest with ``--pdb`` option. This option will cause a pdb shell to + appear when an assertion fails + +Example: ``pytest -s --pdb ospf-topo1/test_ospf_topo1.py`` + +- Set a breakpoint in the test code with ``pdb`` + +Example: + +.. code:: py + + # Add the pdb import at the beginning of the file + import pdb + # ... + + # Add a breakpoint where you think the problem is + def test_bla(): + # ... + pdb.set_trace() + # ... + +The `Python Debugger <https://docs.python.org/2.7/library/pdb.html>`__ (pdb) +shell allows us to run many useful operations like: + +- Setting breaking point on file/function/conditions (e.g. ``break``, + ``condition``) +- Inspecting variables (e.g. ``p`` (print), ``pp`` (pretty print)) +- Running python code + +.. tip:: + + The TopoGear (equipment abstraction class) implements the ``__str__`` method + that allows the user to inspect equipment information. + +Example of pdb usage: + +.. code:: shell + + > /media/sf_src/topotests/ospf-topo1/test_ospf_topo1.py(121)test_ospf_convergence() + -> for rnum in range(1, 5): + (Pdb) help + Documented commands (type help <topic>): + ======================================== + EOF bt cont enable jump pp run unt + a c continue exit l q s until + alias cl d h list quit step up + args clear debug help n r tbreak w + b commands disable ignore next restart u whatis + break condition down j p return unalias where + + Miscellaneous help topics: + ========================== + exec pdb + + Undocumented commands: + ====================== + retval rv + + (Pdb) list + 116 title2="Expected output") + 117 + 118 def test_ospf_convergence(): + 119 "Test OSPF daemon convergence" + 120 pdb.set_trace() + 121 -> for rnum in range(1, 5): + 122 router = 'r{}'.format(rnum) + 123 + 124 # Load expected results from the command + 125 reffile = os.path.join(CWD, '{}/ospfroute.txt'.format(router)) + 126 expected = open(reffile).read() + (Pdb) step + > /media/sf_src/topotests/ospf-topo1/test_ospf_topo1.py(122)test_ospf_convergence() + -> router = 'r{}'.format(rnum) + (Pdb) step + > /media/sf_src/topotests/ospf-topo1/test_ospf_topo1.py(125)test_ospf_convergence() + -> reffile = os.path.join(CWD, '{}/ospfroute.txt'.format(router)) + (Pdb) print rnum + 1 + (Pdb) print router + r1 + (Pdb) tgen = get_topogen() + (Pdb) pp tgen.gears[router] + <lib.topogen.TopoRouter object at 0x7f74e06c9850> + (Pdb) pp str(tgen.gears[router]) + 'TopoGear<name="r1",links=["r1-eth0"<->"s1-eth0","r1-eth1"<->"s3-eth0"]> TopoRouter<>' + (Pdb) l 125 + 120 pdb.set_trace() + 121 for rnum in range(1, 5): + 122 router = 'r{}'.format(rnum) + 123 + 124 # Load expected results from the command + 125 -> reffile = os.path.join(CWD, '{}/ospfroute.txt'.format(router)) + 126 expected = open(reffile).read() + 127 + 128 # Run test function until we get an result. Wait at most 60 seconds. + 129 test_func = partial(compare_show_ip_ospf, router, expected) + 130 result, diff = topotest.run_and_expect(test_func, '', + (Pdb) router1 = tgen.gears[router] + (Pdb) router1.vtysh_cmd('show ip ospf route') + '============ OSPF network routing table ============\r\nN 10.0.1.0/24 [10] area: 0.0.0.0\r\n directly attached to r1-eth0\r\nN 10.0.2.0/24 [20] area: 0.0.0.0\r\n via 10.0.3.3, r1-eth1\r\nN 10.0.3.0/24 [10] area: 0.0.0.0\r\n directly attached to r1-eth1\r\nN 10.0.10.0/24 [20] area: 0.0.0.0\r\n via 10.0.3.1, r1-eth1\r\nN IA 172.16.0.0/24 [20] area: 0.0.0.0\r\n via 10.0.3.1, r1-eth1\r\nN IA 172.16.1.0/24 [30] area: 0.0.0.0\r\n via 10.0.3.1, r1-eth1\r\n\r\n============ OSPF router routing table =============\r\nR 10.0.255.2 [10] area: 0.0.0.0, ASBR\r\n via 10.0.3.3, r1-eth1\r\nR 10.0.255.3 [10] area: 0.0.0.0, ABR, ASBR\r\n via 10.0.3.1, r1-eth1\r\nR 10.0.255.4 IA [20] area: 0.0.0.0, ASBR\r\n via 10.0.3.1, r1-eth1\r\n\r\n============ OSPF external routing table ===========\r\n\r\n\r\n' + (Pdb) tgen.mininet_cli() + *** Starting CLI: + mininet> + +To enable more debug messages in other Topogen subsystems (like Mininet), more +logging messages can be displayed by modifying the test configuration file +``pytest.ini``: + +.. code:: ini + + [topogen] + # Change the default verbosity line from 'info'... + #verbosity = info + # ...to 'debug' + verbosity = debug + +Instructions for use, write or debug topologies can be found in :ref:`topotests-guidelines`. +To learn/remember common code snippets see :ref:`topotests-snippets`. + +Before creating a new topology, make sure that there isn't one already that +does what you need. If nothing is similar, then you may create a new topology, +preferably, using the newest template +(:file:`tests/topotests/example-test/test_template.py`). + +.. include:: topotests-snippets.rst + +License +------- + +All the configs and scripts are licensed under a ISC-style license. See Python +scripts for details. diff --git a/doc/user/ipv6.rst b/doc/user/ipv6.rst index 585c3a505a..cc8fd18fee 100644 --- a/doc/user/ipv6.rst +++ b/doc/user/ipv6.rst @@ -179,10 +179,56 @@ Router Advertisement hosts in proper interface configuration. The announced value is not verified to be consistent with router interface MTU. - Default: don't advertise any MTU option.:: - interface eth0 - no ipv6 nd suppress-ra - ipv6 nd prefix 2001:0DB8:5009::/64 + Default: don't advertise any MTU option. + +.. index:: + single: ipv6 nd rdnss ipv6address [lifetime] + single: no ipv6 nd rdnss ipv6address [lifetime] +.. clicmd:: [no] ipv6 nd rdnss ipv6address [lifetime] + + Recursive DNS server address to advertise using the RDNSS (type 25) option + described in RFC8106. Can be specified more than once to advertise multiple + addresses. Note that hosts may choose to limit the number of RDNSS addresses + to track. + + Optional parameter: + + - ``lifetime``: the maximum time in seconds over which the specified address + may be used for domain name resolution. Value ``infinite`` represents + infinity (i.e. a value of all one bits (``0xffffffff``)). A value of 0 + indicates that the address must no longer be used. + Range: ``(0-4294967295)`` Default: ``3 * ra-interval`` + + Default: do not emit RDNSS option + +.. index:: + single: ipv6 nd dnssl domain-name-suffix [lifetime] + single: no ipv6 nd dnssl domain-name-suffix [lifetime] +.. clicmd:: [no] ipv6 nd dnssl domain-name-suffix [lifetime] + + Advertise DNS search list using the DNSSL (type 31) option described in + RFC8106. Specify more than once to advertise multiple domain name suffixes. + Host implementations may limit the number of honored search list entries. + + Optional parameter: + + - ``lifetime``: the maximum time in seconds over which the specified domain + suffix may be used in the course of name resolution. Value ``infinite`` + represents infinity (i.e. a value of all one bits (``0xffffffff``)). A + value of 0 indicates that the name suffix must no longer be used. + Range: ``(0-4294967295)`` Default: ``3 * ra-interval`` + + Default: do not emit DNSSL option + +Router Advertisement Configuration Example +========================================== +A small example: + +.. code-block:: frr + + interface eth0 + no ipv6 nd suppress-ra + ipv6 nd prefix 2001:0DB8:5009::/64 .. seealso:: @@ -191,3 +237,4 @@ Router Advertisement - :rfc:`4861` (Neighbor Discovery for IP Version 6 (IPv6)) - :rfc:`6275` (Mobility Support in IPv6) - :rfc:`4191` (Default Router Preferences and More-Specific Routes) + - :rfc:`8106` (IPv6 Router Advertisement Options for DNS Configuration) diff --git a/doc/user/routemap.rst b/doc/user/routemap.rst index 42a8250ae0..ef9ebe8ddc 100644 --- a/doc/user/routemap.rst +++ b/doc/user/routemap.rst @@ -38,11 +38,12 @@ to four distinct sets of clauses: the ordered entry in the route-map. See below. Call Action - Call to another route-map, after any :term:`Set Actions` have been carried out. - If the route-map called returns `deny` then processing of the route-map - finishes and the route is denied, regardless of the :term:Matching Policy` or - the :term:`Exit Policy`. If the called route-map returns `permit`, then - :term:`Matching Policy` and :term:`Exit Policy` govern further behaviour, as normal. + Call to another route-map, after any :term:`Set Actions` have been + carried out. If the route-map called returns `deny` then processing of + the route-map finishes and the route is denied, regardless of the + :term:`Matching Policy` or the :term:`Exit Policy`. If the called + route-map returns `permit`, then :term:`Matching Policy` and :term:`Exit + Policy` govern further behaviour, as normal. Exit Policy An entry may, optionally, specify an alternative :dfn:`Exit Policy` to diff --git a/doc/user/sharp.rst b/doc/user/sharp.rst index c2d32a718e..ca8f1f512f 100644 --- a/doc/user/sharp.rst +++ b/doc/user/sharp.rst @@ -56,6 +56,14 @@ keyword. At present, no sharp commands will be preserved in the config. log and when all routes have been successfully deleted the debug log will be updated with this information as well. +.. index:: sharp data route +.. clicmd:: sharp data route + + Allow end user doing route install and deletion to get timing information + from the vty or vtysh instead of having to read the log file. This command + is informational only and you should look at sharp_vty.c for explanation + of the output as that it may change. + .. index:: sharp label .. clicmd:: sharp label <ipv4|ipv6> vrf NAME label (0-1000000) @@ -63,7 +71,18 @@ keyword. At present, no sharp commands will be preserved in the config. be used for pop and forward operations when the specified label is seen. .. index:: sharp watch -.. clicmd:: sharp watch nexthop <A.B.C.D|X:X::X:X> +.. clicmd:: [no] sharp watch <nexthop|import> <A.B.C.D|X:X::X:X> [connected] Instruct zebra to monitor and notify sharp when the specified nexthop is changed. The notification from zebra is written into the debug log. + The nexthop or import choice chooses the type of nexthop we are asking + zebra to watch for us. This choice affects zebra's decision on what + matches. Connected tells zebra whether or not that we want the route + matched against to be a static or connected route. The no form of + the command obviously turns this watching off. + +.. index:: sharp data nexthop +.. clicmd:: sharp data nexthop + + Allow end user to dump associated data with the nexthop tracking that + may have been turned on. diff --git a/docker/debian/Dockerfile b/docker/debian/Dockerfile new file mode 100644 index 0000000000..4f192ec33e --- /dev/null +++ b/docker/debian/Dockerfile @@ -0,0 +1,10 @@ +FROM debian:stretch +MAINTAINER Rob Gil (rob@rem5.com) +RUN apt-get update +RUN apt-get install -y libpcre3-dev apt-transport-https ca-certificates curl wget logrotate \ + libc-ares2 libjson-c3 vim systemd procps +RUN curl -sLO https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-1/Debian-9-x86_64-Packages/libyang_0.16.46_amd64.deb && dpkg -i libyang_0.16.46_amd64.deb +RUN curl -sLO https://github.com/FRRouting/frr/releases/download/frr-6.0.2/frr_6.0.2-0.deb9u1_amd64.deb && dpkg -i frr_6.0.2-0.deb9u1_amd64.deb +ADD daemons /etc/frr/daemons +ADD docker-start /usr/sbin/docker-start +ENTRYPOINT ["/usr/sbin/docker-start"] diff --git a/docker/debian/README.md b/docker/debian/README.md new file mode 100644 index 0000000000..b10d696a78 --- /dev/null +++ b/docker/debian/README.md @@ -0,0 +1,17 @@ +# Debian9 Docker +This is a binary docker container build of debian9. + +# Build +``` +docker build --rm -t frr:6.0.2 . +``` + +# Running +``` +docker run -itd --privileged --name frr frr:latest +``` + +vtysh +``` +docker exec -it frr vtysh +``` diff --git a/docker/debian/daemons b/docker/debian/daemons new file mode 100644 index 0000000000..ed4d98e1f8 --- /dev/null +++ b/docker/debian/daemons @@ -0,0 +1,65 @@ +# This file tells the frr package which daemons to start. +# +# Sample configurations for these daemons can be found in +# /usr/share/doc/frr/examples/. +# +# ATTENTION: +# +# When activation a daemon at the first time, a config file, even if it is +# empty, has to be present *and* be owned by the user and group "frr", else +# the daemon will not be started by /etc/init.d/frr. The permissions should +# be u=rw,g=r,o=. +# When using "vtysh" such a config file is also needed. It should be owned by +# group "frrvty" and set to ug=rw,o= though. Check /etc/pam.d/frr, too. +# +# The watchfrr and zebra daemons are always started. +# +bgpd=yes +ospfd=no +ospf6d=no +ripd=no +ripngd=no +isisd=no +pimd=no +ldpd=no +nhrpd=no +eigrpd=no +babeld=no +sharpd=no +pbrd=no +bfdd=no +fabricd=no + +# +# If this option is set the /etc/init.d/frr script automatically loads +# the config via "vtysh -b" when the servers are started. +# Check /etc/pam.d/frr if you intend to use "vtysh"! +# +vtysh_enable=yes +zebra_options=" -A 127.0.0.1 -s 90000000" +bgpd_options=" -A 127.0.0.1" +ospfd_options=" -A 127.0.0.1" +ospf6d_options=" -A ::1" +ripd_options=" -A 127.0.0.1" +ripngd_options=" -A ::1" +isisd_options=" -A 127.0.0.1" +pimd_options=" -A 127.0.0.1" +ldpd_options=" -A 127.0.0.1" +nhrpd_options=" -A 127.0.0.1" +eigrpd_options=" -A 127.0.0.1" +babeld_options=" -A 127.0.0.1" +sharpd_options=" -A 127.0.0.1" +pbrd_options=" -A 127.0.0.1" +staticd_options="-A 127.0.0.1" +bfdd_options=" -A 127.0.0.1" +fabricd_options="-A 127.0.0.1" + +# The list of daemons to watch is automatically generated by the init script. +watchfrr_options="-r '/usr/lib/frr/watchfrr.sh restart %s' -s '/usr/lib/frr/watchfrr.sh start %s' -k '/usr/lib/frr/watchfrr.sh stop %s'" + +# for debugging purposes, you can specify a "wrap" command to start instead +# of starting the daemon directly, e.g. to use valgrind on ospfd: +# ospfd_wrap="/usr/bin/valgrind" +# or you can use "all_wrap" for all daemons, e.g. to use perf record: +# all_wrap="/usr/bin/perf record --call-graph -" +# the normal daemon command is added to this at the end. diff --git a/docker/debian/docker-start b/docker/debian/docker-start new file mode 100755 index 0000000000..43854ab142 --- /dev/null +++ b/docker/debian/docker-start @@ -0,0 +1,10 @@ +#!/bin/sh + +set -e + +## +# For volume mounts... +## +chown -R frr:frr /etc/frr +/etc/init.d/frr start +exec sleep 10000d diff --git a/eigrpd/eigrp_dump.c b/eigrpd/eigrp_dump.c index 876e1cac07..583db6622d 100644 --- a/eigrpd/eigrp_dump.c +++ b/eigrpd/eigrp_dump.c @@ -174,7 +174,7 @@ const char *eigrp_if_ip_string(struct eigrp_interface *ei) if (!ei) return "inactive"; - ifaddr = ntohl(ei->address->u.prefix4.s_addr); + ifaddr = ntohl(ei->address.u.prefix4.s_addr); snprintf(buf, EIGRP_IF_STRING_MAXLEN, "%u.%u.%u.%u", (ifaddr >> 24) & 0xff, (ifaddr >> 16) & 0xff, (ifaddr >> 8) & 0xff, ifaddr & 0xff); @@ -301,14 +301,14 @@ void show_ip_eigrp_prefix_entry(struct vty *vty, struct eigrp_prefix_entry *tn) } void show_ip_eigrp_nexthop_entry(struct vty *vty, struct eigrp *eigrp, - struct eigrp_nexthop_entry *te, int *first) + struct eigrp_nexthop_entry *te, bool *first) { if (te->reported_distance == EIGRP_MAX_METRIC) return; if (*first) { show_ip_eigrp_prefix_entry(vty, te->prefix); - *first = 0; + *first = false; } if (te->adv_router == eigrp->neighbor_self) diff --git a/eigrpd/eigrp_dump.h b/eigrpd/eigrp_dump.h index 389ac1b5fd..34b55ab419 100644 --- a/eigrpd/eigrp_dump.h +++ b/eigrpd/eigrp_dump.h @@ -156,8 +156,9 @@ extern void show_ip_eigrp_neighbor_sub(struct vty *, struct eigrp_neighbor *, int); extern void show_ip_eigrp_prefix_entry(struct vty *, struct eigrp_prefix_entry *); -extern void show_ip_eigrp_nexthop_entry(struct vty *, struct eigrp *, - struct eigrp_nexthop_entry *, int *); +extern void show_ip_eigrp_nexthop_entry(struct vty *vty, struct eigrp *eigrp, + struct eigrp_nexthop_entry *ne, + bool *first); extern void eigrp_debug_init(void); diff --git a/eigrpd/eigrp_hello.c b/eigrpd/eigrp_hello.c index 413a35f2fa..b4d850be08 100644 --- a/eigrpd/eigrp_hello.c +++ b/eigrpd/eigrp_hello.c @@ -248,7 +248,7 @@ static void eigrp_peer_termination_decode(struct eigrp_neighbor *nbr, struct TLV_Peer_Termination_type *param = (struct TLV_Peer_Termination_type *)tlv; - uint32_t my_ip = nbr->ei->address->u.prefix4.s_addr; + uint32_t my_ip = nbr->ei->address.u.prefix4.s_addr; uint32_t received_ip = param->neighbor_ip; if (my_ip == received_ip) { diff --git a/eigrpd/eigrp_interface.c b/eigrpd/eigrp_interface.c index e6cfe1deea..c52a98ee25 100644 --- a/eigrpd/eigrp_interface.c +++ b/eigrpd/eigrp_interface.c @@ -68,7 +68,7 @@ struct eigrp_interface *eigrp_if_new(struct eigrp *eigrp, struct interface *ifp, /* Set zebra interface pointer. */ ei->ifp = ifp; - ei->address = p; + prefix_copy(&ei->address, p); ifp->info = ei; listnode_add(eigrp->eiflist, ei); @@ -114,6 +114,8 @@ int eigrp_if_delete_hook(struct interface *ifp) eigrp = ei->eigrp; listnode_delete(eigrp->eiflist, ei); + eigrp_fifo_free(ei->obuf); + XFREE(MTYPE_EIGRP_IF_INFO, ifp->info); ifp->info = NULL; @@ -183,7 +185,7 @@ int eigrp_if_up(struct eigrp_interface *ei) struct prefix dest_addr; - dest_addr = *ei->address; + dest_addr = ei->address; apply_mask(&dest_addr); pe = eigrp_topology_table_lookup_ipv4(eigrp->topology_table, &dest_addr); @@ -265,16 +267,11 @@ void eigrp_if_stream_unset(struct eigrp_interface *ei) { struct eigrp *eigrp = ei->eigrp; - if (ei->obuf) { - eigrp_fifo_free(ei->obuf); - ei->obuf = NULL; - - if (ei->on_write_q) { - listnode_delete(eigrp->oi_write_q, ei); - if (list_isempty(eigrp->oi_write_q)) - thread_cancel(eigrp->t_write); - ei->on_write_q = 0; - } + if (ei->on_write_q) { + listnode_delete(eigrp->oi_write_q, ei); + if (list_isempty(eigrp->oi_write_q)) + thread_cancel(eigrp->t_write); + ei->on_write_q = 0; } } @@ -295,7 +292,7 @@ void eigrp_if_set_multicast(struct eigrp_interface *ei) /* The interface should belong to the EIGRP-all-routers group. */ if (!ei->member_allrouters - && (eigrp_if_add_allspfrouters(ei->eigrp, ei->address, + && (eigrp_if_add_allspfrouters(ei->eigrp, &ei->address, ei->ifp->ifindex) >= 0)) /* Set the flag only if the system call to join @@ -306,7 +303,7 @@ void eigrp_if_set_multicast(struct eigrp_interface *ei) * group. */ if (ei->member_allrouters) { /* Only actually drop if this is the last reference */ - eigrp_if_drop_allspfrouters(ei->eigrp, ei->address, + eigrp_if_drop_allspfrouters(ei->eigrp, &ei->address, ei->ifp->ifindex); /* Unset the flag regardless of whether the system call to leave @@ -342,7 +339,7 @@ void eigrp_if_free(struct eigrp_interface *ei, int source) eigrp_hello_send(ei, EIGRP_HELLO_GRACEFUL_SHUTDOWN, NULL); } - dest_addr = *ei->address; + dest_addr = ei->address; apply_mask(&dest_addr); pe = eigrp_topology_table_lookup_ipv4(eigrp->topology_table, &dest_addr); @@ -351,7 +348,6 @@ void eigrp_if_free(struct eigrp_interface *ei, int source) eigrp_if_down(ei); - list_delete(&ei->nbrs); listnode_delete(ei->eigrp->eiflist, ei); } @@ -379,7 +375,7 @@ struct eigrp_interface *eigrp_if_lookup_by_local_addr(struct eigrp *eigrp, if (ifp && ei->ifp != ifp) continue; - if (IPV4_ADDR_SAME(&address, &ei->address->u.prefix4)) + if (IPV4_ADDR_SAME(&address, &ei->address.u.prefix4)) return ei; } diff --git a/eigrpd/eigrp_network.c b/eigrpd/eigrp_network.c index 6bb619f0e1..76f8cfc93b 100644 --- a/eigrpd/eigrp_network.c +++ b/eigrpd/eigrp_network.c @@ -293,7 +293,7 @@ void eigrp_if_update(struct interface *ifp) */ for (ALL_LIST_ELEMENTS(eigrp_om->eigrp, node, nnode, eigrp)) { /* EIGRP must be on and Router-ID must be configured. */ - if (!eigrp || eigrp->router_id.s_addr == 0) + if (eigrp->router_id.s_addr == 0) continue; /* Run each network for this interface. */ @@ -333,7 +333,7 @@ int eigrp_network_unset(struct eigrp *eigrp, struct prefix *p) if (rn->info == NULL) continue; - if (eigrp_network_match_iface(ei->address, &rn->p)) { + if (eigrp_network_match_iface(&ei->address, &rn->p)) { found = true; route_unlock_node(rn); break; diff --git a/eigrpd/eigrp_packet.c b/eigrpd/eigrp_packet.c index ee0476b28d..bedaf15c47 100644 --- a/eigrpd/eigrp_packet.c +++ b/eigrpd/eigrp_packet.c @@ -281,7 +281,7 @@ int eigrp_make_sha256_digest(struct eigrp_interface *ei, struct stream *s, return 0; } - inet_ntop(AF_INET, &ei->address->u.prefix4, source_ip, PREFIX_STRLEN); + inet_ntop(AF_INET, &ei->address.u.prefix4, source_ip, PREFIX_STRLEN); memset(&ctx, 0, sizeof(ctx)); buffer[0] = '\n'; @@ -362,7 +362,7 @@ int eigrp_write(struct thread *thread) } if (ep->dst.s_addr == htonl(EIGRP_MULTICAST_ADDRESS)) - eigrp_if_ipmulticast(eigrp, ei->address, ei->ifp->ifindex); + eigrp_if_ipmulticast(eigrp, &ei->address, ei->ifp->ifindex); memset(&iph, 0, sizeof(struct ip)); memset(&sa_dst, 0, sizeof(sa_dst)); @@ -418,7 +418,7 @@ int eigrp_write(struct thread *thread) iph.ip_ttl = EIGRP_IP_TTL; iph.ip_p = IPPROTO_EIGRPIGP; iph.ip_sum = 0; - iph.ip_src.s_addr = ei->address->u.prefix4.s_addr; + iph.ip_src.s_addr = ei->address.u.prefix4.s_addr; iph.ip_dst.s_addr = ep->dst.s_addr; memset(&msg, 0, sizeof(msg)); @@ -547,7 +547,7 @@ int eigrp_read(struct thread *thread) /* Self-originated packet should be discarded silently. */ if (eigrp_if_lookup_by_local_addr(eigrp, NULL, iph->ip_src) - || (IPV4_ADDR_SAME(&iph->ip_src, &ei->address->u.prefix4))) { + || (IPV4_ADDR_SAME(&iph->ip_src, &ei->address.u.prefix4))) { if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV)) zlog_debug( "eigrp_read[%s]: Dropping self-originated packet", @@ -581,7 +581,7 @@ int eigrp_read(struct thread *thread) sizeof(buf[0])), inet_ntop(AF_INET, &iph->ip_dst, buf[1], sizeof(buf[1])), - inet_ntop(AF_INET, &ei->address->u.prefix4, + inet_ntop(AF_INET, &ei->address.u.prefix4, buf[2], sizeof(buf[2]))); if (iph->ip_dst.s_addr == htonl(EIGRP_MULTICAST_ADDRESS)) { @@ -981,9 +981,9 @@ static int eigrp_check_network_mask(struct eigrp_interface *ei, if (ei->type == EIGRP_IFTYPE_POINTOPOINT) return 1; - masklen2ip(ei->address->prefixlen, &mask); + masklen2ip(ei->address.prefixlen, &mask); - me.s_addr = ei->address->u.prefix4.s_addr & mask.s_addr; + me.s_addr = ei->address.u.prefix4.s_addr & mask.s_addr; him.s_addr = ip_src.s_addr & mask.s_addr; if (IPV4_ADDR_SAME(&me, &him)) diff --git a/eigrpd/eigrp_structs.h b/eigrpd/eigrp_structs.h index 644ab0829f..a78e5a53cf 100644 --- a/eigrpd/eigrp_structs.h +++ b/eigrpd/eigrp_structs.h @@ -180,7 +180,7 @@ struct eigrp_interface { /* EIGRP Network Type. */ uint8_t type; - struct prefix *address; /* Interface prefix */ + struct prefix address; /* Interface prefix */ /* Neighbor information. */ struct list *nbrs; /* EIGRP Neighbor List */ diff --git a/eigrpd/eigrp_topology.c b/eigrpd/eigrp_topology.c index 2d0ebf1bc5..e861cdb333 100644 --- a/eigrpd/eigrp_topology.c +++ b/eigrpd/eigrp_topology.c @@ -141,10 +141,10 @@ void eigrp_prefix_entry_add(struct route_table *topology, __PRETTY_FUNCTION__, prefix2str(pe->destination, buf, sizeof(buf))); } + route_unlock_node(rn); } rn->info = pe; - route_lock_node(rn); } /* @@ -161,7 +161,7 @@ void eigrp_nexthop_entry_add(struct eigrp_prefix_entry *node, listnode_add_sort(node->entries, entry); entry->prefix = node; - eigrp_zebra_route_add(node->destination, l); + eigrp_zebra_route_add(node->destination, l, node->fdistance); } list_delete(&l); @@ -477,7 +477,8 @@ void eigrp_update_routing_table(struct eigrp_prefix_entry *prefix) successors = eigrp_topology_get_successor_max(prefix, eigrp->max_paths); if (successors) { - eigrp_zebra_route_add(prefix->destination, successors); + eigrp_zebra_route_add(prefix->destination, successors, + prefix->fdistance); for (ALL_LIST_ELEMENTS_RO(successors, node, entry)) entry->flags |= EIGRP_NEXTHOP_ENTRY_INTABLE_FLAG; diff --git a/eigrpd/eigrp_vty.c b/eigrpd/eigrp_vty.c index 474f683989..a9b103de47 100644 --- a/eigrpd/eigrp_vty.c +++ b/eigrpd/eigrp_vty.c @@ -455,9 +455,33 @@ DEFUN (no_eigrp_neighbor, return CMD_SUCCESS; } -DEFUN (show_ip_eigrp_topology, - show_ip_eigrp_topology_cmd, - "show ip eigrp topology [all-links]", +static void eigrp_vty_display_prefix_entry(struct vty *vty, + struct eigrp *eigrp, + struct eigrp_prefix_entry *pe, + bool all) +{ + bool first = true; + struct eigrp_nexthop_entry *te; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(pe->entries, node, te)) { + if (all + || (((te->flags + & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG) + == EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG) + || ((te->flags + & EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG) + == EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG))) { + show_ip_eigrp_nexthop_entry(vty, eigrp, te, + &first); + first = false; + } + } +} + +DEFPY (show_ip_eigrp_topology_all, + show_ip_eigrp_topology_all_cmd, + "show ip eigrp topology [all-links$all]", SHOW_STR IP_STR "IP-EIGRP show commands\n" @@ -465,11 +489,8 @@ DEFUN (show_ip_eigrp_topology, "Show all links in topology table\n") { struct eigrp *eigrp; - struct listnode *node; struct eigrp_prefix_entry *tn; - struct eigrp_nexthop_entry *te; struct route_node *rn; - int first; eigrp = eigrp_lookup(); if (eigrp == NULL) { @@ -484,34 +505,63 @@ DEFUN (show_ip_eigrp_topology, continue; tn = rn->info; - first = 1; - for (ALL_LIST_ELEMENTS_RO(tn->entries, node, te)) { - if (argc == 5 - || (((te->flags - & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG) - == EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG) - || ((te->flags - & EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG) - == EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG))) { - show_ip_eigrp_nexthop_entry(vty, eigrp, te, - &first); - first = 0; - } - } + eigrp_vty_display_prefix_entry(vty, eigrp, tn, + all ? true : false); } return CMD_SUCCESS; + } -ALIAS(show_ip_eigrp_topology, show_ip_eigrp_topology_detail_cmd, - "show ip eigrp topology <A.B.C.D|A.B.C.D/M|detail|summary>", - SHOW_STR IP_STR - "IP-EIGRP show commands\n" - "IP-EIGRP topology\n" - "Netwok to display information about\n" - "IP prefix <network>/<length>, e.g., 192.168.0.0/16\n" - "Show all links in topology table\n" - "Show a summary of the topology table\n") +DEFPY (show_ip_eigrp_topology, + show_ip_eigrp_topology_cmd, + "show ip eigrp topology <A.B.C.D$address|A.B.C.D/M$prefix>", + SHOW_STR + IP_STR + "IP-EIGRP show commands\n" + "IP-EIGRP topology\n" + "For a specific address\n" + "For a specific prefix\n") +{ + struct eigrp *eigrp; + struct eigrp_prefix_entry *tn; + struct route_node *rn; + struct prefix cmp; + + eigrp = eigrp_lookup(); + if (eigrp == NULL) { + vty_out(vty, " EIGRP Routing Process not enabled\n"); + return CMD_SUCCESS; + } + + show_ip_eigrp_topology_header(vty, eigrp); + + if (address_str) + prefix_str = address_str; + + if (str2prefix(prefix_str, &cmp) < 0) { + vty_out(vty, "%% Malformed address\n"); + return CMD_WARNING; + } + + rn = route_node_match(eigrp->topology_table, &cmp); + if (!rn) { + vty_out(vty, "%% Network not in table\n"); + return CMD_WARNING; + } + + if (!rn->info) { + vty_out(vty, "%% Network not in table\n"); + route_unlock_node(rn); + return CMD_WARNING; + } + + tn = rn->info; + eigrp_vty_display_prefix_entry(vty, eigrp, tn, argc == 5); + + route_unlock_node(rn); + return CMD_SUCCESS; +} DEFUN (show_ip_eigrp_interfaces, show_ip_eigrp_interfaces_cmd, @@ -1485,8 +1535,7 @@ void eigrp_vty_show_init(void) install_element(VIEW_NODE, &show_ip_eigrp_neighbors_cmd); install_element(VIEW_NODE, &show_ip_eigrp_topology_cmd); - - install_element(VIEW_NODE, &show_ip_eigrp_topology_detail_cmd); + install_element(VIEW_NODE, &show_ip_eigrp_topology_all_cmd); } /* eigrpd's interface node. */ diff --git a/eigrpd/eigrp_zebra.c b/eigrpd/eigrp_zebra.c index a810e01468..dc1ae675b0 100644 --- a/eigrpd/eigrp_zebra.c +++ b/eigrpd/eigrp_zebra.c @@ -258,7 +258,8 @@ static int eigrp_interface_address_delete(int command, struct zclient *zclient, return 0; /* Call interface hook functions to clean up */ - eigrp_if_free(ei, INTERFACE_DOWN_BY_ZEBRA); + if (prefix_cmp(&ei->address, c->address) == 0) + eigrp_if_free(ei, INTERFACE_DOWN_BY_ZEBRA); connected_free(c); @@ -353,7 +354,8 @@ static struct interface *zebra_interface_if_lookup(struct stream *s) return if_lookup_by_name(ifname_tmp, VRF_DEFAULT); } -void eigrp_zebra_route_add(struct prefix *p, struct list *successors) +void eigrp_zebra_route_add(struct prefix *p, struct list *successors, + uint32_t distance) { struct zapi_route api; struct zapi_nexthop *api_nh; @@ -368,9 +370,11 @@ void eigrp_zebra_route_add(struct prefix *p, struct list *successors) api.vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_EIGRP; api.safi = SAFI_UNICAST; + api.metric = distance; memcpy(&api.prefix, p, sizeof(*p)); SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); + SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); /* Nexthop, ifindex, distance and metric information. */ for (ALL_LIST_ELEMENTS_RO(successors, node, te)) { diff --git a/eigrpd/eigrp_zebra.h b/eigrpd/eigrp_zebra.h index 1c418dddef..86b337cfe6 100644 --- a/eigrpd/eigrp_zebra.h +++ b/eigrpd/eigrp_zebra.h @@ -33,7 +33,8 @@ extern void eigrp_zebra_init(void); -extern void eigrp_zebra_route_add(struct prefix *, struct list *); +extern void eigrp_zebra_route_add(struct prefix *, struct list *, + uint32_t distance); extern void eigrp_zebra_route_delete(struct prefix *); extern int eigrp_redistribute_set(struct eigrp *, int, struct eigrp_metrics); extern int eigrp_redistribute_unset(struct eigrp *, int); diff --git a/eigrpd/subdir.am b/eigrpd/subdir.am index d532afbbe6..4503030fdf 100644 --- a/eigrpd/subdir.am +++ b/eigrpd/subdir.am @@ -65,4 +65,4 @@ noinst_HEADERS += \ # end eigrpd_eigrpd_SOURCES = eigrpd/eigrp_main.c -eigrpd_eigrpd_LDADD = eigrpd/libeigrp.a lib/libfrr.la @LIBCAP@ +eigrpd_eigrpd_LDADD = eigrpd/libeigrp.a lib/libfrr.la $(LIBCAP) diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c index c68f49f92d..bd8b58e8f0 100644 --- a/isisd/isis_cli.c +++ b/isisd/isis_cli.c @@ -89,7 +89,7 @@ DEFPY(no_router_isis, no_router_isis_cmd, "no router isis WORD$tag", return CMD_ERR_NOTHING_TODO; } - nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); area = isis_area_lookup(tag); if (area && area->circuit_list && listcount(area->circuit_list)) { for (ALL_LIST_ELEMENTS(area->circuit_list, node, nnode, @@ -103,7 +103,7 @@ DEFPY(no_router_isis, no_router_isis_cmd, "no router isis WORD$tag", temp_xpath, XPATH_MAXLEN, "/frr-interface:lib/interface[name='%s'][vrf='%s']/frr-isisd:isis", circuit->interface->name, vrf_name); - nb_cli_enqueue_change(vty, temp_xpath, NB_OP_DELETE, + nb_cli_enqueue_change(vty, temp_xpath, NB_OP_DESTROY, NULL); } } @@ -289,7 +289,7 @@ DEFPY(no_ip_router_isis, no_ip_router_isis_cmd, && !yang_dnode_get_bool(dnode, "./frr-isisd:isis/ipv4-routing")) nb_cli_enqueue_change(vty, "./frr-isisd:isis", - NB_OP_DELETE, NULL); + NB_OP_DESTROY, NULL); else nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv6-routing", @@ -299,7 +299,7 @@ DEFPY(no_ip_router_isis, no_ip_router_isis_cmd, && !yang_dnode_get_bool(dnode, "./frr-isisd:isis/ipv6-routing")) nb_cli_enqueue_change(vty, "./frr-isisd:isis", - NB_OP_DELETE, NULL); + NB_OP_DESTROY, NULL); else nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv4-routing", @@ -336,7 +336,7 @@ DEFPY(net, net_cmd, "[no] net WORD", "XX.XXXX. ... .XXX.XX Network entity title (NET)\n") { nb_cli_enqueue_change(vty, "./area-address", - no ? NB_OP_DELETE : NB_OP_CREATE, net); + no ? NB_OP_DESTROY : NB_OP_CREATE, net); return nb_cli_apply_changes(vty, NULL); } @@ -589,7 +589,7 @@ DEFPY(no_area_passwd, no_area_passwd_cmd, "Configure the authentication password for an area\n" "Set the authentication password for a routing domain\n") { - nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, "./%s", cmd); } @@ -892,7 +892,7 @@ DEFPY(no_spf_delay_ietf, no_spf_delay_ietf_cmd, "Maximum duration needed to learn all the events related to a single failure\n" "Maximum duration needed to learn all the events related to a single failure (in milliseconds)\n") { - nb_cli_enqueue_change(vty, "./spf/ietf-backoff-delay", NB_OP_DELETE, + nb_cli_enqueue_change(vty, "./spf/ietf-backoff-delay", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); @@ -947,7 +947,7 @@ DEFPY(no_isis_mpls_te_on, no_isis_mpls_te_on_cmd, "no mpls-te [on]", "Disable the MPLS-TE functionality\n" "Enable the MPLS-TE functionality\n") { - nb_cli_enqueue_change(vty, "/frr-isisd:isis/mpls-te", NB_OP_DELETE, + nb_cli_enqueue_change(vty, "/frr-isisd:isis/mpls-te", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); @@ -1014,16 +1014,16 @@ DEFPY(isis_default_originate, isis_default_originate_cmd, "Pointer to route-map entries\n") { if (no) - nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); else { nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); nb_cli_enqueue_change(vty, "./always", NB_OP_MODIFY, always ? "true" : "false"); nb_cli_enqueue_change(vty, "./route-map", - rmap ? NB_OP_MODIFY : NB_OP_DELETE, + rmap ? NB_OP_MODIFY : NB_OP_DESTROY, rmap ? rmap : NULL); nb_cli_enqueue_change(vty, "./metric", - metric ? NB_OP_MODIFY : NB_OP_DELETE, + metric ? NB_OP_MODIFY : NB_OP_DESTROY, metric ? metric_str : NULL); if (strmatch(ip, "ipv6") && !always) { vty_out(vty, @@ -1094,14 +1094,14 @@ DEFPY(isis_redistribute, isis_redistribute_cmd, "Pointer to route-map entries\n") { if (no) - nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); else { nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); nb_cli_enqueue_change(vty, "./route-map", - route_map ? NB_OP_MODIFY : NB_OP_DELETE, + route_map ? NB_OP_MODIFY : NB_OP_DESTROY, route_map ? route_map : NULL); nb_cli_enqueue_change(vty, "./metric", - metric ? NB_OP_MODIFY : NB_OP_DELETE, + metric ? NB_OP_MODIFY : NB_OP_DESTROY, metric ? metric_str : NULL); } @@ -1182,7 +1182,7 @@ DEFPY(isis_topology, isis_topology_cmd, topology); if (no) - nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); else { nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); nb_cli_enqueue_change(vty, "./overload", NB_OP_MODIFY, @@ -1297,7 +1297,7 @@ DEFPY(no_isis_passwd, no_isis_passwd_cmd, "no isis password [<md5|clear> WORD]", "Cleartext password\n" "Circuit password\n") { - nb_cli_enqueue_change(vty, "./frr-isisd:isis/password", NB_OP_DELETE, + nb_cli_enqueue_change(vty, "./frr-isisd:isis/password", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); diff --git a/isisd/isis_northbound.c b/isisd/isis_northbound.c index 9c2bb1728e..3364a9f0be 100644 --- a/isisd/isis_northbound.c +++ b/isisd/isis_northbound.c @@ -72,7 +72,7 @@ static int isis_instance_create(enum nb_event event, return NB_OK; } -static int isis_instance_delete(enum nb_event event, +static int isis_instance_destroy(enum nb_event event, const struct lyd_node *dnode) { const char *area_tag; @@ -193,7 +193,7 @@ static int isis_instance_area_address_create(enum nb_event event, return NB_OK; } -static int isis_instance_area_address_delete(enum nb_event event, +static int isis_instance_area_address_destroy(enum nb_event event, const struct lyd_node *dnode) { struct area_addr addr, *addrp = NULL; @@ -536,7 +536,7 @@ isis_instance_spf_ietf_backoff_delay_create(enum nb_event event, } static int -isis_instance_spf_ietf_backoff_delay_delete(enum nb_event event, +isis_instance_spf_ietf_backoff_delay_destroy(enum nb_event event, const struct lyd_node *dnode) { struct isis_area *area; @@ -676,7 +676,7 @@ static int isis_instance_area_password_create(enum nb_event event, return NB_OK; } -static int isis_instance_area_password_delete(enum nb_event event, +static int isis_instance_area_password_destroy(enum nb_event event, const struct lyd_node *dnode) { struct isis_area *area; @@ -755,7 +755,7 @@ static int isis_instance_domain_password_create(enum nb_event event, return NB_OK; } -static int isis_instance_domain_password_delete(enum nb_event event, +static int isis_instance_domain_password_destroy(enum nb_event event, const struct lyd_node *dnode) { struct isis_area *area; @@ -851,7 +851,7 @@ static int isis_instance_default_information_originate_ipv4_create( return NB_OK; } -static int isis_instance_default_information_originate_ipv4_delete( +static int isis_instance_default_information_originate_ipv4_destroy( enum nb_event event, const struct lyd_node *dnode) { struct isis_area *area; @@ -889,7 +889,7 @@ static int isis_instance_default_information_originate_ipv4_route_map_modify( return NB_OK; } -static int isis_instance_default_information_originate_ipv4_route_map_delete( +static int isis_instance_default_information_originate_ipv4_route_map_destroy( enum nb_event event, const struct lyd_node *dnode) { /* It's all done by default_info_origin_apply_finish */ @@ -907,7 +907,7 @@ static int isis_instance_default_information_originate_ipv4_metric_modify( return NB_OK; } -static int isis_instance_default_information_originate_ipv4_metric_delete( +static int isis_instance_default_information_originate_ipv4_metric_destroy( enum nb_event event, const struct lyd_node *dnode) { /* It's all done by default_info_origin_apply_finish */ @@ -925,7 +925,7 @@ static int isis_instance_default_information_originate_ipv6_create( return NB_OK; } -static int isis_instance_default_information_originate_ipv6_delete( +static int isis_instance_default_information_originate_ipv6_destroy( enum nb_event event, const struct lyd_node *dnode) { struct isis_area *area; @@ -963,7 +963,7 @@ static int isis_instance_default_information_originate_ipv6_route_map_modify( return NB_OK; } -static int isis_instance_default_information_originate_ipv6_route_map_delete( +static int isis_instance_default_information_originate_ipv6_route_map_destroy( enum nb_event event, const struct lyd_node *dnode) { /* It's all done by default_info_origin_apply_finish */ @@ -981,7 +981,7 @@ static int isis_instance_default_information_originate_ipv6_metric_modify( return NB_OK; } -static int isis_instance_default_information_originate_ipv6_metric_delete( +static int isis_instance_default_information_originate_ipv6_metric_destroy( enum nb_event event, const struct lyd_node *dnode) { /* It's all done by default_info_origin_apply_finish */ @@ -1029,7 +1029,7 @@ static int isis_instance_redistribute_ipv4_create(enum nb_event event, return NB_OK; } -static int isis_instance_redistribute_ipv4_delete(enum nb_event event, +static int isis_instance_redistribute_ipv4_destroy(enum nb_event event, const struct lyd_node *dnode) { struct isis_area *area; @@ -1059,7 +1059,7 @@ isis_instance_redistribute_ipv4_route_map_modify(enum nb_event event, } static int -isis_instance_redistribute_ipv4_route_map_delete(enum nb_event event, +isis_instance_redistribute_ipv4_route_map_destroy(enum nb_event event, const struct lyd_node *dnode) { /* It's all done by redistribute_apply_finish */ @@ -1079,7 +1079,7 @@ isis_instance_redistribute_ipv4_metric_modify(enum nb_event event, } static int -isis_instance_redistribute_ipv4_metric_delete(enum nb_event event, +isis_instance_redistribute_ipv4_metric_destroy(enum nb_event event, const struct lyd_node *dnode) { /* It's all done by redistribute_apply_finish */ @@ -1097,7 +1097,7 @@ static int isis_instance_redistribute_ipv6_create(enum nb_event event, return NB_OK; } -static int isis_instance_redistribute_ipv6_delete(enum nb_event event, +static int isis_instance_redistribute_ipv6_destroy(enum nb_event event, const struct lyd_node *dnode) { struct isis_area *area; @@ -1127,7 +1127,7 @@ isis_instance_redistribute_ipv6_route_map_modify(enum nb_event event, } static int -isis_instance_redistribute_ipv6_route_map_delete(enum nb_event event, +isis_instance_redistribute_ipv6_route_map_destroy(enum nb_event event, const struct lyd_node *dnode) { /* It's all done by redistribute_apply_finish */ @@ -1147,7 +1147,7 @@ isis_instance_redistribute_ipv6_metric_modify(enum nb_event event, } static int -isis_instance_redistribute_ipv6_metric_delete(enum nb_event event, +isis_instance_redistribute_ipv6_metric_destroy(enum nb_event event, const struct lyd_node *dnode) { /* It's all done by redistribute_apply_finish */ @@ -1217,7 +1217,7 @@ isis_instance_multi_topology_ipv4_multicast_create(enum nb_event event, } static int -isis_instance_multi_topology_ipv4_multicast_delete(enum nb_event event, +isis_instance_multi_topology_ipv4_multicast_destroy(enum nb_event event, const struct lyd_node *dnode) { return isis_multi_topology_common(event, dnode, "ipv4-multicast", @@ -1245,7 +1245,7 @@ static int isis_instance_multi_topology_ipv4_management_create( return isis_multi_topology_common(event, dnode, "ipv4-mgmt", true); } -static int isis_instance_multi_topology_ipv4_management_delete( +static int isis_instance_multi_topology_ipv4_management_destroy( enum nb_event event, const struct lyd_node *dnode) { return isis_multi_topology_common(event, dnode, "ipv4-mgmt", false); @@ -1273,7 +1273,7 @@ isis_instance_multi_topology_ipv6_unicast_create(enum nb_event event, } static int -isis_instance_multi_topology_ipv6_unicast_delete(enum nb_event event, +isis_instance_multi_topology_ipv6_unicast_destroy(enum nb_event event, const struct lyd_node *dnode) { return isis_multi_topology_common(event, dnode, "ipv6-unicast", false); @@ -1302,7 +1302,7 @@ isis_instance_multi_topology_ipv6_multicast_create(enum nb_event event, } static int -isis_instance_multi_topology_ipv6_multicast_delete(enum nb_event event, +isis_instance_multi_topology_ipv6_multicast_destroy(enum nb_event event, const struct lyd_node *dnode) { return isis_multi_topology_common(event, dnode, "ipv6-multicast", @@ -1330,7 +1330,7 @@ static int isis_instance_multi_topology_ipv6_management_create( return isis_multi_topology_common(event, dnode, "ipv6-mgmt", true); } -static int isis_instance_multi_topology_ipv6_management_delete( +static int isis_instance_multi_topology_ipv6_management_destroy( enum nb_event event, const struct lyd_node *dnode) { return isis_multi_topology_common(event, dnode, "ipv6-mgmt", false); @@ -1358,7 +1358,7 @@ isis_instance_multi_topology_ipv6_dstsrc_create(enum nb_event event, } static int -isis_instance_multi_topology_ipv6_dstsrc_delete(enum nb_event event, +isis_instance_multi_topology_ipv6_dstsrc_destroy(enum nb_event event, const struct lyd_node *dnode) { return isis_multi_topology_common(event, dnode, "ipv6-dstsrc", false); @@ -1436,7 +1436,7 @@ static int isis_mpls_te_create(enum nb_event event, return NB_OK; } -static int isis_mpls_te_delete(enum nb_event event, +static int isis_mpls_te_destroy(enum nb_event event, const struct lyd_node *dnode) { struct listnode *node; @@ -1494,7 +1494,7 @@ static int isis_mpls_te_router_address_modify(enum nb_event event, return NB_OK; } -static int isis_mpls_te_router_address_delete(enum nb_event event, +static int isis_mpls_te_router_address_destroy(enum nb_event event, const struct lyd_node *dnode) { struct listnode *node; @@ -1555,7 +1555,7 @@ static int lib_interface_isis_create(enum nb_event event, return NB_OK; } -static int lib_interface_isis_delete(enum nb_event event, +static int lib_interface_isis_destroy(enum nb_event event, const struct lyd_node *dnode) { struct isis_circuit *circuit; @@ -2062,7 +2062,7 @@ static int lib_interface_isis_password_create(enum nb_event event, return NB_OK; } -static int lib_interface_isis_password_delete(enum nb_event event, +static int lib_interface_isis_password_destroy(enum nb_event event, const struct lyd_node *dnode) { struct isis_circuit *circuit; @@ -2749,7 +2749,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance", .cbs.create = isis_instance_create, - .cbs.delete = isis_instance_delete, + .cbs.destroy = isis_instance_destroy, .cbs.cli_show = cli_show_router_isis, .priority = NB_DFLT_PRIORITY - 1, }, @@ -2761,7 +2761,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/area-address", .cbs.create = isis_instance_area_address_create, - .cbs.delete = isis_instance_area_address_delete, + .cbs.destroy = isis_instance_area_address_destroy, .cbs.cli_show = cli_show_isis_area_address, }, { @@ -2833,7 +2833,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/spf/ietf-backoff-delay", .cbs.create = isis_instance_spf_ietf_backoff_delay_create, - .cbs.delete = isis_instance_spf_ietf_backoff_delay_delete, + .cbs.destroy = isis_instance_spf_ietf_backoff_delay_destroy, .cbs.apply_finish = ietf_backoff_delay_apply_finish, .cbs.cli_show = cli_show_isis_spf_ietf_backoff, }, @@ -2872,7 +2872,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/area-password", .cbs.create = isis_instance_area_password_create, - .cbs.delete = isis_instance_area_password_delete, + .cbs.destroy = isis_instance_area_password_destroy, .cbs.apply_finish = area_password_apply_finish, .cbs.cli_show = cli_show_isis_area_pwd, }, @@ -2891,7 +2891,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/domain-password", .cbs.create = isis_instance_domain_password_create, - .cbs.delete = isis_instance_domain_password_delete, + .cbs.destroy = isis_instance_domain_password_destroy, .cbs.apply_finish = domain_password_apply_finish, .cbs.cli_show = cli_show_isis_domain_pwd, }, @@ -2910,7 +2910,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv4", .cbs.create = isis_instance_default_information_originate_ipv4_create, - .cbs.delete = isis_instance_default_information_originate_ipv4_delete, + .cbs.destroy = isis_instance_default_information_originate_ipv4_destroy, .cbs.apply_finish = default_info_origin_ipv4_apply_finish, .cbs.cli_show = cli_show_isis_def_origin_ipv4, }, @@ -2921,17 +2921,17 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv4/route-map", .cbs.modify = isis_instance_default_information_originate_ipv4_route_map_modify, - .cbs.delete = isis_instance_default_information_originate_ipv4_route_map_delete, + .cbs.destroy = isis_instance_default_information_originate_ipv4_route_map_destroy, }, { .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv4/metric", .cbs.modify = isis_instance_default_information_originate_ipv4_metric_modify, - .cbs.delete = isis_instance_default_information_originate_ipv4_metric_delete, + .cbs.destroy = isis_instance_default_information_originate_ipv4_metric_destroy, }, { .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv6", .cbs.create = isis_instance_default_information_originate_ipv6_create, - .cbs.delete = isis_instance_default_information_originate_ipv6_delete, + .cbs.destroy = isis_instance_default_information_originate_ipv6_destroy, .cbs.apply_finish = default_info_origin_ipv6_apply_finish, .cbs.cli_show = cli_show_isis_def_origin_ipv6, }, @@ -2942,51 +2942,51 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv6/route-map", .cbs.modify = isis_instance_default_information_originate_ipv6_route_map_modify, - .cbs.delete = isis_instance_default_information_originate_ipv6_route_map_delete, + .cbs.destroy = isis_instance_default_information_originate_ipv6_route_map_destroy, }, { .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv6/metric", .cbs.modify = isis_instance_default_information_originate_ipv6_metric_modify, - .cbs.delete = isis_instance_default_information_originate_ipv6_metric_delete, + .cbs.destroy = isis_instance_default_information_originate_ipv6_metric_destroy, }, { .xpath = "/frr-isisd:isis/instance/redistribute/ipv4", .cbs.create = isis_instance_redistribute_ipv4_create, - .cbs.delete = isis_instance_redistribute_ipv4_delete, + .cbs.destroy = isis_instance_redistribute_ipv4_destroy, .cbs.apply_finish = redistribute_ipv4_apply_finish, .cbs.cli_show = cli_show_isis_redistribute_ipv4, }, { .xpath = "/frr-isisd:isis/instance/redistribute/ipv4/route-map", .cbs.modify = isis_instance_redistribute_ipv4_route_map_modify, - .cbs.delete = isis_instance_redistribute_ipv4_route_map_delete, + .cbs.destroy = isis_instance_redistribute_ipv4_route_map_destroy, }, { .xpath = "/frr-isisd:isis/instance/redistribute/ipv4/metric", .cbs.modify = isis_instance_redistribute_ipv4_metric_modify, - .cbs.delete = isis_instance_redistribute_ipv4_metric_delete, + .cbs.destroy = isis_instance_redistribute_ipv4_metric_destroy, }, { .xpath = "/frr-isisd:isis/instance/redistribute/ipv6", .cbs.create = isis_instance_redistribute_ipv6_create, - .cbs.delete = isis_instance_redistribute_ipv6_delete, + .cbs.destroy = isis_instance_redistribute_ipv6_destroy, .cbs.apply_finish = redistribute_ipv6_apply_finish, .cbs.cli_show = cli_show_isis_redistribute_ipv6, }, { .xpath = "/frr-isisd:isis/instance/redistribute/ipv6/route-map", .cbs.modify = isis_instance_redistribute_ipv6_route_map_modify, - .cbs.delete = isis_instance_redistribute_ipv6_route_map_delete, + .cbs.destroy = isis_instance_redistribute_ipv6_route_map_destroy, }, { .xpath = "/frr-isisd:isis/instance/redistribute/ipv6/metric", .cbs.modify = isis_instance_redistribute_ipv6_metric_modify, - .cbs.delete = isis_instance_redistribute_ipv6_metric_delete, + .cbs.destroy = isis_instance_redistribute_ipv6_metric_destroy, }, { .xpath = "/frr-isisd:isis/instance/multi-topology/ipv4-multicast", .cbs.create = isis_instance_multi_topology_ipv4_multicast_create, - .cbs.delete = isis_instance_multi_topology_ipv4_multicast_delete, + .cbs.destroy = isis_instance_multi_topology_ipv4_multicast_destroy, .cbs.cli_show = cli_show_isis_mt_ipv4_multicast, }, { @@ -2996,7 +2996,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/multi-topology/ipv4-management", .cbs.create = isis_instance_multi_topology_ipv4_management_create, - .cbs.delete = isis_instance_multi_topology_ipv4_management_delete, + .cbs.destroy = isis_instance_multi_topology_ipv4_management_destroy, .cbs.cli_show = cli_show_isis_mt_ipv4_mgmt, }, { @@ -3006,7 +3006,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/multi-topology/ipv6-unicast", .cbs.create = isis_instance_multi_topology_ipv6_unicast_create, - .cbs.delete = isis_instance_multi_topology_ipv6_unicast_delete, + .cbs.destroy = isis_instance_multi_topology_ipv6_unicast_destroy, .cbs.cli_show = cli_show_isis_mt_ipv6_unicast, }, { @@ -3016,7 +3016,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/multi-topology/ipv6-multicast", .cbs.create = isis_instance_multi_topology_ipv6_multicast_create, - .cbs.delete = isis_instance_multi_topology_ipv6_multicast_delete, + .cbs.destroy = isis_instance_multi_topology_ipv6_multicast_destroy, .cbs.cli_show = cli_show_isis_mt_ipv6_multicast, }, { @@ -3026,7 +3026,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/multi-topology/ipv6-management", .cbs.create = isis_instance_multi_topology_ipv6_management_create, - .cbs.delete = isis_instance_multi_topology_ipv6_management_delete, + .cbs.destroy = isis_instance_multi_topology_ipv6_management_destroy, .cbs.cli_show = cli_show_isis_mt_ipv6_mgmt, }, { @@ -3036,7 +3036,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/instance/multi-topology/ipv6-dstsrc", .cbs.create = isis_instance_multi_topology_ipv6_dstsrc_create, - .cbs.delete = isis_instance_multi_topology_ipv6_dstsrc_delete, + .cbs.destroy = isis_instance_multi_topology_ipv6_dstsrc_destroy, .cbs.cli_show = cli_show_isis_mt_ipv6_dstsrc, }, { @@ -3051,19 +3051,19 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-isisd:isis/mpls-te", .cbs.create = isis_mpls_te_create, - .cbs.delete = isis_mpls_te_delete, + .cbs.destroy = isis_mpls_te_destroy, .cbs.cli_show = cli_show_isis_mpls_te, }, { .xpath = "/frr-isisd:isis/mpls-te/router-address", .cbs.modify = isis_mpls_te_router_address_modify, - .cbs.delete = isis_mpls_te_router_address_delete, + .cbs.destroy = isis_mpls_te_router_address_destroy, .cbs.cli_show = cli_show_isis_mpls_te_router_addr, }, { .xpath = "/frr-interface:lib/interface/frr-isisd:isis", .cbs.create = lib_interface_isis_create, - .cbs.delete = lib_interface_isis_delete, + .cbs.destroy = lib_interface_isis_destroy, }, { .xpath = "/frr-interface:lib/interface/frr-isisd:isis/area-tag", @@ -3174,7 +3174,7 @@ const struct frr_yang_module_info frr_isisd_info = { { .xpath = "/frr-interface:lib/interface/frr-isisd:isis/password", .cbs.create = lib_interface_isis_password_create, - .cbs.delete = lib_interface_isis_password_delete, + .cbs.destroy = lib_interface_isis_password_destroy, .cbs.cli_show = cli_show_ip_isis_password, }, { diff --git a/isisd/isis_redist.c b/isisd/isis_redist.c index 815de513fc..20f3e62a74 100644 --- a/isisd/isis_redist.c +++ b/isisd/isis_redist.c @@ -338,12 +338,14 @@ static void isis_redist_routemap_set(struct isis_redist *redist, { if (redist->map_name) { XFREE(MTYPE_ISIS, redist->map_name); + route_map_counter_decrement(redist->map); redist->map = NULL; } if (routemap && strlen(routemap)) { redist->map_name = XSTRDUP(MTYPE_ISIS, routemap); redist->map = route_map_lookup_by_name(routemap); + route_map_counter_increment(redist->map); } } diff --git a/isisd/subdir.am b/isisd/subdir.am index c5b9b31a48..4371d5993a 100644 --- a/isisd/subdir.am +++ b/isisd/subdir.am @@ -98,7 +98,7 @@ ISIS_SOURCES = \ isisd/isis_pfpacket.c \ # end -ISIS_LDADD_COMMON = lib/libfrr.la @LIBCAP@ +ISIS_LDADD_COMMON = lib/libfrr.la $(LIBCAP) # Building isisd diff --git a/ldpd/subdir.am b/ldpd/subdir.am index 24e738d622..42c5ad024b 100644 --- a/ldpd/subdir.am +++ b/ldpd/subdir.am @@ -55,4 +55,4 @@ noinst_HEADERS += \ # end ldpd_ldpd_SOURCES = ldpd/ldpd.c -ldpd_ldpd_LDADD = ldpd/libldp.a lib/libfrr.la @LIBCAP@ +ldpd_ldpd_LDADD = ldpd/libldp.a lib/libfrr.la $(LIBCAP) diff --git a/lib/agg_table.h b/lib/agg_table.h index dc2ff03b67..40ffe8c755 100644 --- a/lib/agg_table.h +++ b/lib/agg_table.h @@ -23,6 +23,10 @@ #include "prefix.h" #include "table.h" +#ifdef __cplusplus +extern "C" { +#endif + struct agg_table { struct route_table *route_table; @@ -150,4 +154,9 @@ static inline struct agg_table *agg_get_table(struct agg_node *node) { return (struct agg_table *)route_table_get_info(node->table); } + +#ifdef __cplusplus +} +#endif + #endif @@ -26,6 +26,10 @@ #include "lib/json.h" #include "lib/zclient.h" +#ifdef __cplusplus +extern "C" { +#endif + #define BFD_DEF_MIN_RX 300 #define BFD_MIN_MIN_RX 50 #define BFD_MAX_MIN_RX 60000 @@ -104,4 +108,8 @@ extern void bfd_gbl_init(void); extern void bfd_gbl_exit(void); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_BFD_H */ diff --git a/lib/bitfield.h b/lib/bitfield.h index 0e031ccc49..eebfc049d9 100644 --- a/lib/bitfield.h +++ b/lib/bitfield.h @@ -44,6 +44,10 @@ #include <string.h> #include <stdlib.h> +#ifdef __cplusplus +extern "C" { +#endif + typedef unsigned int word_t; #define WORD_MAX 0xFFFFFFFF #define WORD_SIZE (sizeof(word_t) * 8) @@ -153,4 +157,8 @@ typedef unsigned int word_t; } \ } while (0) +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/buffer.h b/lib/buffer.h index 0c945a2acf..8b5a89825f 100644 --- a/lib/buffer.h +++ b/lib/buffer.h @@ -22,6 +22,10 @@ #ifndef _ZEBRA_BUFFER_H #define _ZEBRA_BUFFER_H +#ifdef __cplusplus +extern "C" { +#endif + /* Create a new buffer. Memory will be allocated in chunks of the given size. If the argument is 0, the library will supply a reasonable default size suitable for buffering socket I/O. */ @@ -99,4 +103,8 @@ extern buffer_status_t buffer_flush_all(struct buffer *, int fd); extern buffer_status_t buffer_flush_window(struct buffer *, int fd, int width, int height, int erase, int no_more); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_BUFFER_H */ diff --git a/lib/checksum.h b/lib/checksum.h index c2764e35fb..7d50371439 100644 --- a/lib/checksum.h +++ b/lib/checksum.h @@ -1,4 +1,12 @@ +#ifdef __cplusplus +extern "C" { +#endif + extern int in_cksum(void *, int); #define FLETCHER_CHECKSUM_VALIDATE 0xffff extern uint16_t fletcher_checksum(uint8_t *, const size_t len, const uint16_t offset); + +#ifdef __cplusplus +} +#endif diff --git a/lib/clippy.h b/lib/clippy.h index 8df98cbb8e..be4db6e638 100644 --- a/lib/clippy.h +++ b/lib/clippy.h @@ -22,7 +22,15 @@ #include <Python.h> +#ifdef __cplusplus +extern "C" { +#endif + extern PyObject *clippy_parse(PyObject *self, PyObject *args); extern PyMODINIT_FUNC command_py_init(void); +#ifdef __cplusplus +} +#endif + #endif /* _FRR_CLIPPY_H */ diff --git a/lib/command.c b/lib/command.c index 06879f6854..b46241ac87 100644 --- a/lib/command.c +++ b/lib/command.c @@ -1009,7 +1009,7 @@ enum node_type node_parent(enum node_type node) } /* Execute command by argument vline vector. */ -static int cmd_execute_command_real(vector vline, enum filter_type filter, +static int cmd_execute_command_real(vector vline, enum cmd_filter_type filter, struct vty *vty, const struct cmd_element **cmd) { diff --git a/lib/command.h b/lib/command.h index 11514fd5e8..0faaa426ac 100644 --- a/lib/command.h +++ b/lib/command.h @@ -30,6 +30,10 @@ #include "hash.h" #include "command_graph.h" +#ifdef __cplusplus +extern "C" { +#endif + DECLARE_MTYPE(HOST) DECLARE_MTYPE(COMPLETION) @@ -488,4 +492,9 @@ cmd_variable_handler_register(const struct cmd_variable_handler *cvh); extern char *cmd_variable_comp2str(vector comps, unsigned short cols); extern void command_setup_early_logging(const char *dest, const char *level); + +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_COMMAND_H */ diff --git a/lib/command_graph.h b/lib/command_graph.h index 82d562694c..903d515834 100644 --- a/lib/command_graph.h +++ b/lib/command_graph.h @@ -32,6 +32,10 @@ #include "vector.h" #include "graph.h" +#ifdef __cplusplus +extern "C" { +#endif + DECLARE_MTYPE(CMD_ARG) struct vty; @@ -114,7 +118,7 @@ extern void cmd_token_varname_set(struct cmd_token *token, const char *varname); extern void cmd_graph_parse(struct graph *graph, struct cmd_element *cmd); extern void cmd_graph_names(struct graph *graph); -extern void cmd_graph_merge(struct graph *old, struct graph *new, +extern void cmd_graph_merge(struct graph *old, struct graph *n, int direction); /* * Print callback for DOT dumping. @@ -133,4 +137,8 @@ extern void cmd_graph_node_print_cb(struct graph_node *gn, struct buffer *buf); */ char *cmd_graph_dump_dot(struct graph *cmdgraph); +#ifdef __cplusplus +} +#endif + #endif /* _FRR_COMMAND_GRAPH_H */ diff --git a/lib/command_match.h b/lib/command_match.h index c636d2dd95..fcb333120f 100644 --- a/lib/command_match.h +++ b/lib/command_match.h @@ -28,10 +28,14 @@ #include "linklist.h" #include "command.h" +#ifdef __cplusplus +extern "C" { +#endif + /* These definitions exist in command.c in the current engine but should be * relocated here in the new engine */ -enum filter_type { FILTER_RELAXED, FILTER_STRICT }; +enum cmd_filter_type { FILTER_RELAXED, FILTER_STRICT }; /* matcher result value */ enum matcher_rv { @@ -98,4 +102,8 @@ enum matcher_rv command_match(struct graph *cmdgraph, vector vline, enum matcher_rv command_complete(struct graph *cmdgraph, vector vline, struct list **completions); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_COMMAND_MATCH_H */ diff --git a/lib/compiler.h b/lib/compiler.h index 24b8fafd10..cb4f7531ec 100644 --- a/lib/compiler.h +++ b/lib/compiler.h @@ -17,6 +17,10 @@ #ifndef _FRR_COMPILER_H #define _FRR_COMPILER_H +#ifdef __cplusplus +extern "C" { +#endif + /* function attributes, use like * void prototype(void) __attribute__((_CONSTRUCTOR(100))); */ @@ -88,4 +92,8 @@ #define CPP_NOTICE(text) #endif +#ifdef __cplusplus +} +#endif + #endif /* _FRR_COMPILER_H */ @@ -70,6 +70,10 @@ #include <stdarg.h> #include <sys/queue.h> +#ifdef __cplusplus +extern "C" { +#endif + typedef struct _csv_field_t_ csv_field_t; typedef struct _csv_record_t_ csv_record_t; typedef struct _csv_t_ csv_t; @@ -185,4 +189,8 @@ void csv_clone_record(csv_t *csv, csv_record_t *in_rec, csv_record_t **out_rec); */ int csv_num_records(csv_t *csv); +#ifdef __cplusplus +} +#endif + #endif @@ -38,6 +38,10 @@ #include <sqlite3.h> +#ifdef __cplusplus +extern "C" { +#endif + extern int db_init(const char *path_fmt, ...); extern int db_close(void); extern int db_bindf(struct sqlite3_stmt *ss, const char *fmt, ...); @@ -48,5 +52,9 @@ extern int db_loadf(struct sqlite3_stmt *ss, const char *fmt, ...); extern void db_finalize(struct sqlite3_stmt **ss); extern int db_execute(const char *stmt_fmt, ...); +#ifdef __cplusplus +} +#endif + #endif /* HAVE_SQLITE3 */ #endif /* _FRR_DB_H_ */ diff --git a/lib/debug.h b/lib/debug.h index d0fa27d3fe..ace060d057 100644 --- a/lib/debug.h +++ b/lib/debug.h @@ -24,6 +24,10 @@ #include "command.h" #include "frratomic.h" +#ifdef __cplusplus +extern "C" { +#endif + /* * Debugging modes. * @@ -76,7 +80,7 @@ * Human-readable description of this debugging record. */ struct debug { - _Atomic uint32_t flags; + atomic_uint_fast32_t flags; const char *desc; }; @@ -231,4 +235,8 @@ struct debug_callbacks { */ void debug_init(const struct debug_callbacks *cb); +#ifdef __cplusplus +} +#endif + #endif /* _FRRDEBUG_H */ diff --git a/lib/distribute.h b/lib/distribute.h index 44c699b38a..4016d3b133 100644 --- a/lib/distribute.h +++ b/lib/distribute.h @@ -25,6 +25,10 @@ #include "if.h" #include "filter.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Disctirubte list types. */ enum distribute_type { DISTRIBUTE_V4_IN, @@ -81,4 +85,8 @@ extern enum filter_type distribute_apply_in(struct interface *, extern enum filter_type distribute_apply_out(struct interface *, struct prefix *); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_DISTRIBUTE_H */ diff --git a/lib/event_counter.h b/lib/event_counter.h index de5dbc0665..8ae276ffef 100644 --- a/lib/event_counter.h +++ b/lib/event_counter.h @@ -43,6 +43,10 @@ #ifndef _ZEBRA_EVENT_COUNTER_H #define _ZEBRA_EVENT_COUNTER_H +#ifdef __cplusplus +extern "C" { +#endif + struct event_counter { unsigned long long count; time_t last; @@ -51,4 +55,8 @@ struct event_counter { void event_counter_inc(struct event_counter *counter); const char *event_counter_format(const struct event_counter *counter); +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/ferr.h b/lib/ferr.h index 335875c166..93d0ced538 100644 --- a/lib/ferr.h +++ b/lib/ferr.h @@ -27,6 +27,10 @@ #include "vty.h" +#ifdef __cplusplus +extern "C" { +#endif + /* return type when this error indication stuff is used. * * guaranteed to have boolean evaluation to "false" when OK, "true" when error @@ -253,4 +257,8 @@ DEFUN("bla") #endif /* THIS_IS_AN_EXAMPLE */ +#ifdef __cplusplus +} +#endif + #endif /* _FERR_H */ diff --git a/lib/fifo.h b/lib/fifo.h index f59e4dc6cd..6f9c59b5c1 100644 --- a/lib/fifo.h +++ b/lib/fifo.h @@ -20,6 +20,10 @@ #ifndef __LIB_FIFO_H__ #define __LIB_FIFO_H__ +#ifdef __cplusplus +extern "C" { +#endif + /* FIFO -- first in first out structure and macros. */ struct fifo { struct fifo *next; @@ -55,4 +59,8 @@ struct fifo { #define FIFO_TOP(F) (FIFO_EMPTY(F) ? NULL : ((struct fifo *)(F))->next) +#ifdef __cplusplus +} +#endif + #endif /* __LIB_FIFO_H__ */ diff --git a/lib/filter.h b/lib/filter.h index 97854b1e97..3dd2eaaf15 100644 --- a/lib/filter.h +++ b/lib/filter.h @@ -24,6 +24,10 @@ #include "if.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Maximum ACL name length */ #define ACL_NAMSIZ 128 @@ -62,4 +66,8 @@ extern struct access_list *access_list_lookup(afi_t, const char *); extern enum filter_type access_list_apply(struct access_list *access, const void *object); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_FILTER_H */ diff --git a/lib/freebsd-queue.h b/lib/freebsd-queue.h index 4fcfe85a68..793cfff8d3 100644 --- a/lib/freebsd-queue.h +++ b/lib/freebsd-queue.h @@ -33,6 +33,10 @@ #ifndef _SYS_QUEUE_H_ #define _SYS_QUEUE_H_ +#ifdef __cplusplus +extern "C" { +#endif + /* * This file defines four types of data structures: singly-linked lists, * singly-linked tail queues, lists and tail queues. @@ -675,4 +679,8 @@ struct qm_trace { (head2)->tqh_last = &(head2)->tqh_first; \ } while (0) +#ifdef __cplusplus +} +#endif + #endif /* !_SYS_QUEUE_H_ */ diff --git a/lib/frr_pthread.c b/lib/frr_pthread.c index fe18eb1051..d7f655271b 100644 --- a/lib/frr_pthread.c +++ b/lib/frr_pthread.c @@ -83,9 +83,9 @@ struct frr_pthread *frr_pthread_new(struct frr_pthread_attr *attr, name = (name ? name : "Anonymous thread"); fpt->name = XSTRDUP(MTYPE_FRR_PTHREAD, name); if (os_name) - snprintf(fpt->os_name, OS_THREAD_NAMELEN, "%s", os_name); + strlcpy(fpt->os_name, os_name, OS_THREAD_NAMELEN); else - snprintf(fpt->os_name, OS_THREAD_NAMELEN, "%s", name); + strlcpy(fpt->os_name, name, OS_THREAD_NAMELEN); /* initialize startup synchronization primitives */ fpt->running_cond_mtx = XCALLOC( MTYPE_PTHREAD_PRIM, sizeof(pthread_mutex_t)); diff --git a/lib/frr_pthread.h b/lib/frr_pthread.h index e6b3f031b3..9bc7b94033 100644 --- a/lib/frr_pthread.h +++ b/lib/frr_pthread.h @@ -25,6 +25,10 @@ #include "memory.h" #include "thread.h" +#ifdef __cplusplus +extern "C" { +#endif + DECLARE_MTYPE(FRR_PTHREAD); DECLARE_MTYPE(PTHREAD_PRIM); @@ -73,7 +77,7 @@ struct frr_pthread { */ pthread_cond_t *running_cond; pthread_mutex_t *running_cond_mtx; - _Atomic bool running; + atomic_bool running; /* * Fake thread-specific storage. No constraints on usage. Helpful when @@ -211,4 +215,8 @@ void frr_pthread_stop_all(void); #define pthread_condattr_setclock(A, B) #endif +#ifdef __cplusplus +} +#endif + #endif /* _FRR_PTHREAD_H */ diff --git a/lib/frr_zmq.h b/lib/frr_zmq.h index 1146b87964..4303df9ccd 100644 --- a/lib/frr_zmq.h +++ b/lib/frr_zmq.h @@ -23,6 +23,10 @@ #include "thread.h" #include <zmq.h> +#ifdef __cplusplus +extern "C" { +#endif + /* linking/packaging note: this is a separate library that needs to be * linked into any daemon/library/module that wishes to use its * functionality. The purpose of this is to encapsulate the libzmq @@ -124,4 +128,8 @@ extern void frrzmq_thread_cancel(struct frrzmq_cb **cb, struct cb_core *core); extern void frrzmq_check_events(struct frrzmq_cb **cbp, struct cb_core *core, int event); +#ifdef __cplusplus +} +#endif + #endif /* _FRRZMQ_H */ diff --git a/lib/frratomic.h b/lib/frratomic.h index 1f1d1b569a..e86030f83c 100644 --- a/lib/frratomic.h +++ b/lib/frratomic.h @@ -26,7 +26,23 @@ #endif /* ISO C11 */ -#ifdef HAVE_STDATOMIC_H +#ifdef __cplusplus +#include <stdint.h> +#include <atomic> +using std::atomic_int; +using std::memory_order; +using std::memory_order_relaxed; +using std::memory_order_acquire; +using std::memory_order_release; +using std::memory_order_acq_rel; +using std::memory_order_consume; +using std::memory_order_seq_cst; + +typedef std::atomic<bool> atomic_bool; +typedef std::atomic<size_t> atomic_size_t; +typedef std::atomic<uint_fast32_t> atomic_uint_fast32_t; + +#elif defined(HAVE_STDATOMIC_H) #include <stdatomic.h> /* These are available in gcc, but not in stdatomic */ @@ -39,6 +55,7 @@ #elif defined(HAVE___ATOMIC) #define _Atomic volatile +#define _ATOMIC_WANT_TYPEDEFS #define memory_order_relaxed __ATOMIC_RELAXED #define memory_order_consume __ATOMIC_CONSUME @@ -74,6 +91,7 @@ #elif defined(HAVE___SYNC) #define _Atomic volatile +#define _ATOMIC_WANT_TYPEDEFS #define memory_order_relaxed 0 #define memory_order_consume 0 @@ -198,4 +216,15 @@ #error no atomic functions... #endif +#ifdef _ATOMIC_WANT_TYPEDEFS +#undef _ATOMIC_WANT_TYPEDEFS + +#include <stdint.h> +#include <stdbool.h> + +typedef _Atomic bool atomic_bool; +typedef _Atomic size_t atomic_size_t; +typedef _Atomic uint_fast32_t atomic_uint_fast32_t; +#endif + #endif /* _FRRATOMIC_H */ diff --git a/lib/frrstr.h b/lib/frrstr.h index 891a3f337c..8b591849a3 100644 --- a/lib/frrstr.h +++ b/lib/frrstr.h @@ -27,6 +27,10 @@ #include "vector.h" +#ifdef __cplusplus +extern "C" { +#endif + /* * Tokenizes a string, storing tokens in a vector. Whitespace is ignored. * Delimiter characters are not included. @@ -108,4 +112,8 @@ bool begins_with(const char *str, const char *prefix); */ int all_digit(const char *str); +#ifdef __cplusplus +} +#endif + #endif /* _FRRSTR_H_ */ diff --git a/lib/graph.h b/lib/graph.h index 87262a07b8..8e126e6be4 100644 --- a/lib/graph.h +++ b/lib/graph.h @@ -28,6 +28,10 @@ #include "vector.h" #include "buffer.h" +#ifdef __cplusplus +extern "C" { +#endif + struct graph { vector nodes; }; @@ -164,4 +168,9 @@ char *graph_dump_dot(struct graph *graph, struct graph_node *start, void (*pcb)(struct graph_node *, struct buffer *buf)); #endif /* BUILDING_CLIPPY */ + +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_COMMAND_GRAPH_H */ diff --git a/lib/hash.h b/lib/hash.h index 45ae6ce60a..8c695d2381 100644 --- a/lib/hash.h +++ b/lib/hash.h @@ -24,6 +24,10 @@ #include "memory.h" #include "frratomic.h" +#ifdef __cplusplus +extern "C" { +#endif + DECLARE_MTYPE(HASH) DECLARE_MTYPE(HASH_BACKET) @@ -54,9 +58,9 @@ struct hash_backet { struct hashstats { /* number of empty hash buckets */ - _Atomic uint_fast32_t empty; + atomic_uint_fast32_t empty; /* sum of squares of bucket length */ - _Atomic uint_fast32_t ssq; + atomic_uint_fast32_t ssq; }; struct hash { @@ -325,4 +329,8 @@ extern unsigned int string_hash_make(const char *); */ extern void hash_cmd_init(void); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_HASH_H */ diff --git a/lib/hook.h b/lib/hook.h index 96fec97d7e..f7fb7b8a5c 100644 --- a/lib/hook.h +++ b/lib/hook.h @@ -22,6 +22,10 @@ #include "module.h" #include "memory.h" +#ifdef __cplusplus +extern "C" { +#endif + /* type-safe subscribable hook points * * where "type-safe" applies to the function pointers used for subscriptions @@ -219,4 +223,8 @@ extern void _hook_unregister(struct hook *hook, void *funcptr, void *arg, #define DEFINE_KOOH(hookname, arglist, passlist) \ DEFINE_HOOK_INT(hookname, arglist, passlist, true) +#ifdef __cplusplus +} +#endif + #endif /* _FRR_HOOK_H */ diff --git a/lib/id_alloc.h b/lib/id_alloc.h index efe355658a..8705ffb37d 100644 --- a/lib/id_alloc.h +++ b/lib/id_alloc.h @@ -24,6 +24,10 @@ #include <limits.h> #include <stdint.h> +#ifdef __cplusplus +extern "C" { +#endif + #define IDALLOC_INVALID 0 #define IDALLOC_DIR_BITS 8 @@ -87,4 +91,8 @@ uint32_t idalloc_reserve(struct id_alloc *alloc, uint32_t id); struct id_alloc *idalloc_new(const char *name); void idalloc_destroy(struct id_alloc *alloc); +#ifdef __cplusplus +} +#endif + #endif @@ -1160,7 +1160,7 @@ DEFPY (no_interface, if (!vrfname) vrfname = VRF_DEFAULT_NAME; - nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); return nb_cli_apply_changes( vty, "/frr-interface:lib/interface[name='%s'][vrf='%s']", @@ -1207,7 +1207,7 @@ DEFPY (no_interface_desc, NO_STR "Interface specific description\n") { - nb_cli_enqueue_change(vty, "./description", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, "./description", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); } @@ -1379,13 +1379,13 @@ const struct frr_yang_module_info frr_interface_info = { { .xpath = "/frr-interface:lib/interface", .cbs.create = lib_interface_create, - .cbs.delete = lib_interface_delete, + .cbs.destroy = lib_interface_delete, .cbs.cli_show = cli_show_interface, }, { .xpath = "/frr-interface:lib/interface/description", .cbs.modify = lib_interface_description_modify, - .cbs.delete = lib_interface_description_delete, + .cbs.destroy = lib_interface_description_delete, .cbs.cli_show = cli_show_interface_desc, }, { @@ -27,6 +27,10 @@ #include "qobj.h" #include "hook.h" +#ifdef __cplusplus +extern "C" { +#endif + DECLARE_MTYPE(IF) DECLARE_MTYPE(CONNECTED_LABEL) @@ -290,9 +294,9 @@ struct interface { }; RB_HEAD(if_name_head, interface); -RB_PROTOTYPE(if_name_head, interface, name_entry, if_cmp_func); +RB_PROTOTYPE(if_name_head, interface, name_entry, if_cmp_func) RB_HEAD(if_index_head, interface); -RB_PROTOTYPE(if_index_head, interface, index_entry, if_cmp_func); +RB_PROTOTYPE(if_index_head, interface, index_entry, if_cmp_func) DECLARE_QOBJ_TYPE(interface) #define IFNAME_RB_INSERT(vrf, ifp) \ @@ -545,4 +549,8 @@ void if_link_params_free(struct interface *); extern void if_cmd_init(void); extern const struct frr_yang_module_info frr_interface_info; +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_IF_H */ diff --git a/lib/if_rmap.h b/lib/if_rmap.h index 4468b9fb9c..8dded2cb48 100644 --- a/lib/if_rmap.h +++ b/lib/if_rmap.h @@ -21,6 +21,10 @@ #ifndef _ZEBRA_IF_RMAP_H #define _ZEBRA_IF_RMAP_H +#ifdef __cplusplus +extern "C" { +#endif + enum if_rmap_type { IF_RMAP_IN, IF_RMAP_OUT, IF_RMAP_MAX }; struct if_rmap { @@ -37,4 +41,8 @@ extern void if_rmap_hook_delete(void (*)(struct if_rmap *)); extern struct if_rmap *if_rmap_lookup(const char *); extern int config_write_if_rmap(struct vty *); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_IF_RMAP_H */ diff --git a/lib/imsg.h b/lib/imsg.h index eed7074e4a..3f81b76bea 100644 --- a/lib/imsg.h +++ b/lib/imsg.h @@ -21,6 +21,10 @@ #ifndef _IMSG_H_ #define _IMSG_H_ +#ifdef __cplusplus +extern "C" { +#endif + #define IBUF_READ_SIZE 65535 #define IMSG_HEADER_SIZE sizeof(struct imsg_hdr) #define MAX_IMSGSIZE 16384 @@ -108,4 +112,8 @@ void imsg_free(struct imsg *); int imsg_flush(struct imsgbuf *); void imsg_clear(struct imsgbuf *); +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/ipaddr.h b/lib/ipaddr.h index 7f2d06548b..f4ddadc66e 100644 --- a/lib/ipaddr.h +++ b/lib/ipaddr.h @@ -25,6 +25,10 @@ #include <zebra.h> +#ifdef __cplusplus +extern "C" { +#endif + /* * Generic IP address - union of IPv4 and IPv6 address. */ @@ -112,4 +116,8 @@ static inline void ipv4_mapped_ipv6_to_ipv4(struct in6_addr *in6, memcpy(in, (char *)in6 + 12, sizeof(struct in_addr)); } +#ifdef __cplusplus +} +#endif + #endif /* __IPADDR_H__ */ diff --git a/lib/jhash.h b/lib/jhash.h index f8ab4209a8..977421495c 100644 --- a/lib/jhash.h +++ b/lib/jhash.h @@ -20,6 +20,10 @@ #ifndef _QUAGGA_JHASH_H #define _QUAGGA_JHASH_H +#ifdef __cplusplus +extern "C" { +#endif + /* The most generic version, hashes an arbitrary sequence * of bytes. No alignment or length assumptions are made about * the input key. @@ -42,4 +46,8 @@ extern uint32_t jhash_3words(uint32_t a, uint32_t b, uint32_t c, extern uint32_t jhash_2words(uint32_t a, uint32_t b, uint32_t initval); extern uint32_t jhash_1word(uint32_t a, uint32_t initval); +#ifdef __cplusplus +} +#endif + #endif /* _QUAGGA_JHASH_H */ diff --git a/lib/json.h b/lib/json.h index d349162304..a5251662be 100644 --- a/lib/json.h +++ b/lib/json.h @@ -21,6 +21,10 @@ #ifndef _QUAGGA_JSON_H #define _QUAGGA_JSON_H +#ifdef __cplusplus +extern "C" { +#endif + #if defined(HAVE_JSON_C_JSON_H) #include <json-c/json.h> @@ -81,4 +85,8 @@ extern void json_object_free(struct json_object *obj); #define JSON_C_TO_STRING_NOSLASHESCAPE (1<<4) #endif +#ifdef __cplusplus +} +#endif + #endif /* _QUAGGA_JSON_H */ diff --git a/lib/keychain.h b/lib/keychain.h index 49da9ba459..e5cf39f7c6 100644 --- a/lib/keychain.h +++ b/lib/keychain.h @@ -23,6 +23,10 @@ #include "qobj.h" +#ifdef __cplusplus +extern "C" { +#endif + struct keychain { char *name; @@ -57,4 +61,8 @@ extern struct key *key_lookup_for_accept(const struct keychain *, uint32_t); extern struct key *key_match_for_accept(const struct keychain *, const char *); extern struct key *key_lookup_for_send(const struct keychain *); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_KEYCHAIN_H */ diff --git a/lib/lib_errors.h b/lib/lib_errors.h index 86a83df46c..fc405c2098 100644 --- a/lib/lib_errors.h +++ b/lib/lib_errors.h @@ -23,6 +23,10 @@ #include "lib/ferr.h" +#ifdef __cplusplus +extern "C" { +#endif + enum lib_log_refs { EC_LIB_PRIVILEGES = LIB_FERR_START, EC_LIB_VRF_START, @@ -82,4 +86,8 @@ enum lib_log_refs { extern void lib_error_init(void); +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/libfrr.h b/lib/libfrr.h index 2705397b85..891e2c1282 100644 --- a/lib/libfrr.h +++ b/lib/libfrr.h @@ -30,6 +30,10 @@ #include "hook.h" #include "northbound.h" +#ifdef __cplusplus +extern "C" { +#endif + /* The following options disable specific command line options that * are not applicable for a particular daemon. */ @@ -152,4 +156,8 @@ extern char frr_protonameinst[]; extern bool debug_memstats_at_exit; +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_FRR_H */ diff --git a/lib/libospf.h b/lib/libospf.h index 45aedb6a7d..d2bb29d80e 100644 --- a/lib/libospf.h +++ b/lib/libospf.h @@ -22,6 +22,10 @@ #ifndef _LIBOSPFD_H #define _LIBOSPFD_H +#ifdef __cplusplus +extern "C" { +#endif + /* IP precedence. */ #ifndef IPTOS_PREC_INTERNETCONTROL #define IPTOS_PREC_INTERNETCONTROL 0xC0 @@ -94,4 +98,8 @@ #define OSPF_LSA_MAXAGE_CHECK_INTERVAL 30 #define OSPF_LSA_MAXAGE_REMOVE_DELAY_DEFAULT 60 +#ifdef __cplusplus +} +#endif + #endif /* _LIBOSPFD_H */ diff --git a/lib/linklist.h b/lib/linklist.h index 0475391e9f..76fad45d08 100644 --- a/lib/linklist.h +++ b/lib/linklist.h @@ -21,6 +21,10 @@ #ifndef _ZEBRA_LINKLIST_H #define _ZEBRA_LINKLIST_H +#ifdef __cplusplus +extern "C" { +#endif + /* listnodes must always contain data to be valid. Adding an empty node * to a list is invalid */ @@ -291,7 +295,8 @@ extern void list_add_list(struct list *list, struct list *add); #define ALL_LIST_ELEMENTS(list, node, nextnode, data) \ (node) = listhead(list), ((data) = NULL); \ (node) != NULL \ - && ((data) = listgetdata(node), (nextnode) = node->next, 1); \ + && ((data) = static_cast(data, listgetdata(node)), \ + (nextnode) = node->next, 1); \ (node) = (nextnode), ((data) = NULL) /* read-only list iteration macro. @@ -302,7 +307,7 @@ extern void list_add_list(struct list *list, struct list *add); */ #define ALL_LIST_ELEMENTS_RO(list, node, data) \ (node) = listhead(list), ((data) = NULL); \ - (node) != NULL && ((data) = listgetdata(node), 1); \ + (node) != NULL && ((data) = static_cast(data, listgetdata(node)), 1); \ (node) = listnextnode(node), ((data) = NULL) /* these *do not* cleanup list nodes and referenced data, as the functions @@ -336,4 +341,8 @@ extern void list_add_list(struct list *list, struct list *add); (L)->count--; \ } while (0) +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_LINKLIST_H */ @@ -29,6 +29,7 @@ #include "memory.h" #include "command.h" #include "lib_errors.h" +#include "lib/hook.h" #ifndef SUNOS_5 #include <sys/un.h> @@ -46,6 +47,10 @@ DEFINE_MTYPE_STATIC(LIB, ZLOG, "Logging") +/* hook for external logging */ +DEFINE_HOOK(zebra_ext_log, (int priority, const char *format, va_list args), + (priority, format, args)); + static int logfile_fd = -1; /* Used in signal handler. */ struct zlog *zlog_default = NULL; @@ -213,6 +218,9 @@ void vzlog(int priority, const char *format, va_list args) tsctl.already_rendered = 0; struct zlog *zl = zlog_default; + /* call external hook */ + hook_call(zebra_ext_log, priority, format, args); + /* When zlog_default is also NULL, use stderr for logging. */ if (zl == NULL) { tsctl.precision = 0; @@ -1019,6 +1027,7 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_RELEASE_LABEL_CHUNK), DESC_ENTRY(ZEBRA_ADVERTISE_ALL_VNI), DESC_ENTRY(ZEBRA_ADVERTISE_DEFAULT_GW), + DESC_ENTRY(ZEBRA_ADVERTISE_SVI_MACIP), DESC_ENTRY(ZEBRA_ADVERTISE_SUBNET), DESC_ENTRY(ZEBRA_LOCAL_ES_ADD), DESC_ENTRY(ZEBRA_LOCAL_ES_DEL), @@ -26,6 +26,16 @@ #include <stdint.h> #include <stdbool.h> #include <stdio.h> +#include <stdarg.h> +#include "lib/hook.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Hook for external logging function */ +DECLARE_HOOK(zebra_ext_log, (int priority, const char *format, va_list args), + (priority, format, args)); /* Here is some guidance on logging levels to use: * @@ -87,11 +97,11 @@ extern void zlog_debug(const char *format, ...) PRINTF_ATTRIBUTE(1, 2); /* For logs which have error codes associated with them */ #define flog_err(ferr_id, format, ...) \ - zlog_err("[EC %"PRIu32"] " format, ferr_id, ##__VA_ARGS__) + zlog_err("[EC %" PRIu32 "] " format, ferr_id, ##__VA_ARGS__) #define flog_err_sys(ferr_id, format, ...) \ flog_err(ferr_id, format, ##__VA_ARGS__) #define flog_warn(ferr_id, format, ...) \ - zlog_warn("[EC %"PRIu32"] " format, ferr_id, ##__VA_ARGS__) + zlog_warn("[EC %" PRIu32 "] " format, ferr_id, ##__VA_ARGS__) extern void zlog_thread_info(int log_level); @@ -190,4 +200,8 @@ struct timestamp_control { "Local use\n" \ "Local use\n" +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_LOG_H */ diff --git a/lib/log_int.h b/lib/log_int.h index a7f8be9ae7..58ae031e1b 100644 --- a/lib/log_int.h +++ b/lib/log_int.h @@ -24,6 +24,10 @@ #include "log.h" +#ifdef __cplusplus +extern "C" { +#endif + struct zlog { const char *ident; /* daemon name (first arg to openlog) */ const char *protoname; @@ -49,4 +53,8 @@ extern const char *zlog_priority[]; extern void vzlog(int priority, const char *format, va_list args); extern void zlog(int priority, const char *format, ...) PRINTF_ATTRIBUTE(2, 3); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_LOG_PRIVATE_H */ diff --git a/lib/logicalrouter.h b/lib/logicalrouter.h index 5a0780c009..d18832ef70 100644 --- a/lib/logicalrouter.h +++ b/lib/logicalrouter.h @@ -20,6 +20,10 @@ #ifndef _ZEBRA_LOGICAL_ROUTER_H #define _ZEBRA_LOGICAL_ROUTER_H +#ifdef __cplusplus +extern "C" { +#endif + /* Logical Router Backend defines */ #define LOGICALROUTER_BACKEND_OFF 0 #define LOGICALROUTER_BACKEND_NETNS 1 @@ -38,4 +42,8 @@ extern void logicalrouter_terminate(void); */ extern void logicalrouter_configure_backend(int backend_netns); +#ifdef __cplusplus +} +#endif + #endif /*_ZEBRA_LOGICAL_ROUTER_H*/ @@ -29,6 +29,10 @@ #include <lualib.h> #include <lauxlib.h> +#ifdef __cplusplus +extern "C" { +#endif + /* * These functions are helper functions that * try to glom some of the lua_XXX functionality @@ -75,5 +79,10 @@ enum lua_rm_status lua_run_rm_rule(lua_State *L, const char *rule); */ const char *get_string(lua_State *L, const char *key); int get_integer(lua_State *L, const char *key); + +#ifdef __cplusplus +} +#endif + #endif #endif @@ -38,6 +38,10 @@ #ifndef _LIBZEBRA_MD5_H_ #define _LIBZEBRA_MD5_H_ +#ifdef __cplusplus +extern "C" { +#endif + #define MD5_BUFLEN 64 typedef struct { @@ -82,4 +86,8 @@ extern void md5_result(uint8_t *, md5_ctxt *); void hmac_md5(unsigned char *text, int text_len, unsigned char *key, int key_len, uint8_t *digest); +#ifdef __cplusplus +} +#endif + #endif /* ! _LIBZEBRA_MD5_H_*/ diff --git a/lib/memory.c b/lib/memory.c index fee23a75ac..149e294d50 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -35,7 +35,6 @@ struct memgroup **mg_insert = &mg_first; DEFINE_MGROUP(LIB, "libfrr") DEFINE_MTYPE(LIB, TMP, "Temporary memory") -DEFINE_MTYPE(LIB, PREFIX_FLOWSPEC, "Prefix Flowspec") static inline void mt_count_alloc(struct memtype *mt, size_t size, void *ptr) { diff --git a/lib/memory.h b/lib/memory.h index 2d6c144778..91a02b7966 100644 --- a/lib/memory.h +++ b/lib/memory.h @@ -22,6 +22,10 @@ #include <frratomic.h> #include "compiler.h" +#ifdef __cplusplus +extern "C" { +#endif + #define array_size(ar) (sizeof(ar) / sizeof(ar[0])) #if defined(HAVE_MALLOC_SIZE) && !defined(HAVE_MALLOC_USABLE_SIZE) @@ -33,12 +37,12 @@ struct memtype { struct memtype *next, **ref; const char *name; - _Atomic size_t n_alloc; - _Atomic size_t n_max; - _Atomic size_t size; + atomic_size_t n_alloc; + atomic_size_t n_max; + atomic_size_t size; #ifdef HAVE_MALLOC_USABLE_SIZE - _Atomic size_t total; - _Atomic size_t max_size; + atomic_size_t total; + atomic_size_t max_size; #endif }; @@ -137,7 +141,6 @@ struct memgroup { DECLARE_MGROUP(LIB) DECLARE_MTYPE(TMP) -DECLARE_MTYPE(PREFIX_FLOWSPEC) extern void *qmalloc(struct memtype *mt, size_t size) @@ -177,4 +180,8 @@ extern int log_memstats(FILE *fp, const char *); extern void memory_oom(size_t size, const char *name); +#ifdef __cplusplus +} +#endif + #endif /* _QUAGGA_MEMORY_H */ diff --git a/lib/memory_vty.h b/lib/memory_vty.h index b66c3b6d6e..941255be1d 100644 --- a/lib/memory_vty.h +++ b/lib/memory_vty.h @@ -23,9 +23,18 @@ #include "memory.h" +#ifdef __cplusplus +extern "C" { +#endif + extern void memory_init(void); /* Human friendly string for given byte count */ #define MTYPE_MEMSTR_LEN 20 extern const char *mtype_memstr(char *, size_t, unsigned long); + +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_MEMORY_VTY_H */ diff --git a/lib/mlag.h b/lib/mlag.h index 73725ca3fd..2b904d44f4 100644 --- a/lib/mlag.h +++ b/lib/mlag.h @@ -22,6 +22,10 @@ #ifndef __MLAG_H__ #define __MLAG_H__ +#ifdef __cplusplus +extern "C" { +#endif + enum mlag_role { MLAG_ROLE_NONE, MLAG_ROLE_PRIMARY, @@ -29,4 +33,9 @@ enum mlag_role { }; extern char *mlag_role2str(enum mlag_role role, char *buf, size_t size); + +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/module.h b/lib/module.h index 68ed959270..c5f96db85b 100644 --- a/lib/module.h +++ b/lib/module.h @@ -20,6 +20,10 @@ #include <stdint.h> #include <stdbool.h> +#ifdef __cplusplus +extern "C" { +#endif + #if !defined(__GNUC__) #error module code needs GCC visibility extensions #elif __GNUC__ < 4 @@ -78,9 +82,10 @@ extern union _frrmod_runtime_u _frrmod_this_module; #define FRR_COREMOD_SETUP(...) \ static const struct frrmod_info _frrmod_info = {__VA_ARGS__}; \ - DSO_LOCAL union _frrmod_runtime_u _frrmod_this_module = { \ - .r.info = &_frrmod_info, \ - }; + DSO_LOCAL union _frrmod_runtime_u _frrmod_this_module = {{ \ + NULL, \ + &_frrmod_info, \ + }}; #define FRR_MODULE_SETUP(...) \ FRR_COREMOD_SETUP(__VA_ARGS__) \ DSO_SELF struct frrmod_runtime *frr_module = &_frrmod_this_module.r; @@ -95,4 +100,8 @@ extern struct frrmod_runtime *frrmod_load(const char *spec, const char *dir, extern void frrmod_unload(struct frrmod_runtime *module); #endif +#ifdef __cplusplus +} +#endif + #endif /* _FRR_MODULE_H */ diff --git a/lib/monotime.h b/lib/monotime.h index 00b9400462..6aac966ea1 100644 --- a/lib/monotime.h +++ b/lib/monotime.h @@ -21,6 +21,10 @@ #include <time.h> #include <sys/time.h> +#ifdef __cplusplus +extern "C" { +#endif + #ifndef TIMESPEC_TO_TIMEVAL /* should be in sys/time.h on BSD & Linux libcs */ #define TIMESPEC_TO_TIMEVAL(tv, ts) \ @@ -91,4 +95,8 @@ static inline char *time_to_string(time_t ts) return ctime(&tbuf); } +#ifdef __cplusplus +} +#endif + #endif /* _FRR_MONOTIME_H */ diff --git a/lib/mpls.h b/lib/mpls.h index 6146985610..b140c8e317 100644 --- a/lib/mpls.h +++ b/lib/mpls.h @@ -25,6 +25,10 @@ #include <zebra.h> #include <arpa/inet.h> +#ifdef __cplusplus +extern "C" { +#endif + #ifdef MPLS_LABEL_MAX #undef MPLS_LABEL_MAX #endif @@ -209,4 +213,8 @@ int mpls_str2label(const char *label_str, uint8_t *num_labels, char *mpls_label2str(uint8_t num_labels, mpls_label_t *labels, char *buf, int len, int pretty); +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/network.h b/lib/network.h index 4703dc9b63..a00c5a0a65 100644 --- a/lib/network.h +++ b/lib/network.h @@ -22,6 +22,10 @@ #ifndef _ZEBRA_NETWORK_H #define _ZEBRA_NETWORK_H +#ifdef __cplusplus +extern "C" { +#endif + /* Both readn and writen are deprecated and will be removed. They are not suitable for use with non-blocking file descriptors. */ @@ -41,4 +45,8 @@ extern int set_cloexec(int fd); extern float htonf(float); extern float ntohf(float); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_NETWORK_H */ diff --git a/lib/nexthop.h b/lib/nexthop.h index e4af405d5f..c79ec590a8 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -26,6 +26,10 @@ #include "prefix.h" #include "mpls.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Maximum next hop string length - gateway + ifindex */ #define NEXTHOP_STRLEN (INET6_ADDRSTRLEN + 30) @@ -146,4 +150,9 @@ extern int nexthop_same_firsthop(struct nexthop *next1, struct nexthop *next2); extern const char *nexthop2str(const struct nexthop *nexthop, char *str, int size); extern struct nexthop *nexthop_next(struct nexthop *nexthop); extern unsigned int nexthop_level(struct nexthop *nexthop); + +#ifdef __cplusplus +} +#endif + #endif /*_LIB_NEXTHOP_H */ diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h index 473ecb34fc..b14cbb5b5c 100644 --- a/lib/nexthop_group.h +++ b/lib/nexthop_group.h @@ -23,6 +23,10 @@ #include <vty.h> +#ifdef __cplusplus +extern "C" { +#endif + /* * What is a nexthop group? * @@ -92,12 +96,12 @@ DECLARE_QOBJ_TYPE(nexthop_group_cmd) * code */ void nexthop_group_init( - void (*new)(const char *name), + void (*create)(const char *name), void (*add_nexthop)(const struct nexthop_group_cmd *nhgc, const struct nexthop *nhop), void (*del_nexthop)(const struct nexthop_group_cmd *nhgc, const struct nexthop *nhop), - void (*delete)(const char *name)); + void (*destroy)(const char *name)); void nexthop_group_enable_vrf(struct vrf *vrf); void nexthop_group_disable_vrf(struct vrf *vrf); @@ -110,4 +114,9 @@ extern struct nexthop *nexthop_exists(struct nexthop_group *nhg, extern struct nexthop_group_cmd *nhgc_find(const char *name); extern void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh); + +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/northbound.c b/lib/northbound.c index 6fe612d72a..15139aa8d0 100644 --- a/lib/northbound.c +++ b/lib/northbound.c @@ -184,8 +184,8 @@ static unsigned int nb_node_validate_cbs(const struct nb_node *nb_node) !!nb_node->cbs.create, false); error += nb_node_validate_cb(nb_node, NB_OP_MODIFY, !!nb_node->cbs.modify, false); - error += nb_node_validate_cb(nb_node, NB_OP_DELETE, - !!nb_node->cbs.delete, false); + error += nb_node_validate_cb(nb_node, NB_OP_DESTROY, + !!nb_node->cbs.destroy, false); error += nb_node_validate_cb(nb_node, NB_OP_MOVE, !!nb_node->cbs.move, false); error += nb_node_validate_cb(nb_node, NB_OP_APPLY_FINISH, @@ -417,7 +417,7 @@ static void nb_config_diff(const struct nb_config *config1, break; case LYD_DIFF_DELETED: dnode = diff->first[i]; - operation = NB_OP_DELETE; + operation = NB_OP_DESTROY; break; case LYD_DIFF_CHANGED: dnode = diff->second[i]; @@ -485,7 +485,7 @@ int nb_candidate_edit(struct nb_config *candidate, lyd_validate(&dnode, LYD_OPT_CONFIG, ly_native_ctx); } break; - case NB_OP_DELETE: + case NB_OP_DESTROY: dnode = yang_dnode_get(candidate->dnode, xpath_edit); if (!dnode) /* @@ -741,8 +741,8 @@ static int nb_configuration_callback(const enum nb_event event, case NB_OP_MODIFY: ret = (*nb_node->cbs.modify)(event, dnode, resource); break; - case NB_OP_DELETE: - ret = (*nb_node->cbs.delete)(event, dnode); + case NB_OP_DESTROY: + ret = (*nb_node->cbs.destroy)(event, dnode); break; case NB_OP_MOVE: ret = (*nb_node->cbs.move)(event, dnode); @@ -912,7 +912,7 @@ static void nb_transaction_apply_finish(struct nb_transaction *transaction) * (the 'apply_finish' callbacks from the node ancestors should * be called though). */ - if (change->cb.operation == NB_OP_DELETE) { + if (change->cb.operation == NB_OP_DESTROY) { char xpath[XPATH_MAXLEN]; dnode = dnode->parent; @@ -1359,7 +1359,7 @@ bool nb_operation_is_valid(enum nb_operation operation, return false; } return true; - case NB_OP_DELETE: + case NB_OP_DESTROY: if (!CHECK_FLAG(snode->flags, LYS_CONFIG_W)) return false; @@ -1511,8 +1511,8 @@ const char *nb_operation_name(enum nb_operation operation) return "create"; case NB_OP_MODIFY: return "modify"; - case NB_OP_DELETE: - return "delete"; + case NB_OP_DESTROY: + return "destroy"; case NB_OP_MOVE: return "move"; case NB_OP_APPLY_FINISH: diff --git a/lib/northbound.h b/lib/northbound.h index 9d35a4e64a..bb6b62af7d 100644 --- a/lib/northbound.h +++ b/lib/northbound.h @@ -27,6 +27,10 @@ #include "yang.h" #include "yang_translator.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Forward declaration(s). */ struct vty; @@ -65,7 +69,7 @@ enum nb_event { enum nb_operation { NB_OP_CREATE, NB_OP_MODIFY, - NB_OP_DELETE, + NB_OP_DESTROY, NB_OP_MOVE, NB_OP_APPLY_FINISH, NB_OP_GET_ELEM, @@ -168,7 +172,7 @@ struct nb_callbacks { * - NB_ERR_INCONSISTENCY when an inconsistency was detected. * - NB_ERR for other errors. */ - int (*delete)(enum nb_event event, const struct lyd_node *dnode); + int (*destroy)(enum nb_event event, const struct lyd_node *dnode); /* * Configuration callback. @@ -839,4 +843,8 @@ extern void nb_init(struct thread_master *tm, const struct frr_yang_module_info */ extern void nb_terminate(void); +#ifdef __cplusplus +} +#endif + #endif /* _FRR_NORTHBOUND_H_ */ diff --git a/lib/northbound_cli.h b/lib/northbound_cli.h index 884f250941..209239ca63 100644 --- a/lib/northbound_cli.h +++ b/lib/northbound_cli.h @@ -22,6 +22,10 @@ #include "northbound.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Possible formats in which a configuration can be displayed. */ enum nb_cfg_format { NB_CFG_FMT_CMDS = 0, @@ -111,4 +115,8 @@ extern void nb_cli_install_default(int node); extern void nb_cli_init(struct thread_master *tm); extern void nb_cli_terminate(void); +#ifdef __cplusplus +} +#endif + #endif /* _FRR_NORTHBOUND_CLI_H_ */ diff --git a/lib/northbound_confd.c b/lib/northbound_confd.c index 53149d0fd2..a8e0017819 100644 --- a/lib/northbound_confd.c +++ b/lib/northbound_confd.c @@ -228,7 +228,7 @@ frr_confd_cdb_diff_iter(confd_hkeypath_t *kp, enum cdb_iter_op cdb_op, nb_op = NB_OP_CREATE; break; case MOP_DELETED: - nb_op = NB_OP_DELETE; + nb_op = NB_OP_DESTROY; break; case MOP_VALUE_SET: if (nb_operation_is_valid(NB_OP_MODIFY, nb_node->snode)) diff --git a/lib/northbound_db.h b/lib/northbound_db.h index ad60966441..14df09caa3 100644 --- a/lib/northbound_db.h +++ b/lib/northbound_db.h @@ -22,6 +22,10 @@ #include "northbound.h" +#ifdef __cplusplus +extern "C" { +#endif + /* * Initialize the northbound database. * @@ -101,4 +105,8 @@ extern int nb_db_transactions_iterate( const char *date, const char *comment), void *arg); +#ifdef __cplusplus +} +#endif + #endif /* _FRR_NORTHBOUND_DB_H_ */ diff --git a/lib/northbound_sysrepo.c b/lib/northbound_sysrepo.c index 860c27edbd..f426f52bd9 100644 --- a/lib/northbound_sysrepo.c +++ b/lib/northbound_sysrepo.c @@ -202,10 +202,10 @@ static int frr_sr_process_change(struct nb_config *candidate, * notified about the removal of all of its leafs, even the ones * that are non-optional. We need to ignore these notifications. */ - if (!nb_operation_is_valid(NB_OP_DELETE, nb_node->snode)) + if (!nb_operation_is_valid(NB_OP_DESTROY, nb_node->snode)) return NB_OK; - nb_op = NB_OP_DELETE; + nb_op = NB_OP_DESTROY; break; case SR_OP_MOVED: nb_op = NB_OP_MOVE; @@ -26,6 +26,10 @@ #include "linklist.h" #include "vty.h" +#ifdef __cplusplus +extern "C" { +#endif + typedef uint32_t ns_id_t; /* the default NS ID */ @@ -174,4 +178,8 @@ extern int ns_enable(struct ns *ns, void (*func)(ns_id_t, void *)); extern struct ns *ns_get_created(struct ns *ns, char *name, ns_id_t ns_id); extern void ns_disable(struct ns *ns); +#ifdef __cplusplus +} +#endif + #endif /*_ZEBRA_NS_H*/ diff --git a/lib/openbsd-queue.h b/lib/openbsd-queue.h index e09cc3d4e5..d4c08a3be8 100644 --- a/lib/openbsd-queue.h +++ b/lib/openbsd-queue.h @@ -35,6 +35,10 @@ #ifndef _SYS_QUEUE_H_ #define _SYS_QUEUE_H_ +#ifdef __cplusplus +extern "C" { +#endif + /* * This file defines five types of data structures: singly-linked lists, * lists, simple queues, tail queues and XOR simple queues. @@ -572,4 +576,8 @@ } \ } while (0) +#ifdef __cplusplus +} +#endif + #endif /* !_SYS_QUEUE_H_ */ diff --git a/lib/openbsd-tree.h b/lib/openbsd-tree.h index 1383ef6de0..d2f0781333 100644 --- a/lib/openbsd-tree.h +++ b/lib/openbsd-tree.h @@ -27,6 +27,10 @@ #ifndef _SYS_TREE_H_ #define _SYS_TREE_H_ +#ifdef __cplusplus +extern "C" { +#endif + /* * This file defines data structures for different types of trees: * splay trees and red-black trees. @@ -397,31 +401,36 @@ int _rb_check(const struct rb_type *, void *, unsigned long); __attribute__((__unused__)) static inline struct _type \ *_name##_RB_INSERT(struct _name *head, struct _type *elm) \ { \ - return _rb_insert(_name##_RB_TYPE, &head->rbh_root, elm); \ + return (struct _type *)_rb_insert( \ + _name##_RB_TYPE, &head->rbh_root, elm); \ } \ \ __attribute__((__unused__)) static inline struct _type \ *_name##_RB_REMOVE(struct _name *head, struct _type *elm) \ { \ - return _rb_remove(_name##_RB_TYPE, &head->rbh_root, elm); \ + return (struct _type *)_rb_remove( \ + _name##_RB_TYPE, &head->rbh_root, elm); \ } \ \ __attribute__((__unused__)) static inline struct _type \ *_name##_RB_FIND(struct _name *head, const struct _type *key) \ { \ - return _rb_find(_name##_RB_TYPE, &head->rbh_root, key); \ + return (struct _type *)_rb_find( \ + _name##_RB_TYPE, &head->rbh_root, key); \ } \ \ __attribute__((__unused__)) static inline struct _type \ *_name##_RB_NFIND(struct _name *head, const struct _type *key) \ { \ - return _rb_nfind(_name##_RB_TYPE, &head->rbh_root, key); \ + return (struct _type *)_rb_nfind( \ + _name##_RB_TYPE, &head->rbh_root, key); \ } \ \ __attribute__((__unused__)) static inline struct _type \ *_name##_RB_ROOT(struct _name *head) \ { \ - return _rb_root(_name##_RB_TYPE, &head->rbh_root); \ + return (struct _type *)_rb_root( \ + _name##_RB_TYPE, &head->rbh_root); \ } \ \ __attribute__((__unused__)) static inline int _name##_RB_EMPTY( \ @@ -433,43 +442,45 @@ int _rb_check(const struct rb_type *, void *, unsigned long); __attribute__((__unused__)) static inline struct _type \ *_name##_RB_MIN(struct _name *head) \ { \ - return _rb_min(_name##_RB_TYPE, &head->rbh_root); \ + return (struct _type *)_rb_min( \ + _name##_RB_TYPE, &head->rbh_root); \ } \ \ __attribute__((__unused__)) static inline struct _type \ *_name##_RB_MAX(struct _name *head) \ { \ - return _rb_max(_name##_RB_TYPE, &head->rbh_root); \ + return (struct _type *)_rb_max( \ + _name##_RB_TYPE, &head->rbh_root); \ } \ \ __attribute__((__unused__)) static inline struct _type \ *_name##_RB_NEXT(struct _type *elm) \ { \ - return _rb_next(_name##_RB_TYPE, elm); \ + return (struct _type *)_rb_next(_name##_RB_TYPE, elm); \ } \ \ __attribute__((__unused__)) static inline struct _type \ *_name##_RB_PREV(struct _type *elm) \ { \ - return _rb_prev(_name##_RB_TYPE, elm); \ + return (struct _type *)_rb_prev(_name##_RB_TYPE, elm); \ } \ \ __attribute__((__unused__)) static inline struct _type \ *_name##_RB_LEFT(struct _type *elm) \ { \ - return _rb_left(_name##_RB_TYPE, elm); \ + return (struct _type *)_rb_left(_name##_RB_TYPE, elm); \ } \ \ __attribute__((__unused__)) static inline struct _type \ *_name##_RB_RIGHT(struct _type *elm) \ { \ - return _rb_right(_name##_RB_TYPE, elm); \ + return (struct _type *)_rb_right(_name##_RB_TYPE, elm); \ } \ \ __attribute__((__unused__)) static inline struct _type \ *_name##_RB_PARENT(struct _type *elm) \ { \ - return _rb_parent(_name##_RB_TYPE, elm); \ + return (struct _type *)_rb_parent(_name##_RB_TYPE, elm); \ } \ \ __attribute__((__unused__)) static inline void _name##_RB_SET_LEFT( \ @@ -560,4 +571,8 @@ int _rb_check(const struct rb_type *, void *, unsigned long); for ((_e) = RB_MAX(_name, (_head)); \ (_e) != NULL && ((_n) = RB_PREV(_name, (_e)), 1); (_e) = (_n)) +#ifdef __cplusplus +} +#endif + #endif /* _SYS_TREE_H_ */ @@ -24,6 +24,10 @@ #include "stream.h" #include "prefix.h" +#ifdef __cplusplus +extern "C" { +#endif + #define PBR_STR "Policy Based Routing\n" /* @@ -121,4 +125,8 @@ struct pbr_rule { extern int zapi_pbr_rule_encode(uint8_t cmd, struct stream *s, struct pbr_rule *zrule); +#ifdef __cplusplus +} +#endif + #endif /* _PBR_H */ diff --git a/lib/plist.h b/lib/plist.h index 8a4fa8d3ce..ba2846d74a 100644 --- a/lib/plist.h +++ b/lib/plist.h @@ -27,6 +27,10 @@ #include "stream.h" #include "vty.h" +#ifdef __cplusplus +extern "C" { +#endif + enum prefix_list_type { PREFIX_DENY, PREFIX_PERMIT, @@ -75,4 +79,8 @@ extern void prefix_bgp_orf_remove_all(afi_t, char *); extern int prefix_bgp_show_prefix_list(struct vty *vty, afi_t afi, char *name, bool use_json); +#ifdef __cplusplus +} +#endif + #endif /* _QUAGGA_PLIST_H */ diff --git a/lib/plist_int.h b/lib/plist_int.h index 6bc2d034d6..443b0c614d 100644 --- a/lib/plist_int.h +++ b/lib/plist_int.h @@ -22,6 +22,10 @@ #ifndef _QUAGGA_PLIST_INT_H #define _QUAGGA_PLIST_INT_H +#ifdef __cplusplus +extern "C" { +#endif + enum prefix_name_type { PREFIX_TYPE_STRING, PREFIX_TYPE_NUMBER }; struct pltrie_table; @@ -68,4 +72,8 @@ struct prefix_list_entry { struct prefix_list_entry *next_best; }; +#ifdef __cplusplus +} +#endif + #endif /* _QUAGGA_PLIST_INT_H */ diff --git a/lib/pqueue.h b/lib/pqueue.h index 53e5aa8332..032ee9db4c 100644 --- a/lib/pqueue.h +++ b/lib/pqueue.h @@ -21,6 +21,10 @@ #ifndef _ZEBRA_PQUEUE_H #define _ZEBRA_PQUEUE_H +#ifdef __cplusplus +extern "C" { +#endif + struct pqueue { void **array; int array_size; @@ -43,4 +47,8 @@ extern void pqueue_remove(void *data, struct pqueue *queue); extern void trickle_down(int index, struct pqueue *queue); extern void trickle_up(int index, struct pqueue *queue); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_PQUEUE_H */ diff --git a/lib/prefix.c b/lib/prefix.c index 07eb1785b7..babd4304d1 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -30,6 +30,7 @@ #include "lib_errors.h" DEFINE_MTYPE_STATIC(LIB, PREFIX, "Prefix") +DEFINE_MTYPE_STATIC(LIB, PREFIX_FLOWSPEC, "Prefix Flowspec") /* Maskbit. */ static const uint8_t maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0, diff --git a/lib/prefix.h b/lib/prefix.h index aaffb1e0c5..ae931288c0 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -35,6 +35,10 @@ #include "ipaddr.h" #include "compiler.h" +#ifdef __cplusplus +extern "C" { +#endif + #ifndef ETH_ALEN #define ETH_ALEN 6 #endif @@ -276,20 +280,29 @@ struct prefix_sg { * side, which strips type safety since the cast will accept any pointer * type.) */ +#ifndef __cplusplus +#define prefixtype(uname, typename, fieldname) \ + typename *fieldname; +#else +#define prefixtype(uname, typename, fieldname) \ + typename *fieldname; \ + uname(typename *x) { this->fieldname = x; } +#endif + union prefixptr { - struct prefix *p; - struct prefix_ipv4 *p4; - struct prefix_ipv6 *p6; - struct prefix_evpn *evp; - const struct prefix_fs *fs; + prefixtype(prefixptr, struct prefix, p) + prefixtype(prefixptr, struct prefix_ipv4, p4) + prefixtype(prefixptr, struct prefix_ipv6, p6) + prefixtype(prefixptr, struct prefix_evpn, evp) + prefixtype(prefixptr, struct prefix_fs, fs) } __attribute__((transparent_union)); union prefixconstptr { - const struct prefix *p; - const struct prefix_ipv4 *p4; - const struct prefix_ipv6 *p6; - const struct prefix_evpn *evp; - const struct prefix_fs *fs; + prefixtype(prefixconstptr, const struct prefix, p) + prefixtype(prefixconstptr, const struct prefix_ipv4, p4) + prefixtype(prefixconstptr, const struct prefix_ipv6, p6) + prefixtype(prefixconstptr, const struct prefix_evpn, evp) + prefixtype(prefixconstptr, const struct prefix_fs, fs) } __attribute__((transparent_union)); #ifndef INET_ADDRSTRLEN @@ -497,4 +510,9 @@ static inline int is_host_route(struct prefix *p) return (p->prefixlen == IPV6_MAX_BITLEN); return 0; } + +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_PREFIX_H */ diff --git a/lib/privs.c b/lib/privs.c index 838ff8fc92..2932800070 100644 --- a/lib/privs.c +++ b/lib/privs.c @@ -789,7 +789,7 @@ void zprivs_preinit(struct zebra_privs_t *zprivs) void zprivs_init(struct zebra_privs_t *zprivs) { - gid_t groups[NGROUPS_MAX]; + gid_t groups[NGROUPS_MAX] = {}; int i, ngroups = 0; int found = 0; @@ -799,7 +799,7 @@ void zprivs_init(struct zebra_privs_t *zprivs) return; if (zprivs->user) { - ngroups = sizeof(groups); + ngroups = array_size(groups); if (getgrouplist(zprivs->user, zprivs_state.zgid, groups, &ngroups) < 0) { diff --git a/lib/privs.h b/lib/privs.h index b061370b75..1fee423a95 100644 --- a/lib/privs.h +++ b/lib/privs.h @@ -23,6 +23,10 @@ #ifndef _ZEBRA_PRIVS_H #define _ZEBRA_PRIVS_H +#ifdef __cplusplus +extern "C" { +#endif + /* list of zebra capabilities */ typedef enum { ZCAP_SETID, @@ -120,4 +124,8 @@ extern void _zprivs_lower(struct zebra_privs_t **privs); _zprivs_raise(privs, __func__); \ _once == NULL; _once = (void *)1) +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_PRIVS_H */ diff --git a/lib/ptm_lib.h b/lib/ptm_lib.h index fc4d520dcb..c2170407c0 100644 --- a/lib/ptm_lib.h +++ b/lib/ptm_lib.h @@ -20,6 +20,10 @@ #ifndef __PTM_LIB_H__ #define __PTM_LIB_H__ +#ifdef __cplusplus +extern "C" { +#endif + #define PTMLIB_MSG_SZ 1024 #define PTMLIB_MSG_HDR_LEN 37 #define PTMLIB_MSG_VERSION 2 @@ -65,4 +69,8 @@ int ptm_lib_append_msg(ptm_lib_handle_t *, void *, const char *, const char *); int ptm_lib_complete_msg(ptm_lib_handle_t *, void *, char *, int *); int ptm_lib_cleanup_msg(ptm_lib_handle_t *, void *); +#ifdef __cplusplus +} +#endif + #endif @@ -20,6 +20,10 @@ #ifndef _FRR_PW_H #define _FRR_PW_H +#ifdef __cplusplus +extern "C" { +#endif + /* L2VPN name length. */ #define L2VPN_NAME_LEN 32 @@ -44,9 +48,10 @@ union pw_protocol_fields { uint32_t pwid; char vpn_name[L2VPN_NAME_LEN]; } ldp; - struct { - /* TODO */ - } bgp; }; +#ifdef __cplusplus +} +#endif + #endif /* _FRR_PW_H */ diff --git a/lib/qobj.h b/lib/qobj.h index b701eeec5f..d63988cbab 100644 --- a/lib/qobj.h +++ b/lib/qobj.h @@ -21,6 +21,10 @@ #include <stdlib.h> #include <stddef.h> +#ifdef __cplusplus +extern "C" { +#endif + /* reserve a specific amount of bytes for a struct, which can grow up to * that size (or be dummy'd out if not needed) * @@ -28,11 +32,17 @@ * this is intentional to prevent the struct from growing beyond the allocated * space. */ +#ifndef __cplusplus #define RESERVED_SPACE_STRUCT(name, fieldname, size) \ struct { \ struct name fieldname; \ char padding##fieldname[size - sizeof(struct name)]; \ }; +#else +#define RESERVED_SPACE_STRUCT(name, fieldname, size) \ + struct name fieldname; \ + char padding##fieldname[size - sizeof(struct name)]; +#endif /* don't need struct definitions for these here. code actually using * these needs to define the struct *before* including this header. @@ -127,4 +137,8 @@ void *qobj_get_typed(uint64_t id, struct qobj_nodetype *type); void qobj_init(void); void qobj_finish(void); +#ifdef __cplusplus +} +#endif + #endif /* _QOBJ_H */ diff --git a/lib/queue.h b/lib/queue.h index 11e28b4c91..dab43e3c54 100644 --- a/lib/queue.h +++ b/lib/queue.h @@ -19,6 +19,10 @@ #ifndef _FRR_QUEUE_H #define _FRR_QUEUE_H +#ifdef __cplusplus +extern "C" { +#endif + #if defined(__OpenBSD__) && !defined(STAILQ_HEAD) #include "openbsd-queue.h" @@ -85,4 +89,8 @@ }; _elm; }) #endif +#ifdef __cplusplus +} +#endif + #endif /* _FRR_QUEUE_H */ diff --git a/lib/ringbuf.h b/lib/ringbuf.h index 15049e3eea..b8f4d9798d 100644 --- a/lib/ringbuf.h +++ b/lib/ringbuf.h @@ -25,6 +25,10 @@ #include "memory.h" +#ifdef __cplusplus +extern "C" { +#endif + struct ringbuf { size_t size; ssize_t start; @@ -122,4 +126,8 @@ void ringbuf_reset(struct ringbuf *buf); */ void ringbuf_wipe(struct ringbuf *buf); +#ifdef __cplusplus +} +#endif + #endif /* _FRR_RINGBUF_H_ */ diff --git a/lib/route_types.pl b/lib/route_types.pl index 7435272761..f297096633 100755 --- a/lib/route_types.pl +++ b/lib/route_types.pl @@ -121,7 +121,7 @@ sub codelist { } $str =~ s/ $//; push @lines, $str . "\\n\" \\\n"; - push @lines, " \" > - selected route, * - FIB route, q - queued route, f - failed route\\n\\n\""; + push @lines, " \" > - selected route, * - FIB route, q - queued route, r - rejected route\\n\\n\""; return join("", @lines); } diff --git a/lib/routemap.c b/lib/routemap.c index 5c6d106d83..61e597520e 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -1007,6 +1007,34 @@ static int vty_show_route_map(struct vty *vty, const char *name) return CMD_SUCCESS; } +/* Unused route map details */ +static int vty_show_unused_route_map(struct vty *vty) +{ + struct list *maplist = list_new(); + struct listnode *ln; + struct route_map *map; + + for (map = route_map_master.head; map; map = map->next) { + /* If use_count is zero, No protocol is using this routemap. + * so adding to the list. + */ + if (!map->use_count) + listnode_add(maplist, map); + } + + if (maplist->count > 0) { + vty_out(vty, "\n%s:\n", frr_protonameinst); + list_sort(maplist, sort_route_map); + + for (ALL_LIST_ELEMENTS_RO(maplist, ln, map)) + vty_show_route_map_entry(vty, map); + } else { + vty_out(vty, "\n%s: None\n", frr_protonameinst); + } + + list_delete(&maplist); + return CMD_SUCCESS; +} /* New route map allocation. Please note route map's name must be specified. */ @@ -2759,6 +2787,15 @@ DEFUN (rmap_show_name, return vty_show_route_map(vty, name); } +DEFUN (rmap_show_unused, + rmap_show_unused_cmd, + "show route-map-unused", + SHOW_STR + "unused route-map information\n") +{ + return vty_show_unused_route_map(vty); +} + DEFUN (rmap_call, rmap_call_cmd, "call WORD", @@ -2949,6 +2986,23 @@ static void rmap_autocomplete(vector comps, struct cmd_token *token) vector_set(comps, XSTRDUP(MTYPE_COMPLETION, map->name)); } +/* Increment the use_count counter while attaching the route map */ +void route_map_counter_increment(struct route_map *map) +{ + if (map) + map->use_count++; +} + +/* Decrement the use_count counter while detaching the route map. */ +void route_map_counter_decrement(struct route_map *map) +{ + if (map) { + if (map->use_count <= 0) + return; + map->use_count--; + } +} + static const struct cmd_variable_handler rmap_var_handlers[] = { {/* "route-map WORD" */ .varname = "route_map", @@ -3006,6 +3060,7 @@ void route_map_init(void) /* Install show command */ install_element(ENABLE_NODE, &rmap_show_name_cmd); + install_element(ENABLE_NODE, &rmap_show_unused_cmd); install_element(RMAP_NODE, &match_interface_cmd); install_element(RMAP_NODE, &no_match_interface_cmd); diff --git a/lib/routemap.h b/lib/routemap.h index 463aa91725..e43e74a633 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -26,6 +26,10 @@ #include "qobj.h" #include "vty.h" +#ifdef __cplusplus +extern "C" { +#endif + DECLARE_MTYPE(ROUTE_MAP_NAME) DECLARE_MTYPE(ROUTE_MAP_RULE) DECLARE_MTYPE(ROUTE_MAP_COMPILED) @@ -169,6 +173,9 @@ struct route_map { /* How many times have we applied this route-map */ uint64_t applied; + /* Counter to track active usage of this route-map */ + uint16_t use_count; + QOBJ_FIELDS }; DECLARE_QOBJ_TYPE(route_map) @@ -379,4 +386,14 @@ extern void route_map_no_set_tag_hook(int (*func)(struct vty *vty, extern void *route_map_rule_tag_compile(const char *arg); extern void route_map_rule_tag_free(void *rule); +/* Increment the route-map used counter */ +extern void route_map_counter_increment(struct route_map *map); + +/* Decrement the route-map used counter */ +extern void route_map_counter_decrement(struct route_map *map); + +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_ROUTEMAP_H */ diff --git a/lib/sbuf.h b/lib/sbuf.h index c38e96912f..b1518a3aa8 100644 --- a/lib/sbuf.h +++ b/lib/sbuf.h @@ -23,6 +23,10 @@ #ifndef SBUF_H #define SBUF_H +#ifdef __cplusplus +extern "C" { +#endif + /* * sbuf provides a simple string buffer. One application where this comes * in handy is the parsing of binary data: If there is an error in the parsing @@ -76,4 +80,8 @@ void sbuf_free(struct sbuf *buf); void sbuf_push(struct sbuf *buf, int indent, const char *format, ...) PRINTF_ATTRIBUTE(3, 4); +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/sha256.h b/lib/sha256.h index 2473da7bda..c93d253051 100644 --- a/lib/sha256.h +++ b/lib/sha256.h @@ -29,6 +29,10 @@ #ifndef _SHA256_H_ #define _SHA256_H_ +#ifdef __cplusplus +extern "C" { +#endif + typedef struct SHA256Context { uint32_t state[8]; uint32_t count[2]; @@ -55,4 +59,8 @@ void HMAC__SHA256_Final(unsigned char[32], HMAC_SHA256_CTX *); void PBKDF2_SHA256(const uint8_t *, size_t, const uint8_t *, size_t, uint64_t, uint8_t *, size_t); +#ifdef __cplusplus +} +#endif + #endif /* !_SHA256_H_ */ diff --git a/lib/sigevent.h b/lib/sigevent.h index d4ab5741ac..a0ad88fcaa 100644 --- a/lib/sigevent.h +++ b/lib/sigevent.h @@ -25,6 +25,10 @@ #include <thread.h> +#ifdef __cplusplus +extern "C" { +#endif + #define QUAGGA_SIGNAL_TIMER_INTERVAL 2L struct quagga_signal_t { @@ -47,4 +51,8 @@ extern void signal_init(struct thread_master *m, int sigc, /* check whether there are signals to handle, process any found */ extern int quagga_sigevent_process(void); +#ifdef __cplusplus +} +#endif + #endif /* _QUAGGA_SIGNAL_H */ diff --git a/lib/skiplist.h b/lib/skiplist.h index a2e8c374b1..2ab37331c9 100644 --- a/lib/skiplist.h +++ b/lib/skiplist.h @@ -31,6 +31,10 @@ #ifndef _ZEBRA_SKIPLIST_H #define _ZEBRA_SKIPLIST_H +#ifdef __cplusplus +extern "C" { +#endif + #define SKIPLIST_0TIMER_DEBUG 1 /* @@ -122,4 +126,8 @@ extern void skiplist_debug(struct vty *vty, struct skiplist *l); extern void skiplist_test(struct vty *vty); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_SKIPLIST_H */ diff --git a/lib/smux.h b/lib/smux.h index 9adfacb3e4..3f860db0dc 100644 --- a/lib/smux.h +++ b/lib/smux.h @@ -26,6 +26,10 @@ #include "thread.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Structures here are mostly compatible with UCD SNMP 4.1.1 */ #define MATCH_FAILED (-1) #define MATCH_SUCCEEDED 0 @@ -103,4 +107,8 @@ extern void oid2in_addr(oid[], int, struct in_addr *); extern void *oid_copy(void *, const void *, size_t); extern void oid_copy_addr(oid[], struct in_addr *, int); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_SNMP_H */ diff --git a/lib/sockopt.h b/lib/sockopt.h index f54f60ffd7..8fa5987cff 100644 --- a/lib/sockopt.h +++ b/lib/sockopt.h @@ -23,6 +23,10 @@ #include "sockunion.h" +#ifdef __cplusplus +extern "C" { +#endif + extern void setsockopt_so_recvbuf(int sock, int size); extern void setsockopt_so_sendbuf(const int sock, int size); extern int getsockopt_so_sendbuf(const int sock); @@ -98,4 +102,9 @@ extern void sockopt_iphdrincl_swab_systoh(struct ip *iph); extern int sockopt_tcp_rtt(int); extern int sockopt_tcp_signature(int sock, union sockunion *su, const char *password); + +#ifdef __cplusplus +} +#endif + #endif /*_ZEBRA_SOCKOPT_H */ diff --git a/lib/sockunion.h b/lib/sockunion.h index b585aee5b4..d7d26ba85a 100644 --- a/lib/sockunion.h +++ b/lib/sockunion.h @@ -28,6 +28,10 @@ #include <netmpls/mpls.h> #endif +#ifdef __cplusplus +extern "C" { +#endif + union sockunion { struct sockaddr sa; struct sockaddr_in sin; @@ -99,4 +103,8 @@ extern union sockunion *sockunion_dup(const union sockunion *); extern void sockunion_free(union sockunion *); extern void sockunion_init(union sockunion *); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_SOCKUNION_H */ diff --git a/lib/spf_backoff.h b/lib/spf_backoff.h index 6de5804ace..11b2701e3e 100644 --- a/lib/spf_backoff.h +++ b/lib/spf_backoff.h @@ -26,6 +26,10 @@ #ifndef _ZEBRA_SPF_BACKOFF_H #define _ZEBRA_SPF_BACKOFF_H +#ifdef __cplusplus +extern "C" { +#endif + struct spf_backoff; struct thread_master; struct vty; @@ -58,4 +62,8 @@ long spf_backoff_long_delay(struct spf_backoff *backoff); long spf_backoff_holddown(struct spf_backoff *backoff); long spf_backoff_timetolearn(struct spf_backoff *backoff); +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/srcdest_table.h b/lib/srcdest_table.h index 54acb51b03..8845931de7 100644 --- a/lib/srcdest_table.h +++ b/lib/srcdest_table.h @@ -46,6 +46,10 @@ #include "prefix.h" #include "table.h" +#ifdef __cplusplus +extern "C" { +#endif + #define SRCDEST2STR_BUFFER (2*PREFIX2STR_BUFFER + sizeof(" from ")) /* extended route node for IPv6 srcdest routing */ @@ -84,7 +88,8 @@ static inline int rnode_is_srcnode(struct route_node *rn) static inline struct route_table *srcdest_rnode_table(struct route_node *rn) { if (rnode_is_srcnode(rn)) { - struct route_node *dst_rn = route_table_get_info(rn->table); + struct route_node *dst_rn = + (struct route_node *)route_table_get_info(rn->table); return dst_rn->table; } else { return rn->table; @@ -95,4 +100,8 @@ static inline void *srcdest_rnode_table_info(struct route_node *rn) return route_table_get_info(srcdest_rnode_table(rn)); } +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_SRC_DEST_TABLE_H */ diff --git a/lib/stream.h b/lib/stream.h index 32b6fb5af1..5341bfa40b 100644 --- a/lib/stream.h +++ b/lib/stream.h @@ -28,6 +28,10 @@ #include "mpls.h" #include "prefix.h" +#ifdef __cplusplus +extern "C" { +#endif + /* * A stream is an arbitrary buffer, whose contents generally are assumed to * be in network order. @@ -115,9 +119,9 @@ struct stream_fifo { pthread_mutex_t mtx; /* number of streams in this fifo */ - _Atomic size_t count; + atomic_size_t count; #if defined DEV_BUILD - _Atomic size_t max_count; + atomic_size_t max_count; #endif struct stream *head; @@ -404,4 +408,8 @@ static inline uint8_t *ptr_get_be32(uint8_t *ptr, uint32_t *out) goto stream_failure; \ } while (0) +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_STREAM_H */ diff --git a/lib/subdir.am b/lib/subdir.am index ccbe13bca6..f245560c45 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -3,7 +3,7 @@ # lib_LTLIBRARIES += lib/libfrr.la lib_libfrr_la_LDFLAGS = -version-info 0:0:0 -Xlinker -e_libfrr_version -lib_libfrr_la_LIBADD = @LIBCAP@ $(UNWIND_LIBS) -lyang +lib_libfrr_la_LIBADD = $(LIBCAP) $(UNWIND_LIBS) $(LIBYANG_LIBS) lib_libfrr_la_SOURCES = \ lib/agg_table.c \ @@ -116,7 +116,7 @@ vtysh_scan += \ vtysh_scan += $(top_srcdir)/lib/agentx.c if SQLITE3 -lib_libfrr_la_LIBADD += -lsqlite3 +lib_libfrr_la_LIBADD += $(SQLITE3_LIBS) lib_libfrr_la_SOURCES += lib/db.c endif @@ -289,7 +289,7 @@ endif lib_confd_la_CFLAGS = $(WERROR) $(CONFD_CFLAGS) lib_confd_la_LDFLAGS = -avoid-version -module -shared -export-dynamic -lib_confd_la_LIBADD = lib/libfrr.la -lconfd +lib_confd_la_LIBADD = lib/libfrr.la $(CONFD_LIBS) lib_confd_la_SOURCES = lib/northbound_confd.c # @@ -299,9 +299,9 @@ if SYSREPO module_LTLIBRARIES += lib/sysrepo.la endif -lib_sysrepo_la_CFLAGS = $(WERROR) +lib_sysrepo_la_CFLAGS = $(WERROR) $(SYSREPO_CFLAGS) lib_sysrepo_la_LDFLAGS = -avoid-version -module -shared -export-dynamic -lib_sysrepo_la_LIBADD = lib/libfrr.la -lsysrepo +lib_sysrepo_la_LIBADD = lib/libfrr.la $(SYSREPO_LIBS) lib_sysrepo_la_SOURCES = lib/northbound_sysrepo.c # @@ -387,11 +387,13 @@ lib/command_lex.h: lib/command_lex.c @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) "lib/command_lex.c"; else :; fi lib/command_lex.lo: lib/command_parse.h lib/command_parse.lo: lib/command_lex.h +lib/clippy-command_lex.$(OBJEXT): lib/command_parse.h +lib/clippy-command_parse.$(OBJEXT): lib/command_lex.h lib/lib_clippy-command_lex.$(OBJEXT): lib/command_parse.h lib/lib_clippy-command_parse.$(OBJEXT): lib/command_lex.h lib/route_types.h: $(top_srcdir)/lib/route_types.txt $(top_srcdir)/lib/route_types.pl - @PERL@ $(top_srcdir)/lib/route_types.pl < $(top_srcdir)/lib/route_types.txt > $@ + $(PERL) $(top_srcdir)/lib/route_types.pl < $(top_srcdir)/lib/route_types.txt > $@ DISTCLEANFILES += lib/route_types.h if GIT_VERSION @@ -405,7 +407,7 @@ PHONY_GITVERSION=lib/gitversion.h.tmp .SILENT: lib/gitversion.h lib/gitversion.h.tmp GITH=lib/gitversion.h lib/gitversion.h.tmp: $(top_srcdir)/.git - @PERL@ $(top_srcdir)/lib/gitversion.pl $(top_srcdir) > ${GITH}.tmp + $(PERL) $(top_srcdir)/lib/gitversion.pl $(top_srcdir) > ${GITH}.tmp lib/gitversion.h: lib/gitversion.h.tmp { test -f ${GITH} && diff -s -q ${GITH}.tmp ${GITH}; } || cp ${GITH}.tmp ${GITH} diff --git a/lib/systemd.h b/lib/systemd.h index a13ea7bfdd..6e43df527d 100644 --- a/lib/systemd.h +++ b/lib/systemd.h @@ -19,6 +19,10 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#ifdef __cplusplus +extern "C" { +#endif + /* * Wrapper functions to systemd calls. * @@ -37,3 +41,7 @@ void systemd_send_stopping(void); * process? */ void systemd_send_started(struct thread_master *master, int the_process); + +#ifdef __cplusplus +} +#endif diff --git a/lib/table.h b/lib/table.h index 541d74d77b..ce578e795c 100644 --- a/lib/table.h +++ b/lib/table.h @@ -25,6 +25,11 @@ #include "memory.h" #include "hash.h" #include "prefix.h" + +#ifdef __cplusplus +extern "C" { +#endif + DECLARE_MTYPE(ROUTE_TABLE) DECLARE_MTYPE(ROUTE_NODE) @@ -318,4 +323,8 @@ static inline int route_table_iter_started(route_table_iter_t *iter) return iter->state != RT_ITER_STATE_INIT; } +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_TABLE_H */ diff --git a/lib/termtable.h b/lib/termtable.h index ca5cc1df9f..491010a856 100644 --- a/lib/termtable.h +++ b/lib/termtable.h @@ -22,6 +22,10 @@ #include <zebra.h> +#ifdef __cplusplus +extern "C" { +#endif + enum ttable_align { LEFT, RIGHT, @@ -294,4 +298,8 @@ void ttable_rowseps(struct ttable *tt, unsigned int row, */ char *ttable_dump(struct ttable *tt, const char *newline); +#ifdef __cplusplus +} +#endif + #endif /* _TERMTABLE_H */ diff --git a/lib/thread.c b/lib/thread.c index ae8e375a27..8c1b3ff06d 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -93,7 +93,8 @@ static void cpu_record_hash_free(void *a) static void vty_out_cpu_thread_history(struct vty *vty, struct cpu_thread_history *a) { - vty_out(vty, "%5d %10lu.%03lu %9u %8lu %9lu %8lu %9lu", a->total_active, + vty_out(vty, "%5"PRIdFAST32" %10lu.%03lu %9"PRIuFAST32 + " %8lu %9lu %8lu %9lu", a->total_active, a->cpu.total / 1000, a->cpu.total % 1000, a->total_calls, a->cpu.total / a->total_calls, a->cpu.max, a->real.total / a->total_calls, a->real.max); diff --git a/lib/thread.h b/lib/thread.h index f404d92755..ec774a6543 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -27,6 +27,10 @@ #include "monotime.h" #include "frratomic.h" +#ifdef __cplusplus +extern "C" { +#endif + struct rusage_t { struct rusage cpu; struct timeval real; @@ -119,13 +123,13 @@ struct thread { struct cpu_thread_history { int (*func)(struct thread *); - _Atomic unsigned int total_calls; - _Atomic unsigned int total_active; + atomic_uint_fast32_t total_calls; + atomic_uint_fast32_t total_active; struct time_stats { - _Atomic unsigned long total, max; + atomic_size_t total, max; } real; struct time_stats cpu; - _Atomic uint32_t types; + atomic_uint_fast32_t types; const char *funcname; }; @@ -233,4 +237,8 @@ extern unsigned long thread_consumed_time(RUSAGE_T *after, RUSAGE_T *before, /* only for use in logging functions! */ extern pthread_key_t thread_current; +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_THREAD_H */ diff --git a/lib/vector.h b/lib/vector.h index 97e15da040..d5857eb599 100644 --- a/lib/vector.h +++ b/lib/vector.h @@ -24,6 +24,10 @@ #include "memory.h" +#ifdef __cplusplus +extern "C" { +#endif + /* struct for vector */ struct _vector { unsigned int active; /* number of active slots */ @@ -63,4 +67,9 @@ extern void *vector_lookup(vector, unsigned int); extern void *vector_lookup_ensure(vector, unsigned int); extern void vector_to_array(vector v, void ***dest, int *argc); extern vector array_to_vector(void **src, int argc); + +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_VECTOR_H */ diff --git a/lib/vlan.h b/lib/vlan.h index 6d15e62dfc..eea2633d4e 100644 --- a/lib/vlan.h +++ b/lib/vlan.h @@ -22,8 +22,16 @@ #ifndef __VLAN_H__ #define __VLAN_H__ +#ifdef __cplusplus +extern "C" { +#endif + /* VLAN Identifier */ typedef uint16_t vlanid_t; #define VLANID_MAX 4095 +#ifdef __cplusplus +} +#endif + #endif /* __VLAN_H__ */ @@ -471,7 +471,7 @@ static const struct cmd_variable_handler vrf_var_handlers[] = { /* Initialize VRF module. */ void vrf_init(int (*create)(struct vrf *), int (*enable)(struct vrf *), - int (*disable)(struct vrf *), int (*delete)(struct vrf *), + int (*disable)(struct vrf *), int (*destroy)(struct vrf *), int ((*update)(struct vrf *))) { struct vrf *default_vrf; @@ -485,7 +485,7 @@ void vrf_init(int (*create)(struct vrf *), int (*enable)(struct vrf *), vrf_master.vrf_new_hook = create; vrf_master.vrf_enable_hook = enable; vrf_master.vrf_disable_hook = disable; - vrf_master.vrf_delete_hook = delete; + vrf_master.vrf_delete_hook = destroy; vrf_master.vrf_update_name_hook = update; /* The default VRF always exists. */ @@ -28,6 +28,10 @@ #include "vty.h" #include "ns.h" +#ifdef __cplusplus +extern "C" { +#endif + /* The default VRF ID */ #define VRF_UNKNOWN UINT32_MAX @@ -200,7 +204,7 @@ extern int vrf_bitmap_check(vrf_bitmap_t, vrf_id_t); * the system ( 2 and 3 ) above. */ extern void vrf_init(int (*create)(struct vrf *vrf), int (*enable)(struct vrf *vrf), - int (*disable)(struct vrf *vrf), int (*delete)(struct vrf *vrf), + int (*disable)(struct vrf *vrf), int (*destroy)(struct vrf *vrf), int (*update)(struct vrf *vrf)); /* @@ -292,4 +296,8 @@ extern int vrf_enable(struct vrf *vrf); extern void vrf_delete(struct vrf *vrf); extern vrf_id_t vrf_generate_id(void); +#ifdef __cplusplus +} +#endif + #endif /*_ZEBRA_VRF_H*/ diff --git a/lib/vrf_int.h b/lib/vrf_int.h index d7fe735817..8dc078e4f3 100644 --- a/lib/vrf_int.h +++ b/lib/vrf_int.h @@ -25,6 +25,10 @@ #include "vrf.h" +#ifdef __cplusplus +extern "C" { +#endif + /* * These functions should only be called by: * zebra/if_netlink.c -> The interface from OS into Zebra @@ -52,4 +56,8 @@ extern int vrf_enable(struct vrf *); */ extern void vrf_delete(struct vrf *); +#ifdef __cplusplus +} +#endif + #endif @@ -31,6 +31,10 @@ #include "compiler.h" #include "northbound.h" +#ifdef __cplusplus +extern "C" { +#endif + #define VTY_BUFSIZ 4096 #define VTY_MAXHIST 20 #define VTY_MAXDEPTH 8 @@ -333,4 +337,8 @@ extern void vty_stdio_close(void); an async-signal-safe function. */ extern void vty_log_fixed(char *buf, size_t len); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_VTY_H */ diff --git a/lib/vxlan.h b/lib/vxlan.h index bcf8354539..2a8077f8cf 100644 --- a/lib/vxlan.h +++ b/lib/vxlan.h @@ -22,6 +22,10 @@ #ifndef __VXLAN_H__ #define __VXLAN_H__ +#ifdef __cplusplus +extern "C" { +#endif + /* VxLAN Network Identifier - 24-bit (RFC 7348) */ typedef uint32_t vni_t; #define VNI_MAX 16777215 /* (2^24 - 1) */ @@ -35,4 +39,9 @@ enum vxlan_flood_control { VXLAN_FLOOD_HEAD_END_REPL = 0, VXLAN_FLOOD_DISABLED, }; + +#ifdef __cplusplus +} +#endif + #endif /* __VXLAN_H__ */ diff --git a/lib/wheel.h b/lib/wheel.h index c8e83fafcb..e66751c1d0 100644 --- a/lib/wheel.h +++ b/lib/wheel.h @@ -20,6 +20,10 @@ #ifndef __WHEEL_H__ #define __WHEEL_H__ +#ifdef __cplusplus +extern "C" { +#endif + struct timer_wheel { char *name; struct thread_master *master; @@ -115,4 +119,8 @@ int wheel_add_item(struct timer_wheel *wheel, void *item); */ int wheel_remove_item(struct timer_wheel *wheel, void *item); +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/workqueue.c b/lib/workqueue.c index 24ef24c774..fa69ec600e 100644 --- a/lib/workqueue.c +++ b/lib/workqueue.c @@ -99,8 +99,10 @@ struct work_queue *work_queue_new(struct thread_master *m, return new; } -void work_queue_free_original(struct work_queue *wq) +void work_queue_free_and_null(struct work_queue **wqp) { + struct work_queue *wq = *wqp; + if (wq->thread != NULL) thread_cancel(wq->thread); @@ -114,13 +116,8 @@ void work_queue_free_original(struct work_queue *wq) XFREE(MTYPE_WORK_QUEUE_NAME, wq->name); XFREE(MTYPE_WORK_QUEUE, wq); - return; -} -void work_queue_free_and_null(struct work_queue **wq) -{ - work_queue_free_original(*wq); - *wq = NULL; + *wqp = NULL; } bool work_queue_is_scheduled(struct work_queue *wq) diff --git a/lib/workqueue.h b/lib/workqueue.h index 7c84655063..7c610f5dd6 100644 --- a/lib/workqueue.h +++ b/lib/workqueue.h @@ -25,6 +25,11 @@ #include "memory.h" #include "queue.h" + +#ifdef __cplusplus +extern "C" { +#endif + DECLARE_MTYPE(WORK_QUEUE) /* Hold time for the initial schedule of a queue run, in millisec */ @@ -159,19 +164,10 @@ extern struct work_queue *work_queue_new(struct thread_master *, const char *); * The usage of work_queue_free is being transitioned to pass * in the double pointer to remove use after free's. */ -#if CONFDATE > 20190205 -CPP_NOTICE("work_queue_free without double pointer is deprecated, please fixup") -#endif -extern void work_queue_free_and_null(struct work_queue **); -extern void work_queue_free_original(struct work_queue *); -#define work_queue_free(X) \ - do { \ - work_queue_free_original((X)); \ - CPP_WARN("Please use work_queue_free_and_null"); \ - } while (0) +extern void work_queue_free_and_null(struct work_queue **wqp); /* Add the supplied data as an item onto the workqueue */ -extern void work_queue_add(struct work_queue *, void *); +extern void work_queue_add(struct work_queue *wq, void *item); /* plug the queue, ie prevent it from being drained / processed */ extern void work_queue_plug(struct work_queue *wq); @@ -185,4 +181,8 @@ extern int work_queue_run(struct thread *); extern void workqueue_cmd_init(void); +#ifdef __cplusplus +} +#endif + #endif /* _QUAGGA_WORK_QUEUE_H */ diff --git a/lib/yang.h b/lib/yang.h index 3259189e98..4680db08d4 100644 --- a/lib/yang.h +++ b/lib/yang.h @@ -29,6 +29,10 @@ #include "yang_wrappers.h" +#ifdef __cplusplus +extern "C" { +#endif + DECLARE_MTYPE(YANG_MODULE) DECLARE_MTYPE(YANG_DATA) @@ -521,4 +525,8 @@ extern void yang_init(void); */ extern void yang_terminate(void); +#ifdef __cplusplus +} +#endif + #endif /* _FRR_YANG_H_ */ diff --git a/lib/yang_translator.h b/lib/yang_translator.h index 6b49d1acf3..55f396a434 100644 --- a/lib/yang_translator.h +++ b/lib/yang_translator.h @@ -20,6 +20,10 @@ #ifndef _FRR_YANG_TRANSLATOR_H_ #define _FRR_YANG_TRANSLATOR_H_ +#ifdef __cplusplus +extern "C" { +#endif + #define YANG_TRANSLATE_TO_NATIVE 0 #define YANG_TRANSLATE_FROM_NATIVE 1 #define YANG_TRANSLATE_MAX 2 @@ -141,4 +145,8 @@ extern void yang_translator_init(void); */ extern void yang_translator_terminate(void); +#ifdef __cplusplus +} +#endif + #endif /* _FRR_YANG_TRANSLATOR_H_ */ diff --git a/lib/zclient.c b/lib/zclient.c index a01da77669..9db1dd74f2 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -414,9 +414,6 @@ void zclient_send_reg_requests(struct zclient *zclient, vrf_id_t vrf_id) /* We need router-id information. */ zebra_message_send(zclient, ZEBRA_ROUTER_ID_ADD, vrf_id); - /* We need interface information. */ - zebra_message_send(zclient, ZEBRA_INTERFACE_ADD, vrf_id); - /* Set unwanted redistribute route. */ for (afi = AFI_IP; afi < AFI_MAX; afi++) vrf_bitmap_set(zclient->redist[afi][zclient->redist_default], @@ -481,9 +478,6 @@ void zclient_send_dereg_requests(struct zclient *zclient, vrf_id_t vrf_id) /* We need router-id information. */ zebra_message_send(zclient, ZEBRA_ROUTER_ID_DELETE, vrf_id); - /* We need interface information. */ - zebra_message_send(zclient, ZEBRA_INTERFACE_DELETE, vrf_id); - /* Set unwanted redistribute route. */ for (afi = AFI_IP; afi < AFI_MAX; afi++) vrf_bitmap_unset(zclient->redist[afi][zclient->redist_default], @@ -596,6 +590,8 @@ int zclient_start(struct zclient *zclient) zebra_hello_send(zclient); + zebra_message_send(zclient, ZEBRA_INTERFACE_ADD, VRF_DEFAULT); + /* Inform the successful connection. */ if (zclient->zebra_connected) (*zclient->zebra_connected)(zclient); diff --git a/lib/zclient.h b/lib/zclient.h index e00821f2f6..3a054e5e72 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -125,6 +125,7 @@ typedef enum { ZEBRA_FEC_UNREGISTER, ZEBRA_FEC_UPDATE, ZEBRA_ADVERTISE_DEFAULT_GW, + ZEBRA_ADVERTISE_SVI_MACIP, ZEBRA_ADVERTISE_SUBNET, ZEBRA_ADVERTISE_ALL_VNI, ZEBRA_LOCAL_ES_ADD, diff --git a/lib/zebra.h b/lib/zebra.h index 43ab4309c2..b96fb5a206 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -232,6 +232,15 @@ typedef unsigned char uint8_t; #include "zassert.h" +/* + * Add explicit static cast only when using a C++ compiler. + */ +#ifdef __cplusplus +#define static_cast(l, r) static_cast<decltype(l)>((r)) +#else +#define static_cast(l, r) (r) +#endif + #ifndef HAVE_STRLCAT size_t strlcat(char *__restrict dest, const char *__restrict src, size_t destsize); diff --git a/nhrpd/subdir.am b/nhrpd/subdir.am index 758c22e2be..6e2b91780f 100644 --- a/nhrpd/subdir.am +++ b/nhrpd/subdir.am @@ -8,8 +8,8 @@ vtysh_scan += $(top_srcdir)/nhrpd/nhrp_vty.c man8 += $(MANBUILD)/nhrpd.8 endif -nhrpd_nhrpd_LDADD = lib/libfrr.la @LIBCAP@ @CARES_LIBS@ -nhrpd_nhrpd_CFLAGS = $(AM_CFLAGS) @CARES_CFLAGS@ +nhrpd_nhrpd_LDADD = lib/libfrr.la $(LIBCAP) $(CARES_LIBS) +nhrpd_nhrpd_CFLAGS = $(AM_CFLAGS) $(CARES_CFLAGS) nhrpd_nhrpd_SOURCES = \ nhrpd/linux.c \ nhrpd/netlink_arp.c \ diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 671267aa05..3153c29aa1 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -856,16 +856,22 @@ void ospf6_asbr_lsentry_remove(struct ospf6_route *asbr_entry) static void ospf6_asbr_routemap_set(int type, const char *mapname) { - if (ospf6->rmap[type].name) + if (ospf6->rmap[type].name) { + route_map_counter_decrement(ospf6->rmap[type].map); free(ospf6->rmap[type].name); + } ospf6->rmap[type].name = strdup(mapname); ospf6->rmap[type].map = route_map_lookup_by_name(mapname); + route_map_counter_increment(ospf6->rmap[type].map); } static void ospf6_asbr_routemap_unset(int type) { if (ospf6->rmap[type].name) free(ospf6->rmap[type].name); + + route_map_counter_decrement(ospf6->rmap[type].map); + ospf6->rmap[type].name = NULL; ospf6->rmap[type].map = NULL; } @@ -939,6 +945,10 @@ static void ospf6_asbr_routemap_update(const char *mapname) "%s: route-map %s update, reset redist %s", __PRETTY_FUNCTION__, mapname, ZROUTE_NAME(type)); + + route_map_counter_increment( + ospf6->rmap[type].map); + ospf6_asbr_distribute_list_update(type); } } else diff --git a/ospf6d/subdir.am b/ospf6d/subdir.am index d9c29f2651..eac0eee45f 100644 --- a/ospf6d/subdir.am +++ b/ospf6d/subdir.am @@ -73,7 +73,7 @@ noinst_HEADERS += \ ospf6d/ospf6d.h \ # end -ospf6d_ospf6d_LDADD = ospf6d/libospf6.a lib/libfrr.la @LIBCAP@ +ospf6d_ospf6d_LDADD = ospf6d/libospf6.a lib/libfrr.la $(LIBCAP) ospf6d_ospf6d_SOURCES = \ ospf6d/ospf6_main.c \ # end diff --git a/ospfclient/subdir.am b/ospfclient/subdir.am index c05d920d5f..94d489358c 100644 --- a/ospfclient/subdir.am +++ b/ospfclient/subdir.am @@ -23,7 +23,7 @@ endif ospfclient_ospfclient_LDADD = \ ospfclient/libfrrospfapiclient.la \ - @LIBCAP@ \ + $(LIBCAP) \ # end if STATIC_BIN diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 30f5a2a80e..ecc55c2ee5 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -2098,10 +2098,22 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, if (current == NULL || (ret = ospf_lsa_more_recent(current, lsa)) < 0) { + /* CVE-2017-3224 */ + if (current && (lsa->data->ls_seqnum == + htonl(OSPF_MAX_SEQUENCE_NUMBER) + && !IS_LSA_MAXAGE(lsa))) { + zlog_debug( + "Link State Update[%s]: has Max Seq but not MaxAge. Dropping it", + dump_lsa_key(lsa)); + + DISCARD_LSA(lsa, 4); + continue; + } + /* Actual flooding procedure. */ if (ospf_flood(oi->ospf, nbr, current, lsa) < 0) /* Trap NSSA later. */ - DISCARD_LSA(lsa, 4); + DISCARD_LSA(lsa, 5); continue; } @@ -2158,7 +2170,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, oi->ls_ack, ospf_lsa_lock(lsa)); - DISCARD_LSA(lsa, 5); + DISCARD_LSA(lsa, 6); } else /* Acknowledge the receipt of the LSA by sending a Link State Acknowledgment packet back out the @@ -2166,7 +2178,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, interface. */ { ospf_ls_ack_send(nbr, lsa); - DISCARD_LSA(lsa, 6); + DISCARD_LSA(lsa, 7); } } @@ -2183,7 +2195,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, if (IS_LSA_MAXAGE(current) && current->data->ls_seqnum == htonl(OSPF_MAX_SEQUENCE_NUMBER)) { - DISCARD_LSA(lsa, 7); + DISCARD_LSA(lsa, 8); } /* Otherwise, as long as the database copy has not been sent in a @@ -2206,7 +2218,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, ospf_ls_upd_send_lsa( nbr, current, OSPF_SEND_PACKET_DIRECT); - DISCARD_LSA(lsa, 8); + DISCARD_LSA(lsa, 9); } } } diff --git a/ospfd/ospf_routemap.c b/ospfd/ospf_routemap.c index 54009639fc..a15e605aca 100644 --- a/ospfd/ospf_routemap.c +++ b/ospfd/ospf_routemap.c @@ -70,11 +70,19 @@ static void ospf_route_map_update(const char *name) /* Keep old route-map. */ struct route_map *old = ROUTEMAP(red); - /* Update route-map. */ - ROUTEMAP(red) = - route_map_lookup_by_name( - ROUTEMAP_NAME(red)); - + if (!old) { + /* Route-map creation */ + /* Update route-map. */ + ROUTEMAP(red) = + route_map_lookup_by_name( + ROUTEMAP_NAME(red)); + + route_map_counter_increment( + ROUTEMAP(red)); + } else { + /* Route-map deletion */ + ROUTEMAP(red) = NULL; + } /* No update for this distribute type. */ if (old == NULL diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index a86800f901..ea2c492e18 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -983,17 +983,22 @@ int ospf_redistribute_check(struct ospf *ospf, struct external_info *ei, /* OSPF route-map set for redistribution */ void ospf_routemap_set(struct ospf_redist *red, const char *name) { - if (ROUTEMAP_NAME(red)) + if (ROUTEMAP_NAME(red)) { + route_map_counter_decrement(ROUTEMAP(red)); free(ROUTEMAP_NAME(red)); + } ROUTEMAP_NAME(red) = strdup(name); ROUTEMAP(red) = route_map_lookup_by_name(name); + route_map_counter_increment(ROUTEMAP(red)); } void ospf_routemap_unset(struct ospf_redist *red) { - if (ROUTEMAP_NAME(red)) + if (ROUTEMAP_NAME(red)) { + route_map_counter_decrement(ROUTEMAP(red)); free(ROUTEMAP_NAME(red)); + } ROUTEMAP_NAME(red) = NULL; ROUTEMAP(red) = NULL; diff --git a/ospfd/subdir.am b/ospfd/subdir.am index 3ad1b870b4..48dd741b24 100644 --- a/ospfd/subdir.am +++ b/ospfd/subdir.am @@ -98,7 +98,7 @@ noinst_HEADERS += \ ospfd/ospf_zebra.h \ # end -ospfd_ospfd_LDADD = ospfd/libfrrospf.a lib/libfrr.la @LIBCAP@ @LIBM@ +ospfd_ospfd_LDADD = ospfd/libfrrospf.a lib/libfrr.la $(LIBCAP) $(LIBM) ospfd_ospfd_SOURCES = ospfd/ospf_main.c ospfd_ospfd_snmp_la_SOURCES = ospfd/ospf_snmp.c diff --git a/pbrd/pbr_map.c b/pbrd/pbr_map.c index eb2c082fb9..950ce8dfe1 100644 --- a/pbrd/pbr_map.c +++ b/pbrd/pbr_map.c @@ -409,7 +409,8 @@ void pbr_map_schedule_policy_from_nhg(const char *nh_group) pbrm->name); for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) { DEBUGD(&pbr_dbg_map, "\tNH Grp name: %s", - pbrms->nhgrp_name ? pbrms->nhgrp_name : "NULL"); + pbrms->nhgrp_name ? + pbrms->nhgrp_name : pbrms->internal_nhg_name); if (pbrms->nhgrp_name && (strcmp(nh_group, pbrms->nhgrp_name) == 0)) { @@ -526,12 +527,9 @@ void pbr_map_check(struct pbr_map_sequence *pbrms) DEBUGD(&pbr_dbg_map, "%s: for %s(%u)", __PRETTY_FUNCTION__, pbrm->name, pbrms->seqno); if (pbr_map_check_valid(pbrm->name)) - DEBUGD(&pbr_dbg_map, "We are totally valid %s\n", + DEBUGD(&pbr_dbg_map, "We are totally valid %s", pbrm->name); - DEBUGD(&pbr_dbg_map, "%s: Installing %s(%u) reason: %" PRIu64, - __PRETTY_FUNCTION__, pbrm->name, pbrms->seqno, pbrms->reason); - if (pbrms->reason == PBR_MAP_VALID_SEQUENCE_NUMBER) { install = true; DEBUGD(&pbr_dbg_map, "%s: Installing %s(%u) reason: %" PRIu64, diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c index 7974bbfb4e..425bc04b4d 100644 --- a/pbrd/pbr_zebra.c +++ b/pbrd/pbr_zebra.c @@ -69,6 +69,9 @@ static int interface_add(int command, struct zclient *zclient, if (!ifp) return 0; + DEBUGD(&pbr_dbg_zebra, + "%s: %s", __PRETTY_FUNCTION__, ifp->name); + if (!ifp->info) pbr_if_new(ifp); @@ -89,6 +92,9 @@ static int interface_delete(int command, struct zclient *zclient, if (ifp == NULL) return 0; + DEBUGD(&pbr_dbg_zebra, + "%s: %s", __PRETTY_FUNCTION__, ifp->name); + if_set_index(ifp, IFINDEX_INTERNAL); return 0; @@ -97,7 +103,14 @@ static int interface_delete(int command, struct zclient *zclient, static int interface_address_add(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { - zebra_interface_address_read(command, zclient->ibuf, vrf_id); + struct connected *c; + char buf[PREFIX_STRLEN]; + + c = zebra_interface_address_read(command, zclient->ibuf, vrf_id); + + DEBUGD(&pbr_dbg_zebra, + "%s: %s added %s", __PRETTY_FUNCTION__, c->ifp->name, + prefix2str(c->address, buf, sizeof(buf))); return 0; } @@ -106,12 +119,17 @@ static int interface_address_delete(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct connected *c; + char buf[PREFIX_STRLEN]; c = zebra_interface_address_read(command, zclient->ibuf, vrf_id); if (!c) return 0; + DEBUGD(&pbr_dbg_zebra, + "%s: %s deleted %s", __PRETTY_FUNCTION__, c->ifp->name, + prefix2str(c->address, buf, sizeof(buf))); + connected_free(c); return 0; } @@ -119,8 +137,12 @@ static int interface_address_delete(int command, struct zclient *zclient, static int interface_state_up(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { + struct interface *ifp; + + ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); - zebra_interface_state_read(zclient->ibuf, vrf_id); + DEBUGD(&pbr_dbg_zebra, + "%s: %s is up", __PRETTY_FUNCTION__, ifp->name); return 0; } @@ -128,8 +150,12 @@ static int interface_state_up(int command, struct zclient *zclient, static int interface_state_down(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { + struct interface *ifp; - zebra_interface_state_read(zclient->ibuf, vrf_id); + ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); + + DEBUGD(&pbr_dbg_zebra, + "%s: %s is down", __PRETTY_FUNCTION__, ifp->name); return 0; } @@ -142,11 +168,11 @@ static int route_notify_owner(int command, struct zclient *zclient, uint32_t table_id; char buf[PREFIX_STRLEN]; - prefix2str(&p, buf, sizeof(buf)); - if (!zapi_route_notify_decode(zclient->ibuf, &p, &table_id, ¬e)) return -1; + prefix2str(&p, buf, sizeof(buf)); + switch (note) { case ZAPI_ROUTE_FAIL_INSTALL: DEBUGD(&pbr_dbg_zebra, @@ -207,20 +233,20 @@ static int rule_notify_owner(int command, struct zclient *zclient, switch (note) { case ZAPI_RULE_FAIL_INSTALL: - DEBUGD(&pbr_dbg_zebra, "%s: Received RULE_FAIL_INSTALL", - __PRETTY_FUNCTION__); pbrms->installed &= ~installed; + DEBUGD(&pbr_dbg_zebra, "%s: Received RULE_FAIL_INSTALL: %lu", + __PRETTY_FUNCTION__, pbrms->installed); break; case ZAPI_RULE_INSTALLED: pbrms->installed |= installed; - DEBUGD(&pbr_dbg_zebra, "%s: Received RULE_INSTALLED", - __PRETTY_FUNCTION__); + DEBUGD(&pbr_dbg_zebra, "%s: Received RULE_INSTALLED: %lu", + __PRETTY_FUNCTION__, pbrms->installed); break; case ZAPI_RULE_FAIL_REMOVE: case ZAPI_RULE_REMOVED: pbrms->installed &= ~installed; - DEBUGD(&pbr_dbg_zebra, "%s: Received RULE REMOVED", - __PRETTY_FUNCTION__); + DEBUGD(&pbr_dbg_zebra, "%s: Received RULE REMOVED: %lu", + __PRETTY_FUNCTION__, pbrms->installed); break; } @@ -229,6 +255,8 @@ static int rule_notify_owner(int command, struct zclient *zclient, static void zebra_connected(struct zclient *zclient) { + DEBUGD(&pbr_dbg_zebra, "%s: Registering for fun and profit", + __PRETTY_FUNCTION__); zclient_send_reg_requests(zclient, VRF_DEFAULT); } @@ -236,11 +264,15 @@ static void route_add_helper(struct zapi_route *api, struct nexthop_group nhg, uint8_t install_afi) { struct zapi_nexthop *api_nh; + char buf[PREFIX_STRLEN]; struct nexthop *nhop; int i; api->prefix.family = install_afi; + DEBUGD(&pbr_dbg_zebra, "\tEncoding %s", + prefix2str(&api->prefix, buf, sizeof(buf))); + i = 0; for (ALL_NEXTHOPS(nhg, nhop)) { api_nh = &api->nexthops[i]; @@ -284,6 +316,9 @@ void route_add(struct pbr_nexthop_group_cache *pnhgc, struct nexthop_group nhg, { struct zapi_route api; + DEBUGD(&pbr_dbg_zebra, "%s for Table: %d", __PRETTY_FUNCTION__, + pnhgc->table_id); + memset(&api, 0, sizeof(api)); api.vrf_id = VRF_DEFAULT; @@ -323,6 +358,9 @@ void route_delete(struct pbr_nexthop_group_cache *pnhgc, afi_t afi) { struct zapi_route api; + DEBUGD(&pbr_dbg_zebra, "%s for Table: %d", __PRETTY_FUNCTION__, + pnhgc->table_id); + memset(&api, 0, sizeof(api)); api.vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_PBR; diff --git a/pbrd/subdir.am b/pbrd/subdir.am index 7947559034..0f2e7ad8bd 100644 --- a/pbrd/subdir.am +++ b/pbrd/subdir.am @@ -38,5 +38,5 @@ pbrd/pbr_debug_clippy.c: $(CLIPPY_DEPS) pbrd/pbr_debug.$(OBJEXT): pbrd/pbr_debug_clippy.c pbrd_pbrd_SOURCES = pbrd/pbr_main.c -pbrd_pbrd_LDADD = pbrd/libpbr.a lib/libfrr.la @LIBCAP@ +pbrd_pbrd_LDADD = pbrd/libpbr.a lib/libfrr.la $(LIBCAP) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 7089e21513..d2d2445a15 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -62,6 +62,10 @@ #include "pim_bfd.h" #include "bfd.h" +#ifndef VTYSH_EXTRACT_PL +#include "pimd/pim_cmd_clippy.c" +#endif + static struct cmd_node interface_node = { INTERFACE_NODE, "%s(config-if)# ", 1 /* vtysh ? yes */ }; @@ -5138,6 +5142,12 @@ static int pim_rp_cmd_worker(struct pim_instance *pim, struct vty *vty, return CMD_WARNING_CONFIG_FAILED; } + if (result == PIM_GROUP_BAD_ADDR_MASK_COMBO) { + vty_out(vty, "%% Inconsistent address and mask: %s\n", + group); + return CMD_WARNING_CONFIG_FAILED; + } + return CMD_SUCCESS; } @@ -6394,6 +6404,31 @@ static int pim_cmd_interface_add(struct interface *ifp) return 1; } +DEFPY_HIDDEN (interface_ip_pim_activeactive, + interface_ip_pim_activeactive_cmd, + "[no$no] ip pim active-active", + NO_STR + IP_STR + PIM_STR + "Mark interface as Active-Active for MLAG operations, Hidden because not finished yet\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct pim_interface *pim_ifp; + + if (!no && !pim_cmd_interface_add(ifp)) { + vty_out(vty, "Could not enable PIM SM active-active on interface\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + pim_ifp = ifp->info; + if (no) + pim_ifp->activeactive = false; + else + pim_ifp->activeactive = true; + + return CMD_SUCCESS; +} + DEFUN_HIDDEN (interface_ip_pim_ssm, interface_ip_pim_ssm_cmd, "ip pim ssm", @@ -8722,6 +8757,7 @@ void pim_cmd_init(void) &interface_ip_igmp_query_max_response_time_dsec_cmd); install_element(INTERFACE_NODE, &interface_no_ip_igmp_query_max_response_time_dsec_cmd); + install_element(INTERFACE_NODE, &interface_ip_pim_activeactive_cmd); install_element(INTERFACE_NODE, &interface_ip_pim_ssm_cmd); install_element(INTERFACE_NODE, &interface_no_ip_pim_ssm_cmd); install_element(INTERFACE_NODE, &interface_ip_pim_sm_cmd); diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 0451ab1e71..6933f4d5bd 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -170,6 +170,8 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool igmp, bool pim, pim_ifp->sec_addr_list->cmp = (int (*)(void *, void *))pim_sec_addr_comp; + pim_ifp->activeactive = false; + RB_INIT(pim_ifchannel_rb, &pim_ifp->ifchannel_rb); ifp->info = pim_ifp; diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h index a7dc097f88..5066998cb5 100644 --- a/pimd/pim_iface.h +++ b/pimd/pim_iface.h @@ -124,6 +124,9 @@ struct pim_interface { /* boundary prefix-list */ char *boundary_oil_plist; + /* Turn on Active-Active for this interface */ + bool activeactive; + int64_t pim_ifstat_start; /* start timestamp for stats */ uint32_t pim_ifstat_hello_sent; uint32_t pim_ifstat_hello_sendfail; diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c index 1290bfe56b..2e12d728cf 100644 --- a/pimd/pim_oil.c +++ b/pimd/pim_oil.c @@ -392,8 +392,10 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif, if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) { - channel_oil->oif_creation[pim_ifp->mroute_vif_index] = - pim_time_monotonic_sec(); + /* Updating time here is not required as this time has to + * indicate when the interface is added + */ + channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask; /* Check the OIF really exists before returning, and only log warning otherwise */ diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index 6b76794b75..08f2ffc4ea 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -345,6 +345,7 @@ int pim_rp_new(struct pim_instance *pim, const char *rp, struct rp_info *tmp_rp_info; char buffer[BUFSIZ]; struct prefix nht_p; + struct prefix temp; struct pim_nexthop_cache pnc; struct route_node *rn; @@ -352,8 +353,17 @@ int pim_rp_new(struct pim_instance *pim, const char *rp, if (group_range == NULL) result = str2prefix("224.0.0.0/4", &rp_info->group); - else + else { result = str2prefix(group_range, &rp_info->group); + if (result) { + prefix_copy(&temp, &rp_info->group); + apply_mask(&temp); + if (!prefix_same(&rp_info->group, &temp)) { + XFREE(MTYPE_PIM_RP, rp_info); + return PIM_GROUP_BAD_ADDR_MASK_COMBO; + } + } + } if (!result) { XFREE(MTYPE_PIM_RP, rp_info); diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index f6385a0ac9..6495788748 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -362,6 +362,9 @@ int pim_interface_config_write(struct vty *vty) } } + if (pim_ifp->activeactive) + vty_out(vty, " ip pim active-active\n"); + /* boundary */ if (pim_ifp->boundary_oil_plist) { vty_out(vty, diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index b7111cf7bf..11ca6e8a10 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -267,6 +267,27 @@ static int pim_zebra_if_state_down(int command, struct zclient *zclient, return 0; } +static int pim_zebra_interface_vrf_update(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct interface *ifp; + vrf_id_t new_vrf_id; + + ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id, + &new_vrf_id); + if (!ifp) + return 0; + + if (PIM_DEBUG_ZEBRA) + zlog_debug("%s: %s updating from %u to %u", + __PRETTY_FUNCTION__, + ifp->name, vrf_id, new_vrf_id); + + if_update_to_new_vrf(ifp, new_vrf_id); + + return 0; +} + #ifdef PIM_DEBUG_IFADDR_DUMP static void dump_if_address(struct interface *ifp) { @@ -762,6 +783,7 @@ void pim_zebra_init(void) zclient->interface_down = pim_zebra_if_state_down; zclient->interface_address_add = pim_zebra_if_address_add; zclient->interface_address_delete = pim_zebra_if_address_del; + zclient->interface_vrf_update = pim_zebra_interface_vrf_update; zclient->nexthop_update = pim_parse_nexthop_update; zclient_init(zclient, ZEBRA_ROUTE_PIM, 0, &pimd_privs); diff --git a/pimd/pimd.h b/pimd/pimd.h index 73ea9f82c4..50c19658da 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -116,16 +116,17 @@ /* Remember 32 bits!!! */ /* PIM error codes */ -#define PIM_SUCCESS 0 -#define PIM_GROUP_BAD_ADDRESS -2 -#define PIM_GROUP_OVERLAP -3 -#define PIM_GROUP_PFXLIST_OVERLAP -4 -#define PIM_RP_BAD_ADDRESS -5 -#define PIM_RP_NO_PATH -6 -#define PIM_RP_NOT_FOUND -7 -#define PIM_RP_PFXLIST_IN_USE -8 -#define PIM_IFACE_NOT_FOUND -9 -#define PIM_UPDATE_SOURCE_DUP -10 +#define PIM_SUCCESS 0 +#define PIM_GROUP_BAD_ADDRESS -2 +#define PIM_GROUP_OVERLAP -3 +#define PIM_GROUP_PFXLIST_OVERLAP -4 +#define PIM_RP_BAD_ADDRESS -5 +#define PIM_RP_NO_PATH -6 +#define PIM_RP_NOT_FOUND -7 +#define PIM_RP_PFXLIST_IN_USE -8 +#define PIM_IFACE_NOT_FOUND -9 +#define PIM_UPDATE_SOURCE_DUP -10 +#define PIM_GROUP_BAD_ADDR_MASK_COMBO -11 const char *const PIM_ALL_SYSTEMS; const char *const PIM_ALL_ROUTERS; diff --git a/pimd/subdir.am b/pimd/subdir.am index fef8e36577..7d8df7d105 100644 --- a/pimd/subdir.am +++ b/pimd/subdir.am @@ -115,7 +115,10 @@ noinst_HEADERS += \ pimd/mtracebis_routeget.h \ # end -pimd_pimd_LDADD = pimd/libpim.a lib/libfrr.la @LIBCAP@ +pimd/pim_cmd_clippy.c: $(CLIPPY_DEPS) +pimd/pim_cmd.$(OBJEXT): pimd/pim_cmd_clippy.c + +pimd_pimd_LDADD = pimd/libpim.a lib/libfrr.la $(LIBCAP) pimd_pimd_SOURCES = pimd/pim_main.c pimd_test_igmpv3_join_LDADD = lib/libfrr.la diff --git a/redhat/frr.service b/redhat/frr.service index 3ae0aabfe2..01934a94e2 100644 --- a/redhat/frr.service +++ b/redhat/frr.service @@ -1,6 +1,8 @@ [Unit] Description=FRRouting (FRR) -After=syslog.target networking.service +Wants=network.target +After=network-pre.target systemd-sysctl.service +Before=network.target OnFailure=heartbeat-failed@%n.service [Service] @@ -19,5 +21,4 @@ ExecStop=/usr/lib/frr/frr stop ExecReload=/usr/lib/frr/frr reload [Install] -WantedBy=network-online.target - +WantedBy=multi-user.target diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in index 7a6344aa4c..6d18c005b9 100644 --- a/redhat/frr.spec.in +++ b/redhat/frr.spec.in @@ -171,6 +171,7 @@ BuildRequires: python27-sphinx BuildRequires: python-devel >= 2.7 BuildRequires: python-sphinx %endif +Requires: initscripts %if %{with_pam} BuildRequires: pam-devel %endif @@ -188,7 +189,6 @@ Requires(post): chkconfig Requires(preun): chkconfig # Initscripts > 5.60 is required for IPv6 support Requires(pre): initscripts >= 5.60 -Requires: initscripts %endif Provides: routingdaemon = %{version}-%{release} Obsoletes: gated mrt zebra frr-sysvinit diff --git a/ripd/rip_cli.c b/ripd/rip_cli.c index 5bb81ef157..6fbcdc059b 100644 --- a/ripd/rip_cli.c +++ b/ripd/rip_cli.c @@ -62,7 +62,7 @@ DEFPY (no_router_rip, "Enable a routing process\n" "Routing Information Protocol (RIP)\n") { - nb_cli_enqueue_change(vty, "/frr-ripd:ripd/instance", NB_OP_DELETE, + nb_cli_enqueue_change(vty, "/frr-ripd:ripd/instance", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); @@ -213,9 +213,9 @@ DEFPY (rip_distance_source, nb_cli_enqueue_change(vty, "./distance", NB_OP_MODIFY, distance_str); nb_cli_enqueue_change(vty, "./access-list", - acl ? NB_OP_MODIFY : NB_OP_DELETE, acl); + acl ? NB_OP_MODIFY : NB_OP_DESTROY, acl); } else - nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, "./distance/source[prefix='%s']", prefix_str); @@ -244,7 +244,7 @@ DEFPY (rip_neighbor, "Neighbor address\n") { nb_cli_enqueue_change(vty, "./explicit-neighbor", - no ? NB_OP_DELETE : NB_OP_CREATE, neighbor_str); + no ? NB_OP_DESTROY : NB_OP_CREATE, neighbor_str); return nb_cli_apply_changes(vty, NULL); } @@ -266,7 +266,7 @@ DEFPY (rip_network_prefix, "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n") { nb_cli_enqueue_change(vty, "./network", - no ? NB_OP_DELETE : NB_OP_CREATE, network_str); + no ? NB_OP_DESTROY : NB_OP_CREATE, network_str); return nb_cli_apply_changes(vty, NULL); } @@ -288,7 +288,7 @@ DEFPY (rip_network_if, "Interface name\n") { nb_cli_enqueue_change(vty, "./interface", - no ? NB_OP_DELETE : NB_OP_CREATE, network); + no ? NB_OP_DESTROY : NB_OP_CREATE, network); return nb_cli_apply_changes(vty, NULL); } @@ -319,7 +319,7 @@ DEFPY (rip_offset_list, nb_cli_enqueue_change(vty, "./metric", NB_OP_MODIFY, metric_str); } else - nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); return nb_cli_apply_changes( vty, "./offset-list[interface='%s'][direction='%s']", @@ -379,9 +379,9 @@ DEFPY (rip_passive_interface, "Interface name\n") { nb_cli_enqueue_change(vty, "./passive-interface", - no ? NB_OP_DELETE : NB_OP_CREATE, ifname); + no ? NB_OP_DESTROY : NB_OP_CREATE, ifname); nb_cli_enqueue_change(vty, "./non-passive-interface", - no ? NB_OP_CREATE : NB_OP_DELETE, ifname); + no ? NB_OP_CREATE : NB_OP_DESTROY, ifname); return nb_cli_apply_changes(vty, NULL); } @@ -417,13 +417,13 @@ DEFPY (rip_redistribute, if (!no) { nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); nb_cli_enqueue_change(vty, "./route-map", - route_map ? NB_OP_MODIFY : NB_OP_DELETE, + route_map ? NB_OP_MODIFY : NB_OP_DESTROY, route_map); nb_cli_enqueue_change(vty, "./metric", - metric_str ? NB_OP_MODIFY : NB_OP_DELETE, + metric_str ? NB_OP_MODIFY : NB_OP_DESTROY, metric_str); } else - nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, "./redistribute[protocol='%s']", protocol); @@ -454,7 +454,7 @@ DEFPY (rip_route, "IP prefix <network>/<length>\n") { nb_cli_enqueue_change(vty, "./static-route", - no ? NB_OP_DELETE : NB_OP_CREATE, route_str); + no ? NB_OP_DESTROY : NB_OP_CREATE, route_str); return nb_cli_apply_changes(vty, NULL); } @@ -942,7 +942,7 @@ DEFPY (no_ip_rip_authentication_key_chain, "Authentication key-chain\n" "name of key-chain\n") { - nb_cli_enqueue_change(vty, "./authentication-key-chain", NB_OP_DELETE, + nb_cli_enqueue_change(vty, "./authentication-key-chain", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, "./frr-ripd:rip"); diff --git a/ripd/rip_northbound.c b/ripd/rip_northbound.c index 4e445bd46d..1e5f86eff8 100644 --- a/ripd/rip_northbound.c +++ b/ripd/rip_northbound.c @@ -1305,7 +1305,7 @@ const struct frr_yang_module_info frr_ripd_info = { { .xpath = "/frr-ripd:ripd/instance", .cbs.create = ripd_instance_create, - .cbs.delete = ripd_instance_delete, + .cbs.destroy = ripd_instance_delete, .cbs.cli_show = cli_show_router_rip, }, { @@ -1331,7 +1331,7 @@ const struct frr_yang_module_info frr_ripd_info = { { .xpath = "/frr-ripd:ripd/instance/distance/source", .cbs.create = ripd_instance_distance_source_create, - .cbs.delete = ripd_instance_distance_source_delete, + .cbs.destroy = ripd_instance_distance_source_delete, .cbs.cli_show = cli_show_rip_distance_source, }, { @@ -1341,30 +1341,30 @@ const struct frr_yang_module_info frr_ripd_info = { { .xpath = "/frr-ripd:ripd/instance/distance/source/access-list", .cbs.modify = ripd_instance_distance_source_access_list_modify, - .cbs.delete = ripd_instance_distance_source_access_list_delete, + .cbs.destroy = ripd_instance_distance_source_access_list_delete, }, { .xpath = "/frr-ripd:ripd/instance/explicit-neighbor", .cbs.create = ripd_instance_explicit_neighbor_create, - .cbs.delete = ripd_instance_explicit_neighbor_delete, + .cbs.destroy = ripd_instance_explicit_neighbor_delete, .cbs.cli_show = cli_show_rip_neighbor, }, { .xpath = "/frr-ripd:ripd/instance/network", .cbs.create = ripd_instance_network_create, - .cbs.delete = ripd_instance_network_delete, + .cbs.destroy = ripd_instance_network_delete, .cbs.cli_show = cli_show_rip_network_prefix, }, { .xpath = "/frr-ripd:ripd/instance/interface", .cbs.create = ripd_instance_interface_create, - .cbs.delete = ripd_instance_interface_delete, + .cbs.destroy = ripd_instance_interface_delete, .cbs.cli_show = cli_show_rip_network_interface, }, { .xpath = "/frr-ripd:ripd/instance/offset-list", .cbs.create = ripd_instance_offset_list_create, - .cbs.delete = ripd_instance_offset_list_delete, + .cbs.destroy = ripd_instance_offset_list_delete, .cbs.cli_show = cli_show_rip_offset_list, }, { @@ -1383,36 +1383,36 @@ const struct frr_yang_module_info frr_ripd_info = { { .xpath = "/frr-ripd:ripd/instance/passive-interface", .cbs.create = ripd_instance_passive_interface_create, - .cbs.delete = ripd_instance_passive_interface_delete, + .cbs.destroy = ripd_instance_passive_interface_delete, .cbs.cli_show = cli_show_rip_passive_interface, }, { .xpath = "/frr-ripd:ripd/instance/non-passive-interface", .cbs.create = ripd_instance_non_passive_interface_create, - .cbs.delete = ripd_instance_non_passive_interface_delete, + .cbs.destroy = ripd_instance_non_passive_interface_delete, .cbs.cli_show = cli_show_rip_non_passive_interface, }, { .xpath = "/frr-ripd:ripd/instance/redistribute", .cbs.create = ripd_instance_redistribute_create, - .cbs.delete = ripd_instance_redistribute_delete, + .cbs.destroy = ripd_instance_redistribute_delete, .cbs.apply_finish = ripd_instance_redistribute_apply_finish, .cbs.cli_show = cli_show_rip_redistribute, }, { .xpath = "/frr-ripd:ripd/instance/redistribute/route-map", .cbs.modify = ripd_instance_redistribute_route_map_modify, - .cbs.delete = ripd_instance_redistribute_route_map_delete, + .cbs.destroy = ripd_instance_redistribute_route_map_delete, }, { .xpath = "/frr-ripd:ripd/instance/redistribute/metric", .cbs.modify = ripd_instance_redistribute_metric_modify, - .cbs.delete = ripd_instance_redistribute_metric_delete, + .cbs.destroy = ripd_instance_redistribute_metric_delete, }, { .xpath = "/frr-ripd:ripd/instance/static-route", .cbs.create = ripd_instance_static_route_create, - .cbs.delete = ripd_instance_static_route_delete, + .cbs.destroy = ripd_instance_static_route_delete, .cbs.cli_show = cli_show_rip_route, }, { @@ -1475,18 +1475,18 @@ const struct frr_yang_module_info frr_ripd_info = { { .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-scheme/md5-auth-length", .cbs.modify = lib_interface_rip_authentication_scheme_md5_auth_length_modify, - .cbs.delete = lib_interface_rip_authentication_scheme_md5_auth_length_delete, + .cbs.destroy = lib_interface_rip_authentication_scheme_md5_auth_length_delete, }, { .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-password", .cbs.modify = lib_interface_rip_authentication_password_modify, - .cbs.delete = lib_interface_rip_authentication_password_delete, + .cbs.destroy = lib_interface_rip_authentication_password_delete, .cbs.cli_show = cli_show_ip_rip_authentication_string, }, { .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-key-chain", .cbs.modify = lib_interface_rip_authentication_key_chain_modify, - .cbs.delete = lib_interface_rip_authentication_key_chain_delete, + .cbs.destroy = lib_interface_rip_authentication_key_chain_delete, .cbs.cli_show = cli_show_ip_rip_authentication_key_chain, }, { diff --git a/ripd/ripd.c b/ripd/ripd.c index 0ce5324057..38b4aed5bc 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -3438,10 +3438,13 @@ static void rip_routemap_update_redistribute(void) if (rip) { for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { - if (rip->route_map[i].name) + if (rip->route_map[i].name) { rip->route_map[i].map = route_map_lookup_by_name( rip->route_map[i].name); + route_map_counter_increment( + rip->route_map[i].map); + } } } } diff --git a/ripd/subdir.am b/ripd/subdir.am index 1c2f8d64c8..2a63cc5229 100644 --- a/ripd/subdir.am +++ b/ripd/subdir.am @@ -44,7 +44,7 @@ noinst_HEADERS += \ ripd/ripd.h \ # end -ripd_ripd_LDADD = ripd/librip.a lib/libfrr.la @LIBCAP@ +ripd_ripd_LDADD = ripd/librip.a lib/libfrr.la $(LIBCAP) ripd_ripd_SOURCES = \ ripd/rip_main.c \ # end diff --git a/ripngd/ripng_cli.c b/ripngd/ripng_cli.c index a187e80fd7..23a4803170 100644 --- a/ripngd/ripng_cli.c +++ b/ripngd/ripng_cli.c @@ -62,7 +62,7 @@ DEFPY (no_router_ripng, "Enable a routing process\n" "Make RIPng instance command\n") { - nb_cli_enqueue_change(vty, "/frr-ripngd:ripngd/instance", NB_OP_DELETE, + nb_cli_enqueue_change(vty, "/frr-ripngd:ripngd/instance", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); @@ -170,7 +170,7 @@ DEFPY (ripng_network_prefix, "IPv6 network\n") { nb_cli_enqueue_change(vty, "./network", - no ? NB_OP_DELETE : NB_OP_CREATE, network_str); + no ? NB_OP_DESTROY : NB_OP_CREATE, network_str); return nb_cli_apply_changes(vty, NULL); } @@ -192,7 +192,7 @@ DEFPY (ripng_network_if, "Interface name\n") { nb_cli_enqueue_change(vty, "./interface", - no ? NB_OP_DELETE : NB_OP_CREATE, network); + no ? NB_OP_DESTROY : NB_OP_CREATE, network); return nb_cli_apply_changes(vty, NULL); } @@ -223,7 +223,7 @@ DEFPY (ripng_offset_list, nb_cli_enqueue_change(vty, "./metric", NB_OP_MODIFY, metric_str); } else - nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); return nb_cli_apply_changes( vty, "./offset-list[interface='%s'][direction='%s']", @@ -257,7 +257,7 @@ DEFPY (ripng_passive_interface, "Interface name\n") { nb_cli_enqueue_change(vty, "./passive-interface", - no ? NB_OP_DELETE : NB_OP_CREATE, ifname); + no ? NB_OP_DESTROY : NB_OP_CREATE, ifname); return nb_cli_apply_changes(vty, NULL); } @@ -286,13 +286,13 @@ DEFPY (ripng_redistribute, if (!no) { nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); nb_cli_enqueue_change(vty, "./route-map", - route_map ? NB_OP_MODIFY : NB_OP_DELETE, + route_map ? NB_OP_MODIFY : NB_OP_DESTROY, route_map); nb_cli_enqueue_change(vty, "./metric", - metric_str ? NB_OP_MODIFY : NB_OP_DELETE, + metric_str ? NB_OP_MODIFY : NB_OP_DESTROY, metric_str); } else - nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, "./redistribute[protocol='%s']", protocol); @@ -323,7 +323,7 @@ DEFPY (ripng_route, "Set static RIPng route announcement\n") { nb_cli_enqueue_change(vty, "./static-route", - no ? NB_OP_DELETE : NB_OP_CREATE, route_str); + no ? NB_OP_DESTROY : NB_OP_CREATE, route_str); return nb_cli_apply_changes(vty, NULL); } @@ -345,7 +345,7 @@ DEFPY (ripng_aggregate_address, "Aggregate network\n") { nb_cli_enqueue_change(vty, "./aggregate-address", - no ? NB_OP_DELETE : NB_OP_CREATE, + no ? NB_OP_DESTROY : NB_OP_CREATE, aggregate_address_str); return nb_cli_apply_changes(vty, NULL); diff --git a/ripngd/ripng_northbound.c b/ripngd/ripng_northbound.c index 7993714e8d..b6998b4ddb 100644 --- a/ripngd/ripng_northbound.c +++ b/ripngd/ripng_northbound.c @@ -845,7 +845,7 @@ const struct frr_yang_module_info frr_ripngd_info = { { .xpath = "/frr-ripngd:ripngd/instance", .cbs.create = ripngd_instance_create, - .cbs.delete = ripngd_instance_delete, + .cbs.destroy = ripngd_instance_delete, .cbs.cli_show = cli_show_router_ripng, }, { @@ -866,19 +866,19 @@ const struct frr_yang_module_info frr_ripngd_info = { { .xpath = "/frr-ripngd:ripngd/instance/network", .cbs.create = ripngd_instance_network_create, - .cbs.delete = ripngd_instance_network_delete, + .cbs.destroy = ripngd_instance_network_delete, .cbs.cli_show = cli_show_ripng_network_prefix, }, { .xpath = "/frr-ripngd:ripngd/instance/interface", .cbs.create = ripngd_instance_interface_create, - .cbs.delete = ripngd_instance_interface_delete, + .cbs.destroy = ripngd_instance_interface_delete, .cbs.cli_show = cli_show_ripng_network_interface, }, { .xpath = "/frr-ripngd:ripngd/instance/offset-list", .cbs.create = ripngd_instance_offset_list_create, - .cbs.delete = ripngd_instance_offset_list_delete, + .cbs.destroy = ripngd_instance_offset_list_delete, .cbs.cli_show = cli_show_ripng_offset_list, }, { @@ -892,36 +892,36 @@ const struct frr_yang_module_info frr_ripngd_info = { { .xpath = "/frr-ripngd:ripngd/instance/passive-interface", .cbs.create = ripngd_instance_passive_interface_create, - .cbs.delete = ripngd_instance_passive_interface_delete, + .cbs.destroy = ripngd_instance_passive_interface_delete, .cbs.cli_show = cli_show_ripng_passive_interface, }, { .xpath = "/frr-ripngd:ripngd/instance/redistribute", .cbs.create = ripngd_instance_redistribute_create, - .cbs.delete = ripngd_instance_redistribute_delete, + .cbs.destroy = ripngd_instance_redistribute_delete, .cbs.apply_finish = ripngd_instance_redistribute_apply_finish, .cbs.cli_show = cli_show_ripng_redistribute, }, { .xpath = "/frr-ripngd:ripngd/instance/redistribute/route-map", .cbs.modify = ripngd_instance_redistribute_route_map_modify, - .cbs.delete = ripngd_instance_redistribute_route_map_delete, + .cbs.destroy = ripngd_instance_redistribute_route_map_delete, }, { .xpath = "/frr-ripngd:ripngd/instance/redistribute/metric", .cbs.modify = ripngd_instance_redistribute_metric_modify, - .cbs.delete = ripngd_instance_redistribute_metric_delete, + .cbs.destroy = ripngd_instance_redistribute_metric_delete, }, { .xpath = "/frr-ripngd:ripngd/instance/static-route", .cbs.create = ripngd_instance_static_route_create, - .cbs.delete = ripngd_instance_static_route_delete, + .cbs.destroy = ripngd_instance_static_route_delete, .cbs.cli_show = cli_show_ripng_route, }, { .xpath = "/frr-ripngd:ripngd/instance/aggregate-address", .cbs.create = ripngd_instance_aggregate_address_create, - .cbs.delete = ripngd_instance_aggregate_address_delete, + .cbs.destroy = ripngd_instance_aggregate_address_delete, .cbs.cli_show = cli_show_ripng_aggregate_address, }, { diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index 0022c726c5..70655beff1 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -2522,10 +2522,13 @@ static void ripng_routemap_update_redistribute(void) if (ripng) { for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { - if (ripng->route_map[i].name) + if (ripng->route_map[i].name) { ripng->route_map[i].map = route_map_lookup_by_name( ripng->route_map[i].name); + route_map_counter_increment( + ripng->route_map[i].map); + } } } } diff --git a/ripngd/subdir.am b/ripngd/subdir.am index d401e9bbf6..ea0ccf1482 100644 --- a/ripngd/subdir.am +++ b/ripngd/subdir.am @@ -40,7 +40,7 @@ noinst_HEADERS += \ ripngd/ripngd.h \ # end -ripngd_ripngd_LDADD = ripngd/libripng.a lib/libfrr.la @LIBCAP@ +ripngd_ripngd_LDADD = ripngd/libripng.a lib/libfrr.la $(LIBCAP) ripngd_ripngd_SOURCES = \ ripngd/ripng_main.c \ # end diff --git a/sharpd/Makefile b/sharpd/Makefile new file mode 100644 index 0000000000..6a904d1a6d --- /dev/null +++ b/sharpd/Makefile @@ -0,0 +1,10 @@ +all: ALWAYS + @$(MAKE) -s -C .. sharpd/sharpd +%: ALWAYS + @$(MAKE) -s -C .. sharpd/$@ + +Makefile: + #nothing +ALWAYS: +.PHONY: ALWAYS makefiles +.SUFFIXES: diff --git a/sharpd/sharp_globals.h b/sharpd/sharp_globals.h new file mode 100644 index 0000000000..065fb092d4 --- /dev/null +++ b/sharpd/sharp_globals.h @@ -0,0 +1,55 @@ +/* + * SHARP - code to track globals + * Copyright (C) 2019 Cumulus Networks, Inc. + * Donald Sharp + * + * This file is part of FRR. + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef __SHARP_GLOBAL_H__ +#define __SHARP_GLOBAL_H__ + +DECLARE_MGROUP(SHARPD) + +struct sharp_routes { + /* The original prefix for route installation */ + struct prefix orig_prefix; + + /* The nexthop group we are using for installation */ + struct nexthop nhop; + struct nexthop_group nhop_group; + + uint32_t total_routes; + uint32_t installed_routes; + uint32_t removed_routes; + int32_t repeat; + + uint8_t inst; + + struct timeval t_start; + struct timeval t_end; +}; + +struct sharp_global { + /* Global data about route install/deletions */ + struct sharp_routes r; + + /* The list of nexthops that we are watching and data about them */ + struct list *nhs; +}; + +extern struct sharp_global sg; +#endif diff --git a/sharpd/sharp_main.c b/sharpd/sharp_main.c index 175a276089..39453ee9ad 100644 --- a/sharpd/sharp_main.c +++ b/sharpd/sharp_main.c @@ -46,10 +46,9 @@ #include "sharp_zebra.h" #include "sharp_vty.h" +#include "sharp_globals.h" -uint32_t total_routes = 0; -uint32_t installed_routes = 0; -uint32_t removed_routes = 0; +DEFINE_MGROUP(SHARPD, "sharpd") zebra_capabilities_t _caps_p[] = { }; @@ -125,7 +124,13 @@ FRR_DAEMON_INFO(sharpd, SHARP, .vty_port = SHARP_VTY_PORT, .privs = &sharp_privs, .yang_modules = sharpd_yang_modules, .n_yang_modules = array_size(sharpd_yang_modules), ) -extern void sharp_vty_init(void); +struct sharp_global sg; + +static void sharp_global_init(void) +{ + memset(&sg, 0, sizeof(sg)); + sg.nhs = list_new(); +} int main(int argc, char **argv, char **envp) { @@ -151,6 +156,8 @@ int main(int argc, char **argv, char **envp) master = frr_init(); + sharp_global_init(); + nexthop_group_init(NULL, NULL, NULL, NULL); vrf_init(NULL, NULL, NULL, NULL, NULL); diff --git a/sharpd/sharp_nht.c b/sharpd/sharp_nht.c new file mode 100644 index 0000000000..174f186863 --- /dev/null +++ b/sharpd/sharp_nht.c @@ -0,0 +1,67 @@ +/* + * SHARP - code to track nexthops + * Copyright (C) Cumulus Networks, Inc. + * Donald Sharp + * + * This file is part of FRR. + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include <zebra.h> + +#include "memory.h" +#include "nexthop.h" +#include "nexthop_group.h" +#include "vty.h" + +#include "sharp_nht.h" +#include "sharp_globals.h" + +DEFINE_MTYPE_STATIC(SHARPD, NH_TRACKER, "Nexthop Tracker") + +struct sharp_nh_tracker *sharp_nh_tracker_get(struct prefix *p) +{ + struct listnode *node; + struct sharp_nh_tracker *nht; + + for (ALL_LIST_ELEMENTS_RO(sg.nhs, node, nht)) { + if (prefix_same(&nht->p, p)) + break; + } + + if (nht) + return nht; + + nht = XCALLOC(MTYPE_NH_TRACKER, sizeof(*nht)); + prefix_copy(&nht->p, p); + + listnode_add(sg.nhs, nht); + return nht; +} + +void sharp_nh_tracker_dump(struct vty *vty) +{ + struct listnode *node; + struct sharp_nh_tracker *nht; + + for (ALL_LIST_ELEMENTS_RO(sg.nhs, node, nht)) { + char buf[PREFIX_STRLEN]; + + vty_out(vty, "%s: Nexthops: %u Updates: %u\n", + prefix2str(&nht->p, buf, sizeof(buf)), + nht->nhop_num, + nht->updates); + } +} diff --git a/sharpd/sharp_nht.h b/sharpd/sharp_nht.h new file mode 100644 index 0000000000..0b00774a81 --- /dev/null +++ b/sharpd/sharp_nht.h @@ -0,0 +1,38 @@ +/* + * SHARP - code to track nexthops + * Copyright (C) Cumulus Networks, Inc. + * Donald Sharp + * + * This file is part of FRR. + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef __SHARP_NHT_H__ +#define __SHARP_NHT_H__ + +struct sharp_nh_tracker { + /* What are we watching */ + struct prefix p; + + /* Number of valid nexthops */ + uint32_t nhop_num; + + uint32_t updates; +}; + +extern struct sharp_nh_tracker *sharp_nh_tracker_get(struct prefix *p); + +extern void sharp_nh_tracker_dump(struct vty *vty); +#endif diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index 86c8bfe1c2..9018cfb359 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -30,32 +30,31 @@ #include "zclient.h" #include "nexthop_group.h" +#include "sharpd/sharp_globals.h" #include "sharpd/sharp_zebra.h" +#include "sharpd/sharp_nht.h" #include "sharpd/sharp_vty.h" #ifndef VTYSH_EXTRACT_PL #include "sharpd/sharp_vty_clippy.c" #endif -extern uint32_t total_routes; -extern uint32_t installed_routes; -extern uint32_t removed_routes; - -uint8_t inst; -struct prefix prefix; -struct prefix orig_prefix; -struct nexthop nhop; -struct nexthop_group nhop_group; -uint32_t rts; -int32_t repeat; - DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd, - "sharp watch nexthop X:X::X:X$nhop", + "sharp watch <nexthop$n|import$import> X:X::X:X$nhop [connected$connected]", "Sharp routing Protocol\n" "Watch for changes\n" "Watch for nexthop changes\n" - "The v6 nexthop to signal for watching\n") + "Watch for import check changes\n" + "The v6 nexthop to signal for watching\n" + "Should the route be connected\n") { struct prefix p; + bool type_import; + + + if (n) + type_import = false; + else + type_import = true; memset(&p, 0, sizeof(p)); @@ -63,27 +62,70 @@ DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd, memcpy(&p.u.prefix6, &nhop, 16); p.family = AF_INET6; - sharp_zebra_nexthop_watch(&p, true); + sharp_nh_tracker_get(&p); + sharp_zebra_nexthop_watch(&p, type_import, true, !!connected); return CMD_SUCCESS; } DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd, - "sharp watch nexthop A.B.C.D$nhop", + "sharp watch <nexthop$n|import$import> A.B.C.D$nhop [connected$connected]", "Sharp routing Protocol\n" "Watch for changes\n" "Watch for nexthop changes\n" - "The v4 nexthop to signal for watching\n") + "Watch for import check changes\n" + "The v4 nexthop to signal for watching\n" + "Should the route be connected\n") { struct prefix p; + bool type_import; memset(&p, 0, sizeof(p)); + if (n) + type_import = false; + else + type_import = true; + p.prefixlen = 32; p.u.prefix4 = nhop; p.family = AF_INET; - sharp_zebra_nexthop_watch(&p, true); + sharp_nh_tracker_get(&p); + sharp_zebra_nexthop_watch(&p, type_import, true, !!connected); + + return CMD_SUCCESS; +} + +DEFPY(sharp_nht_data_dump, + sharp_nht_data_dump_cmd, + "sharp data nexthop", + "Sharp routing Protocol\n" + "Nexthop information\n" + "Data Dump\n") +{ + sharp_nh_tracker_dump(vty); + + return CMD_SUCCESS; +} + +DEFPY (install_routes_data_dump, + install_routes_data_dump_cmd, + "sharp data route", + "Sharp routing Protocol\n" + "Data about what is going on\n" + "Route Install/Removal Information\n") +{ + char buf[PREFIX_STRLEN]; + struct timeval r; + + timersub(&sg.r.t_end, &sg.r.t_start, &r); + vty_out(vty, "Prefix: %s Total: %u %u %u Time: %ld.%ld\n", + prefix2str(&sg.r.orig_prefix, buf, sizeof(buf)), + sg.r.total_routes, + sg.r.installed_routes, + sg.r.removed_routes, + r.tv_sec, r.tv_usec); return CMD_SUCCESS; } @@ -107,18 +149,21 @@ DEFPY (install_routes, "Should we repeat this command\n" "How many times to repeat this command\n") { - total_routes = routes; - installed_routes = 0; + struct prefix prefix; + uint32_t rts; + + sg.r.total_routes = routes; + sg.r.installed_routes = 0; if (rpt >= 2) - repeat = rpt * 2; + sg.r.repeat = rpt * 2; else - repeat = 0; + sg.r.repeat = 0; memset(&prefix, 0, sizeof(prefix)); - memset(&orig_prefix, 0, sizeof(orig_prefix)); - memset(&nhop, 0, sizeof(nhop)); - memset(&nhop_group, 0, sizeof(nhop_group)); + memset(&sg.r.orig_prefix, 0, sizeof(sg.r.orig_prefix)); + memset(&sg.r.nhop, 0, sizeof(sg.r.nhop)); + memset(&sg.r.nhop_group, 0, sizeof(sg.r.nhop_group)); if (start4.s_addr != 0) { prefix.family = AF_INET; @@ -129,7 +174,7 @@ DEFPY (install_routes, prefix.prefixlen = 128; prefix.u.prefix6 = start6; } - orig_prefix = prefix; + sg.r.orig_prefix = prefix; if (nexthop_group) { struct nexthop_group_cmd *nhgc = nhgc_find(nexthop_group); @@ -140,22 +185,22 @@ DEFPY (install_routes, return CMD_WARNING; } - nhop_group.nexthop = nhgc->nhg.nexthop; + sg.r.nhop_group.nexthop = nhgc->nhg.nexthop; } else { if (nexthop4.s_addr != INADDR_ANY) { - nhop.gate.ipv4 = nexthop4; - nhop.type = NEXTHOP_TYPE_IPV4; + sg.r.nhop.gate.ipv4 = nexthop4; + sg.r.nhop.type = NEXTHOP_TYPE_IPV4; } else { - nhop.gate.ipv6 = nexthop6; - nhop.type = NEXTHOP_TYPE_IPV6; + sg.r.nhop.gate.ipv6 = nexthop6; + sg.r.nhop.type = NEXTHOP_TYPE_IPV6; } - nhop_group.nexthop = &nhop; + sg.r.nhop_group.nexthop = &sg.r.nhop; } - inst = instance; + sg.r.inst = instance; rts = routes; - sharp_install_routes_helper(&prefix, inst, &nhop_group, rts); + sharp_install_routes_helper(&prefix, sg.r.inst, &sg.r.nhop_group, rts); return CMD_SUCCESS; } @@ -202,8 +247,11 @@ DEFPY (remove_routes, "instance to use\n" "Value of instance\n") { - total_routes = routes; - removed_routes = 0; + struct prefix prefix; + + sg.r.total_routes = routes; + sg.r.removed_routes = 0; + uint32_t rts; memset(&prefix, 0, sizeof(prefix)); @@ -217,9 +265,9 @@ DEFPY (remove_routes, prefix.u.prefix6 = start6; } - inst = instance; + sg.r.inst = instance; rts = routes; - sharp_remove_routes_helper(&prefix, inst, rts); + sharp_remove_routes_helper(&prefix, sg.r.inst, rts); return CMD_SUCCESS; } @@ -238,9 +286,11 @@ DEFUN_NOSH (show_debugging_sharpd, void sharp_vty_init(void) { + install_element(ENABLE_NODE, &install_routes_data_dump_cmd); install_element(ENABLE_NODE, &install_routes_cmd); install_element(ENABLE_NODE, &remove_routes_cmd); install_element(ENABLE_NODE, &vrf_label_cmd); + install_element(ENABLE_NODE, &sharp_nht_data_dump_cmd); install_element(ENABLE_NODE, &watch_nexthop_v6_cmd); install_element(ENABLE_NODE, &watch_nexthop_v4_cmd); diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index c9f333e34b..4682dbc73a 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -36,6 +36,8 @@ #include "nexthop.h" #include "nexthop_group.h" +#include "sharp_globals.h" +#include "sharp_nht.h" #include "sharp_zebra.h" /* Zebra structure to hold current status. */ @@ -129,16 +131,6 @@ static int interface_state_down(int command, struct zclient *zclient, return 0; } -static struct timeval t_start; -static struct timeval t_end; -extern uint32_t total_routes; -extern uint32_t installed_routes; -extern uint32_t removed_routes; -extern int32_t repeat; -extern struct prefix orig_prefix; -extern struct nexthop_group nhop_group; -extern uint8_t inst; - void sharp_install_routes_helper(struct prefix *p, uint8_t instance, struct nexthop_group *nhg, uint32_t routes) @@ -154,7 +146,7 @@ void sharp_install_routes_helper(struct prefix *p, uint8_t instance, } else temp = ntohl(p->u.val32[3]); - monotime(&t_start); + monotime(&sg.r.t_start); for (i = 0; i < routes; i++) { route_add(p, (uint8_t)instance, nhg); if (v4) @@ -178,7 +170,7 @@ void sharp_remove_routes_helper(struct prefix *p, uint8_t instance, } else temp = ntohl(p->u.val32[3]); - monotime(&t_start); + monotime(&sg.r.t_start); for (i = 0; i < routes; i++) { route_delete(p, (uint8_t)instance); if (v4) @@ -190,21 +182,21 @@ void sharp_remove_routes_helper(struct prefix *p, uint8_t instance, static void handle_repeated(bool installed) { - struct prefix p = orig_prefix; - repeat--; + struct prefix p = sg.r.orig_prefix; + sg.r.repeat--; - if (repeat <= 0) + if (sg.r.repeat <= 0) return; if (installed) { - removed_routes = 0; - sharp_remove_routes_helper(&p, inst, total_routes); + sg.r.removed_routes = 0; + sharp_remove_routes_helper(&p, sg.r.inst, sg.r.total_routes); } - if (!installed) { - installed_routes = 0; - sharp_install_routes_helper(&p, inst, &nhop_group, - total_routes); + if (installed) { + sg.r.installed_routes = 0; + sharp_install_routes_helper(&p, sg.r.inst, &sg.r.nhop_group, + sg.r.total_routes); } } @@ -221,10 +213,10 @@ static int route_notify_owner(int command, struct zclient *zclient, switch (note) { case ZAPI_ROUTE_INSTALLED: - installed_routes++; - if (total_routes == installed_routes) { - monotime(&t_end); - timersub(&t_end, &t_start, &r); + sg.r.installed_routes++; + if (sg.r.total_routes == sg.r.installed_routes) { + monotime(&sg.r.t_end); + timersub(&sg.r.t_end, &sg.r.t_start, &r); zlog_debug("Installed All Items %ld.%ld", r.tv_sec, r.tv_usec); handle_repeated(true); @@ -237,10 +229,10 @@ static int route_notify_owner(int command, struct zclient *zclient, zlog_debug("Better Admin Distance won over us"); break; case ZAPI_ROUTE_REMOVED: - removed_routes++; - if (total_routes == removed_routes) { - monotime(&t_end); - timersub(&t_end, &t_start, &r); + sg.r.removed_routes++; + if (sg.r.total_routes == sg.r.removed_routes) { + monotime(&sg.r.t_end); + timersub(&sg.r.t_end, &sg.r.t_start, &r); zlog_debug("Removed all Items %ld.%ld", r.tv_sec, r.tv_usec); handle_repeated(false); @@ -328,14 +320,24 @@ void route_delete(struct prefix *p, uint8_t instance) return; } -void sharp_zebra_nexthop_watch(struct prefix *p, bool watch) +void sharp_zebra_nexthop_watch(struct prefix *p, bool import, + bool watch, bool connected) { - int command = ZEBRA_NEXTHOP_REGISTER; + int command; - if (!watch) - command = ZEBRA_NEXTHOP_UNREGISTER; + if (!import) { + command = ZEBRA_NEXTHOP_REGISTER; - if (zclient_send_rnh(zclient, command, p, true, VRF_DEFAULT) < 0) + if (!watch) + command = ZEBRA_NEXTHOP_UNREGISTER; + } else { + command = ZEBRA_IMPORT_ROUTE_REGISTER; + + if (!watch) + command = ZEBRA_IMPORT_ROUTE_UNREGISTER; + } + + if (zclient_send_rnh(zclient, command, p, connected, VRF_DEFAULT) < 0) zlog_warn("%s: Failure to send nexthop to zebra", __PRETTY_FUNCTION__); } @@ -343,6 +345,7 @@ void sharp_zebra_nexthop_watch(struct prefix *p, bool watch) static int sharp_nexthop_update(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { + struct sharp_nh_tracker *nht; struct zapi_route nhr; char buf[PREFIX_STRLEN]; int i; @@ -355,6 +358,11 @@ static int sharp_nexthop_update(int command, struct zclient *zclient, zlog_debug("Received update for %s", prefix2str(&nhr.prefix, buf, sizeof(buf))); + + nht = sharp_nh_tracker_get(&nhr.prefix); + nht->nhop_num = nhr.nexthop_num; + nht->updates++; + for (i = 0; i < nhr.nexthop_num; i++) { struct zapi_nexthop *znh = &nhr.nexthops[i]; @@ -407,4 +415,5 @@ void sharp_zebra_init(void) zclient->interface_address_delete = interface_address_delete; zclient->route_notify_owner = route_notify_owner; zclient->nexthop_update = sharp_nexthop_update; + zclient->import_check_update = sharp_nexthop_update; } diff --git a/sharpd/sharp_zebra.h b/sharpd/sharp_zebra.h index 7326056cae..b219022f02 100644 --- a/sharpd/sharp_zebra.h +++ b/sharpd/sharp_zebra.h @@ -28,7 +28,8 @@ extern void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label); extern void route_add(struct prefix *p, uint8_t instance, struct nexthop_group *nhg); extern void route_delete(struct prefix *p, uint8_t instance); -extern void sharp_zebra_nexthop_watch(struct prefix *p, bool watch); +extern void sharp_zebra_nexthop_watch(struct prefix *p, bool import, + bool watch, bool connected); extern void sharp_install_routes_helper(struct prefix *p, uint8_t instance, struct nexthop_group *nhg, diff --git a/sharpd/subdir.am b/sharpd/subdir.am index 2a34aecfb3..4a9028f6fe 100644 --- a/sharpd/subdir.am +++ b/sharpd/subdir.am @@ -11,12 +11,15 @@ man8 += $(MANBUILD)/sharpd.8 endif sharpd_libsharp_a_SOURCES = \ + sharpd/sharp_nht.c \ sharpd/sharp_zebra.c \ sharpd/sharp_vty.c \ # end noinst_HEADERS += \ + sharpd/sharp_nht.h \ sharpd/sharp_vty.h \ + sharpd/sharp_globals.h \ sharpd/sharp_zebra.h \ # end @@ -24,5 +27,5 @@ sharpd/sharp_vty_clippy.c: $(CLIPPY_DEPS) sharpd/sharp_vty.$(OBJEXT): sharpd/sharp_vty_clippy.c sharpd_sharpd_SOURCES = sharpd/sharp_main.c -sharpd_sharpd_LDADD = sharpd/libsharp.a lib/libfrr.la @LIBCAP@ +sharpd_sharpd_LDADD = sharpd/libsharp.a lib/libfrr.la $(LIBCAP) diff --git a/staticd/subdir.am b/staticd/subdir.am index 33cc0e2050..17c4536fe9 100644 --- a/staticd/subdir.am +++ b/staticd/subdir.am @@ -32,4 +32,4 @@ staticd/static_vty_clippy.c: $(CLIPPY_DEPS) staticd/static_vty.$(OBJEXT): staticd/static_vty_clippy.c staticd_staticd_SOURCES = staticd/static_main.c -staticd_staticd_LDADD = staticd/libstatic.a lib/libfrr.la @LIBCAP@ +staticd_staticd_LDADD = staticd/libstatic.a lib/libfrr.la $(LIBCAP) diff --git a/tests/.gitignore b/tests/.gitignore index 5453c0d80a..de648015f1 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -19,6 +19,7 @@ /lib/cli/test_commands /lib/cli/test_commands_defun.c /lib/northbound/test_oper_data +/lib/cxxcompat /lib/test_buffer /lib/test_checksum /lib/test_graph diff --git a/tests/Makefile.in b/tests/Makefile.in new file mode 100644 index 0000000000..29d903e70a --- /dev/null +++ b/tests/Makefile.in @@ -0,0 +1,1338 @@ +# Makefile.in generated by automake 1.15.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2017 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Automake fragment intended to be shared by Makefile.am files in the +# tree. +# + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +check_PROGRAMS = lib/test_buffer$(EXEEXT) lib/test_checksum$(EXEEXT) \ + lib/test_heavy_thread$(EXEEXT) lib/test_heavy_wq$(EXEEXT) \ + lib/test_heavy$(EXEEXT) lib/test_memory$(EXEEXT) \ + lib/test_nexthop_iter$(EXEEXT) lib/test_privs$(EXEEXT) \ + lib/test_ringbuf$(EXEEXT) lib/test_srcdest_table$(EXEEXT) \ + lib/test_segv$(EXEEXT) lib/test_sig$(EXEEXT) \ + lib/test_stream$(EXEEXT) lib/test_table$(EXEEXT) \ + lib/test_timer_correctness$(EXEEXT) \ + lib/test_timer_performance$(EXEEXT) lib/test_ttable$(EXEEXT) \ + lib/cli/test_cli$(EXEEXT) lib/cli/test_commands$(EXEEXT) \ + $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \ + $(am__EXEEXT_4) +@ZEROMQ_TRUE@am__append_1 = \ +@ZEROMQ_TRUE@ lib/test_zmq \ +@ZEROMQ_TRUE@ # end + +subdir = tests +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ax_compare_version.m4 \ + $(top_srcdir)/m4/ax_pthread.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/pkg.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ + $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +@BGPD_TRUE@am__EXEEXT_1 = bgpd/test_aspath$(EXEEXT) \ +@BGPD_TRUE@ bgpd/test_capability$(EXEEXT) \ +@BGPD_TRUE@ bgpd/test_packet$(EXEEXT) \ +@BGPD_TRUE@ bgpd/test_ecommunity$(EXEEXT) \ +@BGPD_TRUE@ bgpd/test_mp_attr$(EXEEXT) bgpd/test_mpath$(EXEEXT) +@ISISD_TRUE@@SOLARIS_FALSE@am__EXEEXT_2 = \ +@ISISD_TRUE@@SOLARIS_FALSE@ isisd/test_fuzz_isis_tlv$(EXEEXT) \ +@ISISD_TRUE@@SOLARIS_FALSE@ isisd/test_isis_vertex_queue$(EXEEXT) +@OSPF6D_TRUE@am__EXEEXT_3 = ospf6d/test_lsdb$(EXEEXT) +@ZEROMQ_TRUE@am__EXEEXT_4 = lib/test_zmq$(EXEEXT) +am__dirstamp = $(am__leading_dot)dirstamp +am_bgpd_test_aspath_OBJECTS = bgpd/test_aspath.$(OBJEXT) +bgpd_test_aspath_OBJECTS = $(am_bgpd_test_aspath_OBJECTS) +@ENABLE_BGP_VNC_TRUE@am__DEPENDENCIES_1 = \ +@ENABLE_BGP_VNC_TRUE@ @top_builddir@/$(LIBRFP)/librfp.a +am__DEPENDENCIES_2 = ../lib/libfrr.la +am__DEPENDENCIES_3 = ../bgpd/libbgp.a $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_2) +bgpd_test_aspath_DEPENDENCIES = $(am__DEPENDENCIES_3) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +am_bgpd_test_capability_OBJECTS = bgpd/test_capability.$(OBJEXT) +bgpd_test_capability_OBJECTS = $(am_bgpd_test_capability_OBJECTS) +bgpd_test_capability_DEPENDENCIES = $(am__DEPENDENCIES_3) +am_bgpd_test_ecommunity_OBJECTS = bgpd/test_ecommunity.$(OBJEXT) +bgpd_test_ecommunity_OBJECTS = $(am_bgpd_test_ecommunity_OBJECTS) +bgpd_test_ecommunity_DEPENDENCIES = $(am__DEPENDENCIES_3) +am_bgpd_test_mp_attr_OBJECTS = bgpd/test_mp_attr.$(OBJEXT) +bgpd_test_mp_attr_OBJECTS = $(am_bgpd_test_mp_attr_OBJECTS) +bgpd_test_mp_attr_DEPENDENCIES = $(am__DEPENDENCIES_3) +am_bgpd_test_mpath_OBJECTS = bgpd/test_mpath.$(OBJEXT) +bgpd_test_mpath_OBJECTS = $(am_bgpd_test_mpath_OBJECTS) +bgpd_test_mpath_DEPENDENCIES = $(am__DEPENDENCIES_3) +am_bgpd_test_packet_OBJECTS = bgpd/test_packet.$(OBJEXT) +bgpd_test_packet_OBJECTS = $(am_bgpd_test_packet_OBJECTS) +bgpd_test_packet_DEPENDENCIES = $(am__DEPENDENCIES_3) +am_isisd_test_fuzz_isis_tlv_OBJECTS = \ + isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.$(OBJEXT) +isisd_test_fuzz_isis_tlv_OBJECTS = \ + $(am_isisd_test_fuzz_isis_tlv_OBJECTS) +am__DEPENDENCIES_4 = ../isisd/libisis.a $(am__DEPENDENCIES_2) +isisd_test_fuzz_isis_tlv_DEPENDENCIES = $(am__DEPENDENCIES_4) +am_isisd_test_isis_vertex_queue_OBJECTS = \ + isisd/test_isis_vertex_queue.$(OBJEXT) +isisd_test_isis_vertex_queue_OBJECTS = \ + $(am_isisd_test_isis_vertex_queue_OBJECTS) +isisd_test_isis_vertex_queue_DEPENDENCIES = $(am__DEPENDENCIES_4) +am_lib_cli_test_cli_OBJECTS = lib/cli/test_cli.$(OBJEXT) \ + lib/cli/common_cli.$(OBJEXT) +lib_cli_test_cli_OBJECTS = $(am_lib_cli_test_cli_OBJECTS) +lib_cli_test_cli_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_cli_test_commands_OBJECTS = \ + lib/cli/test_commands_defun.$(OBJEXT) \ + lib/cli/test_commands.$(OBJEXT) helpers/c/prng.$(OBJEXT) +lib_cli_test_commands_OBJECTS = $(am_lib_cli_test_commands_OBJECTS) +lib_cli_test_commands_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_buffer_OBJECTS = lib/test_buffer.$(OBJEXT) +lib_test_buffer_OBJECTS = $(am_lib_test_buffer_OBJECTS) +lib_test_buffer_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_checksum_OBJECTS = lib/test_checksum.$(OBJEXT) +lib_test_checksum_OBJECTS = $(am_lib_test_checksum_OBJECTS) +lib_test_checksum_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_heavy_OBJECTS = lib/test_heavy.$(OBJEXT) \ + helpers/c/main.$(OBJEXT) +lib_test_heavy_OBJECTS = $(am_lib_test_heavy_OBJECTS) +lib_test_heavy_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_heavy_thread_OBJECTS = lib/test_heavy_thread.$(OBJEXT) \ + helpers/c/main.$(OBJEXT) +lib_test_heavy_thread_OBJECTS = $(am_lib_test_heavy_thread_OBJECTS) +lib_test_heavy_thread_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_heavy_wq_OBJECTS = lib/test_heavy_wq.$(OBJEXT) \ + helpers/c/main.$(OBJEXT) +lib_test_heavy_wq_OBJECTS = $(am_lib_test_heavy_wq_OBJECTS) +lib_test_heavy_wq_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_memory_OBJECTS = lib/test_memory.$(OBJEXT) +lib_test_memory_OBJECTS = $(am_lib_test_memory_OBJECTS) +lib_test_memory_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_nexthop_iter_OBJECTS = lib/test_nexthop_iter.$(OBJEXT) \ + helpers/c/prng.$(OBJEXT) +lib_test_nexthop_iter_OBJECTS = $(am_lib_test_nexthop_iter_OBJECTS) +lib_test_nexthop_iter_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_privs_OBJECTS = lib/test_privs.$(OBJEXT) +lib_test_privs_OBJECTS = $(am_lib_test_privs_OBJECTS) +lib_test_privs_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_ringbuf_OBJECTS = lib/test_ringbuf.$(OBJEXT) +lib_test_ringbuf_OBJECTS = $(am_lib_test_ringbuf_OBJECTS) +lib_test_ringbuf_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_segv_OBJECTS = lib/test_segv.$(OBJEXT) +lib_test_segv_OBJECTS = $(am_lib_test_segv_OBJECTS) +lib_test_segv_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_sig_OBJECTS = lib/test_sig.$(OBJEXT) +lib_test_sig_OBJECTS = $(am_lib_test_sig_OBJECTS) +lib_test_sig_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_srcdest_table_OBJECTS = lib/test_srcdest_table.$(OBJEXT) \ + helpers/c/prng.$(OBJEXT) +lib_test_srcdest_table_OBJECTS = $(am_lib_test_srcdest_table_OBJECTS) +lib_test_srcdest_table_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_stream_OBJECTS = lib/test_stream.$(OBJEXT) +lib_test_stream_OBJECTS = $(am_lib_test_stream_OBJECTS) +lib_test_stream_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_table_OBJECTS = lib/test_table.$(OBJEXT) +lib_test_table_OBJECTS = $(am_lib_test_table_OBJECTS) +lib_test_table_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_timer_correctness_OBJECTS = \ + lib/test_timer_correctness.$(OBJEXT) helpers/c/prng.$(OBJEXT) +lib_test_timer_correctness_OBJECTS = \ + $(am_lib_test_timer_correctness_OBJECTS) +lib_test_timer_correctness_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_timer_performance_OBJECTS = \ + lib/test_timer_performance.$(OBJEXT) helpers/c/prng.$(OBJEXT) +lib_test_timer_performance_OBJECTS = \ + $(am_lib_test_timer_performance_OBJECTS) +lib_test_timer_performance_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_ttable_OBJECTS = lib/test_ttable.$(OBJEXT) +lib_test_ttable_OBJECTS = $(am_lib_test_ttable_OBJECTS) +lib_test_ttable_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_lib_test_zmq_OBJECTS = lib/lib_test_zmq-test_zmq.$(OBJEXT) +lib_test_zmq_OBJECTS = $(am_lib_test_zmq_OBJECTS) +am__DEPENDENCIES_5 = +lib_test_zmq_DEPENDENCIES = ../lib/libfrrzmq.la $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_5) +lib_test_zmq_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(lib_test_zmq_CFLAGS) \ + $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +am_ospf6d_test_lsdb_OBJECTS = ospf6d/test_lsdb.$(OBJEXT) \ + lib/cli/common_cli.$(OBJEXT) +ospf6d_test_lsdb_OBJECTS = $(am_ospf6d_test_lsdb_OBJECTS) +am__DEPENDENCIES_6 = ../ospf6d/libospf6.a $(am__DEPENDENCIES_2) +ospf6d_test_lsdb_DEPENDENCIES = $(am__DEPENDENCIES_6) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(bgpd_test_aspath_SOURCES) $(bgpd_test_capability_SOURCES) \ + $(bgpd_test_ecommunity_SOURCES) $(bgpd_test_mp_attr_SOURCES) \ + $(bgpd_test_mpath_SOURCES) $(bgpd_test_packet_SOURCES) \ + $(isisd_test_fuzz_isis_tlv_SOURCES) \ + $(isisd_test_isis_vertex_queue_SOURCES) \ + $(lib_cli_test_cli_SOURCES) $(lib_cli_test_commands_SOURCES) \ + $(lib_test_buffer_SOURCES) $(lib_test_checksum_SOURCES) \ + $(lib_test_heavy_SOURCES) $(lib_test_heavy_thread_SOURCES) \ + $(lib_test_heavy_wq_SOURCES) $(lib_test_memory_SOURCES) \ + $(lib_test_nexthop_iter_SOURCES) $(lib_test_privs_SOURCES) \ + $(lib_test_ringbuf_SOURCES) $(lib_test_segv_SOURCES) \ + $(lib_test_sig_SOURCES) $(lib_test_srcdest_table_SOURCES) \ + $(lib_test_stream_SOURCES) $(lib_test_table_SOURCES) \ + $(lib_test_timer_correctness_SOURCES) \ + $(lib_test_timer_performance_SOURCES) \ + $(lib_test_ttable_SOURCES) $(lib_test_zmq_SOURCES) \ + $(ospf6d_test_lsdb_SOURCES) +DIST_SOURCES = $(bgpd_test_aspath_SOURCES) \ + $(bgpd_test_capability_SOURCES) \ + $(bgpd_test_ecommunity_SOURCES) $(bgpd_test_mp_attr_SOURCES) \ + $(bgpd_test_mpath_SOURCES) $(bgpd_test_packet_SOURCES) \ + $(isisd_test_fuzz_isis_tlv_SOURCES) \ + $(isisd_test_isis_vertex_queue_SOURCES) \ + $(lib_cli_test_cli_SOURCES) $(lib_cli_test_commands_SOURCES) \ + $(lib_test_buffer_SOURCES) $(lib_test_checksum_SOURCES) \ + $(lib_test_heavy_SOURCES) $(lib_test_heavy_thread_SOURCES) \ + $(lib_test_heavy_wq_SOURCES) $(lib_test_memory_SOURCES) \ + $(lib_test_nexthop_iter_SOURCES) $(lib_test_privs_SOURCES) \ + $(lib_test_ringbuf_SOURCES) $(lib_test_segv_SOURCES) \ + $(lib_test_sig_SOURCES) $(lib_test_srcdest_table_SOURCES) \ + $(lib_test_stream_SOURCES) $(lib_test_table_SOURCES) \ + $(lib_test_timer_correctness_SOURCES) \ + $(lib_test_timer_performance_SOURCES) \ + $(lib_test_ttable_SOURCES) $(lib_test_zmq_SOURCES) \ + $(ospf6d_test_lsdb_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(noinst_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/../common.am $(srcdir)/Makefile.in \ + $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BGPD = @BGPD@ +BISON_CLOSEBRACE = @BISON_CLOSEBRACE@ +BISON_OPENBRACE = @BISON_OPENBRACE@ +BISON_VERBOSE = @BISON_VERBOSE@ +CARES_CFLAGS = @CARES_CFLAGS@ +CARES_LIBS = @CARES_LIBS@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFG_MODULE = @CFG_MODULE@ +CFG_SBIN = @CFG_SBIN@ +CFG_STATE = @CFG_STATE@ +CFG_SYSCONF = @CFG_SYSCONF@ +CFLAGS = @CFLAGS@ +CONFDATE = @CONFDATE@ +CONFIG_ARGS = @CONFIG_ARGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CURSES = @CURSES@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" +DEPDIR = @DEPDIR@ +DFLT_NAME = @DFLT_NAME@ +DLLTOOL = @DLLTOOL@ +DOC = @DOC@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ +HOSTTOOLS = @HOSTTOOLS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCAP = @LIBCAP@ +LIBM = @LIBM@ +LIBOBJS = @LIBOBJS@ +LIBPAM = @LIBPAM@ +LIBREADLINE = @LIBREADLINE@ +LIBRFP = @LIBRFP@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NETSNMP_CONFIG = @NETSNMP_CONFIG@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_EXTRAVERSION = @PACKAGE_EXTRAVERSION@ +PACKAGE_FULLNAME = @PACKAGE_FULLNAME@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PROTOBUF_C_CFLAGS = @PROTOBUF_C_CFLAGS@ +PROTOBUF_C_LIBS = @PROTOBUF_C_LIBS@ +PROTOC_C = @PROTOC_C@ +PTHREAD_CC = @PTHREAD_CC@ +PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +PYTHONCONFIG = @PYTHONCONFIG@ +PYTHON_CFLAGS = @PYTHON_CFLAGS@ +PYTHON_LIBS = @PYTHON_LIBS@ +RANLIB = @RANLIB@ +RFPINC = @RFPINC@ +RFPTEST = @RFPTEST@ +RTRLIB_CFLAGS = @RTRLIB_CFLAGS@ +RTRLIB_LIBS = @RTRLIB_LIBS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SNMP_CFLAGS = @SNMP_CFLAGS@ +SNMP_LIBS = @SNMP_LIBS@ +SOLARIS = @SOLARIS@ +STRIP = @STRIP@ +VERSION = @VERSION@ +VNC_RFP_PATH = @VNC_RFP_PATH@ +VTYSH = @VTYSH@ +WERROR = @WERROR@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZEROMQ_CFLAGS = @ZEROMQ_CFLAGS@ +ZEROMQ_LIBS = @ZEROMQ_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_PYTHONCONFIG = @ac_ct_PYTHONCONFIG@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +ax_pthread_config = @ax_pthread_config@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_group = @enable_group@ +enable_user = @enable_user@ +enable_vty_group = @enable_vty_group@ +exampledir = @exampledir@ +exec_prefix = @exec_prefix@ +frr_statedir = @frr_statedir@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +moduledir = @moduledir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgsrcrcdir = @pkgsrcrcdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AM_V_CLIPPY = $(am__v_CLIPPY_$(V)) +am__v_CLIPPY_ = $(am__v_CLIPPY_$(AM_DEFAULT_VERBOSITY)) +am__v_CLIPPY_0 = @echo " CLIPPY " $@; +am__v_CLIPPY_1 = +CLIPPY_DEPS = $(HOSTTOOLS)lib/clippy $(top_srcdir)/python/clidef.py +SUFFIXES = _clippy.c .proto .pb-c.c .pb-c.h .pb.h + +# Uncomment to use an non-system version of libprotobuf-c. +# +# Q_PROTOBUF_C_CLIENT_INCLUDES = -I$(top_srcdir)/third-party/protobuf-c/src +# Q_PROTOBUF_C_CLIENT_LDOPTS = $(top_builddir)/third-party/protobuf-c/src/libprotobuf-c.la +@HAVE_PROTOBUF_TRUE@Q_PROTOBUF_C_CLIENT_INCLUDES = +@HAVE_PROTOBUF_TRUE@Q_PROTOBUF_C_CLIENT_LDOPTS = -lprotobuf-c +@HAVE_PROTOBUF_TRUE@Q_PROTOC = protoc +@HAVE_PROTOBUF_TRUE@Q_PROTOC_C = protoc-c +@HAVE_PROTOBUF_TRUE@AM_V_PROTOC_C = $(am__v_PROTOC_C_$(V)) +@HAVE_PROTOBUF_TRUE@am__v_PROTOC_C_ = $(am__v_PROTOC_C_$(AM_DEFAULT_VERBOSITY)) +@HAVE_PROTOBUF_TRUE@am__v_PROTOC_C_0 = @echo " PROTOC_C" $@; +@HAVE_PROTOBUF_TRUE@am__v_PROTOC_C_1 = + +# +# Information about how to link to various libraries. +# +@HAVE_PROTOBUF_TRUE@Q_FRR_PB_CLIENT_LDOPTS = $(top_srcdir)/qpb/libfrr_pb.la $(Q_PROTOBUF_C_CLIENT_LDOPTS) +@HAVE_PROTOBUF_TRUE@Q_FPM_PB_CLIENT_LDOPTS = $(top_srcdir)/fpm/libfrrfpm_pb.la $(Q_FRR_PB_CLIENT_LDOPTS) +AUTOMAKE_OPTIONS = subdir-objects +AM_CPPFLAGS = \ + -I.. \ + -I$(top_srcdir) \ + -I$(top_srcdir)/lib \ + -I$(top_builddir)/lib \ + -I$(top_srcdir)/tests/helpers/c \ + -I$(top_builddir)/tests/helpers/c \ + -O + +@BGPD_FALSE@TESTS_BGPD = +@BGPD_TRUE@TESTS_BGPD = \ +@BGPD_TRUE@ bgpd/test_aspath \ +@BGPD_TRUE@ bgpd/test_capability \ +@BGPD_TRUE@ bgpd/test_packet \ +@BGPD_TRUE@ bgpd/test_ecommunity \ +@BGPD_TRUE@ bgpd/test_mp_attr \ +@BGPD_TRUE@ bgpd/test_mpath + +@ISISD_FALSE@TESTS_ISISD = +@ISISD_TRUE@@SOLARIS_FALSE@TESTS_ISISD = \ +@ISISD_TRUE@@SOLARIS_FALSE@ isisd/test_fuzz_isis_tlv \ +@ISISD_TRUE@@SOLARIS_FALSE@ isisd/test_isis_vertex_queue \ +@ISISD_TRUE@@SOLARIS_FALSE@ # end + +@ISISD_TRUE@@SOLARIS_TRUE@TESTS_ISISD = +@OSPF6D_FALSE@TESTS_OSPF6D = +@OSPF6D_TRUE@TESTS_OSPF6D = \ +@OSPF6D_TRUE@ ospf6d/test_lsdb \ +@OSPF6D_TRUE@ # end + +@ENABLE_BGP_VNC_FALSE@BGP_VNC_RFP_LIB = +@ENABLE_BGP_VNC_TRUE@BGP_VNC_RFP_LIB = @top_builddir@/$(LIBRFP)/librfp.a +noinst_HEADERS = \ + ./helpers/c/prng.h \ + ./helpers/c/tests.h \ + ./lib/cli/common_cli.h + +lib_test_buffer_SOURCES = lib/test_buffer.c +lib_test_checksum_SOURCES = lib/test_checksum.c +lib_test_heavy_thread_SOURCES = lib/test_heavy_thread.c helpers/c/main.c +lib_test_heavy_wq_SOURCES = lib/test_heavy_wq.c helpers/c/main.c +lib_test_heavy_SOURCES = lib/test_heavy.c helpers/c/main.c +lib_test_memory_SOURCES = lib/test_memory.c +lib_test_nexthop_iter_SOURCES = lib/test_nexthop_iter.c helpers/c/prng.c +lib_test_privs_SOURCES = lib/test_privs.c +lib_test_srcdest_table_SOURCES = lib/test_srcdest_table.c \ + helpers/c/prng.c + +lib_test_ringbuf_SOURCES = lib/test_ringbuf.c +lib_test_segv_SOURCES = lib/test_segv.c +lib_test_sig_SOURCES = lib/test_sig.c +lib_test_stream_SOURCES = lib/test_stream.c +lib_test_table_SOURCES = lib/test_table.c +lib_test_timer_correctness_SOURCES = lib/test_timer_correctness.c \ + helpers/c/prng.c + +lib_test_timer_performance_SOURCES = lib/test_timer_performance.c \ + helpers/c/prng.c + +lib_test_ttable_SOURCES = lib/test_ttable.c +lib_test_zmq_SOURCES = lib/test_zmq.c +lib_test_zmq_CFLAGS = $(AM_CFLAGS) $(ZEROMQ_CFLAGS) +lib_cli_test_cli_SOURCES = lib/cli/test_cli.c lib/cli/common_cli.c +lib_cli_test_commands_SOURCES = lib/cli/test_commands_defun.c \ + lib/cli/test_commands.c \ + helpers/c/prng.c + +bgpd_test_aspath_SOURCES = bgpd/test_aspath.c +bgpd_test_capability_SOURCES = bgpd/test_capability.c +bgpd_test_packet_SOURCES = bgpd/test_packet.c +bgpd_test_ecommunity_SOURCES = bgpd/test_ecommunity.c +bgpd_test_mp_attr_SOURCES = bgpd/test_mp_attr.c +bgpd_test_mpath_SOURCES = bgpd/test_mpath.c +isisd_test_fuzz_isis_tlv_SOURCES = isisd/test_fuzz_isis_tlv.c +isisd_test_fuzz_isis_tlv_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_builddir)/tests/isisd +isisd_test_isis_vertex_queue_SOURCES = isisd/test_isis_vertex_queue.c +ospf6d_test_lsdb_SOURCES = ospf6d/test_lsdb.c lib/cli/common_cli.c +ALL_TESTS_LDADD = ../lib/libfrr.la @LIBCAP@ +BGP_TEST_LDADD = ../bgpd/libbgp.a $(BGP_VNC_RFP_LIB) $(ALL_TESTS_LDADD) -lm +ISISD_TEST_LDADD = ../isisd/libisis.a $(ALL_TESTS_LDADD) +OSPF6_TEST_LDADD = ../ospf6d/libospf6.a $(ALL_TESTS_LDADD) +lib_test_buffer_LDADD = $(ALL_TESTS_LDADD) +lib_test_checksum_LDADD = $(ALL_TESTS_LDADD) +lib_test_heavy_thread_LDADD = $(ALL_TESTS_LDADD) -lm +lib_test_heavy_wq_LDADD = $(ALL_TESTS_LDADD) -lm +lib_test_heavy_LDADD = $(ALL_TESTS_LDADD) -lm +lib_test_memory_LDADD = $(ALL_TESTS_LDADD) +lib_test_nexthop_iter_LDADD = $(ALL_TESTS_LDADD) +lib_test_privs_LDADD = $(ALL_TESTS_LDADD) +lib_test_ringbuf_LDADD = $(ALL_TESTS_LDADD) +lib_test_srcdest_table_LDADD = $(ALL_TESTS_LDADD) +lib_test_segv_LDADD = $(ALL_TESTS_LDADD) +lib_test_sig_LDADD = $(ALL_TESTS_LDADD) +lib_test_stream_LDADD = $(ALL_TESTS_LDADD) +lib_test_table_LDADD = $(ALL_TESTS_LDADD) -lm +lib_test_timer_correctness_LDADD = $(ALL_TESTS_LDADD) +lib_test_timer_performance_LDADD = $(ALL_TESTS_LDADD) +lib_test_ttable_LDADD = $(ALL_TESTS_LDADD) +lib_test_zmq_LDADD = ../lib/libfrrzmq.la $(ALL_TESTS_LDADD) $(ZEROMQ_LIBS) +lib_cli_test_cli_LDADD = $(ALL_TESTS_LDADD) +lib_cli_test_commands_LDADD = $(ALL_TESTS_LDADD) +bgpd_test_aspath_LDADD = $(BGP_TEST_LDADD) +bgpd_test_capability_LDADD = $(BGP_TEST_LDADD) +bgpd_test_packet_LDADD = $(BGP_TEST_LDADD) +bgpd_test_ecommunity_LDADD = $(BGP_TEST_LDADD) +bgpd_test_mp_attr_LDADD = $(BGP_TEST_LDADD) +bgpd_test_mpath_LDADD = $(BGP_TEST_LDADD) +isisd_test_fuzz_isis_tlv_LDADD = $(ISISD_TEST_LDADD) +isisd_test_isis_vertex_queue_LDADD = $(ISISD_TEST_LDADD) +ospf6d_test_lsdb_LDADD = $(OSPF6_TEST_LDADD) +EXTRA_DIST = \ + runtests.py \ + bgpd/test_aspath.py \ + bgpd/test_capability.py \ + bgpd/test_ecommunity.py \ + bgpd/test_mp_attr.py \ + bgpd/test_mpath.py \ + helpers/python/frrsix.py \ + helpers/python/frrtest.py \ + isisd/test_fuzz_isis_tlv.py \ + isisd/test_fuzz_isis_tlv_tests.h.gz \ + isisd/test_isis_vertex_queue.py \ + lib/cli/test_commands.in \ + lib/cli/test_commands.py \ + lib/cli/test_commands.refout \ + lib/cli/test_cli.in \ + lib/cli/test_cli.py \ + lib/cli/test_cli.refout \ + lib/test_nexthop_iter.py \ + lib/test_ringbuf.py \ + lib/test_srcdest_table.py \ + lib/test_stream.py \ + lib/test_stream.refout \ + lib/test_table.py \ + lib/test_timer_correctness.py \ + lib/test_ttable.py \ + lib/test_ttable.refout \ + ospf6d/test_lsdb.py \ + ospf6d/test_lsdb.in \ + ospf6d/test_lsdb.refout \ + # end + +all: all-am + +.SUFFIXES: +.SUFFIXES: _clippy.c .proto .pb-c.c .pb-c.h .pb.h .c .l .lo .o .obj .y +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(srcdir)/../common.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tests/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu tests/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; +$(srcdir)/../common.am $(am__empty): + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +bgpd/$(am__dirstamp): + @$(MKDIR_P) bgpd + @: > bgpd/$(am__dirstamp) +bgpd/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) bgpd/$(DEPDIR) + @: > bgpd/$(DEPDIR)/$(am__dirstamp) +bgpd/test_aspath.$(OBJEXT): bgpd/$(am__dirstamp) \ + bgpd/$(DEPDIR)/$(am__dirstamp) + +bgpd/test_aspath$(EXEEXT): $(bgpd_test_aspath_OBJECTS) $(bgpd_test_aspath_DEPENDENCIES) $(EXTRA_bgpd_test_aspath_DEPENDENCIES) bgpd/$(am__dirstamp) + @rm -f bgpd/test_aspath$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(bgpd_test_aspath_OBJECTS) $(bgpd_test_aspath_LDADD) $(LIBS) +bgpd/test_capability.$(OBJEXT): bgpd/$(am__dirstamp) \ + bgpd/$(DEPDIR)/$(am__dirstamp) + +bgpd/test_capability$(EXEEXT): $(bgpd_test_capability_OBJECTS) $(bgpd_test_capability_DEPENDENCIES) $(EXTRA_bgpd_test_capability_DEPENDENCIES) bgpd/$(am__dirstamp) + @rm -f bgpd/test_capability$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(bgpd_test_capability_OBJECTS) $(bgpd_test_capability_LDADD) $(LIBS) +bgpd/test_ecommunity.$(OBJEXT): bgpd/$(am__dirstamp) \ + bgpd/$(DEPDIR)/$(am__dirstamp) + +bgpd/test_ecommunity$(EXEEXT): $(bgpd_test_ecommunity_OBJECTS) $(bgpd_test_ecommunity_DEPENDENCIES) $(EXTRA_bgpd_test_ecommunity_DEPENDENCIES) bgpd/$(am__dirstamp) + @rm -f bgpd/test_ecommunity$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(bgpd_test_ecommunity_OBJECTS) $(bgpd_test_ecommunity_LDADD) $(LIBS) +bgpd/test_mp_attr.$(OBJEXT): bgpd/$(am__dirstamp) \ + bgpd/$(DEPDIR)/$(am__dirstamp) + +bgpd/test_mp_attr$(EXEEXT): $(bgpd_test_mp_attr_OBJECTS) $(bgpd_test_mp_attr_DEPENDENCIES) $(EXTRA_bgpd_test_mp_attr_DEPENDENCIES) bgpd/$(am__dirstamp) + @rm -f bgpd/test_mp_attr$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(bgpd_test_mp_attr_OBJECTS) $(bgpd_test_mp_attr_LDADD) $(LIBS) +bgpd/test_mpath.$(OBJEXT): bgpd/$(am__dirstamp) \ + bgpd/$(DEPDIR)/$(am__dirstamp) + +bgpd/test_mpath$(EXEEXT): $(bgpd_test_mpath_OBJECTS) $(bgpd_test_mpath_DEPENDENCIES) $(EXTRA_bgpd_test_mpath_DEPENDENCIES) bgpd/$(am__dirstamp) + @rm -f bgpd/test_mpath$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(bgpd_test_mpath_OBJECTS) $(bgpd_test_mpath_LDADD) $(LIBS) +bgpd/test_packet.$(OBJEXT): bgpd/$(am__dirstamp) \ + bgpd/$(DEPDIR)/$(am__dirstamp) + +bgpd/test_packet$(EXEEXT): $(bgpd_test_packet_OBJECTS) $(bgpd_test_packet_DEPENDENCIES) $(EXTRA_bgpd_test_packet_DEPENDENCIES) bgpd/$(am__dirstamp) + @rm -f bgpd/test_packet$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(bgpd_test_packet_OBJECTS) $(bgpd_test_packet_LDADD) $(LIBS) +isisd/$(am__dirstamp): + @$(MKDIR_P) isisd + @: > isisd/$(am__dirstamp) +isisd/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) isisd/$(DEPDIR) + @: > isisd/$(DEPDIR)/$(am__dirstamp) +isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.$(OBJEXT): \ + isisd/$(am__dirstamp) isisd/$(DEPDIR)/$(am__dirstamp) + +isisd/test_fuzz_isis_tlv$(EXEEXT): $(isisd_test_fuzz_isis_tlv_OBJECTS) $(isisd_test_fuzz_isis_tlv_DEPENDENCIES) $(EXTRA_isisd_test_fuzz_isis_tlv_DEPENDENCIES) isisd/$(am__dirstamp) + @rm -f isisd/test_fuzz_isis_tlv$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(isisd_test_fuzz_isis_tlv_OBJECTS) $(isisd_test_fuzz_isis_tlv_LDADD) $(LIBS) +isisd/test_isis_vertex_queue.$(OBJEXT): isisd/$(am__dirstamp) \ + isisd/$(DEPDIR)/$(am__dirstamp) + +isisd/test_isis_vertex_queue$(EXEEXT): $(isisd_test_isis_vertex_queue_OBJECTS) $(isisd_test_isis_vertex_queue_DEPENDENCIES) $(EXTRA_isisd_test_isis_vertex_queue_DEPENDENCIES) isisd/$(am__dirstamp) + @rm -f isisd/test_isis_vertex_queue$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(isisd_test_isis_vertex_queue_OBJECTS) $(isisd_test_isis_vertex_queue_LDADD) $(LIBS) +lib/cli/$(am__dirstamp): + @$(MKDIR_P) lib/cli + @: > lib/cli/$(am__dirstamp) +lib/cli/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) lib/cli/$(DEPDIR) + @: > lib/cli/$(DEPDIR)/$(am__dirstamp) +lib/cli/test_cli.$(OBJEXT): lib/cli/$(am__dirstamp) \ + lib/cli/$(DEPDIR)/$(am__dirstamp) +lib/cli/common_cli.$(OBJEXT): lib/cli/$(am__dirstamp) \ + lib/cli/$(DEPDIR)/$(am__dirstamp) + +lib/cli/test_cli$(EXEEXT): $(lib_cli_test_cli_OBJECTS) $(lib_cli_test_cli_DEPENDENCIES) $(EXTRA_lib_cli_test_cli_DEPENDENCIES) lib/cli/$(am__dirstamp) + @rm -f lib/cli/test_cli$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_cli_test_cli_OBJECTS) $(lib_cli_test_cli_LDADD) $(LIBS) +lib/cli/test_commands_defun.$(OBJEXT): lib/cli/$(am__dirstamp) \ + lib/cli/$(DEPDIR)/$(am__dirstamp) +lib/cli/test_commands.$(OBJEXT): lib/cli/$(am__dirstamp) \ + lib/cli/$(DEPDIR)/$(am__dirstamp) +helpers/c/$(am__dirstamp): + @$(MKDIR_P) helpers/c + @: > helpers/c/$(am__dirstamp) +helpers/c/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) helpers/c/$(DEPDIR) + @: > helpers/c/$(DEPDIR)/$(am__dirstamp) +helpers/c/prng.$(OBJEXT): helpers/c/$(am__dirstamp) \ + helpers/c/$(DEPDIR)/$(am__dirstamp) + +lib/cli/test_commands$(EXEEXT): $(lib_cli_test_commands_OBJECTS) $(lib_cli_test_commands_DEPENDENCIES) $(EXTRA_lib_cli_test_commands_DEPENDENCIES) lib/cli/$(am__dirstamp) + @rm -f lib/cli/test_commands$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_cli_test_commands_OBJECTS) $(lib_cli_test_commands_LDADD) $(LIBS) +lib/$(am__dirstamp): + @$(MKDIR_P) lib + @: > lib/$(am__dirstamp) +lib/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) lib/$(DEPDIR) + @: > lib/$(DEPDIR)/$(am__dirstamp) +lib/test_buffer.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_buffer$(EXEEXT): $(lib_test_buffer_OBJECTS) $(lib_test_buffer_DEPENDENCIES) $(EXTRA_lib_test_buffer_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_buffer$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_buffer_OBJECTS) $(lib_test_buffer_LDADD) $(LIBS) +lib/test_checksum.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_checksum$(EXEEXT): $(lib_test_checksum_OBJECTS) $(lib_test_checksum_DEPENDENCIES) $(EXTRA_lib_test_checksum_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_checksum$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_checksum_OBJECTS) $(lib_test_checksum_LDADD) $(LIBS) +lib/test_heavy.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) +helpers/c/main.$(OBJEXT): helpers/c/$(am__dirstamp) \ + helpers/c/$(DEPDIR)/$(am__dirstamp) + +lib/test_heavy$(EXEEXT): $(lib_test_heavy_OBJECTS) $(lib_test_heavy_DEPENDENCIES) $(EXTRA_lib_test_heavy_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_heavy$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_heavy_OBJECTS) $(lib_test_heavy_LDADD) $(LIBS) +lib/test_heavy_thread.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_heavy_thread$(EXEEXT): $(lib_test_heavy_thread_OBJECTS) $(lib_test_heavy_thread_DEPENDENCIES) $(EXTRA_lib_test_heavy_thread_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_heavy_thread$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_heavy_thread_OBJECTS) $(lib_test_heavy_thread_LDADD) $(LIBS) +lib/test_heavy_wq.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_heavy_wq$(EXEEXT): $(lib_test_heavy_wq_OBJECTS) $(lib_test_heavy_wq_DEPENDENCIES) $(EXTRA_lib_test_heavy_wq_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_heavy_wq$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_heavy_wq_OBJECTS) $(lib_test_heavy_wq_LDADD) $(LIBS) +lib/test_memory.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_memory$(EXEEXT): $(lib_test_memory_OBJECTS) $(lib_test_memory_DEPENDENCIES) $(EXTRA_lib_test_memory_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_memory$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_memory_OBJECTS) $(lib_test_memory_LDADD) $(LIBS) +lib/test_nexthop_iter.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_nexthop_iter$(EXEEXT): $(lib_test_nexthop_iter_OBJECTS) $(lib_test_nexthop_iter_DEPENDENCIES) $(EXTRA_lib_test_nexthop_iter_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_nexthop_iter$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_nexthop_iter_OBJECTS) $(lib_test_nexthop_iter_LDADD) $(LIBS) +lib/test_privs.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_privs$(EXEEXT): $(lib_test_privs_OBJECTS) $(lib_test_privs_DEPENDENCIES) $(EXTRA_lib_test_privs_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_privs$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_privs_OBJECTS) $(lib_test_privs_LDADD) $(LIBS) +lib/test_ringbuf.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_ringbuf$(EXEEXT): $(lib_test_ringbuf_OBJECTS) $(lib_test_ringbuf_DEPENDENCIES) $(EXTRA_lib_test_ringbuf_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_ringbuf$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_ringbuf_OBJECTS) $(lib_test_ringbuf_LDADD) $(LIBS) +lib/test_segv.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_segv$(EXEEXT): $(lib_test_segv_OBJECTS) $(lib_test_segv_DEPENDENCIES) $(EXTRA_lib_test_segv_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_segv$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_segv_OBJECTS) $(lib_test_segv_LDADD) $(LIBS) +lib/test_sig.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_sig$(EXEEXT): $(lib_test_sig_OBJECTS) $(lib_test_sig_DEPENDENCIES) $(EXTRA_lib_test_sig_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_sig$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_sig_OBJECTS) $(lib_test_sig_LDADD) $(LIBS) +lib/test_srcdest_table.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_srcdest_table$(EXEEXT): $(lib_test_srcdest_table_OBJECTS) $(lib_test_srcdest_table_DEPENDENCIES) $(EXTRA_lib_test_srcdest_table_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_srcdest_table$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_srcdest_table_OBJECTS) $(lib_test_srcdest_table_LDADD) $(LIBS) +lib/test_stream.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_stream$(EXEEXT): $(lib_test_stream_OBJECTS) $(lib_test_stream_DEPENDENCIES) $(EXTRA_lib_test_stream_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_stream$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_stream_OBJECTS) $(lib_test_stream_LDADD) $(LIBS) +lib/test_table.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_table$(EXEEXT): $(lib_test_table_OBJECTS) $(lib_test_table_DEPENDENCIES) $(EXTRA_lib_test_table_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_table$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_table_OBJECTS) $(lib_test_table_LDADD) $(LIBS) +lib/test_timer_correctness.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_timer_correctness$(EXEEXT): $(lib_test_timer_correctness_OBJECTS) $(lib_test_timer_correctness_DEPENDENCIES) $(EXTRA_lib_test_timer_correctness_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_timer_correctness$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_timer_correctness_OBJECTS) $(lib_test_timer_correctness_LDADD) $(LIBS) +lib/test_timer_performance.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_timer_performance$(EXEEXT): $(lib_test_timer_performance_OBJECTS) $(lib_test_timer_performance_DEPENDENCIES) $(EXTRA_lib_test_timer_performance_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_timer_performance$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_timer_performance_OBJECTS) $(lib_test_timer_performance_LDADD) $(LIBS) +lib/test_ttable.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_ttable$(EXEEXT): $(lib_test_ttable_OBJECTS) $(lib_test_ttable_DEPENDENCIES) $(EXTRA_lib_test_ttable_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_ttable$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lib_test_ttable_OBJECTS) $(lib_test_ttable_LDADD) $(LIBS) +lib/lib_test_zmq-test_zmq.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) + +lib/test_zmq$(EXEEXT): $(lib_test_zmq_OBJECTS) $(lib_test_zmq_DEPENDENCIES) $(EXTRA_lib_test_zmq_DEPENDENCIES) lib/$(am__dirstamp) + @rm -f lib/test_zmq$(EXEEXT) + $(AM_V_CCLD)$(lib_test_zmq_LINK) $(lib_test_zmq_OBJECTS) $(lib_test_zmq_LDADD) $(LIBS) +ospf6d/$(am__dirstamp): + @$(MKDIR_P) ospf6d + @: > ospf6d/$(am__dirstamp) +ospf6d/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) ospf6d/$(DEPDIR) + @: > ospf6d/$(DEPDIR)/$(am__dirstamp) +ospf6d/test_lsdb.$(OBJEXT): ospf6d/$(am__dirstamp) \ + ospf6d/$(DEPDIR)/$(am__dirstamp) + +ospf6d/test_lsdb$(EXEEXT): $(ospf6d_test_lsdb_OBJECTS) $(ospf6d_test_lsdb_DEPENDENCIES) $(EXTRA_ospf6d_test_lsdb_DEPENDENCIES) ospf6d/$(am__dirstamp) + @rm -f ospf6d/test_lsdb$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(ospf6d_test_lsdb_OBJECTS) $(ospf6d_test_lsdb_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + -rm -f bgpd/*.$(OBJEXT) + -rm -f helpers/c/*.$(OBJEXT) + -rm -f isisd/*.$(OBJEXT) + -rm -f lib/*.$(OBJEXT) + -rm -f lib/cli/*.$(OBJEXT) + -rm -f ospf6d/*.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@bgpd/$(DEPDIR)/test_aspath.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@bgpd/$(DEPDIR)/test_capability.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@bgpd/$(DEPDIR)/test_ecommunity.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@bgpd/$(DEPDIR)/test_mp_attr.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@bgpd/$(DEPDIR)/test_mpath.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@bgpd/$(DEPDIR)/test_packet.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@helpers/c/$(DEPDIR)/main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@helpers/c/$(DEPDIR)/prng.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@isisd/$(DEPDIR)/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@isisd/$(DEPDIR)/test_isis_vertex_queue.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/lib_test_zmq-test_zmq.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_buffer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_checksum.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_heavy.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_heavy_thread.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_heavy_wq.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_memory.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_nexthop_iter.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_privs.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_ringbuf.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_segv.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_sig.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_srcdest_table.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_stream.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_table.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_timer_correctness.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_timer_performance.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_ttable.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/cli/$(DEPDIR)/common_cli.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/cli/$(DEPDIR)/test_cli.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/cli/$(DEPDIR)/test_commands.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@lib/cli/$(DEPDIR)/test_commands_defun.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@ospf6d/$(DEPDIR)/test_lsdb.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.o: isisd/test_fuzz_isis_tlv.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(isisd_test_fuzz_isis_tlv_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.o -MD -MP -MF isisd/$(DEPDIR)/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.Tpo -c -o isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.o `test -f 'isisd/test_fuzz_isis_tlv.c' || echo '$(srcdir)/'`isisd/test_fuzz_isis_tlv.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) isisd/$(DEPDIR)/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.Tpo isisd/$(DEPDIR)/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='isisd/test_fuzz_isis_tlv.c' object='isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(isisd_test_fuzz_isis_tlv_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.o `test -f 'isisd/test_fuzz_isis_tlv.c' || echo '$(srcdir)/'`isisd/test_fuzz_isis_tlv.c + +isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.obj: isisd/test_fuzz_isis_tlv.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(isisd_test_fuzz_isis_tlv_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.obj -MD -MP -MF isisd/$(DEPDIR)/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.Tpo -c -o isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.obj `if test -f 'isisd/test_fuzz_isis_tlv.c'; then $(CYGPATH_W) 'isisd/test_fuzz_isis_tlv.c'; else $(CYGPATH_W) '$(srcdir)/isisd/test_fuzz_isis_tlv.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) isisd/$(DEPDIR)/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.Tpo isisd/$(DEPDIR)/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='isisd/test_fuzz_isis_tlv.c' object='isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(isisd_test_fuzz_isis_tlv_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.obj `if test -f 'isisd/test_fuzz_isis_tlv.c'; then $(CYGPATH_W) 'isisd/test_fuzz_isis_tlv.c'; else $(CYGPATH_W) '$(srcdir)/isisd/test_fuzz_isis_tlv.c'; fi` + +lib/lib_test_zmq-test_zmq.o: lib/test_zmq.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_test_zmq_CFLAGS) $(CFLAGS) -MT lib/lib_test_zmq-test_zmq.o -MD -MP -MF lib/$(DEPDIR)/lib_test_zmq-test_zmq.Tpo -c -o lib/lib_test_zmq-test_zmq.o `test -f 'lib/test_zmq.c' || echo '$(srcdir)/'`lib/test_zmq.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) lib/$(DEPDIR)/lib_test_zmq-test_zmq.Tpo lib/$(DEPDIR)/lib_test_zmq-test_zmq.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lib/test_zmq.c' object='lib/lib_test_zmq-test_zmq.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_test_zmq_CFLAGS) $(CFLAGS) -c -o lib/lib_test_zmq-test_zmq.o `test -f 'lib/test_zmq.c' || echo '$(srcdir)/'`lib/test_zmq.c + +lib/lib_test_zmq-test_zmq.obj: lib/test_zmq.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_test_zmq_CFLAGS) $(CFLAGS) -MT lib/lib_test_zmq-test_zmq.obj -MD -MP -MF lib/$(DEPDIR)/lib_test_zmq-test_zmq.Tpo -c -o lib/lib_test_zmq-test_zmq.obj `if test -f 'lib/test_zmq.c'; then $(CYGPATH_W) 'lib/test_zmq.c'; else $(CYGPATH_W) '$(srcdir)/lib/test_zmq.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) lib/$(DEPDIR)/lib_test_zmq-test_zmq.Tpo lib/$(DEPDIR)/lib_test_zmq-test_zmq.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lib/test_zmq.c' object='lib/lib_test_zmq-test_zmq.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_test_zmq_CFLAGS) $(CFLAGS) -c -o lib/lib_test_zmq-test_zmq.obj `if test -f 'lib/test_zmq.c'; then $(CYGPATH_W) 'lib/test_zmq.c'; else $(CYGPATH_W) '$(srcdir)/lib/test_zmq.c'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + -rm -rf bgpd/.libs bgpd/_libs + -rm -rf isisd/.libs isisd/_libs + -rm -rf lib/.libs lib/_libs + -rm -rf lib/cli/.libs lib/cli/_libs + -rm -rf ospf6d/.libs ospf6d/_libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) +check: check-am +all-am: Makefile $(HEADERS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f bgpd/$(DEPDIR)/$(am__dirstamp) + -rm -f bgpd/$(am__dirstamp) + -rm -f helpers/c/$(DEPDIR)/$(am__dirstamp) + -rm -f helpers/c/$(am__dirstamp) + -rm -f isisd/$(DEPDIR)/$(am__dirstamp) + -rm -f isisd/$(am__dirstamp) + -rm -f lib/$(DEPDIR)/$(am__dirstamp) + -rm -f lib/$(am__dirstamp) + -rm -f lib/cli/$(DEPDIR)/$(am__dirstamp) + -rm -f lib/cli/$(am__dirstamp) + -rm -f ospf6d/$(DEPDIR)/$(am__dirstamp) + -rm -f ospf6d/$(am__dirstamp) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-checkPROGRAMS clean-generic clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf bgpd/$(DEPDIR) helpers/c/$(DEPDIR) isisd/$(DEPDIR) lib/$(DEPDIR) lib/cli/$(DEPDIR) ospf6d/$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf bgpd/$(DEPDIR) helpers/c/$(DEPDIR) isisd/$(DEPDIR) lib/$(DEPDIR) lib/cli/$(DEPDIR) ospf6d/$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \ + clean-checkPROGRAMS clean-generic clean-libtool cscopelist-am \ + ctags ctags-am distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + +.c_clippy.c: + @{ test -x $(top_builddir)/$(HOSTTOOLS)lib/clippy || $(MAKE) -C $(top_builddir)/$(HOSTTOOLS) lib/clippy; } + $(AM_V_CLIPPY)$(top_builddir)/$(HOSTTOOLS)lib/clippy $(top_srcdir)/python/clidef.py -o $@ $< + +.l.c: + $(AM_V_LEX)$(am__skiplex) $(LEXCOMPILE) $< +.y.c: + $(AM_V_YACC)$(am__skipyacc) $(YACCCOMPILE) $< + +# Rules +@HAVE_PROTOBUF_TRUE@.proto.pb.h: +@HAVE_PROTOBUF_TRUE@ $(Q_PROTOC) -I$(top_srcdir) --cpp_out=$(top_srcdir) $(top_srcdir)/$^ + +@HAVE_PROTOBUF_TRUE@.proto.pb-c.c: +@HAVE_PROTOBUF_TRUE@ $(AM_V_PROTOC_C)$(Q_PROTOC_C) -I$(top_srcdir) --c_out=$(top_srcdir) $(top_srcdir)/$^ +@HAVE_PROTOBUF_TRUE@.pb-c.c.pb-c.h: +@HAVE_PROTOBUF_TRUE@ @/bin/true + +PYTHON ?= python + +lib/cli/test_cli.o: lib/cli/test_cli_clippy.c +ospf6d/test_lsdb.o: ospf6d/test_lsdb_clippy.c + +../vtysh/vtysh_cmd.c: + $(MAKE) -C ../vtysh vtysh_cmd.c + +lib/cli/test_commands_defun.c: ../vtysh/vtysh_cmd.c + sed \ + -e 's/"vtysh\.h"/"tests.h"/' \ + -e 's/vtysh_init_cmd/test_init_cmd/' \ + -e 's/VTYSH_[A-Z][A-Z_0-9]*/0/g' \ + < ../vtysh/vtysh_cmd.c \ + > "$@" + +isisd/test_fuzz_isis_tlv_tests.h: $(top_srcdir)/tests/isisd/test_fuzz_isis_tlv_tests.h.gz + gzip -d < $(top_srcdir)/tests/isisd/test_fuzz_isis_tlv_tests.h.gz > "$@" +isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.$(OBJEXT): \ + isisd/test_fuzz_isis_tlv_tests.h + +.PHONY: tests.xml +tests.xml: $(check_PROGRAMS) + $(PYTHON) $(srcdir)/runtests.py --junitxml=$@ -v $(srcdir) +check: tests.xml + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/tests/lib/cxxcompat.c b/tests/lib/cxxcompat.c new file mode 100644 index 0000000000..530468642e --- /dev/null +++ b/tests/lib/cxxcompat.c @@ -0,0 +1,113 @@ +/* + * C++ compatibility compile-time smoketest + * Copyright (C) 2019 David Lamparter for NetDEF, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "lib/zebra.h" + +#include "lib/agg_table.h" +#include "lib/bfd.h" +#include "lib/bitfield.h" +#include "lib/buffer.h" +#include "lib/checksum.h" +#include "lib/command.h" +#include "lib/command_graph.h" +#include "lib/command_match.h" +#include "lib/compiler.h" +#include "lib/csv.h" +#include "lib/debug.h" +#include "lib/distribute.h" +#include "lib/event_counter.h" +#include "lib/ferr.h" +#include "lib/fifo.h" +#include "lib/filter.h" +#include "lib/frr_pthread.h" +#include "lib/frratomic.h" +#include "lib/frrstr.h" +#include "lib/getopt.h" +#include "lib/graph.h" +#include "lib/hash.h" +#include "lib/hook.h" +#include "lib/id_alloc.h" +#include "lib/if.h" +#include "lib/if_rmap.h" +#include "lib/imsg.h" +#include "lib/ipaddr.h" +#include "lib/jhash.h" +#include "lib/json.h" +#include "lib/keychain.h" +#include "lib/lib_errors.h" +#include "lib/libfrr.h" +#include "lib/libospf.h" +#include "lib/linklist.h" +#include "lib/log.h" +#include "lib/logicalrouter.h" +#include "lib/md5.h" +#include "lib/memory.h" +#include "lib/memory_vty.h" +#include "lib/mlag.h" +#include "lib/module.h" +#include "lib/monotime.h" +#include "lib/mpls.h" +#include "lib/network.h" +#include "lib/nexthop.h" +#include "lib/nexthop_group.h" +#include "lib/northbound.h" +#include "lib/northbound_cli.h" +#include "lib/northbound_db.h" +#include "lib/ns.h" +#include "lib/openbsd-tree.h" +#include "lib/pbr.h" +#include "lib/plist.h" +#include "lib/pqueue.h" +#include "lib/prefix.h" +#include "lib/privs.h" +#include "lib/ptm_lib.h" +#include "lib/pw.h" +#include "lib/qobj.h" +#include "lib/queue.h" +#include "lib/ringbuf.h" +#include "lib/routemap.h" +#include "lib/sbuf.h" +#include "lib/sha256.h" +#include "lib/sigevent.h" +#include "lib/skiplist.h" +#include "lib/sockopt.h" +#include "lib/sockunion.h" +#include "lib/spf_backoff.h" +#include "lib/srcdest_table.h" +#include "lib/stream.h" +#include "lib/table.h" +#include "lib/termtable.h" +#include "lib/thread.h" +#include "lib/vector.h" +#include "lib/vlan.h" +#include "lib/vrf.h" +#include "lib/vty.h" +#include "lib/vxlan.h" +#include "lib/wheel.h" +/* #include "lib/workqueue.h" -- macro problem with STAILQ_LAST */ +#include "lib/yang.h" +#include "lib/yang_translator.h" +#include "lib/yang_wrappers.h" +#include "lib/zassert.h" +#include "lib/zclient.h" + +int main(int argc, char **argv) +{ + return 0; +} diff --git a/tests/subdir.am b/tests/subdir.am index 7d2800a3a2..365fe00cc6 100644 --- a/tests/subdir.am +++ b/tests/subdir.am @@ -46,6 +46,7 @@ tests/ospf6d/tests_ospf6d_test_lsdb-test_lsdb.$(OBJEXT): tests/ospf6d/test_lsdb_ tests/ospf6d/test_lsdb-test_lsdb.$(OBJEXT): tests/ospf6d/test_lsdb_clippy.c check_PROGRAMS = \ + tests/lib/cxxcompat \ tests/lib/test_buffer \ tests/lib/test_checksum \ tests/lib/test_heavy_thread \ @@ -112,10 +113,13 @@ TESTS_CPPFLAGS = $(AM_CPPFLAGS) \ -I$(top_srcdir)/tests/helpers/c \ -I$(top_builddir)/tests/helpers/c \ # end -TESTS_CFLAGS = $(SAN_FLAGS) +TESTS_CFLAGS = \ + $(LIBYANG_CFLAGS) \ + $(SAN_FLAGS) \ + # end # note no -Werror -ALL_TESTS_LDADD = lib/libfrr.la @LIBCAP@ +ALL_TESTS_LDADD = lib/libfrr.la $(LIBCAP) BGP_TEST_LDADD = bgpd/libbgp.a $(RFPLDADD) $(ALL_TESTS_LDADD) -lm ISISD_TEST_LDADD = isisd/libisis.a $(ALL_TESTS_LDADD) OSPF6_TEST_LDADD = ospf6d/libospf6.a $(ALL_TESTS_LDADD) @@ -167,6 +171,10 @@ tests_isisd_test_isis_vertex_queue_CPPFLAGS = $(TESTS_CPPFLAGS) tests_isisd_test_isis_vertex_queue_LDADD = $(ISISD_TEST_LDADD) tests_isisd_test_isis_vertex_queue_SOURCES = tests/isisd/test_isis_vertex_queue.c +tests_lib_cxxcompat_CFLAGS = $(TESTS_CFLAGS) $(CXX_COMPAT_CFLAGS) $(WERROR) +tests_lib_cxxcompat_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_cxxcompat_SOURCES = tests/lib/cxxcompat.c +tests_lib_cxxcompat_LDADD = $(ALL_TESTS_LDADD) tests_lib_cli_test_cli_CFLAGS = $(TESTS_CFLAGS) tests_lib_cli_test_cli_CPPFLAGS = $(TESTS_CPPFLAGS) tests_lib_cli_test_cli_LDADD = $(ALL_TESTS_LDADD) diff --git a/tests/topotests/GUIDELINES.md b/tests/topotests/GUIDELINES.md deleted file mode 100644 index 4bd373796c..0000000000 --- a/tests/topotests/GUIDELINES.md +++ /dev/null @@ -1,571 +0,0 @@ -# Guidelines - -This document describes how to use the topotests testing framework. - - -## Executing Tests - -To run the whole suite of tests the following commands must be executed at the -top level directory of topotest: - -```shell -$ # Change to the top level directory of topotests. -$ cd path/to/topotests -$ # Tests must be run as root, since Mininet requires it. -$ sudo pytest -``` - -In order to run a specific test, you can use the following command: - -```shell -$ # running a specific topology -$ sudo pytest ospf-topo1/ -$ # or inside the test folder -$ cd ospf-topo1 -$ sudo pytest # to run all tests inside the directory -$ sudo pytest test_ospf_topo1.py # to run a specific test -$ # or outside the test folder -$ cd .. -$ sudo pytest ospf-topo1/test_ospf_topo1.py # to run a specific one -``` - -The output of the tested daemons will be available at the temporary folder of -your machine: - -```shell -$ ls /tmp/topotest/ospf-topo1.test_ospf-topo1/r1 -... -zebra.err # zebra stderr output -zebra.log # zebra log file -zebra.out # zebra stdout output -... -``` - -You can also run memory leak tests to get reports: - -```shell -$ # Set the environment variable to apply to a specific test... -$ sudo env TOPOTESTS_CHECK_MEMLEAK="/tmp/memleak_report_" pytest ospf-topo1/test_ospf_topo1.py -$ # ...or apply to all tests adding this line to the configuration file -$ echo 'memleak_path = /tmp/memleak_report_' >> pytest.ini -$ # You can also use your editor -$ $EDITOR pytest.ini -$ # After running tests you should see your files: -$ ls /tmp/memleak_report_* -memleak_report_test_ospf_topo1.txt -``` - - -## Writing a New Test - -This section will guide you in all recommended steps to produce a standard -topology test. - -This is the recommended test writing routine: - -* Write a topology (Graphviz recommended) -* Obtain configuration files -* Write the test itself -* Create a Pull Request - - -### Topotest File Hierarchy - -Before starting to write any tests one must know the file hierarchy. The -repository hierarchy looks like this: - -```shell -$ cd path/to/topotest -$ find ./* -... -./README.md # repository read me -./GUIDELINES.md # this file -./conftest.py # test hooks - pytest related functions -./example-test # example test folder -./example-test/__init__.py # python package marker - must always exist. -./example-test/test_template.jpg # generated topology picture - see next section -./example-test/test_template.dot # Graphviz dot file -./example-test/test_template.py # the topology plus the test -... -./ospf-topo1 # the ospf topology test -./ospf-topo1/r1 # router 1 configuration files -./ospf-topo1/r1/zebra.conf # zebra configuration file -./ospf-topo1/r1/ospfd.conf # ospf configuration file -./ospf-topo1/r1/ospfroute.txt # 'show ip ospf' output reference file -# removed other for shortness sake -... -./lib # shared test/topology functions -./lib/topogen.py # topogen implementation -./lib/topotest.py # topotest implementation -``` - -Guidelines for creating/editing topotest: - -* New topologies that don't fit the existing directories should create its own -* Always remember to add the `__init__.py` to new folders, this makes auto - complete engines and pylint happy -* Router (Quagga/FRR) specific code should go on topotest.py -* Generic/repeated router actions should have an abstraction in - topogen.TopoRouter. -* Generic/repeated non-router code should go to topotest.py -* pytest related code should go to conftest.py (e.g. specialized asserts) - - -### Defining the Topology - -The first step to write a new test is to define the topology. This step can be -done in many ways, but the recommended is to use Graphviz to generate a drawing -of the Topology. It allows us to see the topology graphically and to see the -names of equipments, links and addresses. - -Here is an example of Graphviz dot file that generates the -[template topology](example-test/test_template.dot) (the inlined code might get -outdated, please see the linked file): - -```dot -graph template { - label="template"; - - # Routers - r1 [ - shape=doubleoctagon, - label="r1", - fillcolor="#f08080", - style=filled, - ]; - r2 [ - shape=doubleoctagon, - label="r2", - fillcolor="#f08080", - style=filled, - ]; - - # Switches - s1 [ - shape=oval, - label="s1\n192.168.0.0/24", - fillcolor="#d0e0d0", - style=filled, - ]; - s2 [ - shape=oval, - label="s2\n192.168.1.0/24", - fillcolor="#d0e0d0", - style=filled, - ]; - - # Connections - r1 -- s1 [label="eth0\n.1"]; - - r1 -- s2 [label="eth1\n.100"]; - r2 -- s2 [label="eth0\n.1"]; -} -``` - -Here is the produced graph: - - - - -### Generating / Obtaining Configuration Files - -In order to get the configuration files or command output for each router, we -need to run the topology and execute commands in vtysh. The quickest way to -achieve that is writing the topology building code and running the topology. - -To bootstrap your test topology, do the following steps: - -* Copy the template test - -```shell -$ mkdir new-topo/ -$ touch new-topo/__init__.py -$ cp example-test/test_template.py new-topo/test_new_topo.py -``` - -* Modify the template according to your dot file - -Here is the template topology described in the previous section in python code: - -```py -class TemplateTopo(Topo): - "Test topology builder" - def build(self, *_args, **_opts): - "Build function" - tgen = get_topogen(self) - - # Create 2 routers - for routern in range(1, 3): - tgen.add_router('r{}'.format(routern)) - - # Create a switch with just one router connected to it to simulate a - # empty network. - switch = tgen.add_switch('s1') - switch.add_link(tgen.gears['r1']) - - # Create a connection between r1 and r2 - switch = tgen.add_switch('s2') - switch.add_link(tgen.gears['r1']) - switch.add_link(tgen.gears['r2']) -``` - -* Run the topology - -Topogen allows us to run the topology without running any tests, you can do that -using the following example commands: - -```shell -$ # Running your bootstraped topology -$ sudo pytest -s --topology-only new-topo/test_new_topo.py -$ # Running the test_template.py topology -$ sudo pytest -s --topology-only example-test/test_template.py -$ # Running the ospf_topo1.py topology -$ sudo pytest -s --topology-only ospf-topo1/test_ospf_topo1.py -``` - -Parameters explanation: - -* `-s`: actives input/output capture. This is required by mininet in order to show - the interactive shell. -* `--topology-only`: don't run any tests, just build the topology. - -After executing the commands above, you should get the following terminal -output: - -```shell -=== test session starts === -platform linux2 -- Python 2.7.12, pytest-3.1.2, py-1.4.34, pluggy-0.4.0 -rootdir: /media/sf_src/topotests, inifile: pytest.ini -collected 3 items - -ospf-topo1/test_ospf_topo1.py *** Starting controller - -*** Starting 6 switches -switch1 switch2 switch3 switch4 switch5 switch6 ... -r2: frr zebra started -r2: frr ospfd started -r3: frr zebra started -r3: frr ospfd started -r1: frr zebra started -r1: frr ospfd started -r4: frr zebra started -r4: frr ospfd started -*** Starting CLI: -mininet> -``` - -The last line shows us that we are now using the Mininet CLI (Command Line -Interface), from here you can call your router vtysh or even bash. - -Here are some commands example: - -```shell -mininet> r1 ping 10.0.3.1 -PING 10.0.3.1 (10.0.3.1) 56(84) bytes of data. -64 bytes from 10.0.3.1: icmp_seq=1 ttl=64 time=0.576 ms -64 bytes from 10.0.3.1: icmp_seq=2 ttl=64 time=0.083 ms -64 bytes from 10.0.3.1: icmp_seq=3 ttl=64 time=0.088 ms -^C ---- 10.0.3.1 ping statistics --- -3 packets transmitted, 3 received, 0% packet loss, time 1998ms -rtt min/avg/max/mdev = 0.083/0.249/0.576/0.231 ms - - - -mininet> r1 ping 10.0.3.3 -PING 10.0.3.3 (10.0.3.3) 56(84) bytes of data. -64 bytes from 10.0.3.3: icmp_seq=1 ttl=64 time=2.87 ms -64 bytes from 10.0.3.3: icmp_seq=2 ttl=64 time=0.080 ms -64 bytes from 10.0.3.3: icmp_seq=3 ttl=64 time=0.091 ms -^C ---- 10.0.3.3 ping statistics --- -3 packets transmitted, 3 received, 0% packet loss, time 2003ms -rtt min/avg/max/mdev = 0.080/1.014/2.872/1.313 ms - - - -mininet> r3 vtysh - -Hello, this is FRRouting (version 3.1-devrzalamena-build). -Copyright 1996-2005 Kunihiro Ishiguro, et al. - -frr-1# show running-config -Building configuration... - -Current configuration: -! -frr version 3.1-devrzalamena-build -frr defaults traditional -hostname r3 -no service integrated-vtysh-config -! -log file zebra.log -! -log file ospfd.log -! -interface r3-eth0 - ip address 10.0.3.1/24 -! -interface r3-eth1 - ip address 10.0.10.1/24 -! -interface r3-eth2 - ip address 172.16.0.2/24 -! -router ospf - ospf router-id 10.0.255.3 - redistribute kernel - redistribute connected - redistribute static - network 10.0.3.0/24 area 0 - network 10.0.10.0/24 area 0 - network 172.16.0.0/24 area 1 -! -line vty -! -end -frr-1# -``` - -After you successfully configured your topology, you can obtain the -configuration files (per-daemon) using the following commands: - -```shell -mininet> r3 vtysh -d ospfd - -Hello, this is FRRouting (version 3.1-devrzalamena-build). -Copyright 1996-2005 Kunihiro Ishiguro, et al. - -frr-1# show running-config -Building configuration... - -Current configuration: -! -frr version 3.1-devrzalamena-build -frr defaults traditional -no service integrated-vtysh-config -! -log file ospfd.log -! -router ospf - ospf router-id 10.0.255.3 - redistribute kernel - redistribute connected - redistribute static - network 10.0.3.0/24 area 0 - network 10.0.10.0/24 area 0 - network 172.16.0.0/24 area 1 -! -line vty -! -end -frr-1# -``` - - -### Writing Tests - -Test topologies should always be bootstrapped from the -[example-test/test_template.py](example-test/test_template.py), -because it contains important boilerplate code that can't be avoided, like: - -* imports: os, sys, pytest, topotest/topogen and mininet topology class -* The global variable CWD (Current Working directory): which is most likely - going to be used to reference the routers configuration file location - - Example: - -```py -# For all registered routers, load the zebra configuration file -for rname, router in router_list.iteritems(): - 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 '/'. -``` - -* The topology class that inherits from Mininet Topo class - -```py -class TemplateTopo(Topo): - def build(self, *_args, **_opts): - tgen = get_topogen(self) - # topology build code -``` - -* pytest `setup_module()` and `teardown_module()` to start the topology - -```py -def setup_module(_m): - tgen = Topogen(TemplateTopo) - tgen.start_topology('debug') - -def teardown_module(_m): - tgen = get_topogen() - tgen.stop_topology() -``` - -* `__main__` initialization code (to support running the script directly) - -```py -if __name__ == '__main__': - sys.exit(pytest.main(["-s"])) -``` - -Requirements: - -* Test code should always be declared inside functions that begin with the - `test_` prefix. Functions beginning with different prefixes will not be run by - pytest. -* Configuration files and long output commands should go into separated files - inside folders named after the equipment. -* Tests must be able to run without any interaction. To make sure your test - conforms with this, run it without the `-s` parameter. - -Tips: - -* Keep results in stack variables, so people inspecting code with `pdb` can - easily print their values. - - Don't do this: - - ```py - assert foobar(router1, router2) - ``` - - Do this instead: - - ```py - result = foobar(router1, router2) - assert result - ``` - -* Use `assert` messages to indicate where the test failed. - - Example: - - ```py - for router in router_list: - # ... - assert condition, 'Router "{}" condition failed'.format(router.name) - ``` - - -### Debugging Execution - -The most effective ways to inspect topology tests are: - -* Run pytest with `--pdb` option. This option will cause a pdb shell to appear - when an assertion fails - - Example: `pytest -s --pdb ospf-topo1/test_ospf_topo1.py` - -* Set a breakpoint in the test code with `pdb` - - Example: - -```py -# Add the pdb import at the beginning of the file -import pdb -# ... - -# Add a breakpoint where you think the problem is -def test_bla(): - # ... - pdb.set_trace() - # ... -``` - -The [Python Debugger](https://docs.python.org/2.7/library/pdb.html) (pdb) shell -allows us to run many useful operations like: - -* Setting breaking point on file/function/conditions (e.g. `break`, `condition`) -* Inspecting variables (e.g. `p` (print), `pp` (pretty print)) -* Running python code - -TIP: The TopoGear (equipment abstraction class) implements the `__str__` method -that allows the user to inspect equipment information. - -Example of pdb usage: - -```shell -> /media/sf_src/topotests/ospf-topo1/test_ospf_topo1.py(121)test_ospf_convergence() --> for rnum in range(1, 5): -(Pdb) help -Documented commands (type help <topic>): -======================================== -EOF bt cont enable jump pp run unt -a c continue exit l q s until -alias cl d h list quit step up -args clear debug help n r tbreak w -b commands disable ignore next restart u whatis -break condition down j p return unalias where - -Miscellaneous help topics: -========================== -exec pdb - -Undocumented commands: -====================== -retval rv - -(Pdb) list -116 title2="Expected output") -117 -118 def test_ospf_convergence(): -119 "Test OSPF daemon convergence" -120 pdb.set_trace() -121 -> for rnum in range(1, 5): -122 router = 'r{}'.format(rnum) -123 -124 # Load expected results from the command -125 reffile = os.path.join(CWD, '{}/ospfroute.txt'.format(router)) -126 expected = open(reffile).read() -(Pdb) step -> /media/sf_src/topotests/ospf-topo1/test_ospf_topo1.py(122)test_ospf_convergence() --> router = 'r{}'.format(rnum) -(Pdb) step -> /media/sf_src/topotests/ospf-topo1/test_ospf_topo1.py(125)test_ospf_convergence() --> reffile = os.path.join(CWD, '{}/ospfroute.txt'.format(router)) -(Pdb) print rnum -1 -(Pdb) print router -r1 -(Pdb) tgen = get_topogen() -(Pdb) pp tgen.gears[router] -<lib.topogen.TopoRouter object at 0x7f74e06c9850> -(Pdb) pp str(tgen.gears[router]) -'TopoGear<name="r1",links=["r1-eth0"<->"s1-eth0","r1-eth1"<->"s3-eth0"]> TopoRouter<>' -(Pdb) l 125 -120 pdb.set_trace() -121 for rnum in range(1, 5): -122 router = 'r{}'.format(rnum) -123 -124 # Load expected results from the command -125 -> reffile = os.path.join(CWD, '{}/ospfroute.txt'.format(router)) -126 expected = open(reffile).read() -127 -128 # Run test function until we get an result. Wait at most 60 seconds. -129 test_func = partial(compare_show_ip_ospf, router, expected) -130 result, diff = topotest.run_and_expect(test_func, '', -(Pdb) router1 = tgen.gears[router] -(Pdb) router1.vtysh_cmd('show ip ospf route') -'============ OSPF network routing table ============\r\nN 10.0.1.0/24 [10] area: 0.0.0.0\r\n directly attached to r1-eth0\r\nN 10.0.2.0/24 [20] area: 0.0.0.0\r\n via 10.0.3.3, r1-eth1\r\nN 10.0.3.0/24 [10] area: 0.0.0.0\r\n directly attached to r1-eth1\r\nN 10.0.10.0/24 [20] area: 0.0.0.0\r\n via 10.0.3.1, r1-eth1\r\nN IA 172.16.0.0/24 [20] area: 0.0.0.0\r\n via 10.0.3.1, r1-eth1\r\nN IA 172.16.1.0/24 [30] area: 0.0.0.0\r\n via 10.0.3.1, r1-eth1\r\n\r\n============ OSPF router routing table =============\r\nR 10.0.255.2 [10] area: 0.0.0.0, ASBR\r\n via 10.0.3.3, r1-eth1\r\nR 10.0.255.3 [10] area: 0.0.0.0, ABR, ASBR\r\n via 10.0.3.1, r1-eth1\r\nR 10.0.255.4 IA [20] area: 0.0.0.0, ASBR\r\n via 10.0.3.1, r1-eth1\r\n\r\n============ OSPF external routing table ===========\r\n\r\n\r\n' -(Pdb) tgen.mininet_cli() -*** Starting CLI: -mininet> -``` - -To enable more debug messages in other Topogen subsystems (like Mininet), more -logging messages can be displayed by modifying the test configuration file -`pytest.ini`: - -```ini -[topogen] -# Change the default verbosity line from 'info'... -#verbosity = info -# ...to 'debug' -verbosity = debug -``` diff --git a/tests/topotests/README.md b/tests/topotests/README.md index a495675ee9..d9d849b39f 100644 --- a/tests/topotests/README.md +++ b/tests/topotests/README.md @@ -1,199 +1 @@ -# FRRouting Topology Tests with Mininet - -## Running tests with docker - -There is a docker image which allows to run topotests. Instructions can be -found [here](docker/README.md). - -## Guidelines - -Instructions for use, write or debug topologies can be found in the -[guidelines](GUIDELINES.md). To learn/remember common code snippets see -[here](SNIPPETS.md). - -Before creating a new topology, make sure that there isn't one already -that does what you need. If nothing is similar, then you may create a -new topology, preferably, using the newest -[template](example-test/test_template.py). - -## Installation of Mininet for running tests -Only tested with Ubuntu 16.04 and Ubuntu 18.04 (which uses Mininet 2.2.x) - -Instructions are the same for all setups (ie ExaBGP is only used for BGP -tests) - -### Installing Mininet Infrastructure: - -1. apt-get install mininet -2. apt-get install python-pip -3. apt-get install iproute -4. pip install ipaddr -5. pip install pytest -6. pip install exabgp==3.4.17 - (Newer 4.0 version of exabgp is not yet supported) -7. useradd -d /var/run/exabgp/ -s /bin/false exabgp - -### Enable Coredumps -Optional, will give better output - -1. apt-get install gdb -2. disable apport (which move core files) - - Set `enabled=0` in `/etc/default/apport` - -3. Update security limits - - Add/change `/etc/security/limits.conf` to - - #<domain> <type> <item> <value> - * soft core unlimited - root soft core unlimited - * hard core unlimited - root hard core unlimited - -4. reboot (for options to take effect) - -## FRRouting (FRR) Installation -FRR needs to be installed separatly. It is assume to be configured -like the standard Ubuntu Packages: - -- Binaries in /usr/lib/frr -- State Directory /var/run/frr -- Running under user frr, group frr -- vtygroup: frrvty -- config directory: /etc/frr -- For FRR Packages, install the dbg package as well for coredump decoding - -No FRR config needs to be done and no FRR daemons should be run ahead -of the test. They are all started as part of the test - -#### Manual FRRouting (FRR) build - -If you prefer to manually build FRR, then use the following suggested config: - - ./configure \ - --prefix=/usr \ - --localstatedir=/var/run/frr \ - --sbindir=/usr/lib/frr \ - --sysconfdir=/etc/frr \ - --enable-vtysh \ - --enable-pimd \ - --enable-multipath=64 \ - --enable-user=frr \ - --enable-group=frr \ - --enable-vty-group=frrvty \ - --with-pkg-extra-version=-my-manual-build - -And create frr User and frrvty group as follows: - - addgroup --system --gid 92 frr - addgroup --system --gid 85 frrvty - adduser --system --ingroup frr --home /var/run/frr/ \ - --gecos "FRRouting suite" --shell /bin/false frr - usermod -G frrvty frr - -## Executing Tests - -#### Execute all tests with output to console - - py.test -s -v --tb=no - -All test_* scripts in subdirectories are detected and executed (unless -disabled in `pytest.ini` file) - -`--tb=no` disables the python traceback which might be irrelevant unless the -test script itself is debugged - -#### Execute single test - - cd test_to_be_run - ./test_to_be_run.py - -For further options, refer to pytest documentation - -Test will set exit code which can be used with `git bisect` - -For the simulated topology, see the description in the python file - -If you need to clear the mininet setup between tests (if it isn't cleanly -shutdown), then use the `mn -c` command to clean up the environment - -#### (Optional) StdErr log from daemos after exit - -To enable the reporting of any messages seen on StdErr after the -daemons exit, the following env variable can be set. - - export TOPOTESTS_CHECK_STDERR=Yes - -(The value doesn't matter at this time. The check is if the env variable -exists or not) -There is no pass/fail on this reporting. The Output will be reported to -the console - - export TOPOTESTS_CHECK_MEMLEAK="/home/mydir/memleak_" - -This will enable the check and output to console and the writing of -the information to files with the given prefix (followed by testname), -ie `/home/mydir/memcheck_test_bgp_multiview_topo1.txt` in case of a -memory leak. - -#### (Optional) Collect Memory Leak Information - -FreeRangeRouting processes have the capabilities to report remaining memory -allocations upon exit. To enable the reporting of the memory, define an -enviroment variable `TOPOTESTS_CHECK_MEMLEAK` with the file prefix, ie - - export TOPOTESTS_CHECK_MEMLEAK="/home/mydir/memleak_" - -This will enable the check and output to console and the writing of -the information to files with the given prefix (followed by testname), -ie `/home/mydir/memcheck_test_bgp_multiview_topo1.txt` in case of a -memory leak. - -#### (Optional) Run topotests with GCC AddressSanitizer enabled - -Topotests can be run with the GCC AddressSanitizer. It requires GCC 4.8 or -newer. (Ubuntu 16.04 as suggested here is fine with GCC 5 as default) -For more information on AddressSanitizer, see -https://github.com/google/sanitizers/wiki/AddressSanitizer - -The checks are done automatically in the library call of `checkRouterRunning` -(ie at beginning of tests when there is a check for all daemons running). -No changes or extra configuration for topotests is required beside compiling -the suite with AddressSanitizer enabled. - -If a daemon crashed, then the errorlog is checked for AddressSanitizer -output. If found, then this is added with context (calling test) to -`/tmp/AddressSanitizer.txt` in markdown compatible format. - -Compiling for GCC AddressSanitizer requires to use gcc as a linker as well -(instead of ld). Here is a suggest way to compile frr with AddressSanitizer -for `stable/3.0` branch: - - git clone https://github.com/FRRouting/frr.git - cd frr - git checkout stable/3.0 - ./bootstrap.sh - export CC=gcc - export CFLAGS="-O1 -g -fsanitize=address -fno-omit-frame-pointer" - export LD=gcc - export LDFLAGS="-g -fsanitize=address -ldl" - ./configure --enable-shared=no \ - --prefix=/usr/lib/frr --sysconfdir=/etc/frr \ - --localstatedir=/var/run/frr \ - --sbindir=/usr/lib/frr --bindir=/usr/lib/frr \ - --enable-exampledir=/usr/lib/frr/examples \ - --with-moduledir=/usr/lib/frr/modules \ - --enable-multipath=0 --enable-rtadv \ - --enable-tcp-zebra --enable-fpm --enable-pimd - make - sudo make install - # Create symlink for vtysh, so topotest finds it in /usr/lib/frr - sudo ln -s /usr/lib/frr/vtysh /usr/bin/ - -and create `frr` user and `frrvty` group as shown above - -## License - -All the configs and scripts are licensed under a ISC-style license. See -Python scripts for details. +Documentation is located in /doc/developer/topotests.rst diff --git a/tests/topotests/SNIPPETS.md b/tests/topotests/SNIPPETS.md deleted file mode 100644 index 6c16c44af6..0000000000 --- a/tests/topotests/SNIPPETS.md +++ /dev/null @@ -1,275 +0,0 @@ -# Snippets - -This document will describe common snippets of code that are frequently -needed to perform some test checks. - - -## Checking for router / test failures - -The following check uses the topogen API to check for software failure -(e.g. zebra died) and/or for errors manually set by `Topogen.set_error()`. - -```py -# Get the topology reference -tgen = get_topogen() - -# Check for errors in the topology -if tgen.routers_have_failure(): - # Skip the test with the topology errors as reason - pytest.skip(tgen.errors) -``` - - -## Checking FRR routers version - -This code snippet is usually run after the topology setup to make sure -all routers instantiated in the topology have the correct software -version. - -```py -# Get the topology reference -tgen = get_topogen() - -# Get the router list -router_list = tgen.routers() - -# Run the check for all routers -for router in router_list.values(): - if router.has_version('<', '3'): - # Set topology error, so the next tests are skipped - tgen.set_error('unsupported version') -``` - -A sample of this snippet in a test can be found -[here](ldp-vpls-topo1/test_ldp_vpls_topo1.py). - - -## Interacting with equipments - -You might want to interact with the topology equipments during the tests -and there are different ways to do so. - -Notes: - -1. -> When using the Topogen API, all the equipments code derive from -> `Topogear` ([lib/topogen.py](lib/topogen.py)). If you feel brave you -> can look by yourself how the abstractions that will be mentioned here -> works. - -2. -> When not using the `Topogen` API there is only one way to interact -> with the equipments, which is by calling the `mininet` API functions -> directly to spawn commands. - - -### Interacting with the Linux sandbox - -*Without `Topogen`* - -```py -global net -output = net['r1'].cmd('echo "foobar"') -print 'output is: {}'.format(output) -``` - ---- - -*With `Topogen`* - -```py -tgen = get_topogen() -output = tgen.gears['r1'].run('echo "foobar"') -print 'output is: {}'.format(output) -``` - - -### Interacting with VTYSH - -*Without `Topogen`* - -```py -global net -output = net['r1'].cmd('vtysh "show ip route" 2>/dev/null') -print 'output is: {}'.format(output) -``` - ---- - -*With `Topogen`* - -```py -tgen = get_topogen() -output = tgen.gears['r1'].vtysh_cmd("show ip route") -print 'output is: {}'.format(output) -``` - -`Topogen` also supports sending multiple lines of command: - -```py -tgen = get_topogen() -output = tgen.gears['r1'].vtysh_cmd(""" -configure terminal -router bgp 10 - bgp router-id 10.0.255.1 - neighbor 1.2.3.4 remote-as 10 - ! -router bgp 11 - bgp router-id 10.0.255.2 - ! -""") -print 'output is: {}'.format(output) -``` - -You might also want to run multiple commands and get only the commands -that failed: - -```py -tgen = get_topogen() -output = tgen.gears['r1'].vtysh_multicmd(""" -configure terminal -router bgp 10 - bgp router-id 10.0.255.1 - neighbor 1.2.3.4 remote-as 10 - ! -router bgp 11 - bgp router-id 10.0.255.2 - ! -""", pretty_output=false) -print 'output is: {}'.format(output) -``` - -Translating vtysh JSON output into Python structures: -```py -tgen = get_topogen() -json_output = tgen.gears['r1'].vtysh_cmd("show ip route json", isjson=True) -output = json.dumps(json_output, indent=4) -print 'output is: {}'.format(output) - -# You can also access the data structure as normal. For example: -# protocol = json_output['1.1.1.1/32']['protocol'] -# assert protocol == "ospf", "wrong protocol" -``` - -*NOTE:* `vtysh_(multi)cmd` is only available for router type of -equipments. - - -### Invoking `mininet` CLI - -*Without `Topogen`* - -```py -CLI(net) -``` - ---- - -*With `Topogen`* -```py -tgen = get_topogen() -tgen.mininet_cli() -``` - - -## Reading files - -Loading a normal text file content in the current directory: - -```py -# If you are using Topogen -# CURDIR = CWD -# -# Otherwise find the directory manually: -CURDIR = os.path.dirname(os.path.realpath(__file__)) - -file_name = '{}/r1/show_ip_route.txt'.format(CURDIR) -file_content = open(file_name).read() -``` - -Loading JSON from a file: - -```py -import json - -file_name = '{}/r1/show_ip_route.json'.format(CURDIR) -file_content = json.loads(open(file_name).read()) -``` - - -## Comparing JSON output - -After obtaining JSON output formated with Python data structures, you -may use it to assert a minimalist schema: - -```py -tgen = get_topogen() -json_output = tgen.gears['r1'].vtysh_cmd("show ip route json", isjson=True) - -expect = { - '1.1.1.1/32': { - 'protocol': 'ospf' - } -} - -assertmsg = "route 1.1.1.1/32 was not learned through OSPF" -assert json_cmp(json_output, expect) is None, assertmsg -``` - -`json_cmp` function description (it might be outdated, you can find the -latest description in the source code at [lib/topotest.py](lib/topotest.py)): - -```text - JSON compare function. Receives two parameters: - * `d1`: json value - * `d2`: json subset which we expect - - Returns `None` when all keys that `d1` has matches `d2`, - otherwise a string containing what failed. - - Note: key absence can be tested by adding a key with value `None`. -``` - - -## Pausing execution - -Preferably, choose the `sleep` function that `topotest` provides, as it -prints a notice during the test execution to help debug topology test -execution time. - -```py -# Using the topotest sleep -from lib import topotest - -topotest.sleep(10, 'waiting 10 seconds for bla') -# or just tell it the time: -# topotest.sleep(10) -# It will print 'Sleeping for 10 seconds'. - -# Or you can also use the Python sleep, but it won't show anything -from time import sleep -sleep(5) -``` - - -## `ip route` Linux command as JSON - -`topotest` has two helpers implemented that parses the output of -`ip route` commands to JSON. It might simplify your comparison needs by -only needing to provide a Python dictionary. - -```py -from lib import topotest - -tgen = get_topogen() -routes = topotest.ip4_route(tgen.gears['r1']) -expected = { - '10.0.1.0/24': {}, - '10.0.2.0/24': { - 'dev': 'r1-eth0' - } -} - -assertmsg = "failed to find 10.0.1.0/24 and/or 10.0.2.0/24" -assert json_cmp(routes, expected) is None, assertmsg -``` diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py index 31e23faede..ce542413ba 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py @@ -141,7 +141,10 @@ class ThisTestTopo(Topo): switch[1].add_link(tgen.gears['r2'], nodeif='r2-eth2') switch[1].add_link(tgen.gears['r3'], nodeif='r3-eth1') +l3mdev_accept = 0 + def ltemplatePreRouterStartHook(): + global l3mdev_accept cc = ltemplateRtrCmd() krel = platform.release() tgen = get_topogen() @@ -172,7 +175,7 @@ def ltemplatePreRouterStartHook(): 'ip ru add oif {0}-cust1 table 10', 'ip ru add iif {0}-cust1 table 10', 'ip link set dev {0}-cust1 up', - 'sysctl -w net.ipv4.udp_l3mdev_accept={}'.format(l3mdev_accept)] + 'sysctl -w net.ipv4.tcp_l3mdev_accept={}'.format(l3mdev_accept)] for rtr in rtrs: router = tgen.gears[rtr] for cmd in cmds: @@ -202,7 +205,7 @@ def ltemplatePreRouterStartHook(): 'ip ru add oif {0}-cust2 table 20', 'ip ru add iif {0}-cust2 table 20', 'ip link set dev {0}-cust2 up', - 'sysctl -w net.ipv4.udp_l3mdev_accept={}'.format(l3mdev_accept)] + 'sysctl -w net.ipv4.tcp_l3mdev_accept={}'.format(l3mdev_accept)] for rtr in rtrs: for cmd in cmds: cc.doCmd(tgen, rtr, cmd.format(rtr)) diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py index 778d504040..f5d73a8c49 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py @@ -1,11 +1,12 @@ from lutil import luCommand - -rtrs = ['r1', 'r3', 'r4', 'ce1', 'ce2', 'ce3', 'ce4'] -for rtr in rtrs: +from customize import l3mdev_accept +l3mdev_rtrs = ['r1', 'r3', 'r4', 'ce4'] +for rtr in l3mdev_rtrs: luCommand(rtr,'sysctl net.ipv4.tcp_l3mdev_accept',' = \d*','none','') found = luLast() - luCommand(rtr,'ss -aep',':bgp','pass','IPv4:bgp, l3mdev%s' % found.group(0)) - luCommand(rtr,'ss -aep',':.:bgp','pass','IPv6:bgp') + luCommand(rtr,'ss -naep',':179','pass','IPv4:bgp, l3mdev{}'.format(found.group(0))) + luCommand(rtr,'ss -naep',':.*:179','pass','IPv6:bgp') + luCommand(rtr,'sysctl net.ipv4.tcp_l3mdev_accept',' = {}'.format(l3mdev_accept),'pass','l3mdev matches expected (real/expected{}/{})'.format(found.group(0),l3mdev_accept)) rtrs = ['r1', 'r3', 'r4'] for rtr in rtrs: diff --git a/tests/topotests/eigrp-topo1/r1/show_ip_route.json_ref b/tests/topotests/eigrp-topo1/r1/show_ip_route.json_ref index 36dd5da597..26fa7ca415 100644 --- a/tests/topotests/eigrp-topo1/r1/show_ip_route.json_ref +++ b/tests/topotests/eigrp-topo1/r1/show_ip_route.json_ref @@ -3,7 +3,7 @@ { "prefix":"192.168.1.0/24", "protocol":"eigrp", - "metric":0, + "metric":28160, "nexthops":[ { "directlyConnected":true, @@ -31,7 +31,7 @@ "prefix":"192.168.3.0/24", "protocol":"eigrp", "selected":true, - "metric":0, + "metric":33280, "nexthops":[ { "fib":true, @@ -47,7 +47,7 @@ { "prefix":"193.1.1.0/26", "protocol":"eigrp", - "metric":0, + "metric":28160, "nexthops":[ { "directlyConnected":true, @@ -75,7 +75,7 @@ "prefix":"193.1.2.0/24", "protocol":"eigrp", "selected":true, - "metric":0, + "metric":30720, "nexthops":[ { "fib":true, diff --git a/tests/topotests/eigrp-topo1/r1/zebra.conf b/tests/topotests/eigrp-topo1/r1/zebra.conf index 8537f6dd80..56ae4a66f4 100644 --- a/tests/topotests/eigrp-topo1/r1/zebra.conf +++ b/tests/topotests/eigrp-topo1/r1/zebra.conf @@ -1,4 +1,5 @@ log file zebra.log +debug zebra rib detail ! hostname r1 ! diff --git a/tests/topotests/eigrp-topo1/r2/show_ip_route.json_ref b/tests/topotests/eigrp-topo1/r2/show_ip_route.json_ref index 44903ce3ff..71c931b17a 100644 --- a/tests/topotests/eigrp-topo1/r2/show_ip_route.json_ref +++ b/tests/topotests/eigrp-topo1/r2/show_ip_route.json_ref @@ -4,7 +4,7 @@ "prefix":"192.168.1.0/24", "protocol":"eigrp", "selected":true, - "metric":0, + "metric":30720, "nexthops":[ { "fib":true, @@ -21,7 +21,7 @@ "prefix":"192.168.3.0/24", "protocol":"eigrp", "selected":true, - "metric":0, + "metric":30720, "nexthops":[ { "fib":true, @@ -37,7 +37,7 @@ { "prefix":"193.1.1.0/26", "protocol":"eigrp", - "metric":0, + "metric":28160, "nexthops":[ { "directlyConnected":true, @@ -64,7 +64,7 @@ { "prefix":"193.1.2.0/24", "protocol":"eigrp", - "metric":0, + "metric":28160, "nexthops":[ { "directlyConnected":true, diff --git a/tests/topotests/eigrp-topo1/r3/show_ip_route.json_ref b/tests/topotests/eigrp-topo1/r3/show_ip_route.json_ref index d80e1d97e6..5e0b79d811 100644 --- a/tests/topotests/eigrp-topo1/r3/show_ip_route.json_ref +++ b/tests/topotests/eigrp-topo1/r3/show_ip_route.json_ref @@ -4,7 +4,7 @@ "prefix":"192.168.1.0/24", "protocol":"eigrp", "selected":true, - "metric":0, + "metric":33280, "nexthops":[ { "fib":true, @@ -38,7 +38,7 @@ { "prefix":"192.168.3.0/24", "protocol":"eigrp", - "metric":0, + "metric":28160, "nexthops":[ { "directlyConnected":true, @@ -66,7 +66,7 @@ "prefix":"193.1.1.0/26", "protocol":"eigrp", "selected":true, - "metric":0, + "metric":30720, "nexthops":[ { "fib":true, @@ -82,7 +82,7 @@ { "prefix":"193.1.2.0/24", "protocol":"eigrp", - "metric":0, + "metric":28160, "nexthops":[ { "directlyConnected":true, diff --git a/tests/topotests/eigrp-topo1/test_eigrp_topo1.py b/tests/topotests/eigrp-topo1/test_eigrp_topo1.py index de8cb81f8f..1c00face43 100755 --- a/tests/topotests/eigrp-topo1/test_eigrp_topo1.py +++ b/tests/topotests/eigrp-topo1/test_eigrp_topo1.py @@ -153,7 +153,6 @@ def test_eigrp_routes(): assertmsg = '"show ip eigrp topo" mismatches on {}'.format(router.name) assert topotest.json_cmp(actual, expected) is None, assertmsg - def test_zebra_ipv4_routingTable(): "Test 'show ip route'" @@ -172,6 +171,16 @@ def test_zebra_ipv4_routingTable(): assertmsg = 'Zebra IPv4 Routing Table verification failed for router {}'.format(router.name) assert topotest.json_cmp(output, expected) is None, assertmsg +def test_shut_interface_and_recover(): + "Test shutdown of an interface and recovery of the interface" + + tgen = get_topogen() + router = tgen.gears['r1'] + router.run('ip link set r1-eth1 down') + topotest.sleep(5, 'Waiting for EIGRP convergence') + router.run('ip link set r1-eth1 up') + + def test_shutdown_check_stderr(): if os.environ.get('TOPOTESTS_CHECK_STDERR') is None: diff --git a/tests/topotests/ospf-topo1-vrf/r1/zebra.conf b/tests/topotests/ospf-topo1-vrf/r1/zebra.conf index b1cf342898..e826793657 100644 --- a/tests/topotests/ospf-topo1-vrf/r1/zebra.conf +++ b/tests/topotests/ospf-topo1-vrf/r1/zebra.conf @@ -1,3 +1,7 @@ +debug zebra kernel +debug zebra dplane detail +debug zebra rib +debug zebra event ! hostname r1 password zebra diff --git a/tools/frr.service b/tools/frr.service index c7568593b3..aa45f420fe 100644 --- a/tools/frr.service +++ b/tools/frr.service @@ -1,7 +1,9 @@ [Unit] Description=FRRouting Documentation=https://frrouting.readthedocs.io/en/latest/setup.html -After=networking.service +Wants=network.target +After=network-pre.target systemd-sysctl.service +Before=network.target OnFailure=heartbeat-failed@%n.service [Service] @@ -20,4 +22,4 @@ ExecStop=/usr/lib/frr/frrinit.sh stop ExecReload=/usr/lib/frr/frrinit.sh reload [Install] -WantedBy=network-online.target +WantedBy=multi-user.target diff --git a/tools/gen_northbound_callbacks.c b/tools/gen_northbound_callbacks.c index eded87c12e..f6c757f5d7 100644 --- a/tools/gen_northbound_callbacks.c +++ b/tools/gen_northbound_callbacks.c @@ -54,7 +54,7 @@ static struct nb_callback_info { "enum nb_event event, const struct lyd_node *dnode, union nb_resource *resource", }, { - .operation = NB_OP_DELETE, + .operation = NB_OP_DESTROY, .return_type = "int ", .return_value = "NB_OK", .arguments = diff --git a/tools/subdir.am b/tools/subdir.am index ff41fe2c63..7713bb1ade 100644 --- a/tools/subdir.am +++ b/tools/subdir.am @@ -23,10 +23,10 @@ tools_permutations_SOURCES = tools/permutations.c tools_permutations_LDADD = lib/libfrr.la tools_gen_northbound_callbacks_SOURCES = tools/gen_northbound_callbacks.c -tools_gen_northbound_callbacks_LDADD = lib/libfrr.la -lyang +tools_gen_northbound_callbacks_LDADD = lib/libfrr.la $(LIBYANG_LIBS) tools_gen_yang_deviations_SOURCES = tools/gen_yang_deviations.c -tools_gen_yang_deviations_LDADD = lib/libfrr.la -lyang +tools_gen_yang_deviations_LDADD = lib/libfrr.la $(LIBYANG_LIBS) tools_ssd_SOURCES = tools/start-stop-daemon.c diff --git a/vtysh/subdir.am b/vtysh/subdir.am index c9cdb58543..74595788b0 100644 --- a/vtysh/subdir.am +++ b/vtysh/subdir.am @@ -24,7 +24,7 @@ noinst_HEADERS += \ vtysh/vtysh_user.h \ # end -vtysh_vtysh_LDADD = lib/libfrr.la @LIBCAP@ @LIBREADLINE@ @LIBS@ @LIBPAM@ +vtysh_vtysh_LDADD = lib/libfrr.la $(LIBCAP) $(LIBREADLINE) $(LIBS) $(LIBPAM) AM_V_EXTRACT = $(am__v_EXTRACT_$(V)) am__v_EXTRACT_ = $(am__v_EXTRACT_$(AM_DEFAULT_VERBOSITY)) diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 340c9be601..41fd6ed7d6 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -3330,7 +3330,7 @@ static void vtysh_client_sorted_insert(struct vtysh_client *head_client, #define MAXIMUM_INSTANCES 10 -static void vtysh_update_all_insances(struct vtysh_client *head_client) +static void vtysh_update_all_instances(struct vtysh_client *head_client) { struct vtysh_client *client; DIR *dir; @@ -3373,7 +3373,7 @@ static int vtysh_connect_all_instances(struct vtysh_client *head_client) struct vtysh_client *client; int rc = 0; - vtysh_update_all_insances(head_client); + vtysh_update_all_instances(head_client); client = head_client->next; while (client) { diff --git a/watchfrr/subdir.am b/watchfrr/subdir.am index f0b49c9a84..c27491e55c 100644 --- a/watchfrr/subdir.am +++ b/watchfrr/subdir.am @@ -13,7 +13,7 @@ noinst_HEADERS += \ watchfrr/watchfrr_errors.h \ # end -watchfrr_watchfrr_LDADD = lib/libfrr.la @LIBCAP@ +watchfrr_watchfrr_LDADD = lib/libfrr.la $(LIBCAP) watchfrr_watchfrr_SOURCES = \ watchfrr/watchfrr.c \ watchfrr/watchfrr_errors.c \ diff --git a/yang/libyang_plugins/subdir.am b/yang/libyang_plugins/subdir.am index 7164789083..fe5f34a28a 100644 --- a/yang/libyang_plugins/subdir.am +++ b/yang/libyang_plugins/subdir.am @@ -8,7 +8,7 @@ else libyang_plugins_LTLIBRARIES += yang/libyang_plugins/frr_user_types.la endif -yang_libyang_plugins_frr_user_types_la_CFLAGS = $(WERROR) +yang_libyang_plugins_frr_user_types_la_CFLAGS = $(WERROR) $(LIBYANG_CFLAGS) yang_libyang_plugins_frr_user_types_la_LDFLAGS = -avoid-version -module -shared -export-dynamic yang_libyang_plugins_frr_user_types_la_LIBADD = yang_libyang_plugins_frr_user_types_la_SOURCES = yang/libyang_plugins/frr_user_types.c diff --git a/zebra/debug.c b/zebra/debug.c index 0eb06d7f25..87999a1bbc 100644 --- a/zebra/debug.c +++ b/zebra/debug.c @@ -23,6 +23,10 @@ #include "command.h" #include "debug.h" +#ifndef VTYSH_EXTRACT_PL +#include "zebra/debug_clippy.c" +#endif + /* For debug statement. */ unsigned long zebra_debug_event; unsigned long zebra_debug_packet; @@ -34,6 +38,7 @@ unsigned long zebra_debug_mpls; unsigned long zebra_debug_vxlan; unsigned long zebra_debug_pw; unsigned long zebra_debug_dplane; +unsigned long zebra_debug_mlag; DEFINE_HOOK(zebra_debug_show_debugging, (struct vty *vty), (vty)); @@ -94,6 +99,8 @@ DEFUN_NOSH (show_debugging_zebra, vty_out(vty, " Zebra detailed dataplane debugging is on\n"); else if (IS_ZEBRA_DEBUG_DPLANE) vty_out(vty, " Zebra dataplane debugging is on\n"); + if (IS_ZEBRA_DEBUG_MLAG) + vty_out(vty, " Zebra mlag debugging is on\n"); hook_call(zebra_debug_show_debugging, vty); return CMD_SUCCESS; @@ -284,6 +291,21 @@ DEFUN (debug_zebra_dplane, return CMD_SUCCESS; } +DEFPY (debug_zebra_mlag, + debug_zebra_mlag_cmd, + "[no$no] debug zebra mlag", + NO_STR + DEBUG_STR + "Zebra configuration\n" + "Debug option set for mlag events\n") +{ + if (no) + UNSET_FLAG(zebra_debug_mlag, ZEBRA_DEBUG_MLAG); + else + SET_FLAG(zebra_debug_mlag, ZEBRA_DEBUG_MLAG); + return CMD_SUCCESS; +} + DEFUN (no_debug_zebra_events, no_debug_zebra_events_cmd, "no debug zebra events", @@ -507,6 +529,7 @@ void zebra_debug_init(void) zebra_debug_vxlan = 0; zebra_debug_pw = 0; zebra_debug_dplane = 0; + zebra_debug_mlag = 0; install_node(&debug_node, config_write_debug); @@ -523,6 +546,7 @@ void zebra_debug_init(void) install_element(ENABLE_NODE, &debug_zebra_rib_cmd); install_element(ENABLE_NODE, &debug_zebra_fpm_cmd); install_element(ENABLE_NODE, &debug_zebra_dplane_cmd); + install_element(ENABLE_NODE, &debug_zebra_mlag_cmd); install_element(ENABLE_NODE, &no_debug_zebra_events_cmd); install_element(ENABLE_NODE, &no_debug_zebra_nht_cmd); install_element(ENABLE_NODE, &no_debug_zebra_mpls_cmd); diff --git a/zebra/debug.h b/zebra/debug.h index cd15441ec8..c79cd96c21 100644 --- a/zebra/debug.h +++ b/zebra/debug.h @@ -51,6 +51,8 @@ #define ZEBRA_DEBUG_DPLANE 0x01 #define ZEBRA_DEBUG_DPLANE_DETAILED 0x02 +#define ZEBRA_DEBUG_MLAG 0x01 + /* Debug related macro. */ #define IS_ZEBRA_DEBUG_EVENT (zebra_debug_event & ZEBRA_DEBUG_EVENT) @@ -79,6 +81,8 @@ #define IS_ZEBRA_DEBUG_DPLANE_DETAIL \ (zebra_debug_dplane & ZEBRA_DEBUG_DPLANE_DETAILED) +#define IS_ZEBRA_DEBUG_MLAG (zebra_debug_mlag & ZEBRA_DEBUG_MLAG) + extern unsigned long zebra_debug_event; extern unsigned long zebra_debug_packet; extern unsigned long zebra_debug_kernel; @@ -89,6 +93,7 @@ extern unsigned long zebra_debug_mpls; extern unsigned long zebra_debug_vxlan; extern unsigned long zebra_debug_pw; extern unsigned long zebra_debug_dplane; +extern unsigned long zebra_debug_mlag; extern void zebra_debug_init(void); diff --git a/zebra/interface.c b/zebra/interface.c index 8bb5c6e8ef..229f9c1da4 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -41,7 +41,7 @@ #include "zebra/interface.h" #include "zebra/rib.h" #include "zebra/rt.h" -#include "zebra/zserv.h" +#include "zebra/zebra_router.h" #include "zebra/redistribute.h" #include "zebra/debug.h" #include "zebra/irdp.h" @@ -135,6 +135,8 @@ static int if_zebra_new_hook(struct interface *ifp) rtadv->DefaultPreference = RTADV_PREF_MEDIUM; rtadv->AdvPrefixList = list_new(); + rtadv->AdvRDNSSList = list_new(); + rtadv->AdvDNSSLList = list_new(); } #endif /* HAVE_RTADV */ @@ -153,7 +155,7 @@ static int if_zebra_new_hook(struct interface *ifp) * of seconds and ask again. Hopefully it's all settled * down upon startup. */ - thread_add_timer(zebrad.master, if_zebra_speed_update, ifp, 15, + thread_add_timer(zrouter.master, if_zebra_speed_update, ifp, 15, &zebra_if->speed_update); return 0; } @@ -175,6 +177,8 @@ static int if_zebra_delete_hook(struct interface *ifp) rtadv = &zebra_if->rtadv; list_delete(&rtadv->AdvPrefixList); + list_delete(&rtadv->AdvRDNSSList); + list_delete(&rtadv->AdvDNSSLList); #endif /* HAVE_RTADV */ THREAD_OFF(zebra_if->speed_update); diff --git a/zebra/interface.h b/zebra/interface.h index 01dd697772..1dbcf33fad 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -168,6 +168,22 @@ struct rtadvconf { int DefaultPreference; #define RTADV_PREF_MEDIUM 0x0 /* Per RFC4191. */ + /* + * List of recursive DNS servers to include in the RDNSS option. + * See [RFC8106 5.1] + * + * Default: empty list; do not emit RDNSS option + */ + struct list *AdvRDNSSList; + + /* + * List of DNS search domains to include in the DNSSL option. + * See [RFC8106 5.2] + * + * Default: empty list; do not emit DNSSL option + */ + struct list *AdvDNSSLList; + uint8_t inFastRexmit; /* True if we're rexmits faster than usual */ /* Track if RA was configured by BGP or by the Operator or both */ @@ -182,6 +198,41 @@ struct rtadvconf { #define RTADV_NUM_FAST_REXMITS 4 /* Fast Rexmit RA 4 times on certain events */ }; +struct rtadv_rdnss { + /* Address of recursive DNS server to advertise */ + struct in6_addr addr; + + /* + * Lifetime in seconds; all-ones means infinity, zero + * stop using it. + */ + uint32_t lifetime; + + /* If lifetime not set, use a default of 3*MaxRtrAdvInterval */ + int lifetime_set; +}; + +/* + * [RFC1035 2.3.4] sets the maximum length of a domain name (a sequence of + * labels, each prefixed by a length octet) at 255 octets. + */ +#define RTADV_MAX_ENCODED_DOMAIN_NAME 255 + +struct rtadv_dnssl { + /* Domain name without trailing root zone dot (NUL-terminated) */ + char name[RTADV_MAX_ENCODED_DOMAIN_NAME - 1]; + + /* Name encoded as in [RFC1035 3.1] */ + uint8_t encoded_name[RTADV_MAX_ENCODED_DOMAIN_NAME]; + + /* Actual length of encoded_name */ + size_t encoded_len; + + /* Lifetime as for RDNSS */ + uint32_t lifetime; + int lifetime_set; +}; + #endif /* HAVE_RTADV */ /* Zebra interface type - ones of interest. */ diff --git a/zebra/irdp_interface.c b/zebra/irdp_interface.c index ffc49d2c13..c0b772cd01 100644 --- a/zebra/irdp_interface.c +++ b/zebra/irdp_interface.c @@ -45,7 +45,7 @@ #include "zebra/interface.h" #include "zebra/rtadv.h" #include "zebra/rib.h" -#include "zebra/zserv.h" +#include "zebra/zebra_router.h" #include "zebra/redistribute.h" #include "zebra/irdp.h" #include "zebra/zebra_errors.h" @@ -285,7 +285,7 @@ static void irdp_if_start(struct interface *ifp, int multicast, timer); irdp->t_advertise = NULL; - thread_add_timer(zebrad.master, irdp_send_thread, ifp, timer, + thread_add_timer(zrouter.master, irdp_send_thread, ifp, timer, &irdp->t_advertise); } diff --git a/zebra/irdp_main.c b/zebra/irdp_main.c index 9300ba6034..a9734056bc 100644 --- a/zebra/irdp_main.c +++ b/zebra/irdp_main.c @@ -56,7 +56,7 @@ #include "zebra/interface.h" #include "zebra/rtadv.h" #include "zebra/rib.h" -#include "zebra/zserv.h" +#include "zebra/zebra_router.h" #include "zebra/redistribute.h" #include "zebra/irdp.h" #include "zebra/zebra_errors.h" @@ -113,7 +113,7 @@ int irdp_sock_init(void) }; t_irdp_raw = NULL; - thread_add_read(zebrad.master, irdp_read_raw, NULL, sock, &t_irdp_raw); + thread_add_read(zrouter.master, irdp_read_raw, NULL, sock, &t_irdp_raw); return sock; } @@ -245,7 +245,7 @@ int irdp_send_thread(struct thread *t_advert) timer); irdp->t_advertise = NULL; - thread_add_timer(zebrad.master, irdp_send_thread, ifp, timer, + thread_add_timer(zrouter.master, irdp_send_thread, ifp, timer, &irdp->t_advertise); return 0; } @@ -306,7 +306,7 @@ void process_solicit(struct interface *ifp) timer = (random() % MAX_RESPONSE_DELAY) + 1; irdp->t_advertise = NULL; - thread_add_timer(zebrad.master, irdp_send_thread, ifp, timer, + thread_add_timer(zrouter.master, irdp_send_thread, ifp, timer, &irdp->t_advertise); } diff --git a/zebra/irdp_packet.c b/zebra/irdp_packet.c index bebccd7168..774d84d66d 100644 --- a/zebra/irdp_packet.c +++ b/zebra/irdp_packet.c @@ -58,7 +58,7 @@ #include "zebra/interface.h" #include "zebra/rtadv.h" #include "zebra/rib.h" -#include "zebra/zserv.h" +#include "zebra/zebra_router.h" #include "zebra/redistribute.h" #include "zebra/irdp.h" #include "zebra/zebra_errors.h" @@ -230,7 +230,7 @@ int irdp_read_raw(struct thread *r) int irdp_sock = THREAD_FD(r); t_irdp_raw = NULL; - thread_add_read(zebrad.master, irdp_read_raw, NULL, irdp_sock, + thread_add_read(zrouter.master, irdp_read_raw, NULL, irdp_sock, &t_irdp_raw); ret = irdp_recvmsg(irdp_sock, (uint8_t *)buf, IRDP_RX_BUF, &ifindex); diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index c88bfbb101..2f850c6338 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -43,7 +43,8 @@ #include "mpls.h" #include "lib_errors.h" -#include "zebra/zserv.h" +//#include "zebra/zserv.h" +#include "zebra/zebra_router.h" #include "zebra/zebra_ns.h" #include "zebra/zebra_vrf.h" #include "zebra/rt.h" @@ -388,7 +389,7 @@ static int kernel_read(struct thread *thread) netlink_parse_info(netlink_information_fetch, &zns->netlink, &dp_info, 5, 0); zns->t_netlink = NULL; - thread_add_read(zebrad.master, kernel_read, zns, zns->netlink.sock, + thread_add_read(zrouter.master, kernel_read, zns, zns->netlink.sock, &zns->t_netlink); return 0; @@ -1158,7 +1159,7 @@ void kernel_init(struct zebra_ns *zns) zns->t_netlink = NULL; - thread_add_read(zebrad.master, kernel_read, zns, + thread_add_read(zrouter.master, kernel_read, zns, zns->netlink.sock, &zns->t_netlink); rt_netlink_init(); diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index acd7f911dc..792756efeb 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -43,7 +43,7 @@ #include "zebra/rt.h" #include "zebra/interface.h" -#include "zebra/zserv.h" +#include "zebra/zebra_router.h" #include "zebra/debug.h" #include "zebra/kernel_socket.h" #include "zebra/rib.h" @@ -1372,7 +1372,7 @@ static int kernel_read(struct thread *thread) return 0; } - thread_add_read(zebrad.master, kernel_read, NULL, sock, NULL); + thread_add_read(zrouter.master, kernel_read, NULL, sock, NULL); if (IS_ZEBRA_DEBUG_KERNEL) rtmsg_debug(&buf.r.rtm); @@ -1445,7 +1445,7 @@ static void routing_socket(struct zebra_ns *zns) zlog_warn ("Can't set O_NONBLOCK to routing socket");*/ /* kernel_read needs rewrite. */ - thread_add_read(zebrad.master, kernel_read, NULL, routing_sock, NULL); + thread_add_read(zrouter.master, kernel_read, NULL, routing_sock, NULL); } /* Exported interface function. This function simply calls diff --git a/zebra/label_manager.c b/zebra/label_manager.c index 13472059a0..1b17845e41 100644 --- a/zebra/label_manager.c +++ b/zebra/label_manager.c @@ -34,7 +34,8 @@ #include "lib/zclient.h" #include "lib/libfrr.h" -#include "zebra/zserv.h" +//#include "zebra/zserv.h" +#include "zebra/zebra_router.h" #include "zebra/label_manager.h" #include "zebra/zebra_errors.h" @@ -294,7 +295,7 @@ static int lm_zclient_connect(struct thread *t) if (zclient_socket_connect(zclient) < 0) { flog_err(EC_ZEBRA_LM_CLIENT_CONNECTION_FAILED, "Error connecting synchronous zclient!"); - thread_add_timer(zebrad.master, lm_zclient_connect, zclient, + thread_add_timer(zrouter.master, lm_zclient_connect, zclient, CONNECTION_DELAY, &zclient->t_connect); return -1; } @@ -318,7 +319,7 @@ static void lm_zclient_init(char *lm_zserv_path) lm_zserv_path); /* Set default values. */ - zclient = zclient_new(zebrad.master, &zclient_options_default); + zclient = zclient_new(zrouter.master, &zclient_options_default); zclient->privs = &zserv_privs; zclient->sock = -1; zclient->t_connect = NULL; diff --git a/zebra/main.c b/zebra/main.c index b54c36c109..c605050c57 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -62,12 +62,6 @@ #define ZEBRA_PTM_SUPPORT -/* Zebra instance */ -struct zebra_t zebrad = { - .rtm_table_default = 0, - .packets_to_process = ZEBRA_ZAPI_PACKETS_TO_PROCESS, -}; - /* process id. */ pid_t pid; @@ -156,10 +150,10 @@ static void sigint(void) zebra_dplane_pre_finish(); - for (ALL_LIST_ELEMENTS(zebrad.client_list, ln, nn, client)) + for (ALL_LIST_ELEMENTS(zrouter.client_list, ln, nn, client)) zserv_close_client(client); - list_delete_all_node(zebrad.client_list); + list_delete_all_node(zrouter.client_list); zebra_ptm_finish(); if (retain_mode) @@ -168,8 +162,8 @@ static void sigint(void) if (zvrf) SET_FLAG(zvrf->flags, ZEBRA_VRF_RETAIN); } - if (zebrad.lsp_process_q) - work_queue_free_and_null(&zebrad.lsp_process_q); + if (zrouter.lsp_process_q) + work_queue_free_and_null(&zrouter.lsp_process_q); vrf_terminate(); ns_walk_func(zebra_ns_early_shutdown); @@ -179,7 +173,7 @@ static void sigint(void) prefix_list_reset(); route_map_finish(); - list_delete(&zebrad.client_list); + list_delete(&zrouter.client_list); /* Indicate that all new dplane work has been enqueued. When that * work is complete, the dataplane will enqueue an event @@ -202,9 +196,6 @@ int zebra_finalize(struct thread *dummy) /* Stop dplane thread and finish any cleanup */ zebra_dplane_shutdown(); - work_queue_free_and_null(&zebrad.ribq); - meta_queue_free(zebrad.mq); - zebra_router_terminate(); frr_fini(); @@ -391,7 +382,7 @@ int main(int argc, char **argv) } } - zebrad.master = frr_init(); + zrouter.master = frr_init(); /* Initialize pthread library */ frr_pthread_init(); @@ -479,7 +470,7 @@ int main(int argc, char **argv) #endif /* HANDLE_NETLINK_FUZZING */ - frr_run(zebrad.master); + frr_run(zrouter.master); /* Not reached... */ return 0; diff --git a/zebra/redistribute.c b/zebra/redistribute.c index c5769ae06f..f98a4c02c3 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -33,7 +33,7 @@ #include "srcdest_table.h" #include "zebra/rib.h" -#include "zebra/zserv.h" +#include "zebra/zebra_router.h" #include "zebra/zebra_ns.h" #include "zebra/zebra_vrf.h" #include "zebra/zebra_routemap.h" @@ -159,10 +159,10 @@ void redistribute_update(const struct prefix *p, const struct prefix *src_p, if (IS_ZEBRA_DEBUG_RIB) { zlog_debug( - "%u:%s: Redist update re %p (type %d), old %p (type %d)", + "%u:%s: Redist update re %p (%s), old %p (%s)", re->vrf_id, prefix2str(p, buf, sizeof(buf)), - re, re->type, prev_re, - prev_re ? prev_re->type : -1); + re, zebra_route_string(re->type), prev_re, + prev_re ? zebra_route_string(prev_re->type) : "None"); } afi = family2afi(p->family); @@ -173,7 +173,7 @@ void redistribute_update(const struct prefix *p, const struct prefix *src_p, return; } - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) { + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { send_redistribute = 0; if (is_default_prefix(p) @@ -229,8 +229,9 @@ void redistribute_delete(const struct prefix *p, const struct prefix *src_p, if (IS_ZEBRA_DEBUG_RIB) { inet_ntop(p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN); - zlog_debug("%u:%s/%d: Redist delete re %p (type %d)", - re->vrf_id, buf, p->prefixlen, re, re->type); + zlog_debug("%u:%s/%d: Redist delete re %p (%s)", + re->vrf_id, buf, p->prefixlen, re, + zebra_route_string(re->type)); } /* Add DISTANCE_INFINITY check. */ @@ -245,7 +246,7 @@ void redistribute_delete(const struct prefix *p, const struct prefix *src_p, return; } - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) { + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { if ((is_default_prefix(p) && vrf_bitmap_check(client->redist_default[afi], re->vrf_id)) @@ -404,12 +405,12 @@ void zebra_interface_up_update(struct interface *ifp) ifp->name, ifp->vrf_id); if (ifp->ptm_status || !ifp->ptm_enable) { - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) - if (vrf_bitmap_check(client->ifinfo, ifp->vrf_id)) { - zsend_interface_update(ZEBRA_INTERFACE_UP, - client, ifp); - zsend_interface_link_params(client, ifp); - } + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, + client)) { + zsend_interface_update(ZEBRA_INTERFACE_UP, + client, ifp); + zsend_interface_link_params(client, ifp); + } } } @@ -423,7 +424,7 @@ void zebra_interface_down_update(struct interface *ifp) zlog_debug("MESSAGE: ZEBRA_INTERFACE_DOWN %s(%u)", ifp->name, ifp->vrf_id); - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) { + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { zsend_interface_update(ZEBRA_INTERFACE_DOWN, client, ifp); } } @@ -438,12 +439,11 @@ void zebra_interface_add_update(struct interface *ifp) zlog_debug("MESSAGE: ZEBRA_INTERFACE_ADD %s(%u)", ifp->name, ifp->vrf_id); - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) - if (vrf_bitmap_check(client->ifinfo, ifp->vrf_id)) { - client->ifadd_cnt++; - zsend_interface_add(client, ifp); - zsend_interface_link_params(client, ifp); - } + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { + client->ifadd_cnt++; + zsend_interface_add(client, ifp); + zsend_interface_link_params(client, ifp); + } } void zebra_interface_delete_update(struct interface *ifp) @@ -455,7 +455,7 @@ void zebra_interface_delete_update(struct interface *ifp) zlog_debug("MESSAGE: ZEBRA_INTERFACE_DELETE %s(%u)", ifp->name, ifp->vrf_id); - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) { + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { client->ifdel_cnt++; zsend_interface_delete(client, ifp); } @@ -487,7 +487,7 @@ void zebra_interface_address_add_update(struct interface *ifp, router_id_add_address(ifc); - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) { client->connected_rt_add_cnt++; zsend_interface_address(ZEBRA_INTERFACE_ADDRESS_ADD, @@ -516,7 +516,7 @@ void zebra_interface_address_delete_update(struct interface *ifp, router_id_del_address(ifc); - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) { client->connected_rt_del_cnt++; zsend_interface_address(ZEBRA_INTERFACE_ADDRESS_DELETE, @@ -537,7 +537,7 @@ void zebra_interface_vrf_update_del(struct interface *ifp, vrf_id_t new_vrf_id) "MESSAGE: ZEBRA_INTERFACE_VRF_UPDATE/DEL %s VRF Id %u -> %u", ifp->name, ifp->vrf_id, new_vrf_id); - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) { + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { /* Need to delete if the client is not interested in the new * VRF. */ zsend_interface_update(ZEBRA_INTERFACE_DOWN, client, ifp); @@ -560,7 +560,7 @@ void zebra_interface_vrf_update_add(struct interface *ifp, vrf_id_t old_vrf_id) "MESSAGE: ZEBRA_INTERFACE_VRF_UPDATE/ADD %s VRF Id %u -> %u", ifp->name, old_vrf_id, ifp->vrf_id); - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) { + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { /* Need to add if the client is interested in the new VRF. */ client->ifadd_cnt++; zsend_interface_add(client, ifp); @@ -612,7 +612,7 @@ int zebra_add_import_table_entry(struct route_node *rn, struct route_entry *re, newre->flags = re->flags; newre->metric = re->metric; newre->mtu = re->mtu; - newre->table = zebrad.rtm_table_default; + newre->table = zrouter.rtm_table_default; newre->nexthop_num = 0; newre->uptime = time(NULL); newre->instance = re->table; @@ -633,7 +633,7 @@ int zebra_del_import_table_entry(struct route_node *rn, struct route_entry *re) rib_delete(afi, SAFI_UNICAST, re->vrf_id, ZEBRA_ROUTE_TABLE, re->table, re->flags, &p, NULL, re->ng.nexthop, - zebrad.rtm_table_default, re->metric, re->distance, false); + zrouter.rtm_table_default, re->metric, re->distance, false); return 0; } @@ -648,7 +648,7 @@ int zebra_import_table(afi_t afi, uint32_t table_id, uint32_t distance, if (!is_zebra_valid_kernel_table(table_id) || ((table_id == RT_TABLE_MAIN) - || (table_id == zebrad.rtm_table_default))) + || (table_id == zrouter.rtm_table_default))) return (-1); if (afi >= AFI_MAX) @@ -811,7 +811,6 @@ void zebra_interface_parameters_update(struct interface *ifp) zlog_debug("MESSAGE: ZEBRA_INTERFACE_LINK_PARAMS %s(%u)", ifp->name, ifp->vrf_id); - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) - if (vrf_bitmap_check(client->ifinfo, ifp->vrf_id)) - zsend_interface_link_params(client, ifp); + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) + zsend_interface_link_params(client, ifp); } diff --git a/zebra/router-id.c b/zebra/router-id.c index c500f79a6c..569ffbab41 100644 --- a/zebra/router-id.c +++ b/zebra/router-id.c @@ -38,15 +38,12 @@ #include "rib.h" #include "vrf.h" -#include "zebra/zserv.h" +#include "zebra/zebra_router.h" #include "zebra/zapi_msg.h" #include "zebra/zebra_vrf.h" #include "zebra/router-id.h" #include "zebra/redistribute.h" -/* master zebra server structure */ -extern struct zebra_t zebrad; - static struct connected *router_id_find_node(struct list *l, struct connected *ifc) { @@ -114,7 +111,7 @@ static void router_id_set(struct prefix *p, vrf_id_t vrf_id) router_id_get(&p2, vrf_id); - for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) zsend_router_id_update(client, &p2, vrf_id); } @@ -145,7 +142,7 @@ void router_id_add_address(struct connected *ifc) if (prefix_same(&before, &after)) return; - for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) zsend_router_id_update(client, &after, zvrf_id(zvrf)); } @@ -177,7 +174,7 @@ void router_id_del_address(struct connected *ifc) if (prefix_same(&before, &after)) return; - for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) zsend_router_id_update(client, &after, zvrf_id(zvrf)); } diff --git a/zebra/rt.h b/zebra/rt.h index 0b14a3ef36..4080b0ccb2 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -32,7 +32,7 @@ #include "zebra/zebra_dplane.h" /* - * Update or delete a route or LSP from the kernel, + * Update or delete a route, LSP, or pseudowire from the kernel, * using info from a dataplane context. */ extern enum zebra_dplane_result kernel_route_update( @@ -41,6 +41,8 @@ extern enum zebra_dplane_result kernel_route_update( extern enum zebra_dplane_result kernel_lsp_update( struct zebra_dplane_ctx *ctx); +enum zebra_dplane_result kernel_pw_update(struct zebra_dplane_ctx *ctx); + extern int kernel_address_add_ipv4(struct interface *, struct connected *); extern int kernel_address_delete_ipv4(struct interface *, struct connected *); extern int kernel_address_add_ipv6(struct interface *, struct connected *); @@ -67,6 +69,8 @@ extern int kernel_del_mac(struct interface *ifp, vlanid_t vid, extern int kernel_add_neigh(struct interface *ifp, struct ipaddr *ip, struct ethaddr *mac, uint8_t flags); extern int kernel_del_neigh(struct interface *ifp, struct ipaddr *ip); +extern int kernel_upd_neigh(struct interface *ifp, struct ipaddr *ip, + struct ethaddr *mac, uint8_t flags, uint16_t state); /* * Southbound Initialization routines to get initial starting diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index ce2d25862d..3868412b20 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -556,6 +556,9 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, parse_encap_mpls(tb[RTA_ENCAP], labels); } + if (rtm->rtm_flags & RTNH_F_ONLINK) + SET_FLAG(nh.flags, NEXTHOP_FLAG_ONLINK); + if (num_labels) nexthop_add_labels(&nh, ZEBRA_LSP_STATIC, num_labels, labels); @@ -663,6 +666,10 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, nexthop_add_labels(nh, ZEBRA_LSP_STATIC, num_labels, labels); + if (nh && (rtnh->rtnh_flags & RTNH_F_ONLINK)) + SET_FLAG(nh->flags, + NEXTHOP_FLAG_ONLINK); + if (rtnh->rtnh_len == 0) break; @@ -1133,8 +1140,7 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen, if (nexthop->type != NEXTHOP_TYPE_BLACKHOLE) addattr32(nlmsg, req_size, RTA_OIF, nexthop->ifindex); - if (nexthop->type == NEXTHOP_TYPE_IFINDEX - || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) { + if (nexthop->type == NEXTHOP_TYPE_IFINDEX) { if (cmd == RTM_NEWROUTE) { if (nexthop->rmap_src.ipv4.s_addr) addattr_l(nlmsg, req_size, RTA_PREFSRC, @@ -1150,23 +1156,6 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen, "nexthop via if %u(%u)", routedesc, nexthop->ifindex, nexthop->vrf_id); } - - if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) { - if (cmd == RTM_NEWROUTE) { - if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6)) - addattr_l(nlmsg, req_size, RTA_PREFSRC, - &nexthop->rmap_src.ipv6, bytelen); - else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6)) - addattr_l(nlmsg, req_size, RTA_PREFSRC, - &nexthop->src.ipv6, bytelen); - } - - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "netlink_route_multipath() (%s): " - "nexthop via if %u(%u)", - routedesc, nexthop->ifindex, nexthop->vrf_id); - } } /* This function takes a nexthop as argument and @@ -1338,8 +1327,7 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen, rtnh->rtnh_ifindex = nexthop->ifindex; /* ifindex */ - if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX - || nexthop->type == NEXTHOP_TYPE_IFINDEX) { + if (nexthop->type == NEXTHOP_TYPE_IFINDEX) { if (nexthop->rmap_src.ipv4.s_addr) *src = &nexthop->rmap_src; else if (nexthop->src.ipv4.s_addr) @@ -2713,12 +2701,12 @@ static int netlink_neigh_update2(struct interface *ifp, struct ipaddr *ip, addattr_l(&req.n, sizeof(req), NDA_LLADDR, mac, 6); if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("Tx %s family %s IF %s(%u) Neigh %s MAC %s flags 0x%x", + zlog_debug("Tx %s family %s IF %s(%u) Neigh %s MAC %s flags 0x%x state 0x%x", nl_msg_type_to_str(cmd), nl_family_to_str(req.ndm.ndm_family), ifp->name, ifp->ifindex, ipaddr2str(ip, buf, sizeof(buf)), mac ? prefix_mac2str(mac, buf2, sizeof(buf2)) - : "null", flags); + : "null", flags, state); return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0); @@ -2749,6 +2737,13 @@ int kernel_del_neigh(struct interface *ifp, struct ipaddr *ip) return netlink_neigh_update2(ifp, ip, NULL, 0, 0, RTM_DELNEIGH); } +int kernel_upd_neigh(struct interface *ifp, struct ipaddr *ip, + struct ethaddr *mac, uint8_t flags, uint16_t state) +{ + return netlink_neigh_update2(ifp, ip, mac, flags, + state, RTM_NEWNEIGH); +} + /* * MPLS label forwarding table change via netlink interface, using dataplane * context information. diff --git a/zebra/rtadv.c b/zebra/rtadv.c index a22f6395c9..5088e2e8e1 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -66,6 +66,9 @@ extern struct zebra_privs_t zserv_privs; #define ALLNODE "ff02::1" #define ALLROUTER "ff02::2" +DEFINE_MTYPE_STATIC(ZEBRA, RTADV_RDNSS, "Router Advertisement RDNSS") +DEFINE_MTYPE_STATIC(ZEBRA, RTADV_DNSSL, "Router Advertisement DNSSL") + /* Order is intentional. Matches RFC4191. This array is also used for command matching, so only modify with care. */ const char *rtadv_pref_strs[] = {"medium", "high", "INVALID", "low", 0}; @@ -355,6 +358,78 @@ static void rtadv_send_packet(int sock, struct interface *ifp) len += sizeof(struct nd_opt_mtu); } + /* + * There is no limit on the number of configurable recursive DNS + * servers or search list entries. We don't want the RA message + * to exceed the link's MTU (risking fragmentation) or even + * blow the stack buffer allocated for it. + */ + size_t max_len = MIN(ifp->mtu6 - 40, sizeof(buf)); + + /* Recursive DNS servers */ + struct rtadv_rdnss *rdnss; + + for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvRDNSSList, node, rdnss)) { + size_t opt_len = + sizeof(struct nd_opt_rdnss) + sizeof(struct in6_addr); + + if (len + opt_len > max_len) { + zlog_warn( + "%s(%u): Tx RA: RDNSS option would exceed MTU, omitting it", + ifp->name, ifp->ifindex); + goto no_more_opts; + } + struct nd_opt_rdnss *opt = (struct nd_opt_rdnss *)(buf + len); + + opt->nd_opt_rdnss_type = ND_OPT_RDNSS; + opt->nd_opt_rdnss_len = opt_len / 8; + opt->nd_opt_rdnss_reserved = 0; + opt->nd_opt_rdnss_lifetime = htonl( + rdnss->lifetime_set + ? rdnss->lifetime + : MAX(1, 0.003 * zif->rtadv.MaxRtrAdvInterval)); + + len += sizeof(struct nd_opt_rdnss); + + IPV6_ADDR_COPY(buf + len, &rdnss->addr); + len += sizeof(struct in6_addr); + } + + /* DNS search list */ + struct rtadv_dnssl *dnssl; + + for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvDNSSLList, node, dnssl)) { + size_t opt_len = sizeof(struct nd_opt_dnssl) + + ((dnssl->encoded_len + 7) & ~7); + + if (len + opt_len > max_len) { + zlog_warn( + "%s(%u): Tx RA: DNSSL option would exceed MTU, omitting it", + ifp->name, ifp->ifindex); + goto no_more_opts; + } + struct nd_opt_dnssl *opt = (struct nd_opt_dnssl *)(buf + len); + + opt->nd_opt_dnssl_type = ND_OPT_DNSSL; + opt->nd_opt_dnssl_len = opt_len / 8; + opt->nd_opt_dnssl_reserved = 0; + opt->nd_opt_dnssl_lifetime = htonl( + dnssl->lifetime_set + ? dnssl->lifetime + : MAX(1, 0.003 * zif->rtadv.MaxRtrAdvInterval)); + + len += sizeof(struct nd_opt_dnssl); + + memcpy(buf + len, dnssl->encoded_name, dnssl->encoded_len); + len += dnssl->encoded_len; + + /* Zero-pad to 8-octet boundary */ + while (len % 8) + buf[len++] = '\0'; + } + +no_more_opts: + msg.msg_name = (void *)&addr; msg.msg_namelen = sizeof(struct sockaddr_in6); msg.msg_iov = &iov; @@ -1533,6 +1608,308 @@ DEFUN (no_ipv6_nd_mtu, return CMD_SUCCESS; } +static struct rtadv_rdnss *rtadv_rdnss_new(void) +{ + return XCALLOC(MTYPE_RTADV_RDNSS, sizeof(struct rtadv_rdnss)); +} + +static void rtadv_rdnss_free(struct rtadv_rdnss *rdnss) +{ + XFREE(MTYPE_RTADV_RDNSS, rdnss); +} + +static struct rtadv_rdnss *rtadv_rdnss_lookup(struct list *list, + struct rtadv_rdnss *rdnss) +{ + struct listnode *node; + struct rtadv_rdnss *p; + + for (ALL_LIST_ELEMENTS_RO(list, node, p)) + if (IPV6_ADDR_SAME(&p->addr, &rdnss->addr)) + return p; + return NULL; +} + +static struct rtadv_rdnss *rtadv_rdnss_get(struct list *list, + struct rtadv_rdnss *rdnss) +{ + struct rtadv_rdnss *p; + + p = rtadv_rdnss_lookup(list, rdnss); + if (p) + return p; + + p = rtadv_rdnss_new(); + memcpy(p, rdnss, sizeof(struct rtadv_rdnss)); + listnode_add(list, p); + + return p; +} + +static void rtadv_rdnss_set(struct zebra_if *zif, struct rtadv_rdnss *rdnss) +{ + struct rtadv_rdnss *p; + + p = rtadv_rdnss_get(zif->rtadv.AdvRDNSSList, rdnss); + p->lifetime = rdnss->lifetime; + p->lifetime_set = rdnss->lifetime_set; +} + +static int rtadv_rdnss_reset(struct zebra_if *zif, struct rtadv_rdnss *rdnss) +{ + struct rtadv_rdnss *p; + + p = rtadv_rdnss_lookup(zif->rtadv.AdvRDNSSList, rdnss); + if (p) { + listnode_delete(zif->rtadv.AdvRDNSSList, p); + rtadv_rdnss_free(p); + return 1; + } + + return 0; +} + +static struct rtadv_dnssl *rtadv_dnssl_new(void) +{ + return XCALLOC(MTYPE_RTADV_DNSSL, sizeof(struct rtadv_dnssl)); +} + +static void rtadv_dnssl_free(struct rtadv_dnssl *dnssl) +{ + XFREE(MTYPE_RTADV_DNSSL, dnssl); +} + +static struct rtadv_dnssl *rtadv_dnssl_lookup(struct list *list, + struct rtadv_dnssl *dnssl) +{ + struct listnode *node; + struct rtadv_dnssl *p; + + for (ALL_LIST_ELEMENTS_RO(list, node, p)) + if (!strcasecmp(p->name, dnssl->name)) + return p; + return NULL; +} + +static struct rtadv_dnssl *rtadv_dnssl_get(struct list *list, + struct rtadv_dnssl *dnssl) +{ + struct rtadv_dnssl *p; + + p = rtadv_dnssl_lookup(list, dnssl); + if (p) + return p; + + p = rtadv_dnssl_new(); + memcpy(p, dnssl, sizeof(struct rtadv_dnssl)); + listnode_add(list, p); + + return p; +} + +static void rtadv_dnssl_set(struct zebra_if *zif, struct rtadv_dnssl *dnssl) +{ + struct rtadv_dnssl *p; + + p = rtadv_dnssl_get(zif->rtadv.AdvDNSSLList, dnssl); + memcpy(p, dnssl, sizeof(struct rtadv_dnssl)); +} + +static int rtadv_dnssl_reset(struct zebra_if *zif, struct rtadv_dnssl *dnssl) +{ + struct rtadv_dnssl *p; + + p = rtadv_dnssl_lookup(zif->rtadv.AdvDNSSLList, dnssl); + if (p) { + listnode_delete(zif->rtadv.AdvDNSSLList, p); + rtadv_dnssl_free(p); + return 1; + } + + return 0; +} + +/* + * Convert dotted domain name (with or without trailing root zone dot) to + * sequence of length-prefixed labels, as described in [RFC1035 3.1]. Write up + * to strlen(in) + 2 octets to out. + * + * Returns the number of octets written to out or -1 if in does not constitute + * a valid domain name. + */ +static int rtadv_dnssl_encode(uint8_t *out, const char *in) +{ + const char *label_start, *label_end; + size_t outp; + + outp = 0; + label_start = in; + + while (*label_start) { + size_t label_len; + + label_end = strchr(label_start, '.'); + if (label_end == NULL) + label_end = label_start + strlen(label_start); + + label_len = label_end - label_start; + if (label_len >= 64) + return -1; /* labels must be 63 octets or less */ + + out[outp++] = (uint8_t)label_len; + memcpy(out + outp, label_start, label_len); + outp += label_len; + label_start += label_len; + if (*label_start == '.') + label_start++; + } + + out[outp++] = '\0'; + return outp; +} + +DEFUN(ipv6_nd_rdnss, + ipv6_nd_rdnss_cmd, + "ipv6 nd rdnss X:X::X:X [<(0-4294967295)|infinite>]", + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Recursive DNS server information\n" + "IPv6 address\n" + "Valid lifetime in seconds\n" + "Infinite valid lifetime\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct zebra_if *zif = ifp->info; + struct rtadv_rdnss rdnss = {}; + + if (inet_pton(AF_INET6, argv[3]->arg, &rdnss.addr) != 1) { + vty_out(vty, "Malformed IPv6 address\n"); + return CMD_WARNING_CONFIG_FAILED; + } + if (argc > 4) { + char *lifetime = argv[4]->type == RANGE_TKN ? argv[4]->arg + : argv[4]->text; + rdnss.lifetime = strmatch(lifetime, "infinite") + ? UINT32_MAX + : strtoll(lifetime, NULL, 10); + rdnss.lifetime_set = 1; + } + + rtadv_rdnss_set(zif, &rdnss); + + return CMD_SUCCESS; +} + +DEFUN(no_ipv6_nd_rdnss, + no_ipv6_nd_rdnss_cmd, + "no ipv6 nd rdnss X:X::X:X [<(0-4294967295)|infinite>]", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Recursive DNS server information\n" + "IPv6 address\n" + "Valid lifetime in seconds\n" + "Infinite valid lifetime\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct zebra_if *zif = ifp->info; + struct rtadv_rdnss rdnss = {}; + + if (inet_pton(AF_INET6, argv[4]->arg, &rdnss.addr) != 1) { + vty_out(vty, "Malformed IPv6 address\n"); + return CMD_WARNING_CONFIG_FAILED; + } + if (rtadv_rdnss_reset(zif, &rdnss) != 1) { + vty_out(vty, "Non-existant RDNSS address\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + return CMD_SUCCESS; +} + +DEFUN(ipv6_nd_dnssl, + ipv6_nd_dnssl_cmd, + "ipv6 nd dnssl SUFFIX [<(0-4294967295)|infinite>]", + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "DNS search list information\n" + "Domain name suffix\n" + "Valid lifetime in seconds\n" + "Infinite valid lifetime\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct zebra_if *zif = ifp->info; + struct rtadv_dnssl dnssl = {}; + size_t len; + int ret; + + len = strlcpy(dnssl.name, argv[3]->arg, sizeof(dnssl.name)); + if (len == 0 || len >= sizeof(dnssl.name)) { + vty_out(vty, "Malformed DNS search domain\n"); + return CMD_WARNING_CONFIG_FAILED; + } + if (dnssl.name[len - 1] == '.') { + /* + * Allow, but don't require, a trailing dot signifying the root + * zone. Canonicalize by cutting it off if present. + */ + dnssl.name[len - 1] = '\0'; + len--; + } + if (argc > 4) { + char *lifetime = argv[4]->type == RANGE_TKN ? argv[4]->arg + : argv[4]->text; + dnssl.lifetime = strmatch(lifetime, "infinite") + ? UINT32_MAX + : strtoll(lifetime, NULL, 10); + dnssl.lifetime_set = 1; + } + + ret = rtadv_dnssl_encode(dnssl.encoded_name, dnssl.name); + if (ret < 0) { + vty_out(vty, "Malformed DNS search domain\n"); + return CMD_WARNING_CONFIG_FAILED; + } + dnssl.encoded_len = ret; + rtadv_dnssl_set(zif, &dnssl); + + return CMD_SUCCESS; +} + +DEFUN(no_ipv6_nd_dnssl, + no_ipv6_nd_dnssl_cmd, + "no ipv6 nd dnssl SUFFIX [<(0-4294967295)|infinite>]", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "DNS search list information\n" + "Domain name suffix\n" + "Valid lifetime in seconds\n" + "Infinite valid lifetime\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct zebra_if *zif = ifp->info; + struct rtadv_dnssl dnssl = {}; + size_t len; + + len = strlcpy(dnssl.name, argv[4]->arg, sizeof(dnssl.name)); + if (len == 0 || len >= sizeof(dnssl.name)) { + vty_out(vty, "Malformed DNS search domain\n"); + return CMD_WARNING_CONFIG_FAILED; + } + if (dnssl.name[len - 1] == '.') { + dnssl.name[len - 1] = '\0'; + len--; + } + if (rtadv_dnssl_reset(zif, &dnssl) != 1) { + vty_out(vty, "Non-existant DNS search domain\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + return CMD_SUCCESS; +} + + /* Dump interface ND information to vty. */ static int nd_dump_vty(struct vty *vty, struct interface *ifp) { @@ -1607,6 +1984,8 @@ static int rtadv_config_write(struct vty *vty, struct interface *ifp) struct zebra_if *zif; struct listnode *node; struct rtadv_prefix *rprefix; + struct rtadv_rdnss *rdnss; + struct rtadv_dnssl *dnssl; char buf[PREFIX_STRLEN]; int interval; @@ -1688,6 +2067,29 @@ static int rtadv_config_write(struct vty *vty, struct interface *ifp) vty_out(vty, " router-address"); vty_out(vty, "\n"); } + for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvRDNSSList, node, rdnss)) { + char buf[INET6_ADDRSTRLEN]; + + vty_out(vty, " ipv6 nd rdnss %s", + inet_ntop(AF_INET6, &rdnss->addr, buf, sizeof(buf))); + if (rdnss->lifetime_set) { + if (rdnss->lifetime == UINT32_MAX) + vty_out(vty, " infinite"); + else + vty_out(vty, " %u", rdnss->lifetime); + } + vty_out(vty, "\n"); + } + for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvDNSSLList, node, dnssl)) { + vty_out(vty, " ipv6 nd dnssl %s", dnssl->name); + if (dnssl->lifetime_set) { + if (dnssl->lifetime == UINT32_MAX) + vty_out(vty, " infinite"); + else + vty_out(vty, " %u", dnssl->lifetime); + } + vty_out(vty, "\n"); + } return 0; } @@ -1698,9 +2100,9 @@ static void rtadv_event(struct zebra_ns *zns, enum rtadv_event event, int val) switch (event) { case RTADV_START: - thread_add_read(zebrad.master, rtadv_read, zns, val, + thread_add_read(zrouter.master, rtadv_read, zns, val, &rtadv->ra_read); - thread_add_event(zebrad.master, rtadv_timer, zns, 0, + thread_add_event(zrouter.master, rtadv_timer, zns, 0, &rtadv->ra_timer); break; case RTADV_STOP: @@ -1714,15 +2116,15 @@ static void rtadv_event(struct zebra_ns *zns, enum rtadv_event event, int val) } break; case RTADV_TIMER: - thread_add_timer(zebrad.master, rtadv_timer, zns, val, + thread_add_timer(zrouter.master, rtadv_timer, zns, val, &rtadv->ra_timer); break; case RTADV_TIMER_MSEC: - thread_add_timer_msec(zebrad.master, rtadv_timer, zns, val, + thread_add_timer_msec(zrouter.master, rtadv_timer, zns, val, &rtadv->ra_timer); break; case RTADV_READ: - thread_add_read(zebrad.master, rtadv_read, zns, val, + thread_add_read(zrouter.master, rtadv_read, zns, val, &rtadv->ra_read); break; default: @@ -1782,6 +2184,10 @@ void rtadv_cmd_init(void) install_element(INTERFACE_NODE, &no_ipv6_nd_router_preference_cmd); install_element(INTERFACE_NODE, &ipv6_nd_mtu_cmd); install_element(INTERFACE_NODE, &no_ipv6_nd_mtu_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_rdnss_cmd); + install_element(INTERFACE_NODE, &no_ipv6_nd_rdnss_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_dnssl_cmd); + install_element(INTERFACE_NODE, &no_ipv6_nd_dnssl_cmd); } static int if_join_all_router(int sock, struct interface *ifp) diff --git a/zebra/rtadv.h b/zebra/rtadv.h index 03db13fd69..f7c27ebcb3 100644 --- a/zebra/rtadv.h +++ b/zebra/rtadv.h @@ -91,6 +91,37 @@ struct nd_opt_homeagent_info { /* Home Agent info */ } __attribute__((__packed__)); #endif +#ifndef ND_OPT_RDNSS +#define ND_OPT_RDNSS 25 +#endif +#ifndef ND_OPT_DNSSL +#define ND_OPT_DNSSL 31 +#endif + +#ifndef HAVE_STRUCT_ND_OPT_RDNSS +struct nd_opt_rdnss { /* Recursive DNS server option [RFC8106 5.1] */ + uint8_t nd_opt_rdnss_type; + uint8_t nd_opt_rdnss_len; + uint16_t nd_opt_rdnss_reserved; + uint32_t nd_opt_rdnss_lifetime; + /* Followed by one or more IPv6 addresses */ +} __attribute__((__packed__)); +#endif + +#ifndef HAVE_STRUCT_ND_OPT_DNSSL +struct nd_opt_dnssl { /* DNS search list option [RFC8106 5.2] */ + uint8_t nd_opt_dnssl_type; + uint8_t nd_opt_dnssl_len; + uint16_t nd_opt_dnssl_reserved; + uint32_t nd_opt_dnssl_lifetime; + /* + * Followed by one or more domain names encoded as in [RFC1035 3.1]. + * Multiple domain names are concatenated after encoding. In any case, + * the result is zero-padded to a multiple of 8 octets. + */ +} __attribute__((__packed__)); +#endif + extern const char *rtadv_pref_strs[]; #endif /* HAVE_RTADV */ diff --git a/zebra/subdir.am b/zebra/subdir.am index daa7946bc0..1e36d020a3 100644 --- a/zebra/subdir.am +++ b/zebra/subdir.am @@ -95,6 +95,9 @@ zebra_zebra_SOURCES = \ zebra/zebra_errors.c \ # end +zebra/debug_clippy.c: $(CLIPPY_DEPS) +zebra/debug.$(OBJEXT): zebra/debug_clippy.c + zebra/zebra_mlag_clippy.c: $(CLIPPY_DEPS) zebra/zebra_mlag.$(OBJEXT): zebra/zebra_mlag_clippy.c diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 951a411f25..9b91289dec 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -42,6 +42,7 @@ #include "lib/libfrr.h" #include "lib/sockopt.h" +#include "zebra/zebra_router.h" #include "zebra/rib.h" #include "zebra/zebra_memory.h" #include "zebra/zebra_ns.h" @@ -208,12 +209,6 @@ int zsend_interface_link_params(struct zserv *client, struct interface *ifp) { struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); - /* Check this client need interface information. */ - if (!vrf_bitmap_check(client->ifinfo, ifp->vrf_id)) { - stream_free(s); - return 0; - } - if (!ifp->link_params) { stream_free(s); return 0; @@ -365,7 +360,7 @@ static void zebra_interface_nbr_address_add_update(struct interface *ifp, p->prefixlen, ifc->ifp->name); } - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) zsend_interface_nbr_address(ZEBRA_INTERFACE_NBR_ADDRESS_ADD, client, ifp, ifc); } @@ -389,7 +384,7 @@ static void zebra_interface_nbr_address_delete_update(struct interface *ifp, p->prefixlen, ifc->ifp->name); } - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) zsend_interface_nbr_address(ZEBRA_INTERFACE_NBR_ADDRESS_DELETE, client, ifp, ifc); } @@ -768,7 +763,7 @@ void zsend_rule_notify_owner(struct zebra_pbr_rule *rule, zlog_debug("%s: Notifying %u", __PRETTY_FUNCTION__, rule->rule.unique); - for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) { + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) { if (rule->sock == client->sock) break; } @@ -804,7 +799,7 @@ void zsend_ipset_notify_owner(struct zebra_pbr_ipset *ipset, zlog_debug("%s: Notifying %u", __PRETTY_FUNCTION__, ipset->unique); - for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) { + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) { if (ipset->sock == client->sock) break; } @@ -834,7 +829,7 @@ void zsend_ipset_entry_notify_owner(struct zebra_pbr_ipset_entry *ipset, zlog_debug("%s: Notifying %u", __PRETTY_FUNCTION__, ipset->unique); - for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) { + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) { if (ipset->sock == client->sock) break; } @@ -864,7 +859,7 @@ void zsend_iptable_notify_owner(struct zebra_pbr_iptable *iptable, zlog_debug("%s: Notifying %u", __PRETTY_FUNCTION__, iptable->unique); - for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) { + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) { if (iptable->sock == client->sock) break; } @@ -1316,9 +1311,6 @@ static void zread_interface_add(ZAPI_HANDLER_ARGS) struct vrf *vrf; struct interface *ifp; - /* Interface information is needed. */ - vrf_bitmap_set(client->ifinfo, zvrf_id(zvrf)); - RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { FOR_ALL_INTERFACES (vrf, ifp) { /* Skip pseudo interface. */ @@ -1335,7 +1327,6 @@ static void zread_interface_add(ZAPI_HANDLER_ARGS) /* Unregister zebra server interface information. */ static void zread_interface_delete(ZAPI_HANDLER_ARGS) { - vrf_bitmap_unset(client->ifinfo, zvrf_id(zvrf)); } void zserv_nexthop_num_warn(const char *caller, const struct prefix *p, @@ -1674,6 +1665,18 @@ static void zsend_capabilities(struct zserv *client, struct zebra_vrf *zvrf) zserv_send_message(client, s); } +void zsend_capabilities_all_clients(void) +{ + struct listnode *node, *nnode; + struct zebra_vrf *zvrf; + struct zserv *client; + + zvrf = vrf_info_lookup(VRF_DEFAULT); + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { + zsend_capabilities(client, zvrf); + } +} + /* Tie up route-type and client->sock */ static void zread_hello(ZAPI_HANDLER_ARGS) { @@ -1718,7 +1721,6 @@ static void zread_vrf_unregister(ZAPI_HANDLER_ARGS) vrf_bitmap_unset(client->redist[afi][i], zvrf_id(zvrf)); vrf_bitmap_unset(client->redist_default[afi], zvrf_id(zvrf)); } - vrf_bitmap_unset(client->ifinfo, zvrf_id(zvrf)); vrf_bitmap_unset(client->ridinfo, zvrf_id(zvrf)); } @@ -2455,6 +2457,7 @@ void (*zserv_handlers[])(ZAPI_HANDLER_ARGS) = { [ZEBRA_FEC_REGISTER] = zread_fec_register, [ZEBRA_FEC_UNREGISTER] = zread_fec_unregister, [ZEBRA_ADVERTISE_DEFAULT_GW] = zebra_vxlan_advertise_gw_macip, + [ZEBRA_ADVERTISE_SVI_MACIP] = zebra_vxlan_advertise_svi_macip, [ZEBRA_ADVERTISE_SUBNET] = zebra_vxlan_advertise_subnet, [ZEBRA_ADVERTISE_ALL_VNI] = zebra_vxlan_advertise_all_vni, [ZEBRA_REMOTE_VTEP_ADD] = zebra_vxlan_remote_vtep_add, diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h index 11b469e144..b770b8e881 100644 --- a/zebra/zapi_msg.h +++ b/zebra/zapi_msg.h @@ -84,3 +84,5 @@ extern void zsend_iptable_notify_owner(struct zebra_pbr_iptable *iptable, enum zapi_iptable_notify_owner note); extern void zserv_nexthop_num_warn(const char *caller, const struct prefix *p, const unsigned int nexthop_num); + +extern void zsend_capabilities_all_clients(void); diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 6fbad2f71e..928169a862 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -26,7 +26,7 @@ #include "lib/zebra.h" #include "zebra/zebra_router.h" #include "zebra/zebra_memory.h" -#include "zebra/zserv.h" +#include "zebra/zebra_router.h" #include "zebra/zebra_dplane.h" #include "zebra/rt.h" #include "zebra/debug.h" @@ -102,6 +102,23 @@ struct dplane_route_info { }; /* + * Pseudowire info for the dataplane + */ +struct dplane_pw_info { + char ifname[IF_NAMESIZE]; + ifindex_t ifindex; + int type; + int af; + int status; + uint32_t flags; + union g_addr nexthop; + mpls_label_t local_label; + mpls_label_t remote_label; + + union pw_protocol_fields fields; +}; + +/* * The context block used to exchange info about route updates across * the boundary between the zebra main context (and pthread) and the * dataplane layer (and pthread). @@ -136,6 +153,7 @@ struct zebra_dplane_ctx { union { struct dplane_route_info rinfo; zebra_lsp_t lsp; + struct dplane_pw_info pw; } u; /* Namespace info, used especially for netlink kernel communication */ @@ -237,10 +255,11 @@ static struct zebra_dplane_globals { _Atomic uint32_t dg_other_errors; _Atomic uint32_t dg_lsps_in; - _Atomic uint32_t dg_lsps_queued; - _Atomic uint32_t dg_lsps_queued_max; _Atomic uint32_t dg_lsp_errors; + _Atomic uint32_t dg_pws_in; + _Atomic uint32_t dg_pw_errors; + _Atomic uint32_t dg_update_yields; /* Dataplane pthread */ @@ -276,6 +295,8 @@ static void dplane_info_from_zns(struct zebra_dplane_info *ns_info, struct zebra_ns *zns); static enum zebra_dplane_result lsp_update_internal(zebra_lsp_t *lsp, enum dplane_op_e op); +static enum zebra_dplane_result pw_update_internal(struct zebra_pw *pw, + enum dplane_op_e op); /* * Public APIs @@ -363,6 +384,8 @@ static void dplane_ctx_free(struct zebra_dplane_ctx **pctx) break; } + case DPLANE_OP_PW_INSTALL: + case DPLANE_OP_PW_UNINSTALL: case DPLANE_OP_NONE: break; } @@ -490,6 +513,13 @@ const char *dplane_op2str(enum dplane_op_e op) ret = "LSP_DELETE"; break; + case DPLANE_OP_PW_INSTALL: + ret = "PW_INSTALL"; + break; + case DPLANE_OP_PW_UNINSTALL: + ret = "PW_UNINSTALL"; + break; + }; return ret; @@ -735,6 +765,71 @@ uint32_t dplane_ctx_get_lsp_num_ecmp(const struct zebra_dplane_ctx *ctx) return ctx->u.lsp.num_ecmp; } +const char *dplane_ctx_get_pw_ifname(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.pw.ifname; +} + +mpls_label_t dplane_ctx_get_pw_local_label(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.pw.local_label; +} + +mpls_label_t dplane_ctx_get_pw_remote_label(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.pw.remote_label; +} + +int dplane_ctx_get_pw_type(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.pw.type; +} + +int dplane_ctx_get_pw_af(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.pw.af; +} + +uint32_t dplane_ctx_get_pw_flags(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.pw.flags; +} + +int dplane_ctx_get_pw_status(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.pw.status; +} + +const union g_addr *dplane_ctx_get_pw_nexthop( + const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return &(ctx->u.pw.nexthop); +} + +const union pw_protocol_fields *dplane_ctx_get_pw_proto( + const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return &(ctx->u.pw.fields); +} + /* * End of dplane context accessors */ @@ -938,6 +1033,47 @@ static int dplane_ctx_lsp_init(struct zebra_dplane_ctx *ctx, } /* + * Capture information for an LSP update in a dplane context. + */ +static int dplane_ctx_pw_init(struct zebra_dplane_ctx *ctx, + enum dplane_op_e op, + struct zebra_pw *pw) +{ + int ret = AOK; + + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) + zlog_debug("init dplane ctx %s: pw '%s', loc %u, rem %u", + dplane_op2str(op), pw->ifname, pw->local_label, + pw->remote_label); + + ctx->zd_op = op; + ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; + + /* Capture namespace info: no netlink support as of 12/18, + * but just in case... + */ + dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT), false); + + memset(&ctx->u.pw, 0, sizeof(ctx->u.pw)); + + /* This name appears to be c-string, so we use string copy. */ + strlcpy(ctx->u.pw.ifname, pw->ifname, sizeof(ctx->u.pw.ifname)); + ctx->zd_vrf_id = pw->vrf_id; + ctx->u.pw.ifindex = pw->ifindex; + ctx->u.pw.type = pw->type; + ctx->u.pw.af = pw->af; + ctx->u.pw.local_label = pw->local_label; + ctx->u.pw.remote_label = pw->remote_label; + ctx->u.pw.flags = pw->flags; + + ctx->u.pw.nexthop = pw->nexthop; + + ctx->u.pw.fields = pw->data; + + return ret; +} + +/* * Enqueue a new route update, * and ensure an event is active for the dataplane pthread. */ @@ -1141,6 +1277,22 @@ enum zebra_dplane_result dplane_lsp_delete(zebra_lsp_t *lsp) } /* + * Enqueue pseudowire install for the dataplane. + */ +enum zebra_dplane_result dplane_pw_install(struct zebra_pw *pw) +{ + return pw_update_internal(pw, DPLANE_OP_PW_INSTALL); +} + +/* + * Enqueue pseudowire un-install for the dataplane. + */ +enum zebra_dplane_result dplane_pw_uninstall(struct zebra_pw *pw) +{ + return pw_update_internal(pw, DPLANE_OP_PW_UNINSTALL); +} + +/* * Common internal LSP update utility */ static enum zebra_dplane_result lsp_update_internal(zebra_lsp_t *lsp, @@ -1181,6 +1333,45 @@ done: } /* + * Internal, common handler for pseudowire updates. + */ +static enum zebra_dplane_result pw_update_internal(struct zebra_pw *pw, + enum dplane_op_e op) +{ + enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE; + int ret; + struct zebra_dplane_ctx *ctx = NULL; + + ctx = dplane_ctx_alloc(); + if (ctx == NULL) { + ret = ENOMEM; + goto done; + } + + ret = dplane_ctx_pw_init(ctx, op, pw); + if (ret != AOK) + goto done; + + ret = dplane_route_enqueue(ctx); + +done: + /* Update counter */ + atomic_fetch_add_explicit(&zdplane_info.dg_pws_in, 1, + memory_order_relaxed); + + if (ret == AOK) + result = ZEBRA_DPLANE_REQUEST_QUEUED; + else { + atomic_fetch_add_explicit(&zdplane_info.dg_pw_errors, 1, + memory_order_relaxed); + if (ctx) + dplane_ctx_free(&ctx); + } + + return result; +} + +/* * Handler for 'show dplane' */ int dplane_show_helper(struct vty *vty, bool detailed) @@ -1512,6 +1703,32 @@ kernel_dplane_lsp_update(struct zebra_dplane_ctx *ctx) } /* + * Handler for kernel pseudowire updates + */ +static enum zebra_dplane_result +kernel_dplane_pw_update(struct zebra_dplane_ctx *ctx) +{ + enum zebra_dplane_result res; + + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) + zlog_debug("Dplane pw %s: op %s af %d loc: %u rem: %u", + dplane_ctx_get_pw_ifname(ctx), + dplane_op2str(ctx->zd_op), + dplane_ctx_get_pw_af(ctx), + dplane_ctx_get_pw_local_label(ctx), + dplane_ctx_get_pw_remote_label(ctx)); + + res = kernel_pw_update(ctx); + + if (res != ZEBRA_DPLANE_REQUEST_SUCCESS) + atomic_fetch_add_explicit( + &zdplane_info.dg_pw_errors, 1, + memory_order_relaxed); + + return res; +} + +/* * Handler for kernel route updates */ static enum zebra_dplane_result @@ -1577,6 +1794,11 @@ static int kernel_dplane_process_func(struct zebra_dplane_provider *prov) res = kernel_dplane_lsp_update(ctx); break; + case DPLANE_OP_PW_INSTALL: + case DPLANE_OP_PW_UNINSTALL: + res = kernel_dplane_pw_update(ctx); + break; + default: atomic_fetch_add_explicit( &zdplane_info.dg_other_errors, 1, @@ -1802,7 +2024,7 @@ static int dplane_check_shutdown_status(struct thread *event) /* We appear to be done - schedule a final callback event * for the zebra main pthread. */ - thread_add_event(zebrad.master, zebra_finalize, NULL, 0, NULL); + thread_add_event(zrouter.master, zebra_finalize, NULL, 0, NULL); } return 0; @@ -2052,7 +2274,7 @@ void zebra_dplane_shutdown(void) /* * Initialize the dataplane module during startup, internal/private version */ -static void zebra_dplane_init_internal(struct zebra_t *zebra) +static void zebra_dplane_init_internal(void) { memset(&zdplane_info, 0, sizeof(zdplane_info)); @@ -2101,6 +2323,6 @@ void zebra_dplane_start(void) */ void zebra_dplane_init(int (*results_fp)(struct dplane_ctx_q *)) { - zebra_dplane_init_internal(&zebrad); + zebra_dplane_init_internal(); zdplane_info.dg_results_cb = results_fp; } diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 562a8499a2..81226961e8 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -105,7 +105,11 @@ enum dplane_op_e { /* LSP update */ DPLANE_OP_LSP_INSTALL, DPLANE_OP_LSP_UPDATE, - DPLANE_OP_LSP_DELETE + DPLANE_OP_LSP_DELETE, + + /* Pseudowire update */ + DPLANE_OP_PW_INSTALL, + DPLANE_OP_PW_UNINSTALL, }; /* @@ -203,6 +207,19 @@ zebra_nhlfe_t *dplane_ctx_get_nhlfe(struct zebra_dplane_ctx *ctx); zebra_nhlfe_t *dplane_ctx_get_best_nhlfe(struct zebra_dplane_ctx *ctx); uint32_t dplane_ctx_get_lsp_num_ecmp(const struct zebra_dplane_ctx *ctx); +/* Accessors for pseudowire information */ +const char *dplane_ctx_get_pw_ifname(const struct zebra_dplane_ctx *ctx); +mpls_label_t dplane_ctx_get_pw_local_label(const struct zebra_dplane_ctx *ctx); +mpls_label_t dplane_ctx_get_pw_remote_label(const struct zebra_dplane_ctx *ctx); +int dplane_ctx_get_pw_type(const struct zebra_dplane_ctx *ctx); +int dplane_ctx_get_pw_af(const struct zebra_dplane_ctx *ctx); +uint32_t dplane_ctx_get_pw_flags(const struct zebra_dplane_ctx *ctx); +int dplane_ctx_get_pw_status(const struct zebra_dplane_ctx *ctx); +const union g_addr *dplane_ctx_get_pw_nexthop( + const struct zebra_dplane_ctx *ctx); +const union pw_protocol_fields *dplane_ctx_get_pw_proto( + const struct zebra_dplane_ctx *ctx); + /* Namespace info - esp. for netlink communication */ const struct zebra_dplane_info *dplane_ctx_get_ns( const struct zebra_dplane_ctx *ctx); @@ -232,6 +249,12 @@ enum zebra_dplane_result dplane_lsp_add(zebra_lsp_t *lsp); enum zebra_dplane_result dplane_lsp_update(zebra_lsp_t *lsp); enum zebra_dplane_result dplane_lsp_delete(zebra_lsp_t *lsp); +/* + * Enqueue pseudowire operations for the dataplane. + */ +enum zebra_dplane_result dplane_pw_install(struct zebra_pw *pw); +enum zebra_dplane_result dplane_pw_uninstall(struct zebra_pw *pw); + /* Retrieve the limit on the number of pending, unprocessed updates. */ uint32_t dplane_get_in_queue_limit(void); diff --git a/zebra/zebra_mlag.c b/zebra/zebra_mlag.c index 35be07c024..5012cc2a49 100644 --- a/zebra/zebra_mlag.c +++ b/zebra/zebra_mlag.c @@ -25,16 +25,17 @@ #include "hook.h" #include "zebra/zebra_mlag.h" +#include "zebra/zebra_router.h" +#include "zebra/zapi_msg.h" +#include "zebra/debug.h" #ifndef VTYSH_EXTRACT_PL #include "zebra/zebra_mlag_clippy.c" #endif -enum mlag_role role = MLAG_ROLE_NONE; - enum mlag_role zebra_mlag_get_role(void) { - return role; + return zrouter.mlag_info.role; } DEFUN_HIDDEN (show_mlag, @@ -47,7 +48,7 @@ DEFUN_HIDDEN (show_mlag, char buf[80]; vty_out(vty, "MLag is configured to: %s\n", - mlag_role2str(role, buf, sizeof(buf))); + mlag_role2str(zrouter.mlag_info.role, buf, sizeof(buf))); return CMD_SUCCESS; } @@ -62,12 +63,23 @@ DEFPY_HIDDEN (test_mlag, "Mlag is setup to be primary\n" "Mlag is setup to be the secondary\n") { + enum mlag_role orig = zrouter.mlag_info.role; + char buf1[80], buf2[80]; + if (none) - role = MLAG_ROLE_NONE; + zrouter.mlag_info.role = MLAG_ROLE_NONE; if (primary) - role = MLAG_ROLE_PRIMARY; + zrouter.mlag_info.role = MLAG_ROLE_PRIMARY; if (secondary) - role = MLAG_ROLE_SECONDARY; + zrouter.mlag_info.role = MLAG_ROLE_SECONDARY; + + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug("Test: Changing role from %s to %s", + mlag_role2str(orig, buf1, sizeof(buf1)), + mlag_role2str(orig, buf2, sizeof(buf2))); + + if (orig != zrouter.mlag_info.role) + zsend_capabilities_all_clients(); return CMD_SUCCESS; } diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index c255c68866..78c07f9aaf 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -40,6 +40,7 @@ #include "zebra/rt.h" #include "zebra/interface.h" #include "zebra/zserv.h" +#include "zebra/zebra_router.h" #include "zebra/redistribute.h" #include "zebra/debug.h" #include "zebra/zebra_memory.h" @@ -56,9 +57,6 @@ DEFINE_MTYPE_STATIC(ZEBRA, SNHLFE_IFNAME, "MPLS static nexthop ifname") int mpls_enabled; -/* Default rtm_table for all clients */ -extern struct zebra_t zebrad; - /* static function declarations */ static void fec_evaluate(struct zebra_vrf *zvrf); @@ -126,7 +124,6 @@ static zebra_snhlfe_t *snhlfe_add(zebra_slsp_t *slsp, static int snhlfe_del(zebra_snhlfe_t *snhlfe); static int snhlfe_del_all(zebra_slsp_t *slsp); static char *snhlfe2str(zebra_snhlfe_t *snhlfe, char *buf, int size); -static int mpls_processq_init(struct zebra_t *zebra); /* Static functions */ @@ -1074,13 +1071,13 @@ static int lsp_processq_add(zebra_lsp_t *lsp) if (CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED)) return 0; - if (zebrad.lsp_process_q == NULL) { + if (zrouter.lsp_process_q == NULL) { flog_err(EC_ZEBRA_WQ_NONEXISTENT, "%s: work_queue does not exist!", __func__); return -1; } - work_queue_add(zebrad.lsp_process_q, lsp); + work_queue_add(zrouter.lsp_process_q, lsp); SET_FLAG(lsp->flags, LSP_FLAG_SCHEDULED); return 0; } @@ -1714,21 +1711,21 @@ static char *snhlfe2str(zebra_snhlfe_t *snhlfe, char *buf, int size) /* * Initialize work queue for processing changed LSPs. */ -static int mpls_processq_init(struct zebra_t *zebra) +static int mpls_processq_init(void) { - zebra->lsp_process_q = work_queue_new(zebra->master, "LSP processing"); - if (!zebra->lsp_process_q) { + zrouter.lsp_process_q = work_queue_new(zrouter.master, "LSP processing"); + if (!zrouter.lsp_process_q) { flog_err(EC_ZEBRA_WQ_NONEXISTENT, "%s: could not initialise work queue!", __func__); return -1; } - zebra->lsp_process_q->spec.workfunc = &lsp_process; - zebra->lsp_process_q->spec.del_item_data = &lsp_processq_del; - zebra->lsp_process_q->spec.errorfunc = NULL; - zebra->lsp_process_q->spec.completion_func = &lsp_processq_complete; - zebra->lsp_process_q->spec.max_retries = 0; - zebra->lsp_process_q->spec.hold = 10; + zrouter.lsp_process_q->spec.workfunc = &lsp_process; + zrouter.lsp_process_q->spec.del_item_data = &lsp_processq_del; + zrouter.lsp_process_q->spec.errorfunc = NULL; + zrouter.lsp_process_q->spec.completion_func = &lsp_processq_complete; + zrouter.lsp_process_q->spec.max_retries = 0; + zrouter.lsp_process_q->spec.hold = 10; return 0; } @@ -1803,9 +1800,10 @@ void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx) break; case DPLANE_OP_LSP_DELETE: - flog_warn(EC_ZEBRA_LSP_DELETE_FAILURE, - "LSP Deletion Failure: in-label %u", - dplane_ctx_get_in_label(ctx)); + if (status != ZEBRA_DPLANE_REQUEST_SUCCESS) + flog_warn(EC_ZEBRA_LSP_DELETE_FAILURE, + "LSP Deletion Failure: in-label %u", + dplane_ctx_get_in_label(ctx)); break; default: @@ -3062,7 +3060,7 @@ void zebra_mpls_init(void) return; } - if (!mpls_processq_init(&zebrad)) + if (!mpls_processq_init()) mpls_enabled = 1; hook_register(zserv_client_close, zebra_mpls_cleanup_fecs_for_client); diff --git a/zebra/zebra_mpls_netlink.c b/zebra/zebra_mpls_netlink.c index d8b5ef4ce1..a9233530dc 100644 --- a/zebra/zebra_mpls_netlink.c +++ b/zebra/zebra_mpls_netlink.c @@ -61,6 +61,16 @@ done: ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE); } +/* + * Pseudowire update api - not supported by netlink as of 12/18, + * but note that the default has been to report 'success' for pw updates + * on unsupported platforms. + */ +enum zebra_dplane_result kernel_pw_update(struct zebra_dplane_ctx *ctx) +{ + return ZEBRA_DPLANE_REQUEST_SUCCESS; +} + int mpls_kernel_init(void) { struct stat st; diff --git a/zebra/zebra_mpls_null.c b/zebra/zebra_mpls_null.c index 409432c4fb..2cc3f3b69d 100644 --- a/zebra/zebra_mpls_null.c +++ b/zebra/zebra_mpls_null.c @@ -29,6 +29,15 @@ int mpls_kernel_init(void) return -1; }; +/* + * Pseudowire update api - note that the default has been + * to report 'success' for pw updates on unsupported platforms. + */ +enum zebra_dplane_result kernel_pw_update(struct zebra_dplane_ctx *ctx) +{ + return ZEBRA_DPLANE_REQUEST_SUCCESS; +} + enum zebra_dplane_result kernel_lsp_update(struct zebra_dplane_ctx *ctx) { return ZEBRA_DPLANE_REQUEST_FAILURE; diff --git a/zebra/zebra_mpls_openbsd.c b/zebra/zebra_mpls_openbsd.c index da76c6ebf9..72c8f73522 100644 --- a/zebra/zebra_mpls_openbsd.c +++ b/zebra/zebra_mpls_openbsd.c @@ -314,16 +314,17 @@ enum zebra_dplane_result kernel_lsp_update(struct zebra_dplane_ctx *ctx) ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE); } -static int kmpw_install(struct zebra_pw *pw) +static enum zebra_dplane_result kmpw_install(struct zebra_dplane_ctx *ctx) { struct ifreq ifr; struct ifmpwreq imr; struct sockaddr_storage ss; struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss; struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)&ss; + const union g_addr *gaddr; memset(&imr, 0, sizeof(imr)); - switch (pw->type) { + switch (dplane_ctx_get_pw_type(ctx)) { case PW_TYPE_ETHERNET: imr.imr_type = IMR_TYPE_ETHERNET; break; @@ -332,67 +333,91 @@ static int kmpw_install(struct zebra_pw *pw) break; default: zlog_debug("%s: unhandled pseudowire type (%#X)", __func__, - pw->type); - return -1; + dplane_ctx_get_pw_type(ctx)); + return ZEBRA_DPLANE_REQUEST_FAILURE; } - if (pw->flags & F_PSEUDOWIRE_CWORD) + if (dplane_ctx_get_pw_flags(ctx) & F_PSEUDOWIRE_CWORD) imr.imr_flags |= IMR_FLAG_CONTROLWORD; /* pseudowire nexthop */ memset(&ss, 0, sizeof(ss)); - switch (pw->af) { + gaddr = dplane_ctx_get_pw_nexthop(ctx); + switch (dplane_ctx_get_pw_af(ctx)) { case AF_INET: sa_in->sin_family = AF_INET; sa_in->sin_len = sizeof(struct sockaddr_in); - sa_in->sin_addr = pw->nexthop.ipv4; + sa_in->sin_addr = gaddr->ipv4; break; case AF_INET6: sa_in6->sin6_family = AF_INET6; sa_in6->sin6_len = sizeof(struct sockaddr_in6); - sa_in6->sin6_addr = pw->nexthop.ipv6; + sa_in6->sin6_addr = gaddr->ipv6; break; default: zlog_debug("%s: unhandled pseudowire address-family (%u)", - __func__, pw->af); - return -1; + __func__, dplane_ctx_get_pw_af(ctx)); + return ZEBRA_DPLANE_REQUEST_FAILURE; } memcpy(&imr.imr_nexthop, (struct sockaddr *)&ss, sizeof(imr.imr_nexthop)); /* pseudowire local/remote labels */ - imr.imr_lshim.shim_label = pw->local_label; - imr.imr_rshim.shim_label = pw->remote_label; + imr.imr_lshim.shim_label = dplane_ctx_get_pw_local_label(ctx); + imr.imr_rshim.shim_label = dplane_ctx_get_pw_remote_label(ctx); /* ioctl */ memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, pw->ifname, sizeof(ifr.ifr_name)); + strlcpy(ifr.ifr_name, dplane_ctx_get_pw_ifname(ctx), + sizeof(ifr.ifr_name)); ifr.ifr_data = (caddr_t)&imr; if (ioctl(kr_state.ioctl_fd, SIOCSETMPWCFG, &ifr) == -1) { flog_err_sys(EC_LIB_SYSTEM_CALL, "ioctl SIOCSETMPWCFG: %s", safe_strerror(errno)); - return -1; + return ZEBRA_DPLANE_REQUEST_FAILURE; } - return 0; + return ZEBRA_DPLANE_REQUEST_SUCCESS; } -static int kmpw_uninstall(struct zebra_pw *pw) +static enum zebra_dplane_result kmpw_uninstall(struct zebra_dplane_ctx *ctx) { struct ifreq ifr; struct ifmpwreq imr; memset(&ifr, 0, sizeof(ifr)); memset(&imr, 0, sizeof(imr)); - strlcpy(ifr.ifr_name, pw->ifname, sizeof(ifr.ifr_name)); + strlcpy(ifr.ifr_name, dplane_ctx_get_pw_ifname(ctx), + sizeof(ifr.ifr_name)); ifr.ifr_data = (caddr_t)&imr; if (ioctl(kr_state.ioctl_fd, SIOCSETMPWCFG, &ifr) == -1) { flog_err_sys(EC_LIB_SYSTEM_CALL, "ioctl SIOCSETMPWCFG: %s", safe_strerror(errno)); - return -1; + return ZEBRA_DPLANE_REQUEST_FAILURE; } - return 0; + return ZEBRA_DPLANE_REQUEST_SUCCESS; +} + +/* + * Pseudowire update api for openbsd. + */ +enum zebra_dplane_result kernel_pw_update(struct zebra_dplane_ctx *ctx) +{ + enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE; + + switch (dplane_ctx_get_op(ctx)) { + case DPLANE_OP_PW_INSTALL: + result = kmpw_install(ctx); + break; + case DPLANE_OP_PW_UNINSTALL: + result = kmpw_uninstall(ctx); + break; + default: + break; + }; + + return result; } #define MAX_RTSOCK_BUF 128 * 1024 @@ -431,10 +456,6 @@ int mpls_kernel_init(void) kr_state.rtseq = 1; - /* register hook to install/uninstall pseudowires */ - hook_register(pw_install, kmpw_install); - hook_register(pw_uninstall, kmpw_uninstall); - return 0; } diff --git a/zebra/zebra_netns_notify.c b/zebra/zebra_netns_notify.c index ef31fcf45d..476638591b 100644 --- a/zebra/zebra_netns_notify.c +++ b/zebra/zebra_netns_notify.c @@ -36,7 +36,7 @@ #include "memory.h" #include "lib_errors.h" -#include "zserv.h" +#include "zebra_router.h" #include "zebra_memory.h" #endif /* defined(HAVE_NETLINK) */ @@ -121,7 +121,7 @@ static int zebra_ns_continue_read(struct zebra_netns_info *zns_info, XFREE(MTYPE_NETNS_MISC, zns_info); return 0; } - thread_add_timer_msec(zebrad.master, zebra_ns_ready_read, + thread_add_timer_msec(zrouter.master, zebra_ns_ready_read, (void *)zns_info, ZEBRA_NS_POLLING_INTERVAL_MSEC, NULL); return 0; @@ -242,7 +242,7 @@ static int zebra_ns_notify_read(struct thread *t) ssize_t len; zebra_netns_notify_current = thread_add_read( - zebrad.master, zebra_ns_notify_read, NULL, fd_monitor, NULL); + zrouter.master, zebra_ns_notify_read, NULL, fd_monitor, NULL); len = read(fd_monitor, buf, sizeof(buf)); if (len < 0) { flog_err_sys(EC_ZEBRA_NS_NOTIFY_READ, @@ -284,7 +284,7 @@ static int zebra_ns_notify_read(struct thread *t) sizeof(struct zebra_netns_info)); netnsinfo->retries = ZEBRA_NS_POLLING_MAX_RETRIES; netnsinfo->netnspath = netnspath; - thread_add_timer_msec(zebrad.master, zebra_ns_ready_read, + thread_add_timer_msec(zrouter.master, zebra_ns_ready_read, (void *)netnsinfo, 0, NULL); } return 0; @@ -355,7 +355,7 @@ void zebra_ns_notify_init(void) safe_strerror(errno)); } zebra_netns_notify_current = thread_add_read( - zebrad.master, zebra_ns_notify_read, NULL, fd_monitor, NULL); + zrouter.master, zebra_ns_notify_read, NULL, fd_monitor, NULL); } void zebra_ns_notify_close(void) diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c index e4a4adba05..1e942d6433 100644 --- a/zebra/zebra_ptm.c +++ b/zebra/zebra_ptm.c @@ -41,7 +41,7 @@ #include "zebra/zebra_errors.h" #include "zebra/zebra_ptm.h" #include "zebra/zebra_ptm_redistribute.h" -#include "zebra/zserv.h" +#include "zebra/zebra_router.h" #include "zebra_vrf.h" /* @@ -187,12 +187,12 @@ static int zebra_ptm_flush_messages(struct thread *thread) ptm_cb.ptm_sock = -1; zebra_ptm_reset_status(0); ptm_cb.t_timer = NULL; - thread_add_timer(zebrad.master, zebra_ptm_connect, NULL, + thread_add_timer(zrouter.master, zebra_ptm_connect, NULL, ptm_cb.reconnect_time, &ptm_cb.t_timer); return (-1); case BUFFER_PENDING: ptm_cb.t_write = NULL; - thread_add_write(zebrad.master, zebra_ptm_flush_messages, NULL, + thread_add_write(zrouter.master, zebra_ptm_flush_messages, NULL, ptm_cb.ptm_sock, &ptm_cb.t_write); break; case BUFFER_EMPTY: @@ -213,14 +213,14 @@ static int zebra_ptm_send_message(char *data, int size) ptm_cb.ptm_sock = -1; zebra_ptm_reset_status(0); ptm_cb.t_timer = NULL; - thread_add_timer(zebrad.master, zebra_ptm_connect, NULL, + thread_add_timer(zrouter.master, zebra_ptm_connect, NULL, ptm_cb.reconnect_time, &ptm_cb.t_timer); return -1; case BUFFER_EMPTY: THREAD_OFF(ptm_cb.t_write); break; case BUFFER_PENDING: - thread_add_write(zebrad.master, zebra_ptm_flush_messages, NULL, + thread_add_write(zrouter.master, zebra_ptm_flush_messages, NULL, ptm_cb.ptm_sock, &ptm_cb.t_write); break; } @@ -240,7 +240,7 @@ int zebra_ptm_connect(struct thread *t) if (ptm_cb.ptm_sock != -1) { if (init) { ptm_cb.t_read = NULL; - thread_add_read(zebrad.master, zebra_ptm_sock_read, + thread_add_read(zrouter.master, zebra_ptm_sock_read, NULL, ptm_cb.ptm_sock, &ptm_cb.t_read); zebra_bfd_peer_replay_req(); } @@ -252,7 +252,7 @@ int zebra_ptm_connect(struct thread *t) ptm_cb.reconnect_time = ZEBRA_PTM_RECONNECT_TIME_MAX; ptm_cb.t_timer = NULL; - thread_add_timer(zebrad.master, zebra_ptm_connect, NULL, + thread_add_timer(zrouter.master, zebra_ptm_connect, NULL, ptm_cb.reconnect_time, &ptm_cb.t_timer); } else if (ptm_cb.reconnect_time >= ZEBRA_PTM_RECONNECT_TIME_MAX) { ptm_cb.reconnect_time = ZEBRA_PTM_RECONNECT_TIME_INITIAL; @@ -657,14 +657,14 @@ int zebra_ptm_sock_read(struct thread *thread) ptm_cb.ptm_sock = -1; zebra_ptm_reset_status(0); ptm_cb.t_timer = NULL; - thread_add_timer(zebrad.master, zebra_ptm_connect, NULL, + thread_add_timer(zrouter.master, zebra_ptm_connect, NULL, ptm_cb.reconnect_time, &ptm_cb.t_timer); return (-1); } ptm_cb.t_read = NULL; - thread_add_read(zebrad.master, zebra_ptm_sock_read, NULL, + thread_add_read(zrouter.master, zebra_ptm_sock_read, NULL, ptm_cb.ptm_sock, &ptm_cb.t_read); return 0; @@ -700,7 +700,7 @@ void zebra_ptm_bfd_dst_register(ZAPI_HANDLER_ARGS) if (ptm_cb.ptm_sock == -1) { ptm_cb.t_timer = NULL; - thread_add_timer(zebrad.master, zebra_ptm_connect, NULL, + thread_add_timer(zrouter.master, zebra_ptm_connect, NULL, ptm_cb.reconnect_time, &ptm_cb.t_timer); return; } @@ -854,7 +854,7 @@ void zebra_ptm_bfd_dst_deregister(ZAPI_HANDLER_ARGS) if (ptm_cb.ptm_sock == -1) { ptm_cb.t_timer = NULL; - thread_add_timer(zebrad.master, zebra_ptm_connect, NULL, + thread_add_timer(zrouter.master, zebra_ptm_connect, NULL, ptm_cb.reconnect_time, &ptm_cb.t_timer); return; } @@ -981,7 +981,7 @@ void zebra_ptm_bfd_client_register(ZAPI_HANDLER_ARGS) if (ptm_cb.ptm_sock == -1) { ptm_cb.t_timer = NULL; - thread_add_timer(zebrad.master, zebra_ptm_connect, NULL, + thread_add_timer(zrouter.master, zebra_ptm_connect, NULL, ptm_cb.reconnect_time, &ptm_cb.t_timer); return; } @@ -1039,7 +1039,7 @@ int zebra_ptm_bfd_client_deregister(struct zserv *client) if (ptm_cb.ptm_sock == -1) { ptm_cb.t_timer = NULL; - thread_add_timer(zebrad.master, zebra_ptm_connect, NULL, + thread_add_timer(zrouter.master, zebra_ptm_connect, NULL, ptm_cb.reconnect_time, &ptm_cb.t_timer); return 0; } @@ -1276,7 +1276,7 @@ static void zebra_ptm_send_bfdd(struct stream *msg) } /* Send message to all running BFDd daemons. */ - for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) { + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) { if (client->proto != ZEBRA_ROUTE_BFD) continue; @@ -1308,7 +1308,7 @@ static void zebra_ptm_send_clients(struct stream *msg) } /* Send message to all running client daemons. */ - for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) { + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) { if (!IS_BFD_ENABLED_PROTOCOL(client->proto)) continue; diff --git a/zebra/zebra_ptm_redistribute.c b/zebra/zebra_ptm_redistribute.c index 3acbe3bf2c..01d5114b9f 100644 --- a/zebra/zebra_ptm_redistribute.c +++ b/zebra/zebra_ptm_redistribute.c @@ -22,7 +22,7 @@ #include "prefix.h" #include "vty.h" #include "stream.h" -#include "zebra/zserv.h" +#include "zebra/zebra_router.h" #include "zebra/zapi_msg.h" #include "zebra/zebra_ptm.h" #include "zebra/zebra_ptm_redistribute.h" @@ -36,10 +36,6 @@ static int zsend_interface_bfd_update(int cmd, struct zserv *client, int blen; struct stream *s; - /* Check this client need interface information. */ - if (!vrf_bitmap_check(client->ifinfo, ifp->vrf_id)) - return 0; - s = stream_new(ZEBRA_MAX_PACKET_SIZ); zclient_create_header(s, cmd, vrf_id); @@ -76,7 +72,7 @@ void zebra_interface_bfd_update(struct interface *ifp, struct prefix *dp, struct listnode *node, *nnode; struct zserv *client; - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) { + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { if (!IS_BFD_ENABLED_PROTOCOL(client->proto)) continue; @@ -106,7 +102,7 @@ void zebra_bfd_peer_replay_req(void) struct listnode *node, *nnode; struct zserv *client; - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) { + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { if (!IS_BFD_ENABLED_PROTOCOL(client->proto)) continue; diff --git a/zebra/zebra_pw.c b/zebra/zebra_pw.c index fb9a40fe3d..006c1da02b 100644 --- a/zebra/zebra_pw.c +++ b/zebra/zebra_pw.c @@ -27,7 +27,7 @@ #include "zebra/debug.h" #include "zebra/rib.h" -#include "zebra/zserv.h" +#include "zebra/zebra_router.h" #include "zebra/zapi_msg.h" #include "zebra/zebra_rnh.h" #include "zebra/zebra_vrf.h" @@ -42,8 +42,6 @@ DEFINE_HOOK(pw_uninstall, (struct zebra_pw * pw), (pw)) #define MPLS_NO_LABEL MPLS_INVALID_LABEL -extern struct zebra_t zebrad; - static int zebra_pw_enabled(struct zebra_pw *); static void zebra_pw_install(struct zebra_pw *); static void zebra_pw_uninstall(struct zebra_pw *); @@ -98,9 +96,10 @@ void zebra_pw_del(struct zebra_vrf *zvrf, struct zebra_pw *pw) zebra_deregister_rnh_pseudowire(pw->vrf_id, pw); /* uninstall */ - if (pw->status == PW_STATUS_UP) + if (pw->status == PW_STATUS_UP) { hook_call(pw_uninstall, pw); - else if (pw->install_retry_timer) + dplane_pw_uninstall(pw); + } else if (pw->install_retry_timer) THREAD_TIMER_OFF(pw->install_retry_timer); /* unlink and release memory */ @@ -171,7 +170,8 @@ static void zebra_pw_install(struct zebra_pw *pw) pw->vrf_id, pw->ifname, zebra_route_string(pw->protocol)); - if (hook_call(pw_install, pw)) { + hook_call(pw_install, pw); + if (dplane_pw_install(pw) == ZEBRA_DPLANE_REQUEST_FAILURE) { zebra_pw_install_failure(pw); return; } @@ -192,6 +192,7 @@ static void zebra_pw_uninstall(struct zebra_pw *pw) /* ignore any possible error */ hook_call(pw_uninstall, pw); + dplane_pw_uninstall(pw); if (zebra_pw_enabled(pw)) zebra_pw_update_status(pw, PW_STATUS_DOWN); @@ -213,7 +214,7 @@ void zebra_pw_install_failure(struct zebra_pw *pw) /* schedule to retry later */ THREAD_TIMER_OFF(pw->install_retry_timer); - thread_add_timer(zebrad.master, zebra_pw_install_retry, pw, + thread_add_timer(zrouter.master, zebra_pw_install_retry, pw, PW_INSTALL_RETRY_INTERVAL, &pw->install_retry_timer); zebra_pw_update_status(pw, PW_STATUS_DOWN); diff --git a/zebra/zebra_pw.h b/zebra/zebra_pw.h index e6e0a22c21..9692fb4d40 100644 --- a/zebra/zebra_pw.h +++ b/zebra/zebra_pw.h @@ -62,8 +62,8 @@ RB_PROTOTYPE(zebra_static_pw_head, zebra_pw, static_pw_entry, zebra_pw_compare); DECLARE_HOOK(pw_install, (struct zebra_pw * pw), (pw)) DECLARE_HOOK(pw_uninstall, (struct zebra_pw * pw), (pw)) -struct zebra_pw *zebra_pw_add(struct zebra_vrf *, const char *, uint8_t, - struct zserv *); +struct zebra_pw *zebra_pw_add(struct zebra_vrf *zvrf, const char *ifname, + uint8_t protocol, struct zserv *client); void zebra_pw_del(struct zebra_vrf *, struct zebra_pw *); void zebra_pw_change(struct zebra_pw *, ifindex_t, int, int, union g_addr *, uint32_t, uint32_t, uint8_t, union pw_protocol_fields *); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 3445136d1f..8afcc2b685 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -163,7 +163,7 @@ int is_zebra_valid_kernel_table(uint32_t table_id) int is_zebra_main_routing_table(uint32_t table_id) { if ((table_id == RT_TABLE_MAIN) - || (table_id == zebrad.rtm_table_default)) + || (table_id == zrouter.rtm_table_default)) return 1; return 0; } @@ -437,6 +437,14 @@ static int nexthop_active(afi_t afi, struct route_entry *re, if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_EVPN_RVTEP)) return 1; + /* + * If the kernel has sent us a route, then + * by golly gee whiz it's a good route. + */ + if (re->type == ZEBRA_ROUTE_KERNEL || + re->type == ZEBRA_ROUTE_SYSTEM) + return 1; + /* Skip nexthops that have been filtered out due to route-map */ /* The nexthops are specific to this route and so the same */ /* nexthop for a different route may not have this flag set */ @@ -600,6 +608,9 @@ static int nexthop_active(afi_t afi, struct route_entry *re, if (!CHECK_FLAG(match->status, ROUTE_ENTRY_INSTALLED)) continue; + if (CHECK_FLAG(newhop->flags, + NEXTHOP_FLAG_RECURSIVE)) + continue; if (set) { SET_FLAG(nexthop->flags, @@ -1078,7 +1089,7 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re, hook_call(rib_update, rn, "installing in kernel"); /* Send add or update */ - if (old && (old != re)) + if (old) ret = dplane_route_update(rn, re, old); else ret = dplane_route_add(rn, re); @@ -1266,8 +1277,9 @@ static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn, if (IS_ZEBRA_DEBUG_RIB) { char buf[SRCDEST2STR_BUFFER]; srcdest_rnode2str(rn, buf, sizeof(buf)); - zlog_debug("%u:%s: Adding route rn %p, re %p (type %d)", - zvrf_id(zvrf), buf, rn, new, new->type); + zlog_debug("%u:%s: Adding route rn %p, re %p (%s)", + zvrf_id(zvrf), buf, rn, new, + zebra_route_string(new->type)); } /* If labeled-unicast route, install transit LSP. */ @@ -1292,8 +1304,9 @@ static void rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn, if (IS_ZEBRA_DEBUG_RIB) { char buf[SRCDEST2STR_BUFFER]; srcdest_rnode2str(rn, buf, sizeof(buf)); - zlog_debug("%u:%s: Deleting route rn %p, re %p (type %d)", - zvrf_id(zvrf), buf, rn, old, old->type); + zlog_debug("%u:%s: Deleting route rn %p, re %p (%s)", + zvrf_id(zvrf), buf, rn, old, + zebra_route_string(old->type)); } /* If labeled-unicast route, uninstall transit LSP. */ @@ -1360,15 +1373,16 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, srcdest_rnode2str(rn, buf, sizeof(buf)); if (new != old) zlog_debug( - "%u:%s: Updating route rn %p, re %p (type %d) " - "old %p (type %d)", + "%u:%s: Updating route rn %p, re %p (%s) old %p (%s)", zvrf_id(zvrf), buf, rn, new, - new->type, old, old->type); + zebra_route_string(new->type), + old, + zebra_route_string(old->type)); else zlog_debug( - "%u:%s: Updating route rn %p, re %p (type %d)", + "%u:%s: Updating route rn %p, re %p (%s)", zvrf_id(zvrf), buf, rn, new, - new->type); + zebra_route_string(new->type)); } /* If labeled-unicast route, uninstall transit LSP. */ @@ -1430,15 +1444,16 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, srcdest_rnode2str(rn, buf, sizeof(buf)); if (new != old) zlog_debug( - "%u:%s: Deleting route rn %p, re %p (type %d) " - "old %p (type %d) - nexthop inactive", + "%u:%s: Deleting route rn %p, re %p (%s) old %p (%s) - nexthop inactive", zvrf_id(zvrf), buf, rn, new, - new->type, old, old->type); + zebra_route_string(new->type), + old, + zebra_route_string(old->type)); else zlog_debug( - "%u:%s: Deleting route rn %p, re %p (type %d) - nexthop inactive", + "%u:%s: Deleting route rn %p, re %p (%s) - nexthop inactive", zvrf_id(zvrf), buf, rn, new, - new->type); + zebra_route_string(new->type)); } /* If labeled-unicast route, uninstall transit LSP. */ @@ -1583,10 +1598,10 @@ static void rib_process(struct route_node *rn) RNODE_FOREACH_RE_SAFE (rn, re, next) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug( - "%u:%s: Examine re %p (type %d) status %x flags %x " - "dist %d metric %d", - vrf_id, buf, re, re->type, re->status, - re->flags, re->distance, re->metric); + "%u:%s: Examine re %p (%s) status %x flags %x dist %d metric %d", + vrf_id, buf, re, zebra_route_string(re->type), + re->status, re->flags, re->distance, + re->metric); UNSET_FLAG(re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED); @@ -2140,14 +2155,6 @@ static void do_nht_processing(void) } } -/* - * All meta queues have been processed. Trigger next-hop evaluation. - */ -static void meta_queue_process_complete(struct work_queue *dummy) -{ - do_nht_processing(); -} - /* Dispatch the meta queue by picking, processing and unlocking the next RN from * a non-empty sub-queue with lowest priority. wq is equal to zebra->ribq and * data @@ -2168,8 +2175,8 @@ static wq_item_status meta_queue_process(struct work_queue *dummy, void *data) queue_len, queue_limit); /* Ensure that the meta-queue is actually enqueued */ - if (work_queue_empty(zebrad.ribq)) - work_queue_add(zebrad.ribq, zebrad.mq); + if (work_queue_empty(zrouter.ribq)) + work_queue_add(zrouter.ribq, zrouter.mq); return WQ_QUEUE_BLOCKED; } @@ -2258,7 +2265,7 @@ void rib_queue_add(struct route_node *rn) return; } - if (zebrad.ribq == NULL) { + if (zrouter.ribq == NULL) { flog_err(EC_ZEBRA_WQ_NONEXISTENT, "%s: work_queue does not exist!", __func__); return; @@ -2272,10 +2279,10 @@ void rib_queue_add(struct route_node *rn) * holder, if necessary, then push the work into it in any case. * This semantics was introduced after 0.99.9 release. */ - if (work_queue_empty(zebrad.ribq)) - work_queue_add(zebrad.ribq, zebrad.mq); + if (work_queue_empty(zrouter.ribq)) + work_queue_add(zrouter.ribq, zrouter.mq); - rib_meta_queue_add(zebrad.mq, rn); + rib_meta_queue_add(zrouter.mq, rn); return; } @@ -2309,27 +2316,25 @@ void meta_queue_free(struct meta_queue *mq) } /* initialise zebra rib work queue */ -static void rib_queue_init(struct zebra_t *zebra) +static void rib_queue_init(void) { - assert(zebra); - - if (!(zebra->ribq = - work_queue_new(zebra->master, "route_node processing"))) { + if (!(zrouter.ribq = work_queue_new(zrouter.master, + "route_node processing"))) { flog_err(EC_ZEBRA_WQ_NONEXISTENT, "%s: could not initialise work queue!", __func__); return; } /* fill in the work queue spec */ - zebra->ribq->spec.workfunc = &meta_queue_process; - zebra->ribq->spec.errorfunc = NULL; - zebra->ribq->spec.completion_func = &meta_queue_process_complete; + zrouter.ribq->spec.workfunc = &meta_queue_process; + zrouter.ribq->spec.errorfunc = NULL; + zrouter.ribq->spec.completion_func = NULL; /* XXX: TODO: These should be runtime configurable via vty */ - zebra->ribq->spec.max_retries = 3; - zebra->ribq->spec.hold = ZEBRA_RIB_PROCESS_HOLD_TIME; - zebra->ribq->spec.retry = ZEBRA_RIB_PROCESS_RETRY_TIME; + zrouter.ribq->spec.max_retries = 3; + zrouter.ribq->spec.hold = ZEBRA_RIB_PROCESS_HOLD_TIME; + zrouter.ribq->spec.retry = ZEBRA_RIB_PROCESS_RETRY_TIME; - if (!(zebra->mq = meta_queue_new())) { + if (!(zrouter.mq = meta_queue_new())) { flog_err(EC_ZEBRA_WQ_NONEXISTENT, "%s: could not initialise meta queue!", __func__); return; @@ -2484,9 +2489,9 @@ void rib_delnode(struct route_node *rn, struct route_entry *re) if (IS_ZEBRA_DEBUG_RIB) { char buf[SRCDEST2STR_BUFFER]; srcdest_rnode2str(rn, buf, sizeof(buf)); - zlog_debug( - "%u:%s: Freeing route rn %p, re %p (type %d)", - re->vrf_id, buf, rn, re, re->type); + zlog_debug("%u:%s: Freeing route rn %p, re %p (%s)", + re->vrf_id, buf, rn, re, + zebra_route_string(re->type)); } rib_unlink(rn, re); @@ -2746,10 +2751,9 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, /* Link new re to node.*/ if (IS_ZEBRA_DEBUG_RIB) { - rnode_debug( - rn, re->vrf_id, - "Inserting route rn %p, re %p (type %d) existing %p", - (void *)rn, (void *)re, re->type, (void *)same); + rnode_debug(rn, re->vrf_id, + "Inserting route rn %p, re %p (%s) existing %p", + rn, re, zebra_route_string(re->type), same); if (IS_ZEBRA_DEBUG_RIB_DETAILED) route_entry_dump(p, src_p, re); @@ -2873,10 +2877,10 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, */ if (fib && CHECK_FLAG(flags, ZEBRA_FLAG_SELFROUTE)) { if (IS_ZEBRA_DEBUG_RIB) { - rnode_debug( - rn, vrf_id, - "rn %p, re %p (type %d) was deleted from kernel, adding", - rn, fib, fib->type); + rnode_debug(rn, vrf_id, + "rn %p, re %p (%s) was deleted from kernel, adding", + rn, fib, + zebra_route_string(fib->type)); } if (allow_delete) { UNSET_FLAG(fib->status, ROUTE_ENTRY_INSTALLED); @@ -3225,6 +3229,34 @@ void rib_close_table(struct route_table *table) } /* + * Handler for async dataplane results after a pseudowire installation + */ +static int handle_pw_result(struct zebra_dplane_ctx *ctx) +{ + int ret = 0; + struct zebra_pw *pw; + struct zebra_vrf *vrf; + + /* The pseudowire code assumes success - we act on an error + * result for installation attempts here. + */ + if (dplane_ctx_get_op(ctx) != DPLANE_OP_PW_INSTALL) + goto done; + + if (dplane_ctx_get_status(ctx) != ZEBRA_DPLANE_REQUEST_SUCCESS) { + vrf = zebra_vrf_lookup_by_id(dplane_ctx_get_vrf(ctx)); + pw = zebra_pw_find(vrf, dplane_ctx_get_pw_ifname(ctx)); + if (pw) + zebra_pw_install_failure(pw); + } + +done: + + return ret; +} + + +/* * Handle results from the dataplane system. Dequeue update context * structs, dispatch to appropriate internal handlers. */ @@ -3235,8 +3267,6 @@ static int rib_process_dplane_results(struct thread *thread) /* Dequeue a list of completed updates with one lock/unlock cycle */ - /* TODO -- dequeue a list with one lock/unlock cycle? */ - do { TAILQ_INIT(&ctxlist); @@ -3269,6 +3299,11 @@ static int rib_process_dplane_results(struct thread *thread) zebra_mpls_lsp_dplane_result(ctx); break; + case DPLANE_OP_PW_INSTALL: + case DPLANE_OP_PW_UNINSTALL: + handle_pw_result(ctx); + break; + default: /* Don't expect this: just return the struct? */ dplane_ctx_fini(&ctx); @@ -3302,7 +3337,7 @@ static int rib_dplane_results(struct dplane_ctx_q *ctxlist) pthread_mutex_unlock(&dplane_mutex); /* Ensure event is signalled to zebra main pthread */ - thread_add_event(zebrad.master, rib_process_dplane_results, NULL, 0, + thread_add_event(zrouter.master, rib_process_dplane_results, NULL, 0, &t_dplane); return 0; @@ -3311,7 +3346,7 @@ static int rib_dplane_results(struct dplane_ctx_q *ctxlist) /* Routing information base initialize. */ void rib_init(void) { - rib_queue_init(&zebrad); + rib_queue_init(); /* Init dataplane, and register for results */ pthread_mutex_init(&dplane_mutex, NULL); diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index 6d52e5f9e6..7d72583dd8 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -33,7 +33,7 @@ #include "vrf.h" #include "frrstr.h" -#include "zebra/zserv.h" +#include "zebra/zebra_router.h" #include "zebra/redistribute.h" #include "zebra/debug.h" #include "zebra/zebra_rnh.h" @@ -327,10 +327,11 @@ static int ip_protocol_rm_add(struct zebra_vrf *zvrf, const char *rmap, XFREE(MTYPE_ROUTE_MAP_NAME, PROTO_RM_NAME(zvrf, afi, rtype)); } - + route_map_counter_decrement(PROTO_RM_MAP(zvrf, afi, rtype)); PROTO_RM_NAME(zvrf, afi, rtype) = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap); PROTO_RM_MAP(zvrf, afi, rtype) = route_map_lookup_by_name(PROTO_RM_NAME(zvrf, afi, rtype)); + route_map_counter_increment(PROTO_RM_MAP(zvrf, afi, rtype)); if (PROTO_RM_MAP(zvrf, afi, rtype)) { @@ -356,6 +357,8 @@ static int ip_protocol_rm_del(struct zebra_vrf *zvrf, const char *rmap, return CMD_SUCCESS; if (!rmap || strcmp(rmap, PROTO_RM_NAME(zvrf, afi, rtype)) == 0) { + + route_map_counter_decrement(PROTO_RM_MAP(zvrf, afi, rtype)); if (PROTO_RM_MAP(zvrf, afi, rtype)) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug( @@ -383,10 +386,11 @@ static int ip_nht_rm_add(struct zebra_vrf *zvrf, const char *rmap, int rtype, XFREE(MTYPE_ROUTE_MAP_NAME, NHT_RM_NAME(zvrf, afi, rtype)); } - + route_map_counter_decrement(NHT_RM_MAP(zvrf, afi, rtype)); NHT_RM_NAME(zvrf, afi, rtype) = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap); NHT_RM_MAP(zvrf, afi, rtype) = route_map_lookup_by_name(NHT_RM_NAME(zvrf, afi, rtype)); + route_map_counter_increment(NHT_RM_MAP(zvrf, afi, rtype)); if (NHT_RM_MAP(zvrf, afi, rtype)) zebra_evaluate_rnh(zvrf, AFI_IP, 1, RNH_NEXTHOP_TYPE, NULL); @@ -402,6 +406,7 @@ static int ip_nht_rm_del(struct zebra_vrf *zvrf, const char *rmap, int rtype, return CMD_SUCCESS; if (!rmap || strcmp(rmap, NHT_RM_NAME(zvrf, afi, rtype)) == 0) { + route_map_counter_decrement(NHT_RM_MAP(zvrf, afi, rtype)); if (NHT_RM_MAP(zvrf, afi, rtype)) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug( @@ -1459,6 +1464,7 @@ static void zebra_rib_table_rm_update(const char *rmap) char *rmap_name; char afi_ip = 0; char afi_ipv6 = 0; + struct route_map *old = NULL; RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { zvrf = vrf->info; @@ -1473,8 +1479,19 @@ static void zebra_rib_table_rm_update(const char *rmap) __func__, rmap, zebra_route_string(i)); + old = PROTO_RM_MAP(zvrf, AFI_IP, i); + PROTO_RM_MAP(zvrf, AFI_IP, i) = route_map_lookup_by_name(rmap_name); + /* old is NULL. i.e Route map creation event. + * So update applied_counter. + * If Old is not NULL, i.e It may be routemap + * updation or deletion. + * So no need to update the counter. + */ + if (!old) + route_map_counter_increment( + PROTO_RM_MAP(zvrf, AFI_IP, i)); /* There is single rib table for all protocols */ if (afi_ip == 0) { @@ -1497,8 +1514,13 @@ static void zebra_rib_table_rm_update(const char *rmap) __func__, rmap, zebra_route_string(i)); + old = PROTO_RM_MAP(zvrf, AFI_IP6, i); + PROTO_RM_MAP(zvrf, AFI_IP6, i) = route_map_lookup_by_name(rmap_name); + if (!old) + route_map_counter_increment( + PROTO_RM_MAP(zvrf, AFI_IP6, i)); /* There is single rib table for all protocols */ if (afi_ipv6 == 0) { @@ -1530,6 +1552,7 @@ static void zebra_nht_rm_update(const char *rmap) char *rmap_name; char afi_ip = 0; char afi_ipv6 = 0; + struct route_map *old = NULL; RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { zvrf = vrf->info; @@ -1544,8 +1567,13 @@ static void zebra_nht_rm_update(const char *rmap) __func__, rmap, zebra_route_string(i)); + old = NHT_RM_MAP(zvrf, AFI_IP, i); + NHT_RM_MAP(zvrf, AFI_IP, i) = route_map_lookup_by_name(rmap_name); + if (!old) + route_map_counter_increment( + NHT_RM_MAP(zvrf, AFI_IP, i)); /* There is single rib table for all protocols */ if (afi_ip == 0) { @@ -1570,8 +1598,13 @@ static void zebra_nht_rm_update(const char *rmap) __func__, rmap, zebra_route_string(i)); + old = NHT_RM_MAP(zvrf, AFI_IP6, i); + NHT_RM_MAP(zvrf, AFI_IP6, i) = route_map_lookup_by_name(rmap_name); + if (!old) + route_map_counter_increment( + NHT_RM_MAP(zvrf, AFI_IP6, i)); /* There is single rib table for all protocols */ if (afi_ipv6 == 0) { @@ -1745,7 +1778,7 @@ static void zebra_route_map_mark_update(const char *rmap_name) /* rmap_update_timer of 0 means don't do route updates */ if (zebra_rmap_update_timer && !zebra_t_rmap_update) { zebra_t_rmap_update = NULL; - thread_add_timer(zebrad.master, zebra_route_map_update_timer, + thread_add_timer(zrouter.master, zebra_route_map_update_timer, NULL, zebra_rmap_update_timer, &zebra_t_rmap_update); } diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c index 3e94d6bca8..c3b861c242 100644 --- a/zebra/zebra_router.c +++ b/zebra/zebra_router.c @@ -188,6 +188,9 @@ void zebra_router_terminate(void) zebra_router_free_table(zrt); } + work_queue_free_and_null(&zrouter.ribq); + meta_queue_free(zrouter.mq); + zebra_vxlan_disable(); zebra_mlag_terminate(); @@ -206,6 +209,9 @@ void zebra_router_init(void) { zrouter.sequence_num = 0; + zrouter.rtm_table_default = 0; + zrouter.packets_to_process = ZEBRA_ZAPI_PACKETS_TO_PROCESS; + zebra_vxlan_init(); zebra_mlag_init(); diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h index f63dcd984e..fb28495917 100644 --- a/zebra/zebra_router.h +++ b/zebra/zebra_router.h @@ -22,6 +22,8 @@ #ifndef __ZEBRA_ROUTER_H__ #define __ZEBRA_ROUTER_H__ +#include "lib/mlag.h" + #include "zebra/zebra_ns.h" /* @@ -44,7 +46,24 @@ RB_HEAD(zebra_router_table_head, zebra_router_table); RB_PROTOTYPE(zebra_router_table_head, zebra_router_table, zebra_router_table_entry, zebra_router_table_entry_compare) +struct zebra_mlag_info { + /* Role this zebra router is playing */ + enum mlag_role role; + + /* The peerlink being used for mlag */ + char *peerlink; + ifindex_t peerlink_ifindex; + + /* The system mac being used */ + struct ethaddr mac; +}; + struct zebra_router { + /* Thread master */ + struct thread_master *master; + + /* Lists of clients who have connected to us */ + struct list *client_list; struct zebra_router_table_head tables; @@ -65,6 +84,26 @@ struct zebra_router { /* A sequence number used for tracking routes */ _Atomic uint32_t sequence_num; + + /* The default table used for this router */ + uint32_t rtm_table_default; + + /* rib work queue */ +#define ZEBRA_RIB_PROCESS_HOLD_TIME 10 +#define ZEBRA_RIB_PROCESS_RETRY_TIME 1 + struct work_queue *ribq; + + /* Meta Queue Information */ + struct meta_queue *mq; + + /* LSP work queue */ + struct work_queue *lsp_process_q; + +#define ZEBRA_ZAPI_PACKETS_TO_PROCESS 1000 + _Atomic uint32_t packets_to_process; + + /* Mlag information for the router */ + struct zebra_mlag_info mlag_info; }; extern struct zebra_router zrouter; diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index f1458cb138..d18305495b 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -42,8 +42,6 @@ #include "zebra/zebra_netns_notify.h" #include "zebra/zebra_routemap.h" -extern struct zebra_t zebrad; - static void zebra_vrf_table_create(struct zebra_vrf *zvrf, afi_t afi, safi_t safi); static void zebra_rnhtable_node_cleanup(struct route_table *table, @@ -58,7 +56,7 @@ static void zebra_vrf_add_update(struct zebra_vrf *zvrf) if (IS_ZEBRA_DEBUG_EVENT) zlog_debug("MESSAGE: ZEBRA_VRF_ADD %s", zvrf_name(zvrf)); - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) zsend_vrf_add(client, zvrf); } @@ -70,7 +68,7 @@ static void zebra_vrf_delete_update(struct zebra_vrf *zvrf) if (IS_ZEBRA_DEBUG_EVENT) zlog_debug("MESSAGE: ZEBRA_VRF_DELETE %s", zvrf_name(zvrf)); - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) zsend_vrf_delete(client, zvrf); } @@ -189,13 +187,13 @@ static int zebra_vrf_disable(struct vrf *vrf) struct route_node *rnode; rib_dest_t *dest; - for (ALL_LIST_ELEMENTS(zebrad.mq->subq[i], lnode, nnode, + for (ALL_LIST_ELEMENTS(zrouter.mq->subq[i], lnode, nnode, rnode)) { dest = rib_dest_from_rnode(rnode); if (dest && rib_dest_vrf(dest) == zvrf) { route_unlock_node(rnode); - list_delete_node(zebrad.mq->subq[i], lnode); - zebrad.mq->size--; + list_delete_node(zrouter.mq->subq[i], lnode); + zrouter.mq->size--; } } } @@ -241,13 +239,13 @@ static int zebra_vrf_delete(struct vrf *vrf) struct route_node *rnode; rib_dest_t *dest; - for (ALL_LIST_ELEMENTS(zebrad.mq->subq[i], lnode, nnode, + for (ALL_LIST_ELEMENTS(zrouter.mq->subq[i], lnode, nnode, rnode)) { dest = rib_dest_from_rnode(rnode); if (dest && rib_dest_vrf(dest) == zvrf) { route_unlock_node(rnode); - list_delete_node(zebrad.mq->subq[i], lnode); - zebrad.mq->size--; + list_delete_node(zrouter.mq->subq[i], lnode); + zrouter.mq->size--; } } } @@ -326,14 +324,14 @@ struct route_table *zebra_vrf_table_with_table_id(afi_t afi, safi_t safi, if (vrf_id == VRF_DEFAULT) { if (table_id == RT_TABLE_MAIN - || table_id == zebrad.rtm_table_default) + || table_id == zrouter.rtm_table_default) table = zebra_vrf_table(afi, safi, vrf_id); else table = zebra_vrf_other_route_table(afi, table_id, vrf_id); } else if (vrf_is_backend_netns()) { if (table_id == RT_TABLE_MAIN - || table_id == zebrad.rtm_table_default) + || table_id == zrouter.rtm_table_default) table = zebra_vrf_table(afi, safi, vrf_id); else table = zebra_vrf_other_route_table(afi, table_id, @@ -439,9 +437,9 @@ struct route_table *zebra_vrf_other_route_table(afi_t afi, uint32_t table_id, return NULL; if ((table_id != RT_TABLE_MAIN) - && (table_id != zebrad.rtm_table_default)) { + && (table_id != zrouter.rtm_table_default)) { if (zvrf->table_id == RT_TABLE_MAIN || - zvrf->table_id == zebrad.rtm_table_default) { + zvrf->table_id == zrouter.rtm_table_default) { /* this VRF use default table * so in all cases, it does not use specific table * so it is possible to configure tables in this VRF diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h index 2473299d17..e35101d833 100644 --- a/zebra/zebra_vrf.h +++ b/zebra/zebra_vrf.h @@ -122,6 +122,8 @@ struct zebra_vrf { */ int advertise_gw_macip; + int advertise_svi_macip; + /* l3-vni info */ vni_t l3vni; diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 14288d7bc4..537820f7ea 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -164,7 +164,8 @@ DEFUN (show_ip_rpf_addr, static char re_status_output_char(struct route_entry *re, struct nexthop *nhop) { if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)) { - if (!CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_DUPLICATE)) + if (!CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_DUPLICATE) && + !CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_RECURSIVE)) return '*'; else return ' '; @@ -174,7 +175,7 @@ static char re_status_output_char(struct route_entry *re, struct nexthop *nhop) if (CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED)) return 'q'; - return 'f'; + return 'r'; } if (CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED)) @@ -2456,7 +2457,7 @@ DEFUN_HIDDEN (zebra_packet_process, { uint32_t packets = strtoul(argv[2]->arg, NULL, 10); - atomic_store_explicit(&zebrad.packets_to_process, packets, + atomic_store_explicit(&zrouter.packets_to_process, packets, memory_order_relaxed); return CMD_SUCCESS; @@ -2470,7 +2471,7 @@ DEFUN_HIDDEN (no_zebra_packet_process, "Zapi Protocol\n" "Number of packets to process before relinquishing thread\n") { - atomic_store_explicit(&zebrad.packets_to_process, + atomic_store_explicit(&zrouter.packets_to_process, ZEBRA_ZAPI_PACKETS_TO_PROCESS, memory_order_relaxed); @@ -2485,7 +2486,7 @@ DEFUN_HIDDEN (zebra_workqueue_timer, "Time in milliseconds\n") { uint32_t timer = strtoul(argv[2]->arg, NULL, 10); - zebrad.ribq->spec.hold = timer; + zrouter.ribq->spec.hold = timer; return CMD_SUCCESS; } @@ -2498,7 +2499,7 @@ DEFUN_HIDDEN (no_zebra_workqueue_timer, "Work Queue\n" "Time in milliseconds\n") { - zebrad.ribq->spec.hold = ZEBRA_RIB_PROCESS_HOLD_TIME; + zrouter.ribq->spec.hold = ZEBRA_RIB_PROCESS_HOLD_TIME; return CMD_SUCCESS; } @@ -2548,12 +2549,12 @@ static int config_write_protocol(struct vty *vty) if (zebra_rnh_ipv6_default_route) vty_out(vty, "ipv6 nht resolve-via-default\n"); - if (zebrad.ribq->spec.hold != ZEBRA_RIB_PROCESS_HOLD_TIME) - vty_out(vty, "zebra work-queue %u\n", zebrad.ribq->spec.hold); + if (zrouter.ribq->spec.hold != ZEBRA_RIB_PROCESS_HOLD_TIME) + vty_out(vty, "zebra work-queue %u\n", zrouter.ribq->spec.hold); - if (zebrad.packets_to_process != ZEBRA_ZAPI_PACKETS_TO_PROCESS) + if (zrouter.packets_to_process != ZEBRA_ZAPI_PACKETS_TO_PROCESS) vty_out(vty, "zebra zapi-packets %u\n", - zebrad.packets_to_process); + zrouter.packets_to_process); enum multicast_mode ipv4_multicast_mode = multicast_mode_ipv4_get(); @@ -2581,7 +2582,7 @@ DEFUN (show_table, SHOW_STR "default routing table to use for all clients\n") { - vty_out(vty, "table %d\n", zebrad.rtm_table_default); + vty_out(vty, "table %d\n", zrouter.rtm_table_default); return CMD_SUCCESS; } @@ -2591,7 +2592,7 @@ DEFUN (config_table, "Configure target kernel routing table\n" "TABLE integer\n") { - zebrad.rtm_table_default = strtol(argv[1]->arg, (char **)0, 10); + zrouter.rtm_table_default = strtol(argv[1]->arg, (char **)0, 10); return CMD_SUCCESS; } @@ -2602,7 +2603,7 @@ DEFUN (no_config_table, "Configure target kernel routing table\n" "TABLE integer\n") { - zebrad.rtm_table_default = 0; + zrouter.rtm_table_default = 0; return CMD_SUCCESS; } #endif @@ -2850,8 +2851,8 @@ DEFUN (zebra_show_routing_tables_summary, /* Table configuration write function. */ static int config_write_table(struct vty *vty) { - if (zebrad.rtm_table_default) - vty_out(vty, "table %d\n", zebrad.rtm_table_default); + if (zrouter.rtm_table_default) + vty_out(vty, "table %d\n", zrouter.rtm_table_default); return 0; } diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 49af4a9205..560cd89abd 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -50,7 +50,7 @@ #include "zebra/zebra_vrf.h" #include "zebra/zebra_vxlan.h" #include "zebra/zebra_vxlan_private.h" -#include "zebra/zserv.h" +#include "zebra/zebra_router.h" DEFINE_MTYPE_STATIC(ZEBRA, HOST_PREFIX, "host prefix"); DEFINE_MTYPE_STATIC(ZEBRA, ZVNI, "VNI hash"); @@ -100,6 +100,7 @@ static int zvni_neigh_send_del_to_client(vni_t vni, struct ipaddr *ip, uint8_t flags, int state); static int zvni_neigh_install(zebra_vni_t *zvni, zebra_neigh_t *n); static int zvni_neigh_uninstall(zebra_vni_t *zvni, zebra_neigh_t *n); +static int zvni_neigh_probe(zebra_vni_t *zvni, zebra_neigh_t *n); static zebra_vni_t *zvni_from_svi(struct interface *ifp, struct interface *br_if); static struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if); @@ -179,6 +180,7 @@ static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni, struct ipaddr *ip); struct interface *zebra_get_vrr_intf_for_svi(struct interface *ifp); static int advertise_gw_macip_enabled(zebra_vni_t *zvni); +static int advertise_svi_macip_enabled(zebra_vni_t *zvni); static int zebra_vxlan_ip_inherit_dad_from_mac(struct zebra_vrf *zvrf, zebra_mac_t *old_zmac, zebra_mac_t *new_zmac, @@ -332,6 +334,20 @@ static int advertise_gw_macip_enabled(zebra_vni_t *zvni) return 0; } +static int advertise_svi_macip_enabled(zebra_vni_t *zvni) +{ + struct zebra_vrf *zvrf; + + zvrf = vrf_info_lookup(VRF_DEFAULT); + if (zvrf && zvrf->advertise_svi_macip) + return 1; + + if (zvni && zvni->advertise_svi_macip) + return 1; + + return 0; +} + /* As part Duplicate Address Detection (DAD) for IP mobility * MAC binding changes, ensure to inherit duplicate flag * from MAC. @@ -510,7 +526,7 @@ static void zebra_vxlan_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, sizeof(buf)), mac->flags, zvrf->dad_freeze_time); - thread_add_timer(zebrad.master, + thread_add_timer(zrouter.master, zebra_vxlan_dad_mac_auto_recovery_exp, mac, zvrf->dad_freeze_time, &mac->dad_mac_auto_recovery_timer); @@ -643,7 +659,7 @@ static void zebra_vxlan_dup_addr_detect_for_neigh(struct zebra_vrf *zvrf, ipaddr2str(&nbr->ip, buf1, sizeof(buf1)), nbr->flags, zvrf->dad_freeze_time); - thread_add_timer(zebrad.master, + thread_add_timer(zrouter.master, zebra_vxlan_dad_ip_auto_recovery_exp, nbr, zvrf->dad_freeze_time, &nbr->dad_ip_auto_recovery_timer); @@ -2404,6 +2420,18 @@ static void zvni_process_neigh_on_remote_mac_del(zebra_vni_t *zvni, /* NOTE: Currently a NO-OP. */ } +static void zvni_probe_neigh_on_mac_add(zebra_vni_t *zvni, zebra_mac_t *zmac) +{ + zebra_neigh_t *nbr = NULL; + struct listnode *node = NULL; + + for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, nbr)) { + if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL) && + IS_ZEBRA_NEIGH_INACTIVE(nbr)) + zvni_neigh_probe(zvni, nbr); + } +} + /* * Inform BGP about local neighbor addition. */ @@ -2501,6 +2529,32 @@ static int zvni_neigh_uninstall(zebra_vni_t *zvni, zebra_neigh_t *n) } /* + * Probe neighbor from the kernel. + */ +static int zvni_neigh_probe(zebra_vni_t *zvni, zebra_neigh_t *n) +{ + struct zebra_if *zif; + struct zebra_l2info_vxlan *vxl; + struct interface *vlan_if; + + zif = zvni->vxlan_if->info; + if (!zif) + return -1; + vxl = &zif->l2info.vxl; + + vlan_if = zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if); + if (!vlan_if) + return -1; + +#ifdef GNU_LINUX + return kernel_upd_neigh(vlan_if, &n->ip, &n->emac, + 0, NUD_PROBE); +#else + return 0; +#endif +} + +/* * Install neighbor hash entry - called upon access VLAN change. */ static void zvni_install_neigh_hash(struct hash_backet *backet, void *ctxt) @@ -2835,10 +2889,48 @@ static void zvni_gw_macip_add_for_vni_hash(struct hash_backet *backet, /* Add primary SVI MAC-IP */ zvni_add_macip_for_intf(vlan_if, zvni); - /* Add VRR MAC-IP - if any*/ - vrr_if = zebra_get_vrr_intf_for_svi(vlan_if); - if (vrr_if) - zvni_add_macip_for_intf(vrr_if, zvni); + if (advertise_gw_macip_enabled(zvni)) { + /* Add VRR MAC-IP - if any*/ + vrr_if = zebra_get_vrr_intf_for_svi(vlan_if); + if (vrr_if) + zvni_add_macip_for_intf(vrr_if, zvni); + } + + return; +} + +static void zvni_svi_macip_del_for_vni_hash(struct hash_backet *backet, + void *ctxt) +{ + zebra_vni_t *zvni = NULL; + struct zebra_if *zif = NULL; + struct zebra_l2info_vxlan zl2_info; + struct interface *vlan_if = NULL; + struct interface *ifp; + + /* Add primary SVI MAC*/ + zvni = (zebra_vni_t *)backet->data; + if (!zvni) + return; + + ifp = zvni->vxlan_if; + if (!ifp) + return; + zif = ifp->info; + + /* If down or not mapped to a bridge, we're done. */ + if (!if_is_operative(ifp) || !zif->brslave_info.br_if) + return; + + zl2_info = zif->l2info.vxl; + + vlan_if = zvni_map_to_svi(zl2_info.access_vlan, + zif->brslave_info.br_if); + if (!vlan_if) + return; + + /* Del primary MAC-IP */ + zvni_del_macip_for_intf(vlan_if, zvni); return; } @@ -5329,6 +5421,8 @@ static void process_remote_macip_add(vni_t vni, zvni_neigh_install(zvni, n); } + zvni_probe_neigh_on_mac_add(zvni, mac); + /* Update seq number. */ n->rem_seq = seq; } @@ -6868,6 +6962,8 @@ void zebra_vxlan_print_evpn(struct vty *vty, bool uj) vty_out(vty, "L3 VNIs: %u\n", num_l3vnis); vty_out(vty, "Advertise gateway mac-ip: %s\n", zvrf->advertise_gw_macip ? "Yes" : "No"); + vty_out(vty, "Advertise svi mac-ip: %s\n", + zvrf->advertise_svi_macip ? "Yes" : "No"); vty_out(vty, "Duplicate address detection: %s\n", zvrf->dup_addr_detect ? "Enable" : "Disable"); vty_out(vty, " Detection max-moves %u, time %d\n", @@ -7029,6 +7125,7 @@ int zebra_vxlan_handle_kernel_neigh_del(struct interface *ifp, zebra_vni_t *zvni = NULL; zebra_mac_t *zmac = NULL; zebra_l3vni_t *zl3vni = NULL; + struct zebra_vrf *zvrf; /* check if this is a remote neigh entry corresponding to remote * next-hop @@ -7081,9 +7178,23 @@ int zebra_vxlan_handle_kernel_neigh_del(struct interface *ifp, return 0; } + zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); + if (!zvrf) { + zlog_debug("%s: VNI %u vrf lookup failed.", + __PRETTY_FUNCTION__, zvni->vni); + return -1; + } + + /* In case of feeze action, if local neigh is in duplicate state, + * Mark the Neigh as inactive before sending delete request to BGPd, + * If BGPd has remote entry, it will re-install + */ + if (zvrf->dad_freeze && + CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE)) + ZEBRA_NEIGH_SET_INACTIVE(n); + /* Remove neighbor from BGP. */ - zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac, - 0, n->state); + zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac, 0, n->state); /* Delete this neighbor entry. */ zvni_neigh_del(zvni, n); @@ -8656,6 +8767,102 @@ stream_failure: } /* + * Handle message from client to enable/disable advertisement of svi macip + * routes + */ +void zebra_vxlan_advertise_svi_macip(ZAPI_HANDLER_ARGS) +{ + struct stream *s; + int advertise; + vni_t vni = 0; + zebra_vni_t *zvni = NULL; + struct interface *ifp = NULL; + + if (zvrf_id(zvrf) != VRF_DEFAULT) { + zlog_debug("EVPN GW-MACIP Adv for non-default VRF %u", + zvrf_id(zvrf)); + return; + } + + s = msg; + STREAM_GETC(s, advertise); + STREAM_GETL(s, vni); + + if (!vni) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("EVPN gateway macip Adv %s, currently %s", + advertise ? "enabled" : "disabled", + advertise_gw_macip_enabled(NULL) + ? "enabled" + : "disabled"); + + if (zvrf->advertise_svi_macip == advertise) + return; + + + if (advertise) { + zvrf->advertise_svi_macip = advertise; + hash_iterate(zvrf->vni_table, + zvni_gw_macip_add_for_vni_hash, NULL); + } else { + hash_iterate(zvrf->vni_table, + zvni_svi_macip_del_for_vni_hash, NULL); + zvrf->advertise_svi_macip = advertise; + } + + } else { + struct zebra_if *zif = NULL; + struct zebra_l2info_vxlan zl2_info; + struct interface *vlan_if = NULL; + + zvni = zvni_lookup(vni); + if (!zvni) + return; + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "EVPN SVI macip Adv %s on VNI %d , currently %s", + advertise ? "enabled" : "disabled", vni, + advertise_svi_macip_enabled(zvni) + ? "enabled" + : "disabled"); + + if (zvni->advertise_svi_macip == advertise) + return; + + ifp = zvni->vxlan_if; + if (!ifp) + return; + + zif = ifp->info; + + /* If down or not mapped to a bridge, we're done. */ + if (!if_is_operative(ifp) || !zif->brslave_info.br_if) + return; + + zl2_info = zif->l2info.vxl; + + vlan_if = zvni_map_to_svi(zl2_info.access_vlan, + zif->brslave_info.br_if); + if (!vlan_if) + return; + + if (advertise) { + zvni->advertise_svi_macip = advertise; + /* Add primary SVI MAC-IP */ + zvni_add_macip_for_intf(vlan_if, zvni); + } else { + /* Del primary MAC-IP */ + zvni_del_macip_for_intf(vlan_if, zvni); + zvni->advertise_svi_macip = advertise; + } + } + +stream_failure: + return; +} + +/* * Handle message from client to enable/disable advertisement of g/w macip * routes */ diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h index c25e7357ed..2cf21ff90b 100644 --- a/zebra/zebra_vxlan.h +++ b/zebra/zebra_vxlan.h @@ -68,6 +68,7 @@ extern void zebra_vxlan_remote_vtep_add(ZAPI_HANDLER_ARGS); extern void zebra_vxlan_remote_vtep_del(ZAPI_HANDLER_ARGS); extern void zebra_vxlan_flood_control(ZAPI_HANDLER_ARGS); extern void zebra_vxlan_advertise_subnet(ZAPI_HANDLER_ARGS); +extern void zebra_vxlan_advertise_svi_macip(ZAPI_HANDLER_ARGS); extern void zebra_vxlan_advertise_gw_macip(ZAPI_HANDLER_ARGS); extern void zebra_vxlan_advertise_all_vni(ZAPI_HANDLER_ARGS); extern void zebra_vxlan_dup_addr_detection(ZAPI_HANDLER_ARGS); diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h index cae0d62bb3..c36d156359 100644 --- a/zebra/zebra_vxlan_private.h +++ b/zebra/zebra_vxlan_private.h @@ -70,6 +70,9 @@ struct zebra_vni_t_ { /* Flag for advertising gw macip */ uint8_t advertise_gw_macip; + /* Flag for advertising svi macip */ + uint8_t advertise_svi_macip; + /* Flag for advertising gw macip */ uint8_t advertise_subnet; diff --git a/zebra/zserv.c b/zebra/zserv.c index 766dd54fb3..6532491cef 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -61,12 +61,16 @@ #include "zebra/zapi_msg.h" /* for zserv_handle_commands */ #include "zebra/zebra_vrf.h" /* for zebra_vrf_lookup_by_id, zvrf */ #include "zebra/zserv.h" /* for zserv */ +#include "zebra/zebra_router.h" #include "zebra/zebra_errors.h" /* for error messages */ /* clang-format on */ /* privileges */ extern struct zebra_privs_t zserv_privs; +/* The listener socket for clients connecting to us */ +static int zsock; + /* * Client thread events. * @@ -312,7 +316,7 @@ static int zserv_read(struct thread *thread) uint32_t p2p; struct zmsghdr hdr; - p2p_orig = atomic_load_explicit(&zebrad.packets_to_process, + p2p_orig = atomic_load_explicit(&zrouter.packets_to_process, memory_order_relaxed); cache = stream_fifo_new(); p2p = p2p_orig; @@ -401,8 +405,10 @@ static int zserv_read(struct thread *thread) } /* Debug packet information. */ - if (IS_ZEBRA_DEBUG_EVENT) - zlog_debug("zebra message comes from socket [%d]", + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("zebra message[%s:%u:%u] comes from socket [%d]", + zserv_command_string(hdr.command), + hdr.vrf_id, hdr.length, sock); if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) @@ -438,7 +444,8 @@ static int zserv_read(struct thread *thread) } if (IS_ZEBRA_DEBUG_PACKET) - zlog_debug("Read %d packets", p2p_orig - p2p); + zlog_debug("Read %d packets from client: %s", p2p_orig - p2p, + zebra_route_string(client->proto)); /* Reschedule ourselves */ zserv_client_event(client, ZSERV_CLIENT_READ); @@ -481,9 +488,9 @@ static void zserv_client_event(struct zserv *client, * with the message is executed. This proceeds until there are no more messages, * an error occurs, or the processing limit is reached. * - * The client's I/O thread can push at most zebrad.packets_to_process messages + * The client's I/O thread can push at most zrouter.packets_to_process messages * onto the input buffer before notifying us there are packets to read. As long - * as we always process zebrad.packets_to_process messages here, then we can + * as we always process zrouter.packets_to_process messages here, then we can * rely on the read thread to handle queuing this task enough times to process * everything on the input queue. */ @@ -492,7 +499,7 @@ static int zserv_process_messages(struct thread *thread) struct zserv *client = THREAD_ARG(thread); struct stream *msg; struct stream_fifo *cache = stream_fifo_new(); - uint32_t p2p = zebrad.packets_to_process; + uint32_t p2p = zrouter.packets_to_process; bool need_resched = false; pthread_mutex_lock(&client->ibuf_mtx); @@ -622,7 +629,6 @@ static void zserv_client_free(struct zserv *client) vrf_bitmap_free(client->redist_default[afi]); } - vrf_bitmap_free(client->ifinfo); vrf_bitmap_free(client->ridinfo); XFREE(MTYPE_TMP, client); @@ -637,7 +643,7 @@ void zserv_close_client(struct zserv *client) zlog_debug("Closing client '%s'", zebra_route_string(client->proto)); - thread_cancel_event(zebrad.master, client); + thread_cancel_event(zrouter.master, client); THREAD_OFF(client->t_cleanup); THREAD_OFF(client->t_process); @@ -646,7 +652,7 @@ void zserv_close_client(struct zserv *client) client->pthread = NULL; /* remove from client list */ - listnode_delete(zebrad.client_list, client); + listnode_delete(zrouter.client_list, client); /* delete client */ zserv_client_free(client); @@ -695,7 +701,7 @@ static struct zserv *zserv_client_create(int sock) client->wb = buffer_new(0); /* Set table number. */ - client->rtm_table = zebrad.rtm_table_default; + client->rtm_table = zrouter.rtm_table_default; atomic_store_explicit(&client->connect_time, (uint32_t) monotime(NULL), memory_order_relaxed); @@ -706,14 +712,13 @@ static struct zserv *zserv_client_create(int sock) client->redist[afi][i] = vrf_bitmap_init(); client->redist_default[afi] = vrf_bitmap_init(); } - client->ifinfo = vrf_bitmap_init(); client->ridinfo = vrf_bitmap_init(); /* by default, it's not a synchronous client */ client->is_synchronous = 0; /* Add this client to linked list. */ - listnode_add(zebrad.client_list, client); + listnode_add(zrouter.client_list, client); struct frr_pthread_attr zclient_pthr_attrs = { .start = frr_pthread_attr_default.start, @@ -783,16 +788,16 @@ void zserv_start(char *path) old_mask = umask(0077); /* Make UNIX domain socket. */ - zebrad.sock = socket(sa.ss_family, SOCK_STREAM, 0); - if (zebrad.sock < 0) { + zsock = socket(sa.ss_family, SOCK_STREAM, 0); + if (zsock < 0) { flog_err_sys(EC_LIB_SOCKET, "Can't create zserv socket: %s", safe_strerror(errno)); return; } if (sa.ss_family != AF_UNIX) { - sockopt_reuseaddr(zebrad.sock); - sockopt_reuseport(zebrad.sock); + sockopt_reuseaddr(zsock); + sockopt_reuseport(zsock); } else { struct sockaddr_un *suna = (struct sockaddr_un *)&sa; if (suna->sun_path[0]) @@ -800,28 +805,28 @@ void zserv_start(char *path) } frr_elevate_privs(&zserv_privs) { - setsockopt_so_recvbuf(zebrad.sock, 1048576); - setsockopt_so_sendbuf(zebrad.sock, 1048576); + setsockopt_so_recvbuf(zsock, 1048576); + setsockopt_so_sendbuf(zsock, 1048576); } frr_elevate_privs((sa.ss_family != AF_UNIX) ? &zserv_privs : NULL) { - ret = bind(zebrad.sock, (struct sockaddr *)&sa, sa_len); + ret = bind(zsock, (struct sockaddr *)&sa, sa_len); } if (ret < 0) { flog_err_sys(EC_LIB_SOCKET, "Can't bind zserv socket on %s: %s", path, safe_strerror(errno)); - close(zebrad.sock); - zebrad.sock = -1; + close(zsock); + zsock = -1; return; } - ret = listen(zebrad.sock, 5); + ret = listen(zsock, 5); if (ret < 0) { flog_err_sys(EC_LIB_SOCKET, "Can't listen to zserv socket %s: %s", path, safe_strerror(errno)); - close(zebrad.sock); - zebrad.sock = -1; + close(zsock); + zsock = -1; return; } @@ -834,15 +839,15 @@ void zserv_event(struct zserv *client, enum zserv_event event) { switch (event) { case ZSERV_ACCEPT: - thread_add_read(zebrad.master, zserv_accept, NULL, zebrad.sock, + thread_add_read(zrouter.master, zserv_accept, NULL, zsock, NULL); break; case ZSERV_PROCESS_MESSAGES: - thread_add_event(zebrad.master, zserv_process_messages, client, + thread_add_event(zrouter.master, zserv_process_messages, client, 0, &client->t_process); break; case ZSERV_HANDLE_CLIENT_FAIL: - thread_add_event(zebrad.master, zserv_handle_client_fail, + thread_add_event(zrouter.master, zserv_handle_client_fail, client, 0, &client->t_cleanup); } } @@ -1002,7 +1007,7 @@ struct zserv *zserv_find_client(uint8_t proto, unsigned short instance) struct listnode *node, *nnode; struct zserv *client; - for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) { + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { if (client->proto == proto && client->instance == instance) return client; } @@ -1021,7 +1026,7 @@ DEFUN (show_zebra_client, struct listnode *node; struct zserv *client; - for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) zebra_show_client_detail(vty, client); return CMD_SUCCESS; @@ -1044,7 +1049,7 @@ DEFUN (show_zebra_client_summary, vty_out(vty, "--------------------------------------------------------------------------------\n"); - for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) zebra_show_client_brief(vty, client); vty_out(vty, "Routes column shows (added+updated)/deleted\n"); @@ -1067,10 +1072,10 @@ void zserv_read_file(char *input) void zserv_init(void) { /* Client list init. */ - zebrad.client_list = list_new(); + zrouter.client_list = list_new(); /* Misc init. */ - zebrad.sock = -1; + zsock = -1; install_element(ENABLE_NODE, &show_zebra_client_cmd); install_element(ENABLE_NODE, &show_zebra_client_summary_cmd); diff --git a/zebra/zserv.h b/zebra/zserv.h index 041485cdc2..ac016e65f3 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -89,9 +89,6 @@ struct zserv { /* Redistribute default route flag. */ vrf_bitmap_t redist_default[AFI_MAX]; - /* Interface information. */ - vrf_bitmap_t ifinfo; - /* Router-id information. */ vrf_bitmap_t ridinfo; @@ -173,31 +170,6 @@ struct zserv { DECLARE_HOOK(zserv_client_connect, (struct zserv *client), (client)); DECLARE_KOOH(zserv_client_close, (struct zserv *client), (client)); -/* Zebra instance */ -struct zebra_t { - /* Thread master */ - struct thread_master *master; - struct list *client_list; - - /* Socket */ - int sock; - - /* default table */ - uint32_t rtm_table_default; - -/* rib work queue */ -#define ZEBRA_RIB_PROCESS_HOLD_TIME 10 -#define ZEBRA_RIB_PROCESS_RETRY_TIME 1 - struct work_queue *ribq; - struct meta_queue *mq; - - /* LSP work queue */ - struct work_queue *lsp_process_q; - -#define ZEBRA_ZAPI_PACKETS_TO_PROCESS 1000 - _Atomic uint32_t packets_to_process; -}; -extern struct zebra_t zebrad; extern unsigned int multipath_num; /* |
