/* 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.
* 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
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;
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 *,
* 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;
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)
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)
show_l3vni_entry(vty, bgp_temp, json);
}
+/*
+ * 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
*/
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");
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",
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;
}
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 */
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",
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");
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);
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,
{
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);
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;
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);
}
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) {
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;
}
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;
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))
|| (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) {
|| (strcmp(rmap_name, red->rmap.name) != 0))
continue;
+ if (!red->rmap.map)
+ route_map_counter_increment(map);
+
red->rmap.map = map;
if (!route_update)
{
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;
}
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;
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);
}
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;
}
/* 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;
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;
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,
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;
}
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. */
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;
}
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;
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)) {
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,
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;
}
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;
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)) {
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);
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;
}
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;
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);
if (rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi])
free(rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi]);
+ route_map_counter_decrement(
+ rfg->plist_redist[ZEBRA_ROUTE_BGP_DIRECT][afi]);
rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi] = NULL;
rfg->plist_redist[ZEBRA_ROUTE_BGP_DIRECT][afi] = NULL;
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;
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);
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;
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;
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);
}
|| (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);
|| (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); */
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); */
}
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);
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]);
}
}
* 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]);
}
}
# 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.
packaging
process-architecture
library
+ testing
bgpd
ospf
zebra
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
--- /dev/null
+.. _testing:
+
+*******
+Testing
+*******
+
+.. toctree::
+ :maxdepth: 2
+
+ topotests
--- /dev/null
+.. _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
--- /dev/null
+.. _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.
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
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)
Instruct zebra to monitor and notify sharp when the specified nexthop is
changed. The notification from zebra is written into the debug log.
+
+.. 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.
}
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)
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);
eigrp = ei->eigrp;
listnode_delete(eigrp->eiflist, ei);
+ eigrp_fifo_free(ei->obuf);
+
XFREE(MTYPE_EIGRP_IF_INFO, ifp->info);
ifp->info = NULL;
{
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;
}
}
eigrp_if_down(ei);
- list_delete(&ei->nbrs);
listnode_delete(ei->eigrp->eiflist, ei);
}
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);
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;
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"
"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) {
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);
+
+ return CMD_SUCCESS;
+}
DEFUN (show_ip_eigrp_interfaces,
show_ip_eigrp_interfaces_cmd,
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. */
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;
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)) {
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);
{
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);
}
}
#include "memory.h"
#include "command.h"
#include "lib_errors.h"
+#include "lib/hook.h"
#ifndef SUNOS_5
#include <sys/un.h>
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;
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;
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),
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
+#include <stdarg.h>
+#include "lib/hook.h"
+
+/* 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:
*
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)
{
DECLARE_MGROUP(LIB)
DECLARE_MTYPE(TMP)
-DECLARE_MTYPE(PREFIX_FLOWSPEC)
extern void *qmalloc(struct memtype *mt, size_t size)
#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,
}
$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);
}
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. */
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",
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",
/* 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);
/* 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)
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);
+
#endif /* _ZEBRA_ROUTEMAP_H */
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);
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)
* 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);
/* 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],
/* 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],
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);
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,
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;
}
"%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
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;
}
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
interface. */
{
ospf_ls_ack_send(nbr, lsa);
- DISCARD_LSA(lsa, 6);
+ DISCARD_LSA(lsa, 7);
}
}
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
ospf_ls_upd_send_lsa(
nbr, current,
OSPF_SEND_PACKET_DIRECT);
- DISCARD_LSA(lsa, 8);
+ DISCARD_LSA(lsa, 9);
}
}
}
/* 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
/* 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;
#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 */
};
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;
}
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",
&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);
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;
/* 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;
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 */
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;
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);
}
}
+ if (pim_ifp->activeactive)
+ vty_out(vty, " ip pim active-active\n");
+
/* boundary */
if (pim_ifp->boundary_oil_plist) {
vty_out(vty,
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)
{
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);
/* 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;
pimd/mtracebis_routeget.h \
# end
+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
[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]
ExecReload=/usr/lib/frr/frr reload
[Install]
-WantedBy=network-online.target
-
+WantedBy=multi-user.target
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);
+ }
}
}
}
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);
+ }
}
}
}
--- /dev/null
+/*
+ * 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
#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[] = {
};
.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)
{
master = frr_init();
+ sharp_global_init();
+
nexthop_group_init(NULL, NULL, NULL, NULL);
vrf_init(NULL, NULL, NULL, NULL, NULL);
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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
#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 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")
+ "The v6 nexthop to signal for watching\n"
+ "Should the route be connected\n")
{
struct prefix p;
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, true, !!connected);
return CMD_SUCCESS;
}
DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd,
- "sharp watch nexthop A.B.C.D$nhop",
+ "sharp watch nexthop 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")
+ "The v4 nexthop to signal for watching\n"
+ "Should the route be connected\n")
{
struct prefix p;
p.u.prefix4 = nhop;
p.family = AF_INET;
- sharp_zebra_nexthop_watch(&p, true);
+ sharp_nh_tracker_get(&p);
+ sharp_zebra_nexthop_watch(&p, 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;
}
"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;
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);
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;
}
"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));
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;
}
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);
#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. */
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)
} 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)
} 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)
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);
}
}
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);
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);
return;
}
-void sharp_zebra_nexthop_watch(struct prefix *p, bool watch)
+void sharp_zebra_nexthop_watch(struct prefix *p, bool watch, bool connected)
{
int command = ZEBRA_NEXTHOP_REGISTER;
if (!watch)
command = ZEBRA_NEXTHOP_UNREGISTER;
- if (zclient_send_rnh(zclient, command, p, true, VRF_DEFAULT) < 0)
+ if (zclient_send_rnh(zclient, command, p, connected, VRF_DEFAULT) < 0)
zlog_warn("%s: Failure to send nexthop to zebra",
__PRETTY_FUNCTION__);
}
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;
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];
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 watch,
+ bool connected);
extern void sharp_install_routes_helper(struct prefix *p, uint8_t instance,
struct nexthop_group *nhg,
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
--- /dev/null
+# 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:
+++ /dev/null
-# 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:
-
-![template topology graph](example-test/test_template.jpg)
-
-
-### 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
-```
-# 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
+++ /dev/null
-# 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
-```
{
"prefix":"192.168.1.0/24",
"protocol":"eigrp",
- "metric":0,
+ "metric":28160,
"nexthops":[
{
"directlyConnected":true,
"prefix":"192.168.3.0/24",
"protocol":"eigrp",
"selected":true,
- "metric":0,
+ "metric":33280,
"nexthops":[
{
"fib":true,
{
"prefix":"193.1.1.0/26",
"protocol":"eigrp",
- "metric":0,
+ "metric":28160,
"nexthops":[
{
"directlyConnected":true,
"prefix":"193.1.2.0/24",
"protocol":"eigrp",
"selected":true,
- "metric":0,
+ "metric":30720,
"nexthops":[
{
"fib":true,
"prefix":"192.168.1.0/24",
"protocol":"eigrp",
"selected":true,
- "metric":0,
+ "metric":30720,
"nexthops":[
{
"fib":true,
"prefix":"192.168.3.0/24",
"protocol":"eigrp",
"selected":true,
- "metric":0,
+ "metric":30720,
"nexthops":[
{
"fib":true,
{
"prefix":"193.1.1.0/26",
"protocol":"eigrp",
- "metric":0,
+ "metric":28160,
"nexthops":[
{
"directlyConnected":true,
{
"prefix":"193.1.2.0/24",
"protocol":"eigrp",
- "metric":0,
+ "metric":28160,
"nexthops":[
{
"directlyConnected":true,
"prefix":"192.168.1.0/24",
"protocol":"eigrp",
"selected":true,
- "metric":0,
+ "metric":33280,
"nexthops":[
{
"fib":true,
{
"prefix":"192.168.3.0/24",
"protocol":"eigrp",
- "metric":0,
+ "metric":28160,
"nexthops":[
{
"directlyConnected":true,
"prefix":"193.1.1.0/26",
"protocol":"eigrp",
"selected":true,
- "metric":0,
+ "metric":30720,
"nexthops":[
{
"fib":true,
{
"prefix":"193.1.2.0/24",
"protocol":"eigrp",
- "metric":0,
+ "metric":28160,
"nexthops":[
{
"directlyConnected":true,
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'"
+debug zebra kernel
+debug zebra dplane detail
+debug zebra rib
+debug zebra event
!
hostname r1
password zebra
[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]
ExecReload=/usr/lib/frr/frrinit.sh reload
[Install]
-WantedBy=network-online.target
+WantedBy=multi-user.target
#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;
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) {
#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;
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));
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;
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",
zebra_debug_vxlan = 0;
zebra_debug_pw = 0;
zebra_debug_dplane = 0;
+ zebra_debug_mlag = 0;
install_node(&debug_node, config_write_debug);
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);
#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)
#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;
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);
#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"
* 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;
}
#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"
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);
}
#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"
};
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;
}
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;
}
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);
}
#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"
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);
#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"
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;
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();
#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"
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);
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
#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"
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;
}
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;
#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;
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)
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);
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
/* 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();
}
}
- zebrad.master = frr_init();
+ zrouter.master = frr_init();
/* Initialize pthread library */
frr_pthread_init();
#endif /* HANDLE_NETLINK_FUZZING */
- frr_run(zebrad.master);
+ frr_run(zrouter.master);
/* Not reached... */
return 0;
#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"
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)
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))
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);
+ }
}
}
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);
}
}
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)
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);
}
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,
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,
"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);
"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);
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;
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;
}
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)
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);
}
#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)
{
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);
}
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));
}
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));
}
#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(
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 *);
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
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,
"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
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)
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);
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.
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:
}
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:
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
#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"
{
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;
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);
}
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);
}
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;
}
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;
}
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;
}
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;
}
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. */
/* 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,
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)
{
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));
}
[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,
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);
#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"
};
+/*
+ * 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
union {
struct dplane_route_info rinfo;
zebra_lsp_t lsp;
+ struct dplane_pw_info pw;
} u;
/* Namespace info, used especially for netlink kernel communication */
_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 */
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
break;
}
+ case DPLANE_OP_PW_INSTALL:
+ case DPLANE_OP_PW_UNINSTALL:
case DPLANE_OP_NONE:
break;
}
ret = "LSP_DELETE";
break;
+ case DPLANE_OP_PW_INSTALL:
+ ret = "PW_INSTALL";
+ break;
+ case DPLANE_OP_PW_UNINSTALL:
+ ret = "PW_UNINSTALL";
+ break;
+
};
return ret;
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
*/
return ret;
}
+/*
+ * 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.
return ret;
}
+/*
+ * 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
*/
return result;
}
+/*
+ * 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'
*/
return res;
}
+/*
+ * 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
*/
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,
/* 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;
/*
* 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));
*/
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;
}
/* 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,
};
/*
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);
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);
#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,
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;
}
"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;
}
#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"
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);
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 */
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;
}
/*
* 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;
}
return;
}
- if (!mpls_processq_init(&zebrad))
+ if (!mpls_processq_init())
mpls_enabled = 1;
hook_register(zserv_client_close, zebra_mpls_cleanup_fecs_for_client);
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;
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;
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;
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
kr_state.rtseq = 1;
- /* register hook to install/uninstall pseudowires */
- hook_register(pw_install, kmpw_install);
- hook_register(pw_uninstall, kmpw_uninstall);
-
return 0;
}
#include "memory.h"
#include "lib_errors.h"
-#include "zserv.h"
+#include "zebra_router.h"
#include "zebra_memory.h"
#endif /* defined(HAVE_NETLINK) */
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;
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,
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;
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)
#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"
/*
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:
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;
}
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();
}
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;
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;
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;
}
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;
}
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;
}
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;
}
}
/* 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;
}
/* 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;
#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"
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);
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;
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;
#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"
#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 *);
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 */
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;
}
/* 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);
/* 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);
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 *);
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;
}
if (!CHECK_FLAG(match->status,
ROUTE_ENTRY_INSTALLED))
continue;
+ if (CHECK_FLAG(newhop->flags,
+ NEXTHOP_FLAG_RECURSIVE))
+ continue;
if (set) {
SET_FLAG(nexthop->flags,
}
}
-/*
- * 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
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;
}
return;
}
- if (zebrad.ribq == NULL) {
+ if (zrouter.ribq == NULL) {
flog_err(EC_ZEBRA_WQ_NONEXISTENT,
"%s: work_queue does not exist!", __func__);
return;
* 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;
}
}
/* 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;
}
}
+/*
+ * 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.
/* Dequeue a list of completed updates with one lock/unlock cycle */
- /* TODO -- dequeue a list with one lock/unlock cycle? */
-
do {
TAILQ_INIT(&ctxlist);
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);
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;
/* 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);
#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"
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)) {
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(
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);
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(
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;
__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) {
__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) {
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;
__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) {
__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) {
/* 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);
}
zebra_router_free_table(zrt);
}
+ work_queue_free_and_null(&zrouter.ribq);
+ meta_queue_free(zrouter.mq);
+
zebra_vxlan_disable();
zebra_mlag_terminate();
{
zrouter.sequence_num = 0;
+ zrouter.rtm_table_default = 0;
+ zrouter.packets_to_process = ZEBRA_ZAPI_PACKETS_TO_PROCESS;
+
zebra_vxlan_init();
zebra_mlag_init();
#ifndef __ZEBRA_ROUTER_H__
#define __ZEBRA_ROUTER_H__
+#include "lib/mlag.h"
+
#include "zebra/zebra_ns.h"
/*
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;
/* 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;
#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,
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);
}
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);
}
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--;
}
}
}
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--;
}
}
}
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,
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
*/
int advertise_gw_macip;
+ int advertise_svi_macip;
+
/* l3-vni info */
vni_t l3vni;
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 ' ';
if (CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED))
return 'q';
- return 'f';
+ return 'r';
}
if (CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED))
{
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;
"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);
"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;
}
"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;
}
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();
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;
}
"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;
}
"Configure target kernel routing table\n"
"TABLE integer\n")
{
- zebrad.rtm_table_default = 0;
+ zrouter.rtm_table_default = 0;
return CMD_SUCCESS;
}
#endif
/* 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;
}
#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");
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);
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,
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.
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);
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);
/* 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.
*/
return kernel_del_neigh(vlan_if, &n->ip);
}
+/*
+ * 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.
*/
/* 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;
}
zvni_neigh_install(zvni, n);
}
+ zvni_probe_neigh_on_mac_add(zvni, mac);
+
/* Update seq number. */
n->rem_seq = seq;
}
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",
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
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);
return;
}
+/*
+ * 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
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);
/* 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;
#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.
*
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;
}
/* 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)
}
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);
* 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.
*/
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);
vrf_bitmap_free(client->redist_default[afi]);
}
- vrf_bitmap_free(client->ifinfo);
vrf_bitmap_free(client->ridinfo);
XFREE(MTYPE_TMP, 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);
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);
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);
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,
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])
}
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;
}
{
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);
}
}
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;
}
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;
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");
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);
/* Redistribute default route flag. */
vrf_bitmap_t redist_default[AFI_MAX];
- /* Interface information. */
- vrf_bitmap_t ifinfo;
-
/* Router-id information. */
vrf_bitmap_t ridinfo;
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;
/*