From 7666589034ef51aa56e8530031c7fa08f81f4c58 Mon Sep 17 00:00:00 2001 From: Olivier Dugeon Date: Fri, 9 Feb 2018 12:06:35 +0100 Subject: [PATCH 01/10] ospfd: Add json output for Segment Routing - To ease checking the Segment Routing conformity in topotest, add json output to 'show ip ospf database segment-routing' CLI. - Update ospfd user guide accordingly - Update OSPF-SR documentation with supported features and interoperability Signed-off-by: Olivier Dugeon --- doc/OSPF-SR.rst | 23 ++++- doc/ospfd.texi | 7 +- ospfd/ospf_sr.c | 248 +++++++++++++++++++++++++++++++++++++----------- 3 files changed, 219 insertions(+), 59 deletions(-) diff --git a/doc/OSPF-SR.rst b/doc/OSPF-SR.rst index 0ee1a12f28..299a7e1c87 100644 --- a/doc/OSPF-SR.rst +++ b/doc/OSPF-SR.rst @@ -5,6 +5,26 @@ This is an EXPERIMENTAL support of draft `draft-ietf-ospf-segment-routing-extensions-24`. DON'T use it for production network. +Supported Features +------------------ + +* Automatic computation of Primary and Backup Adjacency SID with + Cisco experimental remote IP address +* SRGB configuration +* Prefix configuration for Node SID with optional NO-PHP flag (Linux + kernel support both mode) +* Node MSD configuration (with Linux Kernel >= 4.10 a maximum of 32 labels + could be stack) +* Automatic provisioning of MPLS table +* Static route configuration with label stack up to 32 labels + +Interoperability +---------------- + +* tested on various topology including point-to-point and LAN interfaces + in a mix of Free Range Routing instance and Cisco IOS-XR 6.0.x +* check OSPF LSA conformity with latest wireshark release 2.5.0-rc + Implementation details ---------------------- @@ -248,9 +268,6 @@ Known limitations * MPLS table are not flush at startup. Thus, restarting zebra process is mandatory to remove old MPLS entries in the data plane after a crash of ospfd daemon -* Due to a bug in OSPF Opaque, LSA are not flood when enable Segment Routing - through CLI once OSPFd started. You must configure Segment Routing within - configuration file before launching OSPFd * With NO Penultimate Hop Popping, it is not possible to express a Segment Path with an Adjacency SID due to the impossibility for the Linux Kernel to perform double POP instruction. diff --git a/doc/ospfd.texi b/doc/ospfd.texi index 33341d2be6..9694be1efe 100644 --- a/doc/ospfd.texi +++ b/doc/ospfd.texi @@ -759,10 +759,11 @@ currently supported. The 'no-php-flag' means NO Penultimate Hop Popping that allows SR node to request to its neighbor to not pop the label. @end deffn -@deffn {Command} {show ip ospf database segment-routing} {} -@deffnx {Command} {show ip ospf database segment-routing adv-router @var{adv-router}} {} -@deffnx {Command} {show ip ospf database segment-routing self-originate} {} +@deffn {Command} {show ip ospf database segment-routing [json]} {} +@deffnx {Command} {show ip ospf database segment-routing adv-router @var{adv-router} [json]} {} +@deffnx {Command} {show ip ospf database segment-routing self-originate [json]} {} Show Segment Routing Data Base, all SR nodes, specific advertized router or self router. +Optional Json output could be obtain by adding 'json' at the end of the command. @end deffn @node Debugging OSPF diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c index 1560977ae8..2944c8b09a 100644 --- a/ospfd/ospf_sr.c +++ b/ospfd/ospf_sr.c @@ -47,6 +47,7 @@ #include "thread.h" #include "vty.h" #include "zclient.h" +#include #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" @@ -2128,91 +2129,197 @@ DEFUN (no_sr_prefix_sid, -static void show_vty_sr_node(struct vty *vty, struct sr_node *srn) +static void show_sr_node(struct vty *vty, struct json_object *json, + struct sr_node *srn) { struct listnode *node; struct sr_link *srl; struct sr_prefix *srp; struct interface *itf; - char pref[16]; + char pref[19]; char sid[22]; char label[8]; + json_object *json_node = NULL, *json_algo, *json_obj; + json_object *json_prefix = NULL, *json_link = NULL; /* Sanity Check */ if (srn == NULL) return; - vty_out(vty, "SR-Node: %s", inet_ntoa(srn->adv_router)); - vty_out(vty, "\tSRGB (Size/Label): %u/%u", srn->srgb.range_size, - srn->srgb.lower_bound); - vty_out(vty, "\tAlgorithm(s): %s", - srn->algo[0] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF"); - for (int i = 1; i < ALGORITHM_COUNT; i++) { - if (srn->algo[i] == SR_ALGORITHM_UNSET) - continue; - vty_out(vty, "/%s", - srn->algo[i] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF"); - } - if (srn->msd != 0) - vty_out(vty, "\tMSD: %u", srn->msd); + if (json) { + json_node = json_object_new_object(); + json_object_string_add(json_node, "routerID", + inet_ntoa(srn->adv_router)); + json_object_int_add(json_node, "srgbSize", + srn->srgb.range_size); + json_object_int_add(json_node, "srgbLabel", + srn->srgb.lower_bound); + json_algo = json_object_new_array(); + json_object_object_add(json_node, "algorithms", json_algo); + for (int i = 0; i < ALGORITHM_COUNT; i++) { + if (srn->algo[i] == SR_ALGORITHM_UNSET) + continue; + json_obj = json_object_new_object(); + char tmp[2]; - vty_out(vty, - "\n\n Prefix or Link Label In Label Out " - "Node or Adj. SID Interface Nexthop\n"); - vty_out(vty, - "------------------ -------- --------- " - "--------------------- --------- ---------------\n"); + snprintf(tmp, 2, "%u", i); + json_object_string_add(json_obj, tmp, + srn->algo[i] == SR_ALGORITHM_SPF ? + "SPF" : "S-SPF"); + json_object_array_add(json_algo, json_obj); + } + if (srn->msd != 0) + json_object_int_add(json_node, "nodeMsd", srn->msd); + } else { + vty_out(vty, "SR-Node: %s", inet_ntoa(srn->adv_router)); + vty_out(vty, "\tSRGB (Size/Label): %u/%u", + srn->srgb.range_size, srn->srgb.lower_bound); + vty_out(vty, "\tAlgorithm(s): %s", + srn->algo[0] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF"); + for (int i = 1; i < ALGORITHM_COUNT; i++) { + if (srn->algo[i] == SR_ALGORITHM_UNSET) + continue; + vty_out(vty, "/%s", + srn->algo[i] == SR_ALGORITHM_SPF ? + "SPF" : "S-SPF"); + } + if (srn->msd != 0) + vty_out(vty, "\tMSD: %u", srn->msd); + } + + if (!json) { + vty_out(vty, + "\n\n Prefix or Link Label In Label Out " + "Node or Adj. SID Interface Nexthop\n"); + vty_out(vty, + "------------------ -------- --------- " + "--------------------- --------- ---------------\n"); + } for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) { - strncpy(pref, inet_ntoa(srp->nhlfe.prefv4.prefix), 16); + snprintf(pref, 19, "%s/%u", + inet_ntoa(srp->nhlfe.prefv4.prefix), + srp->nhlfe.prefv4.prefixlen); snprintf(sid, 22, "SR Pfx (idx %u)", srp->sid); if (srp->nhlfe.label_out == MPLS_LABEL_IMPLICIT_NULL) sprintf(label, "pop"); else sprintf(label, "%u", srp->nhlfe.label_out); itf = if_lookup_by_index(srp->nhlfe.ifindex, VRF_DEFAULT); - vty_out(vty, "%15s/%u %8u %9s %21s %9s %15s\n", pref, - srp->nhlfe.prefv4.prefixlen, srp->nhlfe.label_in, label, - sid, itf ? itf->name : "-", - inet_ntoa(srp->nhlfe.nexthop)); + if (json) { + if (!json_prefix) { + json_prefix = json_object_new_array(); + json_object_object_add(json_node, + "extendedPrefix", json_prefix); + } + json_obj = json_object_new_object(); + json_object_string_add(json_obj, "prefix", pref); + json_object_int_add(json_obj, "sid", srp->sid); + json_object_int_add(json_obj, "inputLabel", + srp->nhlfe.label_in); + json_object_string_add(json_obj, "outputLabel", + label); + json_object_string_add(json_obj, "interface", + itf ? itf->name : "-"); + json_object_string_add(json_obj, "nexthop", + inet_ntoa(srp->nhlfe.nexthop)); + json_object_array_add(json_prefix, json_obj); + } else { + vty_out(vty, "%18s %8u %9s %21s %9s %15s\n", + pref, srp->nhlfe.label_in, label, + sid, itf ? itf->name : "-", + inet_ntoa(srp->nhlfe.nexthop)); + } } for (ALL_LIST_ELEMENTS_RO(srn->ext_link, node, srl)) { - strncpy(pref, inet_ntoa(srl->nhlfe[0].prefv4.prefix), 16); + snprintf(pref, 19, "%s/%u", + inet_ntoa(srl->nhlfe[0].prefv4.prefix), + srl->nhlfe[0].prefv4.prefixlen); snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[0]); if (srl->nhlfe[0].label_out == MPLS_LABEL_IMPLICIT_NULL) sprintf(label, "pop"); else sprintf(label, "%u", srl->nhlfe[0].label_out); itf = if_lookup_by_index(srl->nhlfe[0].ifindex, VRF_DEFAULT); - vty_out(vty, "%15s/%u %8u %9s %21s %9s %15s\n", pref, - srl->nhlfe[0].prefv4.prefixlen, srl->nhlfe[0].label_in, - label, sid, itf ? itf->name : "-", - inet_ntoa(srl->nhlfe[0].nexthop)); - snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[1]); - if (srl->nhlfe[1].label_out == MPLS_LABEL_IMPLICIT_NULL) - sprintf(label, "pop"); - else - sprintf(label, "%u", srl->nhlfe[0].label_out); - vty_out(vty, "%15s/%u %8u %9s %21s %9s %15s\n", pref, - srl->nhlfe[1].prefv4.prefixlen, srl->nhlfe[1].label_in, - label, sid, itf ? itf->name : "-", - inet_ntoa(srl->nhlfe[1].nexthop)); + if (json) { + if (!json_link) { + json_link = json_object_new_array(); + json_object_object_add(json_node, + "extendedLink", json_link); + } + /* Primary Link */ + json_obj = json_object_new_object(); + json_object_string_add(json_obj, "prefix", pref); + json_object_int_add(json_obj, "sid", srl->sid[0]); + json_object_int_add(json_obj, "inputLabel", + srl->nhlfe[0].label_in); + json_object_string_add(json_obj, "outputLabel", + label); + json_object_string_add(json_obj, "interface", + itf ? itf->name : "-"); + json_object_string_add(json_obj, "nexthop", + inet_ntoa(srl->nhlfe[0].nexthop)); + json_object_array_add(json_link, json_obj); + /* Backup Link */ + json_obj = json_object_new_object(); + snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[1]); + if (srl->nhlfe[1].label_out == MPLS_LABEL_IMPLICIT_NULL) + sprintf(label, "pop"); + else + sprintf(label, "%u", srl->nhlfe[0].label_out); + json_object_string_add(json_obj, "prefix", pref); + json_object_int_add(json_obj, "sid", srl->sid[1]); + json_object_int_add(json_obj, "inputLabel", + srl->nhlfe[1].label_in); + json_object_string_add(json_obj, "outputLabel", + label); + json_object_string_add(json_obj, "interface", + itf ? itf->name : "-"); + json_object_string_add(json_obj, "nexthop", + inet_ntoa(srl->nhlfe[1].nexthop)); + json_object_array_add(json_link, json_obj); + } else { + vty_out(vty, "%18s %8u %9s %21s %9s %15s\n", + pref, srl->nhlfe[0].label_in, + label, sid, itf ? itf->name : "-", + inet_ntoa(srl->nhlfe[0].nexthop)); + snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[1]); + if (srl->nhlfe[1].label_out == MPLS_LABEL_IMPLICIT_NULL) + sprintf(label, "pop"); + else + sprintf(label, "%u", srl->nhlfe[1].label_out); + vty_out(vty, "%18s %8u %9s %21s %9s %15s\n", + pref, srl->nhlfe[1].label_in, + label, sid, itf ? itf->name : "-", + inet_ntoa(srl->nhlfe[1].nexthop)); + } } - vty_out(vty, "\n"); + if (json) + json_object_array_add(json, json_node); + else + vty_out(vty, "\n"); } -static void show_srdb_entry(struct hash_backet *backet, void *args) +static void show_vty_srdb(struct hash_backet *backet, void *args) { struct vty *vty = (struct vty *)args; struct sr_node *srn = (struct sr_node *)backet->data; - show_vty_sr_node(vty, srn); + show_sr_node(vty, NULL, srn); +} + +static void show_json_srdb(struct hash_backet *backet, void *args) +{ + struct json_object *json = (struct json_object *)args; + struct sr_node *srn = (struct sr_node *)backet->data; + + show_sr_node(NULL, json, srn); } DEFUN (show_ip_opsf_srdb, show_ip_ospf_srdb_cmd, - "show ip ospf database segment-routing [adv-router A.B.C.D|self-originate]", + "show ip ospf database segment-routing [adv-router A.B.C.D|self-originate] [json]", SHOW_STR IP_STR OSPF_STR @@ -2220,23 +2327,41 @@ DEFUN (show_ip_opsf_srdb, "Show Segment Routing Data Base\n" "Advertising SR node\n" "Advertising SR node ID (as an IP address)\n" - "Self-originated SR node\n") + "Self-originated SR node\n" + JSON_STR) { int idx = 0; struct in_addr rid; struct sr_node *srn; + u_char uj = use_json(argc, argv); + json_object *json = NULL, *json_node_array = NULL; if (!OspfSR.enabled) { vty_out(vty, "Segment Routing is disabled on this router\n"); return CMD_WARNING; } - vty_out(vty, "\n OSPF Segment Routing database for ID %s\n\n", - inet_ntoa(OspfSR.self->adv_router)); + if (uj) { + json = json_object_new_object(); + json_node_array = json_object_new_array(); + json_object_string_add(json, "srdbID", + inet_ntoa(OspfSR.self->adv_router)); + json_object_object_add(json, "srNodes", json_node_array); + } else { + vty_out(vty, + "\n\t\tOSPF Segment Routing database for ID %s\n\n", + inet_ntoa(OspfSR.self->adv_router)); + } if (argv_find(argv, argc, "self-originate", &idx)) { srn = OspfSR.self; - show_vty_sr_node(vty, srn); + show_sr_node(vty, json_node_array, srn); + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext(json, + JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } return CMD_SUCCESS; } @@ -2250,15 +2375,32 @@ DEFUN (show_ip_opsf_srdb, /* Get the SR Node from the SRDB */ srn = (struct sr_node *)hash_lookup(OspfSR.neighbors, (void *)&rid); - show_vty_sr_node(vty, srn); + show_sr_node(vty, json_node_array, srn); + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext(json, + JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } return CMD_SUCCESS; } /* No parameters have been provided, Iterate through all the SRDB */ - hash_iterate( - OspfSR.neighbors, - (void (*)(struct hash_backet *, void *))show_srdb_entry, - (void *)vty); + if (uj) { + hash_iterate( + OspfSR.neighbors, + (void (*)(struct hash_backet *, void *))show_json_srdb, + (void *)json_node_array); + vty_out(vty, "%s\n", + json_object_to_json_string_ext(json, + JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } else { + hash_iterate( + OspfSR.neighbors, + (void (*)(struct hash_backet *, void *))show_vty_srdb, + (void *)vty); + } return CMD_SUCCESS; } From 4ca997a8f82e442ef3e28a8ae14c0b914adc5e4a Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 28 Feb 2018 18:53:44 -0500 Subject: [PATCH 02/10] lib: Use STREAM_GET The addition of some rmac code snuck in the usage of a stream_get instead of a STREAM_GET() We need to be using STREAM_GET() Signed-off-by: Donald Sharp --- lib/zclient.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/zclient.c b/lib/zclient.c index ad91eb504b..01d8838e1f 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1085,7 +1085,7 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api) STREAM_GETC(s, api->message); STREAM_GETC(s, api->safi); if (CHECK_FLAG(api->flags, ZEBRA_FLAG_EVPN_ROUTE)) - stream_get(&(api->rmac), s, sizeof(struct ethaddr)); + STREAM_GET(&(api->rmac), s, sizeof(struct ethaddr)); /* Prefix. */ STREAM_GETC(s, api->prefix.family); From c7bacffe4618f27f45edb954426257c6f935d716 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 28 Feb 2018 18:55:10 -0500 Subject: [PATCH 03/10] zebra: Use the passed in nexthops vrf When decoding and creating the appropriate data structures for a nexthop, use the passed in vrf. Signed-off-by: Donald Sharp --- zebra/zserv.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/zebra/zserv.c b/zebra/zserv.c index 98cb54f7b8..bca8a509d8 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -1166,12 +1166,12 @@ static int zread_route_add(struct zserv *client, u_short length, switch (api_nh->type) { case NEXTHOP_TYPE_IFINDEX: nexthop = route_entry_nexthop_ifindex_add( - re, api_nh->ifindex, re->vrf_id); + re, api_nh->ifindex, api_nh->vrf_id); break; case NEXTHOP_TYPE_IPV4: nexthop = route_entry_nexthop_ipv4_add( re, &api_nh->gate.ipv4, NULL, - re->vrf_id); + api_nh->vrf_id); break; case NEXTHOP_TYPE_IPV4_IFINDEX: { @@ -1188,7 +1188,7 @@ static int zread_route_add(struct zserv *client, u_short length, nexthop = route_entry_nexthop_ipv4_ifindex_add( re, &api_nh->gate.ipv4, NULL, ifindex, - re->vrf_id); + api_nh->vrf_id); /* if this an EVPN route entry, program the nh as neigh @@ -1211,12 +1211,12 @@ static int zread_route_add(struct zserv *client, u_short length, } case NEXTHOP_TYPE_IPV6: nexthop = route_entry_nexthop_ipv6_add( - re, &api_nh->gate.ipv6, re->vrf_id); + re, &api_nh->gate.ipv6, api_nh->vrf_id); break; case NEXTHOP_TYPE_IPV6_IFINDEX: nexthop = route_entry_nexthop_ipv6_ifindex_add( re, &api_nh->gate.ipv6, api_nh->ifindex, - re->vrf_id); + api_nh->vrf_id); break; case NEXTHOP_TYPE_BLACKHOLE: nexthop = route_entry_nexthop_blackhole_add( From 1374aec98ff77fb02b7a7dba88d6a10fd8058196 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 28 Feb 2018 19:10:02 -0500 Subject: [PATCH 04/10] bgpd: Cleanup api_nh in bgpd a bit The api_nh was being figured 2 times, also refactor the vrf_id placement as well. Signed-off-by: Donald Sharp : --- bgpd/bgp_zebra.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index daa7ccbf42..029b3d4d36 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1054,6 +1054,9 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, else continue; + api_nh = &api.nexthops[valid_nh_count]; + api_nh->vrf_id = bgp->vrf_id; + if (nh_family == AF_INET) { struct in_addr *nexthop; @@ -1078,9 +1081,7 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, nexthop = &mpinfo_cp->attr->nexthop; - api_nh = &api.nexthops[valid_nh_count]; api_nh->gate.ipv4 = *nexthop; - api_nh->vrf_id = bgp->vrf_id; /* EVPN type-2 routes are programmed as onlink on l3-vni SVI */ @@ -1135,7 +1136,6 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, if (ifindex == 0) continue; - api_nh = &api.nexthops[valid_nh_count]; api_nh->gate.ipv6 = *nexthop; api_nh->ifindex = ifindex; api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX; From f56ee10fc7a4c028e767161c2503d26cceed194b Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 28 Feb 2018 19:16:51 -0500 Subject: [PATCH 05/10] ospfd: Add vrf to nhlfe route add So when a ospf SR is sending down routes to the kernel ensure that the nexthop vrf_id is set appropriately. Yes SR is in the default VRF. But for people who run across this code in the future, they will know to do the right thing from it. Signed-off-by: Donald Sharp --- ospfd/ospf_sr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c index 1560977ae8..02cf2636cc 100644 --- a/ospfd/ospf_sr.c +++ b/ospfd/ospf_sr.c @@ -675,6 +675,7 @@ static int ospf_zebra_send_mpls_ftn(int cmd, struct sr_nhlfe nhlfe) SET_FLAG(api.message, ZAPI_MESSAGE_LABEL); api_nh->labels[0] = nhlfe.label_out; api_nh->label_num = 1; + api_nh->vrf_id = VRF_DEFAULT; api.nexthop_num = 1; } From 07b37f93a7e5670b7a25e66a29a7363640005027 Mon Sep 17 00:00:00 2001 From: Chirag Shah Date: Wed, 14 Feb 2018 19:02:11 -0800 Subject: [PATCH 06/10] ospf6d: ECMP for external routes The route being added check its origin matches, with any of the existing path (list of paths). Remove the existing path, add if its cost is eqaual or less than any of the existing path. For a given route and of existing path cost is lower (better) than one being added, discard new route update. The existing path cost is higher (lower) than one being added, ospf6_route_add replaces existing with new route info. Compare cost between delete request and with existing route. Ticket:CM-16139 Signed-off-by: Chirag Shah --- ospf6d/ospf6_asbr.c | 267 +++++++++++++++++++++++++++++++++++++------ ospf6d/ospf6_asbr.h | 3 +- ospf6d/ospf6_route.c | 26 +++-- ospf6d/ospf6_top.c | 25 ++-- 4 files changed, 266 insertions(+), 55 deletions(-) diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 11f9e7c7b6..b52f1cef6c 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -204,26 +204,142 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old, { struct ospf6_route *old_route; struct ospf6_path *ecmp_path, *o_path = NULL; - struct listnode *anode; + struct listnode *anode, *anext; struct listnode *nnode, *rnode, *rnext; struct ospf6_nexthop *nh, *rnh; char buf[PREFIX2STR_BUFFER]; bool route_found = false; + /* check for old entry match with new route origin, + * delete old entry. + */ for (old_route = old; old_route; old_route = old_route->next) { - if (ospf6_route_is_same(old_route, route) && - (old_route->path.type == route->path.type) && - (old_route->path.cost == route->path.cost) && - (old_route->path.u.cost_e2 == route->path.u.cost_e2)) { + bool route_updated = false; + + if (!ospf6_route_is_same(old_route, route) || + (old_route->path.type != route->path.type)) + continue; + + /* Current and New route has same origin, + * delete old entry. + */ + for (ALL_LIST_ELEMENTS(old_route->paths, anode, anext, + o_path)) { + /* Check old route path and route has same + * origin. + */ + if (o_path->area_id != route->path.area_id || + (memcmp(&(o_path)->origin, &(route)->path.origin, + sizeof(struct ospf6_ls_origin)) != 0)) + continue; + + /* Cost is not same then delete current path */ + if ((o_path->cost == route->path.cost) && + (o_path->u.cost_e2 == route->path.u.cost_e2)) + continue; if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { prefix2str(&old_route->prefix, buf, sizeof(buf)); - zlog_debug("%s: old route %s path cost %u [%u]", + zlog_debug("%s: route %s cost old %u new %u is not same, replace route", + __PRETTY_FUNCTION__, buf, + o_path->cost, route->path.cost); + } + + /* Remove selected current rout path's nh from + * effective nh list. + */ + for (ALL_LIST_ELEMENTS_RO(o_path->nh_list, nnode, nh)) { + for (ALL_LIST_ELEMENTS(old_route->nh_list, + rnode, rnext, rnh)) { + if (!ospf6_nexthop_is_same(rnh, nh)) + continue; + listnode_delete(old_route->nh_list, + rnh); + ospf6_nexthop_delete(rnh); + route_updated = true; + } + } + + listnode_delete(old_route->paths, o_path); + ospf6_path_free(o_path); + + /* Current route's path (adv_router info) is similar + * to route being added. + * Replace current route's path with paths list head. + * Update FIB with effective NHs. + */ + if (listcount(old_route->paths)) { + if (old_route->path.origin.id == + route->path.origin.id && + old_route->path.origin.adv_router == + route->path.origin.adv_router) { + struct ospf6_path *h_path; + + h_path = (struct ospf6_path *) + listgetdata(listhead(old_route->paths)); + old_route->path.origin.type = + h_path->origin.type; + old_route->path.origin.id = + h_path->origin.id; + old_route->path.origin.adv_router = + h_path->origin.adv_router; + } + + if (route_updated) { + for (ALL_LIST_ELEMENTS(old_route->paths, + anode, anext, o_path)) { + ospf6_merge_nexthops( + old_route->nh_list, + o_path->nh_list); + } + /* Update RIB/FIB with effective + * nh_list + */ + if (ospf6->route_table->hook_add) + (*ospf6->route_table->hook_add) + (old_route); + break; + } + } else { + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { + prefix2str(&old_route->prefix, buf, + sizeof(buf)); + zlog_debug("%s: route %s old cost %u new cost %u, delete old entry.", + __PRETTY_FUNCTION__, buf, + old_route->path.cost, + route->path.cost); + } + ospf6_route_remove(old_route, + ospf6->route_table); + break; + } + } + if (route_updated) + break; + } + + /* Add new route */ + for (old_route = old; old_route; old_route = old_route->next) { + + /* Current and New Route prefix or route type + * is not same skip this current node. + */ + if (!ospf6_route_is_same(old_route, route) || + (old_route->path.type != route->path.type)) + continue; + + /* Old Route and New Route have Equal Cost, Merge NHs */ + if ((old_route->path.cost == route->path.cost) && + (old_route->path.u.cost_e2 == route->path.u.cost_e2)) { + + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { + prefix2str(&old_route->prefix, buf, + sizeof(buf)); + zlog_debug("%s: old route %s path cost %u e2 %u", __PRETTY_FUNCTION__, buf, old_route->path.cost, - ospf6_route_is_same(old_route, - route)); + old_route->path.u.cost_e2); } route_found = true; /* check if this path exists already in @@ -232,9 +348,10 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old, */ for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode, o_path)) { - if ((o_path->origin.id == route->path.origin.id) - && (o_path->origin.adv_router == - route->path.origin.adv_router)) + if (o_path->area_id == route->path.area_id && + (memcmp(&(o_path)->origin, + &(route)->path.origin, + sizeof(struct ospf6_ls_origin)) == 0)) break; } /* If path is not found in old_route paths's list, @@ -262,12 +379,13 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old, if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { prefix2str(&route->prefix, buf, sizeof(buf)); - zlog_debug("%s: route %s another path added with nh %u, Paths %u", + zlog_debug("%s: route %s another path added with nh %u, effective paths %u nh %u", __PRETTY_FUNCTION__, buf, listcount(ecmp_path->nh_list), old_route->paths ? listcount(old_route->paths) - : 0); + : 0, + listcount(old_route->nh_list)); } } else { for (ALL_LIST_ELEMENTS_RO(o_path->nh_list, @@ -313,6 +431,7 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old, * route. */ ospf6_route_delete(route); + break; } } @@ -426,11 +545,12 @@ void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa) } -void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa) +void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa, + struct ospf6_route *asbr_entry) { struct ospf6_as_external_lsa *external; struct prefix prefix; - struct ospf6_route *route, *nroute; + struct ospf6_route *route, *nroute, *route_to_del; char buf[PREFIX2STR_BUFFER]; external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END( @@ -445,6 +565,35 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa) return; } + route_to_del = ospf6_route_create(); + route_to_del->type = OSPF6_DEST_TYPE_NETWORK; + route_to_del->prefix.family = AF_INET6; + route_to_del->prefix.prefixlen = external->prefix.prefix_length; + ospf6_prefix_in6_addr(&route_to_del->prefix.u.prefix6, + &external->prefix); + + route_to_del->path.origin.type = lsa->header->type; + route_to_del->path.origin.id = lsa->header->id; + route_to_del->path.origin.adv_router = lsa->header->adv_router; + + if (asbr_entry) { + route_to_del->path.area_id = asbr_entry->path.area_id; + if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_E)) { + route_to_del->path.type = OSPF6_PATH_TYPE_EXTERNAL2; + route_to_del->path.metric_type = 2; + route_to_del->path.cost = asbr_entry->path.cost; + route_to_del->path.u.cost_e2 = + OSPF6_ASBR_METRIC(external); + } else { + route_to_del->path.type = OSPF6_PATH_TYPE_EXTERNAL1; + route_to_del->path.metric_type = 1; + route_to_del->path.cost = + asbr_entry->path.cost + + OSPF6_ASBR_METRIC(external); + route_to_del->path.u.cost_e2 = 0; + } + } + memset(&prefix, 0, sizeof(struct prefix)); prefix.family = AF_INET6; prefix.prefixlen = external->prefix.prefix_length; @@ -459,14 +608,25 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa) return; } - for (ospf6_route_lock(route); - route && ospf6_route_is_prefix(&prefix, route); route = nroute) { + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { + prefix2str(&prefix, buf, sizeof(buf)); + zlog_debug("%s: Current route %s cost %u e2 %u, route to del cost %u e2 %u", + __PRETTY_FUNCTION__, buf, route->path.cost, + route->path.u.cost_e2, + route_to_del->path.cost, + route_to_del->path.u.cost_e2); + } + + for (ospf6_route_lock(route); route && + ospf6_route_is_prefix(&prefix, route); route = nroute) { nroute = ospf6_route_next(route); + if (route->type != OSPF6_DEST_TYPE_NETWORK) continue; - /* Route has multiple ECMP paths remove, - * matching path and update effective route's nh list. + /* Route has multiple ECMP paths, remove matching + * path. Update current route's effective nh list + * after removal of one of the path. */ if (listcount(route->paths) > 1) { struct listnode *anode, *anext; @@ -481,18 +641,36 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa) */ for (ALL_LIST_ELEMENTS(route->paths, anode, anext, o_path)) { - if (o_path->origin.type != lsa->header->type) + if ((o_path->origin.type != lsa->header->type) + || (o_path->origin.adv_router != + lsa->header->adv_router) || + (o_path->origin.id != lsa->header->id)) continue; - if (o_path->origin.id != lsa->header->id) - continue; - if (o_path->origin.adv_router != - lsa->header->adv_router) + + /* Compare LSA cost with current + * route info. + */ + if (!asbr_entry && (o_path->cost != + route_to_del->path.cost || + o_path->u.cost_e2 != + route_to_del->path.u.cost_e2)) { + if (IS_OSPF6_DEBUG_EXAMIN( + AS_EXTERNAL)) { + prefix2str(&prefix, buf, + sizeof(buf)); + zlog_debug( + "%s: route %s to delete is not same, cost %u del cost %u. skip", + __PRETTY_FUNCTION__, buf, + route->path.cost, + route_to_del->path.cost); + } continue; + } if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { prefix2str(&prefix, buf, sizeof(buf)); zlog_debug( - "%s: route %s path found with nh %u", + "%s: route %s path found with nh %u to remove.", __PRETTY_FUNCTION__, buf, listcount(o_path->nh_list)); } @@ -542,13 +720,13 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa) listcount(route->nh_list)); } - /* Update RIB/FIB w/ effective nh_list */ + /* Update RIB/FIB with effective nh_list */ if (ospf6->route_table->hook_add) (*ospf6->route_table->hook_add)(route); - /* route's path is similar to lsa header, - * replace route's path with route's - * paths list head. + /* route's primary path is similar to LSA, + * replace route's primary path with + * route's paths list head. */ if (route->path.origin.id == lsa->header->id && route->path.origin.adv_router == @@ -568,12 +746,29 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa) continue; } else { - if (route->path.origin.type != lsa->header->type) + /* Compare LSA origin and cost with current route info. + * if any check fails skip del this route node. + */ + if (asbr_entry && (!ospf6_route_is_same_origin(route, + route_to_del) || + (route->path.type != route_to_del->path.type) || + (route->path.cost != route_to_del->path.cost) || + (route->path.u.cost_e2 != + route_to_del->path.u.cost_e2))) { + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { + prefix2str(&prefix, buf, sizeof(buf)); + zlog_debug("%s: route %s to delete is not same, cost %u del cost %u. skip", + __PRETTY_FUNCTION__, buf, + route->path.cost, + route_to_del->path.cost); + } continue; - if (route->path.origin.id != lsa->header->id) - continue; - if (route->path.origin.adv_router != - lsa->header->adv_router) + } + + if ((route->path.origin.type != lsa->header->type) || + (route->path.origin.adv_router != + lsa->header->adv_router) || + (route->path.origin.id != lsa->header->id)) continue; } if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { @@ -589,6 +784,8 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa) } if (route != NULL) ospf6_route_unlock(route); + + ospf6_route_delete(route_to_del); } void ospf6_asbr_lsentry_add(struct ospf6_route *asbr_entry) @@ -622,7 +819,7 @@ void ospf6_asbr_lsentry_remove(struct ospf6_route *asbr_entry) type = htons(OSPF6_LSTYPE_AS_EXTERNAL); router = ospf6_linkstate_prefix_adv_router(&asbr_entry->prefix); for (ALL_LSDB_TYPED_ADVRTR(ospf6->lsdb, type, router, lsa)) - ospf6_asbr_lsa_remove(lsa); + ospf6_asbr_lsa_remove(lsa, asbr_entry); } diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h index cc4f0272aa..bd160a6456 100644 --- a/ospf6d/ospf6_asbr.h +++ b/ospf6d/ospf6_asbr.h @@ -71,7 +71,8 @@ struct ospf6_as_external_lsa { } extern void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa); -extern void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa); +extern void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa, + struct ospf6_route *asbr_entry); extern void ospf6_asbr_lsentry_add(struct ospf6_route *asbr_entry); extern void ospf6_asbr_lsentry_remove(struct ospf6_route *asbr_entry); diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index 19eb9a3fe6..ef0a093d13 100644 --- a/ospf6d/ospf6_route.c +++ b/ospf6d/ospf6_route.c @@ -469,6 +469,8 @@ int ospf6_route_cmp(struct ospf6_route *ra, struct ospf6_route *rb) if (ra->path.type == OSPF6_PATH_TYPE_EXTERNAL2) { if (ra->path.u.cost_e2 != rb->path.u.cost_e2) return (ra->path.u.cost_e2 - rb->path.u.cost_e2); + else + return (ra->path.cost - rb->path.cost); } else { if (ra->path.cost != rb->path.cost) return (ra->path.cost - rb->path.cost); @@ -627,10 +629,10 @@ struct ospf6_route *ospf6_route_add(struct ospf6_route *route, if (ospf6_route_is_identical(old, route)) { if (IS_OSPF6_DEBUG_ROUTE(MEMORY)) zlog_debug( - "%s %p: route add %p: needless update of %p", + "%s %p: route add %p: needless update of %p old cost %u", ospf6_route_table_name(table), (void *)table, (void *)route, - (void *)old); + (void *)old, old->path.cost); else if (IS_OSPF6_DEBUG_ROUTE(TABLE)) zlog_debug("%s: route add: needless update", ospf6_route_table_name(table)); @@ -645,9 +647,10 @@ struct ospf6_route *ospf6_route_add(struct ospf6_route *route, } if (IS_OSPF6_DEBUG_ROUTE(MEMORY)) - zlog_debug("%s %p: route add %p: update of %p", + zlog_debug("%s %p: route add %p cost %u: update of %p old cost %u", ospf6_route_table_name(table), (void *)table, - (void *)route, (void *)old); + (void *)route, route->path.cost, (void *)old, + old->path.cost); else if (IS_OSPF6_DEBUG_ROUTE(TABLE)) zlog_debug("%s: route add: update", ospf6_route_table_name(table)); @@ -686,13 +689,14 @@ struct ospf6_route *ospf6_route_add(struct ospf6_route *route, if (prev || next) { if (IS_OSPF6_DEBUG_ROUTE(MEMORY)) zlog_debug( - "%s %p: route add %p: another path: prev %p, next %p node refcount %u", + "%s %p: route add %p cost %u: another path: prev %p, next %p node ref %u", ospf6_route_table_name(table), (void *)table, - (void *)route, (void *)prev, (void *)next, - node->lock); + (void *)route, route->path.cost, (void *)prev, + (void *)next, node->lock); else if (IS_OSPF6_DEBUG_ROUTE(TABLE)) - zlog_debug("%s: route add: another path found", - ospf6_route_table_name(table)); + zlog_debug("%s: route add cost %u: another path found", + ospf6_route_table_name(table), + route->path.cost); if (prev == NULL) prev = next->prev; @@ -814,9 +818,9 @@ void ospf6_route_remove(struct ospf6_route *route, prefix2str(&route->prefix, buf, sizeof(buf)); if (IS_OSPF6_DEBUG_ROUTE(MEMORY)) - zlog_debug("%s %p: route remove %p: %s refcount %u", + zlog_debug("%s %p: route remove %p: %s cost %u refcount %u", ospf6_route_table_name(table), (void *)table, - (void *)route, buf, route->lock); + (void *)route, buf, route->path.cost, route->lock); else if (IS_OSPF6_DEBUG_ROUTE(TABLE)) zlog_debug("%s: route remove: %s", ospf6_route_table_name(table), buf); diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 25d968fb68..afe2d7397b 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -72,7 +72,7 @@ static void ospf6_top_lsdb_hook_remove(struct ospf6_lsa *lsa) { switch (ntohs(lsa->header->type)) { case OSPF6_LSTYPE_AS_EXTERNAL: - ospf6_asbr_lsa_remove(lsa); + ospf6_asbr_lsa_remove(lsa, NULL); break; default: @@ -96,11 +96,16 @@ static void ospf6_top_route_hook_remove(struct ospf6_route *route) static void ospf6_top_brouter_hook_add(struct ospf6_route *route) { if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { - char buf[PREFIX2STR_BUFFER]; + uint32_t brouter_id; + char brouter_name[16]; - prefix2str(&route->prefix, buf, sizeof(buf)); - zlog_debug("%s: brouter %s add with nh count %u", - __PRETTY_FUNCTION__, buf, listcount(route->nh_list)); + brouter_id = ADV_ROUTER_IN_PREFIX(&route->prefix); + inet_ntop(AF_INET, &brouter_id, brouter_name, + sizeof(brouter_name)); + zlog_debug("%s: brouter %s add with adv router %x nh count %u", + __PRETTY_FUNCTION__, brouter_name, + route->path.origin.adv_router, + listcount(route->nh_list)); } ospf6_abr_examin_brouter(ADV_ROUTER_IN_PREFIX(&route->prefix)); ospf6_asbr_lsentry_add(route); @@ -110,11 +115,15 @@ static void ospf6_top_brouter_hook_add(struct ospf6_route *route) static void ospf6_top_brouter_hook_remove(struct ospf6_route *route) { if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { - char buf[PREFIX2STR_BUFFER]; + uint32_t brouter_id; + char brouter_name[16]; - prefix2str(&route->prefix, buf, sizeof(buf)); + brouter_id = ADV_ROUTER_IN_PREFIX(&route->prefix); + inet_ntop(AF_INET, &brouter_id, brouter_name, + sizeof(brouter_name)); zlog_debug("%s: brouter %s del with nh count %u", - __PRETTY_FUNCTION__, buf, listcount(route->nh_list)); + __PRETTY_FUNCTION__, brouter_name, + listcount(route->nh_list)); } route->flag |= OSPF6_ROUTE_REMOVE; ospf6_abr_examin_brouter(ADV_ROUTER_IN_PREFIX(&route->prefix)); From df25d292130839218fa7c812a62ee300aab46746 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 2 Mar 2018 05:15:33 -0500 Subject: [PATCH 07/10] ospfd: Cleanup ospf SR log messages When OSPF SR is not configured one would expect to not see any output from it at all in the debug log with no debugs turned on. Signed-off-by: Donald Sharp --- ospfd/ospf_sr.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c index 1560977ae8..1a68eda6cc 100644 --- a/ospfd/ospf_sr.c +++ b/ospfd/ospf_sr.c @@ -306,7 +306,8 @@ int ospf_sr_init(void) { int rc = -1; - zlog_info("SR (%s): Initialize SR Data Base", __func__); + if (IS_DEBUG_OSPF_SR) + zlog_info("SR (%s): Initialize SR Data Base", __func__); memset(&OspfSR, 0, sizeof(struct ospf_sr_db)); OspfSR.enabled = false; @@ -1616,11 +1617,11 @@ static int ospf_sr_update_schedule(struct thread *t) monotime(&stop_time); - zlog_info( - "SR (%s): SPF Processing Time(usecs): %lld\n", - __func__, - (stop_time.tv_sec - start_time.tv_sec) * 1000000LL - + (stop_time.tv_usec - start_time.tv_usec)); + if (IS_DEBUG_OSPF_SR) + zlog_debug("SR (%s): SPF Processing Time(usecs): %lld\n", + __func__, + (stop_time.tv_sec - start_time.tv_sec) * 1000000LL + + (stop_time.tv_usec - start_time.tv_usec)); OspfSR.update = false; return 1; From 4b322ffebb13880f6fc6175acb926c225b07d117 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 2 Mar 2018 15:20:43 +0100 Subject: [PATCH 08/10] bgpd,ospfd: add sys_admin capabilities This capability, when used, is mapped over linux sys_admin capability. This is necessary from the daemon perspective, in order to handle NETNS based VRFs, because calling setns() requires sys admin capability. Signed-off-by: Philippe Guibert --- bgpd/bgp_main.c | 2 +- ospfd/ospf_main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 82c74e4afa..30b7afff92 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -106,7 +106,7 @@ static int retain_mode = 0; /* privileges */ static zebra_capabilities_t _caps_p[] = { - ZCAP_BIND, ZCAP_NET_RAW, ZCAP_NET_ADMIN, + ZCAP_BIND, ZCAP_NET_RAW, ZCAP_NET_ADMIN, ZCAP_SYS_ADMIN }; struct zebra_privs_t bgpd_privs = { diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index 7bd644f43d..8dbf39ef5d 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -55,7 +55,7 @@ /* ospfd privileges */ zebra_capabilities_t _caps_p[] = { - ZCAP_NET_RAW, ZCAP_BIND, ZCAP_NET_ADMIN, + ZCAP_NET_RAW, ZCAP_BIND, ZCAP_NET_ADMIN, ZCAP_SYS_ADMIN }; struct zebra_privs_t ospfd_privs = { From 4cfe547340bf56205203a714ef35880b7ec441cc Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Mon, 5 Mar 2018 19:43:39 +0100 Subject: [PATCH 09/10] tests: fix python test description for test_ringbuf Signed-off-by: Christian Franke --- tests/lib/test_ringbuf.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/lib/test_ringbuf.py b/tests/lib/test_ringbuf.py index 860d872f86..5d994ddd7b 100644 --- a/tests/lib/test_ringbuf.py +++ b/tests/lib/test_ringbuf.py @@ -1,4 +1,6 @@ import frrtest -class TestRingbuf(frrtest.TestExitNonzero): +class TestRingbuf(frrtest.TestMultiOut): program = './test_ringbuf' + +TestRingbuf.exit_cleanly() From 2d0e9b80262bca2828f50379e976507b830bb7a4 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Mon, 5 Mar 2018 19:49:31 +0100 Subject: [PATCH 10/10] tests: update gitignore Signed-off-by: Christian Franke --- tests/.gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/.gitignore b/tests/.gitignore index ab1d55b548..c2fe9c8890 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -24,10 +24,12 @@ __pycache__ /bgpd/test_ecommunity /bgpd/test_mp_attr /bgpd/test_mpath +/bgpd/test_packet /isisd/test_fuzz_isis_tlv /isisd/test_fuzz_isis_tlv_tests.h /isisd/test_isis_vertex_queue /lib/cli/test_cli +/lib/cli/test_cli_clippy.c /lib/cli/test_commands /lib/cli/test_commands_defun.c /lib/test_buffer @@ -38,6 +40,7 @@ __pycache__ /lib/test_memory /lib/test_nexthop_iter /lib/test_privs +/lib/test_ringbuf /lib/test_srcdest_table /lib/test_segv /lib/test_sig @@ -48,3 +51,4 @@ __pycache__ /lib/test_ttable /lib/test_zmq /ospf6d/test_lsdb +/ospf6d/test_lsdb_clippy.c