From ec91e8a9ee1c5936a2a21fa2a20d8f0d7717ffe5 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Mon, 1 Jun 2020 16:03:35 -0400 Subject: [PATCH 1/6] docker: fix centos7 install We require python3-sphinx for RPM builds, but it wasn't being installed. Signed-off-by: Quentin Young --- docker/centos-7/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/centos-7/Dockerfile b/docker/centos-7/Dockerfile index a8564bdd87..cca8baa147 100644 --- a/docker/centos-7/Dockerfile +++ b/docker/centos-7/Dockerfile @@ -1,10 +1,10 @@ # This stage builds an rpm from the source FROM centos:centos7 as centos-7-builder - +RUN yum install -y epel-release RUN yum install -y rpm-build autoconf automake libtool make \ readline-devel texinfo net-snmp-devel groff pkgconfig \ json-c-devel pam-devel bison flex pytest c-ares-devel \ - python-devel systemd-devel python-sphinx libcap-devel \ + python3-devel python3-sphinx systemd-devel libcap-devel \ https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-10/CentOS-7-x86_64-Packages/libyang-0.16.111-0.x86_64.rpm \ https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-10/CentOS-7-x86_64-Packages/libyang-devel-0.16.111-0.x86_64.rpm \ https://ci1.netdef.org/artifact/RPKI-RTRLIB/shared/build-110/CentOS-7-x86_64-Packages/librtr-0.7.0-1.el7.centos.x86_64.rpm \ From b37eb79c014e73e7f18caf351b049bea55ea9757 Mon Sep 17 00:00:00 2001 From: Olivier Dugeon Date: Fri, 20 Mar 2020 11:34:52 +0100 Subject: [PATCH 2/6] ospfd: Add ECMP support to OSPF Segment Routing * Change sr_prefix structure in ospf_sr.h to add support to ECMP * Add new Segment Routing information to ospf_paths in ospf_route.h * Backport MPLS label configuration from IS-IS Segment Routing implementation * Re-write log message in ospf_sr.c and ospf_ext.c Signed-off-by: Olivier Dugeon --- ospfd/ospf_ext.c | 176 ++++------ ospfd/ospf_route.h | 12 + ospfd/ospf_spf.c | 2 +- ospfd/ospf_sr.c | 857 ++++++++++++++++++++++++--------------------- ospfd/ospf_sr.h | 39 ++- 5 files changed, 570 insertions(+), 516 deletions(-) diff --git a/ospfd/ospf_ext.c b/ospfd/ospf_ext.c index 1543e2015d..14f38bc330 100644 --- a/ospfd/ospf_ext.c +++ b/ospfd/ospf_ext.c @@ -465,12 +465,8 @@ uint32_t ospf_ext_schedule_prefix_index(struct interface *ifp, uint32_t index, return rc; if (p != NULL) { - if (IS_DEBUG_OSPF_SR) - zlog_debug( - "EXT (%s): Schedule new prefix %s/%u with " - "index %u on interface %s", - __func__, inet_ntoa(p->prefix), p->prefixlen, - index, ifp->name); + osr_debug("EXT (%s): Schedule new prefix %pFX with index %u " + "on interface %s", __func__, p, index, ifp->name); /* Set first Extended Prefix then the Prefix SID information */ set_ext_prefix(exti, OSPF_PATH_INTRA_AREA, EXT_TLV_PREF_NFLG, @@ -488,9 +484,8 @@ uint32_t ospf_ext_schedule_prefix_index(struct interface *ifp, uint32_t index, exti, REORIGINATE_THIS_LSA); } } else { - if (IS_DEBUG_OSPF_SR) - zlog_debug("EXT (%s): Remove prefix for interface %s", - __func__, ifp->name); + osr_debug("EXT (%s): Remove prefix for interface %s", __func__, + ifp->name); if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED)) { ospf_ext_pref_lsa_schedule(exti, FLUSH_THIS_LSA); @@ -513,9 +508,8 @@ void ospf_ext_update_sr(bool enable) struct listnode *node; struct ext_itf *exti; - if (IS_DEBUG_OSPF_SR) - zlog_debug("EXT (%s): %s Extended LSAs for Segment Routing ", - __func__, enable ? "Enable" : "Disable"); + osr_debug("EXT (%s): %s Extended LSAs for Segment Routing ", __func__, + enable ? "Enable" : "Disable"); if (enable) { OspfEXT.enabled = true; @@ -629,12 +623,12 @@ static void ospf_ext_ism_change(struct ospf_interface *oi, int old_status) exti->instance = get_ext_pref_instance_value(); exti->area = oi->area; - zlog_debug("EXT (%s): Set Prefix SID to interface %s ", - __func__, oi->ifp->name); + osr_debug("EXT (%s): Set Prefix SID to interface %s ", + __func__, oi->ifp->name); /* Complete SRDB if the interface belongs to a Prefix */ if (OspfEXT.enabled) - ospf_sr_update_prefix(oi->ifp, oi->address); + ospf_sr_update_local_prefix(oi->ifp, oi->address); } else { /* Determine if interface is related to Adj. or LAN Adj. SID */ if (oi->state == ISM_DR) @@ -650,9 +644,9 @@ static void ospf_ext_ism_change(struct ospf_interface *oi, int old_status) * Note: Adjacency SID information are completed when ospf * adjacency become up see ospf_ext_link_nsm_change() */ - zlog_debug("EXT (%s): Set %sAdjacency SID for interface %s ", - __func__, exti->stype == ADJ_SID ? "" : "LAN-", - oi->ifp->name); + osr_debug("EXT (%s): Set %sAdjacency SID for interface %s ", + __func__, exti->stype == ADJ_SID ? "" : "LAN-", + oi->ifp->name); } } @@ -742,11 +736,9 @@ static void ospf_ext_link_nsm_change(struct ospf_neighbor *nbr, int old_status) return; } - if (IS_DEBUG_OSPF_SR) - zlog_debug( - "EXT (%s): Complete %sAdjacency SID for interface %s ", - __func__, exti->stype == ADJ_SID ? "" : "LAN-", - oi->ifp->name); + osr_debug("EXT (%s): Complete %sAdjacency SID for interface %s ", + __func__, exti->stype == ADJ_SID ? "" : "LAN-", + oi->ifp->name); /* flood this links params if everything is ok */ SET_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE); @@ -962,12 +954,10 @@ static struct ospf_lsa *ospf_ext_pref_lsa_new(struct ospf_area *area, /* Set opaque-LSA header fields. */ lsa_header_set(s, options, lsa_type, lsa_id, router_id); - if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) - zlog_debug( - "EXT (%s): LSA[Type%u:%s]: Create an Opaque-LSA " - "Extended Prefix Opaque LSA instance", - __func__, lsa_type, inet_ntoa(lsa_id)); - + osr_debug( + "EXT (%s): LSA[Type%u:%pI4]: Create an Opaque-LSA Extended " + "Prefix Opaque LSA instance", + __func__, lsa_type, &lsa_id); /* Set opaque-LSA body fields. */ ospf_ext_pref_lsa_body_set(s, exti); @@ -1022,11 +1012,10 @@ static struct ospf_lsa *ospf_ext_link_lsa_new(struct ospf_area *area, tmp = SET_OPAQUE_LSID(OPAQUE_TYPE_EXTENDED_LINK_LSA, exti->instance); lsa_id.s_addr = htonl(tmp); - if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) - zlog_debug( - "EXT (%s) LSA[Type%u:%s]: Create an Opaque-LSA " - "Extended Link Opaque LSA instance", - __func__, lsa_type, inet_ntoa(lsa_id)); + osr_debug( + "EXT (%s) LSA[Type%u:%pI4]: Create an Opaque-LSA Extended " + "Link Opaque LSA instance", + __func__, lsa_type, &lsa_id); /* Set opaque-LSA header fields. */ lsa_header_set(s, options, lsa_type, lsa_id, area->ospf->router_id); @@ -1089,17 +1078,13 @@ static int ospf_ext_pref_lsa_originate1(struct ospf_area *area, /* Flood new LSA through area. */ ospf_flood_through_area(area, NULL /*nbr */, new); - if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) { - char area_id[INET_ADDRSTRLEN]; - - inet_ntop(AF_INET, &area->area_id, area_id, sizeof(area_id)); - zlog_debug( - "EXT (%s): LSA[Type%u:%s]: Originate Opaque-LSA " - "Extended Prefix Opaque LSA: Area(%s), Link(%s)", - __func__, new->data->type, inet_ntoa(new->data->id), - area_id, exti->ifp->name); + osr_debug( + "EXT (%s): LSA[Type%u:%pI4]: Originate Opaque-LSA" + "Extended Prefix Opaque LSA: Area(%pI4), Link(%s)", + __func__, new->data->type, &new->data->id, + &area->area_id, exti->ifp->name); + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) ospf_lsa_header_dump(new->data); - } rc = 0; @@ -1141,17 +1126,13 @@ static int ospf_ext_link_lsa_originate1(struct ospf_area *area, /* Flood new LSA through area. */ ospf_flood_through_area(area, NULL /*nbr */, new); - if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) { - char area_id[INET_ADDRSTRLEN]; - - inet_ntop(AF_INET, &area->area_id, area_id, sizeof(area_id)); - zlog_debug( - "EXT (%s): LSA[Type%u:%s]: Originate Opaque-LSA " - "Extended Link Opaque LSA: Area(%s), Link(%s)", - __func__, new->data->type, inet_ntoa(new->data->id), - area_id, exti->ifp->name); + osr_debug( + "EXT (%s): LSA[Type%u:%pI4]: Originate Opaque-LSA " + "Extended Link Opaque LSA: Area(%pI4), Link(%s)", + __func__, new->data->type, &new->data->id, + &area->area_id, exti->ifp->name); + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) ospf_lsa_header_dump(new->data); - } rc = 0; @@ -1168,15 +1149,13 @@ static int ospf_ext_pref_lsa_originate(void *arg) if (!OspfEXT.enabled) { zlog_info( - "EXT (%s): Segment Routing " - "functionality is Disabled now", + "EXT (%s): Segment Routing functionality is Disabled now", __func__); rc = 0; /* This is not an error case. */ return rc; } - if (IS_DEBUG_OSPF_SR) - zlog_debug("EXT (%s): Start Originate Prefix LSA for area %s", - __func__, inet_ntoa(area->area_id)); + osr_debug("EXT (%s): Start Originate Prefix LSA for area %pI4", + __func__, &area->area_id); /* Check if Extended Prefix Opaque LSA is already engaged */ for (ALL_LIST_ELEMENTS_RO(OspfEXT.iflist, node, exti)) { @@ -1206,12 +1185,10 @@ static int ospf_ext_pref_lsa_originate(void *arg) } /* Ok, let's try to originate an LSA */ - if (IS_DEBUG_OSPF_SR) - zlog_debug( - "EXT (%s): Let's finally reoriginate the " - "LSA 7.0.0.%u for Itf %s", - __func__, exti->instance, - exti->ifp ? exti->ifp->name : ""); + osr_debug( + "EXT (%s): Let's finally re-originate the LSA 7.0.0.%u " + "for Itf %s", __func__, exti->instance, + exti->ifp ? exti->ifp->name : ""); ospf_ext_pref_lsa_originate1(area, exti); } @@ -1229,8 +1206,7 @@ static int ospf_ext_link_lsa_originate(void *arg) if (!OspfEXT.enabled) { zlog_info( - "EXT (%s): Segment Routing " - "functionality is Disabled now", + "EXT (%s): Segment Routing functionality is Disabled now", __func__); rc = 0; /* This is not an error case. */ return rc; @@ -1268,13 +1244,11 @@ static int ospf_ext_link_lsa_originate(void *arg) } /* Ok, let's try to originate an LSA */ - if (IS_DEBUG_OSPF_SR) - zlog_debug( - "EXT (%s): Let's finally reoriginate the " - "LSA 8.0.0.%u for Itf %s through the Area %s", - __func__, exti->instance, - exti->ifp ? exti->ifp->name : "-", - inet_ntoa(area->area_id)); + osr_debug( + "EXT (%s): Let's finally reoriginate the LSA 8.0.0.%u " + "for Itf %s through the Area %pI4", __func__, + exti->instance, exti->ifp ? exti->ifp->name : "-", + &area->area_id); ospf_ext_link_lsa_originate1(area, exti); } @@ -1297,8 +1271,7 @@ static struct ospf_lsa *ospf_ext_pref_lsa_refresh(struct ospf_lsa *lsa) * It seems a slip among routers in the routing domain. */ zlog_info( - "EXT (%s): Segment Routing functionality is " - "Disabled", + "EXT (%s): Segment Routing functionality is Disabled", __func__); /* Flush it anyway. */ lsa->data->ls_age = htons(OSPF_LSA_MAXAGE); @@ -1362,12 +1335,11 @@ static struct ospf_lsa *ospf_ext_pref_lsa_refresh(struct ospf_lsa *lsa) ospf_flood_through_area(area, NULL /*nbr */, new); /* Debug logging. */ - if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) { - zlog_debug( - "EXT (%s): LSA[Type%u:%s] Refresh Extended Prefix LSA", - __func__, new->data->type, inet_ntoa(new->data->id)); + osr_debug("EXT (%s): LSA[Type%u:%pI4] Refresh Extended Prefix LSA", + __func__, new->data->type, &new->data->id); + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) ospf_lsa_header_dump(new->data); - } + return new; } @@ -1438,12 +1410,10 @@ static struct ospf_lsa *ospf_ext_link_lsa_refresh(struct ospf_lsa *lsa) ospf_flood_through_area(area, NULL /*nbr */, new); /* Debug logging. */ - if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) { - zlog_debug( - "EXT (%s): LSA[Type%u:%s]: Refresh Extended Link LSA", - __func__, new->data->type, inet_ntoa(new->data->id)); + osr_debug("EXT (%s): LSA[Type%u:%pI4]: Refresh Extended Link LSA", + __func__, new->data->type, &new->data->id); + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) ospf_lsa_header_dump(new->data); - } return new; } @@ -1468,18 +1438,17 @@ static void ospf_ext_pref_lsa_schedule(struct ext_itf *exti, if (!(CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE))) return; - zlog_debug("EXT (%s): Schedule %s%s%s LSA for interface %s", __func__, - opcode == REORIGINATE_THIS_LSA ? "Re-Originate" : "", - opcode == REFRESH_THIS_LSA ? "Refresh" : "", - opcode == FLUSH_THIS_LSA ? "Flush" : "", - exti->ifp ? exti->ifp->name : "-"); + osr_debug("EXT (%s): Schedule %s%s%s LSA for interface %s", __func__, + opcode == REORIGINATE_THIS_LSA ? "Re-Originate" : "", + opcode == REFRESH_THIS_LSA ? "Refresh" : "", + opcode == FLUSH_THIS_LSA ? "Flush" : "", + exti->ifp ? exti->ifp->name : "-"); /* Verify Area */ if (exti->area == NULL) { - if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) - zlog_debug( - "EXT (%s): Area is not yet set. Try to use Backbone Area", - __func__); + osr_debug( + "EXT (%s): Area is not yet set. Try to use Backbone Area", + __func__); top = ospf_lookup_by_vrf_id(VRF_DEFAULT); struct in_addr backbone = {.s_addr = INADDR_ANY}; @@ -1533,18 +1502,17 @@ static void ospf_ext_link_lsa_schedule(struct ext_itf *exti, if (!(CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE))) return; - zlog_debug("EXT (%s): Schedule %s%s%s LSA for interface %s", __func__, - opcode == REORIGINATE_THIS_LSA ? "Re-Originate" : "", - opcode == REFRESH_THIS_LSA ? "Refresh" : "", - opcode == FLUSH_THIS_LSA ? "Flush" : "", - exti->ifp ? exti->ifp->name : "-"); + osr_debug("EXT (%s): Schedule %s%s%s LSA for interface %s", __func__, + opcode == REORIGINATE_THIS_LSA ? "Re-Originate" : "", + opcode == REFRESH_THIS_LSA ? "Refresh" : "", + opcode == FLUSH_THIS_LSA ? "Flush" : "", + exti->ifp ? exti->ifp->name : "-"); /* Verify Area */ if (exti->area == NULL) { - if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) - zlog_debug( - "EXT (%s): Area is not yet set. Try to use Backbone Area", - __func__); + osr_debug( + "EXT (%s): Area is not yet set. Try to use Backbone Area", + __func__); top = ospf_lookup_by_vrf_id(VRF_DEFAULT); struct in_addr backbone = {.s_addr = INADDR_ANY}; diff --git a/ospfd/ospf_route.h b/ospfd/ospf_route.h index 8cb5d32a8a..20cdc75fe8 100644 --- a/ospfd/ospf_route.h +++ b/ospfd/ospf_route.h @@ -33,12 +33,24 @@ #define OSPF_PATH_TYPE2_EXTERNAL 4 #define OSPF_PATH_MAX 5 +/* Segment Routing information to complement ospf_path structure */ +struct sr_nexthop_info { + /* Output label associated to this route */ + mpls_label_t label_out; + /* + * Pointer to SR Node which is the next hop for this route + * or NULL if next hop is the destination of the prefix + */ + struct sr_node *nexthop; +}; + /* OSPF Path. */ struct ospf_path { struct in_addr nexthop; struct in_addr adv_router; ifindex_t ifindex; unsigned char unnumbered; + struct sr_nexthop_info srni; }; /* Below is the structure linked to every diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c index ae70a5c789..64c59c9abf 100644 --- a/ospfd/ospf_spf.c +++ b/ospfd/ospf_spf.c @@ -1369,7 +1369,7 @@ static int ospf_spf_calculate_timer(struct thread *thread) abr_time = monotime_since(&start_time, NULL); /* Schedule Segment Routing update */ - ospf_sr_update_timer_add(ospf); + ospf_sr_update_task(ospf); total_spf_time = monotime_since(&spf_start_time, &ospf->ts_spf_duration); diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c index 2a35bd2ef9..de037a4b43 100644 --- a/ospfd/ospf_sr.c +++ b/ospfd/ospf_sr.c @@ -51,6 +51,7 @@ #include "thread.h" #include "vty.h" #include "zclient.h" +#include "sbuf.h" #include #include "ospf_errors.h" @@ -79,7 +80,11 @@ */ static struct ospf_sr_db OspfSR; static void ospf_sr_register_vty(void); -static inline void del_sid_nhlfe(struct sr_nhlfe nhlfe); +static inline void del_adj_sid(struct sr_nhlfe nhlfe); +static void delete_prefix_sid(const struct sr_prefix *srp); + +#define IS_NO_ROUTE(srp) ((srp->route == NULL) || (srp->route->paths == NULL) \ + || list_isempty(srp->route->paths)) /* * Segment Routing Data Base functions @@ -107,8 +112,8 @@ static void del_sr_link(void *val) { struct sr_link *srl = (struct sr_link *)val; - del_sid_nhlfe(srl->nhlfe[0]); - del_sid_nhlfe(srl->nhlfe[1]); + del_adj_sid(srl->nhlfe[0]); + del_adj_sid(srl->nhlfe[1]); XFREE(MTYPE_OSPF_SR_PARAMS, val); } @@ -117,7 +122,7 @@ static void del_sr_pref(void *val) { struct sr_prefix *srp = (struct sr_prefix *)val; - del_sid_nhlfe(srp->nhlfe); + delete_prefix_sid(srp); XFREE(MTYPE_OSPF_SR_PARAMS, val); } @@ -151,9 +156,7 @@ static struct sr_node *sr_node_new(struct in_addr *rid) new->neighbor = NULL; new->instance = 0; - if (IS_DEBUG_OSPF_SR) - zlog_debug(" |- Created new SR node for %s", - inet_ntoa(new->adv_router)); + osr_debug(" |- Created new SR node for %pI4", &new->adv_router); return new; } @@ -188,9 +191,7 @@ static struct sr_node *get_sr_node_by_nexthop(struct ospf *ospf, if (OspfSR.neighbors == NULL) return NULL; - if (IS_DEBUG_OSPF_SR) - zlog_debug(" |- Search SR-Node for nexthop %s", - inet_ntoa(nexthop)); + osr_debug(" |- Search SR-Node for nexthop %pI4", &nexthop); /* First, search neighbor Router ID for this nexthop */ found = false; @@ -209,9 +210,8 @@ static struct sr_node *get_sr_node_by_nexthop(struct ospf *ospf, if (!found) return NULL; - if (IS_DEBUG_OSPF_SR) - zlog_debug(" |- Found nexthop Router ID %s", - inet_ntoa(nbr->router_id)); + osr_debug(" |- Found nexthop Router ID %pI4", &nbr->router_id); + /* Then, search SR Node */ srn = (struct sr_node *)hash_lookup(OspfSR.neighbors, &nbr->router_id); @@ -230,8 +230,7 @@ static int ospf_sr_start(struct ospf *ospf) struct sr_node *srn; int rc = 0; - if (IS_DEBUG_OSPF_SR) - zlog_debug("SR (%s): Start Segment Routing", __func__); + osr_debug("SR (%s): Start Segment Routing", __func__); /* Initialize self SR Node */ srn = hash_get(OspfSR.neighbors, (void *)&(ospf->router_id), @@ -244,8 +243,7 @@ static int ospf_sr_start(struct ospf *ospf) srn->msd = OspfSR.msd; OspfSR.self = srn; - if (IS_DEBUG_OSPF_EVENT) - zlog_debug("SR (%s): Update SR-DB from LSDB", __func__); + osr_debug("SR (%s): Update SR-DB from LSDB", __func__); /* Start by looking to Router Info & Extended LSA in lsdb */ if ((ospf != NULL) && (ospf->backbone != NULL)) { @@ -278,8 +276,7 @@ static int ospf_sr_start(struct ospf *ospf) static void ospf_sr_stop(void) { - if (IS_DEBUG_OSPF_SR) - zlog_debug("SR (%s): Stop Segment Routing", __func__); + osr_debug("SR (%s): Stop Segment Routing", __func__); /* * Remove all SR Nodes from the Hash table. Prefix and Link SID will @@ -299,8 +296,7 @@ int ospf_sr_init(void) { int rc = -1; - if (IS_DEBUG_OSPF_SR) - zlog_info("SR (%s): Initialize SR Data Base", __func__); + osr_debug("SR (%s): Initialize SR Data Base", __func__); memset(&OspfSR, 0, sizeof(struct ospf_sr_db)); OspfSR.enabled = false; @@ -417,21 +413,17 @@ static struct ospf_neighbor *get_neighbor_by_addr(struct ospf *top, } /* Get OSPF Path from address */ -static struct ospf_path *get_nexthop_by_addr(struct ospf *top, - struct prefix_ipv4 p) +static struct ospf_route *get_nexthop_by_addr(struct ospf *top, + struct prefix_ipv4 p) { - struct ospf_route * or ; - struct ospf_path *path; - struct listnode *node; struct route_node *rn; /* Sanity Check */ if (top == NULL) return NULL; - if (IS_DEBUG_OSPF_SR) - zlog_debug(" |- Search Nexthop for prefix %s/%u", - inet_ntoa(p.prefix), p.prefixlen); + osr_debug(" |- Search Nexthop for prefix %pFX", + (struct prefix *)&p); rn = route_node_lookup(top->new_table, (struct prefix *)&p); @@ -443,16 +435,7 @@ static struct ospf_path *get_nexthop_by_addr(struct ospf *top, return NULL; route_unlock_node(rn); - or = rn->info; - if (or == NULL) - return NULL; - - /* Then search path from this route */ - for (ALL_LIST_ELEMENTS_RO(or->paths, node, path)) - if (path->nexthop.s_addr != INADDR_ANY || path->ifindex != 0) - return path; - - return NULL; + return rn->info; } /* Compute NHLFE entry for Extended Link */ @@ -462,10 +445,7 @@ static int compute_link_nhlfe(struct sr_link *srl) struct ospf_neighbor *nh; int rc = 0; - if (IS_DEBUG_OSPF_SR) - zlog_debug(" |- Compute NHLFE for link %s/%u", - inet_ntoa(srl->nhlfe[0].prefv4.prefix), - srl->nhlfe[0].prefv4.prefixlen); + osr_debug(" |- Compute NHLFE for link %pI4", &srl->itf_addr); /* First determine the OSPF Neighbor */ nh = get_neighbor_by_addr(top, srl->nhlfe[0].nexthop); @@ -477,9 +457,7 @@ static int compute_link_nhlfe(struct sr_link *srl) if (nh == NULL) return rc; - if (IS_DEBUG_OSPF_SR) - zlog_debug(" |- Found nexthop NHLFE %s", - inet_ntoa(nh->router_id)); + osr_debug(" |- Found nexthop %pI4", &nh->router_id); /* Set ifindex for this neighbor */ srl->nhlfe[0].ifindex = nh->oi->ifp->ifindex; @@ -515,119 +493,102 @@ static int compute_link_nhlfe(struct sr_link *srl) * * @param srp - Segment Routing Prefix * - * @return -1 if next hop is not found, 0 if nexthop has not changed - * and 1 if success + * @return -1 if no route is found, 0 if there is no SR route ready + * and 1 if success or update */ static int compute_prefix_nhlfe(struct sr_prefix *srp) { struct ospf *top = ospf_lookup_by_vrf_id(VRF_DEFAULT); - struct ospf_path *nh = NULL; + struct ospf_path *path; + struct listnode *node; struct sr_node *srnext; int rc = -1; - if (IS_DEBUG_OSPF_SR) - zlog_debug(" |- Compute NHLFE for prefix %s/%u", - inet_ntoa(srp->nhlfe.prefv4.prefix), - srp->nhlfe.prefv4.prefixlen); + osr_debug(" |- Compute NHLFE for prefix %pFX", + (struct prefix *)&srp->prefv4); + /* First determine the nexthop */ - nh = get_nexthop_by_addr(top, srp->nhlfe.prefv4); + srp->or = get_nexthop_by_addr(top, srp->prefv4); /* Nexthop could be not found when OSPF Adjacency just fire up * because SPF don't yet populate routing table. This NHLFE will * be fixed later when SR SPF schedule will be called. */ - if (nh == NULL) + if (srp->or == NULL) return rc; - /* Check if NextHop has changed when call after running a new SPF */ - if (IPV4_ADDR_SAME(&nh->nexthop, &srp->nhlfe.nexthop) - && (nh->ifindex == srp->nhlfe.ifindex)) - return 0; - - if (IS_DEBUG_OSPF_SR) - zlog_debug(" |- Found new next hop for this NHLFE: %s", - inet_ntoa(nh->nexthop)); - - /* - * Get SR-Node for this nexthop. Could be not yet available - * as Extende Link / Prefix and Router Information are flooded - * after LSA Type 1 & 2 which populate the OSPF Route Table - */ - srnext = get_sr_node_by_nexthop(top, nh->nexthop); - if (srnext == NULL) - return rc; - - /* And store this information for later update if SR Node is found */ - srnext->neighbor = OspfSR.self; - if (IPV4_ADDR_SAME(&srnext->adv_router, &srp->adv_router)) - srp->nexthop = NULL; - else - srp->nexthop = srnext; - - /* - * SR Node could be known, but SRGB could be not initialize - * This is due to the fact that Extended Link / Prefix could - * be received before corresponding Router Information LSA - */ - if ((srnext == NULL) || (srnext->srgb.lower_bound == 0) - || (srnext->srgb.range_size == 0)) - return rc; - - if (IS_DEBUG_OSPF_SR) - zlog_debug(" |- Found SRGB %u/%u for next hop SR-Node %s", - srnext->srgb.range_size, srnext->srgb.lower_bound, - inet_ntoa(srnext->adv_router)); - - /* Set ip addr & ifindex for this neighbor */ - IPV4_ADDR_COPY(&srp->nhlfe.nexthop, &nh->nexthop); - srp->nhlfe.ifindex = nh->ifindex; - /* Compute Input Label with self SRGB */ - srp->nhlfe.label_in = index2label(srp->sid, OspfSR.srgb); - /* - * and Output Label with Next hop SR Node SRGB or Implicit Null label - * if next hop is the destination and request PHP - */ - if ((srp->nexthop == NULL) - && (!CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG))) - srp->nhlfe.label_out = MPLS_LABEL_IMPLICIT_NULL; - else if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_VFLG)) - srp->nhlfe.label_out = srp->sid; - else - srp->nhlfe.label_out = index2label(srp->sid, srnext->srgb); + srp->label_in = index2label(srp->sid, OspfSR.srgb); - if (IS_DEBUG_OSPF_SR) - zlog_debug(" |- Computed new labels in: %u out: %u", - srp->nhlfe.label_in, srp->nhlfe.label_out); + rc = 0; + for (ALL_LIST_ELEMENTS_RO(srp->or->paths, node, path)) { - rc = 1; + osr_debug(" |- Process new route via %pI4 for this prefix", + &path->nexthop); + + /* + * Get SR-Node for this nexthop. Could be not yet available + * as Extended Link / Prefix and Router Information are flooded + * after LSA Type 1 & 2 which populate the OSPF Route Table + */ + srnext = get_sr_node_by_nexthop(top, path->nexthop); + if (srnext == NULL) + continue; + + /* And store this information for later update */ + srnext->neighbor = OspfSR.self; + if (IPV4_ADDR_SAME(&srnext->adv_router, &srp->adv_router)) + path->srni.nexthop = NULL; + else + path->srni.nexthop = srnext; + + /* + * SR Node could be known, but SRGB could be not initialize + * This is due to the fact that Extended Link / Prefix could + * be received before corresponding Router Information LSA + */ + if ((srnext == NULL) || (srnext->srgb.lower_bound == 0) + || (srnext->srgb.range_size == 0)) + continue; + + osr_debug(" |- Found SRGB %u/%u for next hop SR-Node %pI4", + srnext->srgb.range_size, srnext->srgb.lower_bound, + &srnext->adv_router); + + /* + * Compute Output Label with Nexthop SR Node SRGB or Implicit + * Null label if next hop is the destination and request PHP + */ + if ((path->srni.nexthop == NULL) + && (!CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG))) + path->srni.label_out = MPLS_LABEL_IMPLICIT_NULL; + else if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_VFLG)) + path->srni.label_out = srp->sid; + else + path->srni.label_out = + index2label(srp->sid, srnext->srgb); + + osr_debug(" |- Computed new labels in: %u out: %u", + srp->label_in, path->srni.label_out); + rc = 1; + } return rc; } /* Send MPLS Label entry to Zebra for installation or deletion */ -static int ospf_zebra_send_mpls_labels(int cmd, struct sr_nhlfe nhlfe) +static int send_adjacency_sid(int cmd, struct sr_nhlfe nhlfe) { - struct zapi_labels zl = {}; + struct zapi_labels zl; struct zapi_nexthop *znh; - if (IS_DEBUG_OSPF_SR) - zlog_debug(" |- %s LSP %u/%u for %s/%u via %u", - cmd == ZEBRA_MPLS_LABELS_ADD ? "Add" : "Delete", - nhlfe.label_in, nhlfe.label_out, - inet_ntoa(nhlfe.prefv4.prefix), - nhlfe.prefv4.prefixlen, nhlfe.ifindex); + osr_debug(" |- %s Labels %u/%u for Adjacency via %u", + cmd == ZEBRA_MPLS_LABELS_ADD ? "Add" : "Delete", + nhlfe.label_in, nhlfe.label_out, nhlfe.ifindex); + memset(&zl, 0, sizeof(zl)); zl.type = ZEBRA_LSP_OSPF_SR; zl.local_label = nhlfe.label_in; - - SET_FLAG(zl.message, ZAPI_LABELS_FTN); - zl.route.prefix.family = nhlfe.prefv4.family; - zl.route.prefix.prefixlen = nhlfe.prefv4.prefixlen; - zl.route.prefix.u.prefix4 = nhlfe.prefv4.prefix; - zl.route.type = ZEBRA_ROUTE_OSPF; - zl.route.instance = 0; - zl.nexthop_num = 1; znh = &zl.nexthops[0]; znh->type = NEXTHOP_TYPE_IPV4_IFINDEX; @@ -639,26 +600,114 @@ static int ospf_zebra_send_mpls_labels(int cmd, struct sr_nhlfe nhlfe) return zebra_send_mpls_labels(zclient, cmd, &zl); } -/* Add new NHLFE entry for SID */ -static inline void add_sid_nhlfe(struct sr_nhlfe nhlfe) +/* Add new NHLFE entry for Adjacency SID */ +static inline void add_adj_sid(struct sr_nhlfe nhlfe) { - if ((nhlfe.label_in != 0) && (nhlfe.label_out != 0)) - ospf_zebra_send_mpls_labels(ZEBRA_MPLS_LABELS_ADD, nhlfe); + if (nhlfe.label_in != 0) + send_adjacency_sid(ZEBRA_MPLS_LABELS_ADD, nhlfe); } -/* Remove NHLFE entry for SID */ -static inline void del_sid_nhlfe(struct sr_nhlfe nhlfe) +/* Remove NHLFE entry for Adjacency SID */ +static inline void del_adj_sid(struct sr_nhlfe nhlfe) { - if ((nhlfe.label_in != 0) && (nhlfe.label_out != 0)) - ospf_zebra_send_mpls_labels(ZEBRA_MPLS_LABELS_DELETE, nhlfe); + if (nhlfe.label_in != 0) + send_adjacency_sid(ZEBRA_MPLS_LABELS_DELETE, nhlfe); } -/* Update NHLFE entry for SID */ -static inline void update_sid_nhlfe(struct sr_nhlfe n1, struct sr_nhlfe n2) +/* Update NHLFE entry for Adjacency SID */ +static inline void update_adj_sid(struct sr_nhlfe n1, struct sr_nhlfe n2) { + del_adj_sid(n1); + add_adj_sid(n2); +} - del_sid_nhlfe(n1); - add_sid_nhlfe(n2); +/* Update NHLFE for Prefix SID */ +static void update_prefix_sid (const struct sr_prefix *srp) { + struct zapi_labels zl; + struct zapi_nexthop *znh; + struct listnode *node; + struct ospf_path *path; + + osr_debug(" |- Update Labels %u for Prefix %pFX", + srp->label_in, (struct prefix *)&srp->prefv4); + + /* Prepare message. */ + memset(&zl, 0, sizeof(zl)); + zl.type = ZEBRA_LSP_OSPF_SR; + zl.local_label = srp->label_in; + + switch (srp->type) { + case LOCAL_SID: + /* Set Label for local Prefix */ + znh = &zl.nexthops[zl.nexthop_num++]; + znh->type = NEXTHOP_TYPE_IFINDEX; + znh->ifindex = srp->nhlfe.ifindex; + znh->label_num = 1; + znh->labels[0] = srp->nhlfe.label_out; + break; + + case PREF_SID: + /* Update route in the RIB too. */ + SET_FLAG(zl.message, ZAPI_LABELS_FTN); + zl.route.prefix.u.prefix4 = srp->prefv4.prefix; + zl.route.prefix.prefixlen = srp->prefv4.prefixlen; + zl.route.prefix.family = srp->prefv4.family; + zl.route.type = ZEBRA_ROUTE_OSPF; + zl.route.instance = 0; + + /* Check that SRP contains at least one valid path */ + if ((srp->or == NULL) || (srp->or->paths == NULL) + || (list_isempty(srp->or->paths))) { + return; + } + for (ALL_LIST_ELEMENTS_RO(srp->or->paths, node, path)) { + if (path->srni.label_out == MPLS_INVALID_LABEL) + continue; + + if (zl.nexthop_num >= MULTIPATH_NUM) + break; + + znh = &zl.nexthops[zl.nexthop_num++]; + znh->type = NEXTHOP_TYPE_IPV4_IFINDEX; + znh->gate.ipv4 = path->nexthop; + znh->ifindex = path->ifindex; + znh->label_num = 1; + znh->labels[0] = path->srni.label_out; + } + break; + default: + return; + } + + /* Finally, send message to zebra. */ + (void)zebra_send_mpls_labels(zclient, ZEBRA_MPLS_LABELS_REPLACE, &zl); +} + +/* Remove NHLFE for Prefix-SID */ +static void delete_prefix_sid(const struct sr_prefix *srp) +{ + struct zapi_labels zl; + + osr_debug(" |- Delete Labels %u for Prefix %pFX", + srp->label_in, (struct prefix *)&srp->prefv4); + + /* Prepare message. */ + memset(&zl, 0, sizeof(zl)); + zl.type = ZEBRA_LSP_OSPF_SR; + zl.local_label = srp->label_in; + + if (srp->type == PREF_SID) { + /* Update route in the RIB too */ + SET_FLAG(zl.message, ZAPI_LABELS_FTN); + zl.route.prefix.u.prefix4 = srp->prefv4.prefix; + zl.route.prefix.prefixlen = srp->prefv4.prefixlen; + zl.route.prefix.family = srp->prefv4.family; + zl.route.type = ZEBRA_ROUTE_OSPF; + zl.route.instance = 0; + } + + /* Send message to zebra. */ + (void)zebra_send_mpls_labels(zclient, ZEBRA_MPLS_LABELS_DELETE, &zl); } /* @@ -729,23 +778,10 @@ static struct sr_link *get_ext_link_sid(struct tlv_header *tlvh) sum += TLV_SIZE(sub_tlvh); } - IPV4_ADDR_COPY(&srl->nhlfe[0].prefv4.prefix, &link->link_data); - srl->nhlfe[0].prefv4.prefixlen = IPV4_MAX_PREFIXLEN; - srl->nhlfe[0].prefv4.family = AF_INET; - apply_mask_ipv4(&srl->nhlfe[0].prefv4); - IPV4_ADDR_COPY(&srl->nhlfe[1].prefv4.prefix, &link->link_data); - srl->nhlfe[1].prefv4.prefixlen = IPV4_MAX_PREFIXLEN; - srl->nhlfe[1].prefv4.family = AF_INET; - apply_mask_ipv4(&srl->nhlfe[1].prefv4); + IPV4_ADDR_COPY(&srl->itf_addr, &link->link_data); - if (IS_DEBUG_OSPF_SR) { - zlog_debug(" |- Found primary Adj/Lan Sid %u for %s/%u", - srl->sid[0], inet_ntoa(srl->nhlfe[0].prefv4.prefix), - srl->nhlfe[0].prefv4.prefixlen); - zlog_debug(" |- Found backup Adj/Lan Sid %u for %s/%u", - srl->sid[1], inet_ntoa(srl->nhlfe[1].prefv4.prefix), - srl->nhlfe[1].prefv4.prefixlen); - } + osr_debug(" |- Found primary %u and backup %u Adj/Lan Sid for %pI4", + srl->sid[0], srl->sid[1], &srl->itf_addr); return srl; } @@ -784,11 +820,11 @@ static struct sr_prefix *get_ext_prefix_sid(struct tlv_header *tlvh) srp->sid = GET_LABEL(ntohl(psid->value)); else srp->sid = ntohl(psid->value); - IPV4_ADDR_COPY(&srp->nhlfe.prefv4.prefix, + IPV4_ADDR_COPY(&srp->prefv4.prefix, &pref->address); - srp->nhlfe.prefv4.prefixlen = pref->pref_length; - srp->nhlfe.prefv4.family = AF_INET; - apply_mask_ipv4(&srp->nhlfe.prefv4); + srp->prefv4.prefixlen = pref->pref_length; + srp->prefv4.family = AF_INET; + apply_mask_ipv4(&srp->prefv4); break; default: break; @@ -796,10 +832,9 @@ static struct sr_prefix *get_ext_prefix_sid(struct tlv_header *tlvh) sum += TLV_SIZE(sub_tlvh); } - if (IS_DEBUG_OSPF_SR) - zlog_debug(" |- Found SID %u for prefix %s/%u", srp->sid, - inet_ntoa(srp->nhlfe.prefv4.prefix), - srp->nhlfe.prefv4.prefixlen); + osr_debug(" |- Found SID %u for prefix %pFX", srp->sid, + (struct prefix *)&srp->prefv4); + return srp; } @@ -839,8 +874,7 @@ static void update_ext_link_sid(struct sr_node *srn, struct sr_link *srl, if ((srn == NULL) || (srl == NULL)) return; - if (IS_DEBUG_OSPF_SR) - zlog_debug(" |- Process Extended Link Adj/Lan-SID"); + osr_debug(" |- Process Extended Link Adj/Lan-SID"); /* Process only Local Adj/Lan_Adj SID coming from LSA SELF */ if (!CHECK_FLAG(srl->flags[0], EXT_SUBTLV_LINK_ADJ_SID_LFLG) @@ -855,11 +889,9 @@ static void update_ext_link_sid(struct sr_node *srn, struct sr_link *srl, break; } - if (IS_DEBUG_OSPF_SR) - zlog_debug(" |- %s SR Link 8.0.0.%u for SR node %s", - found ? "Update" : "Add", - GET_OPAQUE_ID(srl->instance), - inet_ntoa(srn->adv_router)); + osr_debug(" |- %s SR Link 8.0.0.%u for SR node %pI4", + found ? "Update" : "Add", GET_OPAQUE_ID(srl->instance), + &srn->adv_router); /* if not found, add new Segment Link and install NHLFE */ if (!found) { @@ -869,14 +901,14 @@ static void update_ext_link_sid(struct sr_node *srn, struct sr_link *srl, listnode_add(srn->ext_link, srl); /* Try to set MPLS table */ if (compute_link_nhlfe(srl)) { - add_sid_nhlfe(srl->nhlfe[0]); - add_sid_nhlfe(srl->nhlfe[1]); + add_adj_sid(srl->nhlfe[0]); + add_adj_sid(srl->nhlfe[1]); } } else { if (sr_link_cmp(lk, srl)) { if (compute_link_nhlfe(srl)) { - update_sid_nhlfe(lk->nhlfe[0], srl->nhlfe[0]); - update_sid_nhlfe(lk->nhlfe[1], srl->nhlfe[1]); + update_adj_sid(lk->nhlfe[0], srl->nhlfe[0]); + update_adj_sid(lk->nhlfe[1], srl->nhlfe[1]); /* Replace Segment List */ listnode_delete(srn->ext_link, lk); XFREE(MTYPE_OSPF_SR_PARAMS, lk); @@ -912,8 +944,7 @@ static void update_ext_prefix_sid(struct sr_node *srn, struct sr_prefix *srp) if (srn == NULL || srp == NULL) return; - if (IS_DEBUG_OSPF_SR) - zlog_debug(" |- Process Extended Prefix SID %u", srp->sid); + osr_debug(" |- Process Extended Prefix SID %u", srp->sid); /* Process only Global Prefix SID */ if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_LFLG)) @@ -926,11 +957,9 @@ static void update_ext_prefix_sid(struct sr_node *srn, struct sr_prefix *srp) break; } - if (IS_DEBUG_OSPF_SR) - zlog_debug(" |- %s SR LSA ID 7.0.0.%u for SR node %s", - found ? "Update" : "Add", - GET_OPAQUE_ID(srp->instance), - inet_ntoa(srn->adv_router)); + osr_debug(" |- %s SR LSA ID 7.0.0.%u for SR node %pI4", + found ? "Update" : "Add", GET_OPAQUE_ID(srp->instance), + &srn->adv_router); /* if not found, add new Segment Prefix and install NHLFE */ if (!found) { @@ -940,11 +969,11 @@ static void update_ext_prefix_sid(struct sr_node *srn, struct sr_prefix *srp) listnode_add(srn->ext_prefix, srp); /* Try to set MPLS table */ if (compute_prefix_nhlfe(srp) == 1) - add_sid_nhlfe(srp->nhlfe); + update_prefix_sid(srp); } else { if (sr_prefix_cmp(pref, srp)) { if (compute_prefix_nhlfe(srp) == 1) { - update_sid_nhlfe(pref->nhlfe, srp->nhlfe); + delete_prefix_sid(pref); /* Replace Segment Prefix */ listnode_delete(srn->ext_prefix, pref); XFREE(MTYPE_OSPF_SR_PARAMS, pref); @@ -952,6 +981,7 @@ static void update_ext_prefix_sid(struct sr_node *srn, struct sr_prefix *srp) IPV4_ADDR_COPY(&srp->adv_router, &srn->adv_router); listnode_add(srn->ext_prefix, srp); + update_prefix_sid(srp); } else { /* New NHLFE was not found. * Just free the SR Prefix @@ -976,7 +1006,6 @@ static void update_in_nhlfe(struct hash_bucket *bucket, void *args) struct listnode *node; struct sr_node *srn = (struct sr_node *)bucket->data; struct sr_prefix *srp; - struct sr_nhlfe new; /* Process Every Extended Prefix for this SR-Node */ for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) { @@ -989,13 +1018,10 @@ static void update_in_nhlfe(struct hash_bucket *bucket, void *args) if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_VFLG)) continue; - /* OK. Compute new NHLFE */ - memcpy(&new, &srp->nhlfe, sizeof(struct sr_nhlfe)); - new.label_in = index2label(srp->sid, OspfSR.srgb); - /* Update MPLS LFIB */ - update_sid_nhlfe(srp->nhlfe, new); - /* Finally update Input Label */ - srp->nhlfe.label_in = new.label_in; + /* OK. Compute new input label ... */ + srp->label_in = index2label(srp->sid, OspfSR.srgb); + /* ... and update MPLS LFIB */ + update_prefix_sid(srp); } } @@ -1005,21 +1031,26 @@ static void update_in_nhlfe(struct hash_bucket *bucket, void *args) */ static void update_out_nhlfe(struct hash_bucket *bucket, void *args) { - struct listnode *node; + struct listnode *node, *pnode; struct sr_node *srn = (struct sr_node *)bucket->data; struct sr_node *srnext = (struct sr_node *)args; struct sr_prefix *srp; - struct sr_nhlfe new; + struct ospf_path *path; for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) { - /* Process only SID Index for next hop without PHP */ - if ((srp->nexthop == NULL) - && (!CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG))) + /* Process only SID Index with valid route */ + if (srp->or == NULL) continue; - memcpy(&new, &srp->nhlfe, sizeof(struct sr_nhlfe)); - new.label_out = index2label(srp->sid, srnext->srgb); - update_sid_nhlfe(srp->nhlfe, new); - srp->nhlfe.label_out = new.label_out; + + for (ALL_LIST_ELEMENTS_RO(srp->or->paths, pnode, path)) { + /* Process only SID Index for next hop without PHP */ + if ((path->srni.nexthop == NULL) + && (!CHECK_FLAG(srp->flags, + EXT_SUBTLV_PREFIX_SID_NPFLG))) + continue; + path->srni.label_out = index2label(srp->sid, srnext->srgb); + update_prefix_sid(srp); + } } } @@ -1041,12 +1072,9 @@ void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa) struct sr_srgb srgb; uint16_t length = 0, sum = 0; - if (IS_DEBUG_OSPF_SR) - zlog_debug( - "SR (%s): Process Router " - "Information LSA 4.0.0.%u from %s", - __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)), - inet_ntoa(lsah->adv_router)); + osr_debug("SR (%s): Process Router Information LSA 4.0.0.%u from %pI4", + __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)), + &lsah->adv_router); /* Sanity check */ if (IS_LSA_SELF(lsa)) @@ -1158,10 +1186,9 @@ void ospf_sr_ri_lsa_delete(struct ospf_lsa *lsa) struct sr_node *srn; struct lsa_header *lsah = lsa->data; - if (IS_DEBUG_OSPF_SR) - zlog_debug("SR (%s): Remove SR node %s from lsa_id 4.0.0.%u", - __func__, inet_ntoa(lsah->adv_router), - GET_OPAQUE_ID(ntohl(lsah->id.s_addr))); + osr_debug("SR (%s): Remove SR node %pI4 from lsa_id 4.0.0.%u", + __func__, &lsah->adv_router, + GET_OPAQUE_ID(ntohl(lsah->id.s_addr))); /* Sanity check */ if (OspfSR.neighbors == NULL) { @@ -1203,11 +1230,9 @@ void ospf_sr_ext_link_lsa_update(struct ospf_lsa *lsa) uint16_t length, sum; - if (IS_DEBUG_OSPF_SR) - zlog_debug( - "SR (%s): Process Extended Link LSA 8.0.0.%u from %s", - __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)), - inet_ntoa(lsah->adv_router)); + osr_debug("SR (%s): Process Extended Link LSA 8.0.0.%u from %pI4", + __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)), + &lsah->adv_router); /* Sanity check */ if (OspfSR.neighbors == NULL) { @@ -1256,10 +1281,9 @@ void ospf_sr_ext_link_lsa_delete(struct ospf_lsa *lsa) struct lsa_header *lsah = (struct lsa_header *)lsa->data; uint32_t instance = ntohl(lsah->id.s_addr); - if (IS_DEBUG_OSPF_SR) - zlog_debug("SR (%s): Remove Extended Link LSA 8.0.0.%u from %s", - __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)), - inet_ntoa(lsah->adv_router)); + osr_debug("SR (%s): Remove Extended Link LSA 8.0.0.%u from %pI4", + __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)), + &lsah->adv_router); /* Sanity check */ if (OspfSR.neighbors == NULL) { @@ -1290,8 +1314,8 @@ void ospf_sr_ext_link_lsa_delete(struct ospf_lsa *lsa) /* Remove Segment Link if found */ if ((srl != NULL) && (srl->instance == instance)) { - del_sid_nhlfe(srl->nhlfe[0]); - del_sid_nhlfe(srl->nhlfe[1]); + del_adj_sid(srl->nhlfe[0]); + del_adj_sid(srl->nhlfe[1]); listnode_delete(srn->ext_link, srl); XFREE(MTYPE_OSPF_SR_PARAMS, srl); } else { @@ -1313,12 +1337,9 @@ void ospf_sr_ext_prefix_lsa_update(struct ospf_lsa *lsa) uint16_t length, sum; - if (IS_DEBUG_OSPF_SR) - zlog_debug( - "SR (%s): Process Extended Prefix LSA " - "7.0.0.%u from %s", - __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)), - inet_ntoa(lsah->adv_router)); + osr_debug("SR (%s): Process Extended Prefix LSA 7.0.0.%u from %pI4", + __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)), + &lsah->adv_router); /* Sanity check */ if (OspfSR.neighbors == NULL) { @@ -1367,11 +1388,9 @@ void ospf_sr_ext_prefix_lsa_delete(struct ospf_lsa *lsa) struct lsa_header *lsah = (struct lsa_header *)lsa->data; uint32_t instance = ntohl(lsah->id.s_addr); - if (IS_DEBUG_OSPF_SR) - zlog_debug( - "SR (%s): Remove Extended Prefix LSA 7.0.0.%u from %s", - __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)), - inet_ntoa(lsah->adv_router)); + osr_debug("SR (%s): Remove Extended Prefix LSA 7.0.0.%u from %pI4", + __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)), + &lsah->adv_router); /* Sanity check */ if (OspfSR.neighbors == NULL) { @@ -1400,10 +1419,10 @@ void ospf_sr_ext_prefix_lsa_delete(struct ospf_lsa *lsa) if (srp->instance == instance) break; - /* Remove Segment Link if found */ + /* Remove Prefix if found */ if ((srp != NULL) && (srp->instance == instance)) { - del_sid_nhlfe(srp->nhlfe); - listnode_delete(srn->ext_link, srp); + delete_prefix_sid(srp); + listnode_delete(srn->ext_prefix, srp); XFREE(MTYPE_OSPF_SR_PARAMS, srp); } else { flog_err( @@ -1428,14 +1447,14 @@ uint32_t get_ext_link_label_value(void) /* * Update Prefix SID. Call by ospf_ext_pref_ism_change to - * complete initial CLI command at startutp. + * complete initial CLI command at startup. * * @param ifp - Loopback interface * @param pref - Prefix address of this interface * * @return - void */ -void ospf_sr_update_prefix(struct interface *ifp, struct prefix *p) +void ospf_sr_update_local_prefix(struct interface *ifp, struct prefix *p) { struct listnode *node; struct sr_prefix *srp; @@ -1450,29 +1469,31 @@ void ospf_sr_update_prefix(struct interface *ifp, struct prefix *p) */ for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node, srp)) { if ((srp->nhlfe.ifindex == ifp->ifindex) - || ((IPV4_ADDR_SAME(&srp->nhlfe.prefv4.prefix, + || ((IPV4_ADDR_SAME(&srp->prefv4.prefix, &p->u.prefix4)) - && (srp->nhlfe.prefv4.prefixlen == p->prefixlen))) { + && (srp->prefv4.prefixlen == p->prefixlen))) { /* Update Interface & Prefix info */ srp->nhlfe.ifindex = ifp->ifindex; - IPV4_ADDR_COPY(&srp->nhlfe.prefv4.prefix, - &p->u.prefix4); - srp->nhlfe.prefv4.prefixlen = p->prefixlen; - srp->nhlfe.prefv4.family = p->family; + IPV4_ADDR_COPY(&srp->prefv4.prefix, &p->u.prefix4); + srp->prefv4.prefixlen = p->prefixlen; + srp->prefv4.family = p->family; IPV4_ADDR_COPY(&srp->nhlfe.nexthop, &p->u.prefix4); /* OK. Let's Schedule Extended Prefix LSA */ srp->instance = ospf_ext_schedule_prefix_index( - ifp, srp->sid, &srp->nhlfe.prefv4, srp->flags); + ifp, srp->sid, &srp->prefv4, srp->flags); + + osr_debug(" |- Update Node SID %pFX - %u for self SR Node", + (struct prefix *)&srp->prefv4, srp->sid); /* Install NHLFE if NO-PHP is requested */ if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG)) { - srp->nhlfe.label_in = index2label( + srp->label_in = index2label( srp->sid, OspfSR.self->srgb); srp->nhlfe.label_out = MPLS_LABEL_IMPLICIT_NULL; - add_sid_nhlfe(srp->nhlfe); + update_prefix_sid(srp); } } } @@ -1488,12 +1509,10 @@ static void ospf_sr_nhlfe_update(struct hash_bucket *bucket, void *args) struct sr_node *srn = (struct sr_node *)bucket->data; struct listnode *node; struct sr_prefix *srp; - struct sr_nhlfe old; + bool old; int rc; - if (IS_DEBUG_OSPF_SR) - zlog_debug(" |- Update Prefix for SR Node %s", - inet_ntoa(srn->adv_router)); + osr_debug(" |- Update Prefix for SR Node %pI4", &srn->adv_router); /* Skip Self SR Node */ if (srn == OspfSR.self) @@ -1502,24 +1521,25 @@ static void ospf_sr_nhlfe_update(struct hash_bucket *bucket, void *args) /* Update Extended Prefix */ for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) { - /* Backup current NHLFE */ - memcpy(&old, &srp->nhlfe, sizeof(struct sr_nhlfe)); + /* Keep track of valid route */ + old = srp->route != NULL; /* Compute the new NHLFE */ rc = compute_prefix_nhlfe(srp); /* Check computation result */ switch (rc) { - /* next hop is not know, remove old NHLFE to avoid loop */ + /* Routes are not know, remove old NHLFE if any to avoid loop */ case -1: - del_sid_nhlfe(srp->nhlfe); + if (old) + delete_prefix_sid(srp); break; - /* next hop has not changed, skip it */ + /* Routes exist but are not ready, skip it */ case 0: break; - /* there is a new next hop, update NHLFE */ + /* There is at least one route, update NHLFE */ case 1: - update_sid_nhlfe(old, srp->nhlfe); + update_prefix_sid(srp); break; default: break; @@ -1527,22 +1547,17 @@ static void ospf_sr_nhlfe_update(struct hash_bucket *bucket, void *args) } } -static int ospf_sr_update_schedule(struct thread *t) +void ospf_sr_update_task(struct ospf *ospf) { - struct ospf *ospf; struct timeval start_time, stop_time; - ospf = THREAD_ARG(t); - ospf->t_sr_update = NULL; - - if (!OspfSR.update) - return 0; + if (ospf == NULL) + return; monotime(&start_time); - if (IS_DEBUG_OSPF_SR) - zlog_debug("SR (%s): Start SPF update", __func__); + osr_debug("SR (%s): Start SPF update", __func__); hash_iterate(OspfSR.neighbors, (void (*)(struct hash_bucket *, void *))ospf_sr_nhlfe_update, @@ -1550,32 +1565,9 @@ static int ospf_sr_update_schedule(struct thread *t) monotime(&stop_time); - if (IS_DEBUG_OSPF_SR) - zlog_debug("SR (%s): SPF Processing Time(usecs): %lld", - __func__, - (stop_time.tv_sec - start_time.tv_sec) * 1000000LL - + (stop_time.tv_usec - start_time.tv_usec)); - - OspfSR.update = false; - return 1; -} - -#define OSPF_SR_UPDATE_INTERVAL 1 - -void ospf_sr_update_timer_add(struct ospf *ospf) -{ - - if (ospf == NULL) - return; - - /* Check if an update is not alreday engage */ - if (OspfSR.update) - return; - - OspfSR.update = true; - - thread_add_timer(master, ospf_sr_update_schedule, ospf, - OSPF_SR_UPDATE_INTERVAL, &ospf->t_sr_update); + osr_debug("SR (%s): SPF Processing Time(usecs): %lld", __func__, + (stop_time.tv_sec - start_time.tv_sec) * 1000000LL + + (stop_time.tv_usec - start_time.tv_usec)); } /* @@ -1620,8 +1612,8 @@ void ospf_sr_config_write_router(struct vty *vty) vty_out(vty, " segment-routing prefix %s/%u " "index %u%s\n", - inet_ntoa(srp->nhlfe.prefv4.prefix), - srp->nhlfe.prefv4.prefixlen, srp->sid, + inet_ntoa(srp->prefv4.prefix), + srp->prefv4.prefixlen, srp->sid, CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG) ? " no-php-flag" @@ -1650,22 +1642,19 @@ DEFUN(ospf_sr_enable, return CMD_WARNING_CONFIG_FAILED; } - if (IS_DEBUG_OSPF_EVENT) - zlog_debug("SR: Segment Routing: OFF -> ON"); + osr_debug("SR: Segment Routing: OFF -> ON"); /* Start Segment Routing */ OspfSR.enabled = true; ospf_sr_start(ospf); /* Set Router Information SR parameters */ - if (IS_DEBUG_OSPF_EVENT) - zlog_debug("SR: Activate SR for Router Information LSA"); + osr_debug("SR: Activate SR for Router Information LSA"); ospf_router_info_update_sr(true, OspfSR.srgb, OspfSR.msd); /* Update Ext LSA */ - if (IS_DEBUG_OSPF_EVENT) - zlog_debug("SR: Activate SR for Extended Link/Prefix LSA"); + osr_debug("SR: Activate SR for Extended Link/Prefix LSA"); ospf_ext_update_sr(true); @@ -1683,8 +1672,7 @@ DEFUN (no_ospf_sr_enable, if (!OspfSR.enabled) return CMD_SUCCESS; - if (IS_DEBUG_OSPF_EVENT) - zlog_debug("SR: Segment Routing: ON -> OFF"); + osr_debug("SR: Segment Routing: ON -> OFF"); /* Start by Disabling Extended Link & Prefix LSA */ ospf_ext_update_sr(false); @@ -1913,22 +1901,20 @@ DEFUN (sr_prefix_sid, /* Create new Extended Prefix to SRDB if not found */ new = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_prefix)); - IPV4_ADDR_COPY(&new->nhlfe.prefv4.prefix, &p.u.prefix4); - IPV4_ADDR_COPY(&new->nhlfe.nexthop, &p.u.prefix4); - new->nhlfe.prefv4.prefixlen = p.prefixlen; - new->nhlfe.prefv4.family = p.family; + IPV4_ADDR_COPY(&new->prefv4.prefix, &p.u.prefix4); + new->prefv4.prefixlen = p.prefixlen; + new->prefv4.family = p.family; new->sid = index; + new->type = LOCAL_SID; /* Set NO PHP flag if present and compute NHLFE */ if (argv_find(argv, argc, "no-php-flag", &idx)) { SET_FLAG(new->flags, EXT_SUBTLV_PREFIX_SID_NPFLG); - new->nhlfe.label_in = index2label(new->sid, OspfSR.self->srgb); + new->label_in = index2label(new->sid, OspfSR.self->srgb); new->nhlfe.label_out = MPLS_LABEL_IMPLICIT_NULL; } - if (IS_DEBUG_OSPF_SR) - zlog_debug("SR (%s): Add new index %u to Prefix %s/%u", - __func__, index, inet_ntoa(new->nhlfe.prefv4.prefix), - new->nhlfe.prefv4.prefixlen); + osr_debug("SR (%s): Add new index %u to Prefix %pFX", __func__, + index, (struct prefix *)&new->prefv4); /* Get Interface and check if it is a Loopback */ ifp = if_lookup_prefix(&p, VRF_DEFAULT); @@ -1941,9 +1927,8 @@ DEFUN (sr_prefix_sid, */ listnode_add(OspfSR.self->ext_prefix, new); zlog_info( - "Interface for prefix %s/%u not found. Deferred LSA " - "flooding", - inet_ntoa(p.u.prefix4), p.prefixlen); + "Interface for prefix %pFX not found. Deferred LSA " + "flooding", &p); return CMD_SUCCESS; } @@ -1956,8 +1941,8 @@ DEFUN (sr_prefix_sid, /* Search if this prefix already exist */ for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node, srp)) { - if ((IPV4_ADDR_SAME(&srp->nhlfe.prefv4.prefix, &p.u.prefix4) - && srp->nhlfe.prefv4.prefixlen == p.prefixlen)) + if ((IPV4_ADDR_SAME(&srp->prefv4.prefix, &p.u.prefix4) + && srp->prefv4.prefixlen == p.prefixlen)) break; else srp = NULL; @@ -1965,17 +1950,16 @@ DEFUN (sr_prefix_sid, /* Update or Add this new SR Prefix */ if (srp) { - update_sid_nhlfe(srp->nhlfe, new->nhlfe); listnode_delete(OspfSR.self->ext_prefix, srp); listnode_add(OspfSR.self->ext_prefix, new); } else { listnode_add(OspfSR.self->ext_prefix, new); - add_sid_nhlfe(new->nhlfe); } + update_prefix_sid(new); /* Finally, update Extended Prefix LSA */ new->instance = ospf_ext_schedule_prefix_index( - ifp, new->sid, &new->nhlfe.prefv4, new->flags); + ifp, new->sid, &new->prefv4, new->flags); if (new->instance == 0) { vty_out(vty, "Unable to set index %u for prefix %s/%u\n", index, inet_ntoa(p.u.prefix4), p.prefixlen); @@ -2017,8 +2001,8 @@ DEFUN (no_sr_prefix_sid, /* check that the prefix is already set */ for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node, srp)) - if (IPV4_ADDR_SAME(&srp->nhlfe.prefv4.prefix, &p.u.prefix4) - && (srp->nhlfe.prefv4.prefixlen == p.prefixlen)) { + if (IPV4_ADDR_SAME(&srp->prefv4.prefix, &p.u.prefix4) + && (srp->prefv4.prefixlen == p.prefixlen)) { found = true; break; } @@ -2043,14 +2027,12 @@ DEFUN (no_sr_prefix_sid, return CMD_WARNING; } - if (IS_DEBUG_OSPF_SR) - zlog_debug("SR (%s): Remove Prefix %s/%u with index %u", - __func__, inet_ntoa(srp->nhlfe.prefv4.prefix), - srp->nhlfe.prefv4.prefixlen, srp->sid); + osr_debug("SR (%s): Remove Prefix %pFX with index %u", __func__, + (struct prefix *)&srp->prefv4, srp->sid); - /* Delete NHLFE is NO-PHP is set */ + /* Delete NHLFE if NO-PHP is set */ if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG)) - del_sid_nhlfe(srp->nhlfe); + delete_prefix_sid(srp); /* OK, all is clean, remove SRP from SRDB */ listnode_delete(OspfSR.self->ext_prefix, srp); @@ -2060,6 +2042,117 @@ DEFUN (no_sr_prefix_sid, } +static char *sr_op2str(char *buf, size_t size, mpls_label_t label_in, + mpls_label_t label_out) +{ + if (size < 24) + return NULL; + + switch (label_out) { + case MPLS_LABEL_IMPLICIT_NULL: + snprintf(buf, size, "Pop(%u)", label_in); + break; + case MPLS_LABEL_IPV4_EXPLICIT_NULL: + snprintf(buf, size, "Swap(%u, null)", label_in); + break; + case MPLS_INVALID_LABEL: + snprintf(buf, size, "no-op."); + break; + default: + snprintf(buf, size, "Swap(%u, %u)", label_in, label_out); + break; + } + return buf; +} + +static void show_sr_prefix(struct sbuf *sbuf, struct json_object *json, + struct sr_prefix *srp) +{ + + struct listnode *node; + struct ospf_path *path; + struct interface *itf; + json_object *json_route = NULL, *json_obj; + char pref[19]; + char sid[22]; + char op[32]; + int indent = 0; + + snprintf(pref, 19, "%s/%u", inet_ntoa(srp->prefv4.prefix), + srp->prefv4.prefixlen); + snprintf(sid, 22, "SR Pfx (idx %u)", srp->sid); + if (json) { + json_object_string_add(json, "prefix", pref); + json_object_int_add(json, "sid", srp->sid); + json_object_int_add(json, "inputLabel", srp->label_in); + } else { + sbuf_push(sbuf, 0, "%18s %21s ", pref, sid); + } + + /* Check if it is a Local Node SID */ + if (srp->type == LOCAL_SID) { + itf = if_lookup_by_index(srp->nhlfe.ifindex, VRF_DEFAULT); + if (json) { + if (!json_route) { + json_route = json_object_new_array(); + json_object_object_add(json, "prefixRoute", + json_route); + } + json_obj = json_object_new_object(); + json_object_int_add(json_obj, "outputLabel", + srp->nhlfe.label_out); + 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_route, json_obj); + } else { + sbuf_push(sbuf, 0, "%20s %9s %15s\n", + sr_op2str(op, 32, srp->label_in, + srp->nhlfe.label_out), + itf ? itf->name : "-", + inet_ntoa(srp->nhlfe.nexthop)); + } + return; + } + + /* Check if we have a valid path for this prefix */ + if (srp->or == NULL) { + if (!json) { + sbuf_push(sbuf, 0, "\n"); + } + return; + } + + /* Process list of OSPF paths */ + for (ALL_LIST_ELEMENTS_RO(srp->or->paths, node, path)) { + itf = if_lookup_by_index(path->ifindex, VRF_DEFAULT); + if (json) { + if (!json_route) { + json_route = json_object_new_array(); + json_object_object_add(json, "prefixRoute", + json_route); + } + json_obj = json_object_new_object(); + json_object_int_add(json_obj, "outputLabel", + path->srni.label_out); + json_object_string_add(json_obj, "interface", + itf ? itf->name : "-"); + json_object_string_add(json_obj, "nexthop", + inet_ntoa(path->nexthop)); + json_object_array_add(json_route, json_obj); + } else { + sbuf_push(sbuf, indent, "%20s %9s %15s\n", + sr_op2str(op, 32, srp->label_in, + path->srni.label_out), + itf ? itf->name : "-", + inet_ntoa(path->nexthop)); + /* Offset to align information for ECMP */ + indent = 43; + } + } +} + static void show_sr_node(struct vty *vty, struct json_object *json, struct sr_node *srn) { @@ -2068,9 +2161,10 @@ static void show_sr_node(struct vty *vty, struct json_object *json, struct sr_link *srl; struct sr_prefix *srp; struct interface *itf; + struct sbuf sbuf; char pref[19]; char sid[22]; - char label[8]; + char op[32]; json_object *json_node = NULL, *json_algo, *json_obj; json_object *json_prefix = NULL, *json_link = NULL; @@ -2078,6 +2172,8 @@ static void show_sr_node(struct vty *vty, struct json_object *json, if (srn == NULL) return; + sbuf_init(&sbuf, NULL, 0); + if (json) { json_node = json_object_new_object(); json_object_string_add(json_node, "routerID", @@ -2104,41 +2200,32 @@ static void show_sr_node(struct vty *vty, struct json_object *json, 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", + sbuf_push(&sbuf, 0, "SR-Node: %s", inet_ntoa(srn->adv_router)); + sbuf_push(&sbuf, 0, "\tSRGB (Size/Label): %u/%u", + srn->srgb.range_size, srn->srgb.lower_bound); + sbuf_push(&sbuf, 0, "\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", + sbuf_push(&sbuf, 0, "/%s", srn->algo[i] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF"); } if (srn->msd != 0) - vty_out(vty, "\tMSD: %u", srn->msd); + sbuf_push(&sbuf, 0, "\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"); + sbuf_push(&sbuf, 0, + "\n\n Prefix or Link Node or Adj. SID " + " Label Operation Interface Nexthop\n"); + sbuf_push( + &sbuf, 0, + "------------------ --------------------- " + "-------------------- --------- ---------------\n"); } for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) { - snprintf(pref, sizeof(pref), "%s/%u", - inet_ntoa(srp->nhlfe.prefv4.prefix), - srp->nhlfe.prefv4.prefixlen); - snprintf(sid, sizeof(sid), "SR Pfx (idx %u)", srp->sid); - if (srp->nhlfe.label_out == MPLS_LABEL_IMPLICIT_NULL) - snprintf(label, sizeof(label), "pop"); - else - snprintf(label, sizeof(label), "%u", - srp->nhlfe.label_out); - itf = if_lookup_by_index(srp->nhlfe.ifindex, VRF_DEFAULT); if (json) { if (!json_prefix) { json_prefix = json_object_new_array(); @@ -2147,34 +2234,16 @@ static void show_sr_node(struct vty *vty, struct json_object *json, 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)); + show_sr_prefix(NULL, json_obj, srp); 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)); + show_sr_prefix(&sbuf, NULL, srp); } } for (ALL_LIST_ELEMENTS_RO(srn->ext_link, node, srl)) { - snprintf(pref, sizeof(pref), "%s/%u", - inet_ntoa(srl->nhlfe[0].prefv4.prefix), - srl->nhlfe[0].prefv4.prefixlen); - snprintf(sid, sizeof(sid), "SR Adj. (lbl %u)", srl->sid[0]); - if (srl->nhlfe[0].label_out == MPLS_LABEL_IMPLICIT_NULL) - snprintf(label, sizeof(label), "pop"); - else - snprintf(label, sizeof(label), "%u", - srl->nhlfe[0].label_out); + snprintf(pref, 19, "%s/32", inet_ntoa(srl->itf_addr)); + snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[0]); itf = if_lookup_by_index(srl->nhlfe[0].ifindex, VRF_DEFAULT); if (json) { if (!json_link) { @@ -2188,7 +2257,8 @@ static void show_sr_node(struct vty *vty, struct json_object *json, 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_int_add(json_obj, "outputLabel", + srl->nhlfe[0].label_out); json_object_string_add(json_obj, "interface", itf ? itf->name : "-"); json_object_string_add( @@ -2197,18 +2267,13 @@ static void show_sr_node(struct vty *vty, struct json_object *json, json_object_array_add(json_link, json_obj); /* Backup Link */ json_obj = json_object_new_object(); - snprintf(sid, sizeof(sid), "SR Adj. (lbl %u)", - srl->sid[1]); - if (srl->nhlfe[1].label_out == MPLS_LABEL_IMPLICIT_NULL) - snprintf(label, sizeof(label), "pop"); - else - snprintf(label, sizeof(label), "%u", - srl->nhlfe[0].label_out); + snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[1]); 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_int_add(json_obj, "outputLabel", + srl->nhlfe[1].label_out); json_object_string_add(json_obj, "interface", itf ? itf->name : "-"); json_object_string_add( @@ -2216,19 +2281,17 @@ static void show_sr_node(struct vty *vty, struct json_object *json, 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, + sbuf_push(&sbuf, 0, "%18s %21s %20s %9s %15s\n", + pref, sid, sr_op2str(op, 32, + srl->nhlfe[0].label_in, + srl->nhlfe[0].label_out), itf ? itf->name : "-", inet_ntoa(srl->nhlfe[0].nexthop)); - snprintf(sid, sizeof(sid), "SR Adj. (lbl %u)", - srl->sid[1]); - if (srl->nhlfe[1].label_out == MPLS_LABEL_IMPLICIT_NULL) - snprintf(label, sizeof(label), "pop"); - else - snprintf(label, sizeof(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, + snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[1]); + sbuf_push(&sbuf, 0, "%18s %21s %20s %9s %15s\n", + pref, sid, sr_op2str(op, 32, + srl->nhlfe[1].label_in, + srl->nhlfe[1].label_out), itf ? itf->name : "-", inet_ntoa(srl->nhlfe[1].nexthop)); } @@ -2236,7 +2299,9 @@ static void show_sr_node(struct vty *vty, struct json_object *json, if (json) json_object_array_add(json, json_node); else - vty_out(vty, "\n"); + vty_out(vty, "%s\n", sbuf_buf(&sbuf)); + + sbuf_free(&sbuf); } static void show_vty_srdb(struct hash_bucket *bucket, void *args) diff --git a/ospfd/ospf_sr.h b/ospfd/ospf_sr.h index df923e970f..1010d79d6b 100644 --- a/ospfd/ospf_sr.h +++ b/ospfd/ospf_sr.h @@ -51,6 +51,13 @@ #define SID_INDEX 4 #define SID_INDEX_SIZE(U) (U) +/* Macro to log debug message */ +#define osr_debug(...) \ + do { \ + if (IS_DEBUG_OSPF_SR) \ + zlog_debug(__VA_ARGS__); \ + } while (0) + /* SID/Label Sub TLV - section 2.1 */ #define SUBTLV_SID_LABEL 1 #define SUBTLV_SID_LABEL_SIZE 8 @@ -180,16 +187,13 @@ struct sr_srgb { }; /* SID type to make difference between loopback interfaces and others */ -enum sid_type { PREF_SID, ADJ_SID, LAN_ADJ_SID }; +enum sid_type { PREF_SID, LOCAL_SID, ADJ_SID, LAN_ADJ_SID }; /* Structure aggregating all OSPF Segment Routing information for the node */ struct ospf_sr_db { /* Status of Segment Routing: enable or disable */ bool enabled; - /* Ongoing Update following an OSPF SPF */ - bool update; - /* Flooding Scope: Area = 10 or AS = 11 */ uint8_t scope; @@ -237,7 +241,6 @@ struct sr_node { /* Segment Routing - NHLFE info: support IPv4 Only */ struct sr_nhlfe { - struct prefix_ipv4 prefv4; struct in_addr nexthop; ifindex_t ifindex; mpls_label_t label_in; @@ -251,6 +254,9 @@ struct sr_link { /* 24-bit Opaque-ID field value according to RFC 7684 specification */ uint32_t instance; + /* Interface address */ + struct in_addr itf_addr; + /* Flags to manage this link parameters. */ uint8_t flags[2]; @@ -258,7 +264,7 @@ struct sr_link { uint32_t sid[2]; enum sid_type type; - /* SR NHLFE for this link */ + /* SR NHLFE (Primary + Backup) for this link */ struct sr_nhlfe nhlfe[2]; /* Back pointer to SR Node which advertise this Link */ @@ -271,6 +277,9 @@ struct sr_prefix { /* 24-bit Opaque-ID field value according to RFC 7684 specification */ uint32_t instance; + /* Prefix itself */ + struct prefix_ipv4 prefv4; + /* Flags to manage this prefix parameters. */ uint8_t flags; @@ -278,17 +287,17 @@ struct sr_prefix { uint32_t sid; enum sid_type type; - /* SR NHLFE for this prefix */ + /* Incoming label for this prefix */ + mpls_label_t label_in; + + /* Back pointer to OSPF Route for remote prefix */ + struct ospf_route *or; + + /* NHLFE for local prefix */ struct sr_nhlfe nhlfe; /* Back pointer to SR Node which advertise this Prefix */ struct sr_node *srn; - - /* - * Pointer to SR Node which is the next hop for this Prefix - * or NULL if next hop is the destination of the prefix - */ - struct sr_node *nexthop; }; /* Prototypes definition */ @@ -306,7 +315,7 @@ extern void ospf_sr_ext_prefix_lsa_delete(struct ospf_lsa *lsa); /* Segment Routing configuration functions */ extern uint32_t get_ext_link_label_value(void); extern void ospf_sr_config_write_router(struct vty *vty); -extern void ospf_sr_update_prefix(struct interface *ifp, struct prefix *p); +extern void ospf_sr_update_local_prefix(struct interface *ifp, struct prefix *p); /* Segment Routing re-routing function */ -extern void ospf_sr_update_timer_add(struct ospf *ospf); +extern void ospf_sr_update_task(struct ospf *ospf); #endif /* _FRR_OSPF_SR_H */ From b61264a8a3d4cb63eff283304a7a2349ae1f4edf Mon Sep 17 00:00:00 2001 From: Olivier Dugeon Date: Tue, 7 Apr 2020 19:36:12 +0200 Subject: [PATCH 3/6] ospfd: OSPF Segment Routing improvement - Improve parsing of Router Information, especially when a router stops advertising Segment Routing capabilities - Finish conversion to '%pFX' and '%pI4' Signed-off-by: Olivier Dugeon --- ospfd/ospf_sr.c | 303 ++++++++++++++++++++++++--------------------- ospfd/ospf_sr.h | 5 +- ospfd/ospf_zebra.c | 1 + 3 files changed, 164 insertions(+), 145 deletions(-) diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c index de037a4b43..33d994c79c 100644 --- a/ospfd/ospf_sr.c +++ b/ospfd/ospf_sr.c @@ -33,6 +33,7 @@ #include #include +#include "printfrr.h" #include "command.h" #include "hash.h" #include "if.h" @@ -167,6 +168,8 @@ static void sr_node_del(struct sr_node *srn) if (srn == NULL) return; + osr_debug(" |- Delete SR node for %pI4", &srn->adv_router); + /* Clean Extended Link */ list_delete(&srn->ext_link); @@ -509,20 +512,20 @@ static int compute_prefix_nhlfe(struct sr_prefix *srp) /* First determine the nexthop */ - srp->or = get_nexthop_by_addr(top, srp->prefv4); + srp->route = get_nexthop_by_addr(top, srp->prefv4); /* Nexthop could be not found when OSPF Adjacency just fire up * because SPF don't yet populate routing table. This NHLFE will * be fixed later when SR SPF schedule will be called. */ - if (srp->or == NULL) + if (srp->route == NULL) return rc; /* Compute Input Label with self SRGB */ srp->label_in = index2label(srp->sid, OspfSR.srgb); rc = 0; - for (ALL_LIST_ELEMENTS_RO(srp->or->paths, node, path)) { + for (ALL_LIST_ELEMENTS_RO(srp->route->paths, node, path)) { osr_debug(" |- Process new route via %pI4 for this prefix", &path->nexthop); @@ -548,8 +551,8 @@ static int compute_prefix_nhlfe(struct sr_prefix *srp) * This is due to the fact that Extended Link / Prefix could * be received before corresponding Router Information LSA */ - if ((srnext == NULL) || (srnext->srgb.lower_bound == 0) - || (srnext->srgb.range_size == 0)) + if (srnext == NULL || srnext->srgb.lower_bound == 0 + || srnext->srgb.range_size == 0) continue; osr_debug(" |- Found SRGB %u/%u for next hop SR-Node %pI4", @@ -622,14 +625,15 @@ static inline void update_adj_sid(struct sr_nhlfe n1, struct sr_nhlfe n2) } /* Update NHLFE for Prefix SID */ -static void update_prefix_sid (const struct sr_prefix *srp) { +static void update_prefix_sid(const struct sr_prefix *srp) +{ struct zapi_labels zl; struct zapi_nexthop *znh; struct listnode *node; struct ospf_path *path; - osr_debug(" |- Update Labels %u for Prefix %pFX", - srp->label_in, (struct prefix *)&srp->prefv4); + osr_debug(" |- Update Labels %u for Prefix %pFX", srp->label_in, + (struct prefix *)&srp->prefv4); /* Prepare message. */ memset(&zl, 0, sizeof(zl)); @@ -656,11 +660,10 @@ static void update_prefix_sid (const struct sr_prefix *srp) { zl.route.instance = 0; /* Check that SRP contains at least one valid path */ - if ((srp->or == NULL) || (srp->or->paths == NULL) - || (list_isempty(srp->or->paths))) { + if (IS_NO_ROUTE(srp)) { return; } - for (ALL_LIST_ELEMENTS_RO(srp->or->paths, node, path)) { + for (ALL_LIST_ELEMENTS_RO(srp->route->paths, node, path)) { if (path->srni.label_out == MPLS_INVALID_LABEL) continue; @@ -688,8 +691,8 @@ static void delete_prefix_sid(const struct sr_prefix *srp) { struct zapi_labels zl; - osr_debug(" |- Delete Labels %u for Prefix %pFX", - srp->label_in, (struct prefix *)&srp->prefv4); + osr_debug(" |- Delete Labels %u for Prefix %pFX", srp->label_in, + (struct prefix *)&srp->prefv4); /* Prepare message. */ memset(&zl, 0, sizeof(zl)); @@ -820,8 +823,7 @@ static struct sr_prefix *get_ext_prefix_sid(struct tlv_header *tlvh) srp->sid = GET_LABEL(ntohl(psid->value)); else srp->sid = ntohl(psid->value); - IPV4_ADDR_COPY(&srp->prefv4.prefix, - &pref->address); + IPV4_ADDR_COPY(&srp->prefv4.prefix, &pref->address); srp->prefv4.prefixlen = pref->pref_length; srp->prefv4.family = AF_INET; apply_mask_ipv4(&srp->prefv4); @@ -876,10 +878,10 @@ static void update_ext_link_sid(struct sr_node *srn, struct sr_link *srl, osr_debug(" |- Process Extended Link Adj/Lan-SID"); - /* Process only Local Adj/Lan_Adj SID coming from LSA SELF */ - if (!CHECK_FLAG(srl->flags[0], EXT_SUBTLV_LINK_ADJ_SID_LFLG) - || !CHECK_FLAG(srl->flags[1], EXT_SUBTLV_LINK_ADJ_SID_LFLG) - || !CHECK_FLAG(lsa_flags, OSPF_LSA_SELF)) + /* Skip Local Adj/Lan_Adj SID coming from neighbors */ + if (!CHECK_FLAG(lsa_flags, OSPF_LSA_SELF) + && (CHECK_FLAG(srl->flags[0], EXT_SUBTLV_LINK_ADJ_SID_LFLG) + || CHECK_FLAG(srl->flags[1], EXT_SUBTLV_LINK_ADJ_SID_LFLG))) return; /* Search for existing Segment Link */ @@ -1039,16 +1041,17 @@ static void update_out_nhlfe(struct hash_bucket *bucket, void *args) for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) { /* Process only SID Index with valid route */ - if (srp->or == NULL) + if (srp->route == NULL) continue; - for (ALL_LIST_ELEMENTS_RO(srp->or->paths, pnode, path)) { + for (ALL_LIST_ELEMENTS_RO(srp->route->paths, pnode, path)) { /* Process only SID Index for next hop without PHP */ if ((path->srni.nexthop == NULL) && (!CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG))) continue; - path->srni.label_out = index2label(srp->sid, srnext->srgb); + path->srni.label_out = + index2label(srp->sid, srnext->srgb); update_prefix_sid(srp); } } @@ -1067,10 +1070,11 @@ void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa) struct sr_node *srn; struct tlv_header *tlvh; struct lsa_header *lsah = lsa->data; - struct ri_sr_tlv_sid_label_range *ri_srgb; - struct ri_sr_tlv_sr_algorithm *algo; + struct ri_sr_tlv_sid_label_range *ri_srgb = NULL; + struct ri_sr_tlv_sr_algorithm *algo = NULL; struct sr_srgb srgb; uint16_t length = 0, sum = 0; + uint8_t msd = 0; osr_debug("SR (%s): Process Router Information LSA 4.0.0.%u from %pI4", __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)), @@ -1086,26 +1090,10 @@ void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa) return; } - /* Get SR Node in hash table from Router ID */ - srn = hash_get(OspfSR.neighbors, (void *)&(lsah->adv_router), - (void *)sr_node_new); + /* Search SR Node in hash table from Router ID */ + srn = (struct sr_node *)hash_lookup(OspfSR.neighbors, + &lsah->adv_router); - /* Sanity check */ - if (srn == NULL) { - flog_err(EC_OSPF_SR_NODE_CREATE, - "SR (%s): Abort! can't create SR node in hash table", - __func__); - return; - } - - if ((srn->instance != 0) && (srn->instance != ntohl(lsah->id.s_addr))) { - flog_err(EC_OSPF_SR_INVALID_LSA_ID, - "SR (%s): Abort! Wrong " - "LSA ID 4.0.0.%u for SR node %s/%u", - __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)), - inet_ntoa(lsah->adv_router), srn->instance); - return; - } /* Collect Router Information Sub TLVs */ /* Initialize TLV browsing */ @@ -1118,23 +1106,14 @@ void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa) switch (ntohs(tlvh->type)) { case RI_SR_TLV_SR_ALGORITHM: algo = (struct ri_sr_tlv_sr_algorithm *)tlvh; - int i; - - for (i = 0; i < ntohs(algo->header.length); i++) - srn->algo[i] = algo->value[0]; - for (; i < ALGORITHM_COUNT; i++) - srn->algo[i] = SR_ALGORITHM_UNSET; sum += TLV_SIZE(tlvh); break; case RI_SR_TLV_SID_LABEL_RANGE: ri_srgb = (struct ri_sr_tlv_sid_label_range *)tlvh; - srgb.range_size = GET_RANGE_SIZE(ntohl(ri_srgb->size)); - srgb.lower_bound = - GET_LABEL(ntohl(ri_srgb->lower.value)); sum += TLV_SIZE(tlvh); break; case RI_SR_TLV_NODE_MSD: - srn->msd = ((struct ri_sr_tlv_node_msd *)(tlvh))->value; + msd = ((struct ri_sr_tlv_node_msd *)(tlvh))->value; sum += TLV_SIZE(tlvh); break; default: @@ -1143,38 +1122,82 @@ void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa) } } - /* Check that we collect mandatory parameters */ - if (srn->algo[0] == SR_ALGORITHM_UNSET || srgb.range_size == 0 - || srgb.lower_bound == 0) { - flog_err(EC_OSPF_SR_NODE_CREATE, - "SR (%s): Missing mandatory parameters. Abort!", - __func__); - hash_release(OspfSR.neighbors, &(srn->adv_router)); - XFREE(MTYPE_OSPF_SR_PARAMS, srn); + /* Check if Segment Routing Capabilities has been found */ + if (ri_srgb == NULL) { + /* Skip Router Information without SR capabilities + * advertise by a non SR Node */ + if (srn == NULL) { + return; + } else { + /* Remove SR Node that advertise Router Information + * without SR capabilities. This could correspond to a + * Node stopping Segment Routing */ + hash_release(OspfSR.neighbors, &(srn->adv_router)); + sr_node_del(srn); + return; + } + } + + /* Check that RI LSA belongs to the correct SR Node */ + if ((srn != NULL) && (srn->instance != 0) + && (srn->instance != ntohl(lsah->id.s_addr))) { + flog_err(EC_OSPF_SR_INVALID_LSA_ID, + "SR (%s): Abort! Wrong " + "LSA ID 4.0.0.%u for SR node %pI4/%u", + __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)), + &lsah->adv_router, srn->instance); return; } + /* OK. All things look good. Get SRGB */ + srgb.range_size = GET_RANGE_SIZE(ntohl(ri_srgb->size)); + srgb.lower_bound = GET_LABEL(ntohl(ri_srgb->lower.value)); + /* Check if it is a new SR Node or not */ - if (srn->instance == 0) { + if (srn == NULL) { + /* Get a new SR Node in hash table from Router ID */ + srn = (struct sr_node *)hash_get(OspfSR.neighbors, + &lsah->adv_router, + (void *)sr_node_new); + /* Sanity check */ + if (srn == NULL) { + flog_err( + EC_OSPF_SR_NODE_CREATE, + "SR (%s): Abort! can't create SR node in hash table", + __func__); + return; + } /* update LSA ID */ srn->instance = ntohl(lsah->id.s_addr); /* Copy SRGB */ srn->srgb.range_size = srgb.range_size; srn->srgb.lower_bound = srgb.lower_bound; + /* Set Algorithm */ + if (algo != NULL) { + int i; + for (i = 0; i < ntohs(algo->header.length); i++) + srn->algo[i] = algo->value[0]; + for (; i < ALGORITHM_COUNT; i++) + srn->algo[i] = SR_ALGORITHM_UNSET; + } else { + srn->algo[0] = SR_ALGORITHM_SPF; + } + /* set MSD */ + srn->msd = msd; + return; } /* Check if SRGB has changed */ - if ((srn->srgb.range_size != srgb.range_size) - || (srn->srgb.lower_bound != srgb.lower_bound)) { - srn->srgb.range_size = srgb.range_size; - srn->srgb.lower_bound = srgb.lower_bound; - /* Update NHLFE if it is a neighbor SR node */ - if (srn->neighbor == OspfSR.self) - hash_iterate(OspfSR.neighbors, - (void (*)(struct hash_bucket *, - void *))update_out_nhlfe, - (void *)srn); - } + if ((srn->srgb.range_size == srgb.range_size) + && (srn->srgb.lower_bound == srgb.lower_bound)) + return; + + /* Update SRGB ... */ + srn->srgb.range_size = srgb.range_size; + srn->srgb.lower_bound = srgb.lower_bound; + /* ... and NHLFE if it is a neighbor SR node */ + if (srn->neighbor == OspfSR.self) + hash_iterate(OspfSR.neighbors, update_out_nhlfe, srn); } /* @@ -1186,9 +1209,8 @@ void ospf_sr_ri_lsa_delete(struct ospf_lsa *lsa) struct sr_node *srn; struct lsa_header *lsah = lsa->data; - osr_debug("SR (%s): Remove SR node %pI4 from lsa_id 4.0.0.%u", - __func__, &lsah->adv_router, - GET_OPAQUE_ID(ntohl(lsah->id.s_addr))); + osr_debug("SR (%s): Remove SR node %pI4 from lsa_id 4.0.0.%u", __func__, + &lsah->adv_router, GET_OPAQUE_ID(ntohl(lsah->id.s_addr))); /* Sanity check */ if (OspfSR.neighbors == NULL) { @@ -1203,16 +1225,17 @@ void ospf_sr_ri_lsa_delete(struct ospf_lsa *lsa) /* Sanity check */ if (srn == NULL) { flog_err(EC_OSPF_SR_NODE_CREATE, - "SR (%s): Abort! no entry in SRDB for SR Node %s", - __func__, inet_ntoa(lsah->adv_router)); + "SR (%s): Abort! no entry in SRDB for SR Node %pI4", + __func__, &lsah->adv_router); return; } if ((srn->instance != 0) && (srn->instance != ntohl(lsah->id.s_addr))) { - flog_err(EC_OSPF_SR_INVALID_LSA_ID, - "SR (%s): Abort! Wrong LSA ID 4.0.0.%u for SR node %s", - __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)), - inet_ntoa(lsah->adv_router)); + flog_err( + EC_OSPF_SR_INVALID_LSA_ID, + "SR (%s): Abort! Wrong LSA ID 4.0.0.%u for SR node %pI4", + __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)), + &lsah->adv_router); return; } @@ -1278,7 +1301,7 @@ void ospf_sr_ext_link_lsa_delete(struct ospf_lsa *lsa) struct listnode *node; struct sr_link *srl; struct sr_node *srn; - struct lsa_header *lsah = (struct lsa_header *)lsa->data; + struct lsa_header *lsah = lsa->data; uint32_t instance = ntohl(lsah->id.s_addr); osr_debug("SR (%s): Remove Extended Link LSA 8.0.0.%u from %pI4", @@ -1302,8 +1325,8 @@ void ospf_sr_ext_link_lsa_delete(struct ospf_lsa *lsa) */ if (srn == NULL) { flog_err(EC_OSPF_SR_INVALID_DB, - "SR (%s): Stop! no entry in SRDB for SR Node %s", - __func__, inet_ntoa(lsah->adv_router)); + "SR (%s): Stop! no entry in SRDB for SR Node %pI4", + __func__, &lsah->adv_router); return; } @@ -1312,18 +1335,13 @@ void ospf_sr_ext_link_lsa_delete(struct ospf_lsa *lsa) if (srl->instance == instance) break; - /* Remove Segment Link if found */ + /* Remove Segment Link if found. Note that for Neighbors, only Global + * Adj/Lan-Adj SID are stored in the SR-DB */ if ((srl != NULL) && (srl->instance == instance)) { del_adj_sid(srl->nhlfe[0]); del_adj_sid(srl->nhlfe[1]); listnode_delete(srn->ext_link, srl); XFREE(MTYPE_OSPF_SR_PARAMS, srl); - } else { - flog_err(EC_OSPF_SR_INVALID_DB, - "SR (%s): Didn't found corresponding SR Link 8.0.0.%u " - "for SR Node %s", - __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)), - inet_ntoa(lsah->adv_router)); } } @@ -1332,7 +1350,7 @@ void ospf_sr_ext_prefix_lsa_update(struct ospf_lsa *lsa) { struct sr_node *srn; struct tlv_header *tlvh; - struct lsa_header *lsah = lsa->data; + struct lsa_header *lsah = (struct lsa_header *)lsa->data; struct sr_prefix *srp; uint16_t length, sum; @@ -1409,12 +1427,12 @@ void ospf_sr_ext_prefix_lsa_delete(struct ospf_lsa *lsa) */ if (srn == NULL) { flog_err(EC_OSPF_SR_INVALID_DB, - "SR (%s): Stop! no entry in SRDB for SR Node %s", - __func__, inet_ntoa(lsah->adv_router)); + "SR (%s): Stop! no entry in SRDB for SR Node %pI4", + __func__, &lsah->adv_router); return; } - /* Search for corresponding Segment Link */ + /* Search for corresponding Segment Prefix */ for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) if (srp->instance == instance) break; @@ -1427,9 +1445,9 @@ void ospf_sr_ext_prefix_lsa_delete(struct ospf_lsa *lsa) } else { flog_err( EC_OSPF_SR_INVALID_DB, - "SR (%s): Didn't found corresponding SR Prefix 7.0.0.%u for SR Node %s", + "SR (%s): Didn't found corresponding SR Prefix 7.0.0.%u for SR Node %pI4", __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)), - inet_ntoa(lsah->adv_router)); + &lsah->adv_router); } } @@ -1469,8 +1487,7 @@ void ospf_sr_update_local_prefix(struct interface *ifp, struct prefix *p) */ for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node, srp)) { if ((srp->nhlfe.ifindex == ifp->ifindex) - || ((IPV4_ADDR_SAME(&srp->prefv4.prefix, - &p->u.prefix4)) + || ((IPV4_ADDR_SAME(&srp->prefv4.prefix, &p->u.prefix4)) && (srp->prefv4.prefixlen == p->prefixlen))) { /* Update Interface & Prefix info */ @@ -1484,14 +1501,15 @@ void ospf_sr_update_local_prefix(struct interface *ifp, struct prefix *p) srp->instance = ospf_ext_schedule_prefix_index( ifp, srp->sid, &srp->prefv4, srp->flags); - osr_debug(" |- Update Node SID %pFX - %u for self SR Node", - (struct prefix *)&srp->prefv4, srp->sid); + osr_debug( + " |- Update Node SID %pFX - %u for self SR Node", + (struct prefix *)&srp->prefv4, srp->sid); /* Install NHLFE if NO-PHP is requested */ if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG)) { - srp->label_in = index2label( - srp->sid, OspfSR.self->srgb); + srp->label_in = index2label(srp->sid, + OspfSR.self->srgb); srp->nhlfe.label_out = MPLS_LABEL_IMPLICIT_NULL; update_prefix_sid(srp); } @@ -1567,7 +1585,7 @@ void ospf_sr_update_task(struct ospf *ospf) osr_debug("SR (%s): SPF Processing Time(usecs): %lld", __func__, (stop_time.tv_sec - start_time.tv_sec) * 1000000LL - + (stop_time.tv_usec - start_time.tv_usec)); + + (stop_time.tv_usec - start_time.tv_usec)); } /* @@ -1913,8 +1931,8 @@ DEFUN (sr_prefix_sid, new->nhlfe.label_out = MPLS_LABEL_IMPLICIT_NULL; } - osr_debug("SR (%s): Add new index %u to Prefix %pFX", __func__, - index, (struct prefix *)&new->prefv4); + osr_debug("SR (%s): Add new index %u to Prefix %pFX", __func__, index, + (struct prefix *)&new->prefv4); /* Get Interface and check if it is a Loopback */ ifp = if_lookup_prefix(&p, VRF_DEFAULT); @@ -1928,7 +1946,8 @@ DEFUN (sr_prefix_sid, listnode_add(OspfSR.self->ext_prefix, new); zlog_info( "Interface for prefix %pFX not found. Deferred LSA " - "flooding", &p); + "flooding", + &p); return CMD_SUCCESS; } @@ -2078,8 +2097,7 @@ static void show_sr_prefix(struct sbuf *sbuf, struct json_object *json, char op[32]; int indent = 0; - snprintf(pref, 19, "%s/%u", inet_ntoa(srp->prefv4.prefix), - srp->prefv4.prefixlen); + snprintfrr(pref, 19, "%pFX", (struct prefix *)&srp->prefv4); snprintf(sid, 22, "SR Pfx (idx %u)", srp->sid); if (json) { json_object_string_add(json, "prefix", pref); @@ -2108,16 +2126,16 @@ static void show_sr_prefix(struct sbuf *sbuf, struct json_object *json, json_object_array_add(json_route, json_obj); } else { sbuf_push(sbuf, 0, "%20s %9s %15s\n", - sr_op2str(op, 32, srp->label_in, - srp->nhlfe.label_out), - itf ? itf->name : "-", - inet_ntoa(srp->nhlfe.nexthop)); + sr_op2str(op, 32, srp->label_in, + srp->nhlfe.label_out), + itf ? itf->name : "-", + inet_ntoa(srp->nhlfe.nexthop)); } return; } /* Check if we have a valid path for this prefix */ - if (srp->or == NULL) { + if (srp->route == NULL) { if (!json) { sbuf_push(sbuf, 0, "\n"); } @@ -2125,17 +2143,17 @@ static void show_sr_prefix(struct sbuf *sbuf, struct json_object *json, } /* Process list of OSPF paths */ - for (ALL_LIST_ELEMENTS_RO(srp->or->paths, node, path)) { + for (ALL_LIST_ELEMENTS_RO(srp->route->paths, node, path)) { itf = if_lookup_by_index(path->ifindex, VRF_DEFAULT); if (json) { if (!json_route) { json_route = json_object_new_array(); json_object_object_add(json, "prefixRoute", - json_route); + json_route); } json_obj = json_object_new_object(); json_object_int_add(json_obj, "outputLabel", - path->srni.label_out); + path->srni.label_out); json_object_string_add(json_obj, "interface", itf ? itf->name : "-"); json_object_string_add(json_obj, "nexthop", @@ -2143,10 +2161,10 @@ static void show_sr_prefix(struct sbuf *sbuf, struct json_object *json, json_object_array_add(json_route, json_obj); } else { sbuf_push(sbuf, indent, "%20s %9s %15s\n", - sr_op2str(op, 32, srp->label_in, - path->srni.label_out), - itf ? itf->name : "-", - inet_ntoa(path->nexthop)); + sr_op2str(op, 32, srp->label_in, + path->srni.label_out), + itf ? itf->name : "-", + inet_ntoa(path->nexthop)); /* Offset to align information for ECMP */ indent = 43; } @@ -2202,15 +2220,15 @@ static void show_sr_node(struct vty *vty, struct json_object *json, } else { sbuf_push(&sbuf, 0, "SR-Node: %s", inet_ntoa(srn->adv_router)); sbuf_push(&sbuf, 0, "\tSRGB (Size/Label): %u/%u", - srn->srgb.range_size, srn->srgb.lower_bound); + srn->srgb.range_size, srn->srgb.lower_bound); sbuf_push(&sbuf, 0, "\tAlgorithm(s): %s", - srn->algo[0] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF"); + 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; sbuf_push(&sbuf, 0, "/%s", - srn->algo[i] == SR_ALGORITHM_SPF ? "SPF" - : "S-SPF"); + srn->algo[i] == SR_ALGORITHM_SPF ? "SPF" + : "S-SPF"); } if (srn->msd != 0) sbuf_push(&sbuf, 0, "\tMSD: %u", srn->msd); @@ -2218,12 +2236,11 @@ static void show_sr_node(struct vty *vty, struct json_object *json, if (!json) { sbuf_push(&sbuf, 0, - "\n\n Prefix or Link Node or Adj. SID " - " Label Operation Interface Nexthop\n"); - sbuf_push( - &sbuf, 0, - "------------------ --------------------- " - "-------------------- --------- ---------------\n"); + "\n\n Prefix or Link Node or Adj. SID " + " Label Operation Interface Nexthop\n"); + sbuf_push(&sbuf, 0, + "------------------ --------------------- " + "-------------------- --------- ---------------\n"); } for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) { if (json) { @@ -2242,7 +2259,7 @@ static void show_sr_node(struct vty *vty, struct json_object *json, } for (ALL_LIST_ELEMENTS_RO(srn->ext_link, node, srl)) { - snprintf(pref, 19, "%s/32", inet_ntoa(srl->itf_addr)); + snprintfrr(pref, 19, "%pI4/32", &srl->itf_addr); snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[0]); itf = if_lookup_by_index(srl->nhlfe[0].ifindex, VRF_DEFAULT); if (json) { @@ -2282,18 +2299,18 @@ static void show_sr_node(struct vty *vty, struct json_object *json, json_object_array_add(json_link, json_obj); } else { sbuf_push(&sbuf, 0, "%18s %21s %20s %9s %15s\n", - pref, sid, sr_op2str(op, 32, - srl->nhlfe[0].label_in, - srl->nhlfe[0].label_out), - itf ? itf->name : "-", - inet_ntoa(srl->nhlfe[0].nexthop)); + pref, sid, + sr_op2str(op, 32, srl->nhlfe[0].label_in, + srl->nhlfe[0].label_out), + itf ? itf->name : "-", + inet_ntoa(srl->nhlfe[0].nexthop)); snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[1]); sbuf_push(&sbuf, 0, "%18s %21s %20s %9s %15s\n", - pref, sid, sr_op2str(op, 32, - srl->nhlfe[1].label_in, - srl->nhlfe[1].label_out), - itf ? itf->name : "-", - inet_ntoa(srl->nhlfe[1].nexthop)); + pref, sid, + sr_op2str(op, 32, srl->nhlfe[1].label_in, + srl->nhlfe[1].label_out), + itf ? itf->name : "-", + inet_ntoa(srl->nhlfe[1].nexthop)); } } if (json) diff --git a/ospfd/ospf_sr.h b/ospfd/ospf_sr.h index 1010d79d6b..d03da71108 100644 --- a/ospfd/ospf_sr.h +++ b/ospfd/ospf_sr.h @@ -291,7 +291,7 @@ struct sr_prefix { mpls_label_t label_in; /* Back pointer to OSPF Route for remote prefix */ - struct ospf_route *or; + struct ospf_route *route; /* NHLFE for local prefix */ struct sr_nhlfe nhlfe; @@ -315,7 +315,8 @@ extern void ospf_sr_ext_prefix_lsa_delete(struct ospf_lsa *lsa); /* Segment Routing configuration functions */ extern uint32_t get_ext_link_label_value(void); extern void ospf_sr_config_write_router(struct vty *vty); -extern void ospf_sr_update_local_prefix(struct interface *ifp, struct prefix *p); +extern void ospf_sr_update_local_prefix(struct interface *ifp, + struct prefix *p); /* Segment Routing re-routing function */ extern void ospf_sr_update_task(struct ospf *ospf); #endif /* _FRR_OSPF_SR_H */ diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index e8e2fbeaa6..00b90d10c3 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -1351,6 +1351,7 @@ void ospf_zebra_vrf_deregister(struct ospf *ospf) zclient_send_dereg_requests(zclient, ospf->vrf_id); } } + static void ospf_zebra_connected(struct zclient *zclient) { /* Send the client registration */ From 008bcff499bd8d9f5b968c9a90d1c46b951af275 Mon Sep 17 00:00:00 2001 From: Olivier Dugeon Date: Tue, 7 Apr 2020 20:29:28 +0200 Subject: [PATCH 4/6] ospfd: OSPF Segment Routing topostest update Update OSPF Segment Routing topotest in conformity to ECMP - Add one more interface between r1 and r2 for ECMP - Anonymize Adjacency SID - Update expected json output Signed-off-by: Olivier Dugeon --- .../topotests/ospf-sr-topo1/r1/ospf_srdb.json | 91 ++++++++---- tests/topotests/ospf-sr-topo1/r1/ospfd.conf | 5 + tests/topotests/ospf-sr-topo1/r1/zebra.conf | 3 + .../ospf-sr-topo1/r1/zebra_mpls.json | 58 +++++++- .../topotests/ospf-sr-topo1/r2/ospf_srdb.json | 129 +++++++++++------- tests/topotests/ospf-sr-topo1/r2/ospfd.conf | 4 + tests/topotests/ospf-sr-topo1/r2/zebra.conf | 7 +- .../ospf-sr-topo1/r2/zebra_mpls.json | 61 +++++++-- .../topotests/ospf-sr-topo1/r3/ospf_srdb.json | 52 ++++--- tests/topotests/ospf-sr-topo1/r3/ospfd.conf | 1 - .../ospf-sr-topo1/r3/zebra_mpls.json | 8 +- .../topotests/ospf-sr-topo1/r4/ospf_srdb.json | 63 +++++---- .../ospf-sr-topo1/r4/zebra_mpls.json | 11 +- .../ospf-sr-topo1/test_ospf_sr_topo1.py | 30 ++-- 14 files changed, 357 insertions(+), 166 deletions(-) diff --git a/tests/topotests/ospf-sr-topo1/r1/ospf_srdb.json b/tests/topotests/ospf-sr-topo1/r1/ospf_srdb.json index 4ffca6f940..652978aff8 100644 --- a/tests/topotests/ospf-sr-topo1/r1/ospf_srdb.json +++ b/tests/topotests/ospf-sr-topo1/r1/ospf_srdb.json @@ -15,9 +15,18 @@ "prefix":"10.0.255.2\/32", "sid":200, "inputLabel":20200, - "outputLabel":"pop", - "interface":"r1-eth0", - "nexthop":"10.0.1.2" + "prefixRoute":[ + { + "outputLabel":3, + "interface":"r1-eth0", + "nexthop":"10.0.0.2" + }, + { + "outputLabel":3, + "interface":"r1-eth1", + "nexthop":"10.0.1.2" + } + ] } ] }, @@ -36,9 +45,18 @@ "prefix":"10.0.255.4\/32", "sid":400, "inputLabel":20400, - "outputLabel":"8400", - "interface":"r1-eth0", - "nexthop":"10.0.1.2" + "prefixRoute":[ + { + "outputLabel":8400, + "interface":"r1-eth0", + "nexthop":"10.0.0.2" + }, + { + "outputLabel":8400, + "interface":"r1-eth1", + "nexthop":"10.0.1.2" + } + ] } ] }, @@ -47,19 +65,24 @@ "srgbSize":10000, "srgbLabel":10000, "algorithms":[ - { - "0":"SPF" - } ], - "nodeMsd":8, "extendedPrefix":[ { "prefix":"10.0.255.3\/32", "sid":300, "inputLabel":20300, - "outputLabel":"8300", - "interface":"r1-eth0", - "nexthop":"10.0.1.2" + "prefixRoute":[ + { + "outputLabel":8300, + "interface":"r1-eth0", + "nexthop":"10.0.0.2" + }, + { + "outputLabel":8300, + "interface":"r1-eth1", + "nexthop":"10.0.1.2" + } + ] } ] }, @@ -78,26 +101,46 @@ "prefix":"10.0.255.1\/32", "sid":100, "inputLabel":20100, - "outputLabel":"pop", - "interface":"lo", - "nexthop":"10.0.255.1" + "prefixRoute":[ + { + "outputLabel":3, + "interface":"lo", + "nexthop":"10.0.255.1" + } + ] } ], "extendedLink":[ { - "prefix":"10.0.1.1\/32", - "sid":50001, - "inputLabel":50001, - "outputLabel":"pop", + "prefix":"10.0.0.1\/32", + "sid":"XX", + "inputLabel":"XX", + "outputLabel":3, "interface":"r1-eth0", + "nexthop":"10.0.0.2" + }, + { + "prefix":"10.0.0.1\/32", + "sid":"XX", + "inputLabel":"XX", + "outputLabel":3, + "interface":"r1-eth0", + "nexthop":"10.0.0.2" + }, + { + "prefix":"10.0.1.1\/32", + "sid":"XX", + "inputLabel":"XX", + "outputLabel":3, + "interface":"r1-eth1", "nexthop":"10.0.1.2" }, { "prefix":"10.0.1.1\/32", - "sid":50000, - "inputLabel":50000, - "outputLabel":"pop", - "interface":"r1-eth0", + "sid":"XX", + "inputLabel":"XX", + "outputLabel":3, + "interface":"r1-eth1", "nexthop":"10.0.1.2" } ] diff --git a/tests/topotests/ospf-sr-topo1/r1/ospfd.conf b/tests/topotests/ospf-sr-topo1/r1/ospfd.conf index e8593d1a1a..292d4e6367 100644 --- a/tests/topotests/ospf-sr-topo1/r1/ospfd.conf +++ b/tests/topotests/ospf-sr-topo1/r1/ospfd.conf @@ -3,6 +3,11 @@ interface lo ip ospf area 0.0.0.0 ! interface r1-eth0 + ip ospf network point-to-point + ip ospf area 0.0.0.0 +! +interface r1-eth1 + ip ospf network point-to-point ip ospf area 0.0.0.0 ! router ospf diff --git a/tests/topotests/ospf-sr-topo1/r1/zebra.conf b/tests/topotests/ospf-sr-topo1/r1/zebra.conf index f1fcc7dd3b..faf71db25c 100644 --- a/tests/topotests/ospf-sr-topo1/r1/zebra.conf +++ b/tests/topotests/ospf-sr-topo1/r1/zebra.conf @@ -3,6 +3,9 @@ interface lo ip address 10.0.255.1/32 ! interface r1-eth0 + ip address 10.0.0.1/24 +! +interface r1-eth1 ip address 10.0.1.1/24 ! ip forwarding diff --git a/tests/topotests/ospf-sr-topo1/r1/zebra_mpls.json b/tests/topotests/ospf-sr-topo1/r1/zebra_mpls.json index 6b1fe76b6e..88ba28da42 100644 --- a/tests/topotests/ospf-sr-topo1/r1/zebra_mpls.json +++ b/tests/topotests/ospf-sr-topo1/r1/zebra_mpls.json @@ -7,8 +7,7 @@ "type":"SR (OSPF)", "outLabel":3, "distance":150, - "installed":true, - "nexthop":"10.0.255.1" + "installed":true } ] }, @@ -22,6 +21,13 @@ "distance":150, "installed":true, "nexthop":"10.0.1.2" + }, + { + "type":"SR (OSPF)", + "outLabel":3, + "distance":150, + "installed":true, + "nexthop":"10.0.0.2" } ] }, @@ -35,6 +41,13 @@ "distance":150, "installed":true, "nexthop":"10.0.1.2" + }, + { + "type":"SR (OSPF)", + "outLabel":8300, + "distance":150, + "installed":true, + "nexthop":"10.0.0.2" } ] }, @@ -48,11 +61,44 @@ "distance":150, "installed":true, "nexthop":"10.0.1.2" + }, + { + "type":"SR (OSPF)", + "outLabel":8400, + "distance":150, + "installed":true, + "nexthop":"10.0.0.2" } ] }, - "50000":{ - "inLabel":50000, + "XX":{ + "inLabel":"XX", + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "distance":150, + "installed":true, + "nexthop":"10.0.0.2" + } + ] + }, + "XX":{ + "inLabel":"XX", + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "distance":150, + "installed":true, + "nexthop":"10.0.0.2" + } + ] + }, + "XX":{ + "inLabel":"XX", "installed":true, "nexthops":[ { @@ -64,8 +110,8 @@ } ] }, - "50001":{ - "inLabel":50001, + "XX":{ + "inLabel":"XX", "installed":true, "nexthops":[ { diff --git a/tests/topotests/ospf-sr-topo1/r2/ospf_srdb.json b/tests/topotests/ospf-sr-topo1/r2/ospf_srdb.json index 2548299cc7..13437c9cf5 100644 --- a/tests/topotests/ospf-sr-topo1/r2/ospf_srdb.json +++ b/tests/topotests/ospf-sr-topo1/r2/ospf_srdb.json @@ -15,59 +15,79 @@ "prefix":"10.0.255.2\/32", "sid":200, "inputLabel":0, - "outputLabel":"0", - "interface":"lo", - "nexthop":"10.0.255.2" + "prefixRoute":[ + { + "outputLabel":0, + "interface":"lo", + "nexthop":"10.0.255.2" + } + ] } ], "extendedLink":[ { "prefix":"10.0.4.2\/32", - "sid":50001, - "inputLabel":50001, - "outputLabel":"pop", - "interface":"r2-eth2", + "sid":"XX", + "inputLabel":"XX", + "outputLabel":3, + "interface":"r2-eth3", "nexthop":"10.0.4.1" }, { "prefix":"10.0.4.2\/32", - "sid":50000, - "inputLabel":50000, - "outputLabel":"pop", - "interface":"r2-eth2", + "sid":"XX", + "inputLabel":"XX", + "outputLabel":3, + "interface":"r2-eth3", "nexthop":"10.0.4.1" }, { - "prefix":"10.0.3.2\/32", - "sid":50003, - "inputLabel":50003, - "outputLabel":"pop", - "interface":"r2-eth1", - "nexthop":"10.0.3.1" + "prefix":"10.0.0.2\/32", + "sid":"XX", + "inputLabel":"XX", + "outputLabel":3, + "interface":"r2-eth0", + "nexthop":"10.0.0.1" }, { - "prefix":"10.0.3.2\/32", - "sid":50002, - "inputLabel":50002, - "outputLabel":"pop", - "interface":"r2-eth1", - "nexthop":"10.0.3.1" + "prefix":"10.0.0.2\/32", + "sid":"XX", + "inputLabel":"XX", + "outputLabel":3, + "interface":"r2-eth0", + "nexthop":"10.0.0.1" }, { "prefix":"10.0.1.2\/32", - "sid":50005, - "inputLabel":50005, - "outputLabel":"pop", - "interface":"r2-eth0", + "sid":"XX", + "inputLabel":"XX", + "outputLabel":3, + "interface":"r2-eth1", "nexthop":"10.0.1.1" }, { "prefix":"10.0.1.2\/32", - "sid":50004, - "inputLabel":50004, - "outputLabel":"pop", - "interface":"r2-eth0", + "sid":"XX", + "inputLabel":"XX", + "outputLabel":3, + "interface":"r2-eth1", "nexthop":"10.0.1.1" + }, + { + "prefix":"10.0.3.2\/32", + "sid":"XX", + "inputLabel":"XX", + "outputLabel":3, + "interface":"r2-eth2", + "nexthop":"10.0.3.1" + }, + { + "prefix":"10.0.3.2\/32", + "sid":"XX", + "inputLabel":"XX", + "outputLabel":3, + "interface":"r2-eth2", + "nexthop":"10.0.3.1" } ] }, @@ -76,19 +96,19 @@ "srgbSize":10000, "srgbLabel":10000, "algorithms":[ - { - "0":"SPF" - } ], - "nodeMsd":12, "extendedPrefix":[ { "prefix":"10.0.255.4\/32", "sid":400, "inputLabel":8400, - "outputLabel":"10400", - "interface":"r2-eth2", - "nexthop":"10.0.4.1" + "prefixRoute":[ + { + "outputLabel":10400, + "interface":"r2-eth3", + "nexthop":"10.0.4.1" + } + ] } ] }, @@ -97,19 +117,19 @@ "srgbSize":10000, "srgbLabel":10000, "algorithms":[ - { - "0":"SPF" - } ], - "nodeMsd":8, "extendedPrefix":[ { "prefix":"10.0.255.3\/32", "sid":300, "inputLabel":8300, - "outputLabel":"pop", - "interface":"r2-eth1", - "nexthop":"10.0.3.1" + "prefixRoute":[ + { + "outputLabel":3, + "interface":"r2-eth2", + "nexthop":"10.0.3.1" + } + ] } ] }, @@ -118,19 +138,24 @@ "srgbSize":10000, "srgbLabel":20000, "algorithms":[ - { - "0":"SPF" - } ], - "nodeMsd":16, "extendedPrefix":[ { "prefix":"10.0.255.1\/32", "sid":100, "inputLabel":8100, - "outputLabel":"20100", - "interface":"r2-eth0", - "nexthop":"10.0.1.1" + "prefixRoute":[ + { + "outputLabel":20100, + "interface":"r2-eth0", + "nexthop":"10.0.0.1" + }, + { + "outputLabel":20100, + "interface":"r2-eth1", + "nexthop":"10.0.1.1" + } + ] } ] } diff --git a/tests/topotests/ospf-sr-topo1/r2/ospfd.conf b/tests/topotests/ospf-sr-topo1/r2/ospfd.conf index 4d6146aaa7..b8c7b999e8 100644 --- a/tests/topotests/ospf-sr-topo1/r2/ospfd.conf +++ b/tests/topotests/ospf-sr-topo1/r2/ospfd.conf @@ -5,6 +5,7 @@ interface lo ip ospf area 0.0.0.0 ! interface r2-eth0 + ip ospf network point-to-point ip ospf area 0.0.0.0 ! interface r2-eth1 @@ -12,6 +13,9 @@ interface r2-eth1 ip ospf area 0.0.0.0 ! interface r2-eth2 + ip ospf area 0.0.0.0 +! +interface r2-eth3 ip ospf network point-to-point ip ospf area 0.0.0.0 ! diff --git a/tests/topotests/ospf-sr-topo1/r2/zebra.conf b/tests/topotests/ospf-sr-topo1/r2/zebra.conf index f89548d8c5..ba1d833f50 100644 --- a/tests/topotests/ospf-sr-topo1/r2/zebra.conf +++ b/tests/topotests/ospf-sr-topo1/r2/zebra.conf @@ -3,12 +3,15 @@ interface lo ip address 10.0.255.2/32 ! interface r2-eth0 - ip address 10.0.1.2/24 + ip address 10.0.0.2/24 ! interface r2-eth1 - ip address 10.0.3.2/24 + ip address 10.0.1.2/24 ! interface r2-eth2 + ip address 10.0.3.2/24 +! +interface r2-eth3 ip address 10.0.4.2/24 ! ip forwarding diff --git a/tests/topotests/ospf-sr-topo1/r2/zebra_mpls.json b/tests/topotests/ospf-sr-topo1/r2/zebra_mpls.json index 79965d280a..2931b7dc34 100644 --- a/tests/topotests/ospf-sr-topo1/r2/zebra_mpls.json +++ b/tests/topotests/ospf-sr-topo1/r2/zebra_mpls.json @@ -9,6 +9,13 @@ "distance":150, "installed":true, "nexthop":"10.0.1.1" + }, + { + "type":"SR (OSPF)", + "outLabel":20100, + "distance":150, + "installed":true, + "nexthop":"10.0.0.1" } ] }, @@ -38,8 +45,8 @@ } ] }, - "50000":{ - "inLabel":50000, + "XX":{ + "inLabel":"XX", "installed":true, "nexthops":[ { @@ -51,8 +58,8 @@ } ] }, - "50001":{ - "inLabel":50001, + "XX":{ + "inLabel":"XX", "installed":true, "nexthops":[ { @@ -64,8 +71,8 @@ } ] }, - "50002":{ - "inLabel":50002, + "XX":{ + "inLabel":"XX", "installed":true, "nexthops":[ { @@ -73,12 +80,12 @@ "outLabel":3, "distance":150, "installed":true, - "nexthop":"10.0.3.1" + "nexthop":"10.0.0.1" } ] }, - "50003":{ - "inLabel":50003, + "XX":{ + "inLabel":"XX", "installed":true, "nexthops":[ { @@ -86,12 +93,12 @@ "outLabel":3, "distance":150, "installed":true, - "nexthop":"10.0.3.1" + "nexthop":"10.0.0.1" } ] }, - "50004":{ - "inLabel":50004, + "XX":{ + "inLabel":"XX", "installed":true, "nexthops":[ { @@ -103,8 +110,8 @@ } ] }, - "50005":{ - "inLabel":50005, + "XX":{ + "inLabel":"XX", "installed":true, "nexthops":[ { @@ -115,5 +122,31 @@ "nexthop":"10.0.1.1" } ] + }, + "XX":{ + "inLabel":"XX", + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "distance":150, + "installed":true, + "nexthop":"10.0.3.1" + } + ] + }, + "XX":{ + "inLabel":"XX", + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "distance":150, + "installed":true, + "nexthop":"10.0.3.1" + } + ] } } diff --git a/tests/topotests/ospf-sr-topo1/r3/ospf_srdb.json b/tests/topotests/ospf-sr-topo1/r3/ospf_srdb.json index 4b618cc7ad..d070aafb1e 100644 --- a/tests/topotests/ospf-sr-topo1/r3/ospf_srdb.json +++ b/tests/topotests/ospf-sr-topo1/r3/ospf_srdb.json @@ -15,9 +15,13 @@ "prefix":"10.0.255.2\/32", "sid":200, "inputLabel":10200, - "outputLabel":"pop", - "interface":"r3-eth0", - "nexthop":"10.0.3.2" + "prefixRoute":[ + { + "outputLabel":3, + "interface":"r3-eth0", + "nexthop":"10.0.3.2" + } + ] } ] }, @@ -36,9 +40,13 @@ "prefix":"10.0.255.4\/32", "sid":400, "inputLabel":10400, - "outputLabel":"8400", - "interface":"r3-eth0", - "nexthop":"10.0.3.2" + "prefixRoute":[ + { + "outputLabel":8400, + "interface":"r3-eth0", + "nexthop":"10.0.3.2" + } + ] } ] }, @@ -57,25 +65,29 @@ "prefix":"10.0.255.3\/32", "sid":300, "inputLabel":0, - "outputLabel":"0", - "interface":"lo", - "nexthop":"10.0.255.3" + "prefixRoute":[ + { + "outputLabel":0, + "interface":"lo", + "nexthop":"10.0.255.3" + } + ] } ], "extendedLink":[ { "prefix":"10.0.3.1\/32", - "sid":50001, - "inputLabel":50001, - "outputLabel":"pop", + "sid":"XX", + "inputLabel":"XX", + "outputLabel":3, "interface":"r3-eth0", "nexthop":"10.0.3.2" }, { "prefix":"10.0.3.1\/32", - "sid":50000, - "inputLabel":50000, - "outputLabel":"pop", + "sid":"XX", + "inputLabel":"XX", + "outputLabel":3, "interface":"r3-eth0", "nexthop":"10.0.3.2" } @@ -96,9 +108,13 @@ "prefix":"10.0.255.1\/32", "sid":100, "inputLabel":10100, - "outputLabel":"8100", - "interface":"r3-eth0", - "nexthop":"10.0.3.2" + "prefixRoute":[ + { + "outputLabel":8100, + "interface":"r3-eth0", + "nexthop":"10.0.3.2" + } + ] } ] } diff --git a/tests/topotests/ospf-sr-topo1/r3/ospfd.conf b/tests/topotests/ospf-sr-topo1/r3/ospfd.conf index 5aaa14fac4..cf274bed2e 100644 --- a/tests/topotests/ospf-sr-topo1/r3/ospfd.conf +++ b/tests/topotests/ospf-sr-topo1/r3/ospfd.conf @@ -3,7 +3,6 @@ interface lo ip ospf area 0.0.0.0 ! interface r3-eth0 - ip ospf network point-to-point ip ospf area 0.0.0.0 ! ! diff --git a/tests/topotests/ospf-sr-topo1/r3/zebra_mpls.json b/tests/topotests/ospf-sr-topo1/r3/zebra_mpls.json index ceb2f7a0e5..c9264d8a42 100644 --- a/tests/topotests/ospf-sr-topo1/r3/zebra_mpls.json +++ b/tests/topotests/ospf-sr-topo1/r3/zebra_mpls.json @@ -38,8 +38,8 @@ } ] }, - "50000":{ - "inLabel":50000, + "XX":{ + "inLabel":"XX", "installed":true, "nexthops":[ { @@ -51,8 +51,8 @@ } ] }, - "50001":{ - "inLabel":50001, + "XX":{ + "inLabel":"XX", "installed":true, "nexthops":[ { diff --git a/tests/topotests/ospf-sr-topo1/r4/ospf_srdb.json b/tests/topotests/ospf-sr-topo1/r4/ospf_srdb.json index 098e87dc25..17c0ea276e 100644 --- a/tests/topotests/ospf-sr-topo1/r4/ospf_srdb.json +++ b/tests/topotests/ospf-sr-topo1/r4/ospf_srdb.json @@ -6,18 +6,19 @@ "srgbSize":20000, "srgbLabel":8000, "algorithms":[ - { - "0":"SPF" - } ], "extendedPrefix":[ { "prefix":"10.0.255.2\/32", "sid":200, "inputLabel":10200, - "outputLabel":"pop", - "interface":"r4-eth0", - "nexthop":"10.0.4.2" + "prefixRoute":[ + { + "outputLabel":3, + "interface":"r4-eth0", + "nexthop":"10.0.4.2" + } + ] } ] }, @@ -36,25 +37,29 @@ "prefix":"10.0.255.4\/32", "sid":400, "inputLabel":10400, - "outputLabel":"pop", - "interface":"lo", - "nexthop":"10.0.255.4" + "prefixRoute":[ + { + "outputLabel":3, + "interface":"lo", + "nexthop":"10.0.255.4" + } + ] } ], "extendedLink":[ { "prefix":"10.0.4.1\/32", - "sid":50001, - "inputLabel":50001, - "outputLabel":"pop", + "sid":"XX", + "inputLabel":"XX", + "outputLabel":3, "interface":"r4-eth0", "nexthop":"10.0.4.2" }, { "prefix":"10.0.4.1\/32", - "sid":50000, - "inputLabel":50000, - "outputLabel":"pop", + "sid":"XX", + "inputLabel":"XX", + "outputLabel":3, "interface":"r4-eth0", "nexthop":"10.0.4.2" } @@ -65,19 +70,19 @@ "srgbSize":10000, "srgbLabel":10000, "algorithms":[ - { - "0":"SPF" - } ], - "nodeMsd":8, "extendedPrefix":[ { "prefix":"10.0.255.3\/32", "sid":300, "inputLabel":10300, - "outputLabel":"8300", - "interface":"r4-eth0", - "nexthop":"10.0.4.2" + "prefixRoute":[ + { + "outputLabel":8300, + "interface":"r4-eth0", + "nexthop":"10.0.4.2" + } + ] } ] }, @@ -86,19 +91,19 @@ "srgbSize":10000, "srgbLabel":20000, "algorithms":[ - { - "0":"SPF" - } ], - "nodeMsd":16, "extendedPrefix":[ { "prefix":"10.0.255.1\/32", "sid":100, "inputLabel":10100, - "outputLabel":"8100", - "interface":"r4-eth0", - "nexthop":"10.0.4.2" + "prefixRoute":[ + { + "outputLabel":8100, + "interface":"r4-eth0", + "nexthop":"10.0.4.2" + } + ] } ] } diff --git a/tests/topotests/ospf-sr-topo1/r4/zebra_mpls.json b/tests/topotests/ospf-sr-topo1/r4/zebra_mpls.json index d7f54b224d..3a829fa858 100644 --- a/tests/topotests/ospf-sr-topo1/r4/zebra_mpls.json +++ b/tests/topotests/ospf-sr-topo1/r4/zebra_mpls.json @@ -46,13 +46,12 @@ "type":"SR (OSPF)", "outLabel":3, "distance":150, - "installed":true, - "nexthop":"10.0.255.4" + "installed":true } ] }, - "50000":{ - "inLabel":50000, + "XX":{ + "inLabel":"XX", "installed":true, "nexthops":[ { @@ -64,8 +63,8 @@ } ] }, - "50001":{ - "inLabel":50001, + "XX":{ + "inLabel":"XX", "installed":true, "nexthops":[ { diff --git a/tests/topotests/ospf-sr-topo1/test_ospf_sr_topo1.py b/tests/topotests/ospf-sr-topo1/test_ospf_sr_topo1.py index 92cebfe0b6..114de5861b 100755 --- a/tests/topotests/ospf-sr-topo1/test_ospf_sr_topo1.py +++ b/tests/topotests/ospf-sr-topo1/test_ospf_sr_topo1.py @@ -27,6 +27,7 @@ test_ospf_sr_topo1.py: Test the FRR OSPF routing daemon with Segment Routing. """ import os +import re import sys from functools import partial @@ -62,20 +63,23 @@ class OspfSrTopo(Topo): for routern in range(1, 5): tgen.add_router("r{}".format(routern)) - # Interconect router 1 and 2 - switch = tgen.add_switch("s1") - switch.add_link(tgen.gears["r1"]) - switch.add_link(tgen.gears["r2"]) + # Interconect router 1 and 2 with 2 links + 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.add_link(tgen.gears['r2']) # Interconect router 3 and 2 - switch = tgen.add_switch("s2") - switch.add_link(tgen.gears["r3"]) - switch.add_link(tgen.gears["r2"]) + switch = tgen.add_switch('s3') + switch.add_link(tgen.gears['r3']) + switch.add_link(tgen.gears['r2']) # Interconect router 4 and 2 - switch = tgen.add_switch("s3") - switch.add_link(tgen.gears["r4"]) - switch.add_link(tgen.gears["r2"]) + switch = tgen.add_switch('s4') + switch.add_link(tgen.gears['r4']) + switch.add_link(tgen.gears['r2']) def setup_module(mod): @@ -130,6 +134,9 @@ def compare_ospf_srdb(rname, expected): """ tgen = get_topogen() current = tgen.gears[rname].vtysh_cmd("show ip ospf database segment-routing json") + # Filter Adjacency SID allocation + current = re.sub(r'"sid":5000[0-9],', '"sid":"XX",', current) + current = re.sub(r'"inputLabel":5000[0-9],', '"inputLabel":"XX",', current) return topotest.difflines( current, expected, title1="Current output", title2="Expected output" ) @@ -142,6 +149,9 @@ def compare_mpls_table(rname, expected): """ tgen = get_topogen() current = tgen.gears[rname].vtysh_cmd("show mpls table json") + # Filter Adjacency SID allocation + current = re.sub(r'"5000[0-9]":', '"XX":', current) + current = re.sub(r'"inLabel":5000[0-9],', '"inLabel":"XX",', current) return topotest.difflines( current, expected, title1="Current output", title2="Expected output" ) From 21baf89affbcffdd02fd557e81d16b80850266ca Mon Sep 17 00:00:00 2001 From: Olivier Dugeon Date: Tue, 12 May 2020 16:42:38 +0200 Subject: [PATCH 5/6] ospfd: Update Prefix & Adjacency SIDs Management SIDs are not uninstall in LFIB when ospf adjacenyi or loopback goes down as self LSA flusing is not handle by ospf_ext_link_lsa_update(). The patch introduces new functions ospf_sr_ext_itf_add() and ospf_sr_ext_itf_delete() in ospf_sr.c to directly manage LFIB for SIDs when change is detected in ospf_ext_link_ism_change() and ospf_ext_link_nsm_change(). Signed-off-by: Olivier Dugeon --- ospfd/ospf_ext.c | 75 ++++++++++++++++++++++---- ospfd/ospf_sr.c | 138 ++++++++++++++++++++++++++++++++++++++++++++--- ospfd/ospf_sr.h | 4 ++ 3 files changed, 201 insertions(+), 16 deletions(-) diff --git a/ospfd/ospf_ext.c b/ospfd/ospf_ext.c index 14f38bc330..86088a7137 100644 --- a/ospfd/ospf_ext.c +++ b/ospfd/ospf_ext.c @@ -443,6 +443,32 @@ static void set_rmt_itf_addr(struct ext_itf *exti, struct in_addr rmtif) exti->rmt_itf_addr.value = rmtif; } +/* Delete Extended LSA */ +static void ospf_extended_lsa_delete(struct ext_itf *exti) +{ + + /* Process only Active Extended Prefix/Link LSA */ + if (!CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE)) + return; + + osr_debug("EXT (%s): Disable %s%s%s-SID on interface %s", __func__, + exti->stype == PREF_SID ? "Prefix" : "", + exti->stype == ADJ_SID ? "Adjacency" : "", + exti->stype == LAN_ADJ_SID ? "LAN-Adjacency" : "", + exti->ifp->name); + + /* Flush LSA if already engaged */ + if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED)) { + ospf_ext_lsa_schedule(exti, FLUSH_THIS_LSA); + UNSET_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED); + } + + /* De-activate this Extended Prefix/Link and remove corresponding + * Segment-Routing Prefix-SID or (LAN)-ADJ-SID */ + exti->flags = EXT_LPFLG_LSA_INACTIVE; + ospf_sr_ext_itf_delete(exti); +} + /* * Update Extended prefix SID index for Loopback interface type * @@ -516,6 +542,7 @@ void ospf_ext_update_sr(bool enable) /* Refresh LSAs if already engaged or originate */ for (ALL_LIST_ELEMENTS_RO(OspfEXT.iflist, node, exti)) { + /* Skip inactive Extended Link */ if (!CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE)) continue; @@ -526,17 +553,15 @@ void ospf_ext_update_sr(bool enable) REORIGINATE_THIS_LSA); } } else { - /* Start by Flushing engaged LSAs */ - for (ALL_LIST_ELEMENTS_RO(OspfEXT.iflist, node, exti)) { - if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED)) - ospf_ext_lsa_schedule(exti, FLUSH_THIS_LSA); - exti->flags = EXT_LPFLG_LSA_INACTIVE; - } + /* Start by Removing Extended LSA */ + for (ALL_LIST_ELEMENTS_RO(OspfEXT.iflist, node, exti)) + ospf_extended_lsa_delete(exti); /* And then disable Extended Link/Prefix */ OspfEXT.enabled = false; } } + /* * ----------------------------------------------------------------------- * Followings are callback functions against generic Opaque-LSAs handling @@ -574,10 +599,11 @@ static int ospf_ext_link_del_if(struct interface *ifp) exti = lookup_ext_by_ifp(ifp); if (exti != NULL) { - struct list *iflist = OspfEXT.iflist; + /* Flush LSA and remove Adjacency SID */ + ospf_extended_lsa_delete(exti); /* Dequeue listnode entry from the list. */ - listnode_delete(iflist, exti); + listnode_delete(OspfEXT.iflist, exti); XFREE(MTYPE_OSPF_EXT_PARAMS, exti); @@ -610,6 +636,7 @@ static void ospf_ext_ism_change(struct ospf_interface *oi, int old_status) /* Reset Extended information if ospf interface goes Down */ if (oi->state == ISM_Down) { + ospf_extended_lsa_delete(exti); exti->area = NULL; exti->flags = EXT_LPFLG_LSA_INACTIVE; return; @@ -660,8 +687,8 @@ static void ospf_ext_link_nsm_change(struct ospf_neighbor *nbr, int old_status) struct ext_itf *exti; uint32_t label; - /* Process Neighbor only when its state is NSM Full */ - if (nbr->state != NSM_Full) + /* Process Link only when neighbor old or new state is NSM Full */ + if (nbr->state != NSM_Full && old_status != NSM_Full) return; /* Get interface information for Segment Routing */ @@ -673,6 +700,23 @@ static void ospf_ext_link_nsm_change(struct ospf_neighbor *nbr, int old_status) return; } + /* Check that we have a valid area and ospf context */ + if (oi->area == NULL || oi->area->ospf == NULL) { + flog_warn(EC_OSPF_EXT_LSA_UNEXPECTED, + "EXT (%s): Cannot refer to OSPF from OI(%s)", + __func__, IF_NAME(oi)); + return; + } + + /* Remove Extended Link if Neighbor State goes Down or Deleted */ + if (nbr->state == NSM_Down || nbr->state == NSM_Deleted) { + ospf_extended_lsa_delete(exti); + return; + } + + /* Keep Area information in combination with SR info. */ + exti->area = oi->area; + /* Process only Adjacency/LAN SID */ if (exti->stype == PREF_SID) return; @@ -748,6 +792,9 @@ static void ospf_ext_link_nsm_change(struct ospf_neighbor *nbr, int old_status) else ospf_ext_link_lsa_schedule(exti, REORIGINATE_THIS_LSA); } + + /* Finally install (LAN)Adjacency-SID in the SRDB */ + ospf_sr_ext_itf_add(exti); } /* Callbacks to handle Extended Link Segment Routing LSA information */ @@ -770,6 +817,10 @@ static int ospf_ext_link_lsa_update(struct ospf_lsa *lsa) != OPAQUE_TYPE_EXTENDED_LINK_LSA) return 0; + /* Check if it is not my LSA */ + if (IS_LSA_SELF(lsa)) + return 0; + /* Check if Extended is enable */ if (!OspfEXT.enabled) return 0; @@ -1218,6 +1269,10 @@ static int ospf_ext_link_lsa_originate(void *arg) if (exti->stype == PREF_SID) continue; + /* Skip Inactive Extended Link */ + if (!CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE)) + continue; + /* Process only Extended Link with valid Area ID */ if ((exti->area == NULL) || (!IPV4_ADDR_SAME(&exti->area->area_id, &area->area_id))) diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c index 33d994c79c..d92968644d 100644 --- a/ospfd/ospf_sr.c +++ b/ospfd/ospf_sr.c @@ -286,6 +286,8 @@ static void ospf_sr_stop(void) * be remove though list_delete() call. See sr_node_del() */ hash_clean(OspfSR.neighbors, (void *)sr_node_del); + OspfSR.self = NULL; + OspfSR.enabled = false; } /* @@ -352,9 +354,6 @@ void ospf_sr_term(void) /* Clear Prefix Table */ if (OspfSR.prefix) route_table_finish(OspfSR.prefix); - - OspfSR.enabled = false; - OspfSR.self = NULL; } /* @@ -367,8 +366,6 @@ void ospf_sr_finish(void) { /* Stop Segment Routing */ ospf_sr_stop(); - - OspfSR.enabled = false; } /* @@ -1345,6 +1342,136 @@ void ospf_sr_ext_link_lsa_delete(struct ospf_lsa *lsa) } } +/* Add (LAN)Adjacency-SID from Extended Link Information */ +void ospf_sr_ext_itf_add(struct ext_itf *exti) +{ + struct sr_node *srn = OspfSR.self; + struct sr_link *srl; + + osr_debug("SR (%s): Add Extended Link LSA 8.0.0.%u from self", __func__, + exti->instance); + + /* Sanity check */ + if (srn == NULL) + return; + + /* Initialize new Segment Routing Link */ + srl = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_link)); + srl->srn = srn; + srl->adv_router = srn->adv_router; + srl->itf_addr = exti->link.link_data; + srl->instance = + SET_OPAQUE_LSID(OPAQUE_TYPE_EXTENDED_LINK_LSA, exti->instance); + switch (exti->stype) { + case ADJ_SID: + srl->type = ADJ_SID; + /* Primary information */ + srl->flags[0] = exti->adj_sid[0].flags; + if (CHECK_FLAG(exti->adj_sid[0].flags, + EXT_SUBTLV_LINK_ADJ_SID_VFLG)) + srl->sid[0] = GET_LABEL(ntohl(exti->adj_sid[0].value)); + else + srl->sid[0] = ntohl(exti->adj_sid[0].value); + if (exti->rmt_itf_addr.header.type == 0) + srl->nhlfe[0].nexthop = exti->link.link_id; + else + srl->nhlfe[0].nexthop = exti->rmt_itf_addr.value; + /* Backup Information if set */ + if (exti->adj_sid[1].header.type == 0) + break; + srl->flags[1] = exti->adj_sid[1].flags; + if (CHECK_FLAG(exti->adj_sid[1].flags, + EXT_SUBTLV_LINK_ADJ_SID_VFLG)) + srl->sid[1] = GET_LABEL(ntohl(exti->adj_sid[1].value)); + else + srl->sid[1] = ntohl(exti->adj_sid[1].value); + if (exti->rmt_itf_addr.header.type == 0) + srl->nhlfe[1].nexthop = exti->link.link_id; + else + srl->nhlfe[1].nexthop = exti->rmt_itf_addr.value; + break; + case LAN_ADJ_SID: + srl->type = LAN_ADJ_SID; + /* Primary information */ + srl->flags[0] = exti->lan_sid[0].flags; + if (CHECK_FLAG(exti->lan_sid[0].flags, + EXT_SUBTLV_LINK_ADJ_SID_VFLG)) + srl->sid[0] = GET_LABEL(ntohl(exti->lan_sid[0].value)); + else + srl->sid[0] = ntohl(exti->lan_sid[0].value); + if (exti->rmt_itf_addr.header.type == 0) + srl->nhlfe[0].nexthop = exti->lan_sid[0].neighbor_id; + else + srl->nhlfe[0].nexthop = exti->rmt_itf_addr.value; + /* Backup Information if set */ + if (exti->lan_sid[1].header.type == 0) + break; + srl->flags[1] = exti->lan_sid[1].flags; + if (CHECK_FLAG(exti->lan_sid[1].flags, + EXT_SUBTLV_LINK_ADJ_SID_VFLG)) + srl->sid[1] = GET_LABEL(ntohl(exti->lan_sid[1].value)); + else + srl->sid[1] = ntohl(exti->lan_sid[1].value); + if (exti->rmt_itf_addr.header.type == 0) + srl->nhlfe[1].nexthop = exti->lan_sid[1].neighbor_id; + else + srl->nhlfe[1].nexthop = exti->rmt_itf_addr.value; + break; + default: + /* Wrong SID Type. Abort! */ + XFREE(MTYPE_OSPF_SR_PARAMS, srl); + return; + } + + /* Segment Routing Link is ready, update it */ + update_ext_link_sid(srn, srl, OSPF_LSA_SELF); +} + +/* Delete Prefix or (LAN)Adjacency-SID from Extended Link Information */ +void ospf_sr_ext_itf_delete(struct ext_itf *exti) +{ + struct listnode *node; + struct sr_node *srn = OspfSR.self; + struct sr_prefix *srp = NULL; + struct sr_link *srl = NULL; + uint32_t instance; + + osr_debug("SR (%s): Remove Extended LSA %u.0.0.%u from self", + __func__, exti->stype == PREF_SID ? 7 : 8, exti->instance); + + /* Sanity check: SR-Node and Extended Prefix/Link list may have been + * removed earlier when stopping OSPF or OSPF-SR */ + if (srn == NULL || srn->ext_prefix == NULL || srn->ext_link == NULL) + return; + + if (exti->stype == PREF_SID) { + instance = SET_OPAQUE_LSID(OPAQUE_TYPE_EXTENDED_PREFIX_LSA, + exti->instance); + for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) + if (srp->instance == instance) + break; + + /* Uninstall Segment Prefix SID if found */ + if ((srp != NULL) && (srp->instance == instance)) + delete_prefix_sid(srp); + } else { + /* Search for corresponding Segment Link for self SR-Node */ + instance = SET_OPAQUE_LSID(OPAQUE_TYPE_EXTENDED_LINK_LSA, + exti->instance); + for (ALL_LIST_ELEMENTS_RO(srn->ext_link, node, srl)) + if (srl->instance == instance) + break; + + /* Remove Segment Link if found */ + if ((srl != NULL) && (srl->instance == instance)) { + del_adj_sid(srl->nhlfe[0]); + del_adj_sid(srl->nhlfe[1]); + listnode_delete(srn->ext_link, srl); + XFREE(MTYPE_OSPF_SR_PARAMS, srl); + } + } +} + /* Update Segment Routing from Extended Prefix LSA */ void ospf_sr_ext_prefix_lsa_update(struct ospf_lsa *lsa) { @@ -1700,7 +1827,6 @@ DEFUN (no_ospf_sr_enable, /* Finally, stop Segment Routing */ ospf_sr_stop(); - OspfSR.enabled = false; return CMD_SUCCESS; } diff --git a/ospfd/ospf_sr.h b/ospfd/ospf_sr.h index d03da71108..5e1e1f7837 100644 --- a/ospfd/ospf_sr.h +++ b/ospfd/ospf_sr.h @@ -312,6 +312,10 @@ extern void ospf_sr_ext_link_lsa_update(struct ospf_lsa *lsa); extern void ospf_sr_ext_link_lsa_delete(struct ospf_lsa *lsa); extern void ospf_sr_ext_prefix_lsa_update(struct ospf_lsa *lsa); extern void ospf_sr_ext_prefix_lsa_delete(struct ospf_lsa *lsa); +/* Segment Routing Extending Link management */ +struct ext_itf; +extern void ospf_sr_ext_itf_add(struct ext_itf *exti); +extern void ospf_sr_ext_itf_delete(struct ext_itf *exti); /* Segment Routing configuration functions */ extern uint32_t get_ext_link_label_value(void); extern void ospf_sr_config_write_router(struct vty *vty); From 43e7abb55549ec976a86b1c42d503b54ce173d61 Mon Sep 17 00:00:00 2001 From: Olivier Dugeon Date: Tue, 2 Jun 2020 19:24:46 +0200 Subject: [PATCH 6/6] ospfd: Move Segment Routing Zebra functions For coherency, move and rename functions that send MPLS labels configurations from ospf_sr.c to ospf_zebra.c: - ospf_zebra_update_prefix_sid() - ospf_zebra_delete_prefix_sid() - ospf_zebra_send_adjacency_sid() Signed-off-by: Olivier Dugeon --- ospfd/ospf_sr.c | 147 +++++---------------------------------------- ospfd/ospf_sr.h | 4 ++ ospfd/ospf_zebra.c | 114 +++++++++++++++++++++++++++++++++++ ospfd/ospf_zebra.h | 8 ++- 4 files changed, 140 insertions(+), 133 deletions(-) diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c index d92968644d..1a65bfa411 100644 --- a/ospfd/ospf_sr.c +++ b/ospfd/ospf_sr.c @@ -82,10 +82,6 @@ static struct ospf_sr_db OspfSR; static void ospf_sr_register_vty(void); static inline void del_adj_sid(struct sr_nhlfe nhlfe); -static void delete_prefix_sid(const struct sr_prefix *srp); - -#define IS_NO_ROUTE(srp) ((srp->route == NULL) || (srp->route->paths == NULL) \ - || list_isempty(srp->route->paths)) /* * Segment Routing Data Base functions @@ -123,7 +119,7 @@ static void del_sr_pref(void *val) { struct sr_prefix *srp = (struct sr_prefix *)val; - delete_prefix_sid(srp); + ospf_zebra_delete_prefix_sid(srp); XFREE(MTYPE_OSPF_SR_PARAMS, val); } @@ -576,42 +572,18 @@ static int compute_prefix_nhlfe(struct sr_prefix *srp) return rc; } -/* Send MPLS Label entry to Zebra for installation or deletion */ -static int send_adjacency_sid(int cmd, struct sr_nhlfe nhlfe) -{ - struct zapi_labels zl; - struct zapi_nexthop *znh; - - osr_debug(" |- %s Labels %u/%u for Adjacency via %u", - cmd == ZEBRA_MPLS_LABELS_ADD ? "Add" : "Delete", - nhlfe.label_in, nhlfe.label_out, nhlfe.ifindex); - - memset(&zl, 0, sizeof(zl)); - zl.type = ZEBRA_LSP_OSPF_SR; - zl.local_label = nhlfe.label_in; - zl.nexthop_num = 1; - znh = &zl.nexthops[0]; - znh->type = NEXTHOP_TYPE_IPV4_IFINDEX; - znh->gate.ipv4 = nhlfe.nexthop; - znh->ifindex = nhlfe.ifindex; - znh->label_num = 1; - znh->labels[0] = nhlfe.label_out; - - return zebra_send_mpls_labels(zclient, cmd, &zl); -} - /* Add new NHLFE entry for Adjacency SID */ static inline void add_adj_sid(struct sr_nhlfe nhlfe) { if (nhlfe.label_in != 0) - send_adjacency_sid(ZEBRA_MPLS_LABELS_ADD, nhlfe); + ospf_zebra_send_adjacency_sid(ZEBRA_MPLS_LABELS_ADD, nhlfe); } /* Remove NHLFE entry for Adjacency SID */ static inline void del_adj_sid(struct sr_nhlfe nhlfe) { if (nhlfe.label_in != 0) - send_adjacency_sid(ZEBRA_MPLS_LABELS_DELETE, nhlfe); + ospf_zebra_send_adjacency_sid(ZEBRA_MPLS_LABELS_DELETE, nhlfe); } /* Update NHLFE entry for Adjacency SID */ @@ -621,95 +593,6 @@ static inline void update_adj_sid(struct sr_nhlfe n1, struct sr_nhlfe n2) add_adj_sid(n2); } -/* Update NHLFE for Prefix SID */ -static void update_prefix_sid(const struct sr_prefix *srp) -{ - struct zapi_labels zl; - struct zapi_nexthop *znh; - struct listnode *node; - struct ospf_path *path; - - osr_debug(" |- Update Labels %u for Prefix %pFX", srp->label_in, - (struct prefix *)&srp->prefv4); - - /* Prepare message. */ - memset(&zl, 0, sizeof(zl)); - zl.type = ZEBRA_LSP_OSPF_SR; - zl.local_label = srp->label_in; - - switch (srp->type) { - case LOCAL_SID: - /* Set Label for local Prefix */ - znh = &zl.nexthops[zl.nexthop_num++]; - znh->type = NEXTHOP_TYPE_IFINDEX; - znh->ifindex = srp->nhlfe.ifindex; - znh->label_num = 1; - znh->labels[0] = srp->nhlfe.label_out; - break; - - case PREF_SID: - /* Update route in the RIB too. */ - SET_FLAG(zl.message, ZAPI_LABELS_FTN); - zl.route.prefix.u.prefix4 = srp->prefv4.prefix; - zl.route.prefix.prefixlen = srp->prefv4.prefixlen; - zl.route.prefix.family = srp->prefv4.family; - zl.route.type = ZEBRA_ROUTE_OSPF; - zl.route.instance = 0; - - /* Check that SRP contains at least one valid path */ - if (IS_NO_ROUTE(srp)) { - return; - } - for (ALL_LIST_ELEMENTS_RO(srp->route->paths, node, path)) { - if (path->srni.label_out == MPLS_INVALID_LABEL) - continue; - - if (zl.nexthop_num >= MULTIPATH_NUM) - break; - - znh = &zl.nexthops[zl.nexthop_num++]; - znh->type = NEXTHOP_TYPE_IPV4_IFINDEX; - znh->gate.ipv4 = path->nexthop; - znh->ifindex = path->ifindex; - znh->label_num = 1; - znh->labels[0] = path->srni.label_out; - } - break; - default: - return; - } - - /* Finally, send message to zebra. */ - (void)zebra_send_mpls_labels(zclient, ZEBRA_MPLS_LABELS_REPLACE, &zl); -} - -/* Remove NHLFE for Prefix-SID */ -static void delete_prefix_sid(const struct sr_prefix *srp) -{ - struct zapi_labels zl; - - osr_debug(" |- Delete Labels %u for Prefix %pFX", srp->label_in, - (struct prefix *)&srp->prefv4); - - /* Prepare message. */ - memset(&zl, 0, sizeof(zl)); - zl.type = ZEBRA_LSP_OSPF_SR; - zl.local_label = srp->label_in; - - if (srp->type == PREF_SID) { - /* Update route in the RIB too */ - SET_FLAG(zl.message, ZAPI_LABELS_FTN); - zl.route.prefix.u.prefix4 = srp->prefv4.prefix; - zl.route.prefix.prefixlen = srp->prefv4.prefixlen; - zl.route.prefix.family = srp->prefv4.family; - zl.route.type = ZEBRA_ROUTE_OSPF; - zl.route.instance = 0; - } - - /* Send message to zebra. */ - (void)zebra_send_mpls_labels(zclient, ZEBRA_MPLS_LABELS_DELETE, &zl); -} - /* * Functions to parse and get Extended Link / Prefix * TLVs and SubTLVs @@ -968,11 +851,11 @@ static void update_ext_prefix_sid(struct sr_node *srn, struct sr_prefix *srp) listnode_add(srn->ext_prefix, srp); /* Try to set MPLS table */ if (compute_prefix_nhlfe(srp) == 1) - update_prefix_sid(srp); + ospf_zebra_update_prefix_sid(srp); } else { if (sr_prefix_cmp(pref, srp)) { if (compute_prefix_nhlfe(srp) == 1) { - delete_prefix_sid(pref); + ospf_zebra_delete_prefix_sid(pref); /* Replace Segment Prefix */ listnode_delete(srn->ext_prefix, pref); XFREE(MTYPE_OSPF_SR_PARAMS, pref); @@ -980,7 +863,7 @@ static void update_ext_prefix_sid(struct sr_node *srn, struct sr_prefix *srp) IPV4_ADDR_COPY(&srp->adv_router, &srn->adv_router); listnode_add(srn->ext_prefix, srp); - update_prefix_sid(srp); + ospf_zebra_update_prefix_sid(srp); } else { /* New NHLFE was not found. * Just free the SR Prefix @@ -1020,7 +903,7 @@ static void update_in_nhlfe(struct hash_bucket *bucket, void *args) /* OK. Compute new input label ... */ srp->label_in = index2label(srp->sid, OspfSR.srgb); /* ... and update MPLS LFIB */ - update_prefix_sid(srp); + ospf_zebra_update_prefix_sid(srp); } } @@ -1049,7 +932,7 @@ static void update_out_nhlfe(struct hash_bucket *bucket, void *args) continue; path->srni.label_out = index2label(srp->sid, srnext->srgb); - update_prefix_sid(srp); + ospf_zebra_update_prefix_sid(srp); } } } @@ -1453,7 +1336,7 @@ void ospf_sr_ext_itf_delete(struct ext_itf *exti) /* Uninstall Segment Prefix SID if found */ if ((srp != NULL) && (srp->instance == instance)) - delete_prefix_sid(srp); + ospf_zebra_delete_prefix_sid(srp); } else { /* Search for corresponding Segment Link for self SR-Node */ instance = SET_OPAQUE_LSID(OPAQUE_TYPE_EXTENDED_LINK_LSA, @@ -1566,7 +1449,7 @@ void ospf_sr_ext_prefix_lsa_delete(struct ospf_lsa *lsa) /* Remove Prefix if found */ if ((srp != NULL) && (srp->instance == instance)) { - delete_prefix_sid(srp); + ospf_zebra_delete_prefix_sid(srp); listnode_delete(srn->ext_prefix, srp); XFREE(MTYPE_OSPF_SR_PARAMS, srp); } else { @@ -1638,7 +1521,7 @@ void ospf_sr_update_local_prefix(struct interface *ifp, struct prefix *p) srp->label_in = index2label(srp->sid, OspfSR.self->srgb); srp->nhlfe.label_out = MPLS_LABEL_IMPLICIT_NULL; - update_prefix_sid(srp); + ospf_zebra_update_prefix_sid(srp); } } } @@ -1677,14 +1560,14 @@ static void ospf_sr_nhlfe_update(struct hash_bucket *bucket, void *args) /* Routes are not know, remove old NHLFE if any to avoid loop */ case -1: if (old) - delete_prefix_sid(srp); + ospf_zebra_delete_prefix_sid(srp); break; /* Routes exist but are not ready, skip it */ case 0: break; /* There is at least one route, update NHLFE */ case 1: - update_prefix_sid(srp); + ospf_zebra_update_prefix_sid(srp); break; default: break; @@ -2100,7 +1983,7 @@ DEFUN (sr_prefix_sid, } else { listnode_add(OspfSR.self->ext_prefix, new); } - update_prefix_sid(new); + ospf_zebra_update_prefix_sid(new); /* Finally, update Extended Prefix LSA */ new->instance = ospf_ext_schedule_prefix_index( @@ -2177,7 +2060,7 @@ DEFUN (no_sr_prefix_sid, /* Delete NHLFE if NO-PHP is set */ if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG)) - delete_prefix_sid(srp); + ospf_zebra_delete_prefix_sid(srp); /* OK, all is clean, remove SRP from SRDB */ listnode_delete(OspfSR.self->ext_prefix, srp); diff --git a/ospfd/ospf_sr.h b/ospfd/ospf_sr.h index 5e1e1f7837..3621ea53de 100644 --- a/ospfd/ospf_sr.h +++ b/ospfd/ospf_sr.h @@ -58,6 +58,10 @@ zlog_debug(__VA_ARGS__); \ } while (0) +/* Macro to check if SR Prefix has no valid route */ +#define IS_NO_ROUTE(srp) ((srp->route == NULL) || (srp->route->paths == NULL) \ + || list_isempty(srp->route->paths)) + /* SID/Label Sub TLV - section 2.1 */ #define SUBTLV_SID_LABEL 1 #define SUBTLV_SID_LABEL_SIZE 8 diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index 00b90d10c3..644ea7f922 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -50,6 +50,7 @@ #include "ospfd/ospf_nsm.h" #include "ospfd/ospf_zebra.h" #include "ospfd/ospf_te.h" +#include "ospfd/ospf_sr.h" DEFINE_MTYPE_STATIC(OSPFD, OSPF_EXTERNAL, "OSPF External route table") DEFINE_MTYPE_STATIC(OSPFD, OSPF_REDISTRIBUTE, "OSPF Redistriute") @@ -415,6 +416,119 @@ void ospf_external_del(struct ospf *ospf, uint8_t type, unsigned short instance) } } +/* Update NHLFE for Prefix SID */ +void ospf_zebra_update_prefix_sid(const struct sr_prefix *srp) +{ + struct zapi_labels zl; + struct zapi_nexthop *znh; + struct listnode *node; + struct ospf_path *path; + + osr_debug("SR (%s): Update Labels %u for Prefix %pFX", __func__, + srp->label_in, (struct prefix *)&srp->prefv4); + + /* Prepare message. */ + memset(&zl, 0, sizeof(zl)); + zl.type = ZEBRA_LSP_OSPF_SR; + zl.local_label = srp->label_in; + + switch (srp->type) { + case LOCAL_SID: + /* Set Label for local Prefix */ + znh = &zl.nexthops[zl.nexthop_num++]; + znh->type = NEXTHOP_TYPE_IFINDEX; + znh->ifindex = srp->nhlfe.ifindex; + znh->label_num = 1; + znh->labels[0] = srp->nhlfe.label_out; + break; + + case PREF_SID: + /* Update route in the RIB too. */ + SET_FLAG(zl.message, ZAPI_LABELS_FTN); + zl.route.prefix.u.prefix4 = srp->prefv4.prefix; + zl.route.prefix.prefixlen = srp->prefv4.prefixlen; + zl.route.prefix.family = srp->prefv4.family; + zl.route.type = ZEBRA_ROUTE_OSPF; + zl.route.instance = 0; + + /* Check that SRP contains at least one valid path */ + if (srp->route == NULL) { + return; + } + for (ALL_LIST_ELEMENTS_RO(srp->route->paths, node, path)) { + if (path->srni.label_out == MPLS_INVALID_LABEL) + continue; + + if (zl.nexthop_num >= MULTIPATH_NUM) + break; + + znh = &zl.nexthops[zl.nexthop_num++]; + znh->type = NEXTHOP_TYPE_IPV4_IFINDEX; + znh->gate.ipv4 = path->nexthop; + znh->ifindex = path->ifindex; + znh->label_num = 1; + znh->labels[0] = path->srni.label_out; + } + break; + default: + return; + } + + /* Finally, send message to zebra. */ + (void)zebra_send_mpls_labels(zclient, ZEBRA_MPLS_LABELS_REPLACE, &zl); +} + +/* Remove NHLFE for Prefix-SID */ +void ospf_zebra_delete_prefix_sid(const struct sr_prefix *srp) +{ + struct zapi_labels zl; + + osr_debug("SR (%s): Delete Labels %u for Prefix %pFX", __func__, + srp->label_in, (struct prefix *)&srp->prefv4); + + /* Prepare message. */ + memset(&zl, 0, sizeof(zl)); + zl.type = ZEBRA_LSP_OSPF_SR; + zl.local_label = srp->label_in; + + if (srp->type == PREF_SID) { + /* Update route in the RIB too */ + SET_FLAG(zl.message, ZAPI_LABELS_FTN); + zl.route.prefix.u.prefix4 = srp->prefv4.prefix; + zl.route.prefix.prefixlen = srp->prefv4.prefixlen; + zl.route.prefix.family = srp->prefv4.family; + zl.route.type = ZEBRA_ROUTE_OSPF; + zl.route.instance = 0; + } + + /* Send message to zebra. */ + (void)zebra_send_mpls_labels(zclient, ZEBRA_MPLS_LABELS_DELETE, &zl); +} + +/* Send MPLS Label entry to Zebra for installation or deletion */ +void ospf_zebra_send_adjacency_sid(int cmd, struct sr_nhlfe nhlfe) +{ + struct zapi_labels zl; + struct zapi_nexthop *znh; + + osr_debug("SR (%s): %s Labels %u/%u for Adjacency via %u", __func__, + cmd == ZEBRA_MPLS_LABELS_ADD ? "Add" : "Delete", + nhlfe.label_in, nhlfe.label_out, nhlfe.ifindex); + + memset(&zl, 0, sizeof(zl)); + zl.type = ZEBRA_LSP_OSPF_SR; + zl.local_label = nhlfe.label_in; + zl.nexthop_num = 1; + znh = &zl.nexthops[0]; + znh->type = NEXTHOP_TYPE_IPV4_IFINDEX; + znh->gate.ipv4 = nhlfe.nexthop; + znh->ifindex = nhlfe.ifindex; + znh->label_num = 1; + znh->labels[0] = nhlfe.label_out; + + (void)zebra_send_mpls_labels(zclient, cmd, &zl); +} + struct ospf_redist *ospf_redist_lookup(struct ospf *ospf, uint8_t type, unsigned short instance) { diff --git a/ospfd/ospf_zebra.h b/ospfd/ospf_zebra.h index d3f8a0380b..253d2e0a3f 100644 --- a/ospfd/ospf_zebra.h +++ b/ospfd/ospf_zebra.h @@ -63,6 +63,13 @@ extern struct ospf_external *ospf_external_lookup(struct ospf *, uint8_t, unsigned short); extern struct ospf_external *ospf_external_add(struct ospf *, uint8_t, unsigned short); + +struct sr_prefix; +struct sr_nhlfe; +extern void ospf_zebra_update_prefix_sid(const struct sr_prefix *srp); +extern void ospf_zebra_delete_prefix_sid(const struct sr_prefix *srp); +extern void ospf_zebra_send_adjacency_sid(int cmd, struct sr_nhlfe nhlfe); + extern void ospf_external_del(struct ospf *, uint8_t, unsigned short); extern struct ospf_redist *ospf_redist_lookup(struct ospf *, uint8_t, unsigned short); @@ -70,7 +77,6 @@ extern struct ospf_redist *ospf_redist_add(struct ospf *, uint8_t, unsigned short); extern void ospf_redist_del(struct ospf *, uint8_t, unsigned short); - extern int ospf_redistribute_set(struct ospf *, int, unsigned short, int, int); extern int ospf_redistribute_unset(struct ospf *, int, unsigned short); extern int ospf_redistribute_default_set(struct ospf *, int, int, int);