From f159940c1cd1648143f2e2cb6baca0099604805f Mon Sep 17 00:00:00 2001 From: Sindhu Parvathi Gopinathan Date: Fri, 28 Apr 2023 05:28:58 -0700 Subject: [PATCH 001/106] zebra:add df flag into evpn esi json output FRR "show evpn es 'esi-id' json" output dont have the 'df' flag. Modified the code to add the 'df' flag into json output. Before Fix: ``` torm-11# show evpn es 03:44:38:39:ff:ff:01:00:00:01 json { "esi":"03:44:38:39:ff:ff:01:00:00:01", "accessPort":"hostbond1", "flags":[ "local", "remote", "readyForBgp", "bridgePort", "operUp", "nexthopGroupActive" ====================> df is missing ], "vniCount":10, "macCount":13, "dfPreference":50000, "nexthopGroup":536870913, "vteps":[ { "vtep":"27.0.0.16", "dfAlgorithm":"preference", "dfPreference":32767, "nexthopId":268435460 }, { "vtep":"27.0.0.17", "dfAlgorithm":"preference", "dfPreference":32767, "nexthopId":268435461 } ] } torm-11# ``` After Fix:- ``` torm-11# show evpn es 03:44:38:39:ff:ff:01:00:00:01 json { "esi":"03:44:38:39:ff:ff:01:00:00:01", "accessPort":"hostbond1", "flags":[ "local", "remote", "readyForBgp", "bridgePort", "operUp", "nexthopGroupActive", "df" ========================> designated-forward flag added ], "vniCount":10, "macCount":13, "dfPreference":50000, "nexthopGroup":536870913, "vteps":[ { "vtep":"27.0.0.16", "dfAlgorithm":"preference", "dfPreference":32767, "nexthopId":268435460 }, { "vtep":"27.0.0.17", "dfAlgorithm":"preference", "dfPreference":32767, "nexthopId":268435461 } ] } torm-11# ``` Ticket:# 3447935 Issue: 3447935 Testing: UT done Signed-off-by: Sindhu Parvathi Gopinathan's Signed-off-by: Chirag Shah --- zebra/zebra_evpn_mh.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c index 75e7e20176a9..7a951816acec 100644 --- a/zebra/zebra_evpn_mh.c +++ b/zebra/zebra_evpn_mh.c @@ -3101,6 +3101,9 @@ static void zebra_evpn_es_show_entry(struct vty *vty, struct zebra_evpn_es *es, json_array_string_add(json_flags, "local"); if (es->flags & ZEBRA_EVPNES_REMOTE) json_array_string_add(json_flags, "remote"); + if (es->flags & ZEBRA_EVPNES_LOCAL && + !(es->flags & ZEBRA_EVPNES_NON_DF)) + json_array_string_add(json_flags, "df"); if (es->flags & ZEBRA_EVPNES_NON_DF) json_array_string_add(json_flags, "nonDF"); if (es->flags & ZEBRA_EVPNES_BYPASS) From 2899964f427b83c3b4c0f2db3e6908fca09f8edd Mon Sep 17 00:00:00 2001 From: Chirag Shah Date: Mon, 12 Sep 2022 18:32:26 -0700 Subject: [PATCH 002/106] zebra: add vni bridge vlan info in json output Add VNI's associated bridge and vlan info in json output format. torm-11# show evpn vni detail VNI: 1008 Type: L2 Vlan: 1008 Bridge: bridge ... Ticket:#3208813 Reviewed By: Testing Done: torm-11# show evpn vni detail json [ { "vni":1008, "type":"L2", "vlan":1008, <<< New field "bridge":"bridge", <<< New field "vrf":"vrf3", "vxlanInterface":"vxlan0", "ifindex":15, "vtepIp":"27.0.0.15", "mcastGroup":"239.1.1.108", "advertiseGatewayMacip":"No", "advertiseSviMacip":"No", "numMacs":18, "numArpNd":42, "numRemoteVteps":[ "27.0.0.18", "27.0.0.17", "27.0.0.16" ] }, ] Signed-off-by: Chirag Shah --- zebra/zebra_evpn.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c index 25c616c4c956..b92922d22d1e 100644 --- a/zebra/zebra_evpn.c +++ b/zebra/zebra_evpn.c @@ -109,6 +109,9 @@ void zebra_evpn_print(struct zebra_evpn *zevpn, void **ctxt) } else { json_object_int_add(json, "vni", zevpn->vni); json_object_string_add(json, "type", "L2"); + json_object_int_add(json, "vlan", zevpn->vid); + json_object_string_add(json, "bridge", + zevpn->bridge_if ? zevpn->bridge_if->name: ""); json_object_string_add(json, "tenantVrf", vrf_id_to_name(zevpn->vrf_id)); } From a38973195130487ccfc478fda7d1e7dfd739ae2d Mon Sep 17 00:00:00 2001 From: Chirag Shah Date: Wed, 16 Feb 2022 18:01:10 -0800 Subject: [PATCH 003/106] zebra: add json support for svd vxlan type Reorganize common vlxan dump api to handle both screen rending and json data object. Testing Done: "interfaceType":"Vxlan", "vtepIp":"27.0.0.16", "vxlanId":{ "1006":{ "accessVlan":1006, "mcastGroup":"239.1.1.106" } }, "linkInterface":"ipmr-lo", "masterInterface":"bridge", SVD interface output: "interfaceType":"Vxlan", "vtepIp":"27.0.0.16", "vxlanId":{ "1005":{ "accessVlan":1005, "mcastGroup":"0.0.0.0" }, "1001":{ "accessVlan":1001, "mcastGroup":"0.0.0.0" }, "4001":{ "accessVlan":4001, "mcastGroup":"0.0.0.0" }, "1003":{ "accessVlan":1003, "mcastGroup":"0.0.0.0" }, "1007":{ "accessVlan":1007, "mcastGroup":"0.0.0.0" } }, "masterInterface":"bridge", Signed-off-by: Chirag Shah --- zebra/interface.c | 87 +++++++++++++++++++++++++++++------------------ 1 file changed, 54 insertions(+), 33 deletions(-) diff --git a/zebra/interface.c b/zebra/interface.c index f7fd112cd4ce..76674475e113 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -2530,42 +2530,58 @@ static inline bool if_is_protodown_applicable(struct interface *ifp) return true; } -static void zebra_vxlan_if_vni_dump_vty(struct vty *vty, +static void zebra_vxlan_if_vni_dump_vty(struct vty *vty, json_object *json_if, struct zebra_vxlan_vni *vni) { - char str[INET6_ADDRSTRLEN]; + json_object *json_vni; + char vni_str[VNI_STR_LEN]; + char buf[PREFIX_STRLEN]; - vty_out(vty, " VxLAN Id %u", vni->vni); - if (vni->access_vlan) - vty_out(vty, " Access VLAN Id %u\n", vni->access_vlan); + if (vty) { + vty_out(vty, "\n VxLAN Id %u", vni->vni); + if (vni->access_vlan) + vty_out(vty, " Access VLAN Id %u", vni->access_vlan); - if (vni->mcast_grp.s_addr != INADDR_ANY) - vty_out(vty, " Mcast Group %s", - inet_ntop(AF_INET, &vni->mcast_grp, str, sizeof(str))); + if (vni->mcast_grp.s_addr != INADDR_ANY && + inet_ntop(AF_INET, &vni->mcast_grp, buf, sizeof(buf)) != NULL) + vty_out(vty, "\n Mcast Group %s", buf); + } else if (json_if) { + json_vni = json_object_new_object(); + snprintf(vni_str, sizeof(vni_str), "%u", vni->vni); + json_object_int_add(json_vni, "accessVlan", vni->access_vlan); + json_object_string_addf(json_vni, "mcastGroup", "%pI4", + &vni->mcast_grp); + json_object_object_add(json_if, vni_str, json_vni); + } } static void zebra_vxlan_if_vni_hash_dump_vty(struct hash_bucket *bucket, - void *ctxt) + void **args) { - struct vty *vty; struct zebra_vxlan_vni *vni; + struct vty *vty; + json_object *json_if; vni = (struct zebra_vxlan_vni *)bucket->data; - vty = (struct vty *)ctxt; + vty = (struct vty *)args[0]; + json_if = (json_object *)args[1]; - zebra_vxlan_if_vni_dump_vty(vty, vni); + zebra_vxlan_if_vni_dump_vty(vty, json_if, vni); } static void zebra_vxlan_if_dump_vty(struct vty *vty, struct zebra_if *zebra_if) { struct zebra_l2info_vxlan *vxlan_info; struct zebra_vxlan_vni_info *vni_info; + void *args[2]; + char buf[PREFIX_STRLEN]; vxlan_info = &zebra_if->l2info.vxl; vni_info = &vxlan_info->vni_info; - if (vxlan_info->vtep_ip.s_addr != INADDR_ANY) - vty_out(vty, " VTEP IP: %pI4", &vxlan_info->vtep_ip); + if (vxlan_info->vtep_ip.s_addr != INADDR_ANY && + inet_ntop(AF_INET, &vxlan_info->vtep_ip, buf, sizeof(buf)) != NULL) + vty_out(vty, " VTEP IP: %s", buf); if (vxlan_info->ifindex_link && (vxlan_info->link_nsid != NS_UNKNOWN)) { struct interface *ifp; @@ -2578,10 +2594,14 @@ static void zebra_vxlan_if_dump_vty(struct vty *vty, struct zebra_if *zebra_if) } if (IS_ZEBRA_VXLAN_IF_VNI(zebra_if)) { - zebra_vxlan_if_vni_dump_vty(vty, &vni_info->vni); + zebra_vxlan_if_vni_dump_vty(vty, NULL, &vni_info->vni); } else { + args[0] = vty; + args[1] = NULL; hash_iterate(vni_info->vni_table, - zebra_vxlan_if_vni_hash_dump_vty, vty); + (void (*)(struct hash_bucket *, + void *))zebra_vxlan_if_vni_hash_dump_vty, + args); } vty_out(vty, "\n"); @@ -2910,23 +2930,14 @@ static void zebra_vxlan_if_vni_dump_vty_json(json_object *json_if, &vni->mcast_grp); } -static void zebra_vxlan_if_vni_hash_dump_vty_json(struct hash_bucket *bucket, - void *ctxt) -{ - json_object *json_if; - struct zebra_vxlan_vni *vni; - - vni = (struct zebra_vxlan_vni *)bucket->data; - json_if = (json_object *)ctxt; - - zebra_vxlan_if_vni_dump_vty_json(json_if, vni); -} - static void zebra_vxlan_if_dump_vty_json(json_object *json_if, struct zebra_if *zebra_if) { struct zebra_l2info_vxlan *vxlan_info; struct zebra_vxlan_vni_info *vni_info; + json_object *json_vnis = NULL; + uint32_t num_vnis; + void *args[2]; vxlan_info = &zebra_if->l2info.vxl; vni_info = &vxlan_info->vni_info; @@ -2944,12 +2955,23 @@ static void zebra_vxlan_if_dump_vty_json(json_object *json_if, json_object_string_add(json_if, "linkInterface", ifp == NULL ? "Unknown" : ifp->name); } + + json_vnis = json_object_new_object(); if (IS_ZEBRA_VXLAN_IF_VNI(zebra_if)) { zebra_vxlan_if_vni_dump_vty_json(json_if, &vni_info->vni); } else { - hash_iterate(vni_info->vni_table, - zebra_vxlan_if_vni_hash_dump_vty_json, json_if); + num_vnis = hashcount(vni_info->vni_table); + if (num_vnis) { + args[0] = NULL; + args[1] = json_vnis; + hash_iterate(vni_info->vni_table, + (void (*)(struct hash_bucket *, void *)) + zebra_vxlan_if_vni_hash_dump_vty, + args); + } } + + json_object_object_add(json_if, "vxlanId", json_vnis); } static void if_dump_vty_json(struct vty *vty, struct interface *ifp, @@ -3091,7 +3113,6 @@ static void if_dump_vty_json(struct vty *vty, struct interface *ifp, json_object_int_add(json_if, "vlanId", vlan_info->vid); } else if (IS_ZEBRA_IF_VXLAN(ifp)) { zebra_vxlan_if_dump_vty_json(json_if, zebra_if); - } else if (IS_ZEBRA_IF_GRE(ifp)) { struct zebra_l2info_gre *gre_info; @@ -3104,8 +3125,8 @@ static void if_dump_vty_json(struct vty *vty, struct interface *ifp, json_if, "vtepRemoteIp", "%pI4", &gre_info->vtep_ip_remote); } - if (gre_info->ifindex_link - && (gre_info->link_nsid != NS_UNKNOWN)) { + if (gre_info->ifindex_link && + (gre_info->link_nsid != NS_UNKNOWN)) { struct interface *ifp; ifp = if_lookup_by_index_per_ns( From b57ad60afd6a69da0caf790b87f1c0da816c3b35 Mon Sep 17 00:00:00 2001 From: Sindhu Parvathi Gopinathan Date: Mon, 18 Dec 2023 19:18:55 -0800 Subject: [PATCH 004/106] zebra: show nexthop-group rib brief json Handles json brief/tiny output for scaled nexthop-group rib entries. Commands supported: ``` show nexthop-group rib brief json show nexthop-group rib 117 brief json show nexthop-group rib singleton ip brief json show nexthop-group rib singleton ipv6 brief json show nexthop-group rib zebra brief json ``` Ticket: #3710394 Issue: 3710394 Signed-off-by: Sindhu Parvathi Gopinathan's --- lib/nexthop.c | 60 +++++++++++++++++++--------------- lib/nexthop.h | 2 +- zebra/zebra_rnh.c | 6 ++-- zebra/zebra_rnh.h | 2 +- zebra/zebra_vty.c | 82 +++++++++++++++++++++++++++++++---------------- 5 files changed, 95 insertions(+), 57 deletions(-) diff --git a/lib/nexthop.c b/lib/nexthop.c index 332581fbd8f4..379cf3581883 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -1210,7 +1210,7 @@ bool nexthop_is_blackhole(const struct nexthop *nh) */ void nexthop_json_helper(json_object *json_nexthop, const struct nexthop *nexthop, bool display_vrfid, - uint8_t rn_family) + uint8_t rn_family, bool brief) { json_object *json_labels = NULL; json_object *json_backups = NULL; @@ -1220,20 +1220,23 @@ void nexthop_json_helper(json_object *json_nexthop, json_object *json_segs = NULL; int i; - json_object_int_add(json_nexthop, "flags", nexthop->flags); + if (!brief) { + json_object_int_add(json_nexthop, "flags", nexthop->flags); - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)) - json_object_boolean_true_add(json_nexthop, "duplicate"); + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)) + json_object_boolean_true_add(json_nexthop, "duplicate"); - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) - json_object_boolean_true_add(json_nexthop, "fib"); + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) + json_object_boolean_true_add(json_nexthop, "fib"); + } switch (nexthop->type) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: json_object_string_addf(json_nexthop, "ip", "%pI4", &nexthop->gate.ipv4); - json_object_string_add(json_nexthop, "afi", "ipv4"); + if (!brief) + json_object_string_add(json_nexthop, "afi", "ipv4"); if (nexthop->ifindex) { json_object_int_add(json_nexthop, "interfaceIndex", @@ -1247,7 +1250,8 @@ void nexthop_json_helper(json_object *json_nexthop, case NEXTHOP_TYPE_IPV6_IFINDEX: json_object_string_addf(json_nexthop, "ip", "%pI6", &nexthop->gate.ipv6); - json_object_string_add(json_nexthop, "afi", "ipv6"); + if (!brief) + json_object_string_add(json_nexthop, "afi", "ipv6"); if (nexthop->ifindex) { json_object_int_add(json_nexthop, "interfaceIndex", @@ -1259,7 +1263,8 @@ void nexthop_json_helper(json_object *json_nexthop, break; case NEXTHOP_TYPE_IFINDEX: - json_object_boolean_true_add(json_nexthop, "directlyConnected"); + if (!brief) + json_object_boolean_true_add(json_nexthop, "directlyConnected"); json_object_int_add(json_nexthop, "interfaceIndex", nexthop->ifindex); json_object_string_add(json_nexthop, "interfaceName", @@ -1267,24 +1272,32 @@ void nexthop_json_helper(json_object *json_nexthop, nexthop->vrf_id)); break; case NEXTHOP_TYPE_BLACKHOLE: - json_object_boolean_true_add(json_nexthop, "unreachable"); - switch (nexthop->bh_type) { - case BLACKHOLE_REJECT: - json_object_boolean_true_add(json_nexthop, "reject"); - break; - case BLACKHOLE_ADMINPROHIB: - json_object_boolean_true_add(json_nexthop, + if (!brief) { + json_object_boolean_true_add(json_nexthop, "unreachable"); + switch (nexthop->bh_type) { + case BLACKHOLE_REJECT: + json_object_boolean_true_add(json_nexthop, "reject"); + break; + case BLACKHOLE_ADMINPROHIB: + json_object_boolean_true_add(json_nexthop, "adminProhibited"); - break; - case BLACKHOLE_NULL: - json_object_boolean_true_add(json_nexthop, "blackhole"); - break; - case BLACKHOLE_UNSPEC: - break; + break; + case BLACKHOLE_NULL: + json_object_boolean_true_add(json_nexthop, "blackhole"); + break; + case BLACKHOLE_UNSPEC: + break; + } } break; } + if (display_vrfid) + json_object_string_add(json_nexthop, "vrf", + vrf_id_to_name(nexthop->vrf_id)); + if (brief) + return; + /* This nexthop is a resolver for the parent nexthop. * Set resolver flag for better clarity and delimiter * in flat list of nexthops in json. @@ -1292,9 +1305,6 @@ void nexthop_json_helper(json_object *json_nexthop, if (nexthop->rparent) json_object_boolean_true_add(json_nexthop, "resolver"); - if (display_vrfid) - json_object_string_add(json_nexthop, "vrf", - vrf_id_to_name(nexthop->vrf_id)); if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)) json_object_boolean_true_add(json_nexthop, "duplicate"); diff --git a/lib/nexthop.h b/lib/nexthop.h index 5dfb58d84661..5bd38cd1f54a 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -260,7 +260,7 @@ int nexthop_str2backups(const char *str, int *num_backups, void nexthop_json_helper(json_object *json_nexthop, const struct nexthop *nexthop, bool display_vrfid, - uint8_t rn_family); + uint8_t rn_family, bool brief); void nexthop_vty_helper(struct vty *vty, const struct nexthop *nexthop, bool display_vrfid, uint8_t rn_family); diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 640e6551a774..e244843f8ea0 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -1266,7 +1266,7 @@ int zebra_send_rnh_update(struct rnh *rnh, struct zserv *client, void show_nexthop_json_helper(json_object *json_nexthop, const struct nexthop *nexthop, const struct route_node *rn, - const struct route_entry *re) + const struct route_entry *re, bool brief) { bool display_vrfid = false; uint8_t rn_family; @@ -1279,7 +1279,7 @@ void show_nexthop_json_helper(json_object *json_nexthop, else rn_family = AF_UNSPEC; - nexthop_json_helper(json_nexthop, nexthop, display_vrfid, rn_family); + nexthop_json_helper(json_nexthop, nexthop, display_vrfid, rn_family, brief); } /* @@ -1362,7 +1362,7 @@ static void print_rnh(struct route_node *rn, struct vty *vty, json_object *json) json_object_array_add(json_nexthop_array, json_nexthop); show_nexthop_json_helper(json_nexthop, nexthop, - rn, NULL); + rn, NULL, false); } else { show_route_nexthop_helper(vty, rn, NULL, nexthop); diff --git a/zebra/zebra_rnh.h b/zebra/zebra_rnh.h index f0b10d825c84..b2fbe881abe3 100644 --- a/zebra/zebra_rnh.h +++ b/zebra/zebra_rnh.h @@ -46,7 +46,7 @@ bool rnh_get_hide_backups(void); void show_nexthop_json_helper(json_object *json_nexthop, const struct nexthop *nexthop, const struct route_node *rn, - const struct route_entry *re); + const struct route_entry *re, bool brief); void show_route_nexthop_helper(struct vty *vty, const struct route_node *rn, const struct route_entry *re, const struct nexthop *nexthop); diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index b65097e725b4..e8986b85a4df 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -706,7 +706,8 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, for (ALL_NEXTHOPS_PTR(nhg, nexthop)) { json_nexthop = json_object_new_object(); - show_nexthop_json_helper(json_nexthop, nexthop, rn, re); + show_nexthop_json_helper(json_nexthop, nexthop, rn, re, + false); json_object_array_add(json_nexthops, json_nexthop); @@ -727,7 +728,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, json_nexthop = json_object_new_object(); show_nexthop_json_helper(json_nexthop, nexthop, - rn, re); + rn, re, false); json_object_array_add(json_nexthops, json_nexthop); } @@ -1174,7 +1175,7 @@ DEFPY (show_ip_nht, } static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe, - json_object *json_nhe_hdr) + json_object *json_nhe_hdr, bool brief) { struct nexthop *nexthop = NULL; struct nhg_connected *rb_node_dep = NULL; @@ -1196,19 +1197,21 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe, json = json_object_new_object(); if (json) { - json_object_string_add(json, "type", + if (!brief) { + json_object_string_add(json, "type", zebra_route_string(nhe->type)); - json_object_int_add(json, "refCount", nhe->refcnt); - if (event_is_scheduled(nhe->timer)) - json_object_string_add( - json, "timeToDeletion", - event_timer_to_hhmmss(time_left, - sizeof(time_left), - nhe->timer)); + json_object_int_add(json, "refCount", nhe->refcnt); + if (event_is_scheduled(nhe->timer)) + json_object_string_add( + json, "timeToDeletion", + event_timer_to_hhmmss(time_left, + sizeof(time_left), + nhe->timer)); + json_object_string_add(json, "afi", afi2str(nhe->afi)); + } json_object_string_add(json, "uptime", up_str); json_object_string_add(json, "vrf", vrf_id_to_name(nhe->vrf_id)); - json_object_string_add(json, "afi", afi2str(nhe->afi)); } else { vty_out(vty, "ID: %u (%s)\n", nhe->id, @@ -1290,8 +1293,14 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe, for (ALL_NEXTHOPS(nhe->nhg, nexthop)) { if (json_nexthop_array) { json_nexthops = json_object_new_object(); - show_nexthop_json_helper(json_nexthops, nexthop, NULL, - NULL); + if (brief) { + if (zebra_nhg_dependents_is_empty(nhe)) + show_nexthop_json_helper(json_nexthops, + nexthop, NULL, NULL, brief); + } else { + show_nexthop_json_helper(json_nexthops, nexthop, + NULL, NULL, false); + } } else { if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) vty_out(vty, " "); @@ -1341,8 +1350,18 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe, } } - if (json) + if (json) { + if (brief) { + if (zebra_nhg_dependents_is_empty(nhe)) + json_object_object_add(json, "nexthops", + json_nexthop_array); + if (json_nhe_hdr) + json_object_object_addf(json_nhe_hdr, json, + "%u", nhe->id); + return; + } json_object_object_add(json, "nexthops", json_nexthop_array); + } /* Output backup nexthops (if any) */ backup_nhg = zebra_nhg_get_backup_nhg(nhe); @@ -1356,7 +1375,7 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe, if (json_backup_nexthop_array) { json_backup_nexthops = json_object_new_object(); show_nexthop_json_helper(json_backup_nexthops, - nexthop, NULL, NULL); + nexthop, NULL, NULL, false); json_object_array_add(json_backup_nexthop_array, json_backup_nexthops); } else { @@ -1427,14 +1446,14 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe, } static int show_nexthop_group_id_cmd_helper(struct vty *vty, uint32_t id, - json_object *json) + json_object *json, bool brief) { struct nhg_hash_entry *nhe = NULL; nhe = zebra_nhg_lookup_id(id); if (nhe) - show_nexthop_group_out(vty, nhe, json); + show_nexthop_group_out(vty, nhe, json, brief); else { if (json) vty_json(vty, json); @@ -1458,6 +1477,7 @@ struct nhe_show_context { afi_t afi; int type; json_object *json; + bool brief; }; static int nhe_show_walker(struct hash_bucket *bucket, void *arg) @@ -1476,7 +1496,7 @@ static int nhe_show_walker(struct hash_bucket *bucket, void *arg) if (ctx->type && nhe->type != ctx->type) goto done; - show_nexthop_group_out(ctx->vty, nhe, ctx->json); + show_nexthop_group_out(ctx->vty, nhe, ctx->json, ctx->brief); done: return HASHWALK_CONTINUE; @@ -1484,7 +1504,8 @@ static int nhe_show_walker(struct hash_bucket *bucket, void *arg) static void show_nexthop_group_cmd_helper(struct vty *vty, struct zebra_vrf *zvrf, afi_t afi, - int type, json_object *json) + int type, json_object *json, + bool brief) { struct nhe_show_context ctx; @@ -1493,6 +1514,7 @@ static void show_nexthop_group_cmd_helper(struct vty *vty, ctx.vrf_id = zvrf->vrf->vrf_id; ctx.type = type; ctx.json = json; + ctx.brief = brief; hash_walk(zrouter.nhgs_id, nhe_show_walker, &ctx); } @@ -1512,7 +1534,8 @@ static void if_nexthop_group_dump_vty(struct vty *vty, struct interface *ifp) } vty_out(vty, " "); - show_nexthop_group_out(vty, rb_node_dep->nhe, NULL); + show_nexthop_group_out(vty, rb_node_dep->nhe, NULL, + false); } } @@ -1552,7 +1575,7 @@ DEFPY (show_interface_nexthop_group, DEFPY(show_nexthop_group, show_nexthop_group_cmd, - "show nexthop-group rib <(0-4294967295)$id|[singleton ] [$type_str] [vrf ]> [json]", + "show nexthop-group rib <(0-4294967295)$id|[singleton ] [$type_str] [vrf ]> [] [json]", SHOW_STR "Show Nexthop Groups\n" "RIB information\n" @@ -1565,6 +1588,7 @@ DEFPY(show_nexthop_group, "Border Gateway Protocol (BGP)\n" "Super Happy Advanced Routing Protocol (SHARP)\n" VRF_FULL_CMD_HELP_STR + "Brief\n" JSON_STR) { @@ -1579,7 +1603,7 @@ DEFPY(show_nexthop_group, json = json_object_new_object(); if (id) - return show_nexthop_group_id_cmd_helper(vty, id, json); + return show_nexthop_group_id_cmd_helper(vty, id, json, brief); if (v4) afi = AFI_IP; @@ -1618,7 +1642,7 @@ DEFPY(show_nexthop_group, vty_out(vty, "VRF: %s\n", vrf->name); show_nexthop_group_cmd_helper(vty, zvrf, afi, type, - json_vrf); + json_vrf, brief); if (uj) json_object_object_add(json, vrf->name, json_vrf); @@ -1644,10 +1668,14 @@ DEFPY(show_nexthop_group, return CMD_WARNING; } - show_nexthop_group_cmd_helper(vty, zvrf, afi, type, json); + show_nexthop_group_cmd_helper(vty, zvrf, afi, type, json, brief); - if (uj) - vty_json(vty, json); + if (uj) { + if (brief) + vty_json_no_pretty(vty, json); + else + vty_json(vty, json); + } return CMD_SUCCESS; } From aa12b804a3ac475ad6e6904351ab5e5ddd5c5838 Mon Sep 17 00:00:00 2001 From: vivek Date: Mon, 10 Jan 2022 21:12:55 -0800 Subject: [PATCH 005/106] zebra: Define a local MAC cache for EVPN Define a MAC cache to store local MACs upon notification from the kernel. Signed-off-by: Vivek Venkatraman --- zebra/zebra_l2.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/zebra/zebra_l2.h b/zebra/zebra_l2.h index ad5f5eeee008..290662fe10fc 100644 --- a/zebra/zebra_l2.h +++ b/zebra/zebra_l2.h @@ -38,6 +38,13 @@ struct zebra_l2_bridge_vlan { struct zebra_evpn_access_bd *access_bd; }; +struct zebra_l2_brvlan_mac { + struct interface *br_if; + vlanid_t vid; + struct ethaddr macaddr; + ifindex_t ifindex; +}; + struct zebra_l2_bridge_if_ctx { /* input */ struct zebra_if *zif; @@ -48,10 +55,22 @@ struct zebra_l2_bridge_if_ctx { void *arg; }; +struct zebra_l2_brvlan_mac_ctx { + /* input */ + struct interface *br_if; + vlanid_t vid; + int (*func)(struct interface *br_if, vlanid_t vid, + struct ethaddr *macaddr, ifindex_t ifidx, void *arg); + + /* input-output */ + void *arg; +}; + struct zebra_l2_bridge_if { uint8_t vlan_aware; struct zebra_if *br_zif; struct hash *vlan_table; + struct hash *mac_table[VLANID_MAX]; }; /* zebra L2 interface information - bridge interface */ From c5488c9e9ad450bf41b33b918ed09f78a31c359d Mon Sep 17 00:00:00 2001 From: vivek Date: Mon, 10 Jan 2022 21:54:30 -0800 Subject: [PATCH 006/106] zebra: Display local MAC cache Add vtysh handler and backend function to display the local MAC cache. Signed-off-by: Vivek Venkatraman --- zebra/zebra_l2_bridge_if.c | 57 ++++++++++++++++++++++++++++++++++++++ zebra/zebra_l2_bridge_if.h | 2 ++ zebra/zebra_vty.c | 35 +++++++++++++++++++++++ 3 files changed, 94 insertions(+) diff --git a/zebra/zebra_l2_bridge_if.c b/zebra/zebra_l2_bridge_if.c index 00450ddd36a0..cbd6f4d87792 100644 --- a/zebra/zebra_l2_bridge_if.c +++ b/zebra/zebra_l2_bridge_if.c @@ -55,6 +55,27 @@ #include "zebra/zebra_evpn_vxlan.h" #include "zebra/zebra_router.h" +static void zebra_l2_brvlan_print_mac_hash(struct hash_bucket *bucket, + void *ctxt) +{ + struct zebra_l2_brvlan_mac_ctx *ctx; + struct vty *vty; + struct zebra_l2_brvlan_mac *bmac; + char buf[ETHER_ADDR_STRLEN]; + struct interface *ifp; + + ctx = (struct zebra_l2_brvlan_mac_ctx *)ctxt; + vty = (struct vty *)(ctx->arg); + bmac = (struct zebra_l2_brvlan_mac *)bucket->data; + + prefix_mac2str(&bmac->macaddr, buf, sizeof(buf)); + ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT), + bmac->ifindex); + + vty_out(vty, "%-17s %-7u %s\n", buf, bmac->ifindex, + ifp ? ifp->name : "-"); +} + static unsigned int zebra_l2_bridge_vlan_hash_keymake(const void *p) { const struct zebra_l2_bridge_vlan *bvlan; @@ -63,6 +84,42 @@ static unsigned int zebra_l2_bridge_vlan_hash_keymake(const void *p) return jhash(&bvlan->vid, sizeof(bvlan->vid), 0); } +void zebra_l2_brvlan_print_macs(struct vty *vty, struct interface *br_if, + vlanid_t vid, bool uj) +{ + struct zebra_if *zif; + struct zebra_l2_bridge_if *br; + uint32_t num_macs; + struct zebra_l2_brvlan_mac_ctx ctx; + + zif = (struct zebra_if *)br_if->info; + br = BRIDGE_FROM_ZEBRA_IF(zif); + if (!br) { + return; + } + if (!br->mac_table[vid]) { + vty_out(vty, + "%% bridge %s VID %u does not have a MAC hash table\n", + br_if->name, vid); + return; + } + num_macs = hashcount(br->mac_table[vid]); + if (!num_macs) { + vty_out(vty, "bridge %s VID %u - No local MACs\n", br_if->name, + vid); + return; + } + + vty_out(vty, "bridge %s VID %u - Number of local MACs: %u\n", + br_if->name, vid, num_macs); + vty_out(vty, "%-17s %-7s %-30s\n", "MAC", "IfIndex", "Interface"); + memset(&ctx, 0, sizeof(ctx)); + ctx.br_if = br_if; + ctx.vid = vid; + ctx.arg = vty; + hash_iterate(br->mac_table[vid], zebra_l2_brvlan_print_mac_hash, &ctx); +} + static bool zebra_l2_bridge_vlan_hash_cmp(const void *p1, const void *p2) { const struct zebra_l2_bridge_vlan *bv1; diff --git a/zebra/zebra_l2_bridge_if.h b/zebra/zebra_l2_bridge_if.h index 734ecfdcf119..00041ad13dd9 100644 --- a/zebra/zebra_l2_bridge_if.h +++ b/zebra/zebra_l2_bridge_if.h @@ -64,6 +64,8 @@ extern int zebra_l2_bridge_if_vlan_access_bd_deref(struct zebra_evpn_access_bd *bd); extern int zebra_l2_bridge_if_vlan_access_bd_ref(struct zebra_evpn_access_bd *bd); +extern void zebra_l2_brvlan_print_macs(struct vty *vty, struct interface *br_if, + vlanid_t vid, bool uj); extern int zebra_l2_bridge_if_del(struct interface *ifp); extern int zebra_l2_bridge_if_add(struct interface *ifp); extern int zebra_l2_bridge_if_cleanup(struct interface *ifp); diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index e8986b85a4df..372b27084e2f 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -3514,6 +3514,40 @@ DEFUN (show_evpn_neigh_vni_vtep, return CMD_SUCCESS; } +DEFPY(show_evpn_local_mac, show_evpn_local_mac_cmd, + "show evpn local-mac IFNAME$if_name (1-4094)$vid [json$json]", + SHOW_STR + "EVPN\n" + "Local MAC addresses\n" + "Interface Name\n" + "VLAN ID\n" JSON_STR) +{ + struct vrf *vrf = NULL; + struct interface *ifp = NULL; + bool found = false; + bool uj = use_json(argc, argv); + + if (!if_name || !vid) { + return CMD_WARNING; + } + + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + ifp = if_lookup_by_name(if_name, vrf->vrf_id); + if (ifp) { + found = true; + break; + } + } + + if (!found) { + vty_out(vty, "%% Can't find interface %s\n", if_name); + return CMD_WARNING; + } + + zebra_l2_brvlan_print_macs(vty, ifp, vid, uj); + return CMD_SUCCESS; +} + /* policy routing contexts */ DEFUN (show_pbr_ipset, show_pbr_ipset_cmd, @@ -4448,6 +4482,7 @@ void zebra_vty_init(void) install_element(VIEW_NODE, &show_evpn_neigh_vni_vtep_cmd); install_element(VIEW_NODE, &show_evpn_neigh_vni_dad_cmd); install_element(VIEW_NODE, &show_evpn_neigh_vni_all_dad_cmd); + install_element(VIEW_NODE, &show_evpn_local_mac_cmd); install_element(ENABLE_NODE, &clear_evpn_dup_addr_cmd); install_element(CONFIG_NODE, &evpn_accept_bgp_seq_cmd); install_element(CONFIG_NODE, &no_evpn_accept_bgp_seq_cmd); From 5f458b338c8228e61fac6c575fa324fc20080b2b Mon Sep 17 00:00:00 2001 From: Ashwini Reddy Date: Wed, 23 Feb 2022 14:02:08 -0800 Subject: [PATCH 007/106] zebra: json support Added json support for 'show evpn local-mac intf vlan.' Signed-off-by: Ashwini Reddy --- zebra/zebra_l2.h | 1 + zebra/zebra_l2_bridge_if.c | 126 +++++++++++++++++++++++-------------- 2 files changed, 80 insertions(+), 47 deletions(-) diff --git a/zebra/zebra_l2.h b/zebra/zebra_l2.h index 290662fe10fc..0f906f0018a1 100644 --- a/zebra/zebra_l2.h +++ b/zebra/zebra_l2.h @@ -64,6 +64,7 @@ struct zebra_l2_brvlan_mac_ctx { /* input-output */ void *arg; + struct json_object *json; /* Used for JSON Output */ }; struct zebra_l2_bridge_if { diff --git a/zebra/zebra_l2_bridge_if.c b/zebra/zebra_l2_bridge_if.c index cbd6f4d87792..bcb162fc40dc 100644 --- a/zebra/zebra_l2_bridge_if.c +++ b/zebra/zebra_l2_bridge_if.c @@ -58,22 +58,32 @@ static void zebra_l2_brvlan_print_mac_hash(struct hash_bucket *bucket, void *ctxt) { - struct zebra_l2_brvlan_mac_ctx *ctx; - struct vty *vty; - struct zebra_l2_brvlan_mac *bmac; - char buf[ETHER_ADDR_STRLEN]; - struct interface *ifp; - - ctx = (struct zebra_l2_brvlan_mac_ctx *)ctxt; - vty = (struct vty *)(ctx->arg); - bmac = (struct zebra_l2_brvlan_mac *)bucket->data; - - prefix_mac2str(&bmac->macaddr, buf, sizeof(buf)); - ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT), - bmac->ifindex); - - vty_out(vty, "%-17s %-7u %s\n", buf, bmac->ifindex, - ifp ? ifp->name : "-"); + struct zebra_l2_brvlan_mac_ctx *ctx; + struct vty *vty; + struct zebra_l2_brvlan_mac *bmac; + json_object *json_obj = NULL, *json_mac = NULL; + char mac[ETHER_ADDR_STRLEN]; + struct interface *ifp; + + ctx = (struct zebra_l2_brvlan_mac_ctx *)ctxt; + vty = (struct vty *)(ctx->arg); + bmac = (struct zebra_l2_brvlan_mac *)bucket->data; + json_obj = ctx->json; + + prefix_mac2str(&bmac->macaddr, mac, sizeof(mac)); + ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT), + bmac->ifindex); + + if (json_obj) { + json_mac = json_object_new_object(); + json_object_int_add(json_mac, "IfIndex", bmac->ifindex); + json_object_string_add(json_mac, "Interface", + ifp ? ifp->name : "-"); + json_object_object_add(json_obj, mac, json_mac); + } else { + vty_out(vty, "%-17s %-7u %s\n", mac, bmac->ifindex, + ifp ? ifp->name : "-"); + } } static unsigned int zebra_l2_bridge_vlan_hash_keymake(const void *p) @@ -87,37 +97,59 @@ static unsigned int zebra_l2_bridge_vlan_hash_keymake(const void *p) void zebra_l2_brvlan_print_macs(struct vty *vty, struct interface *br_if, vlanid_t vid, bool uj) { - struct zebra_if *zif; - struct zebra_l2_bridge_if *br; - uint32_t num_macs; - struct zebra_l2_brvlan_mac_ctx ctx; - - zif = (struct zebra_if *)br_if->info; - br = BRIDGE_FROM_ZEBRA_IF(zif); - if (!br) { - return; - } - if (!br->mac_table[vid]) { - vty_out(vty, - "%% bridge %s VID %u does not have a MAC hash table\n", - br_if->name, vid); - return; - } - num_macs = hashcount(br->mac_table[vid]); - if (!num_macs) { - vty_out(vty, "bridge %s VID %u - No local MACs\n", br_if->name, - vid); - return; - } - - vty_out(vty, "bridge %s VID %u - Number of local MACs: %u\n", - br_if->name, vid, num_macs); - vty_out(vty, "%-17s %-7s %-30s\n", "MAC", "IfIndex", "Interface"); - memset(&ctx, 0, sizeof(ctx)); - ctx.br_if = br_if; - ctx.vid = vid; - ctx.arg = vty; - hash_iterate(br->mac_table[vid], zebra_l2_brvlan_print_mac_hash, &ctx); + struct zebra_if *zif; + struct zebra_l2_bridge_if *br; + uint32_t num_macs; + struct zebra_l2_brvlan_mac_ctx ctx; + + zif = (struct zebra_if *)br_if->info; + br = BRIDGE_FROM_ZEBRA_IF(zif); + if (!br) { + return; + } + json_object *json_obj = NULL, *json_mac_obj = NULL; + if (uj) { /* json format */ + json_obj = json_object_new_object(); + json_mac_obj = json_object_new_object(); + } + + if (!br->mac_table[vid]) { + vty_out(vty, + "%% bridge %s VID %u does not have a MAC hash table\n", + br_if->name, vid); + return; + } + num_macs = hashcount(br->mac_table[vid]); + if (!num_macs) { + vty_out(vty, "bridge %s VID %u - No local MACs\n", br_if->name, + vid); + return; + } + + if (uj) { + json_object_string_add(json_obj, "bridge", br_if->name); + json_object_int_add(json_obj, "VID", vid); + json_object_int_add(json_obj, "number of local MACS", num_macs); + } else { + vty_out(vty, "bridge %s VID %u - Number of local MACs: %u\n", + br_if->name, vid, num_macs); + vty_out(vty, "%-17s %-7s %-30s\n", "MAC", "IfIndex", + "Interface"); + } + memset(&ctx, 0, sizeof(ctx)); + ctx.br_if = br_if; + ctx.vid = vid; + ctx.arg = vty; + ctx.json = json_mac_obj; + hash_iterate(br->mac_table[vid], zebra_l2_brvlan_print_mac_hash, &ctx); + if (uj) { + json_object_object_add(json_obj, "MAC", json_mac_obj); + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json_obj, JSON_C_TO_STRING_PRETTY)); + json_object_free(json_obj); + } + } static bool zebra_l2_bridge_vlan_hash_cmp(const void *p1, const void *p2) From 7b1ac8bbb93ca15100affb598283dda94f19167a Mon Sep 17 00:00:00 2001 From: Sougata Date: Wed, 4 Dec 2024 10:39:35 +0530 Subject: [PATCH 008/106] zebra: static analyzer reported issue fixes Signed-off-by: Sougata --- lib/nexthop.c | 4 ++-- zebra/zebra_evpn.c | 2 +- zebra/zebra_l2_bridge_if.c | 13 ++++++------- zebra/zebra_l2_bridge_if.h | 4 ++-- zebra/zebra_vty.c | 5 ++--- 5 files changed, 13 insertions(+), 15 deletions(-) diff --git a/lib/nexthop.c b/lib/nexthop.c index 379cf3581883..808a74066b93 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -1223,7 +1223,7 @@ void nexthop_json_helper(json_object *json_nexthop, if (!brief) { json_object_int_add(json_nexthop, "flags", nexthop->flags); - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)) + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)) json_object_boolean_true_add(json_nexthop, "duplicate"); if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) @@ -1295,7 +1295,7 @@ void nexthop_json_helper(json_object *json_nexthop, if (display_vrfid) json_object_string_add(json_nexthop, "vrf", vrf_id_to_name(nexthop->vrf_id)); - if (brief) + if (brief) return; /* This nexthop is a resolver for the parent nexthop. diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c index b92922d22d1e..494978f6ef4a 100644 --- a/zebra/zebra_evpn.c +++ b/zebra/zebra_evpn.c @@ -111,7 +111,7 @@ void zebra_evpn_print(struct zebra_evpn *zevpn, void **ctxt) json_object_string_add(json, "type", "L2"); json_object_int_add(json, "vlan", zevpn->vid); json_object_string_add(json, "bridge", - zevpn->bridge_if ? zevpn->bridge_if->name: ""); + zevpn->bridge_if ? zevpn->bridge_if->name : ""); json_object_string_add(json, "tenantVrf", vrf_id_to_name(zevpn->vrf_id)); } diff --git a/zebra/zebra_l2_bridge_if.c b/zebra/zebra_l2_bridge_if.c index bcb162fc40dc..e2c9807cbbc6 100644 --- a/zebra/zebra_l2_bridge_if.c +++ b/zebra/zebra_l2_bridge_if.c @@ -55,8 +55,7 @@ #include "zebra/zebra_evpn_vxlan.h" #include "zebra/zebra_router.h" -static void zebra_l2_brvlan_print_mac_hash(struct hash_bucket *bucket, - void *ctxt) +static void zebra_l2_brvlan_print_mac_hash(struct hash_bucket *bucket, void *ctxt) { struct zebra_l2_brvlan_mac_ctx *ctx; struct vty *vty; @@ -94,8 +93,7 @@ static unsigned int zebra_l2_bridge_vlan_hash_keymake(const void *p) return jhash(&bvlan->vid, sizeof(bvlan->vid), 0); } -void zebra_l2_brvlan_print_macs(struct vty *vty, struct interface *br_if, - vlanid_t vid, bool uj) +void zebra_l2_brvlan_print_macs(struct vty *vty, struct interface *br_if, vlanid_t vid, bool uj) { struct zebra_if *zif; struct zebra_l2_bridge_if *br; @@ -104,10 +102,11 @@ void zebra_l2_brvlan_print_macs(struct vty *vty, struct interface *br_if, zif = (struct zebra_if *)br_if->info; br = BRIDGE_FROM_ZEBRA_IF(zif); - if (!br) { - return; - } + if (!br) + return; + json_object *json_obj = NULL, *json_mac_obj = NULL; + if (uj) { /* json format */ json_obj = json_object_new_object(); json_mac_obj = json_object_new_object(); diff --git a/zebra/zebra_l2_bridge_if.h b/zebra/zebra_l2_bridge_if.h index 00041ad13dd9..0d0aa76349f8 100644 --- a/zebra/zebra_l2_bridge_if.h +++ b/zebra/zebra_l2_bridge_if.h @@ -64,8 +64,8 @@ extern int zebra_l2_bridge_if_vlan_access_bd_deref(struct zebra_evpn_access_bd *bd); extern int zebra_l2_bridge_if_vlan_access_bd_ref(struct zebra_evpn_access_bd *bd); -extern void zebra_l2_brvlan_print_macs(struct vty *vty, struct interface *br_if, - vlanid_t vid, bool uj); +extern void zebra_l2_brvlan_print_macs(struct vty *vty, struct interface *br_if, vlanid_t vid, + bool uj); extern int zebra_l2_bridge_if_del(struct interface *ifp); extern int zebra_l2_bridge_if_add(struct interface *ifp); extern int zebra_l2_bridge_if_cleanup(struct interface *ifp); diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 372b27084e2f..d4a88901a219 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1675,7 +1675,7 @@ DEFPY(show_nexthop_group, vty_json_no_pretty(vty, json); else vty_json(vty, json); - } + } return CMD_SUCCESS; } @@ -3527,9 +3527,8 @@ DEFPY(show_evpn_local_mac, show_evpn_local_mac_cmd, bool found = false; bool uj = use_json(argc, argv); - if (!if_name || !vid) { + if (!if_name || !vid) return CMD_WARNING; - } RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { ifp = if_lookup_by_name(if_name, vrf->vrf_id); From 5dde8e150c15b742aba44b29e36d590237f8e660 Mon Sep 17 00:00:00 2001 From: famfo Date: Tue, 26 Nov 2024 19:42:03 +0100 Subject: [PATCH 009/106] topotests: Allow runing under both docker and podman Signed-off-by: famfo --- tests/topotests/docker/build.sh | 4 ++-- tests/topotests/docker/frr-topotests.sh | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/topotests/docker/build.sh b/tests/topotests/docker/build.sh index aec20587ba39..20d08e4979f2 100755 --- a/tests/topotests/docker/build.sh +++ b/tests/topotests/docker/build.sh @@ -1,11 +1,11 @@ -#!/bin/bash +#!/usr/bin/env bash # SPDX-License-Identifier: MIT # # Copyright 2018 Network Device Education Foundation, Inc. ("NetDEF") cd "$(dirname "$0")"/.. -exec docker build --pull \ +exec $(command -v docker || command -v podman) build --pull \ --compress \ -t frrouting/topotests:latest \ . diff --git a/tests/topotests/docker/frr-topotests.sh b/tests/topotests/docker/frr-topotests.sh index bd37055147a7..8de8e7b1f676 100755 --- a/tests/topotests/docker/frr-topotests.sh +++ b/tests/topotests/docker/frr-topotests.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # SPDX-License-Identifier: MIT # # Copyright 2018 Network Device Education Foundation, Inc. ("NetDEF") @@ -113,10 +113,12 @@ if [ -z "$TOPOTEST_FRR" ]; then git -C "$TOPOTEST_FRR" ls-files -z > "${TOPOTEST_LOGS}/git-ls-files" fi +cmd="$(command -v docker || command -v podman)" + if [ -z "$TOPOTEST_BUILDCACHE" ]; then TOPOTEST_BUILDCACHE=topotest-buildcache - docker volume inspect "${TOPOTEST_BUILDCACHE}" &> /dev/null \ - || docker volume create "${TOPOTEST_BUILDCACHE}" + "${cmd}" volume inspect "${TOPOTEST_BUILDCACHE}" &> /dev/null \ + || "${cmd}" volume create "${TOPOTEST_BUILDCACHE}" fi if [[ -n "$TMUX" ]]; then @@ -145,4 +147,4 @@ if [ -t 0 ]; then set -- -t "$@" fi -exec docker run "$@" +exec "${cmd}" run "$@" From e7eb1a19a03f3bee7c5e6082a5f7c9f452e540de Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 25 Oct 2024 22:06:11 +0200 Subject: [PATCH 010/106] topotests: bmp, create shared library for bmp The bgp_bmp and bgp_bmp_vrf tests use similar routines to test the bmp, but are duplicates. Gather the bgp_bmp and the bgp_bmp_vrf tests in a single bgp_bmp folder. - Create a bgpbmp.py library under the bgp_bmp test folder - The bgp_bmp and bgp_bmp_vrf test are renamed to bgp_bmp_1 and bgp_bmp_2 test. - Maintain separate folder for config and output results. Adapt the bgp_bmp library accordingly. - The json output for bgp_bmp_2 test has no referenc to hostame. Signed-off-by: Philippe Guibert --- tests/topotests/bgp_bmp/bgpbmp.py | 214 ++++++++ .../bmp1vrf}/bmp-update-loc-rib-step1.json | 0 .../bmp-update-post-policy-step1.json | 0 .../bmp1vrf}/bmp-update-pre-policy-step1.json | 0 .../bmp1vrf}/bmp-withdraw-loc-rib-step1.json | 0 .../bmp-withdraw-post-policy-step1.json | 0 .../bmp-withdraw-pre-policy-step1.json | 0 .../r1 => bgp_bmp/r1vrf}/bgpd.conf | 0 .../r1vrf}/show-bgp-ipv4-update-step1.json | 1 - .../r1vrf}/show-bgp-ipv4-withdraw-step1.json | 0 .../r1vrf}/show-bgp-ipv6-update-step1.json | 2 - .../r1vrf}/show-bgp-ipv6-withdraw-step1.json | 0 .../r1 => bgp_bmp/r1vrf}/zebra.conf | 4 +- .../r2 => bgp_bmp/r2vrf}/bgpd.conf | 0 .../r2 => bgp_bmp/r2vrf}/zebra.conf | 4 +- tests/topotests/bgp_bmp/test_bgp_bmp.py | 476 ------------------ tests/topotests/bgp_bmp/test_bgp_bmp_1.py | 260 ++++++++++ tests/topotests/bgp_bmp/test_bgp_bmp_2.py | 258 ++++++++++ tests/topotests/bgp_bmp_vrf/__init__.py | 0 .../topotests/bgp_bmp_vrf/test_bgp_bmp_vrf.py | 418 --------------- tests/topotests/lib/bgp.py | 19 + 21 files changed, 755 insertions(+), 901 deletions(-) create mode 100644 tests/topotests/bgp_bmp/bgpbmp.py rename tests/topotests/{bgp_bmp_vrf/bmp1 => bgp_bmp/bmp1vrf}/bmp-update-loc-rib-step1.json (100%) rename tests/topotests/{bgp_bmp_vrf/bmp1 => bgp_bmp/bmp1vrf}/bmp-update-post-policy-step1.json (100%) rename tests/topotests/{bgp_bmp_vrf/bmp1 => bgp_bmp/bmp1vrf}/bmp-update-pre-policy-step1.json (100%) rename tests/topotests/{bgp_bmp_vrf/bmp1 => bgp_bmp/bmp1vrf}/bmp-withdraw-loc-rib-step1.json (100%) rename tests/topotests/{bgp_bmp_vrf/bmp1 => bgp_bmp/bmp1vrf}/bmp-withdraw-post-policy-step1.json (100%) rename tests/topotests/{bgp_bmp_vrf/bmp1 => bgp_bmp/bmp1vrf}/bmp-withdraw-pre-policy-step1.json (100%) rename tests/topotests/{bgp_bmp_vrf/r1 => bgp_bmp/r1vrf}/bgpd.conf (100%) rename tests/topotests/{bgp_bmp_vrf/r1 => bgp_bmp/r1vrf}/show-bgp-ipv4-update-step1.json (91%) rename tests/topotests/{bgp_bmp_vrf/r1 => bgp_bmp/r1vrf}/show-bgp-ipv4-withdraw-step1.json (100%) rename tests/topotests/{bgp_bmp_vrf/r1 => bgp_bmp/r1vrf}/show-bgp-ipv6-update-step1.json (88%) rename tests/topotests/{bgp_bmp_vrf/r1 => bgp_bmp/r1vrf}/show-bgp-ipv6-withdraw-step1.json (100%) rename tests/topotests/{bgp_bmp_vrf/r1 => bgp_bmp/r1vrf}/zebra.conf (66%) rename tests/topotests/{bgp_bmp_vrf/r2 => bgp_bmp/r2vrf}/bgpd.conf (100%) rename tests/topotests/{bgp_bmp_vrf/r2 => bgp_bmp/r2vrf}/zebra.conf (72%) delete mode 100644 tests/topotests/bgp_bmp/test_bgp_bmp.py create mode 100644 tests/topotests/bgp_bmp/test_bgp_bmp_1.py create mode 100644 tests/topotests/bgp_bmp/test_bgp_bmp_2.py delete mode 100644 tests/topotests/bgp_bmp_vrf/__init__.py delete mode 100644 tests/topotests/bgp_bmp_vrf/test_bgp_bmp_vrf.py diff --git a/tests/topotests/bgp_bmp/bgpbmp.py b/tests/topotests/bgp_bmp/bgpbmp.py new file mode 100644 index 000000000000..950ffef2f71f --- /dev/null +++ b/tests/topotests/bgp_bmp/bgpbmp.py @@ -0,0 +1,214 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: GPL-2.0-or-later + +# Copyright 2023, 6wind +import json +import os + +from lib import topotest +from lib.topogen import get_topogen +from lib.topolog import logger + +# remember the last sequence number of the logging messages +SEQ = 0 + + +def bmp_reset_seq(): + global SEQ + SEQ = 0 + + +def get_bmp_messages(bmp_collector, bmp_log_file): + """ + Read the BMP logging messages. + """ + messages = [] + text_output = bmp_collector.run(f"cat {bmp_log_file}") + + for m in text_output.splitlines(): + # some output in the bash can break the message decoding + try: + messages.append(json.loads(m)) + except Exception as e: + logger.warning(str(e) + " message: {}".format(str(m))) + continue + + if not messages: + logger.error("Bad BMP log format, check your BMP server") + + return messages + + +def bmp_update_seq(bmp_collector, bmp_log_file): + global SEQ + + messages = get_bmp_messages(bmp_collector, bmp_log_file) + + if len(messages): + SEQ = messages[-1]["seq"] + + +def bmp_update_expected_files( + bmp_actual, expected_prefixes, bmp_log_type, policy, step, bmp_client +): + tgen = get_topogen() + + with open(f"/tmp/bmp-{bmp_log_type}-{policy}-step{step}.json", "w") as json_file: + json.dump(bmp_actual, json_file, indent=4) + + out = bmp_client.vtysh_cmd("show bgp vrf vrf1 ipv4 json", isjson=True) + filtered_out = { + "routes": { + prefix: route_info + for prefix, route_info in out["routes"].items() + if prefix in expected_prefixes + } + } + if bmp_log_type == "withdraw": + for pfx in expected_prefixes: + if "::" in pfx: + continue + filtered_out["routes"][pfx] = None + + # ls /tmp/show*json | while read file; do egrep -v 'prefix|network|metric|ocPrf|version|weight|peerId|vrf|Version|valid|Reason|fe80' $file >$(basename $file); echo >> $(basename $file); done + with open(f"/tmp/show-bgp-ipv4-{bmp_log_type}-step{step}.json", "w") as json_file: + json.dump(filtered_out, json_file, indent=4) + + out = tgen.gears["r1"].vtysh_cmd("show bgp vrf vrf1 ipv6 json", isjson=True) + filtered_out = { + "routes": { + prefix: route_info + for prefix, route_info in out["routes"].items() + if prefix in expected_prefixes + } + } + if bmp_log_type == "withdraw": + for pfx in expected_prefixes: + if "::" not in pfx: + continue + filtered_out["routes"][pfx] = None + + with open(f"/tmp/show-bgp-ipv6-{bmp_log_type}-step{step}.json", "w") as json_file: + json.dump(filtered_out, json_file, indent=4) + + +def bmp_check_for_prefixes( + expected_prefixes, + bmp_log_type, + policy, + step, + bmp_collector, + bmp_log_file, + bmp_client, + expected_json_path, + update_expected_json, + loc_rib, +): + """ + Check for the presence of the given prefixes in the BMP server logs with + the given message type and the set policy. + + """ + global SEQ + + # we care only about the new messages + messages = [ + m + for m in sorted( + get_bmp_messages(bmp_collector, bmp_log_file), key=lambda d: d["seq"] + ) + if m["seq"] > SEQ + ] + + # create empty initial files + # for step in $(seq 1); do + # for i in "update" "withdraw"; do + # for j in "pre-policy" "post-policy" "loc-rib"; do + # echo '{"null": {}}'> bmp-$i-$j-step$step.json + # done + # done + # done + + ref_file = f"{expected_json_path}/bmp-{bmp_log_type}-{policy}-step{step}.json" + expected = json.loads(open(ref_file).read()) + + # Build actual json from logs + actual = {} + for m in messages: + if ( + "bmp_log_type" in m.keys() + and "ip_prefix" in m.keys() + and m["ip_prefix"] in expected_prefixes + and m["bmp_log_type"] == bmp_log_type + and m["policy"] == policy + ): + policy_dict = actual.setdefault(m["policy"], {}) + bmp_log_type_dict = policy_dict.setdefault(m["bmp_log_type"], {}) + + # Add or update the ip_prefix dictionary with filtered key-value pairs + bmp_log_type_dict[m["ip_prefix"]] = { + k: v + for k, v in sorted(m.items()) + # filter out variable keys + if k not in ["timestamp", "seq", "nxhp_link-local"] + and ( + # When policy is loc-rib, the peer-distinguisher is 0:0 + # for the default VRF or the RD if any or the 0:. + # 0: is used to distinguished. RFC7854 says: "If the + # peer is a "Local Instance Peer", it is set to a unique, + # locally defined value." The value is not tested because it + # is variable. + k != "peer_distinguisher" + or policy != loc_rib + or v == "0:0" + or not v.startswith("0:") + ) + } + + # build expected JSON files + if ( + update_expected_json + and actual + and set(actual.get(policy, {}).get(bmp_log_type, {}).keys()) + == set(expected_prefixes) + ): + bmp_update_expected_files( + actual, expected_prefixes, bmp_log_type, policy, step, bmp_client + ) + + return topotest.json_cmp(actual, expected, exact=True) + + +def bmp_check_for_peer_message( + expected_peers, bmp_log_type, bmp_collector, bmp_log_file +): + """ + Check for the presence of a peer up message for the peer + """ + global SEQ + + # we care only about the new messages + messages = [ + m + for m in sorted( + get_bmp_messages(bmp_collector, bmp_log_file), key=lambda d: d["seq"] + ) + if m["seq"] > SEQ + ] + + # get the list of pairs (prefix, policy, seq) for the given message type + peers = [ + m["peer_ip"] + for m in messages + if "peer_ip" in m.keys() and m["bmp_log_type"] == bmp_log_type + ] + + # check for prefixes + for ep in expected_peers: + if ep not in peers: + msg = "The peer {} is not present in the {} log messages." + logger.debug(msg.format(ep, bmp_log_type)) + return False + + SEQ = messages[-1]["seq"] + return True diff --git a/tests/topotests/bgp_bmp_vrf/bmp1/bmp-update-loc-rib-step1.json b/tests/topotests/bgp_bmp/bmp1vrf/bmp-update-loc-rib-step1.json similarity index 100% rename from tests/topotests/bgp_bmp_vrf/bmp1/bmp-update-loc-rib-step1.json rename to tests/topotests/bgp_bmp/bmp1vrf/bmp-update-loc-rib-step1.json diff --git a/tests/topotests/bgp_bmp_vrf/bmp1/bmp-update-post-policy-step1.json b/tests/topotests/bgp_bmp/bmp1vrf/bmp-update-post-policy-step1.json similarity index 100% rename from tests/topotests/bgp_bmp_vrf/bmp1/bmp-update-post-policy-step1.json rename to tests/topotests/bgp_bmp/bmp1vrf/bmp-update-post-policy-step1.json diff --git a/tests/topotests/bgp_bmp_vrf/bmp1/bmp-update-pre-policy-step1.json b/tests/topotests/bgp_bmp/bmp1vrf/bmp-update-pre-policy-step1.json similarity index 100% rename from tests/topotests/bgp_bmp_vrf/bmp1/bmp-update-pre-policy-step1.json rename to tests/topotests/bgp_bmp/bmp1vrf/bmp-update-pre-policy-step1.json diff --git a/tests/topotests/bgp_bmp_vrf/bmp1/bmp-withdraw-loc-rib-step1.json b/tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-loc-rib-step1.json similarity index 100% rename from tests/topotests/bgp_bmp_vrf/bmp1/bmp-withdraw-loc-rib-step1.json rename to tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-loc-rib-step1.json diff --git a/tests/topotests/bgp_bmp_vrf/bmp1/bmp-withdraw-post-policy-step1.json b/tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-post-policy-step1.json similarity index 100% rename from tests/topotests/bgp_bmp_vrf/bmp1/bmp-withdraw-post-policy-step1.json rename to tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-post-policy-step1.json diff --git a/tests/topotests/bgp_bmp_vrf/bmp1/bmp-withdraw-pre-policy-step1.json b/tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-pre-policy-step1.json similarity index 100% rename from tests/topotests/bgp_bmp_vrf/bmp1/bmp-withdraw-pre-policy-step1.json rename to tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-pre-policy-step1.json diff --git a/tests/topotests/bgp_bmp_vrf/r1/bgpd.conf b/tests/topotests/bgp_bmp/r1vrf/bgpd.conf similarity index 100% rename from tests/topotests/bgp_bmp_vrf/r1/bgpd.conf rename to tests/topotests/bgp_bmp/r1vrf/bgpd.conf diff --git a/tests/topotests/bgp_bmp_vrf/r1/show-bgp-ipv4-update-step1.json b/tests/topotests/bgp_bmp/r1vrf/show-bgp-ipv4-update-step1.json similarity index 91% rename from tests/topotests/bgp_bmp_vrf/r1/show-bgp-ipv4-update-step1.json rename to tests/topotests/bgp_bmp/r1vrf/show-bgp-ipv4-update-step1.json index 038c87ca9dd0..dc0228db61f0 100644 --- a/tests/topotests/bgp_bmp_vrf/r1/show-bgp-ipv4-update-step1.json +++ b/tests/topotests/bgp_bmp/r1vrf/show-bgp-ipv4-update-step1.json @@ -9,7 +9,6 @@ "nexthops": [ { "ip": "192.168.0.2", - "hostname": "r2", "afi": "ipv4", "used": true } diff --git a/tests/topotests/bgp_bmp_vrf/r1/show-bgp-ipv4-withdraw-step1.json b/tests/topotests/bgp_bmp/r1vrf/show-bgp-ipv4-withdraw-step1.json similarity index 100% rename from tests/topotests/bgp_bmp_vrf/r1/show-bgp-ipv4-withdraw-step1.json rename to tests/topotests/bgp_bmp/r1vrf/show-bgp-ipv4-withdraw-step1.json diff --git a/tests/topotests/bgp_bmp_vrf/r1/show-bgp-ipv6-update-step1.json b/tests/topotests/bgp_bmp/r1vrf/show-bgp-ipv6-update-step1.json similarity index 88% rename from tests/topotests/bgp_bmp_vrf/r1/show-bgp-ipv6-update-step1.json rename to tests/topotests/bgp_bmp/r1vrf/show-bgp-ipv6-update-step1.json index db34220149e2..64c8622ab523 100644 --- a/tests/topotests/bgp_bmp_vrf/r1/show-bgp-ipv6-update-step1.json +++ b/tests/topotests/bgp_bmp/r1vrf/show-bgp-ipv6-update-step1.json @@ -9,12 +9,10 @@ "nexthops": [ { "ip": "192:168::2", - "hostname": "r2", "afi": "ipv6", "scope": "global" }, { - "hostname": "r2", "afi": "ipv6", "scope": "link-local", "used": true diff --git a/tests/topotests/bgp_bmp_vrf/r1/show-bgp-ipv6-withdraw-step1.json b/tests/topotests/bgp_bmp/r1vrf/show-bgp-ipv6-withdraw-step1.json similarity index 100% rename from tests/topotests/bgp_bmp_vrf/r1/show-bgp-ipv6-withdraw-step1.json rename to tests/topotests/bgp_bmp/r1vrf/show-bgp-ipv6-withdraw-step1.json diff --git a/tests/topotests/bgp_bmp_vrf/r1/zebra.conf b/tests/topotests/bgp_bmp/r1vrf/zebra.conf similarity index 66% rename from tests/topotests/bgp_bmp_vrf/r1/zebra.conf rename to tests/topotests/bgp_bmp/r1vrf/zebra.conf index 0b523c9e18d8..a242eadce8a7 100644 --- a/tests/topotests/bgp_bmp_vrf/r1/zebra.conf +++ b/tests/topotests/bgp_bmp/r1vrf/zebra.conf @@ -1,7 +1,7 @@ -interface r1-eth0 +interface r1vrf-eth0 ip address 192.0.2.1/24 ! -interface r1-eth1 +interface r1vrf-eth1 ip address 192.168.0.1/24 ipv6 address 192:168::1/64 ! diff --git a/tests/topotests/bgp_bmp_vrf/r2/bgpd.conf b/tests/topotests/bgp_bmp/r2vrf/bgpd.conf similarity index 100% rename from tests/topotests/bgp_bmp_vrf/r2/bgpd.conf rename to tests/topotests/bgp_bmp/r2vrf/bgpd.conf diff --git a/tests/topotests/bgp_bmp_vrf/r2/zebra.conf b/tests/topotests/bgp_bmp/r2vrf/zebra.conf similarity index 72% rename from tests/topotests/bgp_bmp_vrf/r2/zebra.conf rename to tests/topotests/bgp_bmp/r2vrf/zebra.conf index 9d82bfe2df5c..9a8da2d95fbd 100644 --- a/tests/topotests/bgp_bmp_vrf/r2/zebra.conf +++ b/tests/topotests/bgp_bmp/r2vrf/zebra.conf @@ -1,8 +1,8 @@ -interface r2-eth0 +interface r2vrf-eth0 ip address 192.168.0.2/24 ipv6 address 192:168::2/64 ! -interface r2-eth1 +interface r2vrf-eth1 ip address 172.31.0.2/24 ipv6 address 172:31::2/64 ! diff --git a/tests/topotests/bgp_bmp/test_bgp_bmp.py b/tests/topotests/bgp_bmp/test_bgp_bmp.py deleted file mode 100644 index 658ad2b99a2c..000000000000 --- a/tests/topotests/bgp_bmp/test_bgp_bmp.py +++ /dev/null @@ -1,476 +0,0 @@ -#!/usr/bin/env python -# SPDX-License-Identifier: ISC - -# Copyright 2023 6WIND S.A. -# Authored by Farid Mihoub -# - -""" -test_bgp_bmp.py: Test BGP BMP functionalities - - +------+ +------+ +------+ - | | | | | | - | BMP1 |------------| R1 |---------------| R2 | - | | | | | | - +------+ +------+ +------+ - -Setup two routers R1 and R2 with one link configured with IPv4 and -IPv6 addresses. -Configure BGP in R1 and R2 to exchange prefixes from -the latter to the first router. -Setup a link between R1 and the BMP server, activate the BMP feature in R1 -and ensure the monitored BGP sessions logs are well present on the BMP server. -""" - -from functools import partial -from ipaddress import ip_network -import json -import os -import pytest -import sys - -# Save the Current Working Directory to find configuration files. -CWD = os.path.dirname(os.path.realpath(__file__)) -sys.path.append(os.path.join("../")) -sys.path.append(os.path.join("../lib/")) - -# pylint: disable=C0413 -# Import topogen and topotest helpers -from lib import topotest -from lib.bgp import verify_bgp_convergence_from_running_config -from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger - -pytestmark = [pytest.mark.bgpd] - -# remember the last sequence number of the logging messages -SEQ = 0 - -PRE_POLICY = "pre-policy" -POST_POLICY = "post-policy" -LOC_RIB = "loc-rib" - -UPDATE_EXPECTED_JSON = False -DEBUG_PCAP = False - - -def build_topo(tgen): - tgen.add_router("r1") - tgen.add_router("r2") - tgen.add_bmp_server("bmp1", ip="192.0.2.10", defaultRoute="via 192.0.2.1") - - switch = tgen.add_switch("s1") - switch.add_link(tgen.gears["r1"]) - switch.add_link(tgen.gears["bmp1"]) - - tgen.add_link(tgen.gears["r1"], tgen.gears["r2"], "r1-eth1", "r2-eth0") - - -def setup_module(mod): - tgen = Topogen(build_topo, mod.__name__) - tgen.start_topology() - - if DEBUG_PCAP: - tgen.gears["r1"].run("rm /tmp/bmp.pcap") - tgen.gears["r1"].run( - "tcpdump -nni r1-eth0 -s 0 -w /tmp/bmp.pcap &", stdout=None - ) - - for rname, router in tgen.routers().items(): - router.load_config( - TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) - ) - router.load_config( - TopoRouter.RD_BGP, - os.path.join(CWD, "{}/bgpd.conf".format(rname)), - "-M bmp", - ) - - tgen.start_router() - - logger.info("starting BMP servers") - for bmp_name, server in tgen.get_bmp_servers().items(): - server.start(log_file=os.path.join(tgen.logdir, bmp_name, "bmp.log")) - - -def teardown_module(_mod): - tgen = get_topogen() - tgen.stop_topology() - - -def test_bgp_convergence(): - tgen = get_topogen() - if tgen.routers_have_failure(): - pytest.skip(tgen.errors) - - result = verify_bgp_convergence_from_running_config(tgen, dut="r1") - assert result is True, "BGP is not converging" - - -def get_bmp_messages(): - """ - Read the BMP logging messages. - """ - messages = [] - tgen = get_topogen() - text_output = tgen.gears["bmp1"].run( - "cat {}".format(os.path.join(tgen.logdir, "bmp1", "bmp.log")) - ) - - for m in text_output.splitlines(): - # some output in the bash can break the message decoding - try: - messages.append(json.loads(m)) - except Exception as e: - logger.warning(str(e) + " message: {}".format(str(m))) - continue - - if not messages: - logger.error("Bad BMP log format, check your BMP server") - - return messages - - -def update_seq(): - global SEQ - - messages = get_bmp_messages() - - if len(messages): - SEQ = messages[-1]["seq"] - - -def update_expected_files(bmp_actual, expected_prefixes, bmp_log_type, policy, step): - tgen = get_topogen() - - with open(f"/tmp/bmp-{bmp_log_type}-{policy}-step{step}.json", "w") as json_file: - json.dump(bmp_actual, json_file, indent=4) - - if step == 2: # vpn - rd = "444:2" - out = tgen.gears["r1"].vtysh_cmd("show bgp ipv4 vpn json", isjson=True) - filtered_out = { - "routes": { - "routeDistinguishers": { - rd: { - prefix: route_info - for prefix, route_info in out["routes"] - .get("routeDistinguishers", {}) - .get(rd, {}) - .items() - if prefix in expected_prefixes - } - } - } - } - if bmp_log_type == "withdraw": - for pfx in expected_prefixes: - if "::" in pfx: - continue - filtered_out["routes"]["routeDistinguishers"][rd][pfx] = None - - # ls /tmp/show*json | while read file; do egrep -v 'prefix|network|metric|ocPrf|version|weight|peerId|vrf|Version|valid|Reason|fe80' $file >$(basename $file); echo >> $(basename $file); done - with open( - f"/tmp/show-bgp-ipv4-{bmp_log_type}-step{step}.json", "w" - ) as json_file: - json.dump(filtered_out, json_file, indent=4) - - rd = "555:2" - out = tgen.gears["r1"].vtysh_cmd("show bgp ipv6 vpn json", isjson=True) - filtered_out = { - "routes": { - "routeDistinguishers": { - rd: { - prefix: route_info - for prefix, route_info in out["routes"] - .get("routeDistinguishers", {}) - .get(rd, {}) - .items() - if prefix in expected_prefixes - } - } - } - } - if bmp_log_type == "withdraw": - for pfx in expected_prefixes: - if "::" not in pfx: - continue - filtered_out["routes"]["routeDistinguishers"][rd][pfx] = None - with open( - f"/tmp/show-bgp-ipv6-{bmp_log_type}-step{step}.json", "w" - ) as json_file: - json.dump(filtered_out, json_file, indent=4) - - return - - out = tgen.gears["r1"].vtysh_cmd("show bgp ipv4 json", isjson=True) - filtered_out = { - "routes": { - prefix: route_info - for prefix, route_info in out["routes"].items() - if prefix in expected_prefixes - } - } - if bmp_log_type == "withdraw": - for pfx in expected_prefixes: - if "::" in pfx: - continue - filtered_out["routes"][pfx] = None - - # ls /tmp/show*json | while read file; do egrep -v 'prefix|network|metric|ocPrf|version|weight|peerId|vrf|Version|valid|Reason|fe80' $file >$(basename $file); echo >> $(basename $file); done - with open(f"/tmp/show-bgp-ipv4-{bmp_log_type}-step{step}.json", "w") as json_file: - json.dump(filtered_out, json_file, indent=4) - - out = tgen.gears["r1"].vtysh_cmd("show bgp ipv6 json", isjson=True) - filtered_out = { - "routes": { - prefix: route_info - for prefix, route_info in out["routes"].items() - if prefix in expected_prefixes - } - } - if bmp_log_type == "withdraw": - for pfx in expected_prefixes: - if "::" not in pfx: - continue - filtered_out["routes"][pfx] = None - with open(f"/tmp/show-bgp-ipv6-{bmp_log_type}-step{step}.json", "w") as json_file: - json.dump(filtered_out, json_file, indent=4) - - -def check_for_prefixes(expected_prefixes, bmp_log_type, policy, step): - """ - Check for the presence of the given prefixes in the BMP server logs with - the given message type and the set policy. - - """ - global SEQ - - # we care only about the new messages - messages = [ - m for m in sorted(get_bmp_messages(), key=lambda d: d["seq"]) if m["seq"] > SEQ - ] - - # create empty initial files - # for step in $(seq 2); do - # for i in "update" "withdraw"; do - # for j in "pre-policy" "post-policy" "loc-rib"; do - # echo '{"null": {}}'> bmp-$i-$j-step$step.json - # done - # done - # done - - ref_file = f"{CWD}/bmp1/bmp-{bmp_log_type}-{policy}-step{step}.json" - expected = json.loads(open(ref_file).read()) - - # Build actual json from logs - actual = {} - for m in messages: - if ( - "bmp_log_type" in m.keys() - and "ip_prefix" in m.keys() - and m["ip_prefix"] in expected_prefixes - and m["bmp_log_type"] == bmp_log_type - and m["policy"] == policy - ): - policy_dict = actual.setdefault(m["policy"], {}) - bmp_log_type_dict = policy_dict.setdefault(m["bmp_log_type"], {}) - - # Add or update the ip_prefix dictionary with filtered key-value pairs - bmp_log_type_dict[m["ip_prefix"]] = { - k: v - for k, v in sorted(m.items()) - # filter out variable keys - if k not in ["timestamp", "seq", "nxhp_link-local"] - and ( - # When policy is loc-rib, the peer-distinguisher is 0:0 - # for the default VRF or the RD if any or the 0:. - # 0: is used to distinguished. RFC7854 says: "If the - # peer is a "Local Instance Peer", it is set to a unique, - # locally defined value." The value is not tested because it - # is variable. - k != "peer_distinguisher" - or policy != LOC_RIB - or v == "0:0" - or not v.startswith("0:") - ) - } - - # build expected JSON files - if ( - UPDATE_EXPECTED_JSON - and actual - and set(actual.get(policy, {}).get(bmp_log_type, {}).keys()) - == set(expected_prefixes) - ): - update_expected_files(actual, expected_prefixes, bmp_log_type, policy, step) - - return topotest.json_cmp(actual, expected, exact=True) - - -def check_for_peer_message(expected_peers, bmp_log_type): - """ - Check for the presence of a peer up message for the peer - """ - global SEQ - # we care only about the new messages - messages = [ - m for m in sorted(get_bmp_messages(), key=lambda d: d["seq"]) if m["seq"] > SEQ - ] - - # get the list of pairs (prefix, policy, seq) for the given message type - peers = [ - m["peer_ip"] - for m in messages - if "peer_ip" in m.keys() and m["bmp_log_type"] == bmp_log_type - ] - - # check for prefixes - for ep in expected_peers: - if ep not in peers: - msg = "The peer {} is not present in the {} log messages." - logger.debug(msg.format(ep, bmp_log_type)) - return False - - SEQ = messages[-1]["seq"] - return True - - -def configure_prefixes(tgen, node, asn, safi, prefixes, vrf=None, update=True): - """ - Configure the bgp prefixes. - """ - withdraw = "no " if not update else "" - vrf = " vrf {}".format(vrf) if vrf else "" - for p in prefixes: - ip = ip_network(p) - cmd = [ - "conf t\n", - "router bgp {}{}\n".format(asn, vrf), - "address-family ipv{} {}\n".format(ip.version, safi), - "{}network {}\n".format(withdraw, ip), - "exit-address-family\n", - ] - logger.debug("setting prefix: ipv{} {} {}".format(ip.version, safi, ip)) - tgen.gears[node].vtysh_cmd("".join(cmd)) - - -def _test_prefixes(policy, vrf=None, step=0): - """ - Setup the BMP monitor policy, Add and withdraw ipv4/v6 prefixes. - Check if the previous actions are logged in the BMP server with the right - message type and the right policy. - """ - tgen = get_topogen() - - safi = "vpn" if vrf else "unicast" - - prefixes = ["172.31.0.15/32", "2001::1111/128"] - - for type in ("update", "withdraw"): - update_seq() - - configure_prefixes( - tgen, "r2", 65502, "unicast", prefixes, vrf=vrf, update=(type == "update") - ) - - logger.info(f"checking for prefixes {type}") - - for ipver in [4, 6]: - if UPDATE_EXPECTED_JSON: - continue - ref_file = "{}/r1/show-bgp-ipv{}-{}-step{}.json".format( - CWD, ipver, type, step - ) - expected = json.loads(open(ref_file).read()) - - test_func = partial( - topotest.router_json_cmp, - tgen.gears["r1"], - f"show bgp ipv{ipver} {safi} json", - expected, - ) - _, res = topotest.run_and_expect(test_func, None, count=30, wait=1) - assertmsg = f"r1: BGP IPv{ipver} convergence failed" - assert res is None, assertmsg - - # check - test_func = partial(check_for_prefixes, prefixes, type, policy, step) - success, res = topotest.run_and_expect(test_func, None, count=30, wait=1) - assert success, "Checking the updated prefixes has failed ! %s" % res - - -def test_bmp_server_logging(): - """ - Assert the logging of the bmp server. - """ - - def check_for_log_file(): - tgen = get_topogen() - output = tgen.gears["bmp1"].run( - "ls {}".format(os.path.join(tgen.logdir, "bmp1")) - ) - if "bmp.log" not in output: - return False - return True - - success, _ = topotest.run_and_expect(check_for_log_file, True, count=30, wait=1) - assert success, "The BMP server is not logging" - - -def test_peer_up(): - """ - Checking for BMP peers up messages - """ - - peers = ["192.168.0.2", "192:168::2"] - - logger.info("checking for BMP peers up messages") - - test_func = partial(check_for_peer_message, peers, "peer up") - success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1) - assert success, "Checking the updated prefixes has been failed !." - - -def test_bmp_bgp_unicast(): - """ - Add/withdraw bgp unicast prefixes and check the bmp logs. - """ - logger.info("*** Unicast prefixes pre-policy logging ***") - _test_prefixes(PRE_POLICY, step=1) - logger.info("*** Unicast prefixes post-policy logging ***") - _test_prefixes(POST_POLICY, step=1) - logger.info("*** Unicast prefixes loc-rib logging ***") - _test_prefixes(LOC_RIB, step=1) - - -def test_bmp_bgp_vpn(): - # check for the prefixes in the BMP server logging file - logger.info("***** VPN prefixes pre-policy logging *****") - _test_prefixes(PRE_POLICY, vrf="vrf1", step=2) - logger.info("***** VPN prefixes post-policy logging *****") - _test_prefixes(POST_POLICY, vrf="vrf1", step=2) - logger.info("***** VPN prefixes loc-rib logging *****") - _test_prefixes(LOC_RIB, vrf="vrf1", step=2) - - -def test_peer_down(): - """ - Checking for BMP peers down messages - """ - tgen = get_topogen() - - tgen.gears["r2"].vtysh_cmd("clear bgp *") - - peers = ["192.168.0.2", "192:168::2"] - - logger.info("checking for BMP peers down messages") - - test_func = partial(check_for_peer_message, peers, "peer down") - success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1) - assert success, "Checking the updated prefixes has been failed !." - - -if __name__ == "__main__": - args = ["-s"] + sys.argv[1:] - sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_bmp/test_bgp_bmp_1.py b/tests/topotests/bgp_bmp/test_bgp_bmp_1.py new file mode 100644 index 000000000000..cc7bc31041d9 --- /dev/null +++ b/tests/topotests/bgp_bmp/test_bgp_bmp_1.py @@ -0,0 +1,260 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright 2023 6WIND S.A. +# Authored by Farid Mihoub +# + +""" +test_bgp_bmp.py: Test BGP BMP functionalities + + +------+ +------+ +------+ + | | | | | | + | BMP1 |------------| R1 |---------------| R2 | + | | | | | | + +------+ +------+ +------+ + +Setup two routers R1 and R2 with one link configured with IPv4 and +IPv6 addresses. +Configure BGP in R1 and R2 to exchange prefixes from +the latter to the first router. +Setup a link between R1 and the BMP server, activate the BMP feature in R1 +and ensure the monitored BGP sessions logs are well present on the BMP server. +""" + +from functools import partial +import json +import os +import pytest +import sys + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join("../")) +sys.path.append(os.path.join("../lib/")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.bgp import verify_bgp_convergence_from_running_config +from lib.bgp import bgp_configure_prefixes +from .bgpbmp import ( + bmp_check_for_prefixes, + bmp_check_for_peer_message, + bmp_update_seq, +) +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +pytestmark = [pytest.mark.bgpd] + +PRE_POLICY = "pre-policy" +POST_POLICY = "post-policy" +LOC_RIB = "loc-rib" + +UPDATE_EXPECTED_JSON = False +DEBUG_PCAP = False + + +def build_topo(tgen): + tgen.add_router("r1") + tgen.add_router("r2") + tgen.add_bmp_server("bmp1", ip="192.0.2.10", defaultRoute="via 192.0.2.1") + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["bmp1"]) + + tgen.add_link(tgen.gears["r1"], tgen.gears["r2"], "r1-eth1", "r2-eth0") + + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + if DEBUG_PCAP: + tgen.gears["r1"].run("rm /tmp/bmp.pcap") + tgen.gears["r1"].run( + "tcpdump -nni r1-eth0 -s 0 -w /tmp/bmp.pcap &", stdout=None + ) + + for rname, router in tgen.routers().items(): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, + os.path.join(CWD, "{}/bgpd.conf".format(rname)), + "-M bmp", + ) + + tgen.start_router() + + logger.info("starting BMP servers") + for bmp_name, server in tgen.get_bmp_servers().items(): + server.start(log_file=os.path.join(tgen.logdir, bmp_name, "bmp.log")) + + +def teardown_module(_mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_convergence(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + result = verify_bgp_convergence_from_running_config(tgen, dut="r1") + assert result is True, "BGP is not converging" + + +def _test_prefixes(policy, vrf=None, step=0): + """ + Setup the BMP monitor policy, Add and withdraw ipv4/v6 prefixes. + Check if the previous actions are logged in the BMP server with the right + message type and the right policy. + """ + tgen = get_topogen() + + safi = "vpn" if vrf else "unicast" + + prefixes = ["172.31.0.15/32", "2001::1111/128"] + + for type in ("update", "withdraw"): + bmp_update_seq(tgen.gears["bmp1"], os.path.join(tgen.logdir, "bmp1", "bmp.log")) + + bgp_configure_prefixes( + tgen.gears["r2"], + 65502, + "unicast", + prefixes, + vrf=vrf, + update=(type == "update"), + ) + + logger.info(f"checking for prefixes {type}") + + for ipver in [4, 6]: + if UPDATE_EXPECTED_JSON: + continue + ref_file = "{}/r1/show-bgp-ipv{}-{}-step{}.json".format( + CWD, ipver, type, step + ) + expected = json.loads(open(ref_file).read()) + + test_func = partial( + topotest.router_json_cmp, + tgen.gears["r1"], + f"show bgp ipv{ipver} {safi} json", + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=30, wait=1) + assertmsg = f"r1: BGP IPv{ipver} convergence failed" + assert res is None, assertmsg + + # check + test_func = partial( + bmp_check_for_prefixes, + prefixes, + type, + policy, + step, + tgen.gears["bmp1"], + os.path.join(tgen.logdir, "bmp1", "bmp.log"), + tgen.gears["r1"], + f"{CWD}/bmp1", + UPDATE_EXPECTED_JSON, + LOC_RIB, + ) + success, res = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert success, "Checking the updated prefixes has failed ! %s" % res + + +def test_bmp_server_logging(): + """ + Assert the logging of the bmp server. + """ + + def check_for_log_file(): + tgen = get_topogen() + output = tgen.gears["bmp1"].run( + "ls {}".format(os.path.join(tgen.logdir, "bmp1")) + ) + if "bmp.log" not in output: + return False + return True + + success, _ = topotest.run_and_expect(check_for_log_file, True, count=30, wait=1) + assert success, "The BMP server is not logging" + + +def test_peer_up(): + """ + Checking for BMP peers up messages + """ + + tgen = get_topogen() + peers = ["192.168.0.2", "192:168::2"] + + logger.info("checking for BMP peers up messages") + + test_func = partial( + bmp_check_for_peer_message, + peers, + "peer up", + tgen.gears["bmp1"], + os.path.join(tgen.logdir, "bmp1", "bmp.log"), + ) + success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1) + assert success, "Checking the updated prefixes has been failed !." + + +def test_bmp_bgp_unicast(): + """ + Add/withdraw bgp unicast prefixes and check the bmp logs. + """ + logger.info("*** Unicast prefixes pre-policy logging ***") + _test_prefixes(PRE_POLICY, step=1) + logger.info("*** Unicast prefixes post-policy logging ***") + _test_prefixes(POST_POLICY, step=1) + logger.info("*** Unicast prefixes loc-rib logging ***") + _test_prefixes(LOC_RIB, step=1) + + +def test_bmp_bgp_vpn(): + # check for the prefixes in the BMP server logging file + logger.info("***** VPN prefixes pre-policy logging *****") + _test_prefixes(PRE_POLICY, vrf="vrf1", step=2) + logger.info("***** VPN prefixes post-policy logging *****") + _test_prefixes(POST_POLICY, vrf="vrf1", step=2) + logger.info("***** VPN prefixes loc-rib logging *****") + _test_prefixes(LOC_RIB, vrf="vrf1", step=2) + + +def test_peer_down(): + """ + Checking for BMP peers down messages + """ + tgen = get_topogen() + + tgen.gears["r2"].vtysh_cmd("clear bgp *") + + peers = ["192.168.0.2", "192:168::2"] + + logger.info("checking for BMP peers down messages") + + test_func = partial( + bmp_check_for_peer_message, + peers, + "peer down", + tgen.gears["bmp1"], + os.path.join(tgen.logdir, "bmp1", "bmp.log"), + ) + success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1) + assert success, "Checking the updated prefixes has been failed !." + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_bmp/test_bgp_bmp_2.py b/tests/topotests/bgp_bmp/test_bgp_bmp_2.py new file mode 100644 index 000000000000..97cc98962bb6 --- /dev/null +++ b/tests/topotests/bgp_bmp/test_bgp_bmp_2.py @@ -0,0 +1,258 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright 2023 6WIND S.A. +# Authored by Farid Mihoub +# + +""" +test_bgp_bmp.py: Test BGP BMP functionalities + + +------+ +------+ +------+ + | | | | | | + | BMP1 |------------| R1 |---------------| R2 | + | | | | | | + +------+ +------+ +------+ + +Setup two routers R1 and R2 with one link configured with IPv4 and +IPv6 addresses. +Configure BGP in R1 and R2 to exchange prefixes from +the latter to the first router. +Setup a link between R1 and the BMP server, activate the BMP feature in R1 +and ensure the monitored BGP sessions logs are well present on the BMP server. +""" + +from functools import partial +import json +import os +import platform +import pytest +import sys + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join("../")) +sys.path.append(os.path.join("../lib/")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.bgp import verify_bgp_convergence_from_running_config +from lib.bgp import bgp_configure_prefixes +from .bgpbmp import ( + bmp_check_for_prefixes, + bmp_check_for_peer_message, + bmp_update_seq, + bmp_reset_seq, +) + + +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +pytestmark = [pytest.mark.bgpd] + +PRE_POLICY = "pre-policy" +POST_POLICY = "post-policy" +LOC_RIB = "loc-rib" + +UPDATE_EXPECTED_JSON = False +DEBUG_PCAP = False + + +def build_topo(tgen): + tgen.add_router("r1vrf") + tgen.add_router("r2vrf") + tgen.add_bmp_server("bmp1vrf", ip="192.0.2.10", defaultRoute="via 192.0.2.1") + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1vrf"]) + switch.add_link(tgen.gears["bmp1vrf"]) + + tgen.add_link(tgen.gears["r1vrf"], tgen.gears["r2vrf"], "r1vrf-eth1", "r2vrf-eth0") + + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + tgen.net["r1vrf"].cmd( + """ +ip link add vrf1 type vrf table 10 +ip link set vrf1 up +ip link set r1vrf-eth1 master vrf1 +""" + ) + bmp_reset_seq() + if DEBUG_PCAP: + tgen.gears["r1vrf"].run("rm /tmp/bmp_vrf.pcap") + tgen.gears["r1vrf"].run( + "tcpdump -nni r1vrf-eth0 -s 0 -w /tmp/bmp_vrf.pcap &", stdout=None + ) + + for rname, router in tgen.routers().items(): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, + os.path.join(CWD, "{}/bgpd.conf".format(rname)), + "-M bmp", + ) + + tgen.start_router() + + logger.info("starting BMP servers") + for bmp_name, server in tgen.get_bmp_servers().items(): + server.start(log_file=os.path.join(tgen.logdir, bmp_name, "bmp.log")) + + +def teardown_module(_mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_convergence(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + result = verify_bgp_convergence_from_running_config(tgen, dut="r1vrf") + assert result is True, "BGP is not converging" + + +def _test_prefixes(policy, step=1): + """ + Setup the BMP monitor policy, Add and withdraw ipv4/v6 prefixes. + Check if the previous actions are logged in the BMP server with the right + message type and the right policy. + """ + tgen = get_topogen() + + prefixes = ["172.31.0.15/32", "2111::1111/128"] + + for type in ("update", "withdraw"): + bmp_update_seq( + tgen.gears["bmp1vrf"], os.path.join(tgen.logdir, "bmp1vrf", "bmp.log") + ) + + # add prefixes + bgp_configure_prefixes( + tgen.gears["r2vrf"], 65502, "unicast", prefixes, update=(type == "update") + ) + + logger.info(f"checking for prefixes {type}") + + for ipver in [4, 6]: + if UPDATE_EXPECTED_JSON: + continue + ref_file = "{}/r1vrf/show-bgp-ipv{}-{}-step{}.json".format( + CWD, ipver, type, step + ) + expected = json.loads(open(ref_file).read()) + + test_func = partial( + topotest.router_json_cmp, + tgen.gears["r1vrf"], + f"show bgp vrf vrf1 ipv{ipver} json", + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=30, wait=1) + assertmsg = f"r1vrf: BGP IPv{ipver} convergence failed" + assert res is None, assertmsg + + # check + test_func = partial( + bmp_check_for_prefixes, + prefixes, + type, + policy, + step, + tgen.gears["bmp1vrf"], + os.path.join(tgen.logdir, "bmp1vrf", "bmp.log"), + tgen.gears["r1vrf"], + f"{CWD}/bmp1vrf", + UPDATE_EXPECTED_JSON, + LOC_RIB, + ) + success, res = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert success, "Checking the updated prefixes has failed ! %s" % res + + +def test_bmp_server_logging(): + """ + Assert the logging of the bmp server. + """ + + def check_for_log_file(): + tgen = get_topogen() + output = tgen.gears["bmp1vrf"].run( + "ls {}".format(os.path.join(tgen.logdir, "bmp1vrf")) + ) + if "bmp.log" not in output: + return False + return True + + success, _ = topotest.run_and_expect(check_for_log_file, True, count=30, wait=1) + assert success, "The BMP server is not logging" + + +def test_peer_up(): + """ + Checking for BMP peers up messages + """ + + tgen = get_topogen() + peers = ["192.168.0.2", "192:168::2"] + + logger.info("checking for BMP peers up messages") + + test_func = partial( + bmp_check_for_peer_message, + peers, + "peer up", + tgen.gears["bmp1vrf"], + os.path.join(tgen.logdir, "bmp1vrf", "bmp.log"), + ) + success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1) + assert success, "Checking the updated prefixes has been failed !." + + +def test_bmp_bgp_unicast(): + """ + Add/withdraw bgp unicast prefixes and check the bmp logs. + """ + logger.info("*** Unicast prefixes pre-policy logging ***") + _test_prefixes(PRE_POLICY) + logger.info("*** Unicast prefixes post-policy logging ***") + _test_prefixes(POST_POLICY) + logger.info("*** Unicast prefixes loc-rib logging ***") + _test_prefixes(LOC_RIB) + + +def test_peer_down(): + """ + Checking for BMP peers down messages + """ + tgen = get_topogen() + + tgen.gears["r2vrf"].vtysh_cmd("clear bgp *") + + peers = ["192.168.0.2", "192:168::2"] + + logger.info("checking for BMP peers down messages") + + test_func = partial( + bmp_check_for_peer_message, + peers, + "peer down", + tgen.gears["bmp1vrf"], + os.path.join(tgen.logdir, "bmp1vrf", "bmp.log"), + ) + success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1) + assert success, "Checking the updated prefixes has been failed !." + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_bmp_vrf/__init__.py b/tests/topotests/bgp_bmp_vrf/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/bgp_bmp_vrf/test_bgp_bmp_vrf.py b/tests/topotests/bgp_bmp_vrf/test_bgp_bmp_vrf.py deleted file mode 100644 index d31328bdb659..000000000000 --- a/tests/topotests/bgp_bmp_vrf/test_bgp_bmp_vrf.py +++ /dev/null @@ -1,418 +0,0 @@ -#!/usr/bin/env python -# SPDX-License-Identifier: ISC - -# Copyright 2023 6WIND S.A. -# Authored by Farid Mihoub -# - -""" -test_bgp_bmp.py: Test BGP BMP functionalities - - +------+ +------+ +------+ - | | | | | | - | BMP1 |------------| R1 |---------------| R2 | - | | | | | | - +------+ +------+ +------+ - -Setup two routers R1 and R2 with one link configured with IPv4 and -IPv6 addresses. -Configure BGP in R1 and R2 to exchange prefixes from -the latter to the first router. -Setup a link between R1 and the BMP server, activate the BMP feature in R1 -and ensure the monitored BGP sessions logs are well present on the BMP server. -""" - -from functools import partial -from ipaddress import ip_network -import json -import os -import platform -import pytest -import sys - -# Save the Current Working Directory to find configuration files. -CWD = os.path.dirname(os.path.realpath(__file__)) -sys.path.append(os.path.join("../")) -sys.path.append(os.path.join("../lib/")) - -# pylint: disable=C0413 -# Import topogen and topotest helpers -from lib import topotest -from lib.bgp import verify_bgp_convergence_from_running_config -from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger - -pytestmark = [pytest.mark.bgpd] - -# remember the last sequence number of the logging messages -SEQ = 0 - -PRE_POLICY = "pre-policy" -POST_POLICY = "post-policy" -LOC_RIB = "loc-rib" - -UPDATE_EXPECTED_JSON = False -DEBUG_PCAP = False - - -def build_topo(tgen): - tgen.add_router("r1") - tgen.add_router("r2") - tgen.add_bmp_server("bmp1", ip="192.0.2.10", defaultRoute="via 192.0.2.1") - - switch = tgen.add_switch("s1") - switch.add_link(tgen.gears["r1"]) - switch.add_link(tgen.gears["bmp1"]) - - tgen.add_link(tgen.gears["r1"], tgen.gears["r2"], "r1-eth1", "r2-eth0") - - -def setup_module(mod): - tgen = Topogen(build_topo, mod.__name__) - tgen.start_topology() - - tgen.net["r1"].cmd( - """ -ip link add vrf1 type vrf table 10 -ip link set vrf1 up -ip link set r1-eth1 master vrf1 -""" - ) - - if DEBUG_PCAP: - tgen.gears["r1"].run("rm /tmp/bmp_vrf.pcap") - tgen.gears["r1"].run( - "tcpdump -nni r1-eth0 -s 0 -w /tmp/bmp_vrf.pcap &", stdout=None - ) - - for rname, router in tgen.routers().items(): - router.load_config( - TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) - ) - router.load_config( - TopoRouter.RD_BGP, - os.path.join(CWD, "{}/bgpd.conf".format(rname)), - "-M bmp", - ) - - tgen.start_router() - - logger.info("starting BMP servers") - for bmp_name, server in tgen.get_bmp_servers().items(): - server.start(log_file=os.path.join(tgen.logdir, bmp_name, "bmp.log")) - - -def teardown_module(_mod): - tgen = get_topogen() - tgen.stop_topology() - - -def test_bgp_convergence(): - tgen = get_topogen() - if tgen.routers_have_failure(): - pytest.skip(tgen.errors) - - result = verify_bgp_convergence_from_running_config(tgen, dut="r1") - assert result is True, "BGP is not converging" - - -def get_bmp_messages(): - """ - Read the BMP logging messages. - """ - messages = [] - tgen = get_topogen() - text_output = tgen.gears["bmp1"].run( - "cat {}".format(os.path.join(tgen.logdir, "bmp1", "bmp.log")) - ) - - for m in text_output.splitlines(): - # some output in the bash can break the message decoding - try: - messages.append(json.loads(m)) - except Exception as e: - logger.warning(str(e) + " message: {}".format(str(m))) - continue - - if not messages: - logger.error("Bad BMP log format, check your BMP server") - - return messages - - -def update_seq(): - global SEQ - - messages = get_bmp_messages() - - if len(messages): - SEQ = messages[-1]["seq"] - - -def update_expected_files(bmp_actual, expected_prefixes, bmp_log_type, policy, step): - tgen = get_topogen() - - with open(f"/tmp/bmp-{bmp_log_type}-{policy}-step{step}.json", "w") as json_file: - json.dump(bmp_actual, json_file, indent=4) - - out = tgen.gears["r1"].vtysh_cmd("show bgp vrf vrf1 ipv4 json", isjson=True) - filtered_out = { - "routes": { - prefix: route_info - for prefix, route_info in out["routes"].items() - if prefix in expected_prefixes - } - } - if bmp_log_type == "withdraw": - for pfx in expected_prefixes: - if "::" in pfx: - continue - filtered_out["routes"][pfx] = None - - # ls /tmp/show*json | while read file; do egrep -v 'prefix|network|metric|ocPrf|version|weight|peerId|vrf|Version|valid|Reason|fe80' $file >$(basename $file); echo >> $(basename $file); done - with open(f"/tmp/show-bgp-ipv4-{bmp_log_type}-step{step}.json", "w") as json_file: - json.dump(filtered_out, json_file, indent=4) - - out = tgen.gears["r1"].vtysh_cmd("show bgp vrf vrf1 ipv6 json", isjson=True) - filtered_out = { - "routes": { - prefix: route_info - for prefix, route_info in out["routes"].items() - if prefix in expected_prefixes - } - } - if bmp_log_type == "withdraw": - for pfx in expected_prefixes: - if "::" not in pfx: - continue - filtered_out["routes"][pfx] = None - - with open(f"/tmp/show-bgp-ipv6-{bmp_log_type}-step{step}.json", "w") as json_file: - json.dump(filtered_out, json_file, indent=4) - - -def check_for_prefixes(expected_prefixes, bmp_log_type, policy, step): - """ - Check for the presence of the given prefixes in the BMP server logs with - the given message type and the set policy. - - """ - global SEQ - - # we care only about the new messages - messages = [ - m for m in sorted(get_bmp_messages(), key=lambda d: d["seq"]) if m["seq"] > SEQ - ] - - # create empty initial files - # for step in $(seq 1); do - # for i in "update" "withdraw"; do - # for j in "pre-policy" "post-policy" "loc-rib"; do - # echo '{"null": {}}'> bmp-$i-$j-step$step.json - # done - # done - # done - - ref_file = f"{CWD}/bmp1/bmp-{bmp_log_type}-{policy}-step{step}.json" - expected = json.loads(open(ref_file).read()) - - # Build actual json from logs - actual = {} - for m in messages: - if ( - "bmp_log_type" in m.keys() - and "ip_prefix" in m.keys() - and m["ip_prefix"] in expected_prefixes - and m["bmp_log_type"] == bmp_log_type - and m["policy"] == policy - ): - policy_dict = actual.setdefault(m["policy"], {}) - bmp_log_type_dict = policy_dict.setdefault(m["bmp_log_type"], {}) - - # Add or update the ip_prefix dictionary with filtered key-value pairs - bmp_log_type_dict[m["ip_prefix"]] = { - k: v - for k, v in sorted(m.items()) - # filter out variable keys - if k not in ["timestamp", "seq", "nxhp_link-local"] - and ( - # When policy is loc-rib, the peer-distinguisher is 0:0 - # for the default VRF or the RD if any or the 0:. - # 0: is used to distinguished. RFC7854 says: "If the - # peer is a "Local Instance Peer", it is set to a unique, - # locally defined value." The value is not tested because it - # is variable. - k != "peer_distinguisher" - or policy != LOC_RIB - or v == "0:0" - or not v.startswith("0:") - ) - } - - # build expected JSON files - if ( - UPDATE_EXPECTED_JSON - and actual - and set(actual.get(policy, {}).get(bmp_log_type, {}).keys()) - == set(expected_prefixes) - ): - update_expected_files(actual, expected_prefixes, bmp_log_type, policy, step) - - return topotest.json_cmp(actual, expected, exact=True) - - -def check_for_peer_message(expected_peers, bmp_log_type): - """ - Check for the presence of a peer up message for the peer - """ - global SEQ - # we care only about the new messages - messages = [ - m for m in sorted(get_bmp_messages(), key=lambda d: d["seq"]) if m["seq"] > SEQ - ] - - # get the list of pairs (prefix, policy, seq) for the given message type - peers = [ - m["peer_ip"] - for m in messages - if "peer_ip" in m.keys() and m["bmp_log_type"] == bmp_log_type - ] - - # check for prefixes - for ep in expected_peers: - if ep not in peers: - msg = "The peer {} is not present in the {} log messages." - logger.debug(msg.format(ep, bmp_log_type)) - return False - - SEQ = messages[-1]["seq"] - return True - - -def configure_prefixes(tgen, node, asn, safi, prefixes, vrf=None, update=True): - """ - Configure the bgp prefixes. - """ - withdraw = "no " if not update else "" - vrf = " vrf {}".format(vrf) if vrf else "" - for p in prefixes: - ip = ip_network(p) - cmd = [ - "conf t\n", - "router bgp {}{}\n".format(asn, vrf), - "address-family ipv{} {}\n".format(ip.version, safi), - "{}network {}\n".format(withdraw, ip), - "exit-address-family\n", - ] - logger.debug("setting prefix: ipv{} {} {}".format(ip.version, safi, ip)) - tgen.gears[node].vtysh_cmd("".join(cmd)) - - -def _test_prefixes(policy, step=1): - """ - Setup the BMP monitor policy, Add and withdraw ipv4/v6 prefixes. - Check if the previous actions are logged in the BMP server with the right - message type and the right policy. - """ - tgen = get_topogen() - - prefixes = ["172.31.0.15/32", "2111::1111/128"] - - for type in ("update", "withdraw"): - update_seq() - - # add prefixes - configure_prefixes( - tgen, "r2", 65502, "unicast", prefixes, update=(type == "update") - ) - - logger.info(f"checking for prefixes {type}") - - for ipver in [4, 6]: - if UPDATE_EXPECTED_JSON: - continue - ref_file = "{}/r1/show-bgp-ipv{}-{}-step{}.json".format( - CWD, ipver, type, step - ) - expected = json.loads(open(ref_file).read()) - - test_func = partial( - topotest.router_json_cmp, - tgen.gears["r1"], - f"show bgp vrf vrf1 ipv{ipver} json", - expected, - ) - _, res = topotest.run_and_expect(test_func, None, count=30, wait=1) - assertmsg = f"r1: BGP IPv{ipver} convergence failed" - assert res is None, assertmsg - - # check - test_func = partial(check_for_prefixes, prefixes, type, policy, step) - success, res = topotest.run_and_expect(test_func, None, count=30, wait=1) - assert success, "Checking the updated prefixes has been failed ! %s" % res - - -def test_bmp_server_logging(): - """ - Assert the logging of the bmp server. - """ - - def check_for_log_file(): - tgen = get_topogen() - output = tgen.gears["bmp1"].run( - "ls {}".format(os.path.join(tgen.logdir, "bmp1")) - ) - if "bmp.log" not in output: - return False - return True - - success, _ = topotest.run_and_expect(check_for_log_file, True, count=30, wait=1) - assert success, "The BMP server is not logging" - - -def test_peer_up(): - """ - Checking for BMP peers up messages - """ - - peers = ["192.168.0.2", "192:168::2"] - - logger.info("checking for BMP peers up messages") - - test_func = partial(check_for_peer_message, peers, "peer up") - success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1) - assert success, "Checking the updated prefixes has been failed !." - - -def test_bmp_bgp_unicast(): - """ - Add/withdraw bgp unicast prefixes and check the bmp logs. - """ - logger.info("*** Unicast prefixes pre-policy logging ***") - _test_prefixes(PRE_POLICY) - logger.info("*** Unicast prefixes post-policy logging ***") - _test_prefixes(POST_POLICY) - logger.info("*** Unicast prefixes loc-rib logging ***") - _test_prefixes(LOC_RIB) - - -def test_peer_down(): - """ - Checking for BMP peers down messages - """ - tgen = get_topogen() - - tgen.gears["r2"].vtysh_cmd("clear bgp *") - - peers = ["192.168.0.2", "192:168::2"] - - logger.info("checking for BMP peers down messages") - - test_func = partial(check_for_peer_message, peers, "peer down") - success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1) - assert success, "Checking the updated prefixes has been failed !." - - -if __name__ == "__main__": - args = ["-s"] + sys.argv[1:] - sys.exit(pytest.main(args)) diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index bcd1c748120f..329c2b54f568 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -5638,3 +5638,22 @@ def configure_bgp_soft_configuration(tgen, dut, neighbor_dict, direction): ) ) return True + + +def bgp_configure_prefixes(router, asn, safi, prefixes, vrf=None, update=True): + """ + Configure the bgp prefixes. + """ + withdraw = "no " if not update else "" + vrf = " vrf {}".format(vrf) if vrf else "" + for p in prefixes: + ip = ipaddress.ip_network(p) + cmd = [ + "conf t\n", + f"router bgp {asn}{vrf}\n" + f"address-family ipv{ip.version} {safi}\n" + f"{withdraw}network {ip}\n".format(withdraw, ip), + "exit-address-family\n", + ] + logger.debug(f"setting prefix: ipv{ip.version} {safi} {ip}") + router.vtysh_cmd("".join(cmd)) From 293833d4c2133e7c9dcf27c9b2a61767d53d950e Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 28 Oct 2024 18:20:13 +0100 Subject: [PATCH 011/106] topotests: fix bmp_collector handling of empty as-path When configuring the bgp_bmp test with an additional peer that sends empty AS-PATH, the bmp collector is stopping: > [2024-10-28 17:41:51] Finished dissecting data from ('192.0.2.1', 33922) > [2024-10-28 17:41:52] Data received from ('192.0.2.1', 33922): length 195 > [2024-10-28 17:41:52] Got message type: > [2024-10-28 17:41:52] unpack_from requires a buffer of at least 2 bytes for unpacking 2 bytes at offset 0 (actual buffer size is 0) > [2024-10-28 17:41:52] TCP session closed with ('192.0.2.1', 33922) > [2024-10-28 17:41:52] Server shutting down on 192.0.2.10:1789 The parser attempts to read an empty AS-path and considers the length value as a length in bytes, whereas RFC mentions this value as definining the number of AS-PAths. Fix this in the parser. Signed-off-by: Philippe Guibert --- .../lib/bmp_collector/bgp/update/path_attributes.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/topotests/lib/bmp_collector/bgp/update/path_attributes.py b/tests/topotests/lib/bmp_collector/bgp/update/path_attributes.py index 3694cb4fe3df..ca49c405d147 100644 --- a/tests/topotests/lib/bmp_collector/bgp/update/path_attributes.py +++ b/tests/topotests/lib/bmp_collector/bgp/update/path_attributes.py @@ -72,6 +72,12 @@ def dissect(cls, data): if path_attr_cls == cls.UNKNOWN_ATTR: return data[offset + attr_len :], None + # RFC1771, 4.3 UPDATE Message Format + # The path segment length is a 1-octet long field containing + # the number of ASs in the path segment value field. + if type_code == PATH_ATTR_TYPE_AS_PATH and attr_len == 0: + return data[offset:], path_attr_cls.dissect(data[offset : offset + 2]) + return data[offset + attr_len :], path_attr_cls.dissect( data[offset : offset + attr_len] ) From 523855379e82fa054bd05fa5500d0f2c4f787f75 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 18 Nov 2024 21:38:45 +0100 Subject: [PATCH 012/106] topotests: bgp_bmp, use unified configuration Use unified configuration procedure. Signed-off-by: Philippe Guibert --- tests/topotests/bgp_bmp/r1/{bgpd.conf => frr.conf} | 9 ++++++++- tests/topotests/bgp_bmp/r1/zebra.conf | 7 ------- tests/topotests/bgp_bmp/r1vrf/{bgpd.conf => frr.conf} | 8 +++++++- tests/topotests/bgp_bmp/r1vrf/zebra.conf | 7 ------- tests/topotests/bgp_bmp/r2/{bgpd.conf => frr.conf} | 8 ++++++++ tests/topotests/bgp_bmp/r2/zebra.conf | 8 -------- tests/topotests/bgp_bmp/r2vrf/{bgpd.conf => frr.conf} | 8 ++++++++ tests/topotests/bgp_bmp/r2vrf/zebra.conf | 8 -------- tests/topotests/bgp_bmp/test_bgp_bmp_1.py | 11 ++++------- tests/topotests/bgp_bmp/test_bgp_bmp_2.py | 11 ++++------- 10 files changed, 39 insertions(+), 46 deletions(-) rename tests/topotests/bgp_bmp/r1/{bgpd.conf => frr.conf} (91%) delete mode 100644 tests/topotests/bgp_bmp/r1/zebra.conf rename tests/topotests/bgp_bmp/r1vrf/{bgpd.conf => frr.conf} (86%) delete mode 100644 tests/topotests/bgp_bmp/r1vrf/zebra.conf rename tests/topotests/bgp_bmp/r2/{bgpd.conf => frr.conf} (87%) delete mode 100644 tests/topotests/bgp_bmp/r2/zebra.conf rename tests/topotests/bgp_bmp/r2vrf/{bgpd.conf => frr.conf} (74%) delete mode 100644 tests/topotests/bgp_bmp/r2vrf/zebra.conf diff --git a/tests/topotests/bgp_bmp/r1/bgpd.conf b/tests/topotests/bgp_bmp/r1/frr.conf similarity index 91% rename from tests/topotests/bgp_bmp/r1/bgpd.conf rename to tests/topotests/bgp_bmp/r1/frr.conf index 485c2170967c..f7cb669b3dd2 100644 --- a/tests/topotests/bgp_bmp/r1/bgpd.conf +++ b/tests/topotests/bgp_bmp/r1/frr.conf @@ -1,3 +1,10 @@ +interface r1-eth0 + ip address 192.0.2.1/24 +! +interface r1-eth1 + ip address 192.168.0.1/24 + ipv6 address 192:168::1/64 +! router bgp 65501 bgp router-id 192.168.0.1 bgp log-neighbor-changes @@ -41,7 +48,7 @@ router bgp 65501 exit-address-family ! router bgp 65501 vrf vrf1 - bgp router_id 192.168.0.1 + bgp router-id 192.168.0.1 bgp log-neighbor-changes address-family ipv4 unicast label vpn export 101 diff --git a/tests/topotests/bgp_bmp/r1/zebra.conf b/tests/topotests/bgp_bmp/r1/zebra.conf deleted file mode 100644 index 0b523c9e18d8..000000000000 --- a/tests/topotests/bgp_bmp/r1/zebra.conf +++ /dev/null @@ -1,7 +0,0 @@ -interface r1-eth0 - ip address 192.0.2.1/24 -! -interface r1-eth1 - ip address 192.168.0.1/24 - ipv6 address 192:168::1/64 -! diff --git a/tests/topotests/bgp_bmp/r1vrf/bgpd.conf b/tests/topotests/bgp_bmp/r1vrf/frr.conf similarity index 86% rename from tests/topotests/bgp_bmp/r1vrf/bgpd.conf rename to tests/topotests/bgp_bmp/r1vrf/frr.conf index 961e20498b2e..cb8a7d2b14e4 100644 --- a/tests/topotests/bgp_bmp/r1vrf/bgpd.conf +++ b/tests/topotests/bgp_bmp/r1vrf/frr.conf @@ -1,3 +1,10 @@ +interface r1vrf-eth0 + ip address 192.0.2.1/24 +! +interface r1vrf-eth1 + ip address 192.168.0.1/24 + ipv6 address 192:168::1/64 +! router bgp 65501 vrf vrf1 bgp router-id 192.168.0.1 bgp log-neighbor-changes @@ -15,7 +22,6 @@ router bgp 65501 vrf vrf1 bmp monitor ipv6 unicast loc-rib exit ! - address-family ipv4 unicast neighbor 192.168.0.2 activate neighbor 192.168.0.2 soft-reconfiguration inbound diff --git a/tests/topotests/bgp_bmp/r1vrf/zebra.conf b/tests/topotests/bgp_bmp/r1vrf/zebra.conf deleted file mode 100644 index a242eadce8a7..000000000000 --- a/tests/topotests/bgp_bmp/r1vrf/zebra.conf +++ /dev/null @@ -1,7 +0,0 @@ -interface r1vrf-eth0 - ip address 192.0.2.1/24 -! -interface r1vrf-eth1 - ip address 192.168.0.1/24 - ipv6 address 192:168::1/64 -! diff --git a/tests/topotests/bgp_bmp/r2/bgpd.conf b/tests/topotests/bgp_bmp/r2/frr.conf similarity index 87% rename from tests/topotests/bgp_bmp/r2/bgpd.conf rename to tests/topotests/bgp_bmp/r2/frr.conf index 40e2cd5bbcb9..250071f48477 100644 --- a/tests/topotests/bgp_bmp/r2/bgpd.conf +++ b/tests/topotests/bgp_bmp/r2/frr.conf @@ -1,3 +1,11 @@ +interface r2-eth0 + ip address 192.168.0.2/24 + ipv6 address 192:168::2/64 +! +interface r2-eth1 + ip address 172.31.0.2/24 + ipv6 address 172:31::2/64 +! router bgp 65502 bgp router-id 192.168.0.2 bgp log-neighbor-changes diff --git a/tests/topotests/bgp_bmp/r2/zebra.conf b/tests/topotests/bgp_bmp/r2/zebra.conf deleted file mode 100644 index 9d82bfe2df5c..000000000000 --- a/tests/topotests/bgp_bmp/r2/zebra.conf +++ /dev/null @@ -1,8 +0,0 @@ -interface r2-eth0 - ip address 192.168.0.2/24 - ipv6 address 192:168::2/64 -! -interface r2-eth1 - ip address 172.31.0.2/24 - ipv6 address 172:31::2/64 -! diff --git a/tests/topotests/bgp_bmp/r2vrf/bgpd.conf b/tests/topotests/bgp_bmp/r2vrf/frr.conf similarity index 74% rename from tests/topotests/bgp_bmp/r2vrf/bgpd.conf rename to tests/topotests/bgp_bmp/r2vrf/frr.conf index 7c8255a17563..5268190dec21 100644 --- a/tests/topotests/bgp_bmp/r2vrf/bgpd.conf +++ b/tests/topotests/bgp_bmp/r2vrf/frr.conf @@ -1,3 +1,11 @@ +interface r2vrf-eth0 + ip address 192.168.0.2/24 + ipv6 address 192:168::2/64 +! +interface r2vrf-eth1 + ip address 172.31.0.2/24 + ipv6 address 172:31::2/64 +! router bgp 65502 bgp router-id 192.168.0.2 bgp log-neighbor-changes diff --git a/tests/topotests/bgp_bmp/r2vrf/zebra.conf b/tests/topotests/bgp_bmp/r2vrf/zebra.conf deleted file mode 100644 index 9a8da2d95fbd..000000000000 --- a/tests/topotests/bgp_bmp/r2vrf/zebra.conf +++ /dev/null @@ -1,8 +0,0 @@ -interface r2vrf-eth0 - ip address 192.168.0.2/24 - ipv6 address 192:168::2/64 -! -interface r2vrf-eth1 - ip address 172.31.0.2/24 - ipv6 address 172:31::2/64 -! diff --git a/tests/topotests/bgp_bmp/test_bgp_bmp_1.py b/tests/topotests/bgp_bmp/test_bgp_bmp_1.py index cc7bc31041d9..493f357f4b4b 100644 --- a/tests/topotests/bgp_bmp/test_bgp_bmp_1.py +++ b/tests/topotests/bgp_bmp/test_bgp_bmp_1.py @@ -79,13 +79,10 @@ def setup_module(mod): ) for rname, router in tgen.routers().items(): - router.load_config( - TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) - ) - router.load_config( - TopoRouter.RD_BGP, - os.path.join(CWD, "{}/bgpd.conf".format(rname)), - "-M bmp", + logger.info("Loading router %s" % rname) + router.load_frr_config( + os.path.join(CWD, "{}/frr.conf".format(rname)), + [(TopoRouter.RD_ZEBRA, None), (TopoRouter.RD_BGP, "-M bmp")], ) tgen.start_router() diff --git a/tests/topotests/bgp_bmp/test_bgp_bmp_2.py b/tests/topotests/bgp_bmp/test_bgp_bmp_2.py index 97cc98962bb6..82d3824a1b93 100644 --- a/tests/topotests/bgp_bmp/test_bgp_bmp_2.py +++ b/tests/topotests/bgp_bmp/test_bgp_bmp_2.py @@ -91,13 +91,10 @@ def setup_module(mod): ) for rname, router in tgen.routers().items(): - router.load_config( - TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) - ) - router.load_config( - TopoRouter.RD_BGP, - os.path.join(CWD, "{}/bgpd.conf".format(rname)), - "-M bmp", + logger.info("Loading router %s" % rname) + router.load_frr_config( + os.path.join(CWD, "{}/frr.conf".format(rname)), + [(TopoRouter.RD_ZEBRA, None), (TopoRouter.RD_BGP, "-M bmp")], ) tgen.start_router() From 45f72294a414b6c5f3b67c9714cdc3838b48e163 Mon Sep 17 00:00:00 2001 From: Louis Scalbert Date: Wed, 20 Nov 2024 11:23:51 +0100 Subject: [PATCH 013/106] tests: add py extension to bmpserver to help identify the file type. And apply black. Signed-off-by: Louis Scalbert --- tests/topotests/lib/bmp_collector/{bmpserver => bmpserver.py} | 4 +--- tests/topotests/lib/topogen.py | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) rename tests/topotests/lib/bmp_collector/{bmpserver => bmpserver.py} (95%) diff --git a/tests/topotests/lib/bmp_collector/bmpserver b/tests/topotests/lib/bmp_collector/bmpserver.py similarity index 95% rename from tests/topotests/lib/bmp_collector/bmpserver rename to tests/topotests/lib/bmp_collector/bmpserver.py index 56d85fc74b30..1f8c12cdd5cf 100755 --- a/tests/topotests/lib/bmp_collector/bmpserver +++ b/tests/topotests/lib/bmp_collector/bmpserver.py @@ -80,9 +80,7 @@ def main(): while len(data) > BMPMsg.MIN_LEN: data = BMPMsg.dissect(data, log_file=LOG_FILE) - timestamp_print( - f"Finished dissecting data from {client_address}" - ) + timestamp_print(f"Finished dissecting data from {client_address}") except Exception as e: timestamp_print(f"{e}") diff --git a/tests/topotests/lib/topogen.py b/tests/topotests/lib/topogen.py index 4d7c56423e36..dce83d5ef5a3 100644 --- a/tests/topotests/lib/topogen.py +++ b/tests/topotests/lib/topogen.py @@ -1296,7 +1296,7 @@ def start(self, log_file=None): with open(log_err, "w") as err: self.run( - "{}/bmp_collector/bmpserver -a {} -p {} {}&".format( + "{}/bmp_collector/bmpserver.py -a {} -p {} {}&".format( CWD, self.ip, self.port, log_arg ), stdout=None, @@ -1304,7 +1304,7 @@ def start(self, log_file=None): ) def stop(self): - self.run("pkill -f bmpserver") + self.run("pkill -f bmpserver.py") return "" From 26a7352cdcfd7b103e1cbdbdcc56131ce070fe63 Mon Sep 17 00:00:00 2001 From: Louis Scalbert Date: Wed, 20 Nov 2024 11:24:13 +0100 Subject: [PATCH 014/106] tests: fix bmp test parallelization Multiple BMP tests can run in parallel but, when one instance ends, it kills the BMP server process of all BMP tests. Save the PID of a BMP server and only kill it at the end. Link: https://github.com/FRRouting/frr/issues/17465 Fixes: 875511c466 ("topotests: add basic bmp collector") Signed-off-by: Louis Scalbert --- .../topotests/lib/bmp_collector/bmpserver.py | 78 ++++++++++++++++++- tests/topotests/lib/topogen.py | 7 +- 2 files changed, 81 insertions(+), 4 deletions(-) diff --git a/tests/topotests/lib/bmp_collector/bmpserver.py b/tests/topotests/lib/bmp_collector/bmpserver.py index 1f8c12cdd5cf..a7c9743c9604 100755 --- a/tests/topotests/lib/bmp_collector/bmpserver.py +++ b/tests/topotests/lib/bmp_collector/bmpserver.py @@ -7,6 +7,7 @@ import argparse # XXX: something more reliable should be used "Twisted" a great choice. +import os import signal import socket import sys @@ -20,11 +21,11 @@ # Global variable to track shutdown signal shutdown = False - parser = argparse.ArgumentParser() parser.add_argument("-a", "--address", type=str, default="0.0.0.0") parser.add_argument("-p", "--port", type=int, default=1789) parser.add_argument("-l", "--logfile", type=str, default="/var/log/bmp.log") +parser.add_argument("-r", "--pidfile", type=str, default="/var/run/bmp.pid") def handle_signal(signum, frame): @@ -40,6 +41,74 @@ def timestamp_print(message, file=sys.stderr): print(f"[{current_time}] {message}", file=file) +def check_pid(pid): + if pid < 0: # user input error + return False + if pid == 0: # all processes + return False + try: + os.kill(pid, 0) + return True + except OSError as err: + if err.errno == errno.EPERM: # a process we were denied access to + return True + if err.errno == errno.ESRCH: # No such process + return False + # should never happen + return False + + +def savepid(): + ownid = os.getpid() + + flags = os.O_CREAT | os.O_EXCL | os.O_WRONLY + mode = ((os.R_OK | os.W_OK) << 6) | (os.R_OK << 3) | os.R_OK + + try: + fd = os.open(pid_file, flags, mode) + except OSError: + try: + pid = open(pid_file, "r").readline().strip() + if check_pid(int(pid)): + timestamp_print( + "PID file already exists and program still running %s\n" % pid_file + ) + return False + else: + # If pid is not running, reopen file without O_EXCL + fd = os.open(pid_file, flags ^ os.O_EXCL, mode) + except (OSError, IOError, ValueError): + timestamp_print( + "issue accessing PID file %s (most likely permission or ownership)\n" + % pid_file + ) + return False + + try: + f = os.fdopen(fd, "w") + line = "%d\n" % ownid + f.write(line) + f.close() + saved_pid = True + except IOError: + timestamp_print("Can not create PID file %s\n" % pid_file) + return False + timestamp_print("Created PID file %s with value %d\n" % (pid_file, ownid)) + return True + + +def removepid(): + try: + os.remove(pid_file) + except OSError as exc: + if exc.errno == errno.ENOENT: + pass + else: + timestamp_print("Can not remove PID file %s\n" % pid_file) + return + timestamp_print("Removed PID file %s\n" % pid_file) + + def main(): global shutdown @@ -51,8 +120,13 @@ def main(): ADDRESS, PORT = args.address, args.port LOG_FILE = args.logfile + global pid_file + pid_file = args.pidfile + timestamp_print(f"Starting bmpserver on {args.address}:{args.port}") + savepid() + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) try: @@ -97,6 +171,7 @@ def main(): timestamp_print(f"{e}") finally: timestamp_print(f"Server shutting down on {ADDRESS}:{PORT}") + removepid() if __name__ == "__main__": @@ -104,4 +179,5 @@ def main(): sys.exit(main()) except KeyboardInterrupt: logging.info("BMP server was interrupted and is shutting down.") + removepid() sys.exit(0) diff --git a/tests/topotests/lib/topogen.py b/tests/topotests/lib/topogen.py index dce83d5ef5a3..0a9a84a4bb07 100644 --- a/tests/topotests/lib/topogen.py +++ b/tests/topotests/lib/topogen.py @@ -1293,18 +1293,19 @@ def start(self, log_file=None): log_err = os.path.join(log_dir, "bmpserver.log") log_arg = "-l {}".format(log_file) if log_file else "" + self.pid_file = os.path.join(log_dir, "bmpserver.pid") with open(log_err, "w") as err: self.run( - "{}/bmp_collector/bmpserver.py -a {} -p {} {}&".format( - CWD, self.ip, self.port, log_arg + "{}/bmp_collector/bmpserver.py -a {} -p {} -r {} {}&".format( + CWD, self.ip, self.port, self.pid_file, log_arg ), stdout=None, stderr=err, ) def stop(self): - self.run("pkill -f bmpserver.py") + self.run(f"kill $(cat {self.pid_file}") return "" From b90814acb3f8197bb29ed5c2e8401707f39e620d Mon Sep 17 00:00:00 2001 From: Louis Scalbert Date: Thu, 21 Nov 2024 11:29:53 +0100 Subject: [PATCH 015/106] tests: save bmp pcap in logdir instead of /tmp DEBUG_PCAP can be set True to manually enable pcap debugging when running bmp tests. Save bmp pcap in logdir (ie. /tmp/topotests/bgp_bmp.bgp_bmp_X/ instead of /tmp. Signed-off-by: Louis Scalbert Signed-off-by: Philippe Guibert --- tests/topotests/bgp_bmp/test_bgp_bmp_1.py | 4 ++-- tests/topotests/bgp_bmp/test_bgp_bmp_2.py | 4 ++-- tests/topotests/lib/bmp_collector/bmpserver.py | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/topotests/bgp_bmp/test_bgp_bmp_1.py b/tests/topotests/bgp_bmp/test_bgp_bmp_1.py index 493f357f4b4b..9fc8e127720f 100644 --- a/tests/topotests/bgp_bmp/test_bgp_bmp_1.py +++ b/tests/topotests/bgp_bmp/test_bgp_bmp_1.py @@ -73,9 +73,9 @@ def setup_module(mod): tgen.start_topology() if DEBUG_PCAP: - tgen.gears["r1"].run("rm /tmp/bmp.pcap") + pcap_file = os.path.join(tgen.logdir, "r1/bmp.pcap") tgen.gears["r1"].run( - "tcpdump -nni r1-eth0 -s 0 -w /tmp/bmp.pcap &", stdout=None + "tcpdump -nni r1-eth0 -s 0 -w {} &".format(pcap_file), stdout=None ) for rname, router in tgen.routers().items(): diff --git a/tests/topotests/bgp_bmp/test_bgp_bmp_2.py b/tests/topotests/bgp_bmp/test_bgp_bmp_2.py index 82d3824a1b93..21e4ce8abeae 100644 --- a/tests/topotests/bgp_bmp/test_bgp_bmp_2.py +++ b/tests/topotests/bgp_bmp/test_bgp_bmp_2.py @@ -85,9 +85,9 @@ def setup_module(mod): ) bmp_reset_seq() if DEBUG_PCAP: - tgen.gears["r1vrf"].run("rm /tmp/bmp_vrf.pcap") + pcap_file = os.path.join(tgen.logdir, "r1vrf/bmp.pcap") tgen.gears["r1vrf"].run( - "tcpdump -nni r1vrf-eth0 -s 0 -w /tmp/bmp_vrf.pcap &", stdout=None + "tcpdump -nni r1vrf-eth0 -s 0 -w {} &".format(pcap_file), stdout=None ) for rname, router in tgen.routers().items(): diff --git a/tests/topotests/lib/bmp_collector/bmpserver.py b/tests/topotests/lib/bmp_collector/bmpserver.py index a7c9743c9604..c42c3875633f 100755 --- a/tests/topotests/lib/bmp_collector/bmpserver.py +++ b/tests/topotests/lib/bmp_collector/bmpserver.py @@ -5,6 +5,8 @@ # Authored by Farid Mihoub # import argparse +import errno +import logging # XXX: something more reliable should be used "Twisted" a great choice. import os From 9712936a4188226049ace1433e5209deebc5c0c4 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 2 Dec 2024 17:07:14 +0100 Subject: [PATCH 016/106] topotests: save bgp_bmp json temp files to bmp log folder instead of /tmp Some temporary files are hardwritten in /tmp folder. Use the bmp log folder instead. Replace the bmp log file argument with bmp log folder. Signed-off-by: Philippe Guibert --- tests/topotests/bgp_bmp/bgpbmp.py | 33 ++++++++++++++++++----- tests/topotests/bgp_bmp/test_bgp_bmp_1.py | 2 +- tests/topotests/bgp_bmp/test_bgp_bmp_2.py | 2 +- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/tests/topotests/bgp_bmp/bgpbmp.py b/tests/topotests/bgp_bmp/bgpbmp.py index 950ffef2f71f..41995e2b5e53 100644 --- a/tests/topotests/bgp_bmp/bgpbmp.py +++ b/tests/topotests/bgp_bmp/bgpbmp.py @@ -49,11 +49,19 @@ def bmp_update_seq(bmp_collector, bmp_log_file): def bmp_update_expected_files( - bmp_actual, expected_prefixes, bmp_log_type, policy, step, bmp_client + bmp_actual, + expected_prefixes, + bmp_log_type, + policy, + step, + bmp_client, + bmp_log_folder, ): tgen = get_topogen() - with open(f"/tmp/bmp-{bmp_log_type}-{policy}-step{step}.json", "w") as json_file: + with open( + f"{bmp_log_folder}/tmp/bmp-{bmp_log_type}-{policy}-step{step}.json", "w" + ) as json_file: json.dump(bmp_actual, json_file, indent=4) out = bmp_client.vtysh_cmd("show bgp vrf vrf1 ipv4 json", isjson=True) @@ -70,8 +78,10 @@ def bmp_update_expected_files( continue filtered_out["routes"][pfx] = None - # ls /tmp/show*json | while read file; do egrep -v 'prefix|network|metric|ocPrf|version|weight|peerId|vrf|Version|valid|Reason|fe80' $file >$(basename $file); echo >> $(basename $file); done - with open(f"/tmp/show-bgp-ipv4-{bmp_log_type}-step{step}.json", "w") as json_file: + # ls {bmp_log_folder}/tmp/show*json | while read file; do egrep -v 'prefix|network|metric|ocPrf|version|weight|peerId|vrf|Version|valid|Reason|fe80' $file >$(basename $file); echo >> $(basename $file); done + with open( + f"{bmp_log_folder}/tmp/show-bgp-ipv4-{bmp_log_type}-step{step}.json", "w" + ) as json_file: json.dump(filtered_out, json_file, indent=4) out = tgen.gears["r1"].vtysh_cmd("show bgp vrf vrf1 ipv6 json", isjson=True) @@ -88,7 +98,9 @@ def bmp_update_expected_files( continue filtered_out["routes"][pfx] = None - with open(f"/tmp/show-bgp-ipv6-{bmp_log_type}-step{step}.json", "w") as json_file: + with open( + f"{bmp_log_folder}/tmp/show-bgp-ipv6-{bmp_log_type}-step{step}.json", "w" + ) as json_file: json.dump(filtered_out, json_file, indent=4) @@ -98,7 +110,7 @@ def bmp_check_for_prefixes( policy, step, bmp_collector, - bmp_log_file, + bmp_log_folder, bmp_client, expected_json_path, update_expected_json, @@ -111,6 +123,7 @@ def bmp_check_for_prefixes( """ global SEQ + bmp_log_file = f"{bmp_log_folder}/bmp.log" # we care only about the new messages messages = [ m @@ -173,7 +186,13 @@ def bmp_check_for_prefixes( == set(expected_prefixes) ): bmp_update_expected_files( - actual, expected_prefixes, bmp_log_type, policy, step, bmp_client + actual, + expected_prefixes, + bmp_log_type, + policy, + step, + bmp_client, + bmp_log_folder, ) return topotest.json_cmp(actual, expected, exact=True) diff --git a/tests/topotests/bgp_bmp/test_bgp_bmp_1.py b/tests/topotests/bgp_bmp/test_bgp_bmp_1.py index 9fc8e127720f..61428634414c 100644 --- a/tests/topotests/bgp_bmp/test_bgp_bmp_1.py +++ b/tests/topotests/bgp_bmp/test_bgp_bmp_1.py @@ -158,7 +158,7 @@ def _test_prefixes(policy, vrf=None, step=0): policy, step, tgen.gears["bmp1"], - os.path.join(tgen.logdir, "bmp1", "bmp.log"), + os.path.join(tgen.logdir, "bmp1"), tgen.gears["r1"], f"{CWD}/bmp1", UPDATE_EXPECTED_JSON, diff --git a/tests/topotests/bgp_bmp/test_bgp_bmp_2.py b/tests/topotests/bgp_bmp/test_bgp_bmp_2.py index 21e4ce8abeae..b45452e7c475 100644 --- a/tests/topotests/bgp_bmp/test_bgp_bmp_2.py +++ b/tests/topotests/bgp_bmp/test_bgp_bmp_2.py @@ -166,7 +166,7 @@ def _test_prefixes(policy, step=1): policy, step, tgen.gears["bmp1vrf"], - os.path.join(tgen.logdir, "bmp1vrf", "bmp.log"), + os.path.join(tgen.logdir, "bmp1vrf"), tgen.gears["r1vrf"], f"{CWD}/bmp1vrf", UPDATE_EXPECTED_JSON, From 4cdbdc8d92f93a30a9606cc69d1c48fb05f6f1e3 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 2 Dec 2024 10:33:57 -0500 Subject: [PATCH 017/106] bgpd: bgp_clist.c does not need jhash.h It's not used in bgp_clist.c so let's just remove it. Signed-off-by: Donald Sharp --- bgpd/bgp_clist.c | 1 - 1 file changed, 1 deletion(-) diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c index 6479126d0637..ca9c428b47b6 100644 --- a/bgpd/bgp_clist.c +++ b/bgpd/bgp_clist.c @@ -11,7 +11,6 @@ #include "queue.h" #include "filter.h" #include "stream.h" -#include "jhash.h" #include "frrstr.h" #include "bgpd/bgpd.h" From f0a5e78895e032ec6d2dbbd8f23cc37e8b734b93 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 2 Dec 2024 10:36:15 -0500 Subject: [PATCH 018/106] tests: bgp_lu_topo[1|2] should not use log files in /tmp Signed-off-by: Donald Sharp --- tests/topotests/bgp_lu_topo1/R3/bgpd.conf | 1 - tests/topotests/bgp_lu_topo1/R3/zebra.conf | 1 - tests/topotests/bgp_lu_topo2/R3/bgpd.conf | 1 - tests/topotests/bgp_lu_topo2/R3/staticd.conf | 1 - tests/topotests/bgp_lu_topo2/R3/zebra.conf | 1 - 5 files changed, 5 deletions(-) diff --git a/tests/topotests/bgp_lu_topo1/R3/bgpd.conf b/tests/topotests/bgp_lu_topo1/R3/bgpd.conf index 31d26ea1ed37..9ba059aeeca9 100644 --- a/tests/topotests/bgp_lu_topo1/R3/bgpd.conf +++ b/tests/topotests/bgp_lu_topo1/R3/bgpd.conf @@ -1,4 +1,3 @@ -log file /tmp/bgpd.log ! ! debug bgp updates ! diff --git a/tests/topotests/bgp_lu_topo1/R3/zebra.conf b/tests/topotests/bgp_lu_topo1/R3/zebra.conf index ea4a1482dd42..fedcd6bc3a7e 100644 --- a/tests/topotests/bgp_lu_topo1/R3/zebra.conf +++ b/tests/topotests/bgp_lu_topo1/R3/zebra.conf @@ -1,4 +1,3 @@ -log file /tmp/zebra.log ! ! debug zebra events ! debug zebra packet detail diff --git a/tests/topotests/bgp_lu_topo2/R3/bgpd.conf b/tests/topotests/bgp_lu_topo2/R3/bgpd.conf index 6443445b802b..a0dd0fe00902 100644 --- a/tests/topotests/bgp_lu_topo2/R3/bgpd.conf +++ b/tests/topotests/bgp_lu_topo2/R3/bgpd.conf @@ -1,4 +1,3 @@ -log file /tmp/bgpd.log no log unique-id ! ! diff --git a/tests/topotests/bgp_lu_topo2/R3/staticd.conf b/tests/topotests/bgp_lu_topo2/R3/staticd.conf index 867fc5a837f4..c0eee461eaab 100644 --- a/tests/topotests/bgp_lu_topo2/R3/staticd.conf +++ b/tests/topotests/bgp_lu_topo2/R3/staticd.conf @@ -1,4 +1,3 @@ -log file /tmp/staticd.log no log unique-id ! ! diff --git a/tests/topotests/bgp_lu_topo2/R3/zebra.conf b/tests/topotests/bgp_lu_topo2/R3/zebra.conf index dd24deb2141d..fd29ed54dcdf 100644 --- a/tests/topotests/bgp_lu_topo2/R3/zebra.conf +++ b/tests/topotests/bgp_lu_topo2/R3/zebra.conf @@ -1,4 +1,3 @@ -log file /tmp/zebra.log no log unique-id ! ! From 3d4e00758f2a121bd408e5c4ff639aa6eb1c58e2 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 2 Dec 2024 10:38:23 -0500 Subject: [PATCH 019/106] tests: bgp_nexthop_ipv6 remove unused reference to /tmp This code should not be outputting anything to the /tmp directory, remove commented out code Signed-off-by: Donald Sharp --- .../topotests/bgp_nexthop_ipv6/test_bgp_nexthop_ipv6_topo1.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/topotests/bgp_nexthop_ipv6/test_bgp_nexthop_ipv6_topo1.py b/tests/topotests/bgp_nexthop_ipv6/test_bgp_nexthop_ipv6_topo1.py index e478139eb1e6..7875f2e0f6a6 100644 --- a/tests/topotests/bgp_nexthop_ipv6/test_bgp_nexthop_ipv6_topo1.py +++ b/tests/topotests/bgp_nexthop_ipv6/test_bgp_nexthop_ipv6_topo1.py @@ -222,7 +222,6 @@ def test_bgp_ipv6_table_step1(): link_local_cache = {} router_list = tgen.routers().values() for router in router_list: - # router.cmd("vtysh -c 'sh bgp ipv6 json' >/tmp/show_bgp_ipv6_%s.json" % router.name) ref_file = "{}/{}/show_bgp_ipv6_step1.json".format(CWD, router.name) expected = json.loads(open(ref_file).read()) replace_link_local(expected, link_local_cache) @@ -275,7 +274,6 @@ def test_bgp_ipv6_table_step2(): router_list = tgen.routers().values() for router in router_list: - # router.cmd("vtysh -c 'sh bgp ipv6 json' >/tmp/show_bgp_ipv6_%s.json" % router.name) ref_file = "{}/{}/show_bgp_ipv6_step2.json".format(CWD, router.name) expected = json.loads(open(ref_file).read()) replace_link_local(expected, link_local_cache) @@ -327,7 +325,6 @@ def test_bgp_ipv6_table_step3(): router_list = tgen.routers().values() for router in router_list: - # router.cmd("vtysh -c 'sh bgp ipv6 json' >/tmp/show_bgp_ipv6_%s.json" % router.name) ref_file = "{}/{}/show_bgp_ipv6_step1.json".format(CWD, router.name) expected = json.loads(open(ref_file).read()) replace_link_local(expected, link_local_cache) From 92756e2bd9aa547038a3d1d14f3923a6dd1259c7 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 2 Dec 2024 10:39:13 -0500 Subject: [PATCH 020/106] tests: zebra_rib should not use /tmp for log files Signed-off-by: Donald Sharp --- tests/topotests/zebra_rib/r1/frr-import.conf | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/topotests/zebra_rib/r1/frr-import.conf b/tests/topotests/zebra_rib/r1/frr-import.conf index d07433144f89..687843be0c43 100644 --- a/tests/topotests/zebra_rib/r1/frr-import.conf +++ b/tests/topotests/zebra_rib/r1/frr-import.conf @@ -1,7 +1,6 @@ ! hostname r1 password zebra -log file /tmp/r1-frr.log ! interface r1-eth0 ip address 10.0.0.1/24 @@ -15,4 +14,4 @@ ip route 10.3.0.0/24 10.10.0.2 table 10 ip route 10.4.0.0/24 10.10.0.2 table 10 ! ip forwarding -! \ No newline at end of file +! From fa317c37d01c1752c79148ba3a082a7cc72eb56a Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 2 Dec 2024 10:40:42 -0500 Subject: [PATCH 021/106] tests: pim_cand_rp_bsr uses /tmp directory and it should not Signed-off-by: Donald Sharp --- tests/topotests/pim_cand_rp_bsr/r1/frr.conf | 2 -- tests/topotests/pim_cand_rp_bsr/r2/frr.conf | 2 -- tests/topotests/pim_cand_rp_bsr/r3/frr.conf | 2 -- tests/topotests/pim_cand_rp_bsr/r4/frr.conf | 2 -- tests/topotests/pim_cand_rp_bsr/r5/frr.conf | 2 -- tests/topotests/pim_cand_rp_bsr/r6/frr.conf | 2 -- 6 files changed, 12 deletions(-) diff --git a/tests/topotests/pim_cand_rp_bsr/r1/frr.conf b/tests/topotests/pim_cand_rp_bsr/r1/frr.conf index 899e9c068413..badcb8307b99 100644 --- a/tests/topotests/pim_cand_rp_bsr/r1/frr.conf +++ b/tests/topotests/pim_cand_rp_bsr/r1/frr.conf @@ -1,7 +1,5 @@ ! hostname r1 -password zebra -log file /tmp/r1-frr.log ! !debug pim packet !debug pim bsm diff --git a/tests/topotests/pim_cand_rp_bsr/r2/frr.conf b/tests/topotests/pim_cand_rp_bsr/r2/frr.conf index 85af461d5eb9..65926688aa01 100644 --- a/tests/topotests/pim_cand_rp_bsr/r2/frr.conf +++ b/tests/topotests/pim_cand_rp_bsr/r2/frr.conf @@ -1,7 +1,5 @@ ! hostname r2 -password zebra -log file /tmp/r2-frr.log ! !debug pim packet !debug pim bsm diff --git a/tests/topotests/pim_cand_rp_bsr/r3/frr.conf b/tests/topotests/pim_cand_rp_bsr/r3/frr.conf index 022c44ea58b7..eae90c987c33 100644 --- a/tests/topotests/pim_cand_rp_bsr/r3/frr.conf +++ b/tests/topotests/pim_cand_rp_bsr/r3/frr.conf @@ -1,7 +1,5 @@ ! hostname r3 -password zebra -log file /tmp/r3-frr.log ! !debug pim packet !debug pim bsm diff --git a/tests/topotests/pim_cand_rp_bsr/r4/frr.conf b/tests/topotests/pim_cand_rp_bsr/r4/frr.conf index 2d0a035f9a9d..276e8792160c 100644 --- a/tests/topotests/pim_cand_rp_bsr/r4/frr.conf +++ b/tests/topotests/pim_cand_rp_bsr/r4/frr.conf @@ -1,7 +1,5 @@ ! hostname r4 -password zebra -log file /tmp/r4-frr.log ! ! interface lo diff --git a/tests/topotests/pim_cand_rp_bsr/r5/frr.conf b/tests/topotests/pim_cand_rp_bsr/r5/frr.conf index 552e51f417f6..b86c62600014 100644 --- a/tests/topotests/pim_cand_rp_bsr/r5/frr.conf +++ b/tests/topotests/pim_cand_rp_bsr/r5/frr.conf @@ -1,7 +1,5 @@ ! hostname r5 -password zebra -log file /tmp/r5-frr.log ! ! interface r5-eth0 diff --git a/tests/topotests/pim_cand_rp_bsr/r6/frr.conf b/tests/topotests/pim_cand_rp_bsr/r6/frr.conf index 20955a12c709..1fd3582211cb 100644 --- a/tests/topotests/pim_cand_rp_bsr/r6/frr.conf +++ b/tests/topotests/pim_cand_rp_bsr/r6/frr.conf @@ -1,7 +1,5 @@ ! hostname r6 -password zebra -log file /tmp/r6-frr.log ! ! interface r6-eth0 From a6fe1ff7d8bce9de14a33a059f9914c371b5e194 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 2 Dec 2024 10:41:25 -0500 Subject: [PATCH 022/106] tests: simple_snmp_test should not use /tmp for logging Signed-off-by: Donald Sharp --- tests/topotests/simple_snmp_test/r1/bgpd.conf | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/topotests/simple_snmp_test/r1/bgpd.conf b/tests/topotests/simple_snmp_test/r1/bgpd.conf index 00d1e1767085..bcdf1c4f7e7e 100644 --- a/tests/topotests/simple_snmp_test/r1/bgpd.conf +++ b/tests/topotests/simple_snmp_test/r1/bgpd.conf @@ -1,4 +1,3 @@ -log file /tmp/bgpd.log debugging ! router bgp 100 bgp router-id 1.1.1.1 From b1ba753e53164eda1455368b8de84f62c4e5d838 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 2 Dec 2024 10:44:46 -0500 Subject: [PATCH 023/106] tests: pim_basic should not use /tmp for outputing of files Use the appropriate log directory. Signed-off-by: Donald Sharp --- tests/topotests/pim_basic/test_pim.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/topotests/pim_basic/test_pim.py b/tests/topotests/pim_basic/test_pim.py index ce1abe42bb09..74d5406970fe 100644 --- a/tests/topotests/pim_basic/test_pim.py +++ b/tests/topotests/pim_basic/test_pim.py @@ -132,14 +132,14 @@ def test_pim_send_mcast_stream(): # Let's establish a S,G stream from r2 -> r1 CWD = os.path.dirname(os.path.realpath(__file__)) r2.run( - "{}/mcast-tx.py --ttl 5 --count 40 --interval 2 229.1.1.1 r2-eth0 > /tmp/bar".format( - CWD + "{}/mcast-tx.py --ttl 5 --count 40 --interval 2 229.1.1.1 r2-eth0 > {}/r2/mcast_tx_output".format( + CWD, tgen.logdir ) ) # And from r3 -> r1 r3.run( - "{}/mcast-tx.py --ttl 5 --count 40 --interval 2 229.1.1.1 r3-eth0 > /tmp/bar".format( - CWD + "{}/mcast-tx.py --ttl 5 --count 40 --interval 2 229.1.1.1 r3-eth0 > {}/r3/mcast_tx_output".format( + CWD, tgen.logdir ) ) From f51c537f78eb388aa77fb46828ceb415c5c0b5fd Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 2 Dec 2024 10:46:50 -0500 Subject: [PATCH 024/106] tests: pim_autorp should not use /tmp Cleanup usage of log file into /tmp. Remove usage of debugs that will slow down test and remove password. Signed-off-by: Donald Sharp --- tests/topotests/pim_autorp/r1/frr.conf | 6 ++---- tests/topotests/pim_autorp/r2/frr.conf | 6 ++---- tests/topotests/pim_autorp/r3/frr.conf | 6 ++---- tests/topotests/pim_autorp/r4/frr.conf | 6 ++---- 4 files changed, 8 insertions(+), 16 deletions(-) diff --git a/tests/topotests/pim_autorp/r1/frr.conf b/tests/topotests/pim_autorp/r1/frr.conf index 92b9b3b41b22..fc4e634452ad 100644 --- a/tests/topotests/pim_autorp/r1/frr.conf +++ b/tests/topotests/pim_autorp/r1/frr.conf @@ -1,9 +1,7 @@ ! hostname r1 -password zebra -log file /tmp/r1-frr.log ! -debug pim autorp +!debug pim autorp ! interface r1-eth0 ip address 10.0.0.1/24 @@ -23,4 +21,4 @@ ip route 10.0.3.0/24 10.0.0.2 50 router pim autorp discovery rp 10.0.3.4 224.0.1.0/24 -! \ No newline at end of file +! diff --git a/tests/topotests/pim_autorp/r2/frr.conf b/tests/topotests/pim_autorp/r2/frr.conf index d67dade6f95f..ded462cad184 100644 --- a/tests/topotests/pim_autorp/r2/frr.conf +++ b/tests/topotests/pim_autorp/r2/frr.conf @@ -1,9 +1,7 @@ ! hostname r2 -password zebra -log file /tmp/r2-frr.log ! -debug pim autorp +!debug pim autorp ! interface r2-eth0 ip address 10.0.0.2/24 @@ -23,4 +21,4 @@ ip route 10.0.3.0/24 10.0.2.4 50 router pim autorp discovery rp 10.0.3.4 224.0.1.0/24 -! \ No newline at end of file +! diff --git a/tests/topotests/pim_autorp/r3/frr.conf b/tests/topotests/pim_autorp/r3/frr.conf index 4e93d4ba211d..31726f2c015c 100644 --- a/tests/topotests/pim_autorp/r3/frr.conf +++ b/tests/topotests/pim_autorp/r3/frr.conf @@ -1,9 +1,7 @@ ! hostname r3 -password zebra -log file /tmp/r3-frr.log ! -debug pim autorp +!debug pim autorp ! interface r3-eth0 ip address 10.0.1.3/24 @@ -23,4 +21,4 @@ ip route 10.0.2.0/24 10.0.3.4 50 router pim autorp discovery rp 10.0.3.4 224.0.1.0/24 -! \ No newline at end of file +! diff --git a/tests/topotests/pim_autorp/r4/frr.conf b/tests/topotests/pim_autorp/r4/frr.conf index 382999b11943..9d37da99aa7b 100644 --- a/tests/topotests/pim_autorp/r4/frr.conf +++ b/tests/topotests/pim_autorp/r4/frr.conf @@ -1,9 +1,7 @@ ! hostname r4 -password zebra -log file /tmp/r4-frr.log ! -debug pim autorp +!debug pim autorp ! interface r4-eth0 ip address 10.0.2.4/24 @@ -23,4 +21,4 @@ ip route 10.0.1.0/24 10.0.2.2 50 router pim autorp discovery rp 10.0.3.4 224.0.1.0/24 -! \ No newline at end of file +! From e5e59a1497e0c0acd06ef9c09da861f4c64ef69a Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 2 Dec 2024 10:48:20 -0500 Subject: [PATCH 025/106] tests: ospf_prefix_suppression should not use /tmp Signed-off-by: Donald Sharp --- tests/topotests/ospf_prefix_suppression/r1/frr.conf | 2 -- tests/topotests/ospf_prefix_suppression/r2/frr.conf | 2 -- tests/topotests/ospf_prefix_suppression/r3/frr.conf | 2 -- 3 files changed, 6 deletions(-) diff --git a/tests/topotests/ospf_prefix_suppression/r1/frr.conf b/tests/topotests/ospf_prefix_suppression/r1/frr.conf index 437b4741533a..4b9df834bf89 100644 --- a/tests/topotests/ospf_prefix_suppression/r1/frr.conf +++ b/tests/topotests/ospf_prefix_suppression/r1/frr.conf @@ -1,7 +1,5 @@ ! hostname r1 -password zebra -log file /tmp/r1-frr.log ip forwarding ! interface r1-eth0 diff --git a/tests/topotests/ospf_prefix_suppression/r2/frr.conf b/tests/topotests/ospf_prefix_suppression/r2/frr.conf index 68390f15f12b..cf4a25a09af5 100644 --- a/tests/topotests/ospf_prefix_suppression/r2/frr.conf +++ b/tests/topotests/ospf_prefix_suppression/r2/frr.conf @@ -1,7 +1,5 @@ ! hostname r2 -password zebra -log file /tmp/r1-frr.log ip forwarding ! interface r2-eth0 diff --git a/tests/topotests/ospf_prefix_suppression/r3/frr.conf b/tests/topotests/ospf_prefix_suppression/r3/frr.conf index 984a39d989c6..dbd1bc375f16 100644 --- a/tests/topotests/ospf_prefix_suppression/r3/frr.conf +++ b/tests/topotests/ospf_prefix_suppression/r3/frr.conf @@ -1,7 +1,5 @@ ! hostname r3 -password zebra -log file /tmp/r1-frr.log ip forwarding ! interface r3-eth0 From 2479d74b32b1c408a01a0b6a9a249b37a03c092e Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 2 Dec 2024 10:49:58 -0500 Subject: [PATCH 026/106] tests: ospf_p2mp should not use /tmp Signed-off-by: Donald Sharp --- tests/topotests/ospf_p2mp/r1/frr-p2mp-non-broadcast.conf | 3 --- tests/topotests/ospf_p2mp/r1/frr-p2mp.conf | 3 --- tests/topotests/ospf_p2mp/r2/frr-p2mp-non-broadcast.conf | 3 --- tests/topotests/ospf_p2mp/r2/frr-p2mp.conf | 4 ---- tests/topotests/ospf_p2mp/r3/frr-p2mp-non-broadcast.conf | 3 --- tests/topotests/ospf_p2mp/r3/frr-p2mp.conf | 4 ---- tests/topotests/ospf_p2mp/r4/frr-p2mp-non-broadcast.conf | 3 --- tests/topotests/ospf_p2mp/r4/frr-p2mp.conf | 4 ---- 8 files changed, 27 deletions(-) diff --git a/tests/topotests/ospf_p2mp/r1/frr-p2mp-non-broadcast.conf b/tests/topotests/ospf_p2mp/r1/frr-p2mp-non-broadcast.conf index ca84349cdcf2..fdc75633b1a5 100644 --- a/tests/topotests/ospf_p2mp/r1/frr-p2mp-non-broadcast.conf +++ b/tests/topotests/ospf_p2mp/r1/frr-p2mp-non-broadcast.conf @@ -1,8 +1,5 @@ ! hostname r1 -password zebra -log file /tmp/r1-frr.log -ip forwarding ! interface r1-eth0 ip address 10.1.0.1/24 diff --git a/tests/topotests/ospf_p2mp/r1/frr-p2mp.conf b/tests/topotests/ospf_p2mp/r1/frr-p2mp.conf index 89f255bb44ea..350c0de7baf6 100644 --- a/tests/topotests/ospf_p2mp/r1/frr-p2mp.conf +++ b/tests/topotests/ospf_p2mp/r1/frr-p2mp.conf @@ -1,13 +1,10 @@ ! -!log file ospfd.log debug ! debug ospf event ! debug ospf client ! debug ospf lsa ! debug ospf packet all hostname r1 -password zebra -log file /tmp/r1-frr.log ip forwarding ! interface r1-eth0 diff --git a/tests/topotests/ospf_p2mp/r2/frr-p2mp-non-broadcast.conf b/tests/topotests/ospf_p2mp/r2/frr-p2mp-non-broadcast.conf index 6e26897c494b..c44e936f9d99 100644 --- a/tests/topotests/ospf_p2mp/r2/frr-p2mp-non-broadcast.conf +++ b/tests/topotests/ospf_p2mp/r2/frr-p2mp-non-broadcast.conf @@ -1,8 +1,5 @@ ! hostname r2 -password zebra -log file /tmp/r1-frr.log -ip forwarding ! interface r2-eth0 ip address 10.1.0.2/24 diff --git a/tests/topotests/ospf_p2mp/r2/frr-p2mp.conf b/tests/topotests/ospf_p2mp/r2/frr-p2mp.conf index 429330987e06..806914d81421 100644 --- a/tests/topotests/ospf_p2mp/r2/frr-p2mp.conf +++ b/tests/topotests/ospf_p2mp/r2/frr-p2mp.conf @@ -1,14 +1,10 @@ ! -!log file ospfd.log debug ! debug ospf event ! debug ospf client ! debug ospf lsa ! debug ospf packet all ! hostname r2 -password zebra -log file /tmp/r1-frr.log -ip forwarding ! interface r2-eth0 ip address 10.1.0.2/24 diff --git a/tests/topotests/ospf_p2mp/r3/frr-p2mp-non-broadcast.conf b/tests/topotests/ospf_p2mp/r3/frr-p2mp-non-broadcast.conf index a69e0557bee7..d89269b3244f 100644 --- a/tests/topotests/ospf_p2mp/r3/frr-p2mp-non-broadcast.conf +++ b/tests/topotests/ospf_p2mp/r3/frr-p2mp-non-broadcast.conf @@ -1,8 +1,5 @@ ! hostname r3 -password zebra -log file /tmp/r1-frr.log -ip forwarding ! interface r3-eth0 ip address 10.1.0.3/24 diff --git a/tests/topotests/ospf_p2mp/r3/frr-p2mp.conf b/tests/topotests/ospf_p2mp/r3/frr-p2mp.conf index eada78450e81..343a9d008627 100644 --- a/tests/topotests/ospf_p2mp/r3/frr-p2mp.conf +++ b/tests/topotests/ospf_p2mp/r3/frr-p2mp.conf @@ -1,14 +1,10 @@ ! -!log file ospfd.log debug ! debug ospf event ! debug ospf client ! debug ospf lsa ! debug ospf packet all ! hostname r3 -password zebra -log file /tmp/r1-frr.log -ip forwarding ! interface r3-eth0 ip address 10.1.0.3/24 diff --git a/tests/topotests/ospf_p2mp/r4/frr-p2mp-non-broadcast.conf b/tests/topotests/ospf_p2mp/r4/frr-p2mp-non-broadcast.conf index 1b8388584b82..aa6c80d41e2b 100644 --- a/tests/topotests/ospf_p2mp/r4/frr-p2mp-non-broadcast.conf +++ b/tests/topotests/ospf_p2mp/r4/frr-p2mp-non-broadcast.conf @@ -1,8 +1,5 @@ ! hostname r4 -password zebra -log file /tmp/r1-frr.log -ip forwarding ! interface r4-eth0 ip address 10.1.0.4/24 diff --git a/tests/topotests/ospf_p2mp/r4/frr-p2mp.conf b/tests/topotests/ospf_p2mp/r4/frr-p2mp.conf index 3146ea095762..a1527f5aa989 100644 --- a/tests/topotests/ospf_p2mp/r4/frr-p2mp.conf +++ b/tests/topotests/ospf_p2mp/r4/frr-p2mp.conf @@ -1,14 +1,10 @@ ! -!log file ospfd.log debug ! debug ospf event ! debug ospf client ! debug ospf lsa ! debug ospf packet all ! hostname r4 -password zebra -log file /tmp/r1-frr.log -ip forwarding ! interface r4-eth0 ip address 10.1.0.4/24 From 554766390ea8ee697f3b4165cac34c4469645e39 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 2 Dec 2024 10:51:13 -0500 Subject: [PATCH 027/106] tests: ospf_netns_vrf should not use /tmp Signed-off-by: Donald Sharp --- tests/topotests/ospf_netns_vrf/r1/ospfd.conf | 2 -- tests/topotests/ospf_netns_vrf/r1/zebra.conf | 2 -- tests/topotests/ospf_netns_vrf/r2/ospfd.conf | 2 -- tests/topotests/ospf_netns_vrf/r2/zebra.conf | 2 -- tests/topotests/ospf_netns_vrf/r3/ospfd.conf | 2 -- tests/topotests/ospf_netns_vrf/r3/zebra.conf | 2 -- 6 files changed, 12 deletions(-) diff --git a/tests/topotests/ospf_netns_vrf/r1/ospfd.conf b/tests/topotests/ospf_netns_vrf/r1/ospfd.conf index ba131465612b..75f38d0058cb 100644 --- a/tests/topotests/ospf_netns_vrf/r1/ospfd.conf +++ b/tests/topotests/ospf_netns_vrf/r1/ospfd.conf @@ -1,7 +1,5 @@ ! hostname r1 -password zebra -log file /tmp/r1-ospfd.log ! interface r1-eth0 vrf r1-ospf-cust1 ip ospf hello-interval 1 diff --git a/tests/topotests/ospf_netns_vrf/r1/zebra.conf b/tests/topotests/ospf_netns_vrf/r1/zebra.conf index 56d7a9764e01..1c08f1e26333 100644 --- a/tests/topotests/ospf_netns_vrf/r1/zebra.conf +++ b/tests/topotests/ospf_netns_vrf/r1/zebra.conf @@ -4,8 +4,6 @@ ! debug zebra event ! hostname r1 -password zebra -log file /tmp/r1-zebra.log ! interface r1-eth0 vrf r1-ospf-cust1 ip address 10.0.1.1/24 diff --git a/tests/topotests/ospf_netns_vrf/r2/ospfd.conf b/tests/topotests/ospf_netns_vrf/r2/ospfd.conf index 01b6b1526b1c..3cd69bb8ff15 100644 --- a/tests/topotests/ospf_netns_vrf/r2/ospfd.conf +++ b/tests/topotests/ospf_netns_vrf/r2/ospfd.conf @@ -1,7 +1,5 @@ ! hostname r2 -password zebra -log file /tmp/r2-ospfd.log ! interface r2-eth0 vrf r2-ospf-cust1 ip ospf hello-interval 1 diff --git a/tests/topotests/ospf_netns_vrf/r2/zebra.conf b/tests/topotests/ospf_netns_vrf/r2/zebra.conf index 6ff72d1267f6..f997028c740c 100644 --- a/tests/topotests/ospf_netns_vrf/r2/zebra.conf +++ b/tests/topotests/ospf_netns_vrf/r2/zebra.conf @@ -1,7 +1,5 @@ ! hostname r2 -password zebra -log file /tmp/r2-zebra.log ! interface r2-eth0 vrf r2-ospf-cust1 ip address 10.0.2.1/24 diff --git a/tests/topotests/ospf_netns_vrf/r3/ospfd.conf b/tests/topotests/ospf_netns_vrf/r3/ospfd.conf index abfaa5b9eff1..4581a609b486 100644 --- a/tests/topotests/ospf_netns_vrf/r3/ospfd.conf +++ b/tests/topotests/ospf_netns_vrf/r3/ospfd.conf @@ -1,7 +1,5 @@ ! hostname r3 -password zebra -log file /tmp/r3-ospfd.log ! ! interface r3-eth0 vrf r3-ospf-cust1 diff --git a/tests/topotests/ospf_netns_vrf/r3/zebra.conf b/tests/topotests/ospf_netns_vrf/r3/zebra.conf index 15341500480a..4053d94a63e5 100644 --- a/tests/topotests/ospf_netns_vrf/r3/zebra.conf +++ b/tests/topotests/ospf_netns_vrf/r3/zebra.conf @@ -1,7 +1,5 @@ ! hostname r3 -password zebra -log file /tmp/r3-zebra.log ! interface r3-eth0 vrf r3-ospf-cust1 ip address 10.0.3.1/24 From 1cacc25ec1bcebd5a9d068e9501e56909b94162a Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 2 Dec 2024 10:52:01 -0500 Subject: [PATCH 028/106] tests: ospf_multi_vrf_bgp_route_leak should not use /tmp Signed-off-by: Donald Sharp --- tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/frr.conf | 2 -- tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/frr.conf | 2 -- tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/frr.conf | 2 -- tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/frr.conf | 2 -- 4 files changed, 8 deletions(-) diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/frr.conf b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/frr.conf index 995958132c93..bcbe2eded6c6 100644 --- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/frr.conf +++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/frr.conf @@ -1,7 +1,5 @@ ! hostname r1 -password zebra -log file /tmp/r1-frr.log ! interface r1-eth0 ip address 10.0.1.1/24 diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/frr.conf b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/frr.conf index 29909de6461d..0d3eb3c8c915 100644 --- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/frr.conf +++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/frr.conf @@ -1,7 +1,5 @@ ! hostname r2 -password zebra -log file /tmp/r2-frr.log ! interface r2-eth0 ip address 10.0.2.2/24 diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/frr.conf b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/frr.conf index 35fe22e9f9bc..1cc2972f0133 100644 --- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/frr.conf +++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/frr.conf @@ -1,7 +1,5 @@ ! hostname r3 -password zebra -log file /tmp/r3-frr.log ! interface r3-eth0 ip address 10.0.3.3/24 diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/frr.conf b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/frr.conf index 721c3d91c388..a82d5b033cf1 100644 --- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/frr.conf +++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/frr.conf @@ -1,7 +1,5 @@ ! hostname r4 -password zebra -log file /tmp/r4-frr.log ! interface r4-eth0 ip address 10.0.4.4/24 From 65187ff4b46b015e0a4bd0a7824bfb7f93d0672c Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 2 Dec 2024 10:52:40 -0500 Subject: [PATCH 029/106] tests: ospf_multi_instance should not use /tmp Signed-off-by: Donald Sharp --- tests/topotests/ospf_multi_instance/r1/frr.conf | 3 --- tests/topotests/ospf_multi_instance/r3/frr.conf | 3 --- 2 files changed, 6 deletions(-) diff --git a/tests/topotests/ospf_multi_instance/r1/frr.conf b/tests/topotests/ospf_multi_instance/r1/frr.conf index c341a7176a09..b9752c63ad96 100644 --- a/tests/topotests/ospf_multi_instance/r1/frr.conf +++ b/tests/topotests/ospf_multi_instance/r1/frr.conf @@ -1,8 +1,5 @@ ! hostname r1 -password zebra -log file /tmp/r1-frr.log -ip forwarding ! interface lo ip address 1.1.1.1/32 diff --git a/tests/topotests/ospf_multi_instance/r3/frr.conf b/tests/topotests/ospf_multi_instance/r3/frr.conf index 97a3e19c9b10..e6f681a46206 100644 --- a/tests/topotests/ospf_multi_instance/r3/frr.conf +++ b/tests/topotests/ospf_multi_instance/r3/frr.conf @@ -1,8 +1,5 @@ ! hostname r3 -password zebra -log file /tmp/r3-frr.log -ip forwarding ! interface lo ip address 3.3.3.1/32 From 35056d0b2d8cbb4ee3c218d330c76d666f1ebeef Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 2 Dec 2024 10:55:09 -0500 Subject: [PATCH 030/106] tests: ospf_metric_propagation do not use /tmp Signed-off-by: Donald Sharp --- tests/topotests/ospf_metric_propagation/h1/frr.conf | 4 +--- tests/topotests/ospf_metric_propagation/h2/frr.conf | 4 +--- tests/topotests/ospf_metric_propagation/r1/frr.conf | 5 +---- tests/topotests/ospf_metric_propagation/r2/frr.conf | 3 --- tests/topotests/ospf_metric_propagation/r3/frr.conf | 3 --- tests/topotests/ospf_metric_propagation/r4/frr.conf | 3 --- tests/topotests/ospf_metric_propagation/ra/frr.conf | 3 --- tests/topotests/ospf_metric_propagation/rb/frr.conf | 3 --- tests/topotests/ospf_metric_propagation/rc/frr.conf | 3 --- 9 files changed, 3 insertions(+), 28 deletions(-) diff --git a/tests/topotests/ospf_metric_propagation/h1/frr.conf b/tests/topotests/ospf_metric_propagation/h1/frr.conf index 1196a192dd50..b8d1834e24ca 100644 --- a/tests/topotests/ospf_metric_propagation/h1/frr.conf +++ b/tests/topotests/ospf_metric_propagation/h1/frr.conf @@ -1,10 +1,8 @@ ! hostname h1 -password zebra -log file /tmp/h1-frr.log ! ip route 0.0.0.0/0 10.0.91.1 ! interface h1-eth0 ip address 10.0.91.2/24 -! \ No newline at end of file +! diff --git a/tests/topotests/ospf_metric_propagation/h2/frr.conf b/tests/topotests/ospf_metric_propagation/h2/frr.conf index f951fe6ba1d6..4377256261b3 100644 --- a/tests/topotests/ospf_metric_propagation/h2/frr.conf +++ b/tests/topotests/ospf_metric_propagation/h2/frr.conf @@ -1,10 +1,8 @@ ! hostname h2 -password zebra -log file /tmp/h2-frr.log ! ip route 0.0.0.0/0 10.0.94.4 ! interface h2-eth0 ip address 10.0.94.2/24 -! \ No newline at end of file +! diff --git a/tests/topotests/ospf_metric_propagation/r1/frr.conf b/tests/topotests/ospf_metric_propagation/r1/frr.conf index 4966e6a9da1b..082f7df51936 100644 --- a/tests/topotests/ospf_metric_propagation/r1/frr.conf +++ b/tests/topotests/ospf_metric_propagation/r1/frr.conf @@ -1,8 +1,5 @@ ! hostname r1 -password zebra -log file /tmp/r1-frr.log -ip forwarding ! interface r1-eth0 ip address 10.0.1.1/24 @@ -93,4 +90,4 @@ route-map costplus permit 30 route-map costplus permit 40 set metric-type type-1 set metric +1 - exit \ No newline at end of file + exit diff --git a/tests/topotests/ospf_metric_propagation/r2/frr.conf b/tests/topotests/ospf_metric_propagation/r2/frr.conf index 0ac5001b1b99..e6ced31d876e 100644 --- a/tests/topotests/ospf_metric_propagation/r2/frr.conf +++ b/tests/topotests/ospf_metric_propagation/r2/frr.conf @@ -1,8 +1,5 @@ ! hostname r2 -password zebra -log file /tmp/r2-frr.log -ip forwarding ! interface r2-eth0 ip address 10.0.1.2/24 diff --git a/tests/topotests/ospf_metric_propagation/r3/frr.conf b/tests/topotests/ospf_metric_propagation/r3/frr.conf index 0859173f7971..f6989057f66a 100644 --- a/tests/topotests/ospf_metric_propagation/r3/frr.conf +++ b/tests/topotests/ospf_metric_propagation/r3/frr.conf @@ -1,8 +1,5 @@ ! hostname r3 -password zebra -log file /tmp/r3-frr.log -ip forwarding ! interface r3-eth0 ip address 10.0.3.3/24 diff --git a/tests/topotests/ospf_metric_propagation/r4/frr.conf b/tests/topotests/ospf_metric_propagation/r4/frr.conf index 743da272727f..b02ae18fc147 100644 --- a/tests/topotests/ospf_metric_propagation/r4/frr.conf +++ b/tests/topotests/ospf_metric_propagation/r4/frr.conf @@ -1,8 +1,5 @@ ! hostname r4 -password zebra -log file /tmp/r4-frr.log -ip forwarding ! interface r4-eth0 ip address 10.0.3.4/24 diff --git a/tests/topotests/ospf_metric_propagation/ra/frr.conf b/tests/topotests/ospf_metric_propagation/ra/frr.conf index 2434faeabc97..5ad819da01bb 100644 --- a/tests/topotests/ospf_metric_propagation/ra/frr.conf +++ b/tests/topotests/ospf_metric_propagation/ra/frr.conf @@ -1,8 +1,5 @@ ! hostname ra -password zebra -log file /tmp/ra-frr.log -ip forwarding ! interface ra-eth0 ip address 10.0.50.5/24 diff --git a/tests/topotests/ospf_metric_propagation/rb/frr.conf b/tests/topotests/ospf_metric_propagation/rb/frr.conf index b83532a8405a..21abefed2604 100644 --- a/tests/topotests/ospf_metric_propagation/rb/frr.conf +++ b/tests/topotests/ospf_metric_propagation/rb/frr.conf @@ -1,8 +1,5 @@ ! hostname rb -password zebra -log file /tmp/rb-frr.log -ip forwarding ! interface rb-eth0 ip address 10.0.50.6/24 diff --git a/tests/topotests/ospf_metric_propagation/rc/frr.conf b/tests/topotests/ospf_metric_propagation/rc/frr.conf index dd8077c3949f..0e6edd92a830 100644 --- a/tests/topotests/ospf_metric_propagation/rc/frr.conf +++ b/tests/topotests/ospf_metric_propagation/rc/frr.conf @@ -1,8 +1,5 @@ ! hostname rc -password zebra -log file /tmp/rc-frr.log -ip forwarding ! interface rc-eth0 ip address 10.0.70.7/24 From a7aacf609a55dac7c40d55b4ce0b4853d3cb5a88 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 2 Dec 2024 10:57:41 -0500 Subject: [PATCH 031/106] tests: bgp_snmp_mplsl3vpn should not use /tmp directory Signed-off-by: Donald Sharp --- tests/topotests/bgp_snmp_mplsl3vpn/ce1/bgpd.conf | 1 - tests/topotests/bgp_snmp_mplsl3vpn/ce1/zebra.conf | 2 -- tests/topotests/bgp_snmp_mplsl3vpn/ce2/bgpd.conf | 1 - tests/topotests/bgp_snmp_mplsl3vpn/ce2/zebra.conf | 2 -- tests/topotests/bgp_snmp_mplsl3vpn/ce3/bgpd.conf | 1 - tests/topotests/bgp_snmp_mplsl3vpn/ce3/zebra.conf | 2 -- tests/topotests/bgp_snmp_mplsl3vpn/ce4/bgpd.conf | 1 - tests/topotests/bgp_snmp_mplsl3vpn/ce4/zebra.conf | 2 -- tests/topotests/bgp_snmp_mplsl3vpn/r1/bgpd.conf | 1 - tests/topotests/bgp_snmp_mplsl3vpn/r2/zebra.conf | 2 -- tests/topotests/bgp_snmp_mplsl3vpn/r3/zebra.conf | 2 -- tests/topotests/bgp_snmp_mplsl3vpn/r4/bgpd.conf | 1 - tests/topotests/bgp_snmp_mplsl3vpn/r4/zebra.conf | 2 -- 13 files changed, 20 deletions(-) diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/ce1/bgpd.conf b/tests/topotests/bgp_snmp_mplsl3vpn/ce1/bgpd.conf index b598666dfb02..75d8c9e553b9 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/ce1/bgpd.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/ce1/bgpd.conf @@ -1,4 +1,3 @@ -log file /tmp/bgpd.log debugging ! router bgp 65001 timers bgp 3 9 diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/ce1/zebra.conf b/tests/topotests/bgp_snmp_mplsl3vpn/ce1/zebra.conf index 4a8579845c89..8e6743c5fd93 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/ce1/zebra.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/ce1/zebra.conf @@ -1,5 +1,3 @@ -log file /tmp/zebra.log -log stdout ! ! debug zebra events ! debug zebra dplane diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/ce2/bgpd.conf b/tests/topotests/bgp_snmp_mplsl3vpn/ce2/bgpd.conf index e388ccba8a75..37d40651c533 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/ce2/bgpd.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/ce2/bgpd.conf @@ -1,4 +1,3 @@ -log file /tmp/bgpd.log debugging ! router bgp 65001 bgp router-id 192.168.200.10 diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/ce2/zebra.conf b/tests/topotests/bgp_snmp_mplsl3vpn/ce2/zebra.conf index 5e0aa5d3f038..02afea1148b7 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/ce2/zebra.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/ce2/zebra.conf @@ -1,5 +1,3 @@ -log file /tmp/zebra.log -log stdout ! ! debug zebra events ! debug zebra dplane diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/ce3/bgpd.conf b/tests/topotests/bgp_snmp_mplsl3vpn/ce3/bgpd.conf index e388ccba8a75..37d40651c533 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/ce3/bgpd.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/ce3/bgpd.conf @@ -1,4 +1,3 @@ -log file /tmp/bgpd.log debugging ! router bgp 65001 bgp router-id 192.168.200.10 diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/ce3/zebra.conf b/tests/topotests/bgp_snmp_mplsl3vpn/ce3/zebra.conf index fabc11e84d79..714f1ec356f0 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/ce3/zebra.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/ce3/zebra.conf @@ -1,5 +1,3 @@ -log file /tmp/zebra.log -log stdout ! ! debug zebra events ! debug zebra dplane diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/ce4/bgpd.conf b/tests/topotests/bgp_snmp_mplsl3vpn/ce4/bgpd.conf index e388ccba8a75..37d40651c533 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/ce4/bgpd.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/ce4/bgpd.conf @@ -1,4 +1,3 @@ -log file /tmp/bgpd.log debugging ! router bgp 65001 bgp router-id 192.168.200.10 diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/ce4/zebra.conf b/tests/topotests/bgp_snmp_mplsl3vpn/ce4/zebra.conf index e369f41b39e9..d5efab4bf6f4 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/ce4/zebra.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/ce4/zebra.conf @@ -1,5 +1,3 @@ -log file /tmp/zebra.log -log stdout ! ! debug zebra events ! debug zebra dplane diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/r1/bgpd.conf b/tests/topotests/bgp_snmp_mplsl3vpn/r1/bgpd.conf index 098e55d0ed34..b80a90ac7d1e 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/r1/bgpd.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/r1/bgpd.conf @@ -1,4 +1,3 @@ -log file /tmp/bgpd.log debugging ! router bgp 65000 bgp router-id 10.1.1.1 diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/r2/zebra.conf b/tests/topotests/bgp_snmp_mplsl3vpn/r2/zebra.conf index 4fec8af3dbeb..87cffebd8437 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/r2/zebra.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/r2/zebra.conf @@ -1,5 +1,3 @@ -log file /tmp/zebra.log -log stdout ! ! debug zebra events ! debug zebra dplane diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/r3/zebra.conf b/tests/topotests/bgp_snmp_mplsl3vpn/r3/zebra.conf index e43399559377..162f5bbccc47 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/r3/zebra.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/r3/zebra.conf @@ -1,5 +1,3 @@ -log file /tmp/zebra.log -log stdout ! ! debug zebra events ! debug zebra dplane diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/r4/bgpd.conf b/tests/topotests/bgp_snmp_mplsl3vpn/r4/bgpd.conf index 2a834c799ef2..1f44feb0da59 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/r4/bgpd.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/r4/bgpd.conf @@ -1,4 +1,3 @@ -log file /tmp/bgpd.log debugging ! router bgp 65000 bgp router-id 10.4.4.4 diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/r4/zebra.conf b/tests/topotests/bgp_snmp_mplsl3vpn/r4/zebra.conf index 14580e5b3a36..7b0719d266f1 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/r4/zebra.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/r4/zebra.conf @@ -1,5 +1,3 @@ -log file /tmp/zebra.log -log stdout ! ! debug zebra events ! debug zebra dplane From 01d289f21f29ea7f9e0acd43d91cf02b9f06c4bc Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 2 Dec 2024 10:59:07 -0500 Subject: [PATCH 032/106] tests: bgp_route_server_client should not use /tmp Signed-off-by: Donald Sharp --- .../bgp_route_server_client/test_bgp_route_server_client.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py b/tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py index a6334918dfcb..9dfeec6de0d6 100644 --- a/tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py +++ b/tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py @@ -180,7 +180,6 @@ def test_bgp_route_server_client_step1(): else: cmd = "show bgp ipv6 unicast json" - # router.cmd("vtysh -c 'sh bgp ipv6 json' >/tmp/show_bgp_ipv6_%s.json" % router.name) ref_file = "{}/{}/show_bgp_ipv6_step1.json".format(CWD, router.name) expected = json.loads(open(ref_file).read()) replace_link_local(expected, link_local_cache) @@ -230,7 +229,6 @@ def test_bgp_route_server_client_step2(): else: cmd = "show bgp ipv6 unicast json" - # router.cmd("vtysh -c 'sh bgp ipv6 json' >/tmp/show_bgp_ipv6_%s.json" % router.name) ref_file = "{}/{}/show_bgp_ipv6_step2.json".format(CWD, router.name) expected = json.loads(open(ref_file).read()) replace_link_local(expected, link_local_cache) @@ -286,7 +284,6 @@ def test_bgp_route_server_client_step3(): else: cmd = "show bgp ipv6 unicast json" - # router.cmd("vtysh -c 'sh bgp ipv6 json' >/tmp/show_bgp_ipv6_%s.json" % router.name) ref_file = "{}/{}/show_bgp_ipv6_step1.json".format(CWD, router.name) expected = json.loads(open(ref_file).read()) replace_link_local(expected, link_local_cache) From b519572020a29f74262f2abacfb50e85d6b81487 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 27 Nov 2024 08:07:35 +0200 Subject: [PATCH 033/106] bgpd: Use peer group's member for BGP notify instead of the peer-group Fixes: eacf923b00c019e9a877c9716e5d6506594d532e ("bgpd: Fix pattern of usage in bgp_notify_config_change") Signed-off-by: Donatas Abraitis --- bgpd/bgpd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index f92ae969f8c4..2f184894d350 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -5703,7 +5703,7 @@ void peer_update_source_addr_set(struct peer *peer, const union sockunion *su) member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; /* Send notification or reset peer depending on state. */ - if (!peer_notify_config_change(peer->connection)) + if (!peer_notify_config_change(member->connection)) bgp_session_reset(member); /* Apply new source configuration to BFD session. */ From c2079f20a26e4da841e092f3feea6b957154fc88 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Sun, 1 Dec 2024 14:32:08 +0200 Subject: [PATCH 034/106] bgpd: Initialize as_type for peer-group as AS_UNSPECIFIED Previously AS_UNSPECIFIED was treated as 0, but with now it's 1 after renumbering peer_asn_type enum. Fixes: 0dfe25697f5299326046fcfb66f2c6beca7c423c ("bgpd: Implement neighbor X remote-as auto") Signed-off-by: Donatas Abraitis --- bgpd/bgpd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 2f184894d350..dccac3eceb19 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2859,6 +2859,7 @@ struct peer_group *peer_group_get(struct bgp *bgp, const char *name) group->conf->host = XSTRDUP(MTYPE_BGP_PEER_HOST, name); group->conf->group = group; group->conf->as = 0; + group->conf->as_type = AS_UNSPECIFIED; group->conf->ttl = BGP_DEFAULT_TTL; group->conf->gtsm_hops = BGP_GTSM_HOPS_DISABLED; group->conf->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; From e0d6005d9780c93a381f6832d5531f02bef6e582 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Sun, 1 Dec 2024 14:49:40 +0200 Subject: [PATCH 035/106] tests: Check if remote-as is not flushed once peer-group applied Signed-off-by: Donatas Abraitis --- tests/topotests/bgp_peer_group/r1/frr.conf | 7 +++++ tests/topotests/bgp_peer_group/r4/frr.conf | 7 +++++ .../bgp_peer_group/test_bgp_peer-group.py | 29 ++++++++++++++++++- 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 tests/topotests/bgp_peer_group/r4/frr.conf diff --git a/tests/topotests/bgp_peer_group/r1/frr.conf b/tests/topotests/bgp_peer_group/r1/frr.conf index 035c8e4cf16e..cf9d16c91849 100644 --- a/tests/topotests/bgp_peer_group/r1/frr.conf +++ b/tests/topotests/bgp_peer_group/r1/frr.conf @@ -5,6 +5,9 @@ interface r1-eth0 interface r1-eth1 ip address 192.168.251.1/30 ! +interface r1-eth2 + ip address 192.168.252.1/30 +! ip forwarding ! router bgp 65001 @@ -17,5 +20,9 @@ router bgp 65001 neighbor PG1 remote-as external neighbor PG1 timers 3 20 neighbor PG1 graceful-restart-disable + neighbor PG2 peer-group + neighbor PG2 local-as 65554 no-prepend replace-as neighbor 192.168.251.2 peer-group PG1 + neighbor 192.168.252.2 remote-as 65004 + neighbor 192.168.252.2 peer-group PG2 ! diff --git a/tests/topotests/bgp_peer_group/r4/frr.conf b/tests/topotests/bgp_peer_group/r4/frr.conf new file mode 100644 index 000000000000..b1da90f0644e --- /dev/null +++ b/tests/topotests/bgp_peer_group/r4/frr.conf @@ -0,0 +1,7 @@ +! +interface r4-eth0 + ip address 192.168.252.2/30 +! +router bgp 65004 + neighbor 192.168.252.1 remote-as external +! diff --git a/tests/topotests/bgp_peer_group/test_bgp_peer-group.py b/tests/topotests/bgp_peer_group/test_bgp_peer-group.py index 45f713b8a240..e98d5f8b3b07 100644 --- a/tests/topotests/bgp_peer_group/test_bgp_peer-group.py +++ b/tests/topotests/bgp_peer_group/test_bgp_peer-group.py @@ -30,7 +30,7 @@ def build_topo(tgen): - for routern in range(1, 4): + for routern in range(1, 5): tgen.add_router("r{}".format(routern)) switch = tgen.add_switch("s1") @@ -42,6 +42,10 @@ def build_topo(tgen): switch.add_link(tgen.gears["r1"]) switch.add_link(tgen.gears["r2"]) + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r4"]) + def setup_module(mod): tgen = Topogen(build_topo, mod.__name__) @@ -84,6 +88,11 @@ def _bgp_peer_group_configured(): "bgpState": "Established", "neighborCapabilities": {"gracefulRestart": "received"}, }, + "192.168.252.2": { + "peerGroup": "PG2", + "bgpState": "Established", + "neighborCapabilities": {"gracefulRestart": "advertisedAndReceived"}, + }, } return topotest.json_cmp(output, expected) @@ -110,6 +119,24 @@ def _bgp_peer_group_check_advertised_routes(): assert result is None, "Failed checking advertised routes from r3" +def test_show_running_remote_as_peer_group(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + output = ( + tgen.gears["r1"] + .cmd( + 'vtysh -c "show running bgpd" | grep "^ neighbor 192.168.252.2 remote-as 65004"' + ) + .rstrip() + ) + assert ( + output == " neighbor 192.168.252.2 remote-as 65004" + ), "192.168.252.2 remote-as is flushed" + + def test_bgp_peer_group_remote_as_del_readd(): tgen = get_topogen() From 719f6e2e7f0b4f2c076df045a4d07cc7add6630e Mon Sep 17 00:00:00 2001 From: Mark Stapp Date: Wed, 30 Oct 2024 11:02:17 -0400 Subject: [PATCH 036/106] zebra: separate zebra ZAPI server open and accept Separate zebra's ZAPI server socket handling into two phases: an early phase that opens the socket, and a later phase that starts listening for client connections. Signed-off-by: Mark Stapp --- zebra/main.c | 3 +++ zebra/zserv.c | 32 ++++++++++++++++++++++++++++++-- zebra/zserv.h | 15 ++++++++++++--- 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/zebra/main.c b/zebra/main.c index 138a955bc313..4546d1477009 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -467,6 +467,9 @@ int main(int argc, char **argv) zebra_if_init(); zebra_debug_init(); + /* Open Zebra API server socket */ + zserv_open(zserv_path); + /* * Initialize NS( and implicitly the VRF module), and make kernel * routing socket. */ diff --git a/zebra/zserv.c b/zebra/zserv.c index 07e399664316..d6c017d259e4 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -57,6 +57,7 @@ extern struct zebra_privs_t zserv_privs; /* The listener socket for clients connecting to us */ static int zsock; +static bool started_p; /* The lock that protects access to zapi client objects */ static pthread_mutex_t client_mutex; @@ -929,9 +930,16 @@ void zserv_close(void) /* Free client list's mutex */ pthread_mutex_destroy(&client_mutex); + + started_p = false; } -void zserv_start(char *path) + +/* + * Open zebra's ZAPI listener socket. This is done early during startup, + * before zebra is ready to listen and accept client connections. + */ +void zserv_open(const char *path) { int ret; mode_t old_mask; @@ -973,6 +981,26 @@ void zserv_start(char *path) path, safe_strerror(errno)); close(zsock); zsock = -1; + } + + umask(old_mask); +} + +/* + * Start listening for ZAPI client connections. + */ +void zserv_start(const char *path) +{ + int ret; + + /* This may be called more than once during startup - potentially once + * per netns - but only do this work once. + */ + if (started_p) + return; + + if (zsock <= 0) { + flog_err_sys(EC_LIB_SOCKET, "Zserv socket open failed"); return; } @@ -986,7 +1014,7 @@ void zserv_start(char *path) return; } - umask(old_mask); + started_p = true; zserv_event(NULL, ZSERV_ACCEPT); } diff --git a/zebra/zserv.h b/zebra/zserv.h index 87d2b4adbf81..ce47ef19fa36 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -255,16 +255,25 @@ extern void zserv_init(void); */ extern void zserv_close(void); +/* + * Open Zebra API server socket. + * + * Create and open the server socket. + * + * path + * where to place the Unix domain socket + */ +extern void zserv_open(const char *path); + /* * Start Zebra API server. * - * Allocates resources, creates the server socket and begins listening on the - * socket. + * Allocates resources and begins listening on the server socket. * * path * where to place the Unix domain socket */ -extern void zserv_start(char *path); +extern void zserv_start(const char *path); /* * Send a message to a connected Zebra API client. From 9bce8f0bd0d5d67a1dc1a9fc2d7d618422d51fda Mon Sep 17 00:00:00 2001 From: Corey Siltala Date: Tue, 26 Nov 2024 10:04:14 -0600 Subject: [PATCH 037/106] pimd: Fix access-list memory leak in pimd Reset access-lists in pimd on terminate Signed-off-by: Corey Siltala --- pimd/pimd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pimd/pimd.c b/pimd/pimd.c index a390378a5abf..c1de58550a39 100644 --- a/pimd/pimd.c +++ b/pimd/pimd.c @@ -17,6 +17,7 @@ #include "vrf.h" #include "lib_errors.h" #include "bfd.h" +#include "filter.h" #include "pimd.h" #if PIM_IPV == 4 @@ -147,6 +148,7 @@ void pim_terminate(void) prefix_list_add_hook(NULL); prefix_list_delete_hook(NULL); prefix_list_reset(); + access_list_reset(); pim_vxlan_terminate(); pim_vrf_terminate(); From 4e253c60bd3b70376afd5b09cc61e67af0a4dc61 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 3 Dec 2024 12:08:12 -0500 Subject: [PATCH 038/106] lib: Fix session re-establishment Currently if you have this sequence of events: a) BGP starts b) BGP reads cli that has bfd configuration c) BGP attempts to install bfd configuration but fails because zebra is not connected to yet d) BGP connects to zebra e) BGP receives resend bfd code from bfdd f) BGP was not sending down the unsent data to bfd, never causing the bfd session to be established. So effectively bfd was attempting to install but failed and then when it was asked to replay everything it decided that the bfd information for a particular peer was actually installed and does not need to be resent. Modify the code such that the bfd code now tracks failed installation and allows the resend of data to bfdd. Signed-off-by: Donald Sharp --- lib/bfd.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/bfd.c b/lib/bfd.c index 4535fc123378..bc4b1c5b51e6 100644 --- a/lib/bfd.c +++ b/lib/bfd.c @@ -32,6 +32,8 @@ enum bfd_session_event { BSE_UNINSTALL, /** Install the BFD session configuration. */ BSE_INSTALL, + /** We should install but it couldn't because of a error talking to zebra */ + BSE_VALID_FOR_INSTALL, }; /** @@ -527,6 +529,10 @@ static void _bfd_sess_send(struct event *t) vrf_id_to_name(bsp->args.vrf_id), bsp->args.vrf_id, bsp->lastev == BSE_INSTALL ? "installed" : "uninstalled"); + + bsp->installed = false; + if (bsp->lastev == BSE_INSTALL) + bsp->lastev = BSE_VALID_FOR_INSTALL; } } @@ -883,7 +889,7 @@ int zclient_bfd_session_replay(ZAPI_CALLBACK_ARGS) /* Replay all activated peers. */ TAILQ_FOREACH (bsp, &bsglobal.bsplist, entry) { /* Skip not installed sessions. */ - if (!bsp->installed) + if (!bsp->installed && bsp->lastev != BSE_VALID_FOR_INSTALL) continue; /* We are reconnecting, so we must send installation. */ From b2440cd86701d5639dbd40586ce9203b3eb76201 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 3 Dec 2024 18:38:59 -0500 Subject: [PATCH 039/106] lib: Allow setsockopt functions to return size set When finding a send/receive buffer size that is usable let's report how big we were able to set it. Signed-off-by: Donald Sharp --- lib/sockopt.c | 8 ++++++-- lib/sockopt.h | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/sockopt.c b/lib/sockopt.c index 74bc034ccd75..003ddb72dc2d 100644 --- a/lib/sockopt.c +++ b/lib/sockopt.c @@ -19,7 +19,7 @@ #define HAVE_BSD_STRUCT_IP_MREQ_HACK #endif -void setsockopt_so_recvbuf(int sock, int size) +int setsockopt_so_recvbuf(int sock, int size) { int orig_req = size; @@ -34,9 +34,11 @@ void setsockopt_so_recvbuf(int sock, int size) flog_err(EC_LIB_SOCKET, "%s: fd %d: SO_RCVBUF set to %d (requested %d)", __func__, sock, size, orig_req); + + return size; } -void setsockopt_so_sendbuf(const int sock, int size) +int setsockopt_so_sendbuf(const int sock, int size) { int orig_req = size; @@ -51,6 +53,8 @@ void setsockopt_so_sendbuf(const int sock, int size) flog_err(EC_LIB_SOCKET, "%s: fd %d: SO_SNDBUF set to %d (requested %d)", __func__, sock, size, orig_req); + + return size; } int getsockopt_so_sendbuf(const int sock) diff --git a/lib/sockopt.h b/lib/sockopt.h index e6fb78d5e4ef..cbf988cbe718 100644 --- a/lib/sockopt.h +++ b/lib/sockopt.h @@ -12,8 +12,8 @@ extern "C" { #endif -extern void setsockopt_so_recvbuf(int sock, int size); -extern void setsockopt_so_sendbuf(const int sock, int size); +extern int setsockopt_so_recvbuf(int sock, int size); +extern int setsockopt_so_sendbuf(const int sock, int size); extern int getsockopt_so_sendbuf(const int sock); extern int getsockopt_so_recvbuf(const int sock); From 93ea727e9bc448d53666ebe3d304b50ec4220f51 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 3 Dec 2024 18:49:59 -0500 Subject: [PATCH 040/106] lib,vtysh: Use backoff setsockopt option for freebsd Commit: 9112fb367b1ae0168b4e7a81f41c2ca621979199 Introduced the idea of setting the socket buffer send/receive sizes. BSD's in general have the fun issue of not allowing nearly as large as a size as linux. Since the above commit was developed on linux and not run on bsd it was never tested. Modify the codebase to use the backoff setsockopt that we have in the code base and use the returned values to allow us to notice what was set and respond appropriately. Signed-off-by: Donald Sharp --- lib/vty.c | 16 ++++++++++++---- lib/vty.h | 3 +++ vtysh/vtysh.c | 6 +++--- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/lib/vty.c b/lib/vty.c index 256a3bb3f538..1d04e75bf445 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -43,6 +43,7 @@ #include "northbound_cli.h" #include "printfrr.h" #include "json.h" +#include "sockopt.h" #include #include @@ -352,7 +353,7 @@ int vty_out(struct vty *vty, const char *format, ...) * put the data of collective vty->obuf Linked List items on the * socket and free the vty->obuf data. */ - if (vty->vty_buf_size_accumulated >= VTY_MAX_INTERMEDIATE_FLUSH) { + if (vty->vty_buf_size_accumulated >= vty->buf_size_intermediate) { vty->vty_buf_size_accumulated = 0; vtysh_flush(vty); } @@ -2157,15 +2158,15 @@ static void vtysh_accept(struct event *thread) * Increasing the SEND socket buffer size so that the socket can hold * before sending it to VTY shell. */ - ret = setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&sndbufsize, - sizeof(sndbufsize)); - if (ret < 0) { + ret = setsockopt_so_sendbuf(sock, sndbufsize); + if (ret <= 0) { flog_err(EC_LIB_SOCKET, "Cannot set socket %d send buffer size, %s", sock, safe_strerror(errno)); close(sock); return; } + set_cloexec(sock); #ifdef VTYSH_DEBUG @@ -2173,6 +2174,13 @@ static void vtysh_accept(struct event *thread) #endif /* VTYSH_DEBUG */ vty = vty_new(); + + vty->buf_size_set = ret; + if (vty->buf_size_set < VTY_MAX_INTERMEDIATE_FLUSH) + vty->buf_size_intermediate = vty->buf_size_set / 2; + else + vty->buf_size_intermediate = VTY_MAX_INTERMEDIATE_FLUSH; + vty->fd = sock; vty->wfd = sock; vty->type = VTY_SHELL_SERV; diff --git a/lib/vty.h b/lib/vty.h index e511e8e79ae4..be54159aa95d 100644 --- a/lib/vty.h +++ b/lib/vty.h @@ -237,6 +237,9 @@ struct vty { bool mgmt_locked_candidate_ds; bool mgmt_locked_running_ds; uint64_t vty_buf_size_accumulated; + + int buf_size_set; + uint64_t buf_size_intermediate; }; static inline void vty_push_context(struct vty *vty, int node, uint64_t id) diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 5a54c60c6b11..c460dea70cda 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -39,6 +39,7 @@ #include "frrstr.h" #include "json.h" #include "ferr.h" +#include "sockopt.h" DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CMD, "Vtysh cmd copy"); @@ -4690,9 +4691,8 @@ static int vtysh_connect(struct vtysh_client *vclient) * Increasing the RECEIVE socket buffer size so that the socket can hold * after receving from other process. */ - ret = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&rcvbufsize, - sizeof(rcvbufsize)); - if (ret < 0) { + ret = setsockopt_so_recvbuf(sock, rcvbufsize); + if (ret <= 0) { #ifdef DEBUG fprintf(stderr, "Cannot set socket %d rcv buffer size, %s\n", sock, safe_strerror(errno)); From fe5e066476f0249bda7a15625396b41ad8f6f648 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 4 Dec 2024 08:27:13 +0200 Subject: [PATCH 041/106] lib: Print the reason why the route-map and/or the index parsing is done This would give more details why at some point we return deny, no match, etc. Before this we have sometimes (I don't know why), e.g.: ``` Route-map: null, prefix: 192.168.2.0/24, result: deny ``` Signed-off-by: Donatas Abraitis --- lib/routemap.c | 38 ++++++++++++++++++++++++++++++++++---- lib/routemap.h | 11 +++++++++++ 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/lib/routemap.c b/lib/routemap.c index 120731fa61d4..7aaa5d3be8d9 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -875,6 +875,28 @@ void route_map_walk_update_list(void (*route_map_update_fn)(char *name)) } } +static const char *route_map_action_reason2str(enum route_map_action_reason reason) +{ + switch (reason) { + case route_map_action_none: + return "none"; + case route_map_action_map_null: + return "route-map is null"; + case route_map_action_no_index: + return "no index"; + case route_map_action_next_deny: + return "next statement is deny"; + case route_map_action_exit: + return "exit policy"; + case route_map_action_goto_null: + return "goto index is null"; + case route_map_action_index_deny: + return "deny index"; + } + + return "Invalid reason"; +} + /* Return route map's type string. */ static const char *route_map_type_str(enum route_map_type type) { @@ -2554,6 +2576,7 @@ route_map_result_t route_map_apply_ext(struct route_map *map, RUSAGE_T mbefore, mafter; RUSAGE_T ibefore, iafter; unsigned long cputime; + enum route_map_action_reason reason = route_map_action_none; if (recursion > RMAP_RECURSION_LIMIT) { if (map) @@ -2571,6 +2594,7 @@ route_map_result_t route_map_apply_ext(struct route_map *map, if (map) map->applied++; ret = RMAP_DENYMATCH; + reason = route_map_action_map_null; goto route_map_apply_end; } @@ -2614,6 +2638,7 @@ route_map_result_t route_map_apply_ext(struct route_map *map, ret = RMAP_PERMITMATCH; else ret = RMAP_DENYMATCH; + reason = route_map_action_no_index; goto route_map_apply_end; } @@ -2701,12 +2726,15 @@ route_map_result_t route_map_apply_ext(struct route_map *map, } /* If nextrm returned 'deny', finish. */ - if (ret == RMAP_DENYMATCH) + if (ret == RMAP_DENYMATCH) { + reason = route_map_action_next_deny; goto route_map_apply_end; + } } switch (index->exitpolicy) { case RMAP_EXIT: + reason = route_map_action_exit; goto route_map_apply_end; case RMAP_NEXT: continue; @@ -2722,6 +2750,7 @@ route_map_result_t route_map_apply_ext(struct route_map *map, } if (next == NULL) { /* No clauses match! */ + reason = route_map_action_goto_null; goto route_map_apply_end; } } @@ -2730,6 +2759,7 @@ route_map_result_t route_map_apply_ext(struct route_map *map, /* 'deny' */ { ret = RMAP_DENYMATCH; + reason = route_map_action_index_deny; goto route_map_apply_end; } } @@ -2741,9 +2771,9 @@ route_map_result_t route_map_apply_ext(struct route_map *map, route_map_apply_end: if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP))) - zlog_debug("Route-map: %s, prefix: %pFX, result: %s", - (map ? map->name : "null"), prefix, - route_map_result_str(ret)); + zlog_debug("Route-map: %s, prefix: %pFX, result: %s, reason: %s", + (map ? map->name : "null"), prefix, route_map_result_str(ret), + route_map_action_reason2str(reason)); if (pref) { if (index != NULL && ret == RMAP_PERMITMATCH) diff --git a/lib/routemap.h b/lib/routemap.h index e0f738502b9e..8dcc17ecc307 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -29,6 +29,17 @@ extern uint32_t rmap_debug; /* Route map's type. */ enum route_map_type { RMAP_PERMIT, RMAP_DENY, RMAP_ANY }; +/* Route-map's action reason */ +enum route_map_action_reason { + route_map_action_none, + route_map_action_map_null, + route_map_action_no_index, + route_map_action_next_deny, + route_map_action_exit, + route_map_action_goto_null, + route_map_action_index_deny, +}; + typedef enum { RMAP_DENYMATCH, RMAP_PERMITMATCH From 1b5ce058463466969905fdc6071e2c3f800f9cb7 Mon Sep 17 00:00:00 2001 From: "Barry A. Trent" Date: Tue, 3 Dec 2024 11:17:33 -0800 Subject: [PATCH 042/106] pimd: igmp proxy joins should not be written as part of config Signed-off-by: Barry A. Trent --- pimd/pim_vty.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index 4d83593c17d2..ed91d2339b5f 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -342,6 +342,9 @@ static int gm_config_write(struct vty *vty, int writes, struct listnode *node; struct gm_join *ij; for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_join_list, node, ij)) { + if (ij->join_type == GM_JOIN_PROXY) + continue; + if (pim_addr_is_any(ij->source_addr)) vty_out(vty, " ip igmp join-group %pPAs\n", &ij->group_addr); @@ -412,6 +415,9 @@ static int gm_config_write(struct vty *vty, int writes, struct gm_join *ij; for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_join_list, node, ij)) { + if (ij->join_type == GM_JOIN_PROXY) + continue; + if (pim_addr_is_any(ij->source_addr)) vty_out(vty, " ipv6 mld join-group %pPAs\n", &ij->group_addr); From 1b64d76b2f7f271315c0463845b0937c2b5ab3a7 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 4 Dec 2024 10:47:33 -0500 Subject: [PATCH 043/106] pimd: Prevent crash of pim when auto-rp's socket is not initialized If the socket associated with the auto-rp fails to initialize then the memory for the auto-rp is just dropped on the floor. Additionally any type of attempt at using the feature will just cause pimd to crash, when the pointer is derefed. Since it is derefed all over the place without checking. Clearly if you cannot bind/use the socket let's allow continuation. Fixes: #17540 Signed-off-by: Donald Sharp --- pimd/pim_autorp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pimd/pim_autorp.c b/pimd/pim_autorp.c index 3b46e7fb2bde..caed914a87fb 100644 --- a/pimd/pim_autorp.c +++ b/pimd/pim_autorp.c @@ -1508,12 +1508,14 @@ void pim_autorp_init(struct pim_instance *pim) autorp->discovery_holdtime = DEFAULT_AUTORP_DISCOVERY_HOLDTIME; cand_addrsel_clear(&(autorp->mapping_agent_addrsel)); + pim->autorp = autorp; + if (!pim_autorp_socket_enable(autorp)) { - zlog_warn("%s: AutoRP failed to initialize", __func__); + zlog_warn("%s: AutoRP failed to initialize, feature will not work correctly", + __func__); return; } - pim->autorp = autorp; if (PIM_DEBUG_AUTORP) zlog_debug("%s: AutoRP Initialized", __func__); From 85b502edca3e1abd2e581aa2025475294a604bd4 Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Tue, 10 May 2022 08:23:33 -0300 Subject: [PATCH 044/106] pimd: implement MSDP shutdown command Allow MSDP protocol to be disabled. Signed-off-by: Rafael Zalamena --- pimd/pim_cmd.c | 19 +++++++++++++++++ pimd/pim_msdp.c | 50 ++++++++++++++++++++++++++++++++++++++++++++ pimd/pim_msdp.h | 15 +++++++++++++ pimd/pim_nb.c | 6 ++++++ pimd/pim_nb.h | 1 + pimd/pim_nb_config.c | 27 ++++++++++++++++++++++++ yang/frr-pim.yang | 7 +++++++ 7 files changed, 125 insertions(+) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index a2a4c3493108..f4c25ea81ea9 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -7560,6 +7560,24 @@ DEFPY_ATTR(no_ip_pim_msdp_mesh_group, return ret; } +DEFPY(msdp_shutdown, + msdp_shutdown_cmd, + "[no] msdp shutdown", + NO_STR + CFG_MSDP_STR + "Shutdown MSDP operation\n") +{ + char xpath_value[XPATH_MAXLEN]; + + snprintf(xpath_value, sizeof(xpath_value), "./msdp/shutdown"); + if (no) + nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL); + else + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, "true"); + + return nb_cli_apply_changes(vty, NULL); +} + static void ip_msdp_show_mesh_group(struct vty *vty, struct pim_msdp_mg *mg, struct json_object *json) { @@ -8954,6 +8972,7 @@ void pim_cmd_init(void) install_element(PIM_NODE, &no_pim_msdp_mesh_group_cmd); install_element(PIM_NODE, &msdp_log_neighbor_changes_cmd); install_element(PIM_NODE, &msdp_log_sa_changes_cmd); + install_element(PIM_NODE, &msdp_shutdown_cmd); install_element(PIM_NODE, &pim_bsr_candidate_rp_cmd); install_element(PIM_NODE, &pim_bsr_candidate_rp_group_cmd); diff --git a/pimd/pim_msdp.c b/pimd/pim_msdp.c index a536ab6fe031..ae887b248253 100644 --- a/pimd/pim_msdp.c +++ b/pimd/pim_msdp.c @@ -734,6 +734,10 @@ static void pim_msdp_peer_state_chg_log(struct pim_msdp_peer *mp) * a tcp connection will be made */ static void pim_msdp_peer_connect(struct pim_msdp_peer *mp) { + /* Stop here if we are shutdown. */ + if (mp->pim->msdp.shutdown) + return; + mp->state = PIM_MSDP_CONNECTING; if (pim_msdp_log_neighbor_events(mp->pim)) pim_msdp_peer_state_chg_log(mp); @@ -744,6 +748,10 @@ static void pim_msdp_peer_connect(struct pim_msdp_peer *mp) /* 11.2.A3: passive peer - just listen for connections */ static void pim_msdp_peer_listen(struct pim_msdp_peer *mp) { + /* Stop here if we are shutdown. */ + if (mp->pim->msdp.shutdown) + return; + mp->state = PIM_MSDP_LISTEN; if (pim_msdp_log_neighbor_events(mp->pim)) pim_msdp_peer_state_chg_log(mp); @@ -1311,6 +1319,9 @@ bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim) written = true; } + if (pim->msdp.shutdown) + vty_out(vty, " msdp shutdown\n"); + return written; } @@ -1431,3 +1442,42 @@ struct pim_msdp_mg_mbr *pim_msdp_mg_mbr_add(struct pim_instance *pim, return mbr; } + +void pim_msdp_shutdown(struct pim_instance *pim, bool state) +{ + struct pim_msdp_peer *peer; + struct listnode *node; + + /* Same value nothing to do. */ + if (pim->msdp.shutdown == state) + return; + + if (state) { + pim->msdp.shutdown = true; + + for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, node, peer)) { + /* Stop the tcp connection and shutdown all timers */ + pim_msdp_peer_stop_tcp_conn(peer, true); + + /* Stop listening socket if any. */ + event_cancel(&peer->auth_listen_ev); + if (peer->auth_listen_sock != -1) + close(peer->auth_listen_sock); + + /* Disable and remove listener flag. */ + UNSET_FLAG(pim->msdp.flags, PIM_MSDPF_ENABLE | PIM_MSDPF_LISTENER); + } + } else { + pim->msdp.shutdown = false; + + for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, node, peer)) { + /* Start connection again. */ + if (PIM_MSDP_PEER_IS_LISTENER(peer)) + pim_msdp_peer_listen(peer); + else + pim_msdp_peer_connect(peer); + + SET_FLAG(pim->msdp.flags, PIM_MSDPF_ENABLE); + } + } +} diff --git a/pimd/pim_msdp.h b/pimd/pim_msdp.h index 0a7c74e438e7..d0aa83d9978c 100644 --- a/pimd/pim_msdp.h +++ b/pimd/pim_msdp.h @@ -216,6 +216,9 @@ struct pim_msdp { uint32_t keep_alive; /** MSDP global connection retry period. */ uint32_t connection_retry; + + /** MSDP operation state. */ + bool shutdown; }; #define PIM_MSDP_PEER_READ_ON(mp) \ @@ -327,6 +330,14 @@ void pim_msdp_peer_change_source(struct pim_msdp_peer *mp, */ void pim_msdp_peer_restart(struct pim_msdp_peer *mp); +/** + * Toggle MSDP functionality administrative state. + * + * \param pim PIM instance we want to shutdown. + * \param state shutdown state. + */ +void pim_msdp_shutdown(struct pim_instance *pim, bool state); + #else /* PIM_IPV == 6 */ static inline void pim_msdp_init(struct pim_instance *pim, struct event_loop *master) @@ -370,6 +381,10 @@ static inline bool pim_msdp_peer_config_write(struct vty *vty, { return false; } + +static inline void pim_msdp_shutdown(struct pim_instance *pim, bool state) +{ +} #endif /* PIM_IPV == 6 */ #endif diff --git a/pimd/pim_nb.c b/pimd/pim_nb.c index c5a9c7f05562..4a5ad87942b2 100644 --- a/pimd/pim_nb.c +++ b/pimd/pim_nb.c @@ -141,6 +141,12 @@ const struct frr_yang_module_info frr_pim_info = { .modify = pim_msdp_log_sa_events_modify, } }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp/shutdown", + .cbs = { + .modify = pim_msdp_shutdown_modify, + } + }, { .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-groups", .cbs = { diff --git a/pimd/pim_nb.h b/pimd/pim_nb.h index 8412ef4a6e5a..a9693c65d8e6 100644 --- a/pimd/pim_nb.h +++ b/pimd/pim_nb.h @@ -56,6 +56,7 @@ int pim_msdp_keep_alive_modify(struct nb_cb_modify_args *args); int pim_msdp_connection_retry_modify(struct nb_cb_modify_args *args); int pim_msdp_log_neighbor_events_modify(struct nb_cb_modify_args *args); int pim_msdp_log_sa_events_modify(struct nb_cb_modify_args *args); +int pim_msdp_shutdown_modify(struct nb_cb_modify_args *args); int pim_msdp_mesh_group_create(struct nb_cb_create_args *args); int pim_msdp_mesh_group_destroy(struct nb_cb_destroy_args *args); int pim_msdp_mesh_group_members_create(struct nb_cb_create_args *args); diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index e594a150fd2f..171614208f09 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -1098,6 +1098,7 @@ pim6_msdp_err(pim_msdp_peer_authentication_key_modify, nb_cb_modify_args); pim6_msdp_err(pim_msdp_peer_authentication_key_destroy, nb_cb_destroy_args); pim6_msdp_err(pim_msdp_log_neighbor_events_modify, nb_cb_modify_args); pim6_msdp_err(pim_msdp_log_sa_events_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_shutdown_modify, nb_cb_modify_args); #if PIM_IPV != 6 /* @@ -1158,6 +1159,32 @@ int pim_msdp_log_sa_events_modify(struct nb_cb_modify_args *args) return NB_OK; } +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp/shutdown + */ +int pim_msdp_shutdown_modify(struct nb_cb_modify_args *args) +{ + struct pim_instance *pim; + struct vrf *vrf; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + pim_msdp_shutdown(pim, yang_dnode_get_bool(args->dnode, NULL)); + break; + } + + return NB_OK; +} + /* * XPath: * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-groups diff --git a/yang/frr-pim.yang b/yang/frr-pim.yang index c3c953b76b42..33602fd29e60 100644 --- a/yang/frr-pim.yang +++ b/yang/frr-pim.yang @@ -264,6 +264,13 @@ module frr-pim { description "Log all MSDP SA related events."; } + + leaf shutdown { + type boolean; + default false; + description + "Shutdown MSDP functionality."; + } } list msdp-mesh-groups { From 33dc89a9228eabfb458974208e976116dd5ceb4f Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Mon, 25 Nov 2024 11:32:46 -0300 Subject: [PATCH 045/106] topotests: test MSDP shutdown command New test step to check that MSDP shutdown command is working. Signed-off-by: Rafael Zalamena --- tests/topotests/msdp_topo1/test_msdp_topo1.py | 51 +++++++++++++++++-- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/tests/topotests/msdp_topo1/test_msdp_topo1.py b/tests/topotests/msdp_topo1/test_msdp_topo1.py index 1c97f7cb1e47..8c25eeca06a6 100755 --- a/tests/topotests/msdp_topo1/test_msdp_topo1.py +++ b/tests/topotests/msdp_topo1/test_msdp_topo1.py @@ -521,15 +521,58 @@ def test_msdp_log_events(): r1_log = tgen.gears["r1"].net.getLog("log", "pimd") # Look up for informational messages that should have been enabled. - match = re.search( - "MSDP peer 192.168.1.2 state changed to established", r1_log) + match = re.search("MSDP peer 192.168.1.2 state changed to established", r1_log) assert match is not None - match = re.search( - r"MSDP SA \(192.168.10.100\,229.1.2.3\) created", r1_log) + match = re.search(r"MSDP SA \(192.168.10.100\,229.1.2.3\) created", r1_log) assert match is not None +def test_msdp_shutdown(): + "Shutdown MSDP sessions between r1, r2, r3, then check the state." + + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + tgen.gears["r1"].vtysh_cmd( + """ + configure terminal + router pim + msdp shutdown + """ + ) + + r1_expect = { + "192.168.0.2": { + "state": "inactive", + }, + "192.168.1.2": { + "state": "inactive", + }, + } + r2_expect = { + "192.168.0.1": { + "state": "listen", + } + } + r3_expect = { + "192.168.1.1": { + "state": "listen", + } + } + for router in [("r1", r1_expect), ("r2", r2_expect), ("r3", r3_expect)]: + test_func = partial( + topotest.router_json_cmp, + tgen.gears[router[0]], + "show ip msdp peer json", + router[1], + ) + logger.info("Waiting for {} msdp peer data".format(router[0])) + _, val = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert val is None, "multicast route convergence failure" + + def test_memory_leak(): "Run the memory leak test and report results." tgen = get_topogen() From fdab494f961ef5b4d9f55973e5a4d3239af64e21 Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Mon, 25 Nov 2024 12:03:59 -0300 Subject: [PATCH 046/106] doc: document shutdown command Let users know about the MSDP shutdown command. Signed-off-by: Rafael Zalamena --- doc/user/pim.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/user/pim.rst b/doc/user/pim.rst index 0fe53247b05e..05418da5a990 100644 --- a/doc/user/pim.rst +++ b/doc/user/pim.rst @@ -478,6 +478,10 @@ Commands available for MSDP To apply it immediately call `clear ip msdp peer A.B.C.D`. +.. clicmd:: msdp shutdown + + Shutdown the MSDP sessions in this PIM instance. + .. _show-pim-information: From bd14767cf6a12bf55ae90b7de9f2d1b475d76bf4 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 4 Dec 2024 16:14:34 -0500 Subject: [PATCH 047/106] lib: Speed up reconnection attempts for zapi Currently the zapi reconnection is once every 10 seconds for the first 3 times and then once every 60 seconds from then on out. We are seeing interesting behavior under loaded systems where zebra is just slow to come up and daemons are spending a long time waiting to connect. Let's just make things a bit more aggressive. Change the code to attempt to reconnect once every second for 30 seconds and then change to once every 5 seconds from then on out. This should help with non-integrated configuration on system startup. Signed-off-by: Donald Sharp --- lib/zclient.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/zclient.c b/lib/zclient.c index 557d9c3eb9b4..063944fd3b23 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -4693,6 +4693,9 @@ void zclient_redistribute_default(int command, struct zclient *zclient, zebra_redistribute_default_send(command, zclient, afi, vrf_id); } +#define ZCLIENT_QUICK_RECONNECT 1 +#define ZCLIENT_SLOW_RECONNECT 5 +#define ZCLIENT_SWITCH_TO_SLOW 30 static void zclient_event(enum zclient_event event, struct zclient *zclient) { switch (event) { @@ -4702,11 +4705,13 @@ static void zclient_event(enum zclient_event event, struct zclient *zclient) break; case ZCLIENT_CONNECT: if (zclient_debug) - zlog_debug( - "zclient connect failures: %d schedule interval is now %d", - zclient->fail, zclient->fail < 3 ? 10 : 60); + zlog_debug("zclient connect failures: %d schedule interval is now %d", + zclient->fail, + zclient->fail < ZCLIENT_SWITCH_TO_SLOW ? ZCLIENT_QUICK_RECONNECT + : ZCLIENT_SLOW_RECONNECT); event_add_timer(zclient->master, zclient_connect, zclient, - zclient->fail < 3 ? 10 : 60, + zclient->fail < ZCLIENT_SWITCH_TO_SLOW ? ZCLIENT_QUICK_RECONNECT + : ZCLIENT_SLOW_RECONNECT, &zclient->t_connect); break; case ZCLIENT_READ: From 1276e8fbc3ea9d6bc4a166fc39a45ecec28bee7c Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 4 Dec 2024 21:25:33 +0100 Subject: [PATCH 048/106] bgpd: fix unconfigure asdot neighbor The below command is not successfull on an existing as dot peer > no neighbor 10.0.0.2 remote-as 1.1 > % Create the peer-group or interface first Handle the case where the remote-as argument can be an ASNUM. Fixes: 8079a4138d61 ("lib, bgp: add initial support for asdot format") Signed-off-by: Philippe Guibert --- bgpd/bgp_vty.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 6ff94129dcf5..bb0c69ca56ee 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -5228,7 +5228,7 @@ DEFUN (neighbor_peer_group, DEFUN (no_neighbor, no_neighbor_cmd, - "no neighbor [remote-as <(1-4294967295)|internal|external|auto>]>", + "no neighbor [remote-as ]>", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 @@ -5307,7 +5307,7 @@ DEFUN (no_neighbor, DEFUN (no_neighbor_interface_config, no_neighbor_interface_config_cmd, - "no neighbor WORD interface [v6only] [peer-group PGNAME] [remote-as <(1-4294967295)|internal|external|auto>]", + "no neighbor WORD interface [v6only] [peer-group PGNAME] [remote-as ]", NO_STR NEIGHBOR_STR "Interface name\n" From 430d7cb88c25addd05f6f0362ee1360d862d0f86 Mon Sep 17 00:00:00 2001 From: "Barry A. Trent" Date: Tue, 3 Dec 2024 14:43:47 -0800 Subject: [PATCH 049/106] pimd: free igmp proxy joins on interface deletion Signed-off-by: Barry A. Trent --- pimd/pim_iface.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 20e3ba184ba8..19460aa445d6 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -1464,8 +1464,7 @@ static void pim_if_gm_join_del_all(struct interface *ifp) return; for (ALL_LIST_ELEMENTS(pim_ifp->gm_join_list, node, nextnode, ij)) - pim_if_gm_join_del(ifp, ij->group_addr, ij->source_addr, - GM_JOIN_STATIC); + pim_if_gm_join_del(ifp, ij->group_addr, ij->source_addr, ij->join_type); } ferr_r pim_if_static_group_add(struct interface *ifp, pim_addr group_addr, From 5779690bb3038648560eb5330b672897481800ce Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 5 Dec 2024 10:13:51 -0500 Subject: [PATCH 050/106] tests: bfd_profiles_topo1 is taking a long time to reconnect Make it faster Signed-off-by: Donald Sharp --- tests/topotests/bfd_profiles_topo1/r2/bgpd.conf | 2 ++ tests/topotests/bfd_profiles_topo1/r3/bgpd.conf | 1 + tests/topotests/bfd_profiles_topo1/r4/bgpd.conf | 1 + 3 files changed, 4 insertions(+) diff --git a/tests/topotests/bfd_profiles_topo1/r2/bgpd.conf b/tests/topotests/bfd_profiles_topo1/r2/bgpd.conf index 1aab1d1372e8..0fe6f1c1c4ca 100644 --- a/tests/topotests/bfd_profiles_topo1/r2/bgpd.conf +++ b/tests/topotests/bfd_profiles_topo1/r2/bgpd.conf @@ -5,9 +5,11 @@ router bgp 100 no bgp ebgp-requires-policy neighbor 172.16.1.1 remote-as 100 neighbor 172.16.1.1 timers 3 10 + neighbor 172.16.1.1 timers connect 1 neighbor 172.16.1.1 bfd profile fasttx neighbor 2001:db8:2::2 remote-as 200 neighbor 2001:db8:2::2 timers 3 10 + neighbor 2001:db8:2::2 timers connect 1 neighbor 2001:db8:2::2 ebgp-multihop 2 neighbor 2001:db8:2::2 bfd profile slowtx address-family ipv4 unicast diff --git a/tests/topotests/bfd_profiles_topo1/r3/bgpd.conf b/tests/topotests/bfd_profiles_topo1/r3/bgpd.conf index 65647b39e51d..d1168d93bc32 100644 --- a/tests/topotests/bfd_profiles_topo1/r3/bgpd.conf +++ b/tests/topotests/bfd_profiles_topo1/r3/bgpd.conf @@ -2,6 +2,7 @@ router bgp 100 bgp router-id 10.254.254.3 neighbor 172.16.1.2 remote-as 100 neighbor 172.16.1.2 timers 3 10 + neighbor 172.16.1.2 timers connect 1 neighbor 172.16.1.2 bfd profile DOES_NOT_EXIST address-family ipv4 unicast redistribute connected diff --git a/tests/topotests/bfd_profiles_topo1/r4/bgpd.conf b/tests/topotests/bfd_profiles_topo1/r4/bgpd.conf index 12d68270f8af..1a8e6bb94dc7 100644 --- a/tests/topotests/bfd_profiles_topo1/r4/bgpd.conf +++ b/tests/topotests/bfd_profiles_topo1/r4/bgpd.conf @@ -5,6 +5,7 @@ router bgp 200 no bgp ebgp-requires-policy neighbor 2001:db8:1::2 remote-as 100 neighbor 2001:db8:1::2 timers 3 10 + neighbor 2001:db8:1::2 timers connect 1 neighbor 2001:db8:1::2 ebgp-multihop 2 neighbor 2001:db8:1::2 bfd profile DOES_NOT_EXIST address-family ipv4 unicast From 31572eb17def6bce5d3805d77d1cb4b293f4b71f Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 5 Dec 2024 10:15:18 -0500 Subject: [PATCH 051/106] bgpd: shared_network is a bool, convert it to such Signed-off-by: Donald Sharp --- bgpd/bgp_zebra.c | 8 ++++---- bgpd/bgpd.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 688dfacaa0b6..ee1bdbc5bd3d 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -838,9 +838,9 @@ bool bgp_zebra_nexthop_set(union sockunion *local, union sockunion *remote, if (!v6_ll_avail && !peer->conf_if) v6_ll_avail = true; if (if_lookup_by_ipv4(&remote->sin.sin_addr, peer->bgp->vrf_id)) - peer->shared_network = 1; + peer->shared_network = true; else - peer->shared_network = 0; + peer->shared_network = false; } /* IPv6 connection, fetch and store IPv4 local address if any. */ @@ -903,9 +903,9 @@ bool bgp_zebra_nexthop_set(union sockunion *local, union sockunion *remote, || if_lookup_by_ipv6(&remote->sin6.sin6_addr, remote->sin6.sin6_scope_id, peer->bgp->vrf_id)) - peer->shared_network = 1; + peer->shared_network = true; else - peer->shared_network = 0; + peer->shared_network = false; } /* KAME stack specific treatment. */ diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index df55d879e71d..bb56fd355a05 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -1330,7 +1330,7 @@ struct peer { union sockunion *su_local; /* Sockunion of local address. */ union sockunion *su_remote; /* Sockunion of remote address. */ - int shared_network; /* Is this peer shared same network. */ + bool shared_network; /* Is this peer shared same network. */ struct bgp_nexthop nexthop; /* Nexthop */ /* Roles in bgp session */ From 3d70b9e765ccf6a881b29f2921c961334f57d23c Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 5 Dec 2024 10:16:03 -0500 Subject: [PATCH 052/106] bgpd: When bgp notices a change to shared_network inform bfd of it When bgp is started up and reads the config in *before* it has received interface addresses from zebra, shared_network can be set to false in this case. Later on once bgp attempts to reconnect it will refigure out the shared_network again( because it has received the data from zebra now ). In this case tell bfd about it. Signed-off-by: Donald Sharp --- bgpd/bgp_zebra.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index ee1bdbc5bd3d..ac4a6bb03bf6 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -744,6 +744,7 @@ bool bgp_zebra_nexthop_set(union sockunion *local, union sockunion *remote, int ret = 0; struct interface *ifp = NULL; bool v6_ll_avail = true; + bool shared_network_original = peer->shared_network; memset(nexthop, 0, sizeof(struct bgp_nexthop)); @@ -908,6 +909,9 @@ bool bgp_zebra_nexthop_set(union sockunion *local, union sockunion *remote, peer->shared_network = false; } + if (shared_network_original != peer->shared_network) + bgp_peer_bfd_update_source(peer); + /* KAME stack specific treatment. */ #ifdef KAME if (IN6_IS_ADDR_LINKLOCAL(&nexthop->v6_global) From b8979fb9d054410626bb4ea83f1cc9dc9196808a Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 4 Dec 2024 12:22:59 -0500 Subject: [PATCH 053/106] tests: Convert to using `neighbor X timers connect 1` for exabgp using tests For those tests using exabgp convert them all to use `neighbor X timers connect 1`. I have noticed that occassionally when looking at the support files for tests run that peers are in a wait period for reconnecting which is longer than the test is waiting to converge. Signed-off-by: Donald Sharp --- .../bgp_aggregate_address_topo1/r1/bgpd.conf | 2 ++ .../bgp_aggregate_address_topo1/r2/bgpd.conf | 1 + .../bgp_aggregator_zero/r1/bgpd.conf | 1 + tests/topotests/bgp_aspath_zero/r1/bgpd.conf | 1 + tests/topotests/bgp_ecmp_topo1/r1/bgpd.conf | 20 +++++++++++++++++++ tests/topotests/bgp_flowspec/r1/bgpd.conf | 1 + .../topotests/bgp_invalid_nexthop/r1/frr.conf | 1 + .../bgp_multiview_topo1/r1/bgpd.conf | 8 ++++++++ tests/topotests/bgp_nexthop_ipv6/r1/bgpd.conf | 1 + tests/topotests/bgp_nexthop_ipv6/r2/bgpd.conf | 1 + tests/topotests/bgp_nexthop_ipv6/r4/bgpd.conf | 1 + tests/topotests/bgp_nexthop_ipv6/r5/bgpd.conf | 1 + tests/topotests/bgp_nexthop_ipv6/r6/bgpd.conf | 1 + tests/topotests/bgp_nexthop_ipv6/rr/bgpd.conf | 6 ++++++ .../bgp_path_attribute_discard/r1/frr.conf | 1 + .../bgp_path_attribute_discard/r2/frr.conf | 1 + .../r1/bgpd.conf | 8 ++++++++ .../r2/bgpd.conf | 4 ++++ tests/topotests/bgp_prefix_sid/r1/bgpd.conf | 2 ++ tests/topotests/bgp_prefix_sid2/r1/bgpd.conf | 1 + .../bgp_route_server_client/r1/bgpd.conf | 2 +- .../bgp_route_server_client/r2/bgpd.conf | 8 ++++---- .../bgp_route_server_client/r3/bgpd.conf | 2 +- .../bgp_route_server_client/r4/bgpd.conf | 2 +- tests/topotests/bgp_vrf_netns/r1/bgpd.conf | 1 + 25 files changed, 71 insertions(+), 7 deletions(-) diff --git a/tests/topotests/bgp_aggregate_address_topo1/r1/bgpd.conf b/tests/topotests/bgp_aggregate_address_topo1/r1/bgpd.conf index c7cf4a527f9e..69be4b541d23 100644 --- a/tests/topotests/bgp_aggregate_address_topo1/r1/bgpd.conf +++ b/tests/topotests/bgp_aggregate_address_topo1/r1/bgpd.conf @@ -19,8 +19,10 @@ router bgp 65000 no bgp ebgp-requires-policy neighbor 10.0.0.2 remote-as 65001 neighbor 10.0.0.2 timers 3 10 + neighbor 10.0.0.2 timers connect 1 neighbor 10.0.1.2 remote-as internal neighbor 10.0.1.2 timers 3 10 + neighbor 10.0.1.2 timers connect 1 address-family ipv4 unicast redistribute connected aggregate-address 192.168.0.0/24 matching-MED-only diff --git a/tests/topotests/bgp_aggregate_address_topo1/r2/bgpd.conf b/tests/topotests/bgp_aggregate_address_topo1/r2/bgpd.conf index acacd8652657..418624aed41e 100644 --- a/tests/topotests/bgp_aggregate_address_topo1/r2/bgpd.conf +++ b/tests/topotests/bgp_aggregate_address_topo1/r2/bgpd.conf @@ -1,6 +1,7 @@ router bgp 65000 neighbor 10.0.1.1 remote-as internal neighbor 10.0.1.1 timers 3 10 + neighbor 10.0.1.1 timers connect 1 address-family ipv4 unicast redistribute connected exit-address-family diff --git a/tests/topotests/bgp_aggregator_zero/r1/bgpd.conf b/tests/topotests/bgp_aggregator_zero/r1/bgpd.conf index 002a5c78c0f7..a6e24b221bf0 100644 --- a/tests/topotests/bgp_aggregator_zero/r1/bgpd.conf +++ b/tests/topotests/bgp_aggregator_zero/r1/bgpd.conf @@ -3,4 +3,5 @@ router bgp 65534 no bgp ebgp-requires-policy neighbor 10.0.0.2 remote-as external neighbor 10.0.0.2 timers 3 10 + neighbor 10.0.0.2 timers connect 1 ! diff --git a/tests/topotests/bgp_aspath_zero/r1/bgpd.conf b/tests/topotests/bgp_aspath_zero/r1/bgpd.conf index 002a5c78c0f7..a6e24b221bf0 100644 --- a/tests/topotests/bgp_aspath_zero/r1/bgpd.conf +++ b/tests/topotests/bgp_aspath_zero/r1/bgpd.conf @@ -3,4 +3,5 @@ router bgp 65534 no bgp ebgp-requires-policy neighbor 10.0.0.2 remote-as external neighbor 10.0.0.2 timers 3 10 + neighbor 10.0.0.2 timers connect 1 ! diff --git a/tests/topotests/bgp_ecmp_topo1/r1/bgpd.conf b/tests/topotests/bgp_ecmp_topo1/r1/bgpd.conf index 49981ac58968..09c65321c2e1 100644 --- a/tests/topotests/bgp_ecmp_topo1/r1/bgpd.conf +++ b/tests/topotests/bgp_ecmp_topo1/r1/bgpd.conf @@ -8,44 +8,64 @@ router bgp 100 no bgp ebgp-requires-policy neighbor 10.0.1.101 remote-as 99 neighbor 10.0.1.101 timers 3 10 + neighbor 10.0.1.101 timers connect 1 neighbor 10.0.1.102 remote-as 99 neighbor 10.0.1.102 timers 3 10 + neighbor 10.0.1.102 timers connect 1 neighbor 10.0.1.103 remote-as 99 neighbor 10.0.1.103 timers 3 10 + neighbor 10.0.1.103 timers connect 1 neighbor 10.0.1.104 remote-as 99 neighbor 10.0.1.104 timers 3 10 + neighbor 10.0.1.104 timers connect 1 neighbor 10.0.1.105 remote-as 99 neighbor 10.0.1.105 timers 3 10 + neighbor 10.0.1.105 timers connect 1 neighbor 10.0.2.106 remote-as 99 neighbor 10.0.2.106 timers 3 10 + neighbor 10.0.1.106 timers connect 1 neighbor 10.0.2.107 remote-as 99 neighbor 10.0.2.107 timers 3 10 + neighbor 10.0.1.107 timers connect 1 neighbor 10.0.2.108 remote-as 99 neighbor 10.0.2.108 timers 3 10 + neighbor 10.0.1.108 timers connect 1 neighbor 10.0.2.109 remote-as 99 neighbor 10.0.2.109 timers 3 10 + neighbor 10.0.1.109 timers connect 1 neighbor 10.0.2.110 remote-as 99 neighbor 10.0.2.110 timers 3 10 + neighbor 10.0.1.110 timers connect 1 neighbor 10.0.3.111 remote-as 111 neighbor 10.0.3.111 timers 3 10 + neighbor 10.0.1.111 timers connect 1 neighbor 10.0.3.112 remote-as 112 neighbor 10.0.3.112 timers 3 10 + neighbor 10.0.1.112 timers connect 1 neighbor 10.0.3.113 remote-as 113 neighbor 10.0.3.113 timers 3 10 + neighbor 10.0.1.113 timers connect 1 neighbor 10.0.3.114 remote-as 114 neighbor 10.0.3.114 timers 3 10 + neighbor 10.0.1.114 timers connect 1 neighbor 10.0.3.115 remote-as 115 neighbor 10.0.3.115 timers 3 10 + neighbor 10.0.1.115 timers connect 1 neighbor 10.0.4.116 remote-as 116 neighbor 10.0.4.116 timers 3 10 + neighbor 10.0.1.116 timers connect 1 neighbor 10.0.4.117 remote-as 117 neighbor 10.0.4.117 timers 3 10 + neighbor 10.0.1.117 timers connect 1 neighbor 10.0.4.118 remote-as 118 neighbor 10.0.4.118 timers 3 10 + neighbor 10.0.1.118 timers connect 1 neighbor 10.0.4.119 remote-as 119 neighbor 10.0.4.119 timers 3 10 + neighbor 10.0.1.119 timers connect 1 neighbor 10.0.4.120 remote-as 120 neighbor 10.0.4.120 timers 3 10 + neighbor 10.0.1.120 timers connect 1 ! ! diff --git a/tests/topotests/bgp_flowspec/r1/bgpd.conf b/tests/topotests/bgp_flowspec/r1/bgpd.conf index 4b7a20f95800..288aeaf4dde9 100644 --- a/tests/topotests/bgp_flowspec/r1/bgpd.conf +++ b/tests/topotests/bgp_flowspec/r1/bgpd.conf @@ -6,6 +6,7 @@ router bgp 100 bgp router-id 10.0.1.1 neighbor 10.0.1.101 remote-as 100 neighbor 10.0.1.101 timers 3 10 + neighbor 10.0.1.101 timers connect 1 neighbor 10.0.1.101 update-source 10.0.1.1 address-family ipv6 flowspec local-install r1-eth0 diff --git a/tests/topotests/bgp_invalid_nexthop/r1/frr.conf b/tests/topotests/bgp_invalid_nexthop/r1/frr.conf index 05e1a6c8259e..f96aeb43668c 100644 --- a/tests/topotests/bgp_invalid_nexthop/r1/frr.conf +++ b/tests/topotests/bgp_invalid_nexthop/r1/frr.conf @@ -8,6 +8,7 @@ router bgp 65001 no bgp ebgp-requires-policy neighbor fc00::2 remote-as external neighbor fc00::2 timers 3 10 + neighbor fc00::2 timers connect 1 address-family ipv6 neighbor fc00::2 activate exit-address-family diff --git a/tests/topotests/bgp_multiview_topo1/r1/bgpd.conf b/tests/topotests/bgp_multiview_topo1/r1/bgpd.conf index cd7f44ac6650..ced5cb5e4dcc 100644 --- a/tests/topotests/bgp_multiview_topo1/r1/bgpd.conf +++ b/tests/topotests/bgp_multiview_topo1/r1/bgpd.conf @@ -19,10 +19,13 @@ router bgp 100 view 1 timers bgp 60 180 neighbor 172.16.1.1 remote-as 65001 neighbor 172.16.1.1 timers 3 10 + neighbor 172.16.1.1 timers connect 1 neighbor 172.16.1.2 remote-as 65002 neighbor 172.16.1.2 timers 3 10 + neighbor 172.16.1.2 timers connect 1 neighbor 172.16.1.5 remote-as 65005 neighbor 172.16.1.5 timers 3 10 + neighbor 172.16.1.5 timers connect 1 ! router bgp 100 view 2 bgp router-id 172.30.1.1 @@ -32,8 +35,10 @@ router bgp 100 view 2 timers bgp 60 180 neighbor 172.16.1.3 remote-as 65003 neighbor 172.16.1.3 timers 3 10 + neighbor 172.16.1.3 timers connect 1 neighbor 172.16.1.4 remote-as 65004 neighbor 172.16.1.4 timers 3 10 + neighbor 172.16.1.4 timers connect 1 ! router bgp 100 view 3 bgp router-id 172.30.1.1 @@ -43,10 +48,13 @@ router bgp 100 view 3 timers bgp 60 180 neighbor 172.16.1.6 remote-as 65006 neighbor 172.16.1.6 timers 3 10 + neighbor 172.16.1.6 timers connect 1 neighbor 172.16.1.7 remote-as 65007 neighbor 172.16.1.7 timers 3 10 + neighbor 172.16.1.7 timers connect 1 neighbor 172.16.1.8 remote-as 65008 neighbor 172.16.1.8 timers 3 10 + neighbor 172.16.1.8 timers connect 1 ! route-map local1 permit 10 set community 100:9999 additive diff --git a/tests/topotests/bgp_nexthop_ipv6/r1/bgpd.conf b/tests/topotests/bgp_nexthop_ipv6/r1/bgpd.conf index 7efa1b79fa5d..06ac666ce6ea 100644 --- a/tests/topotests/bgp_nexthop_ipv6/r1/bgpd.conf +++ b/tests/topotests/bgp_nexthop_ipv6/r1/bgpd.conf @@ -2,6 +2,7 @@ router bgp 65000 no bgp ebgp-requires-policy neighbor fd00:0:2::9 remote-as internal neighbor fd00:0:2::9 timers 3 10 + neighbor fd00:0:2::9 timers connect 1 address-family ipv4 unicast redistribute connected route-map RMAP4 ! diff --git a/tests/topotests/bgp_nexthop_ipv6/r2/bgpd.conf b/tests/topotests/bgp_nexthop_ipv6/r2/bgpd.conf index 4d4ae44e284b..4b696b51b38e 100644 --- a/tests/topotests/bgp_nexthop_ipv6/r2/bgpd.conf +++ b/tests/topotests/bgp_nexthop_ipv6/r2/bgpd.conf @@ -2,6 +2,7 @@ router bgp 65000 no bgp ebgp-requires-policy neighbor fd00:0:2::9 remote-as internal neighbor fd00:0:2::9 timers 3 10 + neighbor fd00:0:2::9 timers connect 1 address-family ipv4 unicast redistribute connected route-map RMAP4 ! diff --git a/tests/topotests/bgp_nexthop_ipv6/r4/bgpd.conf b/tests/topotests/bgp_nexthop_ipv6/r4/bgpd.conf index b14c9bace4a6..081909bbb3f6 100644 --- a/tests/topotests/bgp_nexthop_ipv6/r4/bgpd.conf +++ b/tests/topotests/bgp_nexthop_ipv6/r4/bgpd.conf @@ -2,6 +2,7 @@ router bgp 65001 no bgp ebgp-requires-policy neighbor fd00:0:2::9 remote-as external neighbor fd00:0:2::9 timers 3 10 + neighbor fd00:0:2::9 timers connect 1 address-family ipv4 unicast redistribute connected route-map RMAP4 ! diff --git a/tests/topotests/bgp_nexthop_ipv6/r5/bgpd.conf b/tests/topotests/bgp_nexthop_ipv6/r5/bgpd.conf index becea2bbe648..b8f9078f51e8 100644 --- a/tests/topotests/bgp_nexthop_ipv6/r5/bgpd.conf +++ b/tests/topotests/bgp_nexthop_ipv6/r5/bgpd.conf @@ -2,6 +2,7 @@ router bgp 65002 no bgp ebgp-requires-policy neighbor fd00:0:3::9 remote-as external neighbor fd00:0:3::9 timers 3 10 + neighbor fd00:0:3::9 timers connect 1 address-family ipv4 unicast redistribute connected route-map RMAP4 ! diff --git a/tests/topotests/bgp_nexthop_ipv6/r6/bgpd.conf b/tests/topotests/bgp_nexthop_ipv6/r6/bgpd.conf index 801736ab988e..19c6bbc81948 100644 --- a/tests/topotests/bgp_nexthop_ipv6/r6/bgpd.conf +++ b/tests/topotests/bgp_nexthop_ipv6/r6/bgpd.conf @@ -2,6 +2,7 @@ router bgp 65000 no bgp ebgp-requires-policy neighbor fd00:0:4::9 remote-as internal neighbor fd00:0:4::9 timers 3 10 + neighbor fd00:0:4::9 timers connect 1 address-family ipv4 unicast redistribute connected route-map RMAP4 ! diff --git a/tests/topotests/bgp_nexthop_ipv6/rr/bgpd.conf b/tests/topotests/bgp_nexthop_ipv6/rr/bgpd.conf index 705ae78b8e1e..1c8f2fa49edc 100644 --- a/tests/topotests/bgp_nexthop_ipv6/rr/bgpd.conf +++ b/tests/topotests/bgp_nexthop_ipv6/rr/bgpd.conf @@ -2,16 +2,22 @@ router bgp 65000 no bgp ebgp-requires-policy neighbor fd00:0:2::1 remote-as internal neighbor fd00:0:2::1 timers 3 10 + neighbor fd00:0:2::1 timers connect 1 neighbor fd00:0:2::2 remote-as internal neighbor fd00:0:2::2 timers 3 10 + neighbor fd00:0:2::2 timers connect 1 neighbor fd00:0:2::3 remote-as internal neighbor fd00:0:2::3 timers 3 10 + neighbor fd00:0:2::3 timers connect 1 neighbor fd00:0:2::4 remote-as external neighbor fd00:0:2::4 timers 3 10 + neighbor fd00:0:2::4 timers connect 1 neighbor fd00:0:3::5 remote-as external neighbor fd00:0:3::5 timers 3 10 + neighbor fd00:0:3::5 timers connect 1 neighbor fd00:0:4::6 remote-as internal neighbor fd00:0:4::6 timers 3 10 + neighbor fd00:0:4::6 timers connect 1 address-family ipv4 unicast neighbor fd00:0:2::1 route-reflector-client neighbor fd00:0:2::2 route-reflector-client diff --git a/tests/topotests/bgp_path_attribute_discard/r1/frr.conf b/tests/topotests/bgp_path_attribute_discard/r1/frr.conf index ae7fbdd9a93a..ae47862963be 100644 --- a/tests/topotests/bgp_path_attribute_discard/r1/frr.conf +++ b/tests/topotests/bgp_path_attribute_discard/r1/frr.conf @@ -6,4 +6,5 @@ router bgp 65001 no bgp ebgp-requires-policy neighbor 10.0.0.254 remote-as external neighbor 10.0.0.254 timers 3 10 + neighbor 10.0.0.254 timers connect 1 ! diff --git a/tests/topotests/bgp_path_attribute_discard/r2/frr.conf b/tests/topotests/bgp_path_attribute_discard/r2/frr.conf index 1dafbdd8e19f..30ffdefff3f5 100644 --- a/tests/topotests/bgp_path_attribute_discard/r2/frr.conf +++ b/tests/topotests/bgp_path_attribute_discard/r2/frr.conf @@ -6,5 +6,6 @@ router bgp 65254 no bgp ebgp-requires-policy neighbor 10.0.0.254 remote-as internal neighbor 10.0.0.254 timers 3 10 + neighbor 10.0.0.254 timers connect 1 neighbor 10.0.0.254 path-attribute discard 26 ! diff --git a/tests/topotests/bgp_peer_type_multipath_relax/r1/bgpd.conf b/tests/topotests/bgp_peer_type_multipath_relax/r1/bgpd.conf index 038f108aa8b2..e743010922f5 100644 --- a/tests/topotests/bgp_peer_type_multipath_relax/r1/bgpd.conf +++ b/tests/topotests/bgp_peer_type_multipath_relax/r1/bgpd.conf @@ -8,9 +8,17 @@ router bgp 64510 bgp bestpath compare-routerid bgp bestpath peer-type multipath-relax neighbor 10.0.1.2 remote-as 64510 + neighbor 10.0.1.2 timers 3 10 + neighbor 10.0.1.2 timers connect 1 neighbor 10.0.3.2 remote-as 64502 + neighbor 10.0.3.2 timers 3 10 + neighbor 10.0.3.2 timers connect 1 neighbor 10.0.4.2 remote-as 64503 + neighbor 10.0.4.2 timers 3 10 + neighbor 10.0.4.2 timers connect 1 neighbor 10.0.5.2 remote-as 64511 + neighbor 10.0.5.2 timers 3 10 + neighbor 10.0.5.2 timers connect 1 ! line vty ! diff --git a/tests/topotests/bgp_peer_type_multipath_relax/r2/bgpd.conf b/tests/topotests/bgp_peer_type_multipath_relax/r2/bgpd.conf index 2362a19f265a..1da7173bba01 100644 --- a/tests/topotests/bgp_peer_type_multipath_relax/r2/bgpd.conf +++ b/tests/topotests/bgp_peer_type_multipath_relax/r2/bgpd.conf @@ -7,7 +7,11 @@ router bgp 64511 bgp router-id 10.0.5.2 no bgp ebgp-requires-policy neighbor 10.0.2.2 remote-as 64511 + neighbor 10.0.2.2 timers 3 10 + neighbor 10.0.2.2 timers connect 1 neighbor 10.0.5.1 remote-as 64510 + neighbor 10.0.5.1 timers 3 10 + neighbor 10.0.5.1 timers connect 1 ! address-family ipv4 unicast neighbor 10.0.5.1 route-map dropall in diff --git a/tests/topotests/bgp_prefix_sid/r1/bgpd.conf b/tests/topotests/bgp_prefix_sid/r1/bgpd.conf index e02226f2fd64..3fd5e5e9c3cd 100644 --- a/tests/topotests/bgp_prefix_sid/r1/bgpd.conf +++ b/tests/topotests/bgp_prefix_sid/r1/bgpd.conf @@ -7,8 +7,10 @@ router bgp 1 no bgp ebgp-requires-policy neighbor 10.0.0.101 remote-as 2 neighbor 10.0.0.101 timers 3 10 + neighbor 10.0.0.101 timers connect 1 neighbor 10.0.0.102 remote-as 3 neighbor 10.0.0.102 timers 3 10 + neighbor 10.0.0.102 timers connect 1 ! address-family ipv4 labeled-unicast neighbor 10.0.0.101 activate diff --git a/tests/topotests/bgp_prefix_sid2/r1/bgpd.conf b/tests/topotests/bgp_prefix_sid2/r1/bgpd.conf index b3ca0e114d17..946103c30fd2 100644 --- a/tests/topotests/bgp_prefix_sid2/r1/bgpd.conf +++ b/tests/topotests/bgp_prefix_sid2/r1/bgpd.conf @@ -18,6 +18,7 @@ router bgp 1 no bgp ebgp-requires-policy neighbor 10.0.0.101 remote-as 2 neighbor 10.0.0.101 timers 3 10 + neighbor 10.0.0.101 timers connect 1 ! address-family ipv6 vpn neighbor 10.0.0.101 activate diff --git a/tests/topotests/bgp_route_server_client/r1/bgpd.conf b/tests/topotests/bgp_route_server_client/r1/bgpd.conf index e464e6c50b88..d379f7df4527 100644 --- a/tests/topotests/bgp_route_server_client/r1/bgpd.conf +++ b/tests/topotests/bgp_route_server_client/r1/bgpd.conf @@ -5,7 +5,7 @@ router bgp 65001 no bgp enforce-first-as neighbor 2001:db8:1::1 remote-as external neighbor 2001:db8:1::1 timers 3 10 - neighbor 2001:db8:1::1 timers connect 5 + neighbor 2001:db8:1::1 timers connect 1 address-family ipv6 unicast redistribute connected neighbor 2001:db8:1::1 activate diff --git a/tests/topotests/bgp_route_server_client/r2/bgpd.conf b/tests/topotests/bgp_route_server_client/r2/bgpd.conf index 19607660f98f..7fda2b0a058f 100644 --- a/tests/topotests/bgp_route_server_client/r2/bgpd.conf +++ b/tests/topotests/bgp_route_server_client/r2/bgpd.conf @@ -3,16 +3,16 @@ router bgp 65000 view RS no bgp ebgp-requires-policy neighbor 2001:db8:1::2 remote-as external neighbor 2001:db8:1::2 timers 3 10 - neighbor 2001:db8:1::2 timers connect 5 + neighbor 2001:db8:1::2 timers connect 1 neighbor 2001:db8:1::3 remote-as external neighbor 2001:db8:1::3 timers 3 10 - neighbor 2001:db8:1::3 timers connect 5 + neighbor 2001:db8:1::3 timers connect 1 neighbor 2001:db8:1::4 remote-as external neighbor 2001:db8:1::4 timers 3 10 - neighbor 2001:db8:1::4 timers connect 5 + neighbor 2001:db8:1::4 timers connect 1 neighbor 2001:db8:3::2 remote-as external neighbor 2001:db8:3::2 timers 3 10 - neighbor 2001:db8:3::2 timers connect 5 + neighbor 2001:db8:3::2 timers connect 1 address-family ipv6 unicast redistribute connected neighbor 2001:db8:1::2 activate diff --git a/tests/topotests/bgp_route_server_client/r3/bgpd.conf b/tests/topotests/bgp_route_server_client/r3/bgpd.conf index f7daba87face..2f20b9133499 100644 --- a/tests/topotests/bgp_route_server_client/r3/bgpd.conf +++ b/tests/topotests/bgp_route_server_client/r3/bgpd.conf @@ -5,7 +5,7 @@ router bgp 65003 no bgp enforce-first-as neighbor 2001:db8:3::1 remote-as external neighbor 2001:db8:3::1 timers 3 10 - neighbor 2001:db8:3::1 timers connect 5 + neighbor 2001:db8:3::1 timers connect 1 address-family ipv6 unicast redistribute connected neighbor 2001:db8:3::1 activate diff --git a/tests/topotests/bgp_route_server_client/r4/bgpd.conf b/tests/topotests/bgp_route_server_client/r4/bgpd.conf index c907d7284e22..66a15730186f 100644 --- a/tests/topotests/bgp_route_server_client/r4/bgpd.conf +++ b/tests/topotests/bgp_route_server_client/r4/bgpd.conf @@ -5,7 +5,7 @@ router bgp 65004 no bgp enforce-first-as neighbor 2001:db8:1::1 remote-as external neighbor 2001:db8:1::1 timers 3 10 - neighbor 2001:db8:1::1 timers connect 5 + neighbor 2001:db8:1::1 timers connect 1 address-family ipv6 unicast redistribute connected neighbor 2001:db8:1::1 activate diff --git a/tests/topotests/bgp_vrf_netns/r1/bgpd.conf b/tests/topotests/bgp_vrf_netns/r1/bgpd.conf index 572dce745574..2853a7a5caa2 100644 --- a/tests/topotests/bgp_vrf_netns/r1/bgpd.conf +++ b/tests/topotests/bgp_vrf_netns/r1/bgpd.conf @@ -5,6 +5,7 @@ router bgp 100 vrf r1-bgp-cust1 no bgp ebgp-requires-policy neighbor 10.0.1.101 remote-as 99 neighbor 10.0.1.101 timers 3 10 + neighbor 10.0.1.101 timers connect 1 ! ! From e6028d02a1497a79ac4ac220457c5f509abe3dcc Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 4 Dec 2024 12:25:11 -0500 Subject: [PATCH 054/106] tests: Fix invalid escape seq seen in bgp_nexthop_ipv6 Signed-off-by: Donald Sharp --- tests/topotests/bgp_nexthop_ipv6/test_bgp_nexthop_ipv6_topo1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/topotests/bgp_nexthop_ipv6/test_bgp_nexthop_ipv6_topo1.py b/tests/topotests/bgp_nexthop_ipv6/test_bgp_nexthop_ipv6_topo1.py index 7875f2e0f6a6..58daee32c3eb 100644 --- a/tests/topotests/bgp_nexthop_ipv6/test_bgp_nexthop_ipv6_topo1.py +++ b/tests/topotests/bgp_nexthop_ipv6/test_bgp_nexthop_ipv6_topo1.py @@ -36,7 +36,7 @@ def build_topo(tgen): - """ + r""" All peers are FRR BGP peers except r3 that is a exabgp peer. rr is a route-reflector for AS 65000 iBGP peers. Exabgp does not send any IPv6 Link-Local nexthop From f61dde2d9c9dacdebfa9e23817beef61c97ec26e Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 2 Dec 2024 11:07:34 +0100 Subject: [PATCH 055/106] bgpd: fix peer up message for loc-rib not sent At startup, there is no peer up message for loc-rib instance peer. Instead, a global peer up message with address 0.0.0.0 is sent. Such message is wrong, violates the RFC and should be dropped by a strict collector. Actually, the peer type message sent is wrong, and should be set to LOC-RIB peer type. Fix this by changing the peer type of peer up message to either loc-rib or global instance peer type. Fixes: 035304c25a38 ("bgpd: bmp loc-rib peer up/down for vrfs") Signed-off-by: Philippe Guibert --- bgpd/bgp_bmp.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index 2e3a0388d0ed..d6df56026078 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -467,13 +467,19 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down) struct stream *s; size_t len; struct timeval uptime, uptime_real; + uint8_t peer_type; + bool is_locrib = false; uptime.tv_sec = peer->uptime; uptime.tv_usec = 0; monotime_to_realtime(&uptime, &uptime_real); - uint8_t peer_type = bmp_get_peer_type(peer); - bool is_locrib = peer_type == BMP_PEER_TYPE_LOC_RIB_INSTANCE; + peer_type = bmp_get_peer_type(peer); + if (peer_type == BMP_PEER_TYPE_LOC_RIB_INSTANCE) + is_locrib = true; + else + /* TODO: remove this when other RD and local instances supported */ + peer_type = BMP_PEER_TYPE_GLOBAL_INSTANCE; #define BGP_BMP_MAX_PACKET_SIZE 1024 #define BMP_PEERUP_INFO_TYPE_STRING 0 @@ -484,9 +490,7 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down) bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_PEER_UP_NOTIFICATION); - bmp_per_peer_hdr(s, peer->bgp, peer, 0, - BMP_PEER_TYPE_GLOBAL_INSTANCE, 0, - &uptime_real); + bmp_per_peer_hdr(s, peer->bgp, peer, 0, peer_type, 0, &uptime_real); /* Local Address (16 bytes) */ if (is_locrib) From 35f77c523b4f23cdb4774a2a280e7b5394272f82 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Tue, 3 Dec 2024 15:48:26 +0100 Subject: [PATCH 056/106] topotests: bmp, test that loc-rib peer up message is sent Add a test at startup to ensure that peer up message for loc-rib is correctly set. Signed-off-by: Philippe Guibert --- tests/topotests/bgp_bmp/bgpbmp.py | 15 ++++++++++----- tests/topotests/bgp_bmp/test_bgp_bmp_1.py | 2 +- tests/topotests/bgp_bmp/test_bgp_bmp_2.py | 2 +- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/tests/topotests/bgp_bmp/bgpbmp.py b/tests/topotests/bgp_bmp/bgpbmp.py index 41995e2b5e53..5e8b0d9be72d 100644 --- a/tests/topotests/bgp_bmp/bgpbmp.py +++ b/tests/topotests/bgp_bmp/bgpbmp.py @@ -216,11 +216,16 @@ def bmp_check_for_peer_message( ] # get the list of pairs (prefix, policy, seq) for the given message type - peers = [ - m["peer_ip"] - for m in messages - if "peer_ip" in m.keys() and m["bmp_log_type"] == bmp_log_type - ] + peers = [] + for m in messages: + if ( + "peer_ip" in m.keys() + and m["peer_ip"] != "0.0.0.0" + and m["bmp_log_type"] == bmp_log_type + ): + peers.append(m["peer_ip"]) + elif m["policy"] == "loc-rib" and m["bmp_log_type"] == bmp_log_type: + peers.append("0.0.0.0") # check for prefixes for ep in expected_peers: diff --git a/tests/topotests/bgp_bmp/test_bgp_bmp_1.py b/tests/topotests/bgp_bmp/test_bgp_bmp_1.py index 61428634414c..be3e07929a0f 100644 --- a/tests/topotests/bgp_bmp/test_bgp_bmp_1.py +++ b/tests/topotests/bgp_bmp/test_bgp_bmp_1.py @@ -192,7 +192,7 @@ def test_peer_up(): """ tgen = get_topogen() - peers = ["192.168.0.2", "192:168::2"] + peers = ["192.168.0.2", "192:168::2", "0.0.0.0"] logger.info("checking for BMP peers up messages") diff --git a/tests/topotests/bgp_bmp/test_bgp_bmp_2.py b/tests/topotests/bgp_bmp/test_bgp_bmp_2.py index b45452e7c475..e8f67515bd5d 100644 --- a/tests/topotests/bgp_bmp/test_bgp_bmp_2.py +++ b/tests/topotests/bgp_bmp/test_bgp_bmp_2.py @@ -200,7 +200,7 @@ def test_peer_up(): """ tgen = get_topogen() - peers = ["192.168.0.2", "192:168::2"] + peers = ["192.168.0.2", "192:168::2", "0.0.0.0"] logger.info("checking for BMP peers up messages") From b43750ec68948d04189536428b6ac5c601f82d2b Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Fri, 6 Dec 2024 08:25:09 +0200 Subject: [PATCH 057/106] bgpd: Check if as_type is not specified when peer is a peer-group member Fixes this sequences: ``` neighbor pg4 peer-group neighbor 127.0.0.4 peer-group pg4 neighbor 127.0.0.4 remote-as 65004 neighbor pg5 peer-group neighbor 127.0.0.5 peer-group pg5 neighbor 127.0.0.5 remote-as internal ``` Fixes: 0dfe256 ("bgpd: Implement neighbor X remote-as auto") Signed-off-by: Donatas Abraitis --- bgpd/bgpd.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index dccac3eceb19..7b21c29ea663 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2158,8 +2158,7 @@ int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if, /* When this peer is a member of peer-group. */ if (peer->group) { /* peer-group already has AS number/internal/external */ - if (peer->group->conf->as - || peer->group->conf->as_type) { + if (peer->group->conf->as || peer->group->conf->as_type != AS_UNSPECIFIED) { /* Return peer group's AS number. */ *as = peer->group->conf->as; return BGP_ERR_PEER_GROUP_MEMBER; From 805aaec49cada23d529a4482c4f3fcb47fc087e6 Mon Sep 17 00:00:00 2001 From: Igor Ryzhov Date: Sat, 30 Nov 2024 17:16:37 +0200 Subject: [PATCH 058/106] doc: remove no-op "netns NAMESPACE" command from the docs Signed-off-by: Igor Ryzhov --- doc/user/zebra.rst | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index b862ba9f505c..9b9298c1cd99 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -526,16 +526,6 @@ commands in relationship to VRF. Here is an extract of some of those commands: The network administrator can however decide to provision this command in configuration file to provide more clarity about the intended configuration. -.. clicmd:: netns NAMESPACE - - This command is based on VRF configuration mode. This command is available - when *Zebra* is run in :option:`-n` mode. This command reflects which *Linux - network namespace* is to be mapped with *Zebra* VRF. It is to be noted that - *Zebra* creates and detects added/suppressed VRFs from the Linux environment - (in fact, those managed with iproute2). The network administrator can however - decide to provision this command in configuration file to provide more clarity - about the intended configuration. - .. clicmd:: show ip route vrf VRF The show command permits dumping the routing table associated to the VRF. If From 4be15e532185a5f8a5bd6d25af133a715baad2d3 Mon Sep 17 00:00:00 2001 From: Igor Ryzhov Date: Sat, 7 Dec 2024 17:01:43 +0200 Subject: [PATCH 059/106] zebra: add deprecation notice for no-op netns command Signed-off-by: Igor Ryzhov --- zebra/zebra_cli.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/zebra/zebra_cli.c b/zebra/zebra_cli.c index 6ee0fdbb8d90..ca53eb2eb34d 100644 --- a/zebra/zebra_cli.c +++ b/zebra/zebra_cli.c @@ -2252,6 +2252,9 @@ static void lib_vrf_mpls_fec_nexthop_resolution_cli_write( } } +#if CONFDATE > 20251207 +CPP_NOTICE("Remove no-op netns command") +#endif DEFPY_YANG (vrf_netns, vrf_netns_cmd, "[no] netns ![NAME$netns_name]", From 69ea3eb0d91ebab7cbb2edcb3df17711b5a63511 Mon Sep 17 00:00:00 2001 From: anlan_cs Date: Thu, 5 Dec 2024 11:56:34 +0800 Subject: [PATCH 060/106] zebra: use macro for one check Signed-off-by: anlan_cs --- zebra/zebra_rib.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index b2543ca0e8b1..574083ae0283 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -4406,9 +4406,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, if (ng) { nhe.nhg.nexthop = ng->nexthop; - if (re->type == ZEBRA_ROUTE_CONNECT || - re->type == ZEBRA_ROUTE_LOCAL || - re->type == ZEBRA_ROUTE_KERNEL) + if (RIB_SYSTEM_ROUTE(re)) SET_FLAG(nhe.flags, NEXTHOP_GROUP_INITIAL_DELAY_INSTALL); } else if (re->nhe_id > 0) nhe.id = re->nhe_id; From 0589950395fc291ca1bcf498df4f0b5d3c96f82a Mon Sep 17 00:00:00 2001 From: Corey Siltala Date: Mon, 25 Nov 2024 10:43:30 -0600 Subject: [PATCH 061/106] pimd: Move ACL handling to pim_util.c Move the extended access-list handling from pim_msdp_packet.c to pim_util.c to allow use elsewhere in the daemon. Signed-off-by: Corey Siltala --- pimd/pim_msdp_packet.c | 51 ++---------------------------------------- pimd/pim_util.c | 41 +++++++++++++++++++++++++++++++++ pimd/pim_util.h | 3 +++ 3 files changed, 46 insertions(+), 49 deletions(-) diff --git a/pimd/pim_msdp_packet.c b/pimd/pim_msdp_packet.c index f66a941ee312..c858bad1adbb 100644 --- a/pimd/pim_msdp_packet.c +++ b/pimd/pim_msdp_packet.c @@ -367,53 +367,6 @@ static void pim_msdp_pkt_sa_fill_one(struct pim_msdp_sa *sa) stream_put_ipv4(sa->pim->msdp.work_obuf, sa->sg.src.s_addr); } -static bool msdp_cisco_match(const struct filter *filter, - const struct in_addr *source, - const struct in_addr *group) -{ - const struct filter_cisco *cfilter = &filter->u.cfilter; - uint32_t source_addr; - uint32_t group_addr; - - group_addr = group->s_addr & ~cfilter->mask_mask.s_addr; - - if (cfilter->extended) { - source_addr = source->s_addr & ~cfilter->addr_mask.s_addr; - if (group_addr == cfilter->mask.s_addr && - source_addr == cfilter->addr.s_addr) - return true; - } else if (group_addr == cfilter->addr.s_addr) - return true; - - return false; -} - -static enum filter_type msdp_access_list_apply(struct access_list *access, - const struct in_addr *source, - const struct in_addr *group) -{ - struct filter *filter; - struct prefix group_prefix; - - if (access == NULL) - return FILTER_DENY; - - for (filter = access->head; filter; filter = filter->next) { - if (filter->cisco) { - if (msdp_cisco_match(filter, source, group)) - return filter->type; - } else { - group_prefix.family = AF_INET; - group_prefix.prefixlen = IPV4_MAX_BITLEN; - group_prefix.u.prefix4.s_addr = group->s_addr; - if (access_list_apply(access, &group_prefix)) - return filter->type; - } - } - - return FILTER_DENY; -} - bool msdp_peer_sa_filter(const struct pim_msdp_peer *mp, const struct pim_msdp_sa *sa) { @@ -425,7 +378,7 @@ bool msdp_peer_sa_filter(const struct pim_msdp_peer *mp, /* Find access list and test it. */ acl = access_list_lookup(AFI_IP, mp->acl_out); - if (msdp_access_list_apply(acl, &sa->sg.src, &sa->sg.grp) == FILTER_DENY) + if (pim_access_list_apply(acl, &sa->sg.src, &sa->sg.grp) == FILTER_DENY) return true; return false; @@ -641,7 +594,7 @@ static void pim_msdp_pkt_sa_rx_one(struct pim_msdp_peer *mp, struct in_addr rp) /* Filter incoming SA with configured access list. */ if (mp->acl_in) { acl = access_list_lookup(AFI_IP, mp->acl_in); - if (msdp_access_list_apply(acl, &sg.src, &sg.grp) == FILTER_DENY) { + if (pim_access_list_apply(acl, &sg.src, &sg.grp) == FILTER_DENY) { if (pim_msdp_log_sa_events(mp->pim)) zlog_info("MSDP peer %pI4 filter SA in (%pI4, %pI4)", &mp->peer, &sg.src, &sg.grp); diff --git a/pimd/pim_util.c b/pimd/pim_util.c index 657e84ae50aa..49ae6949a2b7 100644 --- a/pimd/pim_util.c +++ b/pimd/pim_util.c @@ -126,6 +126,47 @@ int pim_is_group_224_4(struct in_addr group_addr) return prefix_match(&group_all, &group); } +static bool pim_cisco_match(const struct filter *filter, const struct in_addr *source, + const struct in_addr *group) +{ + const struct filter_cisco *cfilter = &filter->u.cfilter; + uint32_t source_addr; + uint32_t group_addr; + + group_addr = group->s_addr & ~cfilter->mask_mask.s_addr; + + if (cfilter->extended) { + source_addr = source->s_addr & ~cfilter->addr_mask.s_addr; + if (group_addr == cfilter->mask.s_addr && source_addr == cfilter->addr.s_addr) + return true; + } else if (group_addr == cfilter->addr.s_addr) + return true; + + return false; +} + +enum filter_type pim_access_list_apply(struct access_list *access, const struct in_addr *source, + const struct in_addr *group) +{ + struct filter *filter; + struct prefix group_prefix = {}; + + if (access == NULL) + return FILTER_DENY; + + for (filter = access->head; filter; filter = filter->next) { + if (filter->cisco) { + if (pim_cisco_match(filter, source, group)) + return filter->type; + } + } + + group_prefix.family = AF_INET; + group_prefix.prefixlen = IPV4_MAX_BITLEN; + group_prefix.u.prefix4.s_addr = group->s_addr; + return access_list_apply(access, &group_prefix); +} + bool pim_is_group_filtered(struct pim_interface *pim_ifp, pim_addr *grp) { struct prefix grp_pfx; diff --git a/pimd/pim_util.h b/pimd/pim_util.h index c882fe4878a3..cffa93ed2955 100644 --- a/pimd/pim_util.h +++ b/pimd/pim_util.h @@ -10,6 +10,7 @@ #include #include +#include "lib/filter.h" #include "checksum.h" #include "pimd.h" @@ -22,6 +23,8 @@ void pim_pkt_dump(const char *label, const uint8_t *buf, int size); int pim_is_group_224_0_0_0_24(struct in_addr group_addr); int pim_is_group_224_4(struct in_addr group_addr); +enum filter_type pim_access_list_apply(struct access_list *access, const struct in_addr *source, + const struct in_addr *group); bool pim_is_group_filtered(struct pim_interface *pim_ifp, pim_addr *grp); int pim_get_all_mcast_group(struct prefix *prefix); bool pim_addr_is_multicast(pim_addr addr); From 3db9117e7a8ccea0c8913b2aa232b1727b70ef98 Mon Sep 17 00:00:00 2001 From: Corey Siltala Date: Mon, 25 Nov 2024 10:36:54 -0600 Subject: [PATCH 062/106] pimd,yang: Extend multicast boundary functionality Add new interface command ip multicast boundary ACCESSLIST4_NAME. This allows filtering on both source and group using the extended access-list syntax vs. group-only as with the existing "ip multicast boundary oil" command, which uses prefix-lists. If both are configured, the prefix- list is evaluated first. The default behavior for both prefix-lists and access-lists remains "deny", so the prefix-list must have a terminating "permit" statement in order to also evaluate against the access-list. The following example denies groups in range 229.1.1.0/24 and groups in range 232.1.1.0/24 with source 10.0.20.2: ! ip prefix-list pim-oil-plist seq 10 deny 229.1.1.0/24 ip prefix-list pim-oil-plist seq 20 permit any ! access-list pim-acl seq 10 deny ip host 10.0.20.2 232.1.1.0 0.0.0.255 access-list pim-acl seq 20 permit ip any any ! interface r1-eth0 ip address 10.0.20.1/24 ip igmp ip pim ip multicast boundary oil pim-oil-plist ip multicast boundary pim-acl ! Signed-off-by: Corey Siltala --- pimd/pim_cmd.c | 16 +++++++++++ pimd/pim_iface.c | 9 ++++++ pimd/pim_iface.h | 4 ++- pimd/pim_igmp.c | 2 +- pimd/pim_igmpv2.c | 3 ++ pimd/pim_igmpv3.c | 23 ++++++++-------- pimd/pim_join.c | 14 ++++------ pimd/pim_mroute.c | 8 ++++-- pimd/pim_nb.c | 7 +++++ pimd/pim_nb.h | 2 ++ pimd/pim_nb_config.c | 65 ++++++++++++++++++++++++++++++++++++++++++++ pimd/pim_util.c | 43 ++++++++++++++++++++++++----- pimd/pim_util.h | 2 +- pimd/pim_vty.c | 7 +++++ yang/frr-pim.yang | 12 +++++++- 15 files changed, 184 insertions(+), 33 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index f4c25ea81ea9..bac9645759e6 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -5871,6 +5871,21 @@ DEFUN(interface_no_ip_pim_boundary_oil, return pim_process_no_ip_pim_boundary_oil_cmd(vty); } +DEFPY_YANG(interface_ip_pim_boundary_acl, + interface_ip_pim_boundary_acl_cmd, + "[no] ip multicast boundary ACCESSLIST4_NAME$name", + NO_STR + IP_STR + "Generic multicast configuration options\n" + "Define multicast boundary\n" + "Access-list to filter OIL with by source and group\n") +{ + nb_cli_enqueue_change(vty, "./multicast-boundary-acl", + (!!no ? NB_OP_DESTROY : NB_OP_MODIFY), name); + + return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH, FRR_PIM_AF_XPATH_VAL); +} + DEFUN (interface_ip_mroute, interface_ip_mroute_cmd, "ip mroute INTERFACE A.B.C.D [A.B.C.D]", @@ -9018,6 +9033,7 @@ void pim_cmd_init(void) install_element(INTERFACE_NODE, &interface_no_ip_pim_hello_cmd); install_element(INTERFACE_NODE, &interface_ip_pim_boundary_oil_cmd); install_element(INTERFACE_NODE, &interface_no_ip_pim_boundary_oil_cmd); + install_element(INTERFACE_NODE, &interface_ip_pim_boundary_acl_cmd); install_element(INTERFACE_NODE, &interface_ip_igmp_query_generate_cmd); // Static mroutes NEB diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 19460aa445d6..f92a42dd8a54 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -38,6 +38,7 @@ #include "pim_igmp_join.h" #include "pim_vxlan.h" #include "pim_tib.h" +#include "pim_util.h" #include "pim6_mld.h" @@ -1258,6 +1259,14 @@ static int gm_join_sock(const char *ifname, ifindex_t ifindex, { int join_fd; + if (pim_is_group_filtered(pim_ifp, &group_addr, &source_addr)) { + if (PIM_DEBUG_GM_EVENTS) { + zlog_debug("%s: join failed for (S,G)=(%pPAs,%pPAs) due to multicast boundary filtering", + __func__, &source_addr, &group_addr); + } + return -1; + } + pim_ifp->igmp_ifstat_joins_sent++; join_fd = pim_socket_raw(IPPROTO_GM); diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h index 95bac084d2bb..18e88ffbd5dc 100644 --- a/pimd/pim_iface.h +++ b/pimd/pim_iface.h @@ -133,8 +133,10 @@ struct pim_interface { uint32_t pim_dr_priority; /* config */ int pim_dr_num_nondrpri_neighbors; /* neighbors without dr_pri */ - /* boundary prefix-list */ + /* boundary prefix-list (group) */ char *boundary_oil_plist; + /* boundary access-list (source and group) */ + struct access_list *boundary_acl; /* Turn on Active-Active for this interface */ bool activeactive; diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c index 1ba9bc45a20b..12f424248f9f 100644 --- a/pimd/pim_igmp.c +++ b/pimd/pim_igmp.c @@ -666,7 +666,7 @@ static int igmp_v1_recv_report(struct gm_sock *igmp, struct in_addr from, memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr)); - if (pim_is_group_filtered(ifp->info, &group_addr)) + if (pim_is_group_filtered(ifp->info, &group_addr, NULL)) return -1; /* non-existent group is created as INCLUDE {empty} */ diff --git a/pimd/pim_igmpv2.c b/pimd/pim_igmpv2.c index 944dffdc3389..720a4944fef5 100644 --- a/pimd/pim_igmpv2.c +++ b/pimd/pim_igmpv2.c @@ -134,6 +134,9 @@ int igmp_v2_recv_report(struct gm_sock *igmp, struct in_addr from, ifp->name, group_str); } + if (pim_is_group_filtered(pim_ifp, &group_addr, NULL)) + return -1; + /* * RFC 4604 * section 2.2.1 diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c index 2c5ad4d44b1b..d0ba79378b31 100644 --- a/pimd/pim_igmpv3.c +++ b/pimd/pim_igmpv3.c @@ -507,6 +507,8 @@ static void allow(struct gm_sock *igmp, struct in_addr from, struct in_addr *src_addr; src_addr = sources + i; + if (pim_is_group_filtered(igmp->interface->info, &group_addr, src_addr)) + continue; source = igmp_get_source_by_addr(group, *src_addr, NULL); if (!source) @@ -646,7 +648,7 @@ void igmpv3_report_isex(struct gm_sock *igmp, struct in_addr from, on_trace(__func__, ifp, from, group_addr, num_sources, sources); - if (pim_is_group_filtered(ifp->info, &group_addr)) + if (pim_is_group_filtered(ifp->info, &group_addr, NULL)) return; /* non-existent group is created as INCLUDE {empty} */ @@ -1809,12 +1811,13 @@ static bool igmp_pkt_grp_addr_ok(struct interface *ifp, const char *from_str, pim_ifp = ifp->info; /* determine filtering status for group */ - if (pim_is_group_filtered(pim_ifp, &grp)) { + if (pim_is_group_filtered(pim_ifp, &grp, NULL)) { if (PIM_DEBUG_GM_PACKETS) { - zlog_debug( - "Filtering IGMPv3 group record %pI4 from %s on %s per prefix-list %s", - &grp.s_addr, from_str, ifp->name, - pim_ifp->boundary_oil_plist); + zlog_debug("Filtering IGMPv3 group record %pI4 from %s on %s per prefix-list %s or access-list %s", + &grp.s_addr, from_str, ifp->name, + (pim_ifp->boundary_oil_plist ? pim_ifp->boundary_oil_plist + : "(not found)"), + (pim_ifp->boundary_acl ? pim_ifp->boundary_acl->name : "(not found)")); } return false; } @@ -1943,11 +1946,9 @@ int igmp_v3_recv_report(struct gm_sock *igmp, struct in_addr from, sizeof(struct in_addr)); if (PIM_DEBUG_GM_PACKETS) { - zlog_debug( - " Recv IGMP report v3 from %s on %s: record=%d type=%d auxdatalen=%d sources=%d group=%pI4", - from_str, ifp->name, i, rec_type, - rec_auxdatalen, rec_num_sources, - &rec_group); + zlog_debug(" Recv IGMP report v3 (type %d) from %s on %s: record=%d type=%d auxdatalen=%d sources=%d group=%pI4", + rec_type, from_str, ifp->name, i, rec_type, rec_auxdatalen, + rec_num_sources, &rec_group); } /* Scan sources */ diff --git a/pimd/pim_join.c b/pimd/pim_join.c index 2feafabb4dff..7796e8b95169 100644 --- a/pimd/pim_join.c +++ b/pimd/pim_join.c @@ -245,7 +245,7 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, uint16_t msg_num_pruned_sources; int source; struct pim_ifchannel *starg_ch = NULL, *sg_ch = NULL; - bool filtered = false; + bool group_filtered = false; memset(&sg, 0, sizeof(sg)); addr_offset = pim_parse_addr_group(&sg, buf, pastend - buf); @@ -275,7 +275,7 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, &src_addr, ifp->name); /* boundary check */ - filtered = pim_is_group_filtered(pim_ifp, &sg.grp); + group_filtered = pim_is_group_filtered(pim_ifp, &sg.grp, NULL); /* Scan joined sources */ for (source = 0; source < msg_num_joined_sources; ++source) { @@ -287,8 +287,8 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, buf += addr_offset; - /* if we are filtering this group, skip the join */ - if (filtered) + /* if we are filtering this group or (S,G), skip the join */ + if (group_filtered || pim_is_group_filtered(pim_ifp, &sg.grp, &sg.src)) continue; recv_join(ifp, neigh, msg_holdtime, msg_upstream_addr, @@ -312,10 +312,6 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, buf += addr_offset; - /* if we are filtering this group, skip the prune */ - if (filtered) - continue; - recv_prune(ifp, neigh, msg_holdtime, msg_upstream_addr, &sg, msg_source_flags); /* @@ -361,7 +357,7 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, } } } - if (starg_ch && !filtered) + if (starg_ch && !group_filtered) pim_ifchannel_set_star_g_join_state(starg_ch, 1, 0); starg_ch = NULL; } /* scan groups */ diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index 9d290c3c6f2b..96eb5f48f523 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -35,6 +35,7 @@ #include "pim_sock.h" #include "pim_vxlan.h" #include "pim_msg.h" +#include "pim_util.h" static void mroute_read_on(struct pim_instance *pim); static int pim_upstream_mroute_update(struct channel_oil *c_oil, @@ -271,7 +272,9 @@ int pim_mroute_msg_nocache(int fd, struct interface *ifp, const kernmsg *msg) *oil_incoming_vif(up->channel_oil) >= MAXVIFS) { pim_upstream_mroute_iif_update(up->channel_oil, __func__); } - pim_register_join(up); + + if (!pim_is_group_filtered(pim_ifp, &sg.grp, &sg.src)) + pim_register_join(up); /* if we have receiver, inherit from parent */ pim_upstream_inherited_olist_decide(pim_ifp->pim, up); @@ -632,7 +635,8 @@ int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, const char *buf, pim_upstream_keep_alive_timer_start( up, pim_ifp->pim->keep_alive_time); up->channel_oil->cc.pktcnt++; - pim_register_join(up); + if (!pim_is_group_filtered(pim_ifp, &sg.grp, &sg.src)) + pim_register_join(up); pim_upstream_inherited_olist(pim_ifp->pim, up); if (!up->channel_oil->installed) pim_upstream_mroute_add(up->channel_oil, __func__); diff --git a/pimd/pim_nb.c b/pimd/pim_nb.c index 4a5ad87942b2..2b39f2dcb827 100644 --- a/pimd/pim_nb.c +++ b/pimd/pim_nb.c @@ -352,6 +352,13 @@ const struct frr_yang_module_info frr_pim_info = { .destroy = lib_interface_pim_address_family_multicast_boundary_oil_destroy, } }, + { + .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family/multicast-boundary-acl", + .cbs = { + .modify = lib_interface_pim_address_family_multicast_boundary_acl_modify, + .destroy = lib_interface_pim_address_family_multicast_boundary_acl_destroy, + } + }, { .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family/mroute", .cbs = { diff --git a/pimd/pim_nb.h b/pimd/pim_nb.h index a9693c65d8e6..f27b86680fb4 100644 --- a/pimd/pim_nb.h +++ b/pimd/pim_nb.h @@ -140,6 +140,8 @@ int lib_interface_pim_address_family_multicast_boundary_oil_modify( struct nb_cb_modify_args *args); int lib_interface_pim_address_family_multicast_boundary_oil_destroy( struct nb_cb_destroy_args *args); +int lib_interface_pim_address_family_multicast_boundary_acl_modify(struct nb_cb_modify_args *args); +int lib_interface_pim_address_family_multicast_boundary_acl_destroy(struct nb_cb_destroy_args *args); int lib_interface_pim_address_family_mroute_create( struct nb_cb_create_args *args); int lib_interface_pim_address_family_mroute_destroy( diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index 171614208f09..2533f8c4d491 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -2452,6 +2452,71 @@ int lib_interface_pim_address_family_multicast_boundary_oil_destroy( return NB_OK; } +/* + * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/multicast-boundary-acl + */ +int lib_interface_pim_address_family_multicast_boundary_acl_modify(struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + const struct lyd_node *if_dnode; + + switch (args->event) { + case NB_EV_VALIDATE: + if_dnode = yang_dnode_get_parent(args->dnode, "interface"); + if (!is_pim_interface(if_dnode)) { + snprintf(args->errmsg, args->errmsg_len, + "%% Enable PIM and/or IGMP on this interface first"); + return NB_ERR_VALIDATION; + } + if (!access_list_lookup(AFI_IP, yang_dnode_get_string(args->dnode, NULL))) { + snprintf(args->errmsg, args->errmsg_len, + "%% Specified access-list not found"); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_ABORT: + case NB_EV_PREPARE: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + pim_ifp = ifp->info; + pim_ifp->boundary_acl = + access_list_lookup(AFI_IP, yang_dnode_get_string(args->dnode, NULL)); + break; + } + + return NB_OK; +} + +int lib_interface_pim_address_family_multicast_boundary_acl_destroy(struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + const struct lyd_node *if_dnode; + + switch (args->event) { + case NB_EV_VALIDATE: + if_dnode = yang_dnode_get_parent(args->dnode, "interface"); + if (!is_pim_interface(if_dnode)) { + snprintf(args->errmsg, args->errmsg_len, + "%% Enable PIM and/or IGMP on this interface first"); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_ABORT: + case NB_EV_PREPARE: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + pim_ifp = ifp->info; + pim_ifp->boundary_acl = NULL; + break; + } + + return NB_OK; +} + /* * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/mroute */ diff --git a/pimd/pim_util.c b/pimd/pim_util.c index 49ae6949a2b7..b6f3be52fc74 100644 --- a/pimd/pim_util.c +++ b/pimd/pim_util.c @@ -10,6 +10,8 @@ #include "prefix.h" #include "plist.h" +#include "pimd.h" +#include "pim_instance.h" #include "pim_util.h" /* @@ -167,20 +169,47 @@ enum filter_type pim_access_list_apply(struct access_list *access, const struct return access_list_apply(access, &group_prefix); } -bool pim_is_group_filtered(struct pim_interface *pim_ifp, pim_addr *grp) +bool pim_is_group_filtered(struct pim_interface *pim_ifp, pim_addr *grp, pim_addr *src) { - struct prefix grp_pfx; - struct prefix_list *pl; + bool is_filtered = false; +#if PIM_IPV == 4 + struct prefix grp_pfx = {}; + struct prefix_list *pl = NULL; + pim_addr any_src = PIMADDR_ANY; - if (!pim_ifp->boundary_oil_plist) + if (!pim_ifp->boundary_oil_plist && !pim_ifp->boundary_acl) return false; pim_addr_to_prefix(&grp_pfx, *grp); pl = prefix_list_lookup(PIM_AFI, pim_ifp->boundary_oil_plist); - return pl ? prefix_list_apply_ext(pl, NULL, &grp_pfx, true) == - PREFIX_DENY - : false; + + /* Filter if either group or (S,G) are denied */ + if (pl) { + is_filtered = prefix_list_apply_ext(pl, NULL, &grp_pfx, true) == PREFIX_DENY; + if (is_filtered && PIM_DEBUG_EVENTS) { + zlog_debug("Filtering group %pI4 per prefix-list %s", grp, + pim_ifp->boundary_oil_plist); + } + } + if (!is_filtered && pim_ifp->boundary_acl) { + /* If src not provided, set to "any" (*)? */ + if (!src) + src = &any_src; + /* S,G filtering using extended access-list syntax */ + is_filtered = pim_access_list_apply(pim_ifp->boundary_acl, src, grp) == FILTER_DENY; + if (is_filtered && PIM_DEBUG_EVENTS) { + if (pim_addr_is_any(*src)) { + zlog_debug("Filtering (S,G)=(*, %pI4) per access-list %s", grp, + pim_ifp->boundary_acl->name); + } else { + zlog_debug("Filtering (S,G)=(%pI4, %pI4) per access-list %s", src, + grp, pim_ifp->boundary_acl->name); + } + } + } +#endif + return is_filtered; } diff --git a/pimd/pim_util.h b/pimd/pim_util.h index cffa93ed2955..dda93110b80d 100644 --- a/pimd/pim_util.h +++ b/pimd/pim_util.h @@ -25,7 +25,7 @@ int pim_is_group_224_0_0_0_24(struct in_addr group_addr); int pim_is_group_224_4(struct in_addr group_addr); enum filter_type pim_access_list_apply(struct access_list *access, const struct in_addr *source, const struct in_addr *group); -bool pim_is_group_filtered(struct pim_interface *pim_ifp, pim_addr *grp); +bool pim_is_group_filtered(struct pim_interface *pim_ifp, pim_addr *grp, pim_addr *src); int pim_get_all_mcast_group(struct prefix *prefix); bool pim_addr_is_multicast(pim_addr addr); #endif /* PIM_UTIL_H */ diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index ed91d2339b5f..ec87093325f0 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -12,6 +12,7 @@ #include "vty.h" #include "vrf.h" #include "plist.h" +#include "filter.h" #include "pimd.h" #include "pim_vty.h" @@ -496,6 +497,12 @@ int pim_config_write(struct vty *vty, int writes, struct interface *ifp, ++writes; } + if (pim_ifp->boundary_acl) { + vty_out(vty, " " PIM_AF_NAME " multicast boundary %s\n", + pim_ifp->boundary_acl->name); + ++writes; + } + if (pim_ifp->pim_passive_enable) { vty_out(vty, " " PIM_AF_NAME " pim passive\n"); ++writes; diff --git a/yang/frr-pim.yang b/yang/frr-pim.yang index 33602fd29e60..473226653eed 100644 --- a/yang/frr-pim.yang +++ b/yang/frr-pim.yang @@ -78,6 +78,10 @@ module frr-pim { type string; } + typedef access-list-ref { + type string; + } + /* * Groupings */ @@ -507,7 +511,13 @@ module frr-pim { leaf multicast-boundary-oil { type plist-ref; description - "Prefix-List to define multicast boundary"; + "Prefix-List to define multicast boundary by group"; + } + + leaf multicast-boundary-acl { + type access-list-ref; + description + "Access-list to define multicast boundary by source and group"; } list mroute { From 7fc110a8d5f73fc59b79c59a09a591544c3a2b4d Mon Sep 17 00:00:00 2001 From: Corey Siltala Date: Thu, 14 Nov 2024 13:08:28 -0600 Subject: [PATCH 063/106] tests: Add basic multicast boundary test Add simple test to show filtering of IGMP joins using new "ip multicast boundary" filtering with access-lists, include test of existing prefix- list based "ip multicast boundary oil" command. Signed-off-by: Corey Siltala --- tests/topotests/pim_boundary_acl/r1/frr.conf | 39 ++ tests/topotests/pim_boundary_acl/r2/frr.conf | 19 + tests/topotests/pim_boundary_acl/r3/frr.conf | 13 + tests/topotests/pim_boundary_acl/rp/frr.conf | 22 + .../pim_boundary_acl/test_pim_boundary_acl.py | 523 ++++++++++++++++++ 5 files changed, 616 insertions(+) create mode 100644 tests/topotests/pim_boundary_acl/r1/frr.conf create mode 100644 tests/topotests/pim_boundary_acl/r2/frr.conf create mode 100644 tests/topotests/pim_boundary_acl/r3/frr.conf create mode 100644 tests/topotests/pim_boundary_acl/rp/frr.conf create mode 100644 tests/topotests/pim_boundary_acl/test_pim_boundary_acl.py diff --git a/tests/topotests/pim_boundary_acl/r1/frr.conf b/tests/topotests/pim_boundary_acl/r1/frr.conf new file mode 100644 index 000000000000..cc639b304b37 --- /dev/null +++ b/tests/topotests/pim_boundary_acl/r1/frr.conf @@ -0,0 +1,39 @@ +hostname r1 +! +!debug pim events +!debug igmp events +!debug igmp packets +! +ip prefix-list pim-oil-plist seq 10 deny 229.1.1.0/24 +ip prefix-list pim-oil-plist seq 20 permit any +! +access-list pim-acl seq 10 deny ip host 10.0.20.2 232.1.1.0 0.0.0.255 +access-list pim-acl seq 20 permit ip any any +! +interface r1-eth0 + ip address 10.0.20.1/24 + ip igmp + ip pim +! +interface r1-eth1 + ip address 10.0.30.1/24 + ip pim +! +interface r1-eth2 + ip address 10.0.40.1/24 + ip igmp + ip pim +! +interface lo + ip address 10.254.0.1/32 + ip pim +! +router pim + rp 10.254.0.3 + join-prune-interval 5 +! +router bgp 65001 + no bgp ebgp-requires-policy + neighbor 10.0.30.3 remote-as external + neighbor 10.0.30.3 timers 3 10 + redistribute connected diff --git a/tests/topotests/pim_boundary_acl/r2/frr.conf b/tests/topotests/pim_boundary_acl/r2/frr.conf new file mode 100644 index 000000000000..10ace947b2bc --- /dev/null +++ b/tests/topotests/pim_boundary_acl/r2/frr.conf @@ -0,0 +1,19 @@ +hostname r2 +! +!debug pim events +!debug igmp events +!debug igmp packets +! +ip prefix-list pim-oil-plist seq 10 deny 229.1.1.0/24 +ip prefix-list pim-oil-plist seq 20 permit any +! +access-list pim-acl seq 10 deny ip host 10.0.20.2 232.1.1.0 0.0.0.255 +access-list pim-acl seq 20 permit ip any any +! +interface r2-eth0 + ip address 10.0.20.2/24 + ip pim +! +interface lo + ip address 10.254.0.2/32 +! diff --git a/tests/topotests/pim_boundary_acl/r3/frr.conf b/tests/topotests/pim_boundary_acl/r3/frr.conf new file mode 100644 index 000000000000..972077426643 --- /dev/null +++ b/tests/topotests/pim_boundary_acl/r3/frr.conf @@ -0,0 +1,13 @@ +hostname r3 +! +!debug pim events +!debug igmp events +!debug igmp packets +! +interface r3-eth0 + ip address 10.0.40.4/24 + ip pim +! +interface lo + ip address 10.254.0.4/32 +! diff --git a/tests/topotests/pim_boundary_acl/rp/frr.conf b/tests/topotests/pim_boundary_acl/rp/frr.conf new file mode 100644 index 000000000000..f6eed2391705 --- /dev/null +++ b/tests/topotests/pim_boundary_acl/rp/frr.conf @@ -0,0 +1,22 @@ +hostname rp +! +interface rp-eth0 + ip address 10.0.30.3/24 + ip pim +! +interface lo + ip address 10.254.0.3/32 + ip pim +! +router pim + rp 10.254.0.3 + join-prune-interval 5 + register-accept-list ACCEPT +! +ip prefix-list ACCEPT seq 5 permit 10.0.20.0/24 le 32 +! +router bgp 65003 + no bgp ebgp-requires-policy + neighbor 10.0.30.1 remote-as external + neighbor 10.0.30.1 timers 3 10 + redistribute connected \ No newline at end of file diff --git a/tests/topotests/pim_boundary_acl/test_pim_boundary_acl.py b/tests/topotests/pim_boundary_acl/test_pim_boundary_acl.py new file mode 100644 index 000000000000..1488e610c8ce --- /dev/null +++ b/tests/topotests/pim_boundary_acl/test_pim_boundary_acl.py @@ -0,0 +1,523 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# test_pim_boundary_acl.py +# +# Copyright (c) 2024 Architecture Technology Corporation +# Corey Siltala +# + +""" +test_pim_boundary_acl.py: Test multicast boundary commands (access-lists and prefix-lists) +""" + +import os +import sys +import pytest +import json +from functools import partial + +pytestmark = [pytest.mark.pimd] + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +ASM_GROUP="229.1.1.1" +SSM_GROUP="232.1.1.1" + +def build_topo(tgen): + "Build function" + + for routern in range(1, 4): + tgen.add_router("r{}".format(routern)) + + tgen.add_router("rp") + + # rp ------ r1 -------- r2 + # \ + # --------- r3 + # r1 -> .1 + # r2 -> .2 + # rp -> .3 + # r3 -> .4 + # loopback network is 10.254.0.X/32 + # + # r1 <- sw1 -> r2 + # r1-eth0 <-> r2-eth0 + # 10.0.20.0/24 + sw = tgen.add_switch("sw1") + sw.add_link(tgen.gears["r1"]) + sw.add_link(tgen.gears["r2"]) + + # r1 <- sw2 -> rp + # r1-eth1 <-> rp-eth0 + # 10.0.30.0/24 + sw = tgen.add_switch("sw2") + sw.add_link(tgen.gears["r1"]) + sw.add_link(tgen.gears["rp"]) + + # r1 <- sw3 -> r3 + # r1-eth2 <-> r3-eth0 + # 10.0.40.0/24 + sw = tgen.add_switch("sw3") + sw.add_link(tgen.gears["r1"]) + sw.add_link(tgen.gears["r3"]) + + +def setup_module(mod): + "Sets up the pytest environment" + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + # For all registered routers, load the zebra configuration file + for rname, router in tgen.routers().items(): + logger.info("Loading router %s" % rname) + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + # After loading the configurations, this function loads configured daemons. + tgen.start_router() + # tgen.mininet_cli() + + +def teardown_module(): + "Teardown the pytest environment" + tgen = get_topogen() + + # This function tears down the whole topology. + tgen.stop_topology() + + +def test_pim_rp_setup(): + "Ensure basic routing has come up and the rp has an outgoing interface" + # Ensure rp and r1 establish pim neighbor ship and bgp has come up + # Finally ensure that the rp has an outgoing interface on r1 + tgen = get_topogen() + + r1 = tgen.gears["r1"] + expected = { + "10.254.0.3":[ + { + "outboundInterface":"r1-eth1", + "group":"224.0.0.0/4", + "source":"Static" + } + ] + } + + test_func = partial( + topotest.router_json_cmp, r1, "show ip pim rp-info json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assertmsg = '"{}" JSON output mismatches'.format(r1.name) + assert result is None, assertmsg + # tgen.mininet_cli() + + +def test_pim_asm_igmp_join_acl(): + "Test ASM IGMP joins with prefix-list ACLs" + logger.info("Send IGMP joins from r2 to r1 with ACL enabled and disabled") + + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r2 = tgen.gears["r2"] + r1 = tgen.gears["r1"] + + # No IGMP sources other than from self for AutoRP Discovery group initially + expected = { + "r1-eth0":{ + "name":"r1-eth0", + "224.0.1.40":"*", + "229.1.1.1":None + }, + "r1-eth2":{ + "name":"r1-eth2", + "224.0.1.40":"*", + "229.1.1.1":None + } + } + test_func = partial( + topotest.router_json_cmp, r1, "show ip igmp sources json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + assert result is None, "Expected no IGMP sources other than for AutoRP Discovery" + + # Send IGMP join from r2, check if r1 has IGMP source + r2.vtysh_cmd(( + """ + configure terminal + interface {} + ip igmp join {} + """ + ).format("r2-eth0", ASM_GROUP)) + expected = { + "r1-eth0":{ + "name":"r1-eth0", + "229.1.1.1":{ + "group":"229.1.1.1", + "sources":[ + { + "source":"*", + "timer":"--:--", + "forwarded":False, + "uptime":"*" + } + ] + } + } + } + test_func = partial( + topotest.router_json_cmp, r1, "show ip igmp sources json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + assert result is None, "Expected IGMP source to be present but is absent" + + # Test inbound boundary on r1 + # Enable multicast boundary on r1, toggle IGMP join on r2 + r2.vtysh_cmd(( + """ + configure terminal + interface r2-eth0 + no ip igmp join {} + """ + ).format(ASM_GROUP)) + r1.vtysh_cmd( + """ + configure terminal + interface r1-eth0 + ip multicast boundary oil pim-oil-plist + """ + ) + r2.vtysh_cmd(( + """ + configure terminal + interface r2-eth0 + ip igmp join {} + """ + ).format(ASM_GROUP)) + expected = { + "r1-eth0":{ + "name":"r1-eth0", + "229.1.1.1":None + } + } + test_func = partial( + topotest.router_json_cmp, r1, "show ip igmp sources json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + assert result is None, "Expected IGMP source to be absent but is present" + + # Test outbound boundary on r2 + # Enable multicast boundary on r2, toggle IGMP join (test outbound) + # Note: json_cmp treats "*" as wildcard but in this case that's actually what the source is + expected = { + "vrf":"default", + "r2-eth0":{ + "name":"r2-eth0", + "groups":[ + { + "source":"*", + "group":"229.1.1.1", + "primaryAddr":"10.0.20.2", + "sockFd":"*", + "upTime":"*" + } + ] + } + } + test_func = partial( + topotest.router_json_cmp, r2, "show ip igmp join json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + assert result is None, "Expected IGMP join to be present but is absent" + + r2.vtysh_cmd(( + """ + configure terminal + interface r2-eth0 + no ip igmp join {} + ip multicast boundary oil pim-oil-plist + ip igmp join {} + """ + ).format(ASM_GROUP, ASM_GROUP)) + expected = { + "vrf":"default", + "r2-eth0":None + } + test_func = partial( + topotest.router_json_cmp, r2, "show ip igmp join json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + assert result is None, "Expected IGMP join to be absent but is present" + + # Cleanup + r2.vtysh_cmd(( + """ + configure terminal + interface r2-eth0 + no ip igmp join {} + no ip multicast boundary oil pim-oil-plist + """ + ).format(ASM_GROUP)) + + +def test_pim_ssm_igmp_join_acl(): + "Test SSM IGMP joins with extended ACLs" + logger.info("Send IGMP joins from r2 to r1 with ACL enabled and disabled") + + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r3 = tgen.gears["r3"] + r2 = tgen.gears["r2"] + r1 = tgen.gears["r1"] + + # No IGMP sources other than from self for AutoRP Discovery group initially + expected = { + "r1-eth0":{ + "name":"r1-eth0", + "224.0.1.40":"*", + "229.1.1.1":None, + "232.1.1.1":None + }, + "r1-eth2":{ + "name":"r1-eth2", + "224.0.1.40":"*", + "229.1.1.1":None, + "232.1.1.1":None + } + } + test_func = partial( + topotest.router_json_cmp, r1, "show ip igmp sources json", {} + ) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + assert result is None, "Expected no IGMP sources other than from AutoRP Discovery" + + # Send IGMP join from r2, check if r1 has IGMP source + r2.vtysh_cmd(( + """ + configure terminal + interface r2-eth0 + ip igmp join {} 10.0.20.2 + """ + ).format(SSM_GROUP)) + expected = { + "r1-eth0":{ + "name":"r1-eth0", + "232.1.1.1":{ + "group":"232.1.1.1", + "sources":[ + { + "source":"10.0.20.2", + "timer":"*", + "forwarded":False, + "uptime":"*" + } + ] + } + } + } + test_func = partial( + topotest.router_json_cmp, r1, "show ip igmp sources json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + assert result is None, "Expected IGMP source to be present but is absent" + + # Test inbound boundary on r1 + # Enable multicast boundary on r1, toggle IGMP join on r2 + r2.vtysh_cmd(( + """ + configure terminal + interface r2-eth0 + no ip igmp join {} 10.0.20.2 + """ + ).format(SSM_GROUP)) + r1.vtysh_cmd( + """ + configure terminal + interface r1-eth0 + ip multicast boundary pim-acl + """ + ) + r2.vtysh_cmd(( + """ + configure terminal + interface r2-eth0 + ip igmp join {} 10.0.20.2 + """ + ).format(SSM_GROUP)) + expected = { + "r1-eth0":{ + "name":"r1-eth0", + "232.1.1.1":None + } + } + test_func = partial( + topotest.router_json_cmp, r1, "show ip igmp sources json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + assert result is None, "Expected IGMP source to be absent but is present" + + # Add lower, more-specific permit rule to access-list + r2.vtysh_cmd(( + """ + configure terminal + interface r2-eth0 + no ip igmp join {} 10.0.20.2 + """ + ).format(SSM_GROUP)) + r1.vtysh_cmd(( + """ + configure terminal + access-list pim-acl seq 5 permit ip host 10.0.20.2 {} 0.0.0.128 + """ + ).format(SSM_GROUP)) + r2.vtysh_cmd(( + """ + configure terminal + interface r2-eth0 + ip igmp join {} 10.0.20.2 + """ + ).format(SSM_GROUP)) + expected = { + "r1-eth0":{ + "name":"r1-eth0", + "232.1.1.1":{ + "group":"232.1.1.1", + "sources":[ + { + "source":"10.0.20.2", + "timer":"*", + "forwarded":False, + "uptime":"*" + } + ] + } + } + } + test_func = partial( + topotest.router_json_cmp, r1, "show ip igmp sources json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + assert result is None, "Expected IGMP source to be present but is absent" + + # Test outbound boundary on r2 + # Enable multicast boundary on r2, toggle IGMP join (test outbound) + expected = { + "vrf":"default", + "r2-eth0":{ + "name":"r2-eth0", + "groups":[ + { + "source":"10.0.20.2", + "group":"232.1.1.1", + "primaryAddr":"10.0.20.2", + "sockFd":"*", + "upTime":"*" + } + ] + } + } + test_func = partial( + topotest.router_json_cmp, r2, "show ip igmp join json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + assert result is None, "Expected IGMP join to be present but is absent" + + # Enable boundary ACL, check join is absent + r2.vtysh_cmd(( + """ + configure terminal + interface r2-eth0 + no ip igmp join {} 10.0.20.2 + ip multicast boundary pim-acl + ip igmp join {} 10.0.20.2 + """ + ).format(SSM_GROUP, SSM_GROUP)) + expected = { + "vrf":"default", + "r2-eth0":None + } + test_func = partial( + topotest.router_json_cmp, r2, "show ip igmp join json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + assert result is None, "Expected IGMP join to be absent but is present" + # Check sources on r1 again, should be absent even though we permitted it because r2 is blocking it outbound + expected = { + "r1-eth0":{ + "name":"r1-eth0", + "232.1.1.1":None + }, + "r1-eth2":{ + "name":"r1-eth2", + "232.1.1.1":None + } + } + test_func = partial( + topotest.router_json_cmp, r1, "show ip igmp sources json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + assert result is None, "Expected IGMP source to be absent but is present" + + # Send IGMP join from r3 with different source, should show up on r1 + # Add lower, more-specific permit rule to access-list + r3.vtysh_cmd(( + """ + configure terminal + interface r3-eth0 + ip igmp join {} 10.0.40.4 + """ + ).format(SSM_GROUP)) + expected = { + "r1-eth0":{ + "name":"r1-eth0", + "232.1.1.1":None + }, + "r1-eth2":{ + "name":"r1-eth2", + "232.1.1.1":{ + "group":"232.1.1.1", + "sources":[ + { + "source":"10.0.40.4", + "timer":"*", + "forwarded":False, + "uptime":"*" + } + ] + } + } + } + test_func = partial( + topotest.router_json_cmp, r1, "show ip igmp sources json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + assert result is None, "Expected IGMP source to be present but is absent" + + # PIM join + # PIM-DM forwarding + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) From 6288ffd0f5e8964303deecf7f16dedb7fe9cd723 Mon Sep 17 00:00:00 2001 From: Corey Siltala Date: Thu, 14 Nov 2024 13:08:52 -0600 Subject: [PATCH 064/106] doc: Expand ACL and multicast boundary documentation Add documentation for existing extended access-list functionality and the new "ip multicast boundary" command leveraging that functionality. Signed-off-by: Corey Siltala --- doc/user/filter.rst | 27 +++++++++++++++++++++++--- doc/user/pim.rst | 46 ++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 65 insertions(+), 8 deletions(-) diff --git a/doc/user/filter.rst b/doc/user/filter.rst index c1146e50aa2b..be63095166fa 100644 --- a/doc/user/filter.rst +++ b/doc/user/filter.rst @@ -9,9 +9,7 @@ defined, it can be applied in any direction. IP Access List ============== -.. clicmd:: access-list NAME [seq (1-4294967295)] permit IPV4-NETWORK - -.. clicmd:: access-list NAME [seq (1-4294967295)] deny IPV4-NETWORK +.. clicmd:: access-list NAME [seq (1-4294967295)] seq seq `number` can be set either automatically or manually. In the @@ -35,6 +33,29 @@ IP Access List access-list filter permit 10.0.0.0/8 access-list filter seq 13 permit 10.0.0.0/7 +.. clicmd:: access-list NAME [seq (1-4294967295)] ip + + The extended access-list syntax enables filtering on both source and destination + IP addresses (or source and group, if used for multicast boundaries). The + source address is first in order in the command. + + If providing a mask, note that the access-lists use wildcard masks (inverse + matching logic of subnet masks). If specifying ``host``, only the single address + given will be matched. + + A basic example is as follows: + + .. code-block:: frr + + access-list filter seq 5 permit ip host 10.0.20.2 232.1.1.0 0.0.0.128 + access-list filter seq 10 deny ip 10.0.20.0 0.0.0.255 232.1.1.0 0.0.0.255 + access-list filter seq 15 permit ip any any + + .. note :: + + If an access-list is specified but no match is found, the default verdict + is deny. + .. clicmd:: show access-list [json] Display all IPv4 or IPv6 access lists. diff --git a/doc/user/pim.rst b/doc/user/pim.rst index 05418da5a990..ef49b076dff6 100644 --- a/doc/user/pim.rst +++ b/doc/user/pim.rst @@ -6,9 +6,9 @@ PIM PIM -- Protocol Independent Multicast -*pimd* supports pim-sm as well as igmp v2 and v3. pim is -vrf aware and can work within the context of vrf's in order to -do S,G mrouting. Additionally PIM can be used in the EVPN underlay +*pimd* supports PIM-SM as well as IGMP v2 and v3. PIM is +VRF aware and can work within the context of VRFs in order to +do S,G mrouting. Additionally, PIM can be used in the EVPN underlay network for optimizing forwarding of overlay BUM traffic. .. note:: @@ -348,10 +348,46 @@ is in a vrf, enter the interface command with the vrf keyword at the end. .. clicmd:: ip multicast boundary oil WORD - Set a pim multicast boundary, based upon the WORD prefix-list. If a pim join - or IGMP report is received on this interface and the Group is denied by the + Set a PIM multicast boundary, based upon the WORD prefix-list. If a PIM join + or IGMP report is received on this interface and the group is denied by the prefix-list, PIM will ignore the join or report. + .. code-block:: frr + + prefix-list multicast-acl seq 5 permit 232.1.1.1/32 + prefix-list multicast-acl seq 10 deny 232.1.1.0/24 + prefix-list multicast-acl seq 15 permit any + ! + interface r1-eth0 + ip pim + ip igmp + ip multicast boundary oil multicast-acl + exit + +.. clicmd:: ip multicast boundary ACCESS-LIST + + Set a PIM multicast boundary, based upon the ACCESS-LIST. If a PIM join + or IGMP report is received on this interface and the (S,G) tuple is denied by the + access-list, PIM will ignore the join or report. + + To filter on both source and group, the extended access-list syntax must be used. + + If both a prefix-list and access-list are configured for multicast boundaries, + the prefix-list will be evaluated first (and must have a terminating "permit any" + in order to also evaluate against the access-list). + + .. code-block:: frr + + access-list multicast-acl seq 5 permit ip host 10.0.20.2 host 232.1.1.1 + access-list multicast-acl seq 10 deny ip 10.0.20.0 0.0.0.255 232.1.1.0 0.0.0.255 + access-list multicast-acl seq 15 permit ip any any + ! + interface r1-eth0 + ip pim + ip igmp + ip multicast boundary pim-acl + exit + .. clicmd:: ip igmp last-member-query-count (1-255) Set the IGMP last member query count. The default value is 2. 'no' form of From d11bded7cffef80dd078db586414075310307ab1 Mon Sep 17 00:00:00 2001 From: Corey Siltala Date: Tue, 26 Nov 2024 08:35:42 -0600 Subject: [PATCH 065/106] pimd: Convert boundary_oil_plist to struct prefix_list Rather than storing the prefix-list name and looking it up every time we use it, store a pointer to the prefix-list itself. Signed-off-by: Corey Siltala --- pimd/pim_iface.c | 1 - pimd/pim_iface.h | 2 +- pimd/pim_igmpv3.c | 7 +++++-- pimd/pim_nb_config.c | 18 ++++++++---------- pimd/pim_util.c | 11 +++++------ pimd/pim_vty.c | 3 ++- 6 files changed, 21 insertions(+), 21 deletions(-) diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index f92a42dd8a54..bd7164c9b972 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -216,7 +216,6 @@ void pim_if_delete(struct interface *ifp) if (pim_ifp->bfd_config.profile) XFREE(MTYPE_TMP, pim_ifp->bfd_config.profile); - XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist); XFREE(MTYPE_PIM_INTERFACE, pim_ifp); ifp->info = NULL; diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h index 18e88ffbd5dc..90a81a21d026 100644 --- a/pimd/pim_iface.h +++ b/pimd/pim_iface.h @@ -134,7 +134,7 @@ struct pim_interface { int pim_dr_num_nondrpri_neighbors; /* neighbors without dr_pri */ /* boundary prefix-list (group) */ - char *boundary_oil_plist; + struct prefix_list *boundary_oil_plist; /* boundary access-list (source and group) */ struct access_list *boundary_acl; diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c index d0ba79378b31..7348d8130f2c 100644 --- a/pimd/pim_igmpv3.c +++ b/pimd/pim_igmpv3.c @@ -9,6 +9,8 @@ #include "memory.h" #include "if.h" #include "lib_errors.h" +#include "plist.h" +#include "plist_int.h" #include "pimd.h" #include "pim_instance.h" @@ -1815,9 +1817,10 @@ static bool igmp_pkt_grp_addr_ok(struct interface *ifp, const char *from_str, if (PIM_DEBUG_GM_PACKETS) { zlog_debug("Filtering IGMPv3 group record %pI4 from %s on %s per prefix-list %s or access-list %s", &grp.s_addr, from_str, ifp->name, - (pim_ifp->boundary_oil_plist ? pim_ifp->boundary_oil_plist + (pim_ifp->boundary_oil_plist ? pim_ifp->boundary_oil_plist->name : "(not found)"), - (pim_ifp->boundary_acl ? pim_ifp->boundary_acl->name : "(not found)")); + (pim_ifp->boundary_acl ? pim_ifp->boundary_acl->name + : "(not found)")); } return false; } diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index 2533f8c4d491..41457ffba2d2 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -2390,7 +2390,6 @@ int lib_interface_pim_address_family_multicast_boundary_oil_modify( { struct interface *ifp; struct pim_interface *pim_ifp; - const char *plist; const struct lyd_node *if_dnode; switch (args->event) { @@ -2398,7 +2397,12 @@ int lib_interface_pim_address_family_multicast_boundary_oil_modify( if_dnode = yang_dnode_get_parent(args->dnode, "interface"); if (!is_pim_interface(if_dnode)) { snprintf(args->errmsg, args->errmsg_len, - "Pim not enabled on this interface"); + "%% Enable PIM and/or IGMP on this interface first"); + return NB_ERR_VALIDATION; + } + if (!prefix_list_lookup(AFI_IP, yang_dnode_get_string(args->dnode, NULL))) { + snprintf(args->errmsg, args->errmsg_len, + "%% Specified prefix-list not found"); return NB_ERR_VALIDATION; } break; @@ -2408,13 +2412,8 @@ int lib_interface_pim_address_family_multicast_boundary_oil_modify( case NB_EV_APPLY: ifp = nb_running_get_entry(args->dnode, NULL, true); pim_ifp = ifp->info; - plist = yang_dnode_get_string(args->dnode, NULL); - - if (pim_ifp->boundary_oil_plist) - XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist); - pim_ifp->boundary_oil_plist = - XSTRDUP(MTYPE_PIM_INTERFACE, plist); + prefix_list_lookup(AFI_IP, yang_dnode_get_string(args->dnode, NULL)); break; } @@ -2444,8 +2443,7 @@ int lib_interface_pim_address_family_multicast_boundary_oil_destroy( case NB_EV_APPLY: ifp = nb_running_get_entry(args->dnode, NULL, true); pim_ifp = ifp->info; - if (pim_ifp->boundary_oil_plist) - XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist); + pim_ifp->boundary_oil_plist = NULL; break; } diff --git a/pimd/pim_util.c b/pimd/pim_util.c index b6f3be52fc74..40404714e7fb 100644 --- a/pimd/pim_util.c +++ b/pimd/pim_util.c @@ -9,6 +9,7 @@ #include "log.h" #include "prefix.h" #include "plist.h" +#include "plist_int.h" #include "pimd.h" #include "pim_instance.h" @@ -174,7 +175,6 @@ bool pim_is_group_filtered(struct pim_interface *pim_ifp, pim_addr *grp, pim_add bool is_filtered = false; #if PIM_IPV == 4 struct prefix grp_pfx = {}; - struct prefix_list *pl = NULL; pim_addr any_src = PIMADDR_ANY; if (!pim_ifp->boundary_oil_plist && !pim_ifp->boundary_acl) @@ -182,14 +182,13 @@ bool pim_is_group_filtered(struct pim_interface *pim_ifp, pim_addr *grp, pim_add pim_addr_to_prefix(&grp_pfx, *grp); - pl = prefix_list_lookup(PIM_AFI, pim_ifp->boundary_oil_plist); - /* Filter if either group or (S,G) are denied */ - if (pl) { - is_filtered = prefix_list_apply_ext(pl, NULL, &grp_pfx, true) == PREFIX_DENY; + if (pim_ifp->boundary_oil_plist) { + is_filtered = prefix_list_apply_ext(pim_ifp->boundary_oil_plist, NULL, &grp_pfx, + true) == PREFIX_DENY; if (is_filtered && PIM_DEBUG_EVENTS) { zlog_debug("Filtering group %pI4 per prefix-list %s", grp, - pim_ifp->boundary_oil_plist); + pim_ifp->boundary_oil_plist->name); } } if (!is_filtered && pim_ifp->boundary_acl) { diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index ec87093325f0..4c3762b2edfa 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -12,6 +12,7 @@ #include "vty.h" #include "vrf.h" #include "plist.h" +#include "plist_int.h" #include "filter.h" #include "pimd.h" @@ -493,7 +494,7 @@ int pim_config_write(struct vty *vty, int writes, struct interface *ifp, /* boundary */ if (pim_ifp->boundary_oil_plist) { vty_out(vty, " " PIM_AF_NAME " multicast boundary oil %s\n", - pim_ifp->boundary_oil_plist); + pim_ifp->boundary_oil_plist->name); ++writes; } From 7d19912f2c387bdc525a6bca359a133768eae84e Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Sun, 8 Dec 2024 21:44:52 +0200 Subject: [PATCH 066/106] tests: Check if vpn routes can be imported if allowas-in is set Signed-off-by: Donatas Abraitis --- .../bgp_vpnv4_import_allowas_in/__init__.py | 0 .../bgp_vpnv4_import_allowas_in/r1/frr.conf | 30 ++++ .../bgp_vpnv4_import_allowas_in/r2/frr.conf | 40 ++++++ .../test_bgp_vpnv4_import_allowas_in.py | 135 ++++++++++++++++++ 4 files changed, 205 insertions(+) create mode 100644 tests/topotests/bgp_vpnv4_import_allowas_in/__init__.py create mode 100644 tests/topotests/bgp_vpnv4_import_allowas_in/r1/frr.conf create mode 100644 tests/topotests/bgp_vpnv4_import_allowas_in/r2/frr.conf create mode 100644 tests/topotests/bgp_vpnv4_import_allowas_in/test_bgp_vpnv4_import_allowas_in.py diff --git a/tests/topotests/bgp_vpnv4_import_allowas_in/__init__.py b/tests/topotests/bgp_vpnv4_import_allowas_in/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/topotests/bgp_vpnv4_import_allowas_in/r1/frr.conf b/tests/topotests/bgp_vpnv4_import_allowas_in/r1/frr.conf new file mode 100644 index 000000000000..30d11627f538 --- /dev/null +++ b/tests/topotests/bgp_vpnv4_import_allowas_in/r1/frr.conf @@ -0,0 +1,30 @@ +! +interface r1-eth0 + ip address 192.168.179.4/24 +exit +! +router bgp 65001 + bgp router-id 192.168.179.4 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.179.5 remote-as auto +! + address-family ipv4 vpn + neighbor 192.168.179.5 activate + neighbor 192.168.179.5 next-hop-self + neighbor 192.168.179.5 allowas-in 1 + exit-address-family +! +router bgp 65001 vrf CUSTOMER-A + bgp router-id 192.168.0.1 + no bgp ebgp-requires-policy + no bgp network import-check +! + address-family ipv4 unicast + label vpn export auto + rd vpn export 100:1 + rt vpn both 100:1 + export vpn + import vpn + exit-address-family + diff --git a/tests/topotests/bgp_vpnv4_import_allowas_in/r2/frr.conf b/tests/topotests/bgp_vpnv4_import_allowas_in/r2/frr.conf new file mode 100644 index 000000000000..bbfd2c22f4fe --- /dev/null +++ b/tests/topotests/bgp_vpnv4_import_allowas_in/r2/frr.conf @@ -0,0 +1,40 @@ +! +interface lo + ip address 10.10.10.10/32 +! +interface r2-eth0 + ip address 192.168.179.5/24 +exit +! +interface r2-eth1 + ip address 192.168.2.2/24 +exit +! +router bgp 65002 + bgp router-id 192.168.179.5 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.179.4 remote-as auto +! + address-family ipv4 vpn + neighbor 192.168.179.4 activate + neighbor 192.168.179.4 next-hop-self + exit-address-family +! +router bgp 65002 vrf CUSTOMER-A + bgp router-id 192.168.0.2 + no bgp ebgp-requires-policy + no bgp network import-check +! + address-family ipv4 unicast + redistribute connected + network 10.10.10.10/32 route-map r1 + label vpn export auto + rd vpn export 100:1 + rt vpn both 100:1 + export vpn + import vpn + exit-address-family +! +route-map r1 permit 10 + set as-path prepend 65001 diff --git a/tests/topotests/bgp_vpnv4_import_allowas_in/test_bgp_vpnv4_import_allowas_in.py b/tests/topotests/bgp_vpnv4_import_allowas_in/test_bgp_vpnv4_import_allowas_in.py new file mode 100644 index 000000000000..f3d016cb179b --- /dev/null +++ b/tests/topotests/bgp_vpnv4_import_allowas_in/test_bgp_vpnv4_import_allowas_in.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# Copyright (c) 2024 by +# Donatas Abraitis +# + +import os +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, get_topogen + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + tgen.add_router("r1") + tgen.add_router("r2") + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["r1"]) + + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["r2"]) + + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + + r1.run("ip link add CUSTOMER-A type vrf table 1001") + r1.run("ip link set up dev CUSTOMER-A") + r1.run("ip link set r1-eth1 master CUSTOMER-A") + + r2.run("ip link add CUSTOMER-A type vrf table 1001") + r2.run("ip link set up dev CUSTOMER-A") + r2.run("ip link set r2-eth1 master CUSTOMER-A") + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_issue_12502(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + + def _bgp_converge(): + output = json.loads( + r1.vtysh_cmd("show bgp vrf CUSTOMER-A ipv4 unicast 10.10.10.10/32 json") + ) + expected = { + "paths": [ + { + "importedFrom": "100:1", + "aspath": { + "string": "65002 65001", + }, + "valid": True, + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_converge) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Failed to see 192.168.2.0/24 with a valid next-hop" + + def _vrf_route_imported_to_zebra(): + output = json.loads( + r1.vtysh_cmd("show ip route vrf CUSTOMER-A 10.10.10.10/32 json") + ) + expected = { + "10.10.10.10/32": [ + { + "protocol": "bgp", + "vrfName": "CUSTOMER-A", + "selected": True, + "installed": True, + "table": 1001, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "fib": True, + "ip": "192.168.179.5", + "afi": "ipv4", + "interfaceName": "r1-eth0", + "vrf": "default", + "active": True, + } + ], + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_vrf_route_imported_to_zebra) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert ( + result is None + ), "Failed to see 10.10.10.10/32 to be imported into default VRF (Zebra)" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) From b868757f745016ea6a01eeffa02bb936cbefa5c2 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Sun, 8 Dec 2024 21:46:59 +0200 Subject: [PATCH 067/106] bgpd: Import allowed routes with self AS if desired Previously we couldn't install VPN routes with self AS in the path because we never checked if we have allowas-in enabled, or not. Signed-off-by: Donatas Abraitis --- bgpd/bgp_mplsvpn.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index ca7f73dde993..69248d961d50 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -2167,6 +2167,8 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ struct interface *ifp = NULL; char rd_buf[RD_ADDRSTRLEN]; struct aspath *new_aspath; + int32_t aspath_loop_count = 0; + struct peer *peer = path_vpn->peer; int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF); @@ -2227,7 +2229,9 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ bn = bgp_afi_node_get(to_bgp->rib[afi][safi], afi, safi, p, NULL); /* Check if leaked route has our asn. If so, don't import it. */ - if (aspath_loop_check(path_vpn->attr->aspath, to_bgp->as)) { + if (CHECK_FLAG(peer->af_flags[afi][SAFI_MPLS_VPN], PEER_FLAG_ALLOWAS_IN)) + aspath_loop_count = peer->allowas_in[afi][SAFI_MPLS_VPN]; + if (aspath_loop_check(path_vpn->attr->aspath, to_bgp->as) > aspath_loop_count) { for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; bpi = bpi->next) { if (bpi->extra && bpi->extra->vrfleak && From 336fb435db212302ec40e8e9e06b46f858d33a87 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Sun, 8 Dec 2024 21:48:14 +0200 Subject: [PATCH 068/106] bgpd: Print the actual prefix when we try to import in vpn_leak_to_vrf_update Signed-off-by: Donatas Abraitis --- bgpd/bgp_mplsvpn.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 69248d961d50..ecb78c1ce403 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -2517,11 +2517,12 @@ void vpn_leak_to_vrf_update(struct bgp *from_bgp, { struct listnode *mnode, *mnnode; struct bgp *bgp; + const struct prefix *p = bgp_dest_get_prefix(path_vpn->net); int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF); if (debug) - zlog_debug("%s: start (path_vpn=%p)", __func__, path_vpn); + zlog_debug("%s: start (path_vpn=%p, prefix=%pFX)", __func__, path_vpn, p); /* Loop over VRFs */ for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) { From c5087cb16e8d106707a9bfda967d9c38b364e5af Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 4 Dec 2024 14:23:54 +0200 Subject: [PATCH 069/106] bgpd: Show which route-map is used when the prefix is filtered by route-map It might be an unsuppress-map or outbound route-map, let's show which one is used. Signed-off-by: Donatas Abraitis --- bgpd/bgp_route.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 5feda7183739..55368e9ebcc9 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2587,12 +2587,11 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, if (ret == RMAP_DENYMATCH) { if (bgp_debug_update(NULL, p, subgrp->update_group, 0)) - zlog_debug( - "%pBP [Update:SEND] %pFX is filtered by route-map '%s'", - peer, p, - bgp_path_suppressed(pi) - ? UNSUPPRESS_MAP_NAME(filter) - : ROUTE_MAP_OUT_NAME(filter)); + zlog_debug("%pBP [Update:SEND] %pFX is filtered by route-map (%s) '%s'", + peer, p, + bgp_path_suppressed(pi) ? "unsuppress-map" : "out", + bgp_path_suppressed(pi) ? UNSUPPRESS_MAP_NAME(filter) + : ROUTE_MAP_OUT_NAME(filter)); bgp_attr_flush(rmap_path.attr); return false; } From c55bc29037c54fc2db8fdfddb38c19a3f57ba2ae Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Tue, 10 May 2022 08:23:24 -0300 Subject: [PATCH 070/106] yang,pimd: support shutdown and SA limit Add MSDP shutdown and SA limiting configuration to YANG model. (no implementation, just boiler plate code) Signed-off-by: Rafael Zalamena --- pimd/pim_nb.c | 7 +++++++ pimd/pim_nb.h | 2 ++ pimd/pim_nb_config.c | 42 ++++++++++++++++++++++++++++++++++++++++++ yang/frr-pim.yang | 6 ++++++ 4 files changed, 57 insertions(+) diff --git a/pimd/pim_nb.c b/pimd/pim_nb.c index 2b39f2dcb827..b5d20419dd1d 100644 --- a/pimd/pim_nb.c +++ b/pimd/pim_nb.c @@ -208,6 +208,13 @@ const struct frr_yang_module_info frr_pim_info = { .destroy = pim_msdp_peer_authentication_key_destroy, } }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/sa-limit", + .cbs = { + .modify = pim_msdp_peer_sa_limit_modify, + .destroy = pim_msdp_peer_sa_limit_destroy, + } + }, { .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag", .cbs = { diff --git a/pimd/pim_nb.h b/pimd/pim_nb.h index f27b86680fb4..7d30db04be0c 100644 --- a/pimd/pim_nb.h +++ b/pimd/pim_nb.h @@ -76,6 +76,8 @@ int pim_msdp_peer_sa_filter_out_destroy(struct nb_cb_destroy_args *args); int pim_msdp_peer_authentication_type_modify(struct nb_cb_modify_args *args); int pim_msdp_peer_authentication_key_modify(struct nb_cb_modify_args *args); int pim_msdp_peer_authentication_key_destroy(struct nb_cb_destroy_args *args); +int pim_msdp_peer_sa_limit_modify(struct nb_cb_modify_args *args); +int pim_msdp_peer_sa_limit_destroy(struct nb_cb_destroy_args *args); int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_create( struct nb_cb_create_args *args); int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_destroy( diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index 41457ffba2d2..f4c0940bae3e 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -1579,6 +1579,48 @@ int pim_msdp_peer_sa_filter_out_destroy(struct nb_cb_destroy_args *args) return NB_OK; } +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/sa-limit + */ +int pim_msdp_peer_sa_limit_modify(struct nb_cb_modify_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + /* TODO: apply limitation. */ + break; + } + + return NB_OK; +} + +int pim_msdp_peer_sa_limit_destroy(struct nb_cb_destroy_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + /* TODO: remove limitation. */ + break; + } + + return NB_OK; +} + /* * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag */ diff --git a/yang/frr-pim.yang b/yang/frr-pim.yang index 473226653eed..6e5fc3c6ce5d 100644 --- a/yang/frr-pim.yang +++ b/yang/frr-pim.yang @@ -341,6 +341,12 @@ module frr-pim { } uses msdp-authentication; + + leaf sa-limit { + type uint32; + description + "Peer SA maximum limit."; + } } container mlag { From 02939de3a2a8ac1f2d424c08616c31802c95e476 Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Tue, 10 May 2022 08:23:40 -0300 Subject: [PATCH 071/106] pimd: implement MSDP peer SA limiting Implement a command to enable/disable per peer MSDP SA limiting. Signed-off-by: Rafael Zalamena --- pimd/pim_cmd.c | 24 ++++++++++++++++++++++++ pimd/pim_msdp.c | 12 ++++++++++++ pimd/pim_msdp.h | 3 +++ pimd/pim_nb_config.c | 4 ++-- 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index bac9645759e6..3fabe1706c80 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -7593,6 +7593,29 @@ DEFPY(msdp_shutdown, return nb_cli_apply_changes(vty, NULL); } +DEFPY(msdp_peer_sa_limit, msdp_peer_sa_limit_cmd, + "[no] msdp peer A.B.C.D$peer sa-limit ![(1-4294967294)$sa_limit]", + NO_STR + CFG_MSDP_STR + "Configure MSDP peer\n" + "MSDP peer address\n" + "Limit amount of SA\n" + "Maximum number of SA\n") +{ + const struct lyd_node *peer_node; + char xpath[XPATH_MAXLEN + 24]; + + snprintf(xpath, sizeof(xpath), "%s/msdp-peer[peer-ip='%s']", VTY_CURR_XPATH, peer_str); + peer_node = yang_dnode_get(vty->candidate_config->dnode, xpath); + if (peer_node == NULL) { + vty_out(vty, "%% MSDP peer %s not yet configured\n", peer_str); + return CMD_SUCCESS; + } + + nb_cli_enqueue_change(vty, "./sa-limit", NB_OP_MODIFY, sa_limit_str); + return nb_cli_apply_changes(vty, "%s", xpath); +} + static void ip_msdp_show_mesh_group(struct vty *vty, struct pim_msdp_mg *mg, struct json_object *json) { @@ -8988,6 +9011,7 @@ void pim_cmd_init(void) install_element(PIM_NODE, &msdp_log_neighbor_changes_cmd); install_element(PIM_NODE, &msdp_log_sa_changes_cmd); install_element(PIM_NODE, &msdp_shutdown_cmd); + install_element(PIM_NODE, &msdp_peer_sa_limit_cmd); install_element(PIM_NODE, &pim_bsr_candidate_rp_cmd); install_element(PIM_NODE, &pim_bsr_candidate_rp_group_cmd); diff --git a/pimd/pim_msdp.c b/pimd/pim_msdp.c index ae887b248253..bd86ca502d50 100644 --- a/pimd/pim_msdp.c +++ b/pimd/pim_msdp.c @@ -359,6 +359,15 @@ void pim_msdp_sa_ref(struct pim_instance *pim, struct pim_msdp_peer *mp, struct rp_info *rp_info; struct prefix grp; + /* Check peer SA limit. */ + if (mp && mp->sa_limit && mp->sa_cnt >= mp->sa_limit) { + if (pim_msdp_log_sa_events(pim)) + zlog_debug("MSDP peer %pI4 reject SA (%pI4, %pI4): SA limit %u of %u", + &mp->peer, &sg->src, &sg->grp, mp->sa_cnt, mp->sa_limit); + + return; + } + sa = pim_msdp_sa_add(pim, sg, rp); if (!sa) { return; @@ -1316,6 +1325,9 @@ bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim) vty_out(vty, " msdp peer %pI4 sa-filter %s out\n", &mp->peer, mp->acl_out); + if (mp->sa_limit) + vty_out(vty, " msdp peer %pI4 sa-limit %u\n", &mp->peer, mp->sa_limit); + written = true; } diff --git a/pimd/pim_msdp.h b/pimd/pim_msdp.h index d0aa83d9978c..15ed685b3c6a 100644 --- a/pimd/pim_msdp.h +++ b/pimd/pim_msdp.h @@ -152,6 +152,9 @@ struct pim_msdp_peer { char *acl_in; /** SA output access list name. */ char *acl_out; + + /** SA maximum amount. */ + uint32_t sa_limit; }; struct pim_msdp_mg_mbr { diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index f4c0940bae3e..4f79a890df17 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -1595,7 +1595,7 @@ int pim_msdp_peer_sa_limit_modify(struct nb_cb_modify_args *args) break; case NB_EV_APPLY: mp = nb_running_get_entry(args->dnode, NULL, true); - /* TODO: apply limitation. */ + mp->sa_limit = yang_dnode_get_uint32(args->dnode, NULL); break; } @@ -1614,7 +1614,7 @@ int pim_msdp_peer_sa_limit_destroy(struct nb_cb_destroy_args *args) break; case NB_EV_APPLY: mp = nb_running_get_entry(args->dnode, NULL, true); - /* TODO: remove limitation. */ + mp->sa_limit = 0; break; } From 613956ab8926fa06d120deff983fd20e97816574 Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Tue, 26 Nov 2024 11:13:47 -0300 Subject: [PATCH 072/106] topotests: test new MSDP SA limit feature Test that only the limit amount of SAs is learned from the peer. Signed-off-by: Rafael Zalamena --- tests/topotests/msdp_topo1/test_msdp_topo1.py | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/topotests/msdp_topo1/test_msdp_topo1.py b/tests/topotests/msdp_topo1/test_msdp_topo1.py index 8c25eeca06a6..5143ef67a517 100755 --- a/tests/topotests/msdp_topo1/test_msdp_topo1.py +++ b/tests/topotests/msdp_topo1/test_msdp_topo1.py @@ -511,6 +511,42 @@ def test_msdp_sa_filter(): assert val is None, "multicast route convergence failure" +def test_msdp_sa_limit(): + "Test MSDP SA limiting." + + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + tgen.gears["r4"].vtysh_cmd( + """ + configure terminal + router pim + msdp log sa-events + msdp peer 192.168.2.1 sa-limit 4 + msdp peer 192.168.3.1 sa-limit 4 + """ + ) + + # Flow from r1 -> r4 + for multicast_address in [ + "229.1.2.10", + "229.1.2.11", + "229.1.2.12", + "229.1.2.13", + "229.1.2.14", + ]: + app_helper.run("h1", [multicast_address, "h1-eth0"]) + app_helper.run("h2", ["--send=0.7", multicast_address, "h2-eth0"]) + + def test_sa_limit_log(): + r4_log = tgen.gears["r4"].net.getLog("log", "pimd") + return re.search(r"MSDP peer .+ reject SA (.+, .+): SA limit \d+ of 4", r4_log) + + _, val = topotest.run_and_expect(test_sa_limit_log, None, count=30, wait=1) + assert val is None, "SA limit check failed" + + def test_msdp_log_events(): "Test that the enabled logs are working as expected." From f28c74012a6cb754a35961196a7cac2fda7676fc Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Tue, 26 Nov 2024 11:26:43 -0300 Subject: [PATCH 073/106] doc: document new SA limit command Let user know about the new MSDP SA limit command. Signed-off-by: Rafael Zalamena --- doc/user/pim.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/user/pim.rst b/doc/user/pim.rst index ef49b076dff6..e8dd03e7c30a 100644 --- a/doc/user/pim.rst +++ b/doc/user/pim.rst @@ -503,6 +503,10 @@ Commands available for MSDP The filtering will only take effect starting from the command application. +.. clicmd:: msdp peer A.B.C.D sa-limit + + Configure the maximum number of SAs to learn from peer. + .. clicmd:: msdp peer A.B.C.D password WORD Use MD5 authentication to connect with the remote peer. From c8b7a5f30736c1b87f64c1b0c75ab801ad50db51 Mon Sep 17 00:00:00 2001 From: Rajasekar Raja Date: Tue, 10 Dec 2024 13:45:02 -0800 Subject: [PATCH 074/106] bgpd: Fix bgp core with a possible Intf delete Although trigger unknown, based on the backtrace in one of the internal testing, we do see some delete in the Intf where we can have the peer ifp pointer null and we try to dereference it while trying to install the route leading to a crash Skip updating the ifindex in such cases and since the nexthop is not properly updated, BGP skips sending it to zebra. BackTrace: 0 0x00007faef05e7ebc in ?? () from /lib/x86_64-linux-gnu/libc.so.6 1 0x00007faef0598fb2 in raise () from /lib/x86_64-linux-gnu/libc.so.6 2 0x00007faef09900dc in core_handler (signo=11, siginfo=0x7ffdde8cb4b0, context=) at lib/sigevent.c:274 3 4 0x00005560aad4b7d8 in update_ipv6nh_for_route_install (api_nh=0x7ffdde8cbe94, is_evpn=false, best_pi=0x5560b21187d0, pi=0x5560b21187d0, ifindex=0, nexthop=0x5560b03cb0dc, nh_bgp=0x5560ace04df0, nh_othervrf=0) at bgpd/bgp_zebra.c:1273 5 bgp_zebra_announce_actual (dest=dest@entry=0x5560afcfa950, info=0x5560b21187d0, bgp=0x5560ace04df0) at bgpd/bgp_zebra.c:1521 6 0x00005560aad4bc85 in bgp_handle_route_announcements_to_zebra (e=) at bgpd/bgp_zebra.c:1896 7 0x00007faef09a1c0d in thread_call (thread=thread@entry=0x7ffdde8d7580) at lib/thread.c:2008 8 0x00007faef095a598 in frr_run (master=0x5560ac7e5190) at lib/libfrr.c:1223 9 0x00005560aac65db6 in main (argc=, argv=) at bgpd/bgp_main.c:557 (gdb) f 4 4 0x00005560aad4b7d8 in update_ipv6nh_for_route_install (api_nh=0x7ffdde8cbe94, is_evpn=false, best_pi=0x5560b21187d0, pi=0x5560b21187d0, ifindex=0, nexthop=0x5560b03cb0dc, nh_bgp=0x5560ace04df0, nh_othervrf=0) at bgpd/bgp_zebra.c:1273 1273 in bgpd/bgp_zebra.c (gdb) p pi->peer->ifp $26 = (struct interface *) 0x0 Ticket :#4203904 Signed-off-by: Rajasekar Raja --- bgpd/bgp_zebra.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index ac4a6bb03bf6..d1bf471f5d87 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1191,9 +1191,10 @@ static bool update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp, ifindex = pi->peer->nexthop.ifp->ifindex; if (!ifindex) { - if (pi->peer->conf_if) - ifindex = pi->peer->ifp->ifindex; - else if (pi->peer->ifname) + if (pi->peer->conf_if) { + if (pi->peer->ifp) + ifindex = pi->peer->ifp->ifindex; + } else if (pi->peer->ifname) ifindex = ifname2ifindex( pi->peer->ifname, pi->peer->bgp->vrf_id); From 8df357223b70a6faef4ff5009bd263398eb1aa16 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 30 Oct 2024 21:24:44 +0100 Subject: [PATCH 075/106] bgpd, topotests: fix wrong peer type for loc-rib peer events When running the bgp_bmp test, peer_up message from the loc-rib are received with a wrong peer type. > {"peer_type": "global instance", "policy": "pre-policy", "ipv6": false, "peer_ip": "0.0.0.0", > "peer_distinguisher": "0:0", "peer_asn": 0, "peer_bgp_id": "0.0.0.0", > "timestamp": "2024-10-16 21:59:53.111963", "bmp_log_type": "peer up", "local_ip": "0.0.0.0", > "local_port": 0, "remote_port": 0, "seq": 1} RFC9069 mentions in 5.1 that peer address must be set to 0.0.0.0, and the peer_type value must be set to 3. Today, the value set is 0 (global instance). This is wrong. Fix this by modifying the BMP client, update the peer type value to loc-rib on peer up messages. Modify the current BMP test, by checking the peer up messages for the 0.0.0.0 IP address (which is the value used for loc-rib). > {"peer_type": "loc-rib instance", "is_filtered": false, "policy": "loc-rib", > "peer_distinguisher": "0:0", "peer_asn": 65501, "peer_bgp_id": "192.168.0.1", > "timestamp": "2024-10-16 21:59:53.111963", "bmp_log_type": "peer up", "local_ip": "0.0.0.0", > "local_port": 0, "remote_port": 0, "seq": 1} Signed-off-by: Philippe Guibert --- bgpd/bgp_bmp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index d6df56026078..e86e80ba2742 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -481,6 +481,9 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down) /* TODO: remove this when other RD and local instances supported */ peer_type = BMP_PEER_TYPE_GLOBAL_INSTANCE; + if (is_locrib == false) + peer_type = BMP_PEER_TYPE_GLOBAL_INSTANCE; + #define BGP_BMP_MAX_PACKET_SIZE 1024 #define BMP_PEERUP_INFO_TYPE_STRING 0 s = stream_new(BGP_MAX_PACKET_SIZE); @@ -552,9 +555,7 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down) bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_PEER_DOWN_NOTIFICATION); - bmp_per_peer_hdr(s, peer->bgp, peer, 0, - BMP_PEER_TYPE_GLOBAL_INSTANCE, 0, - &uptime_real); + bmp_per_peer_hdr(s, peer->bgp, peer, 0, peer_type, 0, &uptime_real); type_pos = stream_get_endp(s); stream_putc(s, 0); /* placeholder for down reason */ From 9dcf9d800a78dd0a3cc67a4f788a57338f6b8061 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 30 Oct 2024 21:30:44 +0100 Subject: [PATCH 076/106] topotests: bgp_bmp, expose peer_distinguisher in loc-rib The BMP implementation currently only supports global and loc-rib instance types. When loc-rib is selected, the peer_distinguisher is set to the route distinguisher of the L3VRF where the BGP instance is. This functionality has not been tested until now, because the peer distinguisher value had been explicitly omitted in the bmp messages. Expose the peer distinguisher value in all BMP messages received. This change requires to modify the expected output for loc-rib when the BGP instance is in a L3VRF. The handling of peer distinguisher value for RD instances will follow in the next commits. Link: https://www.rfc-editor.org/rfc/rfc7854.html#section-4.2 Signed-off-by: Philippe Guibert --- tests/topotests/bgp_bmp/bgpbmp.py | 12 ------------ .../bgp_bmp/bmp1vrf/bmp-update-loc-rib-step1.json | 2 ++ .../bgp_bmp/bmp1vrf/bmp-withdraw-loc-rib-step1.json | 2 ++ tests/topotests/bgp_bmp/r1vrf/frr.conf | 2 ++ 4 files changed, 6 insertions(+), 12 deletions(-) diff --git a/tests/topotests/bgp_bmp/bgpbmp.py b/tests/topotests/bgp_bmp/bgpbmp.py index 5e8b0d9be72d..0a0a845b3ab3 100644 --- a/tests/topotests/bgp_bmp/bgpbmp.py +++ b/tests/topotests/bgp_bmp/bgpbmp.py @@ -164,18 +164,6 @@ def bmp_check_for_prefixes( for k, v in sorted(m.items()) # filter out variable keys if k not in ["timestamp", "seq", "nxhp_link-local"] - and ( - # When policy is loc-rib, the peer-distinguisher is 0:0 - # for the default VRF or the RD if any or the 0:. - # 0: is used to distinguished. RFC7854 says: "If the - # peer is a "Local Instance Peer", it is set to a unique, - # locally defined value." The value is not tested because it - # is variable. - k != "peer_distinguisher" - or policy != loc_rib - or v == "0:0" - or not v.startswith("0:") - ) } # build expected JSON files diff --git a/tests/topotests/bgp_bmp/bmp1vrf/bmp-update-loc-rib-step1.json b/tests/topotests/bgp_bmp/bmp1vrf/bmp-update-loc-rib-step1.json index ba31bf1d5df7..d6c87dd4fdaa 100644 --- a/tests/topotests/bgp_bmp/bmp1vrf/bmp-update-loc-rib-step1.json +++ b/tests/topotests/bgp_bmp/bmp1vrf/bmp-update-loc-rib-step1.json @@ -10,6 +10,7 @@ "origin": "IGP", "peer_asn": 65501, "peer_bgp_id": "192.168.0.1", + "peer_distinguisher": "444:1", "peer_type": "loc-rib instance", "policy": "loc-rib" }, @@ -23,6 +24,7 @@ "origin": "IGP", "peer_asn": 65501, "peer_bgp_id": "192.168.0.1", + "peer_distinguisher": "555:1", "peer_type": "loc-rib instance", "policy": "loc-rib", "safi": 1 diff --git a/tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-loc-rib-step1.json b/tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-loc-rib-step1.json index 37ddc09ff85b..6a82f7af1af9 100644 --- a/tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-loc-rib-step1.json +++ b/tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-loc-rib-step1.json @@ -7,6 +7,7 @@ "is_filtered": false, "peer_asn": 65501, "peer_bgp_id": "192.168.0.1", + "peer_distinguisher": "444:1", "peer_type": "loc-rib instance", "policy": "loc-rib" }, @@ -17,6 +18,7 @@ "is_filtered": false, "peer_asn": 65501, "peer_bgp_id": "192.168.0.1", + "peer_distinguisher": "555:1", "peer_type": "loc-rib instance", "policy": "loc-rib", "safi": 1 diff --git a/tests/topotests/bgp_bmp/r1vrf/frr.conf b/tests/topotests/bgp_bmp/r1vrf/frr.conf index cb8a7d2b14e4..87066934588e 100644 --- a/tests/topotests/bgp_bmp/r1vrf/frr.conf +++ b/tests/topotests/bgp_bmp/r1vrf/frr.conf @@ -23,12 +23,14 @@ router bgp 65501 vrf vrf1 exit ! address-family ipv4 unicast + rd vpn export 444:1 neighbor 192.168.0.2 activate neighbor 192.168.0.2 soft-reconfiguration inbound no neighbor 192:168::2 activate exit-address-family ! address-family ipv6 unicast + rd vpn export 555:1 neighbor 192:168::2 activate neighbor 192:168::2 soft-reconfiguration inbound exit-address-family From 34d8770a22091b128cee662bc35291a860bafa66 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 30 Oct 2024 22:20:30 +0100 Subject: [PATCH 077/106] bgpd: modify bmp_get_peer_distinguisher to support AFI_UNSPEC If a given L3VRF instance requests a peer distinguisher for a peer up/down message, the AFI_UNSPEC afi parameter will be used; no RD is chosen for this AFI. Fix this by priorizing the AFI_IP value before the AFI_IP6 value. For instance, a router with both RD set for each address-family, peer up/down messages will be sent with the RD set to the one for AFI_IP. Signed-off-by: Philippe Guibert --- bgpd/bgp_bmp.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index e86e80ba2742..56d4c55246bf 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -279,6 +279,8 @@ static inline int bmp_get_peer_distinguisher(struct bmp *bmp, afi_t afi, uint8_t peer_type, uint64_t *result_ref) { + /* use RD if set in VRF config */ + struct prefix_rd *prd; /* remove this check when the other peer types get correct peer dist. *(RFC7854) impl. @@ -294,11 +296,16 @@ static inline int bmp_get_peer_distinguisher(struct bmp *bmp, afi_t afi, if (bgp->inst_type == VRF_DEFAULT) return (*result_ref = 0); - /* use RD if set in VRF config for this AFI */ - struct prefix_rd *prd = &bgp->vpn_policy[afi].tovpn_rd; + prd = &bgp->vpn_policy[AFI_IP].tovpn_rd; + if ((afi == AFI_IP || afi == AFI_UNSPEC) && + CHECK_FLAG(bgp->vpn_policy[AFI_IP].flags, BGP_VPN_POLICY_TOVPN_RD_SET)) { + memcpy(result_ref, prd->val, sizeof(prd->val)); + return 0; + } - if (CHECK_FLAG(bgp->vpn_policy[afi].flags, - BGP_VPN_POLICY_TOVPN_RD_SET)) { + prd = &bgp->vpn_policy[AFI_IP6].tovpn_rd; + if ((afi == AFI_IP6 || afi == AFI_UNSPEC) && + CHECK_FLAG(bgp->vpn_policy[AFI_IP6].flags, BGP_VPN_POLICY_TOVPN_RD_SET)) { memcpy(result_ref, prd->val, sizeof(prd->val)); return 0; } From f7b0f6f3ed2c5b67c90f658ebd4c43c479d5bb57 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 30 Oct 2024 21:57:35 +0100 Subject: [PATCH 078/106] bgpd: bmp, add peer distinguisher support for peer up/down All BMP peer up/down messages send a 0:0 peer distinguisher. This will not be ok when adding RD instance type. Add code to get the peer distinguisher value. - modify the API to pass the BGP instance instead of BMP. - implement error cases with an unknown vrf identifier or a peer type with local type value. - handle the error return of the API; consequently, handle the bmp_peerstate() error return in the calling functions. There is no functional change, as the peer type value is either loc-rib or global, both cases are already handled. The next commit will handle the RD instance case. Signed-off-by: Philippe Guibert --- bgpd/bgp_bmp.c | 47 ++++++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index 56d4c55246bf..fbd6e8a1d144 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -275,13 +275,16 @@ static inline int bmp_get_peer_type(struct peer *peer) return bmp_get_peer_type_vrf(peer->bgp->vrf_id); } -static inline int bmp_get_peer_distinguisher(struct bmp *bmp, afi_t afi, - uint8_t peer_type, +static inline int bmp_get_peer_distinguisher(struct bgp *bgp, afi_t afi, uint8_t peer_type, uint64_t *result_ref) { /* use RD if set in VRF config */ struct prefix_rd *prd; + /* sending vrf_id or rd could be turned into an option at some point */ + if (peer_type == BMP_PEER_TYPE_LOCAL_INSTANCE || bgp->vrf_id == VRF_UNKNOWN) + return 1; + /* remove this check when the other peer types get correct peer dist. *(RFC7854) impl. * for now, always return no error and 0 peer distinguisher as before @@ -289,9 +292,6 @@ static inline int bmp_get_peer_distinguisher(struct bmp *bmp, afi_t afi, if (peer_type != BMP_PEER_TYPE_LOC_RIB_INSTANCE) return (*result_ref = 0); - /* sending vrf_id or rd could be turned into an option at some point */ - struct bgp *bgp = bmp->targets->bgp; - /* vrf default => ok, distinguisher 0 */ if (bgp->inst_type == VRF_DEFAULT) return (*result_ref = 0); @@ -310,10 +310,6 @@ static inline int bmp_get_peer_distinguisher(struct bmp *bmp, afi_t afi, return 0; } - /* VRF has no id => error => message should be skipped */ - if (bgp->vrf_id == VRF_UNKNOWN) - return 1; - /* use VRF id converted to ::vrf_id 64bits format */ *result_ref = ((uint64_t)htonl(bgp->vrf_id)) << 32; return 0; @@ -476,6 +472,7 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down) struct timeval uptime, uptime_real; uint8_t peer_type; bool is_locrib = false; + uint64_t peer_distinguisher = 0; uptime.tv_sec = peer->uptime; uptime.tv_usec = 0; @@ -491,6 +488,12 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down) if (is_locrib == false) peer_type = BMP_PEER_TYPE_GLOBAL_INSTANCE; + if (bmp_get_peer_distinguisher(peer->bgp, AFI_UNSPEC, peer_type, &peer_distinguisher)) { + zlog_warn("skipping bmp message for peer %s: can't get peer distinguisher", + peer->host); + return NULL; + } + #define BGP_BMP_MAX_PACKET_SIZE 1024 #define BMP_PEERUP_INFO_TYPE_STRING 0 s = stream_new(BGP_MAX_PACKET_SIZE); @@ -616,8 +619,10 @@ static int bmp_send_peerup(struct bmp *bmp) /* Walk down all peers */ for (ALL_LIST_ELEMENTS_RO(bmp->targets->bgp->peer, node, peer)) { s = bmp_peerstate(peer, false); - pullwr_write_stream(bmp->pullwr, s); - stream_free(s); + if (s) { + pullwr_write_stream(bmp->pullwr, s); + stream_free(s); + } } return 0; @@ -634,10 +639,10 @@ static int bmp_send_peerup_vrf(struct bmp *bmp) bmp_bgp_update_vrf_status(bmpbgp, vrf_state_unknown); s = bmp_peerstate(bmpbgp->bgp->peer_self, bmpbgp->vrf_state == vrf_state_down); - - pullwr_write_stream(bmp->pullwr, s); - stream_free(s); - + if (s) { + pullwr_write_stream(bmp->pullwr, s); + stream_free(s); + } return 0; } @@ -648,6 +653,9 @@ static void bmp_send_all(struct bmp_bgp *bmpbgp, struct stream *s) struct bmp_targets *bt; struct bmp *bmp; + if (!s) + return; + frr_each(bmp_targets, &bmpbgp->targets, bt) frr_each(bmp_session, &bt->sessions, bmp) pullwr_write_stream(bmp->pullwr, s); @@ -656,6 +664,9 @@ static void bmp_send_all(struct bmp_bgp *bmpbgp, struct stream *s) static void bmp_send_all_safe(struct bmp_bgp *bmpbgp, struct stream *s) { + if (!s) + return; + if (!bmpbgp) { stream_free(s); return; @@ -979,8 +990,7 @@ static void bmp_eor(struct bmp *bmp, afi_t afi, safi_t safi, uint8_t flags, uint64_t peer_distinguisher = 0; /* skip this message if peer distinguisher is not available */ - if (bmp_get_peer_distinguisher(bmp, afi, peer_type_flag, - &peer_distinguisher)) { + if (bmp_get_peer_distinguisher(peer->bgp, afi, peer_type_flag, &peer_distinguisher)) { zlog_warn( "skipping bmp message for reason: can't get peer distinguisher"); continue; @@ -1108,8 +1118,7 @@ static void bmp_monitor(struct bmp *bmp, struct peer *peer, uint8_t flags, uint64_t peer_distinguisher = 0; /* skip this message if peer distinguisher is not available */ - if (bmp_get_peer_distinguisher(bmp, afi, peer_type_flag, - &peer_distinguisher)) { + if (bmp_get_peer_distinguisher(peer->bgp, afi, peer_type_flag, &peer_distinguisher)) { zlog_warn( "skipping bmp message for reason: can't get peer distinguisher"); return; From 0a20ef9389a49fa59a80ebe1003658bb0de9b0d8 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 31 Oct 2024 09:18:56 +0100 Subject: [PATCH 079/106] bgpd, topotests: bmp, fix wrong peer type for vrf route messages When running the bgp_bmp_2 vrf test, peer route messages from the pre and post policy are received with a wrong peer type value > {"peer_type": "global instance", "policy": "pre-policy", "ipv6": false, > "peer_ip": "192.168.0.2", "peer_distinguisher": "0:0", "peer_asn": 65502, > "peer_bgp_id": "192.168.0.2", "timestamp": "2024-10-31 08:19:58.111963", > "bmp_log_type": "update", "origin": "IGP", "as_path": "65501 65502", > "bgp_nexthop": "192.168.0.2", "ip_prefix": "172.31.0.15/32", "seq": 15} In addition to global instance peers, RFC7854 defines RD instance peers. This value can be used for peers which are on a BGP VRF instance, for example with an L3VPN setup. When configuring a BGP VRF instance, the peer type should be seen as an RD instance peer. Fix this by modifying the BMP client: - update the peer type for vrf mirror and monitoring messages - modify bgp_bmp_2 vrf test to control the peer_type value > {"peer_type": "route distinguisher instance", "policy": "pre-policy", "ipv6": false, > "peer_ip": "192.168.0.2", "peer_distinguisher": "0:0", "peer_asn": 65502, > "peer_bgp_id": "192.168.0.2", "timestamp": "2024-10-31 08:19:58.111963", > "bmp_log_type": "update", "origin": "IGP", "as_path": "65501 65502", > "bgp_nexthop": "192.168.0.2", "ip_prefix": "172.31.0.15/32", "seq": 15} Signed-off-by: Philippe Guibert --- bgpd/bgp_bmp.c | 54 ++++++++++--------- .../bmp1vrf/bmp-update-post-policy-step1.json | 4 +- .../bmp1vrf/bmp-update-pre-policy-step1.json | 4 +- .../bmp-withdraw-post-policy-step1.json | 4 +- .../bmp-withdraw-pre-policy-step1.json | 4 +- 5 files changed, 38 insertions(+), 32 deletions(-) diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index fbd6e8a1d144..2b3c2193e717 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -794,14 +794,17 @@ static void bmp_wrmirror_lost(struct bmp *bmp, struct pullwr *pullwr) { struct stream *s; struct timeval tv; + uint8_t peer_type_flag; gettimeofday(&tv, NULL); + peer_type_flag = bmp_get_peer_type_vrf(bmp->targets->bgp->vrf_id); + s = stream_new(BGP_MAX_PACKET_SIZE); bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_ROUTE_MIRRORING); - bmp_per_peer_hdr(s, bmp->targets->bgp, bmp->targets->bgp->peer_self, 0, - BMP_PEER_TYPE_GLOBAL_INSTANCE, 0, &tv); + bmp_per_peer_hdr(s, bmp->targets->bgp, bmp->targets->bgp->peer_self, 0, peer_type_flag, 0, + &tv); stream_putw(s, BMP_MIRROR_TLV_TYPE_INFO); stream_putw(s, 2); @@ -818,6 +821,7 @@ static bool bmp_wrmirror(struct bmp *bmp, struct pullwr *pullwr) struct bmp_mirrorq *bmq; struct peer *peer; bool written = false; + uint8_t peer_type_flag; if (bmp->mirror_lost) { bmp_wrmirror_lost(bmp, pullwr); @@ -835,12 +839,13 @@ static bool bmp_wrmirror(struct bmp *bmp, struct pullwr *pullwr) goto out; } + peer_type_flag = bmp_get_peer_type_vrf(bmp->targets->bgp->vrf_id); + struct stream *s; s = stream_new(BGP_MAX_PACKET_SIZE); bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_ROUTE_MIRRORING); - bmp_per_peer_hdr(s, bmp->targets->bgp, peer, 0, - BMP_PEER_TYPE_GLOBAL_INSTANCE, 0, &bmq->tv); + bmp_per_peer_hdr(s, bmp->targets->bgp, peer, 0, peer_type_flag, 0, &bmq->tv); /* BMP Mirror TLV. */ stream_putw(s, BMP_MIRROR_TLV_TYPE_BGP_MESSAGE); @@ -1152,6 +1157,7 @@ static bool bmp_wrsync(struct bmp *bmp, struct pullwr *pullwr) uint8_t bpi_num_labels, adjin_num_labels; afi_t afi; safi_t safi; + uint8_t peer_type_flag; if (bmp->syncafi == AFI_MAX) { FOREACH_AFI_SAFI (afi, safi) { @@ -1194,6 +1200,8 @@ static bool bmp_wrsync(struct bmp *bmp, struct pullwr *pullwr) struct bgp_path_info *bpi = NULL, *bpiter; struct bgp_adj_in *adjin = NULL, *adjiter; + peer_type_flag = bmp_get_peer_type_vrf(bmp->targets->bgp->vrf_id); + if ((afi == AFI_L2VPN && safi == SAFI_EVPN) || (safi == SAFI_MPLS_VPN)) { /* initialize syncrdpos to the first @@ -1248,10 +1256,8 @@ static bool bmp_wrsync(struct bmp *bmp, struct pullwr *pullwr) bmp->remote, afi2str(afi), safi2str(safi)); - bmp_eor(bmp, afi, safi, BMP_PEER_FLAG_L, - BMP_PEER_TYPE_GLOBAL_INSTANCE); - bmp_eor(bmp, afi, safi, 0, - BMP_PEER_TYPE_GLOBAL_INSTANCE); + bmp_eor(bmp, afi, safi, BMP_PEER_FLAG_L, peer_type_flag); + bmp_eor(bmp, afi, safi, 0, peer_type_flag); bmp_eor(bmp, afi, safi, 0, BMP_PEER_TYPE_LOC_RIB_INSTANCE); @@ -1335,19 +1341,20 @@ static bool bmp_wrsync(struct bmp *bmp, struct pullwr *pullwr) bpi_num_labels); } + if (bpi) + peer_type_flag = bmp_get_peer_type(bpi->peer); + if (bpi && CHECK_FLAG(bpi->flags, BGP_PATH_VALID) && CHECK_FLAG(bmp->targets->afimon[afi][safi], BMP_MON_POSTPOLICY)) - bmp_monitor(bmp, bpi->peer, BMP_PEER_FLAG_L, - BMP_PEER_TYPE_GLOBAL_INSTANCE, bn_p, prd, bpi->attr, + bmp_monitor(bmp, bpi->peer, BMP_PEER_FLAG_L, peer_type_flag, bn_p, prd, bpi->attr, afi, safi, bpi->uptime, - bpi_num_labels ? bpi->extra->labels->label : NULL, - bpi_num_labels); + bpi_num_labels ? bpi->extra->labels->label : NULL, bpi_num_labels); if (adjin) { adjin_num_labels = adjin->labels ? adjin->labels->num_labels : 0; - bmp_monitor(bmp, adjin->peer, 0, BMP_PEER_TYPE_GLOBAL_INSTANCE, bn_p, prd, - adjin->attr, afi, safi, adjin->uptime, - adjin_num_labels ? &adjin->labels->label[0] : NULL, adjin_num_labels); + bmp_monitor(bmp, adjin->peer, 0, peer_type_flag, bn_p, prd, adjin->attr, afi, safi, + adjin->uptime, adjin_num_labels ? &adjin->labels->label[0] : NULL, + adjin_num_labels); } if (bn) @@ -1486,6 +1493,7 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr) struct bgp_dest *bn = NULL; bool written = false; uint8_t bpi_num_labels, adjin_num_labels; + uint8_t peer_type_flag; bqe = bmp_pull(bmp); if (!bqe) @@ -1526,6 +1534,8 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr) bn = bgp_safi_node_lookup(bmp->targets->bgp->rib[afi][safi], safi, &bqe->p, prd); + peer_type_flag = bmp_get_peer_type(peer); + if (CHECK_FLAG(bmp->targets->afimon[afi][safi], BMP_MON_POSTPOLICY)) { struct bgp_path_info *bpi; @@ -1539,12 +1549,9 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr) bpi_num_labels = BGP_PATH_INFO_NUM_LABELS(bpi); - bmp_monitor(bmp, peer, BMP_PEER_FLAG_L, - BMP_PEER_TYPE_GLOBAL_INSTANCE, &bqe->p, prd, - bpi ? bpi->attr : NULL, afi, safi, - bpi ? bpi->uptime : monotime(NULL), - bpi_num_labels ? bpi->extra->labels->label : NULL, - bpi_num_labels); + bmp_monitor(bmp, peer, BMP_PEER_FLAG_L, peer_type_flag, &bqe->p, prd, + bpi ? bpi->attr : NULL, afi, safi, bpi ? bpi->uptime : monotime(NULL), + bpi_num_labels ? bpi->extra->labels->label : NULL, bpi_num_labels); written = true; } @@ -1557,9 +1564,8 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr) break; } adjin_num_labels = adjin && adjin->labels ? adjin->labels->num_labels : 0; - bmp_monitor(bmp, peer, 0, BMP_PEER_TYPE_GLOBAL_INSTANCE, &bqe->p, prd, - adjin ? adjin->attr : NULL, afi, safi, - adjin ? adjin->uptime : monotime(NULL), + bmp_monitor(bmp, peer, 0, peer_type_flag, &bqe->p, prd, adjin ? adjin->attr : NULL, + afi, safi, adjin ? adjin->uptime : monotime(NULL), adjin_num_labels ? &adjin->labels->label[0] : NULL, adjin_num_labels); written = true; } diff --git a/tests/topotests/bgp_bmp/bmp1vrf/bmp-update-post-policy-step1.json b/tests/topotests/bgp_bmp/bmp1vrf/bmp-update-post-policy-step1.json index d5d9d6518265..18f40b16c7d8 100644 --- a/tests/topotests/bgp_bmp/bmp1vrf/bmp-update-post-policy-step1.json +++ b/tests/topotests/bgp_bmp/bmp1vrf/bmp-update-post-policy-step1.json @@ -12,7 +12,7 @@ "peer_bgp_id": "192.168.0.2", "peer_distinguisher": "0:0", "peer_ip": "192.168.0.2", - "peer_type": "global instance", + "peer_type": "route distinguisher instance", "policy": "post-policy" }, "2111::1111/128": { @@ -27,7 +27,7 @@ "peer_bgp_id": "192.168.0.2", "peer_distinguisher": "0:0", "peer_ip": "192:168::2", - "peer_type": "global instance", + "peer_type": "route distinguisher instance", "policy": "post-policy", "safi": 1 } diff --git a/tests/topotests/bgp_bmp/bmp1vrf/bmp-update-pre-policy-step1.json b/tests/topotests/bgp_bmp/bmp1vrf/bmp-update-pre-policy-step1.json index e11badc040a9..61ef0eab86ac 100644 --- a/tests/topotests/bgp_bmp/bmp1vrf/bmp-update-pre-policy-step1.json +++ b/tests/topotests/bgp_bmp/bmp1vrf/bmp-update-pre-policy-step1.json @@ -12,7 +12,7 @@ "peer_bgp_id": "192.168.0.2", "peer_distinguisher": "0:0", "peer_ip": "192.168.0.2", - "peer_type": "global instance", + "peer_type": "route distinguisher instance", "policy": "pre-policy" }, "2111::1111/128": { @@ -27,7 +27,7 @@ "peer_bgp_id": "192.168.0.2", "peer_distinguisher": "0:0", "peer_ip": "192:168::2", - "peer_type": "global instance", + "peer_type": "route distinguisher instance", "policy": "pre-policy", "safi": 1 } diff --git a/tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-post-policy-step1.json b/tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-post-policy-step1.json index de84307a4e6b..c28ce851a2a4 100644 --- a/tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-post-policy-step1.json +++ b/tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-post-policy-step1.json @@ -9,7 +9,7 @@ "peer_bgp_id": "192.168.0.2", "peer_distinguisher": "0:0", "peer_ip": "192.168.0.2", - "peer_type": "global instance", + "peer_type": "route distinguisher instance", "policy": "post-policy" }, "2111::1111/128": { @@ -21,7 +21,7 @@ "peer_bgp_id": "192.168.0.2", "peer_distinguisher": "0:0", "peer_ip": "192:168::2", - "peer_type": "global instance", + "peer_type": "route distinguisher instance", "policy": "post-policy", "safi": 1 } diff --git a/tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-pre-policy-step1.json b/tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-pre-policy-step1.json index 1c34498b7a38..976c7d47167e 100644 --- a/tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-pre-policy-step1.json +++ b/tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-pre-policy-step1.json @@ -9,7 +9,7 @@ "peer_bgp_id": "192.168.0.2", "peer_distinguisher": "0:0", "peer_ip": "192.168.0.2", - "peer_type": "global instance", + "peer_type": "route distinguisher instance", "policy": "pre-policy" }, "2111::1111/128": { @@ -21,7 +21,7 @@ "peer_bgp_id": "192.168.0.2", "peer_distinguisher": "0:0", "peer_ip": "192:168::2", - "peer_type": "global instance", + "peer_type": "route distinguisher instance", "policy": "pre-policy", "safi": 1 } From 6a3e1e3056f3b0091ed23ebb03ff39bb6e754b86 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 31 Oct 2024 08:21:22 +0100 Subject: [PATCH 080/106] bgpd, topotests: bmp, fix wrong peer distinguisher for vrf route events When running the bgp_bmp_2 vrf test, peer route messages from the pre and post policy are received with a wrong peer distinguisher value. > {"peer_type": "route distinguisher instance", "policy": "pre-policy", "ipv6": false, > "peer_ip": "192.168.0.2", "peer_distinguisher": "0:0", "peer_asn": 65502, > "peer_bgp_id": "192.168.0.2", "timestamp": "2024-10-31 08:19:58.111963", > "bmp_log_type": "update", "origin": "IGP", "as_path": "65501 65502", > "bgp_nexthop": "192.168.0.2", "ip_prefix": "172.31.0.15/32", "seq": 15} RFC7854 mentions in 4.2 that if the peer is a "RD Instance Peer", it is set to the route distinguisher of the particular instance the peer belongs to. Fix this by modifying the BMP client: - update the peer distinguisher value by unlocking the filling of the peer distinguisher in the function. This change impacts monitoring messages. - add the peer distinguisher computation for mirror messages - modify the bgp_bmp_2 vrf test, update the peer_distinguisher value > {"peer_type": "route distinguisher instance", "policy": "pre-policy", "ipv6": false, > "peer_ip": "192.168.0.2", "peer_distinguisher": "444:1", "peer_asn": 65502, > "peer_bgp_id": "192.168.0.2", "timestamp": "2024-10-31 08:19:58.111963", > "bmp_log_type": "update", "origin": "IGP", "as_path": "65501 65502", > "bgp_nexthop": "192.168.0.2", "ip_prefix": "172.31.0.15/32", "seq": 15} Signed-off-by: Philippe Guibert --- bgpd/bgp_bmp.c | 28 ++++++++++++------- .../bmp1vrf/bmp-update-post-policy-step1.json | 4 +-- .../bmp1vrf/bmp-update-pre-policy-step1.json | 4 +-- .../bmp-withdraw-post-policy-step1.json | 4 +-- .../bmp-withdraw-pre-policy-step1.json | 4 +-- 5 files changed, 26 insertions(+), 18 deletions(-) diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index 2b3c2193e717..65a99d75e7f4 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -285,13 +285,6 @@ static inline int bmp_get_peer_distinguisher(struct bgp *bgp, afi_t afi, uint8_t if (peer_type == BMP_PEER_TYPE_LOCAL_INSTANCE || bgp->vrf_id == VRF_UNKNOWN) return 1; - /* remove this check when the other peer types get correct peer dist. - *(RFC7854) impl. - * for now, always return no error and 0 peer distinguisher as before - */ - if (peer_type != BMP_PEER_TYPE_LOC_RIB_INSTANCE) - return (*result_ref = 0); - /* vrf default => ok, distinguisher 0 */ if (bgp->inst_type == VRF_DEFAULT) return (*result_ref = 0); @@ -795,16 +788,23 @@ static void bmp_wrmirror_lost(struct bmp *bmp, struct pullwr *pullwr) struct stream *s; struct timeval tv; uint8_t peer_type_flag; + uint64_t peer_distinguisher = 0; gettimeofday(&tv, NULL); peer_type_flag = bmp_get_peer_type_vrf(bmp->targets->bgp->vrf_id); + if (bmp_get_peer_distinguisher(bmp->targets->bgp, AFI_UNSPEC, peer_type_flag, + &peer_distinguisher)) { + zlog_warn("skipping bmp message for reason: can't get peer distinguisher"); + return; + } + s = stream_new(BGP_MAX_PACKET_SIZE); bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_ROUTE_MIRRORING); - bmp_per_peer_hdr(s, bmp->targets->bgp, bmp->targets->bgp->peer_self, 0, peer_type_flag, 0, - &tv); + bmp_per_peer_hdr(s, bmp->targets->bgp, bmp->targets->bgp->peer_self, 0, peer_type_flag, + peer_distinguisher, &tv); stream_putw(s, BMP_MIRROR_TLV_TYPE_INFO); stream_putw(s, 2); @@ -822,6 +822,7 @@ static bool bmp_wrmirror(struct bmp *bmp, struct pullwr *pullwr) struct peer *peer; bool written = false; uint8_t peer_type_flag; + uint64_t peer_distinguisher = 0; if (bmp->mirror_lost) { bmp_wrmirror_lost(bmp, pullwr); @@ -841,11 +842,18 @@ static bool bmp_wrmirror(struct bmp *bmp, struct pullwr *pullwr) peer_type_flag = bmp_get_peer_type_vrf(bmp->targets->bgp->vrf_id); + if (bmp_get_peer_distinguisher(peer->bgp, AFI_UNSPEC, peer_type_flag, &peer_distinguisher)) { + zlog_warn("skipping bmp message for peer %s: can't get peer distinguisher", + peer->host); + goto out; + } + struct stream *s; s = stream_new(BGP_MAX_PACKET_SIZE); bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_ROUTE_MIRRORING); - bmp_per_peer_hdr(s, bmp->targets->bgp, peer, 0, peer_type_flag, 0, &bmq->tv); + bmp_per_peer_hdr(s, bmp->targets->bgp, peer, 0, peer_type_flag, peer_distinguisher, + &bmq->tv); /* BMP Mirror TLV. */ stream_putw(s, BMP_MIRROR_TLV_TYPE_BGP_MESSAGE); diff --git a/tests/topotests/bgp_bmp/bmp1vrf/bmp-update-post-policy-step1.json b/tests/topotests/bgp_bmp/bmp1vrf/bmp-update-post-policy-step1.json index 18f40b16c7d8..04e01623dfc0 100644 --- a/tests/topotests/bgp_bmp/bmp1vrf/bmp-update-post-policy-step1.json +++ b/tests/topotests/bgp_bmp/bmp1vrf/bmp-update-post-policy-step1.json @@ -10,7 +10,7 @@ "origin": "IGP", "peer_asn": 65502, "peer_bgp_id": "192.168.0.2", - "peer_distinguisher": "0:0", + "peer_distinguisher": "444:1", "peer_ip": "192.168.0.2", "peer_type": "route distinguisher instance", "policy": "post-policy" @@ -25,7 +25,7 @@ "origin": "IGP", "peer_asn": 65502, "peer_bgp_id": "192.168.0.2", - "peer_distinguisher": "0:0", + "peer_distinguisher": "555:1", "peer_ip": "192:168::2", "peer_type": "route distinguisher instance", "policy": "post-policy", diff --git a/tests/topotests/bgp_bmp/bmp1vrf/bmp-update-pre-policy-step1.json b/tests/topotests/bgp_bmp/bmp1vrf/bmp-update-pre-policy-step1.json index 61ef0eab86ac..760ee0409ab4 100644 --- a/tests/topotests/bgp_bmp/bmp1vrf/bmp-update-pre-policy-step1.json +++ b/tests/topotests/bgp_bmp/bmp1vrf/bmp-update-pre-policy-step1.json @@ -10,7 +10,7 @@ "origin": "IGP", "peer_asn": 65502, "peer_bgp_id": "192.168.0.2", - "peer_distinguisher": "0:0", + "peer_distinguisher": "444:1", "peer_ip": "192.168.0.2", "peer_type": "route distinguisher instance", "policy": "pre-policy" @@ -25,7 +25,7 @@ "origin": "IGP", "peer_asn": 65502, "peer_bgp_id": "192.168.0.2", - "peer_distinguisher": "0:0", + "peer_distinguisher": "555:1", "peer_ip": "192:168::2", "peer_type": "route distinguisher instance", "policy": "pre-policy", diff --git a/tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-post-policy-step1.json b/tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-post-policy-step1.json index c28ce851a2a4..f57b1a51cefb 100644 --- a/tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-post-policy-step1.json +++ b/tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-post-policy-step1.json @@ -7,7 +7,7 @@ "ipv6": false, "peer_asn": 65502, "peer_bgp_id": "192.168.0.2", - "peer_distinguisher": "0:0", + "peer_distinguisher": "444:1", "peer_ip": "192.168.0.2", "peer_type": "route distinguisher instance", "policy": "post-policy" @@ -19,7 +19,7 @@ "ipv6": true, "peer_asn": 65502, "peer_bgp_id": "192.168.0.2", - "peer_distinguisher": "0:0", + "peer_distinguisher": "555:1", "peer_ip": "192:168::2", "peer_type": "route distinguisher instance", "policy": "post-policy", diff --git a/tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-pre-policy-step1.json b/tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-pre-policy-step1.json index 976c7d47167e..a52308c7892e 100644 --- a/tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-pre-policy-step1.json +++ b/tests/topotests/bgp_bmp/bmp1vrf/bmp-withdraw-pre-policy-step1.json @@ -7,7 +7,7 @@ "ipv6": false, "peer_asn": 65502, "peer_bgp_id": "192.168.0.2", - "peer_distinguisher": "0:0", + "peer_distinguisher": "444:1", "peer_ip": "192.168.0.2", "peer_type": "route distinguisher instance", "policy": "pre-policy" @@ -19,7 +19,7 @@ "ipv6": true, "peer_asn": 65502, "peer_bgp_id": "192.168.0.2", - "peer_distinguisher": "0:0", + "peer_distinguisher": "555:1", "peer_ip": "192:168::2", "peer_type": "route distinguisher instance", "policy": "pre-policy", From ff0e1f2f28d91af62060ac97a5272550fbd4f60b Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 31 Oct 2024 09:31:04 +0100 Subject: [PATCH 081/106] bgpd, topotests: bmp, fix wrong peer type for peer up/down events When running the bgp_bmp_2 vrf test, peer up/down events from the pre and post policy are received with a wrong peer type value > {"peer_type": "global instance", "policy": "pre-policy", "ipv6": false, > "peer_ip": "192.168.0.2", "peer_distinguisher": "0:0", "peer_asn": 65502, > "peer_bgp_id": "192.168.0.2", "timestamp": "2024-10-16 21:59:53.111962", > "bmp_log_type": "peer up", "local_ip": "192.168.0.1", "local_port": 179, > "remote_port": 50710, "seq": 4} RFC7854 defines RD instance peer type, and later in 4.2 requests that the peer distinguisher value be set to non zero value when the peer type is not global. This is the case for peer vrf instances. Fix this by modifying the BMP client, update the peer type value by updating the peer type value when sending peer up/down messages. Add a check in the bgp_bmp_2 test to ensure that peer type is correctly set. > {"peer_type": "route distinguisher instance", "policy": "pre-policy", > "ipv6": true, "peer_ip": "192:168::2", "peer_distinguisher": "0:0", > "peer_asn": 65502, "peer_bgp_id": "192.168.0.2", "timestamp": > "2024-10-16 21:59:53.111962", "bmp_log_type": "peer up", "local_ip": > "192:168::1", "local_port": 179, "remote_port": 50836, "seq": 5} Signed-off-by: Philippe Guibert --- bgpd/bgp_bmp.c | 6 ------ tests/topotests/bgp_bmp/bgpbmp.py | 4 +++- tests/topotests/bgp_bmp/test_bgp_bmp_2.py | 2 ++ 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index 65a99d75e7f4..08cfcdb37c03 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -474,12 +474,6 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down) peer_type = bmp_get_peer_type(peer); if (peer_type == BMP_PEER_TYPE_LOC_RIB_INSTANCE) is_locrib = true; - else - /* TODO: remove this when other RD and local instances supported */ - peer_type = BMP_PEER_TYPE_GLOBAL_INSTANCE; - - if (is_locrib == false) - peer_type = BMP_PEER_TYPE_GLOBAL_INSTANCE; if (bmp_get_peer_distinguisher(peer->bgp, AFI_UNSPEC, peer_type, &peer_distinguisher)) { zlog_warn("skipping bmp message for peer %s: can't get peer distinguisher", diff --git a/tests/topotests/bgp_bmp/bgpbmp.py b/tests/topotests/bgp_bmp/bgpbmp.py index 0a0a845b3ab3..4f770ebcd1d4 100644 --- a/tests/topotests/bgp_bmp/bgpbmp.py +++ b/tests/topotests/bgp_bmp/bgpbmp.py @@ -187,7 +187,7 @@ def bmp_check_for_prefixes( def bmp_check_for_peer_message( - expected_peers, bmp_log_type, bmp_collector, bmp_log_file + expected_peers, bmp_log_type, bmp_collector, bmp_log_file, is_rd_instance=False ): """ Check for the presence of a peer up message for the peer @@ -211,6 +211,8 @@ def bmp_check_for_peer_message( and m["peer_ip"] != "0.0.0.0" and m["bmp_log_type"] == bmp_log_type ): + if is_rd_instance and m["peer_type"] != "route distinguisher instance": + continue peers.append(m["peer_ip"]) elif m["policy"] == "loc-rib" and m["bmp_log_type"] == bmp_log_type: peers.append("0.0.0.0") diff --git a/tests/topotests/bgp_bmp/test_bgp_bmp_2.py b/tests/topotests/bgp_bmp/test_bgp_bmp_2.py index e8f67515bd5d..f16ff2b4458b 100644 --- a/tests/topotests/bgp_bmp/test_bgp_bmp_2.py +++ b/tests/topotests/bgp_bmp/test_bgp_bmp_2.py @@ -210,6 +210,7 @@ def test_peer_up(): "peer up", tgen.gears["bmp1vrf"], os.path.join(tgen.logdir, "bmp1vrf", "bmp.log"), + is_rd_instance=True, ) success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1) assert success, "Checking the updated prefixes has been failed !." @@ -245,6 +246,7 @@ def test_peer_down(): "peer down", tgen.gears["bmp1vrf"], os.path.join(tgen.logdir, "bmp1vrf", "bmp.log"), + is_rd_instance=True, ) success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1) assert success, "Checking the updated prefixes has been failed !." From e5596dd17326ba372953383805655bb93f06f145 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 31 Oct 2024 10:19:48 +0100 Subject: [PATCH 082/106] bgpd, topotests: bmp, fix wrong peer distinguisher value for peer vrf up/down When running the bgp_bmp_2 vrf test, peer vrf up/down events from the pre and post policy are received with a wrong peer distinguisher value. > {"peer_type": "route distinguisher instance", "policy": "pre-policy", > "ipv6": true, "peer_ip": "192:168::2", "peer_distinguisher": "0:0", > "peer_asn": 65502, "peer_bgp_id": "192.168.0.2", "timestamp": > "2024-10-16 21:59:53.111962", "bmp_log_type": "peer up", "local_ip": > "192:168::1", "local_port": 179, "remote_port": 50836, "seq": 5} RFC7854 mentions in 4.2 that if the peer is a "RD Instance Peer", it is set to the route distinguisher of the particular instance the peer belongs to. Fix this by modifying the BMP client, update the peer distinguisher value by filling the peer distinguisher in the bmp_peerstate function. > {"peer_type": "route distinguisher instance", "policy": "pre-policy", > "ipv6": true, "peer_ip": "192:168::2", "peer_distinguisher": "444:1", > "peer_asn": 65502, "peer_bgp_id": "192.168.0.2", "timestamp": > "2024-10-16 21:59:53.111962", "bmp_log_type": "peer up", "local_ip": > "192:168::1", "local_port": 179, "remote_port": 50836, "seq": 5} Add a test to check that peer_distinguisher value is not 0:0 when an RD instance is set. Signed-off-by: Philippe Guibert --- bgpd/bgp_bmp.c | 4 ++-- tests/topotests/bgp_bmp/bgpbmp.py | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index 08cfcdb37c03..677ad935582e 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -490,7 +490,7 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down) bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_PEER_UP_NOTIFICATION); - bmp_per_peer_hdr(s, peer->bgp, peer, 0, peer_type, 0, &uptime_real); + bmp_per_peer_hdr(s, peer->bgp, peer, 0, peer_type, peer_distinguisher, &uptime_real); /* Local Address (16 bytes) */ if (is_locrib) @@ -552,7 +552,7 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down) bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_PEER_DOWN_NOTIFICATION); - bmp_per_peer_hdr(s, peer->bgp, peer, 0, peer_type, 0, &uptime_real); + bmp_per_peer_hdr(s, peer->bgp, peer, 0, peer_type, peer_distinguisher, &uptime_real); type_pos = stream_get_endp(s); stream_putc(s, 0); /* placeholder for down reason */ diff --git a/tests/topotests/bgp_bmp/bgpbmp.py b/tests/topotests/bgp_bmp/bgpbmp.py index 4f770ebcd1d4..eac78a63f767 100644 --- a/tests/topotests/bgp_bmp/bgpbmp.py +++ b/tests/topotests/bgp_bmp/bgpbmp.py @@ -206,6 +206,8 @@ def bmp_check_for_peer_message( # get the list of pairs (prefix, policy, seq) for the given message type peers = [] for m in messages: + if is_rd_instance and m["peer_distinguisher"] == "0:0": + continue if ( "peer_ip" in m.keys() and m["peer_ip"] != "0.0.0.0" From b1f199dd8f3572fd781ce8ce03784a5787c2cd27 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 23 Sep 2024 16:03:13 +0200 Subject: [PATCH 083/106] bgpd: bmp, add peer type and distinguisher support for stat messages Signed-off-by: Philippe Guibert --- bgpd/bgp_bmp.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index 677ad935582e..3a4364c5f997 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -1733,6 +1733,8 @@ static void bmp_stats(struct event *thread) struct peer *peer; struct listnode *node; struct timeval tv; + uint8_t peer_type_flag; + uint64_t peer_distinguisher = 0; if (bt->stat_msec) event_add_timer_msec(bm->master, bmp_stats, bt, bt->stat_msec, @@ -1749,8 +1751,14 @@ static void bmp_stats(struct event *thread) s = stream_new(BGP_MAX_PACKET_SIZE); bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_STATISTICS_REPORT); - bmp_per_peer_hdr(s, bt->bgp, peer, 0, - BMP_PEER_TYPE_GLOBAL_INSTANCE, 0, &tv); + peer_type_flag = bmp_get_peer_type(peer); + if (bmp_get_peer_distinguisher(peer->bgp, AFI_UNSPEC, peer_type_flag, + &peer_distinguisher)) { + zlog_warn("skipping bmp message for peer %s: can't get peer distinguisher", + peer->host); + continue; + } + bmp_per_peer_hdr(s, bt->bgp, peer, 0, peer_type_flag, peer_distinguisher, &tv); count_pos = stream_get_endp(s); stream_putl(s, 0); From 07fbbb834c78b50fb9d9959cbe4724eef8666781 Mon Sep 17 00:00:00 2001 From: vivek Date: Tue, 9 Jun 2020 22:15:33 -0700 Subject: [PATCH 084/106] zebra: Reset MAC's remote sequence number appropriately When a MAC gets deleted but associated neighbors remain, the MAC is kept in the zebra MAC database as an internal ("auto") entry. When this happens, reset the MAC's remote sequence number. This ensures that when the host with the MAC later comes up behind a remote VTEP, the local switch accepts the MAC and installs it into the bridge FDB and we don't end up in a situation where remote MACs are not installed into the bridge FDB. This fix is a corollary of CM-22753 and is this time done for local MACs upon delete. Note: Commit is marked Cumulus-only because I need to evalute more comprehensive changes before upstreaming it. Ticket: CM-29581 Reviewed By: As above Testing Done: 1. Multiple rounds of manual testing 2. Two rounds of evpn-smoke, 1 round of precommit Signed-off-by: Vivek Venkatraman Acked-by: Chirag Shah Acked-by: Anuradha Karuppiah --- zebra/zebra_evpn_mac.c | 2 ++ zebra/zebra_vxlan.c | 1 + 2 files changed, 3 insertions(+) diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c index 0d53591336f8..f9009dabb75b 100644 --- a/zebra/zebra_evpn_mac.c +++ b/zebra/zebra_evpn_mac.c @@ -1152,6 +1152,7 @@ int zebra_evpn_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac) listcount(mac->neigh_list)); SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); + mac->rem_seq = 0; return 0; } @@ -2411,6 +2412,7 @@ int zebra_evpn_del_local_mac(struct zebra_evpn *zevpn, struct zebra_mac *mac, UNSET_FLAG(mac->flags, ZEBRA_MAC_ALL_LOCAL_FLAGS); UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY); SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); + mac->rem_seq = 0; } return 0; diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index ad112a4ab1f4..bc4f34389836 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -4403,6 +4403,7 @@ static int zebra_vxlan_check_del_local_mac(struct interface *ifp, UNSET_FLAG(mac->flags, ZEBRA_MAC_ALL_LOCAL_FLAGS); UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY); SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); + mac->rem_seq = 0; } return 0; From 29a0680ca945f7d954148fbbe680500a98bd4c35 Mon Sep 17 00:00:00 2001 From: vivek Date: Wed, 9 Jun 2021 13:56:22 -0700 Subject: [PATCH 085/106] bgpd: Check L3VNI status before announcing default Check that the L3VNI is "up" before taking action to announce or withdraw the EVPN type-5 default based on configuration. Otherwise, there can be timing conditions where a EVPN type-5 default route gets announced without a VNI and with invalid route targets. Signed-off-by: Vivek Venkatraman Ticket: #2684144 Reviewed By: Chirag Shah Testing Done: 1. Rerun failed test multiple times successfully 2. Some manual testing 3. precommit and partial evpn-smoke --- bgpd/bgp_evpn_vty.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 958a9c6492b5..338f5cefee0c 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -3469,7 +3469,9 @@ static void evpn_process_default_originate_cmd(struct bgp *bgp_vrf, BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6); } - bgp_evpn_install_uninstall_default_route(bgp_vrf, afi, safi, add); + if (is_l3vni_live(bgp_vrf)) + bgp_evpn_install_uninstall_default_route(bgp_vrf, + afi, safi, add); } /* From 880d019a30d93414e1f3a241930a52fdb5ce3c9b Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 10 Jun 2021 10:54:11 -0400 Subject: [PATCH 086/106] zebra: Reduce memory usage of streams for encoding packets For those packets that we are not sending 16k of data, but something far less than 256 bytes. Reduce those stream sizes we allocate to something much more reasonable. Signed-off-by: Donald Sharp --- zebra/zapi_msg.c | 34 ++++++++++++++++------------------ zebra/zebra_mpls.c | 2 +- zebra/zebra_mroute.c | 2 +- zebra/zebra_vxlan.c | 6 +++--- 4 files changed, 21 insertions(+), 23 deletions(-) diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 10acee9be435..d269cdd01537 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -282,7 +282,7 @@ int zsend_interface_address(int cmd, struct zserv *client, { int blen; struct prefix *p; - struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); + struct stream *s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, cmd, ifp->vrf->vrf_id); stream_putl(s, ifp->ifindex); @@ -323,7 +323,7 @@ static int zsend_interface_nbr_address(int cmd, struct zserv *client, struct nbr_connected *ifc) { int blen; - struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); + struct stream *s = stream_new(ZEBRA_SMALL_PACKET_SIZE); struct prefix *p; zclient_create_header(s, cmd, ifp->vrf->vrf_id); @@ -651,7 +651,7 @@ static int zsend_nexthop_lookup_mrib(struct zserv *client, struct ipaddr *addr, struct nexthop *nexthop; /* Get output stream. */ - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); stream_reset(s); /* Fill in result. */ @@ -706,7 +706,7 @@ int zsend_nhg_notify(uint16_t type, uint16_t instance, uint32_t session_id, zlog_debug("%s: type %d, id %d, note %s", __func__, type, id, zapi_nhg_notify_owner2str(note)); - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); stream_reset(s); zclient_create_header(s, ZEBRA_NHG_NOTIFY_OWNER, VRF_DEFAULT); @@ -835,7 +835,7 @@ void zsend_rule_notify_owner(const struct zebra_dplane_ctx *ctx, if (!client) return; - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, ZEBRA_RULE_NOTIFY_OWNER, dplane_ctx_rule_get_vrfid(ctx)); @@ -889,7 +889,7 @@ void zsend_iptable_notify_owner(const struct zebra_dplane_ctx *ctx, if (!client) return; - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, cmd, VRF_DEFAULT); stream_putw(s, note); @@ -923,7 +923,7 @@ void zsend_ipset_notify_owner(const struct zebra_dplane_ctx *ctx, if (!client) return; - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, cmd, VRF_DEFAULT); stream_putw(s, note); @@ -959,7 +959,7 @@ void zsend_ipset_entry_notify_owner(const struct zebra_dplane_ctx *ctx, if (!client) return; - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, cmd, VRF_DEFAULT); stream_putw(s, note); @@ -1049,13 +1049,12 @@ int zsend_router_id_update(struct zserv *client, afi_t afi, struct prefix *p, vrf_id_t vrf_id) { int blen; - struct stream *s; /* Check this client need interface information. */ if (!vrf_bitmap_check(&client->ridinfo[afi], vrf_id)) return 0; - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + struct stream *s = stream_new(ZEBRA_SMALL_PACKET_SIZE); /* Message type. */ zclient_create_header(s, ZEBRA_ROUTER_ID_UPDATE, vrf_id); @@ -1077,7 +1076,7 @@ int zsend_router_id_update(struct zserv *client, afi_t afi, struct prefix *p, */ int zsend_pw_update(struct zserv *client, struct zebra_pw *pw) { - struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); + struct stream *s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, ZEBRA_PW_STATUS_UPDATE, pw->vrf_id); stream_write(s, pw->ifname, IFNAMSIZ); @@ -1094,7 +1093,7 @@ int zsend_pw_update(struct zserv *client, struct zebra_pw *pw) int zsend_assign_label_chunk_response(struct zserv *client, vrf_id_t vrf_id, struct label_manager_chunk *lmc) { - struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); + struct stream *s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, ZEBRA_GET_LABEL_CHUNK, vrf_id); /* proto */ @@ -1120,7 +1119,7 @@ int zsend_assign_label_chunk_response(struct zserv *client, vrf_id_t vrf_id, int zsend_label_manager_connect_response(struct zserv *client, vrf_id_t vrf_id, unsigned short result) { - struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); + struct stream *s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, ZEBRA_LABEL_MANAGER_CONNECT, vrf_id); @@ -1144,7 +1143,7 @@ static int zsend_assign_table_chunk_response(struct zserv *client, vrf_id_t vrf_id, struct table_manager_chunk *tmc) { - struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); + struct stream *s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, ZEBRA_GET_TABLE_CHUNK, vrf_id); @@ -1164,7 +1163,7 @@ static int zsend_table_manager_connect_response(struct zserv *client, vrf_id_t vrf_id, uint16_t result) { - struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); + struct stream *s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, ZEBRA_TABLE_MANAGER_CONNECT, vrf_id); @@ -2406,7 +2405,7 @@ static void zread_router_id_delete(ZAPI_HANDLER_ARGS) static void zsend_capabilities(struct zserv *client, struct zebra_vrf *zvrf) { - struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); + struct stream *s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, ZEBRA_CAPABILITIES, zvrf->vrf->vrf_id); stream_putl(s, vrf_get_backend()); @@ -3990,8 +3989,7 @@ static inline void zebra_gre_source_set(ZAPI_HANDLER_ARGS) static void zsend_error_msg(struct zserv *client, enum zebra_error_types error, struct zmsghdr *bad_hdr) { - - struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); + struct stream *s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, ZEBRA_ERROR, bad_hdr->vrf_id); diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index 0d3fd2a7268f..3325532ca920 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -466,7 +466,7 @@ static int fec_send(struct zebra_fec *fec, struct zserv *client) rn = fec->rn; /* Get output stream. */ - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, ZEBRA_FEC_UPDATE, VRF_DEFAULT); diff --git a/zebra/zebra_mroute.c b/zebra/zebra_mroute.c index 881b681c2f6d..86e25469ba2d 100644 --- a/zebra/zebra_mroute.c +++ b/zebra/zebra_mroute.c @@ -61,7 +61,7 @@ void zebra_ipmr_route_stats(ZAPI_HANDLER_ARGS) suc = kernel_get_ipmr_sg_stats(zvrf, &mroute); stream_failure: - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); stream_reset(s); diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index bc4f34389836..c60eeab94671 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -2203,7 +2203,7 @@ static int zl3vni_send_add_to_client(struct zebra_l3vni *zl3vni) is_anycast_mac = false; } - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); /* The message is used for both vni add and/or update like * vrr mac is added for l3vni SVI. @@ -2246,7 +2246,7 @@ static int zl3vni_send_del_to_client(struct zebra_l3vni *zl3vni) if (!client) return 0; - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, ZEBRA_L3VNI_DEL, zl3vni_vrf_id(zl3vni)); stream_putl(s, zl3vni->vni); @@ -5861,7 +5861,7 @@ static int zebra_vxlan_sg_send(struct zebra_vrf *zvrf, if (!CHECK_FLAG(zvrf->flags, ZEBRA_PIM_SEND_VXLAN_SG)) return 0; - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, cmd, VRF_DEFAULT); stream_putl(s, IPV4_MAX_BYTELEN); From 1dac8010bb6c0fdcac8269f5a1e2559626f26da1 Mon Sep 17 00:00:00 2001 From: Anuradha Karuppiah Date: Fri, 18 Jun 2021 08:38:54 -0700 Subject: [PATCH 087/106] pimd: skip init of mlag roles based on the zebra capabilities message Looks like the cap setting was added for testing mlag via zebra test cli to config the mlag role. However it is interfering with the valid state updates rxed from the MLAG daemon based on timing (in some cases the MLAG state changes are rxed before the capabilities). Reference logs - >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> root@TORC11:mgmt:/home/cumulus# grep -ri "my_role\|MlagRole" /var/log/frr/bgpd.log 2021/06/18 13:26:40.380130 PIM: pim_mlag_process_mlagd_state_change: msg dump: my_role: SECONDARY, peer_state: DOWN 2021/06/18 13:26:40.380766 PIM: pim_mlag_process_mlagd_state_change: msg dump: my_role: SECONDARY, peer_state: DOWN 2021/06/18 13:26:41.382258 PIM: pim_mlag_process_mlagd_state_change: msg dump: my_role: SECONDARY, peer_state: RUNNING 2021/06/18 13:26:41.382379 PIM: pim_mlag_process_mlagd_state_change: msg dump: my_role: PRIMARY, peer_state: RUNNING 2021/06/18 13:26:52.386071 ZEBRA: Sending capabilities to client pim: MPLS enabled numMultipath 128 GR disabled MaintMode off MlagRole 0 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Ticket: #2691629 Signed-off-by: Anuradha Karuppiah --- pimd/pim_zebra.c | 1 - 1 file changed, 1 deletion(-) diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index ce4d85a2c848..f0ec3c6b6e82 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -426,7 +426,6 @@ static void pim_zebra_connected(struct zclient *zclient) static void pim_zebra_capabilities(struct zclient_capabilities *cap) { - router->mlag_role = cap->role; router->multipath = cap->ecmp; } From c90c58fba98ddb3b4bf6a14ac814a26e4253bad3 Mon Sep 17 00:00:00 2001 From: Wesley Coakley Date: Wed, 28 Jul 2021 21:37:44 -0400 Subject: [PATCH 088/106] pbrd: fix vrf_unchanged which may depend on other seqs Ticket: 2740911 Signed-off-by: Wesley Coakley --- pbrd/pbr_map.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pbrd/pbr_map.c b/pbrd/pbr_map.c index 8f7a46377c86..ea0e2e4eaf10 100644 --- a/pbrd/pbr_map.c +++ b/pbrd/pbr_map.c @@ -732,6 +732,14 @@ void pbr_map_schedule_policy_from_nhg(const char *nh_group, bool installed) pbr_map_check(pbrms, false); } + + /* + * vrf_unchanged pbrms have no nhg but their + * installation is contingent on other sequences which + * may... + */ + if (pbrms->vrf_unchanged) + pbr_map_check(pbrms, false); } } } From 396bc3e259c493520352220441be9cfe6207d92f Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Wed, 11 Aug 2021 14:11:02 -0400 Subject: [PATCH 089/106] watchfrr: increase restart timer 20s -> 90s This commit: "tools: run `vtysh -b` once for all-startup" changed things so that `vtysh -b` is run after all daemons have started up instead of doing it for each daemon as they are started up. This results in one long `vtysh -b`, which for large configs and many daemons (in the case I saw, 4 daemons and 30,000 line config) can exceed the 20 second timer watchfrr uses to kill "hung" background tasks. Shouldn't be any harm to increasing this to 90 seconds to give us some leeway while still making sure we kill anything truly misbehaving. Signed-off-by: Quentin Young --- watchfrr/watchfrr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/watchfrr/watchfrr.c b/watchfrr/watchfrr.c index acc612c0a858..611a7872d013 100644 --- a/watchfrr/watchfrr.c +++ b/watchfrr/watchfrr.c @@ -44,7 +44,7 @@ #define DEFAULT_PERIOD 5 #define DEFAULT_TIMEOUT 90 -#define DEFAULT_RESTART_TIMEOUT 20 +#define DEFAULT_RESTART_TIMEOUT 90 #define DEFAULT_LOGLEVEL LOG_INFO #define DEFAULT_MIN_RESTART 60 #define DEFAULT_MAX_RESTART 600 From 1b8b7478ab74b454fd97c17145dd4e7c870bd652 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 18 Oct 2021 13:49:35 -0400 Subject: [PATCH 090/106] zebra: Fix another ships in the night issue with WFI Effectively When bgp would send a route update down to zebra and immediately after that a asic update from the kernel was read. Zebra would choose the asic update and drop the bgp update leaving us in a state where bgp was not used as the true source. Modify the code so that in rib_multipath_nhe we notice that we have an unprocessed route update from bgp. And if so just drop this kernel update about an older version of the route since it is no longer needed. Ticket: 2722533 Signed-off-by: Donald Sharp --- zebra/zebra_rib.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 574083ae0283..11d279d8c9c1 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2838,6 +2838,8 @@ static void process_subq_early_route_add(struct zebra_early_route *ere) if (!ere->startup && (re->flags & ZEBRA_FLAG_SELFROUTE) && zrouter.asic_offloaded) { + struct route_entry *entry; + if (!same) { if (IS_ZEBRA_DEBUG_RIB) zlog_debug( @@ -2854,6 +2856,25 @@ static void process_subq_early_route_add(struct zebra_early_route *ere) early_route_memory_free(ere); return; } + + RNODE_FOREACH_RE (rn, entry) { + if (CHECK_FLAG(entry->status, ROUTE_ENTRY_REMOVED)) + continue; + + if (entry->type != ere->re->type) + continue; + + /* + * If we have an entry that is changed but un + * processed and not a self route, then + * we should just drop this new self route + */ + if (CHECK_FLAG(entry->status, ROUTE_ENTRY_CHANGED) && + !(entry->flags & ZEBRA_FLAG_SELFROUTE)) { + early_route_memory_free(ere); + return; + } + } } /* Set default distance by route type. */ From a2ee9db0ab6c373551be9b221ca633fbbbdfbe1b Mon Sep 17 00:00:00 2001 From: Trey Aspelund Date: Fri, 5 Nov 2021 11:47:57 -0400 Subject: [PATCH 091/106] bgpd: only import specific route-types into EVIs Prior to this we were only filtering EVPN routes from the import logic if they were not route-type 1/2/3/5, which allowed things like RT-5s to be imported into an L2VNI/MAC-VRF. This adds additional logic to ensure routes are only imported into EVIs where they make sense. No more nonsensical route importing! Ticket: 2848204 Signed-off-by: Trey Aspelund --- bgpd/bgp_evpn.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index f173bd01f20f..5617f0d009f2 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -4212,9 +4212,7 @@ static int bgp_evpn_install_uninstall_table(struct bgp *bgp, afi_t afi, assert(attr); - /* Only type-1, type-2, type-3, type-4 and type-5 - * are supported currently - */ + /* Only EVPN route-types 1-5 are supported currently */ if (!(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE || evp->prefix.route_type == BGP_EVPN_IMET_ROUTE || evp->prefix.route_type == BGP_EVPN_ES_ROUTE @@ -4271,26 +4269,28 @@ static int bgp_evpn_install_uninstall_table(struct bgp *bgp, afi_t afi, bgp_evpn_attr_get_esi(pi->attr)); /* - * macip routes (type-2) are imported into VNI and VRF tables. - * IMET route is imported into VNI table. - * prefix routes are imported into VRF table. + * AD/IMET routes (type-1/3) are imported into VNI table. + * MACIP routes (type-2) are imported into VNI and VRF tables. + * Prefix routes (type 5) are imported into VRF table. */ if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE || evp->prefix.route_type == BGP_EVPN_IMET_ROUTE || evp->prefix.route_type == BGP_EVPN_AD_ROUTE || evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE) { + if (evp->prefix.route_type != BGP_EVPN_IP_PREFIX_ROUTE) { + irt = in_vni_rt ? lookup_import_rt(bgp, eval) : NULL; + if (irt) + install_uninstall_route_in_vnis(bgp, afi, safi, evp, pi, + irt->vnis, import); + } - irt = in_vni_rt ? lookup_import_rt(bgp, eval) : NULL; - if (irt) - install_uninstall_route_in_vnis( - bgp, afi, safi, evp, pi, irt->vnis, - import); - - vrf_irt = in_vrf_rt ? lookup_vrf_import_rt(eval) : NULL; - if (vrf_irt) - install_uninstall_route_in_vrfs( - bgp, afi, safi, evp, pi, vrf_irt->vrfs, - import); + if (evp->prefix.route_type != BGP_EVPN_AD_ROUTE && + evp->prefix.route_type != BGP_EVPN_IMET_ROUTE) { + vrf_irt = in_vrf_rt ? lookup_vrf_import_rt(eval) : NULL; + if (vrf_irt) + install_uninstall_route_in_vrfs(bgp, afi, safi, evp, pi, + vrf_irt->vrfs, import); + } /* Also check for non-exact match. * In this, we mask out the AS and From bb5632bd6ab2a7be21268de9bec6387f3d7a76c5 Mon Sep 17 00:00:00 2001 From: Chirag Shah Date: Wed, 26 Jan 2022 15:48:44 -0800 Subject: [PATCH 092/106] bgpd: copy asn of src vrf to evpn type5 route When a unicast route from source vrf is imported into evpn as type5 route, prepend the asn of the source vrf into type5 asn path list. The condition of evpn type5 prefix path info is present but source vrf route has been cleared via clear command. In this case existing path info needs to rewrite the source vrf asn. prepends asn of the source vrf, but the further condition for existing path attribute for the same route needs to prepend source vrf asn. Ticket: #2943080 Testing: Before fix: r4# clear ip bgp vrf overlay prefix 0.0.0.0/0 Route Distinguisher: 128.117.243.209:4 *> [5]:[0]:[0]:[0.0.0.0] 203.0.113.1 0 0 194 ? <--- 64512 is missing ET:8 RT:64532:104001 Rmac:06:ec:bf:59:e8:93 After fix: r4# clear ip bgp vrf overlay prefix 0.0.0.0/0 Route's source vrf bgp output containing ASN 64512: r4# show bgp vrf overlay BGP table version is 2, local router ID is 128.117.243.209, vrf id 10 Default local pref 100, local AS 64512 ... Notice after clear command source vrf asn 64512 is retained. Route Distinguisher: 128.117.243.209:4 *> [5]:[0]:[0]:[0.0.0.0] 203.0.113.1 0 0 64512 194 ? ET:8 RT:64532:104001 Rmac:06:ec:bf:59:e8:93 Signed-off-by: Chirag Shah --- bgpd/bgp_evpn.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 5617f0d009f2..204c95022cc9 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1669,9 +1669,18 @@ static int update_evpn_type5_route_entry(struct bgp *bgp_evpn, /* attribute changed */ *route_changed = 1; + /* if the asn values are different, copy the asn of + * source vrf to the target (evpn) vrf entry. + */ + if (bgp_vrf->as != bgp_evpn->as) { + new_aspath = aspath_dup(static_attr.aspath); + new_aspath = aspath_add_seq(new_aspath, bgp_vrf->as); + static_attr.aspath = new_aspath; + } /* The attribute has changed. */ /* Add (or update) attribute to hash. */ - attr_new = bgp_attr_intern(attr); + attr_new = bgp_attr_intern(&static_attr); + bgp_attr_flush(&static_attr); bgp_path_info_set_flag(dest, tmp_pi, BGP_PATH_ATTR_CHANGED); From 3e2a0f38a501390c2ba3f04f4f506028f201ada1 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 11 Dec 2024 18:13:49 +0200 Subject: [PATCH 093/106] bgpd: Show which prefix is suppressed if debug out is enabled Signed-off-by: Donatas Abraitis --- bgpd/bgp_updgrp_adv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index 1a66df59fc20..ae741a4809e9 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -582,7 +582,7 @@ bool bgp_adj_out_set_subgroup(struct bgp_dest *dest, bgp_dump_attr(attr, attr_str, sizeof(attr_str)); - zlog_debug("%s suppress UPDATE w/ attr: %s", peer->host, + zlog_debug("%s suppress UPDATE %pBD w/ attr: %s", peer->host, dest, attr_str); } From 8f2f7f6077ffbf57b5139d20226dbf201c7eb6e0 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 11 Dec 2024 11:43:48 -0500 Subject: [PATCH 094/106] zebra: Remove tests for allocation failure This cannot happen. No need to test Signed-off-by: Donald Sharp --- zebra/zebra_rib.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 11d279d8c9c1..e64a620f0030 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -3767,10 +3767,8 @@ static struct meta_queue *meta_queue_new(void) new = XCALLOC(MTYPE_WORK_QUEUE, sizeof(struct meta_queue)); - for (i = 0; i < MQ_SIZE; i++) { + for (i = 0; i < MQ_SIZE; i++) new->subq[i] = list_new(); - assert(new->subq[i]); - } return new; } @@ -3956,12 +3954,7 @@ void meta_queue_free(struct meta_queue *mq, struct zebra_vrf *zvrf) /* initialise zebra rib work queue */ static void rib_queue_init(void) { - 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; - } + zrouter.ribq = work_queue_new(zrouter.master, "route_node processing"); /* fill in the work queue spec */ zrouter.ribq->spec.workfunc = &meta_queue_process; @@ -3971,11 +3964,8 @@ static void rib_queue_init(void) zrouter.ribq->spec.hold = ZEBRA_RIB_PROCESS_HOLD_TIME; zrouter.ribq->spec.retry = ZEBRA_RIB_PROCESS_RETRY_TIME; - if (!(zrouter.mq = meta_queue_new())) { - flog_err(EC_ZEBRA_WQ_NONEXISTENT, - "%s: could not initialise meta queue!", __func__); - return; - } + zrouter.mq = meta_queue_new(); + return; } From f8ba744d0fb0e430cacf06042a0053aa04c5d8f6 Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Wed, 11 Dec 2024 11:44:40 -0300 Subject: [PATCH 095/106] pim6d: ignore more MSDP callbacks PIMv6 does not implement MSDP, users should use PIMv6 embedded RP instead. Signed-off-by: Rafael Zalamena --- pimd/pim_nb_config.c | 54 +++++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index 4f79a890df17..fb7047aa4983 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -1008,6 +1008,38 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ss return NB_OK; } +pim6_msdp_err(pim_msdp_hold_time_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_keep_alive_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_connection_retry_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_mesh_group_destroy, nb_cb_destroy_args); +pim6_msdp_err(pim_msdp_mesh_group_create, nb_cb_create_args); +pim6_msdp_err(pim_msdp_mesh_group_source_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_mesh_group_source_destroy, nb_cb_destroy_args); +pim6_msdp_err(pim_msdp_mesh_group_members_create, nb_cb_create_args); +pim6_msdp_err(pim_msdp_mesh_group_members_destroy, nb_cb_destroy_args); +pim6_msdp_err(pim_msdp_peer_sa_filter_in_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_peer_sa_filter_in_destroy, nb_cb_destroy_args); +pim6_msdp_err(pim_msdp_peer_sa_filter_out_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_peer_sa_filter_out_destroy, nb_cb_destroy_args); +pim6_msdp_err(pim_msdp_peer_sa_limit_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_peer_sa_limit_destroy, nb_cb_destroy_args); +pim6_msdp_err( + routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_modify, + nb_cb_modify_args); +pim6_msdp_err( + routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_destroy, + nb_cb_destroy_args); +pim6_msdp_err( + routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_create, + nb_cb_create_args); +pim6_msdp_err(pim_msdp_peer_authentication_type_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_peer_authentication_key_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_peer_authentication_key_destroy, nb_cb_destroy_args); +pim6_msdp_err(pim_msdp_log_neighbor_events_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_log_sa_events_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_shutdown_modify, nb_cb_modify_args); + +#if PIM_IPV != 6 /* * XPath: * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp/hold-time @@ -1081,26 +1113,6 @@ int pim_msdp_connection_retry_modify(struct nb_cb_modify_args *args) return NB_OK; } -pim6_msdp_err(pim_msdp_mesh_group_destroy, nb_cb_destroy_args); -pim6_msdp_err(pim_msdp_mesh_group_create, nb_cb_create_args); -pim6_msdp_err(pim_msdp_mesh_group_source_modify, nb_cb_modify_args); -pim6_msdp_err(pim_msdp_mesh_group_source_destroy, nb_cb_destroy_args); -pim6_msdp_err(pim_msdp_mesh_group_members_create, nb_cb_create_args); -pim6_msdp_err(pim_msdp_mesh_group_members_destroy, nb_cb_destroy_args); -pim6_msdp_err(routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_modify, - nb_cb_modify_args); -pim6_msdp_err(routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_destroy, - nb_cb_destroy_args); -pim6_msdp_err(routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_create, - nb_cb_create_args); -pim6_msdp_err(pim_msdp_peer_authentication_type_modify, nb_cb_modify_args); -pim6_msdp_err(pim_msdp_peer_authentication_key_modify, nb_cb_modify_args); -pim6_msdp_err(pim_msdp_peer_authentication_key_destroy, nb_cb_destroy_args); -pim6_msdp_err(pim_msdp_log_neighbor_events_modify, nb_cb_modify_args); -pim6_msdp_err(pim_msdp_log_sa_events_modify, nb_cb_modify_args); -pim6_msdp_err(pim_msdp_shutdown_modify, nb_cb_modify_args); - -#if PIM_IPV != 6 /* * XPath: * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp/log-neighbor-events @@ -1489,7 +1501,6 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms return NB_OK; } -#endif /* PIM_IPV != 6 */ /* * XPath: @@ -1620,6 +1631,7 @@ int pim_msdp_peer_sa_limit_destroy(struct nb_cb_destroy_args *args) return NB_OK; } +#endif /* PIM_IPV != 6 */ /* * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag From dcf33d022e887a2c566a9d603324976b00f38088 Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Wed, 11 Dec 2024 11:49:46 -0300 Subject: [PATCH 096/106] pimd: move MSDP configuration and initialization Reorganize the MSDP initialization code and configuration writing code to its appropriated place. Signed-off-by: Rafael Zalamena --- pimd/pim_instance.c | 5 ----- pimd/pim_msdp.c | 19 ++++++++++++++++--- pimd/pim_vty.c | 13 ++----------- 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/pimd/pim_instance.c b/pimd/pim_instance.c index 4e4e5a6ce8f9..9a76b5c92496 100644 --- a/pimd/pim_instance.c +++ b/pimd/pim_instance.c @@ -126,11 +126,6 @@ static struct pim_instance *pim_instance_init(struct vrf *vrf) if (pim->reg_sock < 0) assert(0); - /* MSDP global timer defaults. */ - pim->msdp.hold_time = PIM_MSDP_PEER_HOLD_TIME; - pim->msdp.keep_alive = PIM_MSDP_PEER_KA_TIME; - pim->msdp.connection_retry = PIM_MSDP_PEER_CONNECT_RETRY_TIME; - #if PIM_IPV == 4 pim_autorp_init(pim); #endif diff --git a/pimd/pim_msdp.c b/pimd/pim_msdp.c index bd86ca502d50..1a1e1b723707 100644 --- a/pimd/pim_msdp.c +++ b/pimd/pim_msdp.c @@ -1272,10 +1272,21 @@ int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty) char src_str[INET_ADDRSTRLEN]; int count = 0; + if (pim->msdp.hold_time != PIM_MSDP_PEER_HOLD_TIME || + pim->msdp.keep_alive != PIM_MSDP_PEER_KA_TIME || + pim->msdp.connection_retry != PIM_MSDP_PEER_CONNECT_RETRY_TIME) { + vty_out(vty, " msdp timers %u %u", pim->msdp.hold_time, pim->msdp.keep_alive); + if (pim->msdp.connection_retry != PIM_MSDP_PEER_CONNECT_RETRY_TIME) + vty_out(vty, " %u", pim->msdp.connection_retry); + vty_out(vty, "\n"); + } + if (pim_msdp_log_neighbor_events(pim)) vty_out(vty, " msdp log neighbor-events\n"); if (pim_msdp_log_sa_events(pim)) vty_out(vty, " msdp log sa-events\n"); + if (pim->msdp.shutdown) + vty_out(vty, " msdp shutdown\n"); if (SLIST_EMPTY(&pim->msdp.mglist)) return count; @@ -1331,9 +1342,6 @@ bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim) written = true; } - if (pim->msdp.shutdown) - vty_out(vty, " msdp shutdown\n"); - return written; } @@ -1373,6 +1381,11 @@ void pim_msdp_init(struct pim_instance *pim, struct event_loop *master) pim->msdp.sa_list = list_new(); pim->msdp.sa_list->del = (void (*)(void *))pim_msdp_sa_free; pim->msdp.sa_list->cmp = (int (*)(void *, void *))pim_msdp_sa_comp; + + /* MSDP global timer defaults. */ + pim->msdp.hold_time = PIM_MSDP_PEER_HOLD_TIME; + pim->msdp.keep_alive = PIM_MSDP_PEER_KA_TIME; + pim->msdp.connection_retry = PIM_MSDP_PEER_CONNECT_RETRY_TIME; } /* counterpart to MSDP init; XXX: unused currently */ diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index 4c3762b2edfa..fc9781b239c5 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -180,8 +180,10 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty) int writes = 0; struct pim_ssm *ssm = pim->ssm_info; +#if PIM_IPV == 4 writes += pim_msdp_peer_config_write(vty, pim); writes += pim_msdp_config_write(pim, vty); +#endif /* PIM_IPV == 4 */ if (!pim->send_v6_secondary) { vty_out(vty, " no send-v6-secondary\n"); @@ -273,17 +275,6 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty) } } - if (pim->msdp.hold_time != PIM_MSDP_PEER_HOLD_TIME - || pim->msdp.keep_alive != PIM_MSDP_PEER_KA_TIME - || pim->msdp.connection_retry != PIM_MSDP_PEER_CONNECT_RETRY_TIME) { - vty_out(vty, " msdp timers %u %u", pim->msdp.hold_time, - pim->msdp.keep_alive); - if (pim->msdp.connection_retry - != PIM_MSDP_PEER_CONNECT_RETRY_TIME) - vty_out(vty, " %u", pim->msdp.connection_retry); - vty_out(vty, "\n"); - } - return writes; } From c9d6ea75e55948dae6fad5c3d57c9c63dfedbe8a Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Wed, 11 Dec 2024 11:53:36 -0300 Subject: [PATCH 097/106] pimd: move all MSDP code to its own place Guard MSDP code to compile only on IPv4 and remove all MSDP code from PIMv6. Signed-off-by: Rafael Zalamena --- pimd/pim_instance.c | 4 ++++ pimd/pim_instance.h | 5 ++--- pimd/pim_msdp.c | 21 ++++++++++++++++-- pimd/pim_msdp.h | 54 ++++----------------------------------------- pimd/pim_register.c | 3 +++ pimd/pim_rp.c | 6 +++++ pimd/pim_upstream.c | 35 ++++++++++++++--------------- pimd/pim_upstream.h | 1 - 8 files changed, 54 insertions(+), 75 deletions(-) diff --git a/pimd/pim_instance.c b/pimd/pim_instance.c index 9a76b5c92496..5649e49835f9 100644 --- a/pimd/pim_instance.c +++ b/pimd/pim_instance.c @@ -53,7 +53,9 @@ static void pim_instance_terminate(struct pim_instance *pim) pim_oil_terminate(pim); +#if PIM_IPV == 4 pim_msdp_exit(pim); +#endif /* PIM_IPV == 4 */ close(pim->reg_sock); @@ -91,7 +93,9 @@ static struct pim_instance *pim_instance_init(struct vrf *vrf) pim->spt.switchover = PIM_SPT_IMMEDIATE; pim->spt.plist = NULL; +#if PIM_IPV == 4 pim_msdp_init(pim, router->master); +#endif /* PIM_IPV == 4 */ pim_vxlan_init(pim); snprintf(hash_name, sizeof(hash_name), "PIM %s RPF Hash", vrf->name); diff --git a/pimd/pim_instance.h b/pimd/pim_instance.h index dab7ed269828..93acb5e9fd6b 100644 --- a/pimd/pim_instance.h +++ b/pimd/pim_instance.h @@ -150,7 +150,9 @@ struct pim_instance { struct rb_pim_oil_head channel_oil_head; +#if PIM_IPV == 4 struct pim_msdp msdp; +#endif /* PIM_IPV == 4 */ struct pim_vxlan_instance vxlan; struct pim_autorp *autorp; @@ -225,7 +227,4 @@ extern struct pim_router *router; struct pim_instance *pim_get_pim_instance(vrf_id_t vrf_id); -extern bool pim_msdp_log_neighbor_events(const struct pim_instance *pim); -extern bool pim_msdp_log_sa_events(const struct pim_instance *pim); - #endif diff --git a/pimd/pim_msdp.c b/pimd/pim_msdp.c index 1a1e1b723707..f5260c68cab5 100644 --- a/pimd/pim_msdp.c +++ b/pimd/pim_msdp.c @@ -31,8 +31,6 @@ #include "pim_msdp_packet.h" #include "pim_msdp_socket.h" -// struct pim_msdp pim_msdp, *msdp = &pim_msdp; - static void pim_msdp_peer_listen(struct pim_msdp_peer *mp); static void pim_msdp_peer_cr_timer_setup(struct pim_msdp_peer *mp, bool start); static void pim_msdp_peer_ka_timer_setup(struct pim_msdp_peer *mp, bool start); @@ -1468,6 +1466,25 @@ struct pim_msdp_mg_mbr *pim_msdp_mg_mbr_add(struct pim_instance *pim, return mbr; } +/* MSDP on RP needs to know if a source is registerable to this RP */ +static void pim_upstream_msdp_reg_timer(struct event *t) +{ + struct pim_upstream *up = EVENT_ARG(t); + struct pim_instance *pim = up->channel_oil->pim; + + /* source is no longer active - pull the SA from MSDP's cache */ + pim_msdp_sa_local_del(pim, &up->sg); +} + +void pim_upstream_msdp_reg_timer_start(struct pim_upstream *up) +{ + EVENT_OFF(up->t_msdp_reg_timer); + event_add_timer(router->master, pim_upstream_msdp_reg_timer, up, PIM_MSDP_REG_RXED_PERIOD, + &up->t_msdp_reg_timer); + + pim_msdp_sa_local_update(up); +} + void pim_msdp_shutdown(struct pim_instance *pim, bool state) { struct pim_msdp_peer *peer; diff --git a/pimd/pim_msdp.h b/pimd/pim_msdp.h index 15ed685b3c6a..7e0e5c121825 100644 --- a/pimd/pim_msdp.h +++ b/pimd/pim_msdp.h @@ -235,8 +235,6 @@ struct pim_msdp { #define PIM_MSDP_PEER_READ_OFF(mp) event_cancel(&mp->t_read) #define PIM_MSDP_PEER_WRITE_OFF(mp) event_cancel(&mp->t_write) -#if PIM_IPV != 6 -// struct pim_msdp *msdp; struct pim_instance; void pim_msdp_init(struct pim_instance *pim, struct event_loop *master); void pim_msdp_exit(struct pim_instance *pim); @@ -263,6 +261,8 @@ void pim_msdp_up_del(struct pim_instance *pim, pim_sgaddr *sg); enum pim_msdp_err pim_msdp_mg_del(struct pim_instance *pim, const char *mesh_group_name); +extern void pim_upstream_msdp_reg_timer_start(struct pim_upstream *up); + /** * Allocates a new mesh group data structure under PIM instance. */ @@ -341,53 +341,7 @@ void pim_msdp_peer_restart(struct pim_msdp_peer *mp); */ void pim_msdp_shutdown(struct pim_instance *pim, bool state); -#else /* PIM_IPV == 6 */ -static inline void pim_msdp_init(struct pim_instance *pim, - struct event_loop *master) -{ -} - -static inline void pim_msdp_exit(struct pim_instance *pim) -{ -} - -static inline void pim_msdp_i_am_rp_changed(struct pim_instance *pim) -{ -} - -static inline void pim_msdp_up_join_state_changed(struct pim_instance *pim, - struct pim_upstream *xg_up) -{ -} - -static inline void pim_msdp_up_del(struct pim_instance *pim, pim_sgaddr *sg) -{ -} - -static inline void pim_msdp_sa_local_update(struct pim_upstream *up) -{ -} - -static inline void pim_msdp_sa_local_del(struct pim_instance *pim, - pim_sgaddr *sg) -{ -} - -static inline int pim_msdp_config_write(struct pim_instance *pim, - struct vty *vty) -{ - return 0; -} - -static inline bool pim_msdp_peer_config_write(struct vty *vty, - struct pim_instance *pim) -{ - return false; -} - -static inline void pim_msdp_shutdown(struct pim_instance *pim, bool state) -{ -} -#endif /* PIM_IPV == 6 */ +extern bool pim_msdp_log_neighbor_events(const struct pim_instance *pim); +extern bool pim_msdp_log_sa_events(const struct pim_instance *pim); #endif diff --git a/pimd/pim_register.c b/pimd/pim_register.c index b149b5a2a97c..f776a59b7fd8 100644 --- a/pimd/pim_register.c +++ b/pimd/pim_register.c @@ -709,7 +709,10 @@ int pim_register_recv(struct interface *ifp, pim_addr dest_addr, // inherited_olist(S,G,rpt) // This is taken care of by the kernel for us } + +#if PIM_IPV == 4 pim_upstream_msdp_reg_timer_start(upstream); +#endif /* PIM_IPV == 4 */ } else { if (PIM_DEBUG_PIM_REG) { if (!i_am_rp) diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index e6de991a1435..6266f42591e3 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -343,7 +343,9 @@ struct rp_info *pim_rp_find_match_group(struct pim_instance *pim, */ void pim_rp_refresh_group_to_rp_mapping(struct pim_instance *pim) { +#if PIM_IPV == 4 pim_msdp_i_am_rp_changed(pim); +#endif /* PIM_IPV == 4 */ pim_upstream_reeval_use_rpt(pim); } @@ -1030,7 +1032,9 @@ void pim_rp_check_on_if_add(struct pim_interface *pim_ifp) } if (i_am_rp_changed) { +#if PIM_IPV == 4 pim_msdp_i_am_rp_changed(pim); +#endif /* PIM_IPV == 4 */ pim_upstream_reeval_use_rpt(pim); } } @@ -1072,7 +1076,9 @@ void pim_i_am_rp_re_evaluate(struct pim_instance *pim) } if (i_am_rp_changed) { +#if PIM_IPV == 4 pim_msdp_i_am_rp_changed(pim); +#endif /* PIM_IPV == 4 */ pim_upstream_reeval_use_rpt(pim); } } diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index 7417f311377f..8aa61b687dbc 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -178,7 +178,9 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim, { struct listnode *node, *nnode; struct pim_ifchannel *ch; +#if PIM_IPV == 4 bool notify_msdp = false; +#endif /* PIM_IPV == 4 */ if (PIM_DEBUG_PIM_TRACE) zlog_debug( @@ -206,12 +208,14 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim, if (up->join_state == PIM_UPSTREAM_JOINED) { pim_jp_agg_single_upstream_send(&up->rpf, up, 0); +#if PIM_IPV == 4 if (pim_addr_is_any(up->sg.src)) { /* if a (*, G) entry in the joined state is being * deleted we * need to notify MSDP */ notify_msdp = true; } +#endif /* PIM_IPV == 4 */ } join_timer_stop(up); @@ -221,7 +225,9 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim, if (!pim_addr_is_any(up->sg.src)) { if (pim->upstream_sg_wheel) wheel_remove_item(pim->upstream_sg_wheel, up); +#if PIM_IPV == 4 notify_msdp = true; +#endif /* PIM_IPV == 4 */ } pim_mroute_del(up->channel_oil, __func__); @@ -241,9 +247,11 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim, rb_pim_upstream_del(&pim->upstream_head, up); +#if PIM_IPV == 4 if (notify_msdp) { pim_msdp_up_del(pim, &up->sg); } +#endif /* PIM_IPV == 4 */ /* When RP gets deleted, pim_rp_del() deregister addr with Zebra NHT * and assign up->upstream_addr as INADDR_ANY. @@ -723,7 +731,9 @@ void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up, if (old_state != PIM_UPSTREAM_JOINED) { int old_fhr = PIM_UPSTREAM_FLAG_TEST_FHR(up->flags); +#if PIM_IPV == 4 pim_msdp_up_join_state_changed(pim, up); +#endif /* PIM_IPV == 4 */ if (pim_upstream_could_register(up)) { PIM_UPSTREAM_FLAG_SET_FHR(up->flags); if (!old_fhr @@ -753,8 +763,10 @@ void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up, if (!pim_addr_is_any(up->sg.src)) up->sptbit = PIM_UPSTREAM_SPTBIT_FALSE; +#if PIM_IPV == 4 if (old_state == PIM_UPSTREAM_JOINED) pim_msdp_up_join_state_changed(pim, up); +#endif /* PIM_IPV == 4 */ if (old_state != new_state) { old_use_rpt = @@ -1424,8 +1436,10 @@ struct pim_upstream *pim_upstream_keep_alive_timer_proc( */ } +#if PIM_IPV == 4 /* source is no longer active - pull the SA from MSDP's cache */ pim_msdp_sa_local_del(pim, &up->sg); +#endif /* PIM_IPV == 4 */ /* JoinDesired can change when KAT is started or stopped */ pim_upstream_update_join_desired(pim, up); @@ -1493,32 +1507,15 @@ void pim_upstream_keep_alive_timer_start(struct pim_upstream *up, uint32_t time) event_add_timer(router->master, pim_upstream_keep_alive_timer, up, time, &up->t_ka_timer); +#if PIM_IPV == 4 /* any time keepalive is started against a SG we will have to * re-evaluate our active source database */ pim_msdp_sa_local_update(up); +#endif /* PIM_IPV == 4 */ /* JoinDesired can change when KAT is started or stopped */ pim_upstream_update_join_desired(up->pim, up); } -/* MSDP on RP needs to know if a source is registerable to this RP */ -static void pim_upstream_msdp_reg_timer(struct event *t) -{ - struct pim_upstream *up = EVENT_ARG(t); - struct pim_instance *pim = up->channel_oil->pim; - - /* source is no longer active - pull the SA from MSDP's cache */ - pim_msdp_sa_local_del(pim, &up->sg); -} - -void pim_upstream_msdp_reg_timer_start(struct pim_upstream *up) -{ - EVENT_OFF(up->t_msdp_reg_timer); - event_add_timer(router->master, pim_upstream_msdp_reg_timer, up, - PIM_MSDP_REG_RXED_PERIOD, &up->t_msdp_reg_timer); - - pim_msdp_sa_local_update(up); -} - /* * 4.2.1 Last-Hop Switchover to the SPT * diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h index 8b4a35be398c..1d4b2128a8f7 100644 --- a/pimd/pim_upstream.h +++ b/pimd/pim_upstream.h @@ -350,7 +350,6 @@ int pim_upstream_inherited_olist(struct pim_instance *pim, int pim_upstream_empty_inherited_olist(struct pim_upstream *up); void pim_upstream_find_new_rpf(struct pim_instance *pim); -void pim_upstream_msdp_reg_timer_start(struct pim_upstream *up); void pim_upstream_init(struct pim_instance *pim); void pim_upstream_terminate(struct pim_instance *pim); From 78c5bb98ecd03256469c62bd3ad1eeea40b825ce Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Tue, 10 May 2022 08:23:45 -0300 Subject: [PATCH 098/106] pimd: support originator id configuration Allow user to specify the RP field for the SA messages. Signed-off-by: Rafael Zalamena --- pimd/pim_cmd.c | 19 +++++++++++++++++ pimd/pim_msdp.c | 36 ++++++++++++++++++++++++--------- pimd/pim_msdp.h | 10 +++++++++ pimd/pim_msdp_packet.c | 14 +++---------- pimd/pim_nb.c | 7 +++++++ pimd/pim_nb.h | 2 ++ pimd/pim_nb_config.c | 46 ++++++++++++++++++++++++++++++++++++++++++ yang/frr-pim.yang | 8 ++++++++ 8 files changed, 122 insertions(+), 20 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 3fabe1706c80..205f1f95ea61 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -7616,6 +7616,24 @@ DEFPY(msdp_peer_sa_limit, msdp_peer_sa_limit_cmd, return nb_cli_apply_changes(vty, "%s", xpath); } +DEFPY(msdp_originator_id, msdp_originator_id_cmd, + "[no] msdp originator-id ![A.B.C.D$originator_id]", + NO_STR + CFG_MSDP_STR + "Configure MSDP RP originator\n" + "MSDP RP originator identifier\n") +{ + char xpath_value[XPATH_MAXLEN]; + + snprintf(xpath_value, sizeof(xpath_value), "./msdp/originator-id"); + if (no) + nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL); + else + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, originator_id_str); + + return nb_cli_apply_changes(vty, NULL); +} + static void ip_msdp_show_mesh_group(struct vty *vty, struct pim_msdp_mg *mg, struct json_object *json) { @@ -9012,6 +9030,7 @@ void pim_cmd_init(void) install_element(PIM_NODE, &msdp_log_sa_changes_cmd); install_element(PIM_NODE, &msdp_shutdown_cmd); install_element(PIM_NODE, &msdp_peer_sa_limit_cmd); + install_element(PIM_NODE, &msdp_originator_id_cmd); install_element(PIM_NODE, &pim_bsr_candidate_rp_cmd); install_element(PIM_NODE, &pim_bsr_candidate_rp_group_cmd); diff --git a/pimd/pim_msdp.c b/pimd/pim_msdp.c index f5260c68cab5..b428520b894a 100644 --- a/pimd/pim_msdp.c +++ b/pimd/pim_msdp.c @@ -44,6 +44,26 @@ static void pim_msdp_sa_deref(struct pim_msdp_sa *sa, static int pim_msdp_mg_mbr_comp(const void *p1, const void *p2); static void pim_msdp_mg_mbr_free(struct pim_msdp_mg_mbr *mbr); +void pim_msdp_originator_id(struct pim_instance *pim, const struct prefix *group, + struct in_addr *originator_id) +{ + struct rp_info *rp_info; + + originator_id->s_addr = INADDR_ANY; + + /* Originator ID was configured, use it. */ + if (pim->msdp.originator_id.s_addr != INADDR_ANY) { + *originator_id = pim->msdp.originator_id; + return; + } + + rp_info = pim_rp_find_match_group(pim, group); + if (rp_info) { + *originator_id = rp_info->rp.rpf_addr; + return; + } +} + /************************ SA cache management ******************************/ /* RFC-3618:Sec-5.1 - global active source advertisement timer */ static void pim_msdp_sa_adv_timer_cb(struct event *t) @@ -354,7 +374,6 @@ void pim_msdp_sa_ref(struct pim_instance *pim, struct pim_msdp_peer *mp, pim_sgaddr *sg, struct in_addr rp) { struct pim_msdp_sa *sa; - struct rp_info *rp_info; struct prefix grp; /* Check peer SA limit. */ @@ -395,12 +414,7 @@ void pim_msdp_sa_ref(struct pim_instance *pim, struct pim_msdp_peer *mp, /* send an immediate SA update to peers */ pim_addr_to_prefix(&grp, sa->sg.grp); - rp_info = pim_rp_find_match_group(pim, &grp); - if (rp_info) { - sa->rp = rp_info->rp.rpf_addr; - } else { - sa->rp = pim->msdp.originator_id; - } + pim_msdp_originator_id(pim, &grp, &sa->rp); pim_msdp_pkt_sa_tx_one(sa); } sa->flags &= ~PIM_MSDP_SAF_STALE; @@ -1013,8 +1027,6 @@ struct pim_msdp_peer *pim_msdp_peer_add(struct pim_instance *pim, mp->peer = *peer; pim_inet4_dump("", mp->peer, mp->key_str, sizeof(mp->key_str)); mp->local = *local; - /* XXX: originator_id setting needs to move to the mesh group */ - pim->msdp.originator_id = *local; if (mesh_group_name) mp->mesh_group_name = XSTRDUP(MTYPE_PIM_MSDP_MG_NAME, mesh_group_name); @@ -1340,6 +1352,12 @@ bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim) written = true; } + if (pim->msdp.originator_id.s_addr != INADDR_ANY) + vty_out(vty, " msdp originator-id %pI4\n", &pim->msdp.originator_id); + + if (pim->msdp.shutdown) + vty_out(vty, " msdp shutdown\n"); + return written; } diff --git a/pimd/pim_msdp.h b/pimd/pim_msdp.h index 7e0e5c121825..4edb6e6166ec 100644 --- a/pimd/pim_msdp.h +++ b/pimd/pim_msdp.h @@ -341,6 +341,16 @@ void pim_msdp_peer_restart(struct pim_msdp_peer *mp); */ void pim_msdp_shutdown(struct pim_instance *pim, bool state); +/** + * Get the configured originator ID for the SA RP field or the RP for the group. + * + * \param[in] pim PIM instance that MSDP connection belongs to. + * \param[in] group Multicast group. + * \param[out] originator_id Originator output value. + */ +void pim_msdp_originator_id(struct pim_instance *pim, const struct prefix *group, + struct in_addr *originator_id); + extern bool pim_msdp_log_neighbor_events(const struct pim_instance *pim); extern bool pim_msdp_log_sa_events(const struct pim_instance *pim); diff --git a/pimd/pim_msdp_packet.c b/pimd/pim_msdp_packet.c index c858bad1adbb..8c821cb5e548 100644 --- a/pimd/pim_msdp_packet.c +++ b/pimd/pim_msdp_packet.c @@ -409,7 +409,6 @@ static void pim_msdp_pkt_sa_gen(struct pim_instance *pim, { struct listnode *sanode; struct pim_msdp_sa *sa; - struct rp_info *rp_info; struct prefix group_all; struct in_addr rp; int sa_count; @@ -420,14 +419,8 @@ static void pim_msdp_pkt_sa_gen(struct pim_instance *pim, zlog_debug(" sa gen %d", local_cnt); } - rp = pim->msdp.originator_id; - if (pim_get_all_mcast_group(&group_all)) { - rp_info = pim_rp_find_match_group(pim, &group_all); - if (rp_info) { - rp = rp_info->rp.rpf_addr; - } - } - + pim_get_all_mcast_group(&group_all); + pim_msdp_originator_id(pim, &group_all, &rp); local_cnt = pim_msdp_pkt_sa_fill_hdr(pim, local_cnt, rp); for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) { @@ -457,8 +450,7 @@ static void pim_msdp_pkt_sa_gen(struct pim_instance *pim, zlog_debug(" sa gen for remainder %d", local_cnt); } - local_cnt = pim_msdp_pkt_sa_fill_hdr( - pim, local_cnt, rp); + local_cnt = pim_msdp_pkt_sa_fill_hdr(pim, local_cnt, rp); } } diff --git a/pimd/pim_nb.c b/pimd/pim_nb.c index b5d20419dd1d..6b6c0e877949 100644 --- a/pimd/pim_nb.c +++ b/pimd/pim_nb.c @@ -141,6 +141,13 @@ const struct frr_yang_module_info frr_pim_info = { .modify = pim_msdp_log_sa_events_modify, } }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp/originator-id", + .cbs = { + .modify = pim_msdp_originator_id_modify, + .destroy = pim_msdp_originator_id_destroy, + } + }, { .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp/shutdown", .cbs = { diff --git a/pimd/pim_nb.h b/pimd/pim_nb.h index 7d30db04be0c..c50fdb2000d8 100644 --- a/pimd/pim_nb.h +++ b/pimd/pim_nb.h @@ -56,6 +56,8 @@ int pim_msdp_keep_alive_modify(struct nb_cb_modify_args *args); int pim_msdp_connection_retry_modify(struct nb_cb_modify_args *args); int pim_msdp_log_neighbor_events_modify(struct nb_cb_modify_args *args); int pim_msdp_log_sa_events_modify(struct nb_cb_modify_args *args); +int pim_msdp_originator_id_modify(struct nb_cb_modify_args *args); +int pim_msdp_originator_id_destroy(struct nb_cb_destroy_args *args); int pim_msdp_shutdown_modify(struct nb_cb_modify_args *args); int pim_msdp_mesh_group_create(struct nb_cb_create_args *args); int pim_msdp_mesh_group_destroy(struct nb_cb_destroy_args *args); diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index fb7047aa4983..30895e037773 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -1037,6 +1037,8 @@ pim6_msdp_err(pim_msdp_peer_authentication_key_modify, nb_cb_modify_args); pim6_msdp_err(pim_msdp_peer_authentication_key_destroy, nb_cb_destroy_args); pim6_msdp_err(pim_msdp_log_neighbor_events_modify, nb_cb_modify_args); pim6_msdp_err(pim_msdp_log_sa_events_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_originator_id_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_originator_id_destroy, nb_cb_destroy_args); pim6_msdp_err(pim_msdp_shutdown_modify, nb_cb_modify_args); #if PIM_IPV != 6 @@ -1171,6 +1173,50 @@ int pim_msdp_log_sa_events_modify(struct nb_cb_modify_args *args) return NB_OK; } +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp/originator-id + */ +int pim_msdp_originator_id_modify(struct nb_cb_modify_args *args) +{ + struct pim_instance *pim; + struct vrf *vrf; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + yang_dnode_get_ipv4(&pim->msdp.originator_id, args->dnode, NULL); + break; + } + + return NB_OK; +} + +int pim_msdp_originator_id_destroy(struct nb_cb_destroy_args *args) +{ + struct pim_instance *pim; + struct vrf *vrf; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + pim->msdp.originator_id.s_addr = INADDR_ANY; + break; + } + + return NB_OK; +} + /* * XPath: * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp/shutdown diff --git a/yang/frr-pim.yang b/yang/frr-pim.yang index 6e5fc3c6ce5d..5fd7e66a3b1c 100644 --- a/yang/frr-pim.yang +++ b/yang/frr-pim.yang @@ -269,6 +269,14 @@ module frr-pim { "Log all MSDP SA related events."; } + leaf originator-id { + type inet:ip-address; + description + "Configure the RP address for the SAs. + + By default the local system RP address will be used."; + } + leaf shutdown { type boolean; default false; From c7d3e199905105953aa140d32a73cee84ea51f95 Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Tue, 10 Dec 2024 16:44:08 -0300 Subject: [PATCH 099/106] topotests: topology to test MSDP originator ID Import new topology to test originator ID configuration. Signed-off-by: Rafael Zalamena --- tests/topotests/msdp_topo3/__init__.py | 0 tests/topotests/msdp_topo3/r1/frr.conf | 31 ++++ tests/topotests/msdp_topo3/r2/frr.conf | 28 +++ tests/topotests/msdp_topo3/test_msdp_topo3.py | 165 ++++++++++++++++++ 4 files changed, 224 insertions(+) create mode 100644 tests/topotests/msdp_topo3/__init__.py create mode 100644 tests/topotests/msdp_topo3/r1/frr.conf create mode 100644 tests/topotests/msdp_topo3/r2/frr.conf create mode 100644 tests/topotests/msdp_topo3/test_msdp_topo3.py diff --git a/tests/topotests/msdp_topo3/__init__.py b/tests/topotests/msdp_topo3/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/topotests/msdp_topo3/r1/frr.conf b/tests/topotests/msdp_topo3/r1/frr.conf new file mode 100644 index 000000000000..d5b10bf8a15b --- /dev/null +++ b/tests/topotests/msdp_topo3/r1/frr.conf @@ -0,0 +1,31 @@ +log commands +! +interface r1-eth0 + ip address 192.168.1.1/24 + ip pim +! +interface r1-eth1 + ip address 192.168.100.1/24 + ip igmp + ip pim passive +! +interface lo + ip address 10.254.254.1/32 + ip pim + ip pim use-source 10.254.254.1 +! +router bgp 65100 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.1.2 remote-as 65200 + ! + address-family ipv4 unicast + redistribute connected + exit-address-family +! +router pim + msdp originator-id 10.254.254.1 + msdp log sa-events + msdp peer 192.168.1.2 source 192.168.1.1 + rp 192.168.1.1 +! \ No newline at end of file diff --git a/tests/topotests/msdp_topo3/r2/frr.conf b/tests/topotests/msdp_topo3/r2/frr.conf new file mode 100644 index 000000000000..245c06187404 --- /dev/null +++ b/tests/topotests/msdp_topo3/r2/frr.conf @@ -0,0 +1,28 @@ +log commands +! +interface r2-eth0 + ip address 192.168.1.2/24 + ip pim +! +interface r2-eth1 + ip address 192.168.101.1/24 + ip igmp + ip pim passive +! +interface lo + ip address 10.254.254.2/32 +! +router bgp 65200 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.1.1 remote-as 65100 + ! + address-family ipv4 unicast + redistribute connected + exit-address-family +! +router pim + msdp log sa-events + msdp peer 192.168.1.1 source 192.168.1.2 + rp 192.168.1.2 +! \ No newline at end of file diff --git a/tests/topotests/msdp_topo3/test_msdp_topo3.py b/tests/topotests/msdp_topo3/test_msdp_topo3.py new file mode 100644 index 000000000000..9393ae7ffdde --- /dev/null +++ b/tests/topotests/msdp_topo3/test_msdp_topo3.py @@ -0,0 +1,165 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# test_msdp_topo3.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2024 by +# Network Device Education Foundation, Inc. ("NetDEF") +# + +""" +test_msdp_topo3.py: Test the FRR PIM MSDP peer. +""" + +import os +import sys +import json +from functools import partial +import re +import pytest + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest + +# Required to instantiate the topology builder class. +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +from lib.pim import McastTesterHelper + +pytestmark = [pytest.mark.bgpd, pytest.mark.pimd] + +app_helper = McastTesterHelper() + + +def build_topo(tgen): + """ + +----+ +----+ +----+ +----+ + | h1 | <-> | r1 | <-> | r2 | <-> | h2 | + +----+ +----+ +----+ +----+ + + --------------------------> + + Multicast traffic SG(192.168.100.100, 229.1.1.1) + """ + + # Create 2 routers + for routern in range(1, 3): + tgen.add_router(f"r{routern}") + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + # Create a host connected and direct at r1: + switch = tgen.add_switch("s2") + tgen.add_host("h1", "192.168.100.100/24", "via 192.168.100.1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["h1"]) + + # Create a host connected and direct at r2: + switch = tgen.add_switch("s3") + tgen.add_host("h2", "192.168.101.100/24", "via 192.168.101.1") + switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["h2"]) + + +def setup_module(mod): + "Sets up the pytest environment" + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + for _, router in router_list.items(): + router.load_frr_config(os.path.join(CWD, f"{router.name}/frr.conf")) + + # Initialize all routers. + tgen.start_router() + + app_helper.init(tgen) + + +def teardown_module(): + "Teardown the pytest environment" + tgen = get_topogen() + app_helper.cleanup() + tgen.stop_topology() + + +def test_bgp_convergence(): + "Wait for BGP protocol convergence" + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("waiting for protocols to converge") + + def expect_loopback_route(router, iptype, route, proto): + "Wait until route is present on RIB for protocol." + logger.info("waiting route {} in {}".format(route, router)) + test_func = partial( + topotest.router_json_cmp, + tgen.gears[router], + "show {} route json".format(iptype), + {route: [{"protocol": proto}]}, + ) + _, result = topotest.run_and_expect(test_func, None, count=130, wait=1) + assertmsg = '"{}" convergence failure'.format(router) + assert result is None, assertmsg + + # Wait for R1 + expect_loopback_route("r1", "ip", "10.254.254.2/32", "bgp") + + # Wait for R2 + expect_loopback_route("r2", "ip", "10.254.254.1/32", "bgp") + + +def test_sa_learn(): + """ + Test that the learned SA uses the configured originator ID instead + of the configured RP. + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + MCAST_ADDRESS = "229.1.1.1" + app_helper.run("h1", ["--send=0.7", MCAST_ADDRESS, "h1-eth0"]) + app_helper.run("h2", [MCAST_ADDRESS, "h2-eth0"]) + + test_func = partial( + topotest.router_json_cmp, + tgen.gears["r2"], + "show ip msdp sa json", + { + "229.1.1.1": { + "192.168.100.100": { + "rp": "10.254.254.1", + "local": "no", + } + } + } + ) + _, result = topotest.run_and_expect(test_func, None, count=100, wait=1) + assert result is None, 'r2 SA convergence failure' + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) From f0f2940fa6d8e2e23bd89e8938d5f96711f0212e Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Tue, 10 Dec 2024 16:49:01 -0300 Subject: [PATCH 100/106] doc: document new command MSDP originator ID Let user know about new MSDP knob to configure originator ID. Signed-off-by: Rafael Zalamena --- doc/user/pim.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/user/pim.rst b/doc/user/pim.rst index e8dd03e7c30a..322159e44a57 100644 --- a/doc/user/pim.rst +++ b/doc/user/pim.rst @@ -518,6 +518,10 @@ Commands available for MSDP To apply it immediately call `clear ip msdp peer A.B.C.D`. +.. clicmd:: msdp originator-id A.B.C.D + + Use the specified originator ID instead of the multicast RP group. + .. clicmd:: msdp shutdown Shutdown the MSDP sessions in this PIM instance. From f4af5fe3c483a219069cf6eb02dcf88b32e9d402 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 12 Dec 2024 15:08:35 -0500 Subject: [PATCH 101/106] bgpd: When calling bgp_process, prevent infinite loop If we have this construct: for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { ... bgp_process(); } This can induce an infinite loop. This happens because bgp_process will move the unsorted items to the top of the list for handling, as such it is necessary to hold the next pointer to the side to actually look at each possible bgp_path_info. Signed-off-by: Donald Sharp --- bgpd/bgp_fsm.c | 10 +++++----- bgpd/bgp_route.c | 20 ++++++++++++-------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index cadef3997423..6ad8a2e8de70 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -662,7 +662,7 @@ static void bgp_llgr_stale_timer_expire(struct event *thread) static void bgp_set_llgr_stale(struct peer *peer, afi_t afi, safi_t safi) { struct bgp_dest *dest; - struct bgp_path_info *pi; + struct bgp_path_info *pi, *next; struct bgp_table *table; struct attr attr; @@ -677,8 +677,8 @@ static void bgp_set_llgr_stale(struct peer *peer, afi_t afi, safi_t safi) for (rm = bgp_table_top(table); rm; rm = bgp_route_next(rm)) - for (pi = bgp_dest_get_bgp_path_info(rm); pi; - pi = pi->next) { + for (pi = bgp_dest_get_bgp_path_info(rm); + (pi != NULL) && (next = pi->next, 1); pi = next) { if (pi->peer != peer) continue; @@ -709,8 +709,8 @@ static void bgp_set_llgr_stale(struct peer *peer, afi_t afi, safi_t safi) } else { for (dest = bgp_table_top(peer->bgp->rib[afi][safi]); dest; dest = bgp_route_next(dest)) - for (pi = bgp_dest_get_bgp_path_info(dest); pi; - pi = pi->next) { + for (pi = bgp_dest_get_bgp_path_info(dest); + (pi != NULL) && (next = pi->next, 1); pi = next) { if (pi->peer != peer) continue; diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 55368e9ebcc9..c123c232307c 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -7410,7 +7410,7 @@ static void bgp_purge_af_static_redist_routes(struct bgp *bgp, afi_t afi, { struct bgp_table *table; struct bgp_dest *dest; - struct bgp_path_info *pi; + struct bgp_path_info *pi, *next; /* Do not install the aggregate route if BGP is in the * process of termination. @@ -7421,7 +7421,8 @@ static void bgp_purge_af_static_redist_routes(struct bgp *bgp, afi_t afi, table = bgp->rib[afi][safi]; for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) { - for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { + for (pi = bgp_dest_get_bgp_path_info(dest); (pi != NULL) && (next = pi->next, 1); + pi = next) { if (pi->peer == bgp->peer_self && ((pi->type == ZEBRA_ROUTE_BGP && pi->sub_type == BGP_ROUTE_STATIC) @@ -7921,7 +7922,7 @@ void bgp_aggregate_toggle_suppressed(struct bgp_aggregate *aggregate, struct bgp_table *table = bgp->rib[afi][safi]; const struct prefix *dest_p; struct bgp_dest *dest, *top; - struct bgp_path_info *pi; + struct bgp_path_info *pi, *next; /* We've found a different MED we must revert any suppressed routes. */ top = bgp_node_get(table, p); @@ -7931,7 +7932,8 @@ void bgp_aggregate_toggle_suppressed(struct bgp_aggregate *aggregate, if (dest_p->prefixlen <= p->prefixlen) continue; - for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { + for (pi = bgp_dest_get_bgp_path_info(dest); (pi != NULL) && (next = pi->next, 1); + pi = next) { if (BGP_PATH_HOLDDOWN(pi)) continue; if (pi->sub_type == BGP_ROUTE_AGGREGATE) @@ -8006,7 +8008,7 @@ bool bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi, struct community *community = NULL; struct ecommunity *ecommunity = NULL; struct lcommunity *lcommunity = NULL; - struct bgp_path_info *pi; + struct bgp_path_info *pi, *next; uint8_t atomic_aggregate = 0; /* If the bgp instance is being deleted or self peer is deleted @@ -8056,7 +8058,8 @@ bool bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi, if (!bgp_check_advertise(bgp, dest, safi)) continue; - for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { + for (pi = bgp_dest_get_bgp_path_info(dest); (pi != NULL) && (next = pi->next, 1); + pi = next) { if (BGP_PATH_HOLDDOWN(pi)) continue; @@ -8213,7 +8216,7 @@ void bgp_aggregate_delete(struct bgp *bgp, const struct prefix *p, afi_t afi, struct bgp_table *table; struct bgp_dest *top; struct bgp_dest *dest; - struct bgp_path_info *pi; + struct bgp_path_info *pi, *next; table = bgp->rib[afi][safi]; @@ -8226,7 +8229,8 @@ void bgp_aggregate_delete(struct bgp *bgp, const struct prefix *p, afi_t afi, if (dest_p->prefixlen <= p->prefixlen) continue; - for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { + for (pi = bgp_dest_get_bgp_path_info(dest); (pi != NULL) && (next = pi->next, 1); + pi = next) { if (BGP_PATH_HOLDDOWN(pi)) continue; From 31cbe16bc968e6255dd2a4b21e255abd41b8f94b Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Thu, 12 Dec 2024 18:09:45 +0200 Subject: [PATCH 102/106] doc: Update the next release dates Signed-off-by: Donatas Abraitis --- doc/developer/workflow.rst | 10 +-------- doc/figures/releases.dot | 44 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 9 deletions(-) create mode 100644 doc/figures/releases.dot diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst index 5e22c4cb72b5..45142f7d8396 100644 --- a/doc/developer/workflow.rst +++ b/doc/developer/workflow.rst @@ -167,15 +167,7 @@ as early as possible, i.e. the first 2-week window. For reference, the expected release schedule according to the above is: -+---------+------------+------------+------------+ -| Release | 2024-03-12 | 2024-07-02 | 2024-11-05 | -+---------+------------+------------+------------+ -| RC | 2024-02-27 | 2024-06-18 | 2024-10-22 | -+---------+------------+------------+------------+ -| dev/X.Y | 2024-02-13 | 2024-06-04 | 2024-10-08 | -+---------+------------+------------+------------+ -| freeze | 2024-01-30 | 2024-05-21 | 2024-09-24 | -+---------+------------+------------+------------+ +.. graphviz:: ../figures/releases.dot Here is the hint on how to get the dates easily: diff --git a/doc/figures/releases.dot b/doc/figures/releases.dot new file mode 100644 index 000000000000..57d35987f853 --- /dev/null +++ b/doc/figures/releases.dot @@ -0,0 +1,44 @@ +digraph ReleaseTimeline { + rankdir=LR; + node [shape=box, style=rounded, fontsize=10, width=1.5, fontname="Helvetica"]; + + subgraph cluster_dev { + label="Development"; + style=dashed; + color=blue; + node [fillcolor=lightblue, style=filled]; + "dev/X.Y"; + } + + subgraph cluster_rc { + label="Release Candidate"; + style=dashed; + color=orange; + node [fillcolor=orange, style=filled]; + "RC"; + } + + subgraph cluster_stable { + label="Stable Release"; + style=dashed; + color=green; + node [fillcolor=lightgreen, style=filled]; + "release"; + } + + // Release steps with actions + "freeze" [label="Freeze", shape=ellipse, style=dotted, fontcolor=red]; + "dev/X.Y" [label="dev/X.Y\n(Development)", fillcolor=lightblue]; + "RC" [label="RC\n(Release Candidate)", fillcolor=orange]; + "release" [label="Release\n(Final)", fillcolor=lightgreen]; + + // Connect the steps with actions + "freeze" -> "dev/X.Y" [label=" "]; + "dev/X.Y" -> "RC" [label=" "]; + "RC" -> "release" [label=" "]; + + // Date connections (freeze -> dev/X.Y -> RC -> release) + "2025-01-21" -> "2025-02-04" -> "2025-02-18" -> "2025-03-04"; + "2025-05-20" -> "2025-06-03" -> "2025-06-17" -> "2025-07-01"; + "2025-09-23" -> "2025-10-07" -> "2025-10-21" -> "2025-11-04"; +} From 02d336dbb4165163d54b3caa2c162d209a234d39 Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Wed, 11 Dec 2024 10:39:36 -0300 Subject: [PATCH 103/106] pim6d: fix crash on clear ipv6 mroute Fix crash on `clear ipv6 mroute` when using embedded RP. Signed-off-by: Rafael Zalamena --- pimd/pim6_mld.c | 2 +- pimd/pim_tib.c | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/pimd/pim6_mld.c b/pimd/pim6_mld.c index b44169c522f1..acfb0c3af3e0 100644 --- a/pimd/pim6_mld.c +++ b/pimd/pim6_mld.c @@ -449,7 +449,7 @@ static void gm_sg_update(struct gm_sg *sg, bool has_expired) * this data structure. */ if (sg->oil) - pim_channel_oil_del(sg->oil, __func__); + sg->oil = pim_channel_oil_del(sg->oil, __func__); /* multiple paths can lead to the last state going away; * t_sg_expire can still be running if we're arriving from diff --git a/pimd/pim_tib.c b/pimd/pim_tib.c index e21793b8caaf..2786ba440d15 100644 --- a/pimd/pim_tib.c +++ b/pimd/pim_tib.c @@ -115,13 +115,8 @@ bool tib_sg_gm_join(struct pim_instance *pim, pim_sgaddr sg, return false; } - if (!*oilp) { + if (!*oilp) *oilp = tib_sg_oil_setup(pim, sg, oif); -#if PIM_IPV == 6 - if (pim_embedded_rp_is_embedded(&sg.grp)) - (*oilp)->oil_ref_count--; -#endif /* PIM_IPV == 6 */ - } if (!*oilp) return false; From 3049a633d46efc643b7663926de59def88e62e42 Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Thu, 12 Dec 2024 22:44:29 -0300 Subject: [PATCH 104/106] pimd,pim6d: optimize multicast prefix generation Fix Coverity Scan CID 1602463: make it impossible for the function to fail. Hardcode the multicast prefix generation instead of calling `str2prefix()` which caused unnecessary memory allocations and returned error values. Signed-off-by: Rafael Zalamena --- pimd/pim_bsm.c | 8 ++------ pimd/pim_nb_config.c | 20 +++----------------- pimd/pim_rp.c | 26 +++++++------------------- pimd/pim_util.c | 17 +++++++++++------ pimd/pim_util.h | 2 +- 5 files changed, 24 insertions(+), 49 deletions(-) diff --git a/pimd/pim_bsm.c b/pimd/pim_bsm.c index 75104141ae8e..1efdebdee1b7 100644 --- a/pimd/pim_bsm.c +++ b/pimd/pim_bsm.c @@ -480,9 +480,7 @@ static void pim_instate_pend_list(struct bsgrp_node *bsgrp_node) pend = bsm_rpinfos_first(bsgrp_node->partial_bsrp_list); - if (!pim_get_all_mcast_group(&group_all)) - return; - + pim_get_all_mcast_group(&group_all); rp_all = pim_rp_find_match_group(pim, &group_all); rn = route_node_lookup(pim->rp_table, &bsgrp_node->group); @@ -729,9 +727,7 @@ void pim_bsm_clear(struct pim_instance *pim) pim_delete_tracked_nexthop(pim, nht_p, NULL, rp_info); - if (!pim_get_all_mcast_group(&g_all)) - return; - + pim_get_all_mcast_group(&g_all); rp_all = pim_rp_find_match_group(pim, &g_all); if (rp_all == rp_info) { diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index 30895e037773..cf9ae21cc067 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -2825,13 +2825,7 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp else if (yang_dnode_get(args->dnode, "prefix-list")) { plist = yang_dnode_get_string(args->dnode, "./prefix-list"); - if (!pim_get_all_mcast_group(&group)) { - flog_err( - EC_LIB_DEVELOPMENT, - "Unable to convert 224.0.0.0/4 to prefix"); - return NB_ERR_INCONSISTENCY; - } - + pim_get_all_mcast_group(&group); result = pim_no_rp_cmd_worker(pim, rp_addr, group, plist, args->errmsg, args->errmsg_len); @@ -2923,11 +2917,7 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp pim = vrf->info; plist = yang_dnode_get_string(args->dnode, NULL); yang_dnode_get_pimaddr(&rp_addr, args->dnode, "../rp-address"); - if (!pim_get_all_mcast_group(&group)) { - flog_err(EC_LIB_DEVELOPMENT, - "Unable to convert 224.0.0.0/4 to prefix"); - return NB_ERR_INCONSISTENCY; - } + pim_get_all_mcast_group(&group); return pim_rp_cmd_worker(pim, rp_addr, group, plist, args->errmsg, args->errmsg_len); } @@ -2954,11 +2944,7 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp pim = vrf->info; yang_dnode_get_pimaddr(&rp_addr, args->dnode, "../rp-address"); plist = yang_dnode_get_string(args->dnode, NULL); - if (!pim_get_all_mcast_group(&group)) { - flog_err(EC_LIB_DEVELOPMENT, - "Unable to convert 224.0.0.0/4 to prefix"); - return NB_ERR_INCONSISTENCY; - } + pim_get_all_mcast_group(&group); return pim_no_rp_cmd_worker(pim, rp_addr, group, plist, args->errmsg, args->errmsg_len); break; diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index 6266f42591e3..44cc00622668 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -97,14 +97,7 @@ void pim_rp_init(struct pim_instance *pim) rp_info = XCALLOC(MTYPE_PIM_RP, sizeof(*rp_info)); - if (!pim_get_all_mcast_group(&rp_info->group)) { - flog_err(EC_LIB_DEVELOPMENT, - "Unable to convert all-multicast prefix"); - list_delete(&pim->rp_list); - route_table_finish(pim->rp_table); - XFREE(MTYPE_PIM_RP, rp_info); - return; - } + pim_get_all_mcast_group(&rp_info->group); rp_info->rp.rpf_addr = PIMADDR_ANY; listnode_add(pim->rp_list, rp_info); @@ -524,11 +517,7 @@ int pim_rp_new(struct pim_instance *pim, pim_addr rp_addr, struct prefix group, rp_info->plist = XSTRDUP(MTYPE_PIM_FILTER_NAME, plist); } else { - - if (!pim_get_all_mcast_group(&group_all)) { - XFREE(MTYPE_PIM_RP, rp_info); - return PIM_GROUP_BAD_ADDRESS; - } + pim_get_all_mcast_group(&group_all); rp_all = pim_rp_find_match_group(pim, &group_all); /* @@ -708,9 +697,10 @@ void pim_rp_del_config(struct pim_instance *pim, pim_addr rp_addr, struct prefix group; int result; - if (group_range == NULL) - result = pim_get_all_mcast_group(&group); - else + if (group_range == NULL) { + result = 0; + pim_get_all_mcast_group(&group); + } else result = str2prefix(group_range, &group); if (!result) { @@ -789,9 +779,7 @@ int pim_rp_del(struct pim_instance *pim, pim_addr rp_addr, struct prefix group, &nht_p); pim_delete_tracked_nexthop(pim, nht_p, NULL, rp_info); - if (!pim_get_all_mcast_group(&g_all)) - return PIM_RP_BAD_ADDRESS; - + pim_get_all_mcast_group(&g_all); rp_all = pim_rp_find_match_group(pim, &g_all); if (rp_all == rp_info) { diff --git a/pimd/pim_util.c b/pimd/pim_util.c index 40404714e7fb..0aea24058730 100644 --- a/pimd/pim_util.c +++ b/pimd/pim_util.c @@ -213,16 +213,21 @@ bool pim_is_group_filtered(struct pim_interface *pim_ifp, pim_addr *grp, pim_add /* This function returns all multicast group */ -int pim_get_all_mcast_group(struct prefix *prefix) +void pim_get_all_mcast_group(struct prefix *prefix) { + memset(prefix, 0, sizeof(*prefix)); + #if PIM_IPV == 4 - if (!str2prefix("224.0.0.0/4", prefix)) - return 0; + /* Precomputed version of: `str2prefix("224.0.0.0/4", prefix);` */ + prefix->family = AF_INET; + prefix->prefixlen = 4; + prefix->u.prefix4.s_addr = htonl(0xe0000000); #else - if (!str2prefix("FF00::0/8", prefix)) - return 0; + /* Precomputed version of: `str2prefix("FF00::0/8", prefix)` */ + prefix->family = AF_INET6; + prefix->prefixlen = 8; + prefix->u.prefix6.s6_addr[0] = 0xff; #endif - return 1; } bool pim_addr_is_multicast(pim_addr addr) diff --git a/pimd/pim_util.h b/pimd/pim_util.h index dda93110b80d..a3d944b82b96 100644 --- a/pimd/pim_util.h +++ b/pimd/pim_util.h @@ -26,6 +26,6 @@ int pim_is_group_224_4(struct in_addr group_addr); enum filter_type pim_access_list_apply(struct access_list *access, const struct in_addr *source, const struct in_addr *group); bool pim_is_group_filtered(struct pim_interface *pim_ifp, pim_addr *grp, pim_addr *src); -int pim_get_all_mcast_group(struct prefix *prefix); +void pim_get_all_mcast_group(struct prefix *prefix); bool pim_addr_is_multicast(pim_addr addr); #endif /* PIM_UTIL_H */ From b131abf62d87715166c58f9489c3a9e4b58c4f9f Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 13 Dec 2024 11:21:26 -0500 Subject: [PATCH 105/106] zebra: Give a bit more data about zclient connection on errors When debugging a crash I noticed that sometimes we talked about a zclient connection in relation to the fd associated with it and sometimes we did not. Let's just always give the data associated with the fd. It will make it a bit easier for me to follow the transitions. Signed-off-by: Donald Sharp --- zebra/zserv.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/zebra/zserv.c b/zebra/zserv.c index d6c017d259e4..7ef358232991 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -184,10 +184,9 @@ void zserv_log_message(const char *errmsg, struct stream *msg, */ static void zserv_client_fail(struct zserv *client) { - flog_warn( - EC_ZEBRA_CLIENT_IO_ERROR, - "Client '%s' (session id %d) encountered an error and is shutting down.", - zebra_route_string(client->proto), client->session_id); + flog_warn(EC_ZEBRA_CLIENT_IO_ERROR, + "Client %d '%s' (session id %d) encountered an error and is shutting down.", + client->sock, zebra_route_string(client->proto), client->session_id); atomic_store_explicit(&client->pthread->running, false, memory_order_relaxed); @@ -468,8 +467,8 @@ static void zserv_read(struct event *thread) } if (IS_ZEBRA_DEBUG_PACKET) - zlog_debug("Read %d packets from client: %s. Current ibuf fifo count: %zu. Conf P2p %d", - p2p_avail - p2p, zebra_route_string(client->proto), + zlog_debug("Read %d packets from client: %s(%d). Current ibuf fifo count: %zu. Conf P2p %d", + p2p_avail - p2p, zebra_route_string(client->proto), client->sock, client_ibuf_fifo_cnt, p2p_orig); /* Reschedule ourselves since we have space in ibuf_fifo */ From b43c2768dd0fb52f07d72d93ae8905db59d35467 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 13 Dec 2024 10:56:17 -0500 Subject: [PATCH 106/106] tools: Add rip support bundle commands Signed-off-by: Donald Sharp --- tools/etc/frr/support_bundle_commands.conf | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tools/etc/frr/support_bundle_commands.conf b/tools/etc/frr/support_bundle_commands.conf index a248a1a30424..be831a1d344f 100644 --- a/tools/etc/frr/support_bundle_commands.conf +++ b/tools/etc/frr/support_bundle_commands.conf @@ -134,9 +134,11 @@ show ip ospf router-info pce CMD_LIST_END # RIP Support Bundle Command List -# PROC_NAME:rip -# CMD_LIST_START -# CMD_LIST_END +PROC_NAME:rip +CMD_LIST_START +show ip rip +show ip rip status +CMD_LIST_END # ISIS Support Bundle Command List PROC_NAME:isis