From 25f2ca5307e4c7ad5a65cbf4639ee4d13a906cb4 Mon Sep 17 00:00:00 2001 From: vivek Date: Fri, 19 Jan 2018 09:29:49 -0800 Subject: [PATCH 01/25] bgpd: Ensure EVPN routes are not injected back into EVPN EVPN type-2 and type-5 routes received with a L3 VNI and corresponding RTs are installed into the appropriate BGP RIB. Ensure that these routes are not re-injected back into EVPN as type-5 routes when type-5 advertisement is enabled; only regular IPv4 routes (and IPv6 routes in future) in the RIB should be injected into EVPN. As a benefit of this change, no longer restrict that EVPN type-5 routes should be non-host routes - i.e., allow /32 IPv4 routes (and /128 IPv6 routes in future). Signed-off-by: Vivek Venkatraman Signed-off-by: Donald Sharp Signed-off-by: Mitesh Kanjariya Ticket: CM-19456 Reviewed By: CCR-7117 Testing Done: 1. Manual replication of problem and verification of fix 2. evpn-min --- bgpd/bgp_evpn.c | 25 ++++++++++++++++--------- bgpd/bgp_route.c | 6 ++++-- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index c7d5f8d111..a69c3465e3 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -3210,15 +3210,25 @@ void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf, { struct bgp_table *table = NULL; struct bgp_node *rn = NULL; + struct bgp_info *ri; /* Bail out early if we don't have to advertise type-5 routes. */ if (!advertise_type5_routes(bgp_vrf, afi)) return; table = bgp_vrf->rib[afi][safi]; - for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) - bgp_evpn_withdraw_type5_route(bgp_vrf, &rn->p, afi, safi); - + for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { + /* Only care about "selected" routes - non-imported. */ + /* TODO: Support for AddPath for EVPN. */ + for (ri = rn->info; ri; ri = ri->next) { + if (CHECK_FLAG(ri->flags, BGP_INFO_SELECTED) && + (!ri->extra || !ri->extra->parent)) { + bgp_evpn_withdraw_type5_route(bgp_vrf, &rn->p, + afi, safi); + break; + } + } + } } /* @@ -3239,10 +3249,6 @@ void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, struct prefix *p, if (!advertise_type5_routes(bgp_vrf, afi)) return; - /* only advertise subnet routes as type-5 */ - if (is_host_route(p)) - return; - build_type5_prefix_from_ip_prefix(&evp, p); ret = update_evpn_type5_route(bgp_vrf, &evp, src_attr); if (ret) @@ -3270,11 +3276,12 @@ void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, table = bgp_vrf->rib[afi][safi]; for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { /* Need to identify the "selected" route entry to use its - * attribute. + * attribute. Also, we only consider "non-imported" routes. * TODO: Support for AddPath for EVPN. */ for (ri = rn->info; ri; ri = ri->next) { - if (CHECK_FLAG(ri->flags, BGP_INFO_SELECTED)) { + if (CHECK_FLAG(ri->flags, BGP_INFO_SELECTED) && + (!ri->extra || !ri->extra->parent)) { bgp_evpn_advertise_type5_route(bgp_vrf, &rn->p, ri->attr, afi, safi); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 36e0c92482..fe2c5d11a1 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2225,11 +2225,13 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn, /* advertise/withdraw type-5 routes */ if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) { - if (new_select) + if (new_select && + (!new_select->extra || !new_select->extra->parent)) bgp_evpn_advertise_type5_route(bgp, &rn->p, new_select->attr, afi, safi); - else if (old_select) + else if (old_select && + (!old_select->extra || !old_select->extra->parent)) bgp_evpn_withdraw_type5_route(bgp, &rn->p, afi, safi); } From 2ca3a78b6835e4009913cbb8eb67f070bf1595b4 Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Wed, 7 Feb 2018 15:30:55 -0800 Subject: [PATCH 02/25] bgpd: enunciate the error message if user tries to configure 'router bgp' We need a better error message. "Multiple BGP processes are configured" doesnt makes sense anymore as with l3vni, we could have multiple auto configured bgp instances. Signed-off-by: Mitesh Kanjariya --- 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 4a8eeb9121..6c06d72eb4 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -833,7 +833,7 @@ DEFUN_NOSH (router_bgp, if (listcount(bm->bgp) > 1) { vty_out(vty, - "%% Multiple BGP processes are configured\n"); + "%% Please specify ASN and VRF\n"); return CMD_WARNING_CONFIG_FAILED; } } @@ -909,7 +909,7 @@ DEFUN (no_router_bgp, if (listcount(bm->bgp) > 1) { vty_out(vty, - "%% Multiple BGP processes are configured\n"); + "%% Please specify ASN and VRF\n"); return CMD_WARNING_CONFIG_FAILED; } From d1911c2664cf84aa674d433396bbdecf2db9d3eb Mon Sep 17 00:00:00 2001 From: vivek Date: Wed, 24 Jan 2018 22:41:44 -0800 Subject: [PATCH 03/25] bgpd: Handle multiple simultaneous changes for a VNI correctly Ensure that if multiple parameters for a VNI change simultaneously, the changes are processed correctly. The changes of interest are the local tunnel IP address and the tenant VRF to which this VNI is attached. The former is used to originate type-3 routes as well as set the next hop of all routes, the latter helps to determine the route targets and VNIs to include in the route. Signed-off-by: Vivek Venkatraman Reviewed-by: Mitesh Kanjariya Ticket: CM-19099 Reviewed By: CCR-7102 Testing Done: 1. Manually reproduced problem and verified fix. 2. Additional trigger events tested with fix. --- bgpd/bgp_evpn.c | 45 +++++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index a69c3465e3..a50e3707ad 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1725,8 +1725,10 @@ static int delete_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn) } /* - * There is a tunnel endpoint IP address change for this VNI, - * need to re-advertise routes with the new nexthop. + * There is a tunnel endpoint IP address change for this VNI, delete + * prior type-3 route (if needed) and update. + * Note: Route re-advertisement happens elsewhere after other processing + * other changes. */ static int handle_tunnel_ip_change(struct bgp *bgp, struct bgpevpn *vpn, struct in_addr originator_ip) @@ -1754,7 +1756,7 @@ static int handle_tunnel_ip_change(struct bgp *bgp, struct bgpevpn *vpn, /* Update the tunnel IP and re-advertise all routes for this VNI. */ vpn->originator_ip = originator_ip; - return update_routes_for_vni(bgp, vpn); + return 0; } /* @@ -4397,8 +4399,8 @@ int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni) } /* - * Handle add (or update) of a local VNI. The only VNI change we care - * about is change to local-tunnel-ip. + * Handle add (or update) of a local VNI. The VNI changes we care + * about are for the local-tunnel-ip and the (tenant) VRF. */ int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni, struct in_addr originator_ip, @@ -4416,24 +4418,31 @@ int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni, vpn = bgp_evpn_lookup_vni(bgp, vni); if (vpn) { - /* update tenant_vrf_id if required */ - if (vpn->tenant_vrf_id != tenant_vrf_id) { - bgpevpn_unlink_from_l3vni(vpn); - vpn->tenant_vrf_id = tenant_vrf_id; - bgpevpn_link_to_l3vni(vpn); - - /* update all routes with new export RT for VRFs */ - update_routes_for_vni(bgp, vpn); - } - if (is_vni_live(vpn) - && IPV4_ADDR_SAME(&vpn->originator_ip, &originator_ip)) + && IPV4_ADDR_SAME(&vpn->originator_ip, &originator_ip) + && vpn->tenant_vrf_id == tenant_vrf_id) /* Probably some other param has changed that we don't * care about. */ return 0; - /* Local tunnel endpoint IP address has changed */ - handle_tunnel_ip_change(bgp, vpn, originator_ip); + /* Update tenant_vrf_id if it has changed. */ + if (vpn->tenant_vrf_id != tenant_vrf_id) { + bgpevpn_unlink_from_l3vni(vpn); + vpn->tenant_vrf_id = tenant_vrf_id; + bgpevpn_link_to_l3vni(vpn); + } + + /* If tunnel endpoint IP has changed, update (and delete prior + * type-3 route, if needed.) + */ + if (!IPV4_ADDR_SAME(&vpn->originator_ip, &originator_ip)) + handle_tunnel_ip_change(bgp, vpn, originator_ip); + + /* Update all routes with new endpoint IP and/or export RT + * for VRFs + */ + if (is_vni_live(vpn)) + update_routes_for_vni(bgp, vpn); } /* Create or update as appropriate. */ From 3b103fec6be8073eb5f4da86a8a45b8f6d7e708f Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Wed, 7 Feb 2018 14:46:04 -0800 Subject: [PATCH 04/25] vtysh/lib: write domainname to config file Ticket: CM-19626 Review: CCR-7170 Testing: Manual Signed-off-by: Mitesh Kanjariya --- lib/command.c | 3 +++ vtysh/vtysh_config.c | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/lib/command.c b/lib/command.c index d17f2c3d48..6870f4804b 100644 --- a/lib/command.c +++ b/lib/command.c @@ -500,6 +500,9 @@ static int config_write_host(struct vty *vty) if (cmd_hostname_get()) vty_out(vty, "hostname %s\n", cmd_hostname_get()); + if (cmd_domainname_get()) + vty_out(vty, "domainname %s\n", cmd_domainname_get()); + if (host.encrypt) { if (host.password_encrypt) vty_out(vty, "password 8 %s\n", host.password_encrypt); diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index 967f855fbc..5ba749e66f 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -448,6 +448,11 @@ void vtysh_config_write() sprintf(line, "hostname %s", cmd_hostname_get()); vtysh_config_parse_line(NULL, line); } + + if (cmd_domainname_get()) { + sprintf(line, "domainname %s", cmd_domainname_get()); + vtysh_config_parse_line(NULL, line); + } if (vtysh_write_integrated == WRITE_INTEGRATED_NO) vtysh_config_parse_line(NULL, "no service integrated-vtysh-config"); From 01a6143bdababeae6349d8e2ba3560236038b2ba Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Wed, 13 Dec 2017 12:18:11 -0800 Subject: [PATCH 05/25] zebra: do not check if advertise-default-gw is on in no-advertise-default-gw flow Ticket: CM-19116 Review: CCR-7042 Testing: Manual Signed-off-by: Mitesh Kanjariya --- zebra/zebra_vxlan.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index fb1aebecc3..1e15529b00 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -1852,20 +1852,18 @@ static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni, return -1; /* only need to delete the entry from bgp if we sent it before */ - if (advertise_gw_macip_enabled(zvni)) { - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("%u:SVI %s(%u) VNI %u, sending GW MAC %s IP %s del to BGP", - ifp->vrf_id, ifp->name, - ifp->ifindex, zvni->vni, - prefix_mac2str(&(n->emac), - NULL, - ETHER_ADDR_STRLEN), - ipaddr2str(ip, buf2, sizeof(buf2))); + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("%u:SVI %s(%u) VNI %u, sending GW MAC %s IP %s del to BGP", + ifp->vrf_id, ifp->name, + ifp->ifindex, zvni->vni, + prefix_mac2str(&(n->emac), + NULL, + ETHER_ADDR_STRLEN), + ipaddr2str(ip, buf2, sizeof(buf2))); - /* Remove neighbor from BGP. */ - zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac, - ZEBRA_MACIP_TYPE_GW); - } + /* Remove neighbor from BGP. */ + zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac, + ZEBRA_MACIP_TYPE_GW); /* Delete this neighbor entry. */ zvni_neigh_del(zvni, n); @@ -6760,6 +6758,10 @@ int zebra_vxlan_advertise_gw_macip(struct zserv *client, u_short length, struct interface *vlan_if = NULL; struct interface *vrr_if = NULL; + zvni = zvni_lookup(vni); + if (!zvni) + return 0; + if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( "EVPN gateway macip Adv %s on VNI %d , currently %s", @@ -6768,10 +6770,6 @@ int zebra_vxlan_advertise_gw_macip(struct zserv *client, u_short length, ? "enabled" : "disabled"); - zvni = zvni_lookup(vni); - if (!zvni) - return 0; - if (zvni->advertise_gw_macip == advertise) return 0; From 4ac71d4bea5f9a7b01d717ed6955f88035c92d9c Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Wed, 7 Feb 2018 13:18:49 -0800 Subject: [PATCH 06/25] zebra: fix 'show evpn vni' output removed an additional field 'local-tunnel-ip' from l2vnis o/p Ticket: CM-19670 Review: CCR-7167 Testing: Verified that the output is proper Signed-off-by: Mitesh Kanjariya --- zebra/zebra_vxlan.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 1e15529b00..850ee50969 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -1129,7 +1129,8 @@ static void zvni_print_hash(struct hash_backet *backet, void *ctxt[]) "%-10u %-4s %-21s %-8u %-8u %-15u %-37s\n", zvni->vni, "L2", zvni->vxlan_if ? zvni->vxlan_if->name : "unknown", - num_macs, num_neigh, num_vteps, + num_macs, num_neigh, + num_vteps, vrf_id_to_name(zvni->vrf_id)); else { char vni_str[VNI_STR_LEN]; From bca63dc8baf1c309addf47df7ea0f1725e975dac Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Mon, 22 Jan 2018 18:12:13 -0800 Subject: [PATCH 07/25] zebra: Handle change to VxLAN tunnel (local) IP address for L3 VNI similar to what is done for L2 VNI. Ticket: CM-19195 Review: CCR-7122 Test: Manual Signed-of-by: Vivek Venkatraman --- zebra/zebra_vxlan.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 850ee50969..01d5e16556 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -6301,14 +6301,21 @@ int zebra_vxlan_if_update(struct interface *ifp, u_int16_t chgflags) zebra_vxlan_process_l3vni_oper_down(zl3vni); zl3vni->svi_if = NULL; zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); + zl3vni->local_vtep_ip = vxl->vtep_ip; if (is_l3vni_oper_up(zl3vni)) zebra_vxlan_process_l3vni_oper_up( zl3vni); } } - /* if we have a valid new master, process l3-vni oper up */ - if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) { + /* Update local tunnel IP. */ + zl3vni->local_vtep_ip = vxl->vtep_ip; + + /* if we have a valid new master or there is a change to the tunnel IP, + * process l3-vni oper up + */ + if (chgflags + & (ZEBRA_VXLIF_MASTER_CHANGE | ZEBRA_VXLIF_LOCAL_IP_CHANGE)) { if (is_l3vni_oper_up(zl3vni)) zebra_vxlan_process_l3vni_oper_up(zl3vni); } From 12eeac84ff34bd153f6d75f80aac1fa42c3f7db3 Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Mon, 29 Jan 2018 17:14:52 -0800 Subject: [PATCH 08/25] zebra: Handle local-ip change in a correct way for l3-vni Ticket: CM-19603 Review: CCR-7142 Testing: Manual Signed-off-by: Mitesh Kanjariya --- zebra/zebra_vxlan.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 01d5e16556..1a56b14466 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -6308,15 +6308,26 @@ int zebra_vxlan_if_update(struct interface *ifp, u_int16_t chgflags) } } + /* + * local-ip change - process oper down, associate with new + * local-ip and then process oper up again + */ + if (chgflags & ZEBRA_VXLIF_LOCAL_IP_CHANGE) { + if (if_is_operative(ifp)) { + zebra_vxlan_process_l3vni_oper_down(zl3vni); + zl3vni->local_vtep_ip = vxl->vtep_ip; + if (is_l3vni_oper_up(zl3vni)) + zebra_vxlan_process_l3vni_oper_up( + zl3vni); + } + } + /* Update local tunnel IP. */ zl3vni->local_vtep_ip = vxl->vtep_ip; - /* if we have a valid new master or there is a change to the tunnel IP, - * process l3-vni oper up - */ - if (chgflags - & (ZEBRA_VXLIF_MASTER_CHANGE | ZEBRA_VXLIF_LOCAL_IP_CHANGE)) { - if (is_l3vni_oper_up(zl3vni)) + /* if we have a valid new master, process l3-vni oper up */ + if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) { + if (if_is_operative(ifp) && is_l3vni_oper_up(zl3vni)) zebra_vxlan_process_l3vni_oper_up(zl3vni); } } else { From 7fdaec88941d66d831363d32084cc88c5b98ac6c Mon Sep 17 00:00:00 2001 From: mitesh Date: Fri, 9 Feb 2018 21:54:00 -0800 Subject: [PATCH 09/25] bgpd: update the VNI labels in type-2 routes when l3vni gets deleted When an l3-vni is enabled, type-2 routes are sent with 2 labels (l2vni and l3vni). When it gets deleted, we need to update type-2 routes and send them with only one label (l2vni). Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_evpn.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index a50e3707ad..9b1ff8f6a9 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1209,6 +1209,23 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, && !CHECK_FLAG(tmp_ri->flags, BGP_INFO_REMOVED)) route_change = 0; else { + /* + * The attributes have changed, type-2 routes needs to + * be advertised with right labels. + */ + vni2label(vpn->vni, &label[0]); + if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) { + vni_t l3vni; + + l3vni = bgpevpn_get_l3vni(vpn); + if (l3vni) { + vni2label(l3vni, &label[1]); + num_labels++; + } + } + memcpy(&tmp_ri->extra->label, label, sizeof(label)); + tmp_ri->extra->num_labels = num_labels; + /* The attribute has changed. */ /* Add (or update) attribute to hash. */ attr_new = bgp_attr_intern(attr); From 0908f2bfc73c9e419ebc0c212609544291793daf Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 22 Feb 2018 08:48:45 -0500 Subject: [PATCH 10/25] FRR: Update Community.md to reflect release process This is the new release process for FRR. Signed-off-by: Donald Sharp --- COMMUNITY.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/COMMUNITY.md b/COMMUNITY.md index 0eee524d58..081f7ab3b8 100644 --- a/COMMUNITY.md +++ b/COMMUNITY.md @@ -492,6 +492,36 @@ In all cases, compatibility pieces should be marked with compiler/preprocessor annotations to print warnings at compile time, pointing to the appropriate update path. A `-Werror` build should fail if compatibility bits are used. +### Release Process/Schedule + +FRR employs a .. versioning scheme. + +* MAJOR - Significant new features or multiple minor features + A example of a MAJOR feature is a New Routing Protocol +* MINOR - Smaller Features + A example of a MINOR feature is the addition of the BGP Shutdown feature. +* BUGFIX - Fixes for actual bugs and/or security issues. + +We will pull a new development branch for the next release every 4 months. +The current schedule is Feb/June/October 1. The decision for a MAJOR/MINOR +release is made at the time of branch pull based on what has been received +the previous 4 months. The branch name will be dev/MAJOR.MINOR. At +this point in time the master branch configure.ac and packaging systems +will be updated to reflect the next possible release name to allow +for easy distinguishing. Additionally the new dev branch will have +these files updated too. + +After one month the development branch will be renamed to +stable/MAJOR.MINOR. This process is not held up unless a crash or +security issue has been found and needs to be addressed. Issues +being fixed will not cause a delay. + +Bug fix releases are at 1 month intervals until next MAJOR.MINOR is +pulled. Then at that time as needed for issues filed. + +Security issues are fixed for 1 year minimum on old releases and +normal bug fixes for the current and previous release + ### Miscellaneous When in doubt, follow the guidelines in the Linux kernel style guide, or ask on From 4e8b02f4df5d6bcfde6390955b8feda2a17dc9bd Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 26 Feb 2018 21:26:33 -0500 Subject: [PATCH 11/25] *: Rename ZEBRA_FLAG_INTERNAL -> ZEBRA_FLAG_ALLOW_RECURSION The ZEBRA_FLAG_INTERNAL flag is used to signal to zebra that the route being added, the nexthops for it can be recursively resolved. This name keeps throwing me off when I read it so let's rename to something that allows the developer to understand what is going on. Signed-off-by: Donald Sharp --- bgpd/bgp_zebra.c | 8 ++++---- lib/zebra.h | 2 +- nhrpd/nhrp_route.c | 2 +- pimd/TODO | 4 ++-- zebra/zebra_rib.c | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 1da6136428..daa7ccbf42 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1026,14 +1026,14 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED || info->sub_type == BGP_ROUTE_AGGREGATE) { SET_FLAG(api.flags, ZEBRA_FLAG_IBGP); - SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL); + SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION); } if ((peer->sort == BGP_PEER_EBGP && peer->ttl != 1) || CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK) || bgp_flag_check(bgp, BGP_FLAG_DISABLE_NH_CONNECTED_CHK)) - SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL); + SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION); /* Metric is currently based on the best-path only */ metric = info->attr->med; @@ -1265,14 +1265,14 @@ void bgp_zebra_withdraw(struct prefix *p, struct bgp_info *info, safi_t safi) SET_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE); if (peer->sort == BGP_PEER_IBGP) { - SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL); + SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION); SET_FLAG(api.flags, ZEBRA_FLAG_IBGP); } if ((peer->sort == BGP_PEER_EBGP && peer->ttl != 1) || CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK) || bgp_flag_check(peer->bgp, BGP_FLAG_DISABLE_NH_CONNECTED_CHK)) - SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL); + SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION); if (bgp_debug_zebra(p)) { char buf[PREFIX_STRLEN]; diff --git a/lib/zebra.h b/lib/zebra.h index b9a795d160..11bf764b63 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -402,7 +402,7 @@ extern const char *zserv_command_string(unsigned int command); #define strmatch(a,b) (!strcmp((a), (b))) /* Zebra message flags */ -#define ZEBRA_FLAG_INTERNAL 0x01 +#define ZEBRA_FLAG_ALLOW_RECURSION 0x01 #define ZEBRA_FLAG_SELFROUTE 0x02 #define ZEBRA_FLAG_IBGP 0x08 #define ZEBRA_FLAG_SELECTED 0x10 diff --git a/nhrpd/nhrp_route.c b/nhrpd/nhrp_route.c index d43aa4929e..8178a8b4b5 100644 --- a/nhrpd/nhrp_route.c +++ b/nhrpd/nhrp_route.c @@ -114,7 +114,7 @@ void nhrp_route_announce(int add, enum nhrp_cache_type type, const struct prefix SET_FLAG(api.flags, ZEBRA_FLAG_FIB_OVERRIDE); break; } - SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL); + SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION); SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; diff --git a/pimd/TODO b/pimd/TODO index 57d2a17b5f..b9e4152830 100644 --- a/pimd/TODO +++ b/pimd/TODO @@ -167,9 +167,9 @@ T26 DONE Zebra daemon is marking recursive static route as inactive. pointing to kernel routes as inactive: zebra/zebra_rib.c nexthop_active_ipv4: -- Original: - else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL)) + else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_ALLOW_RECURSION)) -- Fixed: - else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL) || + else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_ALLOW_RECURSION) || match->type == ZEBRA_ROUTE_KERNEL) Old problem description: diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 5c316e077f..7f6c8aefa8 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -514,7 +514,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re, nexthop->ifindex = newhop->ifindex; } return 1; - } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_INTERNAL)) { + } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) { resolved = 0; for (ALL_NEXTHOPS(match->nexthop, newhop)) { if (!CHECK_FLAG(newhop->flags, From 95d962bf1dcd60669e14d5fc7fb97a21501607c3 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 26 Feb 2018 21:33:02 -0500 Subject: [PATCH 12/25] pimd: Cleanup TODO file The TODO file had become a dumping ground of changes made to the protocol. That when we modified the underlying code we would need to update the TODO file again due to it's nature. There is no point in keeping the list of items that we've done as that commit messages will indicate the new features. So pull out all the Finished work and rework the Todo numbers used. Signed-off-by: Donald Sharp --- pimd/TODO | 372 ++---------------------------------------------------- 1 file changed, 9 insertions(+), 363 deletions(-) diff --git a/pimd/TODO b/pimd/TODO index b9e4152830..4a147751dd 100644 --- a/pimd/TODO +++ b/pimd/TODO @@ -1,375 +1,21 @@ -T1 DONE Implement debug command - test pim receive join - -T2 DONE Implement debug command - test pim receive prune - -T3 DONE Per-interface Downstream (S,G) state machine - (RFC 4601 4.5.3. Receiving (S,G) Join/Prune Messages) - -T4 DONE Upstream (S,G) state machine - (RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages) - -T5 DONE Verify Data Packet Forwarding Rules - RFC 4601 4.2. Data Packet Forwarding Rules - RFC 4601 4.8.2. PIM-SSM-Only Routers - - Additionally, the Packet forwarding rules of Section 4.2 can be - simplified in a PIM-SSM-only router: - - iif is the incoming interface of the packet. - oiflist = NULL - if (iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined) { - oiflist = inherited_olist(S,G) - } else if (iif is in inherited_olist(S,G)) { - send Assert(S,G) on iif - } - oiflist = oiflist (-) iif - forward packet on all interfaces in oiflist - - Macro: - inherited_olist(S,G) = - joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G) - -T6 DONE Implement (S,G) Assert state machine (RFC 4601, section 4.6.1). - Changes in pim_ifchannel.ifassert_winner should trigger - pim_upstream_update_join_desired(). - Depends on TODO T27. - Depends on TODO T33. - See also CAVEAT C7. - See also: RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages - Transitions from Joined State - RPF'(S,G) changes due to an Assert - - http://www.hep.ucl.ac.uk/~ytl/multi-cast/pim-dm_01.html: - - The PIM Assert mechanism is used to shutoff duplicate flows onto - the same multiaccess network. Routers detect this condiction when - they receive an (S,G) packet via a multi-access interface that is - in the (S,G) OIL. This causes the routers to send Assert - Messages. - - Note that neighbors will not accept Join/Prune or Assert messages - from a router unless they have first heard a Hello message from that - router. Thus, if a router needs to send a Join/Prune or Assert - message on an interface on which it has not yet sent a Hello message - with the currently configured IP address, then it MUST immediately - send the relevant Hello message without waiting for the Hello Timer - to expire, followed by the Join/Prune or Assert message. - -T7 DONE Implement hello option: LAN Prune Delay - -T8 DONE Implement J/P_Override_Interval(I) - Depends on TODO T7. - See pim_ifchannel.c, pim_ifchannel_prune(), jp_override_interval. - -T9 DONE Detect change in IGMPv3 RPF interface/next-hop for S and update. - channel_oil vif index accordingly ? - Beware accidentaly adding looped MFC entries (IIF=OIF). - -T10 DONE React to (S,G) join directed to another upstream address. See - also: - - RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages - - If a router wishes to propagate a Join(S,G) upstream, it must also - watch for messages on its upstream interface from other routers on - that subnet, and these may modify its behavior. If it sees a - Join(S,G) to the correct upstream neighbor, it should suppress its - own Join(S,G). If it sees a Prune(S,G), Prune(S,G,rpt), or - Prune(*,G) to the correct upstream neighbor towards S, it should - be prepared to override that prune by scheduling a Join(S,G) to be - sent almost immediately. - -T11 DONE Review protocol modifications for SSM - (RFC 4601 4.8.1. Protocol Modifications for SSM Destination - Addresses) - -T12 DONE Review updates of RPF entries. - FIXME pim_upstream.c send_join(): - Currently only one upstream state is affected by detection of RPF change. - RPF change should affect all upstream states sharing the RPF cache. - -T13 DONE Check that RFC macros using S,G,RPF_interface(S) are actually - implemented with this strategy: - rpf_ifch=find_ifch(up->rpf->interface). - See pim_rpf.c pim_rpf_find_rpf_addr() for a correct example. - - $ grep -i macro pimd/*.c - pimd/pim_iface.c: RFC 4601: 4.1.6. State Summarization Macros - pimd/pim_ifchannel.c: RFC 4601: 4.6.5. Assert State Macros - pimd/pim_ifchannel.c: RFC 4601: 4.1.6. State Summarization Macros - pimd/pim_ifchannel.c: RFC 4601: 4.1.6. State Summarization Macros - pimd/pim_ifchannel.c: RFC 4601: 4.6.5. Assert State Macros - pimd/pim_ifchannel.c: Macro: - pimd/pim_rpf.c: RFC 4601: 4.1.6. State Summarization Macros - -T14 DONE Send Assert(S,G) on iif as response to WRONGVIF kernel upcall. - See pim_mroute.c mroute_msg(). - -T15 DONE Interface command to statically join (S,G). - interface eth0 - ip igmp join-group 239.1.1.1 source 1.1.1.1 - -T16 DONE RPF'(S,G) lookup is not working for S reachable with default route. - See "RPF'(S,G) not found" in pim_rpf_update() from pim_rpf.c. - Zebra daemon RIB is not reflecting changes in kernel routes - accurately? - -T17 DONE Prevent CLI from creating bogus interfaces. - Example: - conf t - interface xxx - -T18 Consider reliable pim solution (refresh reduction) +T1 Consider reliable pim solution (refresh reduction) A Reliable Transport Mechanism for PIM http://tools.ietf.org/wg/pim/draft-ietf-pim-port/ PORT=PIM-Over-Reliable-Transport -T19 DONE Fix self as neighbor - See mailing list post: - http://lists.gnu.org/archive/html/qpimd-users/2009-04/msg00000.html - -T20 DONE Fix debug message: "pim_neighbor_update: internal error: - trying to replace same prefix list" - See mailing list post: - http://lists.gnu.org/archive/html/qpimd-users/2009-04/msg00000.html - -T21 DONE Clean-up PIM/IGMP interface mismatch debugging - See option PIM_CHECK_RECV_IFINDEX_SANITY in pimd/Makefile.am - See mailing list post: - http://lists.nongnu.org/archive/html/qpimd-users/2009-04/msg00003.html - -T22 DONE IGMP must be protected against adding looped MFC entries - created by both source and receiver attached to the same - interface. - -T23 DONE libfrr crash after zclient_lookup_nexthop. - See mailing list post: - http://lists.nongnu.org/archive/html/qpimd-users/2009-04/msg00008.html - -T24 DONE zserv may return recursive routes: - - nexthop type is set to ZEBRA_NEXTHOP_IPV4 - - ifindex is not reported - - calls expecting ifindex (fib_lookup_if_vif_index) are disrupted - See also this mailing list post: - [PATCH 21/21] Link detect and recursive routes - http://www.gossamer-threads.com/lists/quagga/dev/17564 - -T25 DONE Zclient nexthop lookup missing OSPF route to 1.1.1.1/32 - See also: - pim_zlookup.c zclient_lookup_nexthop misses OSPF 1.1.1.1/32 - zebra/zebra_vty.c show_ip_route_addr_cmd hits OSPF 1.1.1.1/32 - -T26 DONE Zebra daemon is marking recursive static route as inactive. - - FIXED: zebra daemon was incorrectly marking recursive routes - pointing to kernel routes as inactive: - zebra/zebra_rib.c nexthop_active_ipv4: - -- Original: - else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_ALLOW_RECURSION)) - -- Fixed: - else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_ALLOW_RECURSION) || - match->type == ZEBRA_ROUTE_KERNEL) - - Old problem description: - - This prevents rib_match_ipv4 from returning its nexthop: - client: pim_zlookup.c zclient_read_nexthop - server: zebra/zserv.c zsend_ipv4_nexthop_lookup_v2 -> rib_match_ipv4 - - Kernel route is injected into zebra in zebra_rib.c rib_add_ipv4 - Examples: - rt_netlink.c:726: rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, table, metric, 0); - rt_netlink.c:864: rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, 0, 0); - - This patch didn't fix the issue: - [PATCH 21/21] Link detect and recursive routes - http://www.gossamer-threads.com/lists/quagga/dev/17564 - - See the example below for the route 2.2.2.2. - -bash# route add -host 1.1.1.1 gw 127.0.0.1 -bash# route add -host 2.2.2.2 gw 1.1.1.1 -bash# netstat -nvr -Kernel IP routing table -Destination Gateway Genmask Flags MSS Window irtt Iface -2.2.2.2 1.1.1.1 255.255.255.255 UGH 0 0 0 lo -1.1.1.1 127.0.0.1 255.255.255.255 UGH 0 0 0 lo -192.168.0.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0 -0.0.0.0 192.168.0.2 0.0.0.0 UG 0 0 0 eth0 -bash# - -zebra# sh ip route -Codes: K - kernel route, C - connected, S - static, R - RIP, O - OSPF, - I - ISIS, B - BGP, > - selected route, * - FIB route - -K>* 0.0.0.0/0 via 192.168.0.2, eth0 -K>* 1.1.1.1/32 via 127.0.0.1, lo -K * 2.2.2.2/32 via 1.1.1.1, lo inactive -C>* 127.0.0.0/8 is directly connected, lo -C>* 192.168.0.0/24 is directly connected, eth0 - -quagga-pimd-router# sh ip route 1.1.1.1 -Address NextHop Interface Metric Preference -1.1.1.1 127.0.0.1 lo 0 0 -quagga-pimd-router# -quagga-pimd-router# sh ip route 2.2.2.2 -Address NextHop Interface Metric Preference -2.2.2.2 192.168.0.2 eth0 0 0 -quagga-pimd-router# - -T27 DONE Implement debug command - test pim receive assert - See also TODO T6: (S,G) Assert state machine. - -T28 DONE Bad IPv4 address family=02 in Join/Prune dump - Reported by Andrew Lunn - - # 58-byte pim v2 Join/Prune dump - # ------------------------------ - # IPv4 address family=02 is wrong, correct IPv4 address family is 01 - # See http://www.iana.org/assignments/address-family-numbers - # - c8XX YY03 : ip src 200.xx.yy.3 - e000 000d : ip dst 224.0.0.13 - 9404 0000 : ip router alert option 148.4.0.0 - 2300 ab13 : pimv2,type=3 res=00 checksum=ab13 - 0200 : upstream family=02, encoding=00 - c8XX YY08 : upstream 200.xx.yy.8 - 0001 00d2 : res=00 groups=01 holdtime=00d2 - 0200 0020 : group family=02, encoding=00, res=00, mask_len=20 - ef01 0101 : group address 239.1.1.1 - 0001 0000 : joined=0001 pruned=0000 - 0200 0020 : source family=02, encoding=00, res=00, mask_len=20 - 0101 0101 : source address 1.1.1.1 - -T29 DONE Reset interface PIM-hello-sent counter when primary address changes - See pim_ifp->pim_ifstat_hello_sent - - RFC 4601: 4.3.1. Sending Hello Messages - - Thus, if a router needs to send a Join/Prune or Assert message on - an interface on which it has not yet sent a Hello message with the - currently configured IP address, then it MUST immediately send the - relevant Hello message without waiting for the Hello Timer to - expire, followed by the Join/Prune or Assert message. - -T30 DONE Run interface DR election when primary address changes - Reported by Andrew Lunn - See pim_if_dr_election(). - -T31 If an interface changes one of its secondary IP addresses, a Hello +T2 If an interface changes one of its secondary IP addresses, a Hello message with an updated Address_List option and a non-zero HoldTime should be sent immediately. See also detect_secondary_address_change See also CAVEAT C15. See also RFC 4601: 4.3.1. Sending Hello Messages -T32 FIXED Detection of interface primary address changes may fail when - there are multiple addresses. - See also CAVEAT C14. - - pim_find_primary_addr() should return interface primary address - from connected list. Currently it returns the first address. - - Zebra daemon "show int" is able to keep the primary address as - first address. - -T33 DONE Implement debug command: test pim receive upcall - See also TODO T6: (S,G) Assert state machine. - -T34 DONE assert_action_a1 - -T35 DONE Review macros depending on interface I. - - See also: grep ,I\) pimd/*.c - - For the case (S,G,I) check if I is either - 1) interface attached to this per-interface S,G state (don't think so) - or - 2) an arbitrary interface (most probably) - - For the arbitrary interface case (2), consider representing - interface ifp as its primary address (struct in_addr ifaddr). The - benefit is in_addr does not need to be dereferenced, so it does - not demand protection against crashes. - -T36 DONE React to zebra daemon link-detect up/down notification. - pim_ifp->primary_address is managed by detect_primary_address_change() - depending on to ifp->connected (managed by zebra_interface_address_read()). - -T37 DONE Review list of variables which may affect pim_upstream.c - pim_upstream_evaluate_join_desired(). - Call pim_upstream_update_join_desired() accordingly. - - See the order of invokation: - pim_if_dr_election(ifp); - pim_if_update_join_desired(pim_ifp); /* depends on DR */ - pim_if_update_could_assert(ifp); /* depends on DR */ - pim_if_update_my_assert_metric(ifp); /* depends on could_assert */ - - join_desired depends on: - pim_ifp->primary_address - pim_ifp->pim_dr_addr - ch->ifassert_winner_metric - ch->ifassert_winner - ch->local_ifmembership - ch->ifjoin_state - ch->upstream->rpf.source_nexthop.mrib_metric_preference - ch->upstream->rpf.source_nexthop.mrib_route_metric - ch->upstream->rpf.source_nexthop.interface - -T38 DONE Detect change in AssertTrackingDesired(S,G,I) - - See the order of invokation: - dr_election: none - update_join_desired: depends on DR - update_tracking_desired: depends on DR, join_desired - - AssertTrackingDesired(S,G,I) depends on: - pim_ifp->primary_address - pim_ifp->pim_dr_addr - ch->local_ifmembership - ch->ifassert_winner - ch->ifjoin_state - ch->upstream->rpf.source_nexthop.interface - PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(ch->upstream->flags) - -T39 DONE AssertTrackingDesired: flags is not matching evaluation - - # show ip pim assert-internal - CA: CouldAssert - ECA: Evaluate CouldAssert - ATD: AssertTrackingDesired - eATD: Evaluate AssertTrackingDesired - - Interface Address Source Group CA eCA ATD eATD - eth0 192.168.1.100 1.1.1.1 239.1.1.1 no no no yes - # - -T40 Lightweight MLDv2 +T3 Lightweight MLDv2 http://tools.ietf.org/html/draft-ietf-mboned-lightweight-igmpv3-mldv2-05 http://www.ietf.org/internet-drafts/draft-ietf-mboned-lightweight-igmpv3-mldv2-05.txt http://www.ietf.org/html.charters/mboned-charter.html -T41 DONE ssmping support - - See also: - http://www.venaas.no/multicast/ssmping/ - draft-ietf-mboned-ssmping-07 - http://tools.ietf.org/html/draft-ietf-mboned-ssmping-07 - - Example: - - debug ssmpingd - - conf t - ip ssmpingd 1.1.1.1 - - show ip ssmpingd - -T42 Static igmp join fails when loading config at boot time +T4 Static igmp join fails when loading config at boot time ! Wrong behavior seen at boot time: ! @@ -396,7 +42,7 @@ T42 Static igmp join fails when loading config at boot time eth0 200.202.112.3 2 2 0 0 0 0 lo 127.0.0.1 1 1 0 0 0 0 -T43 PIM Neighbor Reduction +T5 PIM Neighbor Reduction https://datatracker.ietf.org/doc/draft-wijnands-pim-neighbor-reduction/ "In a transit LAN (no directly connected source or receiver), many @@ -404,19 +50,19 @@ T43 PIM Neighbor Reduction a procedure to reduce the amount of neighbors established over a transit LAN." -T44 Single Stream Multicast Fast Reroute (SMFR) Method +T6 Single Stream Multicast Fast Reroute (SMFR) Method https://datatracker.ietf.org/doc/draft-liu-pim-single-stream-multicast-frr/ "This document proposes an IP multicast fast convergence method based on differentiating primary and backup PIM join." -T45 RFC5384 - The Join Attribute Format +T7 RFC5384 - The Join Attribute Format "This document describes a modification of the Join message that allows a node to associate attributes with a particular tree." -T46 PIM Multi-Topology ID (MT-ID) Join-Attribute +T8 PIM Multi-Topology ID (MT-ID) Join-Attribute http://tools.ietf.org/html/draft-cai-pim-mtid-00 - Depends on T45. + Depends on T7. "This draft introduces a new type of PIM Join Attribute used to encode the identity of the topology PIM uses for RPF." From a3896844153e8f0105dc33e007805650af42185d Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 26 Feb 2018 21:44:47 -0500 Subject: [PATCH 13/25] sharpd: Allow sharp routes to recurse When passing in a sharp route, allow the nexthop choosen to recurse to find a match. Signed-off-by: Donald Sharp --- sharpd/sharp_zebra.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index 3b22db20aa..f02ce4979c 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -169,6 +169,7 @@ void route_add(struct prefix *p, struct nexthop *nh) api.safi = SAFI_UNICAST; memcpy(&api.prefix, p, sizeof(*p)); + SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION); SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); api_nh = &api.nexthops[0]; From 7666589034ef51aa56e8530031c7fa08f81f4c58 Mon Sep 17 00:00:00 2001 From: Olivier Dugeon Date: Fri, 9 Feb 2018 12:06:35 +0100 Subject: [PATCH 14/25] ospfd: Add json output for Segment Routing - To ease checking the Segment Routing conformity in topotest, add json output to 'show ip ospf database segment-routing' CLI. - Update ospfd user guide accordingly - Update OSPF-SR documentation with supported features and interoperability Signed-off-by: Olivier Dugeon --- doc/OSPF-SR.rst | 23 ++++- doc/ospfd.texi | 7 +- ospfd/ospf_sr.c | 248 +++++++++++++++++++++++++++++++++++++----------- 3 files changed, 219 insertions(+), 59 deletions(-) diff --git a/doc/OSPF-SR.rst b/doc/OSPF-SR.rst index 0ee1a12f28..299a7e1c87 100644 --- a/doc/OSPF-SR.rst +++ b/doc/OSPF-SR.rst @@ -5,6 +5,26 @@ This is an EXPERIMENTAL support of draft `draft-ietf-ospf-segment-routing-extensions-24`. DON'T use it for production network. +Supported Features +------------------ + +* Automatic computation of Primary and Backup Adjacency SID with + Cisco experimental remote IP address +* SRGB configuration +* Prefix configuration for Node SID with optional NO-PHP flag (Linux + kernel support both mode) +* Node MSD configuration (with Linux Kernel >= 4.10 a maximum of 32 labels + could be stack) +* Automatic provisioning of MPLS table +* Static route configuration with label stack up to 32 labels + +Interoperability +---------------- + +* tested on various topology including point-to-point and LAN interfaces + in a mix of Free Range Routing instance and Cisco IOS-XR 6.0.x +* check OSPF LSA conformity with latest wireshark release 2.5.0-rc + Implementation details ---------------------- @@ -248,9 +268,6 @@ Known limitations * MPLS table are not flush at startup. Thus, restarting zebra process is mandatory to remove old MPLS entries in the data plane after a crash of ospfd daemon -* Due to a bug in OSPF Opaque, LSA are not flood when enable Segment Routing - through CLI once OSPFd started. You must configure Segment Routing within - configuration file before launching OSPFd * With NO Penultimate Hop Popping, it is not possible to express a Segment Path with an Adjacency SID due to the impossibility for the Linux Kernel to perform double POP instruction. diff --git a/doc/ospfd.texi b/doc/ospfd.texi index 33341d2be6..9694be1efe 100644 --- a/doc/ospfd.texi +++ b/doc/ospfd.texi @@ -759,10 +759,11 @@ currently supported. The 'no-php-flag' means NO Penultimate Hop Popping that allows SR node to request to its neighbor to not pop the label. @end deffn -@deffn {Command} {show ip ospf database segment-routing} {} -@deffnx {Command} {show ip ospf database segment-routing adv-router @var{adv-router}} {} -@deffnx {Command} {show ip ospf database segment-routing self-originate} {} +@deffn {Command} {show ip ospf database segment-routing [json]} {} +@deffnx {Command} {show ip ospf database segment-routing adv-router @var{adv-router} [json]} {} +@deffnx {Command} {show ip ospf database segment-routing self-originate [json]} {} Show Segment Routing Data Base, all SR nodes, specific advertized router or self router. +Optional Json output could be obtain by adding 'json' at the end of the command. @end deffn @node Debugging OSPF diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c index 1560977ae8..2944c8b09a 100644 --- a/ospfd/ospf_sr.c +++ b/ospfd/ospf_sr.c @@ -47,6 +47,7 @@ #include "thread.h" #include "vty.h" #include "zclient.h" +#include #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" @@ -2128,91 +2129,197 @@ DEFUN (no_sr_prefix_sid, -static void show_vty_sr_node(struct vty *vty, struct sr_node *srn) +static void show_sr_node(struct vty *vty, struct json_object *json, + struct sr_node *srn) { struct listnode *node; struct sr_link *srl; struct sr_prefix *srp; struct interface *itf; - char pref[16]; + char pref[19]; char sid[22]; char label[8]; + json_object *json_node = NULL, *json_algo, *json_obj; + json_object *json_prefix = NULL, *json_link = NULL; /* Sanity Check */ if (srn == NULL) return; - vty_out(vty, "SR-Node: %s", inet_ntoa(srn->adv_router)); - vty_out(vty, "\tSRGB (Size/Label): %u/%u", srn->srgb.range_size, - srn->srgb.lower_bound); - vty_out(vty, "\tAlgorithm(s): %s", - srn->algo[0] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF"); - for (int i = 1; i < ALGORITHM_COUNT; i++) { - if (srn->algo[i] == SR_ALGORITHM_UNSET) - continue; - vty_out(vty, "/%s", - srn->algo[i] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF"); - } - if (srn->msd != 0) - vty_out(vty, "\tMSD: %u", srn->msd); + if (json) { + json_node = json_object_new_object(); + json_object_string_add(json_node, "routerID", + inet_ntoa(srn->adv_router)); + json_object_int_add(json_node, "srgbSize", + srn->srgb.range_size); + json_object_int_add(json_node, "srgbLabel", + srn->srgb.lower_bound); + json_algo = json_object_new_array(); + json_object_object_add(json_node, "algorithms", json_algo); + for (int i = 0; i < ALGORITHM_COUNT; i++) { + if (srn->algo[i] == SR_ALGORITHM_UNSET) + continue; + json_obj = json_object_new_object(); + char tmp[2]; - vty_out(vty, - "\n\n Prefix or Link Label In Label Out " - "Node or Adj. SID Interface Nexthop\n"); - vty_out(vty, - "------------------ -------- --------- " - "--------------------- --------- ---------------\n"); + snprintf(tmp, 2, "%u", i); + json_object_string_add(json_obj, tmp, + srn->algo[i] == SR_ALGORITHM_SPF ? + "SPF" : "S-SPF"); + json_object_array_add(json_algo, json_obj); + } + if (srn->msd != 0) + json_object_int_add(json_node, "nodeMsd", srn->msd); + } else { + vty_out(vty, "SR-Node: %s", inet_ntoa(srn->adv_router)); + vty_out(vty, "\tSRGB (Size/Label): %u/%u", + srn->srgb.range_size, srn->srgb.lower_bound); + vty_out(vty, "\tAlgorithm(s): %s", + srn->algo[0] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF"); + for (int i = 1; i < ALGORITHM_COUNT; i++) { + if (srn->algo[i] == SR_ALGORITHM_UNSET) + continue; + vty_out(vty, "/%s", + srn->algo[i] == SR_ALGORITHM_SPF ? + "SPF" : "S-SPF"); + } + if (srn->msd != 0) + vty_out(vty, "\tMSD: %u", srn->msd); + } + + if (!json) { + vty_out(vty, + "\n\n Prefix or Link Label In Label Out " + "Node or Adj. SID Interface Nexthop\n"); + vty_out(vty, + "------------------ -------- --------- " + "--------------------- --------- ---------------\n"); + } for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) { - strncpy(pref, inet_ntoa(srp->nhlfe.prefv4.prefix), 16); + snprintf(pref, 19, "%s/%u", + inet_ntoa(srp->nhlfe.prefv4.prefix), + srp->nhlfe.prefv4.prefixlen); snprintf(sid, 22, "SR Pfx (idx %u)", srp->sid); if (srp->nhlfe.label_out == MPLS_LABEL_IMPLICIT_NULL) sprintf(label, "pop"); else sprintf(label, "%u", srp->nhlfe.label_out); itf = if_lookup_by_index(srp->nhlfe.ifindex, VRF_DEFAULT); - vty_out(vty, "%15s/%u %8u %9s %21s %9s %15s\n", pref, - srp->nhlfe.prefv4.prefixlen, srp->nhlfe.label_in, label, - sid, itf ? itf->name : "-", - inet_ntoa(srp->nhlfe.nexthop)); + if (json) { + if (!json_prefix) { + json_prefix = json_object_new_array(); + json_object_object_add(json_node, + "extendedPrefix", json_prefix); + } + json_obj = json_object_new_object(); + json_object_string_add(json_obj, "prefix", pref); + json_object_int_add(json_obj, "sid", srp->sid); + json_object_int_add(json_obj, "inputLabel", + srp->nhlfe.label_in); + json_object_string_add(json_obj, "outputLabel", + label); + json_object_string_add(json_obj, "interface", + itf ? itf->name : "-"); + json_object_string_add(json_obj, "nexthop", + inet_ntoa(srp->nhlfe.nexthop)); + json_object_array_add(json_prefix, json_obj); + } else { + vty_out(vty, "%18s %8u %9s %21s %9s %15s\n", + pref, srp->nhlfe.label_in, label, + sid, itf ? itf->name : "-", + inet_ntoa(srp->nhlfe.nexthop)); + } } for (ALL_LIST_ELEMENTS_RO(srn->ext_link, node, srl)) { - strncpy(pref, inet_ntoa(srl->nhlfe[0].prefv4.prefix), 16); + snprintf(pref, 19, "%s/%u", + inet_ntoa(srl->nhlfe[0].prefv4.prefix), + srl->nhlfe[0].prefv4.prefixlen); snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[0]); if (srl->nhlfe[0].label_out == MPLS_LABEL_IMPLICIT_NULL) sprintf(label, "pop"); else sprintf(label, "%u", srl->nhlfe[0].label_out); itf = if_lookup_by_index(srl->nhlfe[0].ifindex, VRF_DEFAULT); - vty_out(vty, "%15s/%u %8u %9s %21s %9s %15s\n", pref, - srl->nhlfe[0].prefv4.prefixlen, srl->nhlfe[0].label_in, - label, sid, itf ? itf->name : "-", - inet_ntoa(srl->nhlfe[0].nexthop)); - snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[1]); - if (srl->nhlfe[1].label_out == MPLS_LABEL_IMPLICIT_NULL) - sprintf(label, "pop"); - else - sprintf(label, "%u", srl->nhlfe[0].label_out); - vty_out(vty, "%15s/%u %8u %9s %21s %9s %15s\n", pref, - srl->nhlfe[1].prefv4.prefixlen, srl->nhlfe[1].label_in, - label, sid, itf ? itf->name : "-", - inet_ntoa(srl->nhlfe[1].nexthop)); + if (json) { + if (!json_link) { + json_link = json_object_new_array(); + json_object_object_add(json_node, + "extendedLink", json_link); + } + /* Primary Link */ + json_obj = json_object_new_object(); + json_object_string_add(json_obj, "prefix", pref); + json_object_int_add(json_obj, "sid", srl->sid[0]); + json_object_int_add(json_obj, "inputLabel", + srl->nhlfe[0].label_in); + json_object_string_add(json_obj, "outputLabel", + label); + json_object_string_add(json_obj, "interface", + itf ? itf->name : "-"); + json_object_string_add(json_obj, "nexthop", + inet_ntoa(srl->nhlfe[0].nexthop)); + json_object_array_add(json_link, json_obj); + /* Backup Link */ + json_obj = json_object_new_object(); + snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[1]); + if (srl->nhlfe[1].label_out == MPLS_LABEL_IMPLICIT_NULL) + sprintf(label, "pop"); + else + sprintf(label, "%u", srl->nhlfe[0].label_out); + json_object_string_add(json_obj, "prefix", pref); + json_object_int_add(json_obj, "sid", srl->sid[1]); + json_object_int_add(json_obj, "inputLabel", + srl->nhlfe[1].label_in); + json_object_string_add(json_obj, "outputLabel", + label); + json_object_string_add(json_obj, "interface", + itf ? itf->name : "-"); + json_object_string_add(json_obj, "nexthop", + inet_ntoa(srl->nhlfe[1].nexthop)); + json_object_array_add(json_link, json_obj); + } else { + vty_out(vty, "%18s %8u %9s %21s %9s %15s\n", + pref, srl->nhlfe[0].label_in, + label, sid, itf ? itf->name : "-", + inet_ntoa(srl->nhlfe[0].nexthop)); + snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[1]); + if (srl->nhlfe[1].label_out == MPLS_LABEL_IMPLICIT_NULL) + sprintf(label, "pop"); + else + sprintf(label, "%u", srl->nhlfe[1].label_out); + vty_out(vty, "%18s %8u %9s %21s %9s %15s\n", + pref, srl->nhlfe[1].label_in, + label, sid, itf ? itf->name : "-", + inet_ntoa(srl->nhlfe[1].nexthop)); + } } - vty_out(vty, "\n"); + if (json) + json_object_array_add(json, json_node); + else + vty_out(vty, "\n"); } -static void show_srdb_entry(struct hash_backet *backet, void *args) +static void show_vty_srdb(struct hash_backet *backet, void *args) { struct vty *vty = (struct vty *)args; struct sr_node *srn = (struct sr_node *)backet->data; - show_vty_sr_node(vty, srn); + show_sr_node(vty, NULL, srn); +} + +static void show_json_srdb(struct hash_backet *backet, void *args) +{ + struct json_object *json = (struct json_object *)args; + struct sr_node *srn = (struct sr_node *)backet->data; + + show_sr_node(NULL, json, srn); } DEFUN (show_ip_opsf_srdb, show_ip_ospf_srdb_cmd, - "show ip ospf database segment-routing [adv-router A.B.C.D|self-originate]", + "show ip ospf database segment-routing [adv-router A.B.C.D|self-originate] [json]", SHOW_STR IP_STR OSPF_STR @@ -2220,23 +2327,41 @@ DEFUN (show_ip_opsf_srdb, "Show Segment Routing Data Base\n" "Advertising SR node\n" "Advertising SR node ID (as an IP address)\n" - "Self-originated SR node\n") + "Self-originated SR node\n" + JSON_STR) { int idx = 0; struct in_addr rid; struct sr_node *srn; + u_char uj = use_json(argc, argv); + json_object *json = NULL, *json_node_array = NULL; if (!OspfSR.enabled) { vty_out(vty, "Segment Routing is disabled on this router\n"); return CMD_WARNING; } - vty_out(vty, "\n OSPF Segment Routing database for ID %s\n\n", - inet_ntoa(OspfSR.self->adv_router)); + if (uj) { + json = json_object_new_object(); + json_node_array = json_object_new_array(); + json_object_string_add(json, "srdbID", + inet_ntoa(OspfSR.self->adv_router)); + json_object_object_add(json, "srNodes", json_node_array); + } else { + vty_out(vty, + "\n\t\tOSPF Segment Routing database for ID %s\n\n", + inet_ntoa(OspfSR.self->adv_router)); + } if (argv_find(argv, argc, "self-originate", &idx)) { srn = OspfSR.self; - show_vty_sr_node(vty, srn); + show_sr_node(vty, json_node_array, srn); + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext(json, + JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } return CMD_SUCCESS; } @@ -2250,15 +2375,32 @@ DEFUN (show_ip_opsf_srdb, /* Get the SR Node from the SRDB */ srn = (struct sr_node *)hash_lookup(OspfSR.neighbors, (void *)&rid); - show_vty_sr_node(vty, srn); + show_sr_node(vty, json_node_array, srn); + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext(json, + JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } return CMD_SUCCESS; } /* No parameters have been provided, Iterate through all the SRDB */ - hash_iterate( - OspfSR.neighbors, - (void (*)(struct hash_backet *, void *))show_srdb_entry, - (void *)vty); + if (uj) { + hash_iterate( + OspfSR.neighbors, + (void (*)(struct hash_backet *, void *))show_json_srdb, + (void *)json_node_array); + vty_out(vty, "%s\n", + json_object_to_json_string_ext(json, + JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } else { + hash_iterate( + OspfSR.neighbors, + (void (*)(struct hash_backet *, void *))show_vty_srdb, + (void *)vty); + } return CMD_SUCCESS; } From 4ca997a8f82e442ef3e28a8ae14c0b914adc5e4a Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 28 Feb 2018 18:53:44 -0500 Subject: [PATCH 15/25] lib: Use STREAM_GET The addition of some rmac code snuck in the usage of a stream_get instead of a STREAM_GET() We need to be using STREAM_GET() Signed-off-by: Donald Sharp --- lib/zclient.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/zclient.c b/lib/zclient.c index ad91eb504b..01d8838e1f 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1085,7 +1085,7 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api) STREAM_GETC(s, api->message); STREAM_GETC(s, api->safi); if (CHECK_FLAG(api->flags, ZEBRA_FLAG_EVPN_ROUTE)) - stream_get(&(api->rmac), s, sizeof(struct ethaddr)); + STREAM_GET(&(api->rmac), s, sizeof(struct ethaddr)); /* Prefix. */ STREAM_GETC(s, api->prefix.family); From c7bacffe4618f27f45edb954426257c6f935d716 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 28 Feb 2018 18:55:10 -0500 Subject: [PATCH 16/25] zebra: Use the passed in nexthops vrf When decoding and creating the appropriate data structures for a nexthop, use the passed in vrf. Signed-off-by: Donald Sharp --- zebra/zserv.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/zebra/zserv.c b/zebra/zserv.c index 98cb54f7b8..bca8a509d8 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -1166,12 +1166,12 @@ static int zread_route_add(struct zserv *client, u_short length, switch (api_nh->type) { case NEXTHOP_TYPE_IFINDEX: nexthop = route_entry_nexthop_ifindex_add( - re, api_nh->ifindex, re->vrf_id); + re, api_nh->ifindex, api_nh->vrf_id); break; case NEXTHOP_TYPE_IPV4: nexthop = route_entry_nexthop_ipv4_add( re, &api_nh->gate.ipv4, NULL, - re->vrf_id); + api_nh->vrf_id); break; case NEXTHOP_TYPE_IPV4_IFINDEX: { @@ -1188,7 +1188,7 @@ static int zread_route_add(struct zserv *client, u_short length, nexthop = route_entry_nexthop_ipv4_ifindex_add( re, &api_nh->gate.ipv4, NULL, ifindex, - re->vrf_id); + api_nh->vrf_id); /* if this an EVPN route entry, program the nh as neigh @@ -1211,12 +1211,12 @@ static int zread_route_add(struct zserv *client, u_short length, } case NEXTHOP_TYPE_IPV6: nexthop = route_entry_nexthop_ipv6_add( - re, &api_nh->gate.ipv6, re->vrf_id); + re, &api_nh->gate.ipv6, api_nh->vrf_id); break; case NEXTHOP_TYPE_IPV6_IFINDEX: nexthop = route_entry_nexthop_ipv6_ifindex_add( re, &api_nh->gate.ipv6, api_nh->ifindex, - re->vrf_id); + api_nh->vrf_id); break; case NEXTHOP_TYPE_BLACKHOLE: nexthop = route_entry_nexthop_blackhole_add( From 1374aec98ff77fb02b7a7dba88d6a10fd8058196 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 28 Feb 2018 19:10:02 -0500 Subject: [PATCH 17/25] bgpd: Cleanup api_nh in bgpd a bit The api_nh was being figured 2 times, also refactor the vrf_id placement as well. Signed-off-by: Donald Sharp : --- bgpd/bgp_zebra.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index daa7ccbf42..029b3d4d36 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1054,6 +1054,9 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, else continue; + api_nh = &api.nexthops[valid_nh_count]; + api_nh->vrf_id = bgp->vrf_id; + if (nh_family == AF_INET) { struct in_addr *nexthop; @@ -1078,9 +1081,7 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, nexthop = &mpinfo_cp->attr->nexthop; - api_nh = &api.nexthops[valid_nh_count]; api_nh->gate.ipv4 = *nexthop; - api_nh->vrf_id = bgp->vrf_id; /* EVPN type-2 routes are programmed as onlink on l3-vni SVI */ @@ -1135,7 +1136,6 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, if (ifindex == 0) continue; - api_nh = &api.nexthops[valid_nh_count]; api_nh->gate.ipv6 = *nexthop; api_nh->ifindex = ifindex; api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX; From f56ee10fc7a4c028e767161c2503d26cceed194b Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 28 Feb 2018 19:16:51 -0500 Subject: [PATCH 18/25] ospfd: Add vrf to nhlfe route add So when a ospf SR is sending down routes to the kernel ensure that the nexthop vrf_id is set appropriately. Yes SR is in the default VRF. But for people who run across this code in the future, they will know to do the right thing from it. Signed-off-by: Donald Sharp --- ospfd/ospf_sr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c index 1560977ae8..02cf2636cc 100644 --- a/ospfd/ospf_sr.c +++ b/ospfd/ospf_sr.c @@ -675,6 +675,7 @@ static int ospf_zebra_send_mpls_ftn(int cmd, struct sr_nhlfe nhlfe) SET_FLAG(api.message, ZAPI_MESSAGE_LABEL); api_nh->labels[0] = nhlfe.label_out; api_nh->label_num = 1; + api_nh->vrf_id = VRF_DEFAULT; api.nexthop_num = 1; } From 05dd5aaf021e2e483ba44872cae4446b0073c1de Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 28 Feb 2018 19:22:47 -0500 Subject: [PATCH 19/25] lib, zebra: Add type and instance to nexthop update message Add the originating routes type and instance to the nexthop update message. This is necessary because there exist scenarios where BGP needs to make a decision about the originating route type and instance to know if it is going to be doing a route replace to a route that would resolve to itself. Signed-off-by: Donald Sharp --- lib/zclient.c | 2 ++ zebra/zebra_rnh.c | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/lib/zclient.c b/lib/zclient.c index ad91eb504b..09c3abc148 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1266,6 +1266,8 @@ bool zapi_nexthop_update_decode(struct stream *s, struct zapi_route *nhr) break; } + STREAM_GETC(s, nhr->type); + STREAM_GETW(s, nhr->instance); STREAM_GETC(s, nhr->distance); STREAM_GETL(s, nhr->metric); STREAM_GETC(s, nhr->nexthop_num); diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 9fc5afff0f..d960dbd937 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -1019,6 +1019,8 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type, break; } if (re) { + stream_putc(s, re->type); + stream_putw(s, re->instance); stream_putc(s, re->distance); stream_putl(s, re->metric); num = 0; @@ -1054,6 +1056,8 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type, } stream_putc_at(s, nump, num); } else { + stream_putc(s, 0); // type + stream_putw(s, 0); // instance stream_putc(s, 0); // distance stream_putl(s, 0); // metric stream_putc(s, 0); // nexthops From 07b37f93a7e5670b7a25e66a29a7363640005027 Mon Sep 17 00:00:00 2001 From: Chirag Shah Date: Wed, 14 Feb 2018 19:02:11 -0800 Subject: [PATCH 20/25] ospf6d: ECMP for external routes The route being added check its origin matches, with any of the existing path (list of paths). Remove the existing path, add if its cost is eqaual or less than any of the existing path. For a given route and of existing path cost is lower (better) than one being added, discard new route update. The existing path cost is higher (lower) than one being added, ospf6_route_add replaces existing with new route info. Compare cost between delete request and with existing route. Ticket:CM-16139 Signed-off-by: Chirag Shah --- ospf6d/ospf6_asbr.c | 267 +++++++++++++++++++++++++++++++++++++------ ospf6d/ospf6_asbr.h | 3 +- ospf6d/ospf6_route.c | 26 +++-- ospf6d/ospf6_top.c | 25 ++-- 4 files changed, 266 insertions(+), 55 deletions(-) diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 11f9e7c7b6..b52f1cef6c 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -204,26 +204,142 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old, { struct ospf6_route *old_route; struct ospf6_path *ecmp_path, *o_path = NULL; - struct listnode *anode; + struct listnode *anode, *anext; struct listnode *nnode, *rnode, *rnext; struct ospf6_nexthop *nh, *rnh; char buf[PREFIX2STR_BUFFER]; bool route_found = false; + /* check for old entry match with new route origin, + * delete old entry. + */ for (old_route = old; old_route; old_route = old_route->next) { - if (ospf6_route_is_same(old_route, route) && - (old_route->path.type == route->path.type) && - (old_route->path.cost == route->path.cost) && - (old_route->path.u.cost_e2 == route->path.u.cost_e2)) { + bool route_updated = false; + + if (!ospf6_route_is_same(old_route, route) || + (old_route->path.type != route->path.type)) + continue; + + /* Current and New route has same origin, + * delete old entry. + */ + for (ALL_LIST_ELEMENTS(old_route->paths, anode, anext, + o_path)) { + /* Check old route path and route has same + * origin. + */ + if (o_path->area_id != route->path.area_id || + (memcmp(&(o_path)->origin, &(route)->path.origin, + sizeof(struct ospf6_ls_origin)) != 0)) + continue; + + /* Cost is not same then delete current path */ + if ((o_path->cost == route->path.cost) && + (o_path->u.cost_e2 == route->path.u.cost_e2)) + continue; if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { prefix2str(&old_route->prefix, buf, sizeof(buf)); - zlog_debug("%s: old route %s path cost %u [%u]", + zlog_debug("%s: route %s cost old %u new %u is not same, replace route", + __PRETTY_FUNCTION__, buf, + o_path->cost, route->path.cost); + } + + /* Remove selected current rout path's nh from + * effective nh list. + */ + for (ALL_LIST_ELEMENTS_RO(o_path->nh_list, nnode, nh)) { + for (ALL_LIST_ELEMENTS(old_route->nh_list, + rnode, rnext, rnh)) { + if (!ospf6_nexthop_is_same(rnh, nh)) + continue; + listnode_delete(old_route->nh_list, + rnh); + ospf6_nexthop_delete(rnh); + route_updated = true; + } + } + + listnode_delete(old_route->paths, o_path); + ospf6_path_free(o_path); + + /* Current route's path (adv_router info) is similar + * to route being added. + * Replace current route's path with paths list head. + * Update FIB with effective NHs. + */ + if (listcount(old_route->paths)) { + if (old_route->path.origin.id == + route->path.origin.id && + old_route->path.origin.adv_router == + route->path.origin.adv_router) { + struct ospf6_path *h_path; + + h_path = (struct ospf6_path *) + listgetdata(listhead(old_route->paths)); + old_route->path.origin.type = + h_path->origin.type; + old_route->path.origin.id = + h_path->origin.id; + old_route->path.origin.adv_router = + h_path->origin.adv_router; + } + + if (route_updated) { + for (ALL_LIST_ELEMENTS(old_route->paths, + anode, anext, o_path)) { + ospf6_merge_nexthops( + old_route->nh_list, + o_path->nh_list); + } + /* Update RIB/FIB with effective + * nh_list + */ + if (ospf6->route_table->hook_add) + (*ospf6->route_table->hook_add) + (old_route); + break; + } + } else { + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { + prefix2str(&old_route->prefix, buf, + sizeof(buf)); + zlog_debug("%s: route %s old cost %u new cost %u, delete old entry.", + __PRETTY_FUNCTION__, buf, + old_route->path.cost, + route->path.cost); + } + ospf6_route_remove(old_route, + ospf6->route_table); + break; + } + } + if (route_updated) + break; + } + + /* Add new route */ + for (old_route = old; old_route; old_route = old_route->next) { + + /* Current and New Route prefix or route type + * is not same skip this current node. + */ + if (!ospf6_route_is_same(old_route, route) || + (old_route->path.type != route->path.type)) + continue; + + /* Old Route and New Route have Equal Cost, Merge NHs */ + if ((old_route->path.cost == route->path.cost) && + (old_route->path.u.cost_e2 == route->path.u.cost_e2)) { + + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { + prefix2str(&old_route->prefix, buf, + sizeof(buf)); + zlog_debug("%s: old route %s path cost %u e2 %u", __PRETTY_FUNCTION__, buf, old_route->path.cost, - ospf6_route_is_same(old_route, - route)); + old_route->path.u.cost_e2); } route_found = true; /* check if this path exists already in @@ -232,9 +348,10 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old, */ for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode, o_path)) { - if ((o_path->origin.id == route->path.origin.id) - && (o_path->origin.adv_router == - route->path.origin.adv_router)) + if (o_path->area_id == route->path.area_id && + (memcmp(&(o_path)->origin, + &(route)->path.origin, + sizeof(struct ospf6_ls_origin)) == 0)) break; } /* If path is not found in old_route paths's list, @@ -262,12 +379,13 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old, if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { prefix2str(&route->prefix, buf, sizeof(buf)); - zlog_debug("%s: route %s another path added with nh %u, Paths %u", + zlog_debug("%s: route %s another path added with nh %u, effective paths %u nh %u", __PRETTY_FUNCTION__, buf, listcount(ecmp_path->nh_list), old_route->paths ? listcount(old_route->paths) - : 0); + : 0, + listcount(old_route->nh_list)); } } else { for (ALL_LIST_ELEMENTS_RO(o_path->nh_list, @@ -313,6 +431,7 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old, * route. */ ospf6_route_delete(route); + break; } } @@ -426,11 +545,12 @@ void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa) } -void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa) +void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa, + struct ospf6_route *asbr_entry) { struct ospf6_as_external_lsa *external; struct prefix prefix; - struct ospf6_route *route, *nroute; + struct ospf6_route *route, *nroute, *route_to_del; char buf[PREFIX2STR_BUFFER]; external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END( @@ -445,6 +565,35 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa) return; } + route_to_del = ospf6_route_create(); + route_to_del->type = OSPF6_DEST_TYPE_NETWORK; + route_to_del->prefix.family = AF_INET6; + route_to_del->prefix.prefixlen = external->prefix.prefix_length; + ospf6_prefix_in6_addr(&route_to_del->prefix.u.prefix6, + &external->prefix); + + route_to_del->path.origin.type = lsa->header->type; + route_to_del->path.origin.id = lsa->header->id; + route_to_del->path.origin.adv_router = lsa->header->adv_router; + + if (asbr_entry) { + route_to_del->path.area_id = asbr_entry->path.area_id; + if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_E)) { + route_to_del->path.type = OSPF6_PATH_TYPE_EXTERNAL2; + route_to_del->path.metric_type = 2; + route_to_del->path.cost = asbr_entry->path.cost; + route_to_del->path.u.cost_e2 = + OSPF6_ASBR_METRIC(external); + } else { + route_to_del->path.type = OSPF6_PATH_TYPE_EXTERNAL1; + route_to_del->path.metric_type = 1; + route_to_del->path.cost = + asbr_entry->path.cost + + OSPF6_ASBR_METRIC(external); + route_to_del->path.u.cost_e2 = 0; + } + } + memset(&prefix, 0, sizeof(struct prefix)); prefix.family = AF_INET6; prefix.prefixlen = external->prefix.prefix_length; @@ -459,14 +608,25 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa) return; } - for (ospf6_route_lock(route); - route && ospf6_route_is_prefix(&prefix, route); route = nroute) { + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { + prefix2str(&prefix, buf, sizeof(buf)); + zlog_debug("%s: Current route %s cost %u e2 %u, route to del cost %u e2 %u", + __PRETTY_FUNCTION__, buf, route->path.cost, + route->path.u.cost_e2, + route_to_del->path.cost, + route_to_del->path.u.cost_e2); + } + + for (ospf6_route_lock(route); route && + ospf6_route_is_prefix(&prefix, route); route = nroute) { nroute = ospf6_route_next(route); + if (route->type != OSPF6_DEST_TYPE_NETWORK) continue; - /* Route has multiple ECMP paths remove, - * matching path and update effective route's nh list. + /* Route has multiple ECMP paths, remove matching + * path. Update current route's effective nh list + * after removal of one of the path. */ if (listcount(route->paths) > 1) { struct listnode *anode, *anext; @@ -481,18 +641,36 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa) */ for (ALL_LIST_ELEMENTS(route->paths, anode, anext, o_path)) { - if (o_path->origin.type != lsa->header->type) + if ((o_path->origin.type != lsa->header->type) + || (o_path->origin.adv_router != + lsa->header->adv_router) || + (o_path->origin.id != lsa->header->id)) continue; - if (o_path->origin.id != lsa->header->id) - continue; - if (o_path->origin.adv_router != - lsa->header->adv_router) + + /* Compare LSA cost with current + * route info. + */ + if (!asbr_entry && (o_path->cost != + route_to_del->path.cost || + o_path->u.cost_e2 != + route_to_del->path.u.cost_e2)) { + if (IS_OSPF6_DEBUG_EXAMIN( + AS_EXTERNAL)) { + prefix2str(&prefix, buf, + sizeof(buf)); + zlog_debug( + "%s: route %s to delete is not same, cost %u del cost %u. skip", + __PRETTY_FUNCTION__, buf, + route->path.cost, + route_to_del->path.cost); + } continue; + } if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { prefix2str(&prefix, buf, sizeof(buf)); zlog_debug( - "%s: route %s path found with nh %u", + "%s: route %s path found with nh %u to remove.", __PRETTY_FUNCTION__, buf, listcount(o_path->nh_list)); } @@ -542,13 +720,13 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa) listcount(route->nh_list)); } - /* Update RIB/FIB w/ effective nh_list */ + /* Update RIB/FIB with effective nh_list */ if (ospf6->route_table->hook_add) (*ospf6->route_table->hook_add)(route); - /* route's path is similar to lsa header, - * replace route's path with route's - * paths list head. + /* route's primary path is similar to LSA, + * replace route's primary path with + * route's paths list head. */ if (route->path.origin.id == lsa->header->id && route->path.origin.adv_router == @@ -568,12 +746,29 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa) continue; } else { - if (route->path.origin.type != lsa->header->type) + /* Compare LSA origin and cost with current route info. + * if any check fails skip del this route node. + */ + if (asbr_entry && (!ospf6_route_is_same_origin(route, + route_to_del) || + (route->path.type != route_to_del->path.type) || + (route->path.cost != route_to_del->path.cost) || + (route->path.u.cost_e2 != + route_to_del->path.u.cost_e2))) { + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { + prefix2str(&prefix, buf, sizeof(buf)); + zlog_debug("%s: route %s to delete is not same, cost %u del cost %u. skip", + __PRETTY_FUNCTION__, buf, + route->path.cost, + route_to_del->path.cost); + } continue; - if (route->path.origin.id != lsa->header->id) - continue; - if (route->path.origin.adv_router != - lsa->header->adv_router) + } + + if ((route->path.origin.type != lsa->header->type) || + (route->path.origin.adv_router != + lsa->header->adv_router) || + (route->path.origin.id != lsa->header->id)) continue; } if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { @@ -589,6 +784,8 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa) } if (route != NULL) ospf6_route_unlock(route); + + ospf6_route_delete(route_to_del); } void ospf6_asbr_lsentry_add(struct ospf6_route *asbr_entry) @@ -622,7 +819,7 @@ void ospf6_asbr_lsentry_remove(struct ospf6_route *asbr_entry) type = htons(OSPF6_LSTYPE_AS_EXTERNAL); router = ospf6_linkstate_prefix_adv_router(&asbr_entry->prefix); for (ALL_LSDB_TYPED_ADVRTR(ospf6->lsdb, type, router, lsa)) - ospf6_asbr_lsa_remove(lsa); + ospf6_asbr_lsa_remove(lsa, asbr_entry); } diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h index cc4f0272aa..bd160a6456 100644 --- a/ospf6d/ospf6_asbr.h +++ b/ospf6d/ospf6_asbr.h @@ -71,7 +71,8 @@ struct ospf6_as_external_lsa { } extern void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa); -extern void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa); +extern void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa, + struct ospf6_route *asbr_entry); extern void ospf6_asbr_lsentry_add(struct ospf6_route *asbr_entry); extern void ospf6_asbr_lsentry_remove(struct ospf6_route *asbr_entry); diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index 19eb9a3fe6..ef0a093d13 100644 --- a/ospf6d/ospf6_route.c +++ b/ospf6d/ospf6_route.c @@ -469,6 +469,8 @@ int ospf6_route_cmp(struct ospf6_route *ra, struct ospf6_route *rb) if (ra->path.type == OSPF6_PATH_TYPE_EXTERNAL2) { if (ra->path.u.cost_e2 != rb->path.u.cost_e2) return (ra->path.u.cost_e2 - rb->path.u.cost_e2); + else + return (ra->path.cost - rb->path.cost); } else { if (ra->path.cost != rb->path.cost) return (ra->path.cost - rb->path.cost); @@ -627,10 +629,10 @@ struct ospf6_route *ospf6_route_add(struct ospf6_route *route, if (ospf6_route_is_identical(old, route)) { if (IS_OSPF6_DEBUG_ROUTE(MEMORY)) zlog_debug( - "%s %p: route add %p: needless update of %p", + "%s %p: route add %p: needless update of %p old cost %u", ospf6_route_table_name(table), (void *)table, (void *)route, - (void *)old); + (void *)old, old->path.cost); else if (IS_OSPF6_DEBUG_ROUTE(TABLE)) zlog_debug("%s: route add: needless update", ospf6_route_table_name(table)); @@ -645,9 +647,10 @@ struct ospf6_route *ospf6_route_add(struct ospf6_route *route, } if (IS_OSPF6_DEBUG_ROUTE(MEMORY)) - zlog_debug("%s %p: route add %p: update of %p", + zlog_debug("%s %p: route add %p cost %u: update of %p old cost %u", ospf6_route_table_name(table), (void *)table, - (void *)route, (void *)old); + (void *)route, route->path.cost, (void *)old, + old->path.cost); else if (IS_OSPF6_DEBUG_ROUTE(TABLE)) zlog_debug("%s: route add: update", ospf6_route_table_name(table)); @@ -686,13 +689,14 @@ struct ospf6_route *ospf6_route_add(struct ospf6_route *route, if (prev || next) { if (IS_OSPF6_DEBUG_ROUTE(MEMORY)) zlog_debug( - "%s %p: route add %p: another path: prev %p, next %p node refcount %u", + "%s %p: route add %p cost %u: another path: prev %p, next %p node ref %u", ospf6_route_table_name(table), (void *)table, - (void *)route, (void *)prev, (void *)next, - node->lock); + (void *)route, route->path.cost, (void *)prev, + (void *)next, node->lock); else if (IS_OSPF6_DEBUG_ROUTE(TABLE)) - zlog_debug("%s: route add: another path found", - ospf6_route_table_name(table)); + zlog_debug("%s: route add cost %u: another path found", + ospf6_route_table_name(table), + route->path.cost); if (prev == NULL) prev = next->prev; @@ -814,9 +818,9 @@ void ospf6_route_remove(struct ospf6_route *route, prefix2str(&route->prefix, buf, sizeof(buf)); if (IS_OSPF6_DEBUG_ROUTE(MEMORY)) - zlog_debug("%s %p: route remove %p: %s refcount %u", + zlog_debug("%s %p: route remove %p: %s cost %u refcount %u", ospf6_route_table_name(table), (void *)table, - (void *)route, buf, route->lock); + (void *)route, buf, route->path.cost, route->lock); else if (IS_OSPF6_DEBUG_ROUTE(TABLE)) zlog_debug("%s: route remove: %s", ospf6_route_table_name(table), buf); diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 25d968fb68..afe2d7397b 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -72,7 +72,7 @@ static void ospf6_top_lsdb_hook_remove(struct ospf6_lsa *lsa) { switch (ntohs(lsa->header->type)) { case OSPF6_LSTYPE_AS_EXTERNAL: - ospf6_asbr_lsa_remove(lsa); + ospf6_asbr_lsa_remove(lsa, NULL); break; default: @@ -96,11 +96,16 @@ static void ospf6_top_route_hook_remove(struct ospf6_route *route) static void ospf6_top_brouter_hook_add(struct ospf6_route *route) { if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { - char buf[PREFIX2STR_BUFFER]; + uint32_t brouter_id; + char brouter_name[16]; - prefix2str(&route->prefix, buf, sizeof(buf)); - zlog_debug("%s: brouter %s add with nh count %u", - __PRETTY_FUNCTION__, buf, listcount(route->nh_list)); + brouter_id = ADV_ROUTER_IN_PREFIX(&route->prefix); + inet_ntop(AF_INET, &brouter_id, brouter_name, + sizeof(brouter_name)); + zlog_debug("%s: brouter %s add with adv router %x nh count %u", + __PRETTY_FUNCTION__, brouter_name, + route->path.origin.adv_router, + listcount(route->nh_list)); } ospf6_abr_examin_brouter(ADV_ROUTER_IN_PREFIX(&route->prefix)); ospf6_asbr_lsentry_add(route); @@ -110,11 +115,15 @@ static void ospf6_top_brouter_hook_add(struct ospf6_route *route) static void ospf6_top_brouter_hook_remove(struct ospf6_route *route) { if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { - char buf[PREFIX2STR_BUFFER]; + uint32_t brouter_id; + char brouter_name[16]; - prefix2str(&route->prefix, buf, sizeof(buf)); + brouter_id = ADV_ROUTER_IN_PREFIX(&route->prefix); + inet_ntop(AF_INET, &brouter_id, brouter_name, + sizeof(brouter_name)); zlog_debug("%s: brouter %s del with nh count %u", - __PRETTY_FUNCTION__, buf, listcount(route->nh_list)); + __PRETTY_FUNCTION__, brouter_name, + listcount(route->nh_list)); } route->flag |= OSPF6_ROUTE_REMOVE; ospf6_abr_examin_brouter(ADV_ROUTER_IN_PREFIX(&route->prefix)); From df25d292130839218fa7c812a62ee300aab46746 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 2 Mar 2018 05:15:33 -0500 Subject: [PATCH 21/25] ospfd: Cleanup ospf SR log messages When OSPF SR is not configured one would expect to not see any output from it at all in the debug log with no debugs turned on. Signed-off-by: Donald Sharp --- ospfd/ospf_sr.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c index 1560977ae8..1a68eda6cc 100644 --- a/ospfd/ospf_sr.c +++ b/ospfd/ospf_sr.c @@ -306,7 +306,8 @@ int ospf_sr_init(void) { int rc = -1; - zlog_info("SR (%s): Initialize SR Data Base", __func__); + if (IS_DEBUG_OSPF_SR) + zlog_info("SR (%s): Initialize SR Data Base", __func__); memset(&OspfSR, 0, sizeof(struct ospf_sr_db)); OspfSR.enabled = false; @@ -1616,11 +1617,11 @@ static int ospf_sr_update_schedule(struct thread *t) monotime(&stop_time); - zlog_info( - "SR (%s): SPF Processing Time(usecs): %lld\n", - __func__, - (stop_time.tv_sec - start_time.tv_sec) * 1000000LL - + (stop_time.tv_usec - start_time.tv_usec)); + if (IS_DEBUG_OSPF_SR) + zlog_debug("SR (%s): SPF Processing Time(usecs): %lld\n", + __func__, + (stop_time.tv_sec - start_time.tv_sec) * 1000000LL + + (stop_time.tv_usec - start_time.tv_usec)); OspfSR.update = false; return 1; From 4b322ffebb13880f6fc6175acb926c225b07d117 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 2 Mar 2018 15:20:43 +0100 Subject: [PATCH 22/25] bgpd,ospfd: add sys_admin capabilities This capability, when used, is mapped over linux sys_admin capability. This is necessary from the daemon perspective, in order to handle NETNS based VRFs, because calling setns() requires sys admin capability. Signed-off-by: Philippe Guibert --- bgpd/bgp_main.c | 2 +- ospfd/ospf_main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 82c74e4afa..30b7afff92 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -106,7 +106,7 @@ static int retain_mode = 0; /* privileges */ static zebra_capabilities_t _caps_p[] = { - ZCAP_BIND, ZCAP_NET_RAW, ZCAP_NET_ADMIN, + ZCAP_BIND, ZCAP_NET_RAW, ZCAP_NET_ADMIN, ZCAP_SYS_ADMIN }; struct zebra_privs_t bgpd_privs = { diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index 7bd644f43d..8dbf39ef5d 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -55,7 +55,7 @@ /* ospfd privileges */ zebra_capabilities_t _caps_p[] = { - ZCAP_NET_RAW, ZCAP_BIND, ZCAP_NET_ADMIN, + ZCAP_NET_RAW, ZCAP_BIND, ZCAP_NET_ADMIN, ZCAP_SYS_ADMIN }; struct zebra_privs_t ospfd_privs = { From 4cfe547340bf56205203a714ef35880b7ec441cc Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Mon, 5 Mar 2018 19:43:39 +0100 Subject: [PATCH 23/25] tests: fix python test description for test_ringbuf Signed-off-by: Christian Franke --- tests/lib/test_ringbuf.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/lib/test_ringbuf.py b/tests/lib/test_ringbuf.py index 860d872f86..5d994ddd7b 100644 --- a/tests/lib/test_ringbuf.py +++ b/tests/lib/test_ringbuf.py @@ -1,4 +1,6 @@ import frrtest -class TestRingbuf(frrtest.TestExitNonzero): +class TestRingbuf(frrtest.TestMultiOut): program = './test_ringbuf' + +TestRingbuf.exit_cleanly() From 2d0e9b80262bca2828f50379e976507b830bb7a4 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Mon, 5 Mar 2018 19:49:31 +0100 Subject: [PATCH 24/25] tests: update gitignore Signed-off-by: Christian Franke --- tests/.gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/.gitignore b/tests/.gitignore index ab1d55b548..c2fe9c8890 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -24,10 +24,12 @@ __pycache__ /bgpd/test_ecommunity /bgpd/test_mp_attr /bgpd/test_mpath +/bgpd/test_packet /isisd/test_fuzz_isis_tlv /isisd/test_fuzz_isis_tlv_tests.h /isisd/test_isis_vertex_queue /lib/cli/test_cli +/lib/cli/test_cli_clippy.c /lib/cli/test_commands /lib/cli/test_commands_defun.c /lib/test_buffer @@ -38,6 +40,7 @@ __pycache__ /lib/test_memory /lib/test_nexthop_iter /lib/test_privs +/lib/test_ringbuf /lib/test_srcdest_table /lib/test_segv /lib/test_sig @@ -48,3 +51,4 @@ __pycache__ /lib/test_ttable /lib/test_zmq /ospf6d/test_lsdb +/ospf6d/test_lsdb_clippy.c From 4a9746fdd0507a7552121072d6f06c7e78a10c63 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 6 Mar 2018 00:46:01 +0100 Subject: [PATCH 25/25] vtysh: initialize vty structure correctly for output to terminal Signed-off-by: Christian Franke --- vtysh/vtysh.c | 2 +- vtysh/vtysh_config.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 8719226281..bf9d70bae9 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -539,7 +539,7 @@ int vtysh_mark_file(const char *filename) } vty = vty_new(); - vty->fd = 0; /* stdout */ + vty->wfd = STDERR_FILENO; vty->type = VTY_TERM; vty->node = CONFIG_NODE; diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index aa1dd407eb..3658128b1c 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -398,7 +398,7 @@ static int vtysh_read_file(FILE *confp) int ret; vty = vty_new(); - vty->fd = 0; /* stdout */ + vty->wfd = STDERR_FILENO; vty->type = VTY_TERM; vty->node = CONFIG_NODE;