]> git.proxmox.com Git - mirror_frr.git/blame - ospfd/ospf_sr.c
ospfd: Add vrf to nhlfe route add
[mirror_frr.git] / ospfd / ospf_sr.c
CommitLineData
cf9b9f77
OD
1/*
2 * This is an implementation of Segment Routing
7743f2f8 3 * as per draft draft-ietf-ospf-segment-routing-extensions-24
cf9b9f77
OD
4 *
5 * Module name: Segment Routing
6 *
cf9b9f77 7 * Author: Olivier Dugeon <olivier.dugeon@orange.com>
7743f2f8 8 * Author: Anselme Sawadogo <anselmesawadogo@gmail.com>
cf9b9f77 9 *
7743f2f8 10 * Copyright (C) 2016 - 2018 Orange Labs http://www.orange.com
cf9b9f77 11 *
7743f2f8
OD
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the Free
14 * Software Foundation; either version 2 of the License, or (at your option)
15 * any later version.
cf9b9f77 16 *
7743f2f8
OD
17 * This program is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
20 * more details.
cf9b9f77 21 *
7743f2f8
OD
22 * You should have received a copy of the GNU General Public License along
23 * with this program; see the file COPYING; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
cf9b9f77
OD
25 */
26
27#include <math.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <zebra.h>
31
32#include "command.h"
33#include "hash.h"
34#include "if.h"
35#include "if.h"
36#include "jhash.h"
37#include "libospf.h" /* for ospf interface types */
38#include "linklist.h"
39#include "log.h"
40#include "memory.h"
41#include "monotime.h"
42#include "network.h"
43#include "prefix.h"
44#include "sockunion.h" /* for inet_aton() */
45#include "stream.h"
46#include "table.h"
47#include "thread.h"
48#include "vty.h"
49#include "zclient.h"
50
51#include "ospfd/ospfd.h"
52#include "ospfd/ospf_interface.h"
53#include "ospfd/ospf_ism.h"
54#include "ospfd/ospf_asbr.h"
55#include "ospfd/ospf_lsa.h"
56#include "ospfd/ospf_lsdb.h"
57#include "ospfd/ospf_neighbor.h"
58#include "ospfd/ospf_nsm.h"
59#include "ospfd/ospf_flood.h"
60#include "ospfd/ospf_packet.h"
61#include "ospfd/ospf_spf.h"
62#include "ospfd/ospf_dump.h"
63#include "ospfd/ospf_route.h"
64#include "ospfd/ospf_ase.h"
65#include "ospfd/ospf_sr.h"
66#include "ospfd/ospf_ri.h"
67#include "ospfd/ospf_ext.h"
68#include "ospfd/ospf_zebra.h"
69
70/*
71 * Global variable to manage Segment Routing on this node.
72 * Note that all parameter values are stored in network byte order.
73 */
74static struct ospf_sr_db OspfSR;
75static void ospf_sr_register_vty(void);
76static inline void del_sid_nhlfe(struct sr_nhlfe nhlfe);
77
78/*
79 * Segment Routing Data Base functions
80 */
81
82/* Hash function for Segment Routing entry */
83static unsigned int sr_hash(void *p)
84{
85 const struct in_addr *rid = p;
86
7743f2f8 87 return jhash_1word(rid->s_addr, 0);
cf9b9f77
OD
88}
89
90/* Compare 2 Router ID hash entries based on SR Node */
91static int sr_cmp(const void *p1, const void *p2)
92{
93 const struct sr_node *srn = p1;
94 const struct in_addr *rid = p2;
95
7743f2f8 96 return IPV4_ADDR_SAME(&srn->adv_router, rid);
cf9b9f77
OD
97}
98
fd3b19f2
OD
99/* Functions to remove an SR Link */
100static void del_sr_link(void *val)
cf9b9f77 101{
fd3b19f2
OD
102 struct sr_link *srl = (struct sr_link *)val;
103
104 del_sid_nhlfe(srl->nhlfe[0]);
105 del_sid_nhlfe(srl->nhlfe[1]);
106 XFREE(MTYPE_OSPF_SR_PARAMS, val);
7743f2f8 107
fd3b19f2
OD
108}
109
110/* Functions to remove an SR Prefix */
111static void del_sr_pref(void *val)
112{
113 struct sr_prefix *srp = (struct sr_prefix *)val;
114
115 del_sid_nhlfe(srp->nhlfe);
cf9b9f77 116 XFREE(MTYPE_OSPF_SR_PARAMS, val);
7743f2f8 117
cf9b9f77
OD
118}
119
120/* Allocate new Segment Routine node */
121static struct sr_node *sr_node_new(struct in_addr *rid)
122{
123
124 if (rid == NULL)
125 return NULL;
126
127 struct sr_node *new;
128
129 /* Allocate Segment Routing node memory */
130 new = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_node));
131
132 /* Sanity Check */
133 if (new == NULL) {
7743f2f8 134 zlog_err("SR (%s): Abort! can't create new SR node", __func__);
cf9b9f77
OD
135 return NULL;
136 }
137
138 /* Default Algorithm, SRGB and MSD */
139 for (int i = 0; i < ALGORITHM_COUNT; i++)
fd3b19f2 140 new->algo[i] = SR_ALGORITHM_UNSET;
cf9b9f77
OD
141
142 new->srgb.range_size = 0;
143 new->srgb.lower_bound = 0;
144 new->msd = 0;
145
146 /* Create Link, Prefix and Range TLVs list */
147 new->ext_link = list_new();
148 new->ext_prefix = list_new();
fd3b19f2
OD
149 new->ext_link->del = del_sr_link;
150 new->ext_prefix->del = del_sr_pref;
cf9b9f77 151
cf9b9f77
OD
152 IPV4_ADDR_COPY(&new->adv_router, rid);
153 new->neighbor = NULL;
154 new->instance = 0;
155
156 if (IS_DEBUG_OSPF_SR)
157 zlog_debug(" |- Created new SR node for %s",
158 inet_ntoa(new->adv_router));
159 return new;
160}
161
162/* Delete Segment Routing node */
163static void sr_node_del(struct sr_node *srn)
164{
cf9b9f77
OD
165 /* Sanity Check */
166 if (srn == NULL)
167 return;
168
169 /* Clean Extended Link */
fd3b19f2 170 list_delete_and_null(&srn->ext_link);
cf9b9f77
OD
171
172 /* Clean Prefix List */
fd3b19f2 173 list_delete_and_null(&srn->ext_prefix);
cf9b9f77
OD
174
175 XFREE(MTYPE_OSPF_SR_PARAMS, srn);
176}
177
178/* Get SR Node for a given nexthop */
179static struct sr_node *get_sr_node_by_nexthop(struct ospf *ospf,
180 struct in_addr nexthop)
181{
182 struct ospf_interface *oi = NULL;
183 struct ospf_neighbor *nbr = NULL;
184 struct listnode *node;
185 struct route_node *rn;
186 struct sr_node *srn;
7743f2f8 187 bool found;
cf9b9f77
OD
188
189 /* Sanity check */
190 if (OspfSR.neighbors == NULL)
191 return NULL;
192
193 if (IS_DEBUG_OSPF_SR)
194 zlog_debug(" |- Search SR-Node for nexthop %s",
195 inet_ntoa(nexthop));
196
197 /* First, search neighbor Router ID for this nexthop */
7743f2f8
OD
198 found = false;
199 for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
200 for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
201 nbr = rn->info;
202 if ((nbr) && (IPV4_ADDR_SAME(&nexthop, &nbr->src))) {
203 found = true;
cf9b9f77 204 break;
7743f2f8
OD
205 }
206 }
207 if (found)
208 break;
209 }
cf9b9f77 210
7743f2f8 211 if (!found)
cf9b9f77
OD
212 return NULL;
213
214 if (IS_DEBUG_OSPF_SR)
215 zlog_debug(" |- Found nexthop Router ID %s",
216 inet_ntoa(nbr->router_id));
217 /* Then, search SR Node */
218 srn = (struct sr_node *)hash_lookup(OspfSR.neighbors, &nbr->router_id);
219
220 return srn;
221}
222
223/*
224 * Segment Routing Initialization functions
225 */
226
227/* Segment Routing starter function */
228static int ospf_sr_start(struct ospf *ospf)
229{
230 struct route_node *rn;
231 struct ospf_lsa *lsa;
232 struct sr_node *srn;
233 int rc = 0;
234
235 if (IS_DEBUG_OSPF_SR)
7743f2f8 236 zlog_debug("SR (%s): Start Segment Routing", __func__);
cf9b9f77
OD
237
238 /* Initialize self SR Node */
239 srn = hash_get(OspfSR.neighbors, (void *)&(ospf->router_id),
240 (void *)sr_node_new);
241
242 /* Sanity Check */
243 if (srn == NULL)
244 return rc;
245
246 /* Complete & Store self SR Node */
247 srn->srgb.range_size = OspfSR.srgb.range_size;
248 srn->srgb.lower_bound = OspfSR.srgb.lower_bound;
249 srn->algo[0] = OspfSR.algo[0];
250 srn->msd = OspfSR.msd;
251 OspfSR.self = srn;
252
253 if (IS_DEBUG_OSPF_EVENT)
7743f2f8 254 zlog_debug("SR (%s): Update SR-DB from LSDB", __func__);
cf9b9f77
OD
255
256 /* Start by looking to Router Info & Extended LSA in lsdb */
257 if ((ospf != NULL) && (ospf->backbone != NULL)) {
258 LSDB_LOOP(OPAQUE_AREA_LSDB(ospf->backbone), rn, lsa)
259 {
260 if (IS_LSA_MAXAGE(lsa) || IS_LSA_SELF(lsa))
261 continue;
262 int lsa_id =
263 GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr));
264 switch (lsa_id) {
265 case OPAQUE_TYPE_ROUTER_INFORMATION_LSA:
266 ospf_sr_ri_lsa_update(lsa);
267 break;
268 case OPAQUE_TYPE_EXTENDED_PREFIX_LSA:
269 ospf_sr_ext_prefix_lsa_update(lsa);
270 break;
271 case OPAQUE_TYPE_EXTENDED_LINK_LSA:
272 ospf_sr_ext_link_lsa_update(lsa);
273 break;
274 default:
275 break;
276 }
277 }
278 }
279
280 rc = 1;
281 return rc;
282}
283
cf9b9f77
OD
284/* Stop Segment Routing */
285static void ospf_sr_stop(void)
286{
287
288 if (IS_DEBUG_OSPF_SR)
7743f2f8 289 zlog_debug("SR (%s): Stop Segment Routing", __func__);
cf9b9f77 290
7743f2f8
OD
291 /*
292 * Remove all SR Nodes from the Hash table. Prefix and Link SID will
293 * be remove though list_delete_and_null() call. See sr_node_del()
294 */
cf9b9f77
OD
295 hash_clean(OspfSR.neighbors, (void *)sr_node_del);
296}
297
298/*
299 * Segment Routing initialize function
300 *
301 * @param - nothing
302 *
303 * @return 0 if OK, -1 otherwise
304 */
305int ospf_sr_init(void)
306{
307 int rc = -1;
308
7743f2f8 309 zlog_info("SR (%s): Initialize SR Data Base", __func__);
cf9b9f77
OD
310
311 memset(&OspfSR, 0, sizeof(struct ospf_sr_db));
312 OspfSR.enabled = false;
313 /* Only AREA flooding is supported in this release */
314 OspfSR.scope = OSPF_OPAQUE_AREA_LSA;
315
316 /* Initialize SRGB, Algorithms and MSD TLVs */
317 /* Only Algorithm SPF is supported */
318 OspfSR.algo[0] = SR_ALGORITHM_SPF;
319 for (int i = 1; i < ALGORITHM_COUNT; i++)
320 OspfSR.algo[i] = SR_ALGORITHM_UNSET;
321
322 OspfSR.srgb.range_size = MPLS_DEFAULT_MAX_SRGB_SIZE;
323 OspfSR.srgb.lower_bound = MPLS_DEFAULT_MIN_SRGB_LABEL;
7743f2f8 324 OspfSR.msd = 0;
cf9b9f77
OD
325
326 /* Initialize Hash table for neighbor SR nodes */
327 OspfSR.neighbors = hash_create(sr_hash, sr_cmp, "OSPF_SR");
328 if (OspfSR.neighbors == NULL)
329 return rc;
330
331 /* Initialize Route Table for prefix */
332 OspfSR.prefix = route_table_init();
333 if (OspfSR.prefix == NULL)
334 return rc;
335
336 /* Register Segment Routing VTY command */
337 ospf_sr_register_vty();
338
339 rc = 0;
340 return rc;
341}
342
343/*
344 * Segment Routing termination function
345 *
346 * @param - nothing
cf9b9f77
OD
347 * @return - nothing
348 */
349void ospf_sr_term(void)
350{
351
352 /* Stop Segment Routing */
353 ospf_sr_stop();
354
355 /* Clear SR Node Table */
356 if (OspfSR.neighbors)
357 hash_free(OspfSR.neighbors);
358
359 /* Clear Prefix Table */
360 if (OspfSR.prefix)
361 route_table_finish(OspfSR.prefix);
362
bcf4475e
OD
363 OspfSR.enabled = false;
364 OspfSR.self = NULL;
365}
366
367/*
368 * Segment Routing finish function
369 *
370 * @param - nothing
371 * @return - nothing
372 */
373void ospf_sr_finish(void)
374{
375 /* Stop Segment Routing */
376 ospf_sr_stop();
377
cf9b9f77
OD
378 OspfSR.enabled = false;
379}
380
381/*
382 * Following functions are used to manipulate the
383 * Next Hop Label Forwarding entry (NHLFE)
384 */
385
386/* Compute label from index */
93f0a26e 387static mpls_label_t index2label(uint32_t index, struct sr_srgb srgb)
cf9b9f77
OD
388{
389 mpls_label_t label;
390
391 label = srgb.lower_bound + index;
392 if (label > (srgb.lower_bound + srgb.range_size))
393 return MPLS_INVALID_LABEL;
394 else
395 return label;
396}
397
398/* Get neighbor full structure from address */
399static struct ospf_neighbor *get_neighbor_by_addr(struct ospf *top,
400 struct in_addr addr)
401{
402 struct ospf_neighbor *nbr;
403 struct ospf_interface *oi;
404 struct listnode *node;
405 struct route_node *rn;
406
407 /* Sanity Check */
408 if (top == NULL)
409 return NULL;
410
411 for (ALL_LIST_ELEMENTS_RO(top->oiflist, node, oi))
7743f2f8
OD
412 for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
413 nbr = rn->info;
414 if (nbr)
cf9b9f77
OD
415 if (IPV4_ADDR_SAME(&nbr->address.u.prefix4,
416 &addr)
417 || IPV4_ADDR_SAME(&nbr->router_id, &addr)) {
418 route_unlock_node(rn);
419 return nbr;
420 }
7743f2f8 421 }
cf9b9f77
OD
422 return NULL;
423}
424
425/* Get OSPF Path from address */
426static struct ospf_path *get_nexthop_by_addr(struct ospf *top,
427 struct prefix_ipv4 p)
428{
7743f2f8 429 struct ospf_route *or;
cf9b9f77
OD
430 struct ospf_path *path;
431 struct listnode *node;
432 struct route_node *rn;
433
434 /* Sanity Check */
9b50aa1f 435 if (top == NULL)
cf9b9f77
OD
436 return NULL;
437
438 if (IS_DEBUG_OSPF_SR)
7743f2f8 439 zlog_debug(" |- Search Nexthop for prefix %s/%u",
cf9b9f77
OD
440 inet_ntoa(p.prefix), p.prefixlen);
441
442 rn = route_node_lookup(top->new_table, (struct prefix *)&p);
443
7743f2f8
OD
444 /*
445 * Check if we found an OSPF route. May be NULL if SPF has not
446 * yet populate routing table for this prefix.
447 */
cf9b9f77
OD
448 if (rn == NULL)
449 return NULL;
450
451 route_unlock_node(rn);
7743f2f8
OD
452 or = rn->info;
453 if (or == NULL)
cf9b9f77
OD
454 return NULL;
455
456 /* Then search path from this route */
457 for (ALL_LIST_ELEMENTS_RO(or->paths, node, path))
458 if (path->nexthop.s_addr != INADDR_ANY || path->ifindex != 0)
459 return path;
460
461 return NULL;
462}
463
464/* Compute NHLFE entry for Extended Link */
465static int compute_link_nhlfe(struct sr_link *srl)
466{
467 struct ospf *top = ospf_lookup_by_vrf_id(VRF_DEFAULT);
468 struct ospf_neighbor *nh;
469 int rc = 0;
470
471 if (IS_DEBUG_OSPF_SR)
7743f2f8 472 zlog_debug(" |- Compute NHLFE for link %s/%u",
cf9b9f77
OD
473 inet_ntoa(srl->nhlfe[0].prefv4.prefix),
474 srl->nhlfe[0].prefv4.prefixlen);
475
476 /* First determine the OSPF Neighbor */
477 nh = get_neighbor_by_addr(top, srl->nhlfe[0].nexthop);
478
479 /* Neighbor could be not found when OSPF Adjacency just fire up
480 * because SPF don't yet populate routing table. This NHLFE will
481 * be fixed later when SR SPF schedule will be called.
482 */
483 if (nh == NULL)
484 return rc;
485
486 if (IS_DEBUG_OSPF_SR)
487 zlog_debug(" |- Found nexthop NHLFE %s",
488 inet_ntoa(nh->router_id));
489
490 /* Set ifindex for this neighbor */
491 srl->nhlfe[0].ifindex = nh->oi->ifp->ifindex;
492 srl->nhlfe[1].ifindex = nh->oi->ifp->ifindex;
493
d922605d
OD
494 /* Update neighbor address for LAN_ADJ_SID */
495 if (srl->type == LAN_ADJ_SID) {
496 IPV4_ADDR_COPY(&srl->nhlfe[0].nexthop, &nh->src);
497 IPV4_ADDR_COPY(&srl->nhlfe[1].nexthop, &nh->src);
498 }
499
cf9b9f77
OD
500 /* Set Input & Output Label */
501 if (CHECK_FLAG(srl->flags[0], EXT_SUBTLV_LINK_ADJ_SID_VFLG))
502 srl->nhlfe[0].label_in = srl->sid[0];
503 else
504 srl->nhlfe[0].label_in =
505 index2label(srl->sid[0], srl->srn->srgb);
506 if (CHECK_FLAG(srl->flags[1], EXT_SUBTLV_LINK_ADJ_SID_VFLG))
507 srl->nhlfe[1].label_in = srl->sid[1];
508 else
509 srl->nhlfe[1].label_in =
510 index2label(srl->sid[1], srl->srn->srgb);
511
70e98a7f
DS
512 srl->nhlfe[0].label_out = MPLS_LABEL_IMPLICIT_NULL;
513 srl->nhlfe[1].label_out = MPLS_LABEL_IMPLICIT_NULL;
cf9b9f77
OD
514
515 rc = 1;
516 return rc;
517}
518
519/*
520 * Compute NHLFE entry for Extended Prefix
521 *
522 * @param srp - Segment Routing Prefix
523 *
524 * @return -1 if next hop is not found, 0 if nexthop has not changed
525 * and 1 if success
526 */
527static int compute_prefix_nhlfe(struct sr_prefix *srp)
528{
529 struct ospf *top = ospf_lookup_by_vrf_id(VRF_DEFAULT);
530 struct ospf_path *nh = NULL;
531 struct sr_node *srnext;
532 int rc = -1;
533
534 if (IS_DEBUG_OSPF_SR)
7743f2f8 535 zlog_debug(" |- Compute NHLFE for prefix %s/%u",
cf9b9f77
OD
536 inet_ntoa(srp->nhlfe.prefv4.prefix),
537 srp->nhlfe.prefv4.prefixlen);
538
539 /* First determine the nexthop */
540 nh = get_nexthop_by_addr(top, srp->nhlfe.prefv4);
541
542 /* Nexthop could be not found when OSPF Adjacency just fire up
543 * because SPF don't yet populate routing table. This NHLFE will
544 * be fixed later when SR SPF schedule will be called.
545 */
546 if (nh == NULL)
547 return rc;
548
549 /* Check if NextHop has changed when call after running a new SPF */
550 if (IPV4_ADDR_SAME(&nh->nexthop, &srp->nhlfe.nexthop)
551 && (nh->ifindex == srp->nhlfe.ifindex))
552 return 0;
553
554 if (IS_DEBUG_OSPF_SR)
555 zlog_debug(" |- Found new next hop for this NHLFE: %s",
556 inet_ntoa(nh->nexthop));
557
7743f2f8
OD
558 /*
559 * Get SR-Node for this nexthop. Could be not yet available
560 * as Extende Link / Prefix and Router Information are flooded
561 * after LSA Type 1 & 2 which populate the OSPF Route Table
562 */
cf9b9f77 563 srnext = get_sr_node_by_nexthop(top, nh->nexthop);
7743f2f8
OD
564 if (srnext == NULL)
565 return rc;
566
567 /* And store this information for later update if SR Node is found */
cf9b9f77
OD
568 srnext->neighbor = OspfSR.self;
569 if (IPV4_ADDR_SAME(&srnext->adv_router, &srp->adv_router))
570 srp->nexthop = NULL;
571 else
572 srp->nexthop = srnext;
573
574 /*
575 * SR Node could be known, but SRGB could be not initialize
576 * This is due to the fact that Extended Link / Prefix could
577 * be received before corresponding Router Information LSA
578 */
579 if ((srnext == NULL) || (srnext->srgb.lower_bound == 0)
580 || (srnext->srgb.range_size == 0))
581 return rc;
582
583 if (IS_DEBUG_OSPF_SR)
7743f2f8 584 zlog_debug(" |- Found SRGB %u/%u for next hop SR-Node %s",
cf9b9f77
OD
585 srnext->srgb.range_size, srnext->srgb.lower_bound,
586 inet_ntoa(srnext->adv_router));
587
588 /* Set ip addr & ifindex for this neighbor */
589 IPV4_ADDR_COPY(&srp->nhlfe.nexthop, &nh->nexthop);
590 srp->nhlfe.ifindex = nh->ifindex;
591
592 /* Compute Input Label with self SRGB */
593 srp->nhlfe.label_in = index2label(srp->sid, OspfSR.srgb);
7743f2f8
OD
594 /*
595 * and Output Label with Next hop SR Node SRGB or Implicit Null label
596 * if next hop is the destination and request PHP
597 */
cf9b9f77
OD
598 if ((srp->nexthop == NULL)
599 && (!CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG)))
70e98a7f 600 srp->nhlfe.label_out = MPLS_LABEL_IMPLICIT_NULL;
cf9b9f77
OD
601 else if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_VFLG))
602 srp->nhlfe.label_out = srp->sid;
603 else
604 srp->nhlfe.label_out = index2label(srp->sid, srnext->srgb);
605
606 if (IS_DEBUG_OSPF_SR)
7743f2f8 607 zlog_debug(" |- Computed new labels in: %u out: %u",
cf9b9f77
OD
608 srp->nhlfe.label_in, srp->nhlfe.label_out);
609
610 rc = 1;
611 return rc;
612}
613
614/* Send MPLS Label entry to Zebra for installation or deletion */
615static int ospf_zebra_send_mpls_labels(int cmd, struct sr_nhlfe nhlfe)
616{
617 struct stream *s;
618
619 /* Reset stream. */
620 s = zclient->obuf;
621 stream_reset(s);
622
623 zclient_create_header(s, cmd, VRF_DEFAULT);
624 stream_putc(s, ZEBRA_LSP_SR);
625 /* OSPF Segment Routing currently support only IPv4 */
626 stream_putl(s, nhlfe.prefv4.family);
627 stream_put_in_addr(s, &nhlfe.prefv4.prefix);
628 stream_putc(s, nhlfe.prefv4.prefixlen);
629 stream_put_in_addr(s, &nhlfe.nexthop);
630 stream_putl(s, nhlfe.ifindex);
631 stream_putc(s, OSPF_SR_PRIORITY_DEFAULT);
632 stream_putl(s, nhlfe.label_in);
633 stream_putl(s, nhlfe.label_out);
634
635 /* Put length at the first point of the stream. */
636 stream_putw_at(s, 0, stream_get_endp(s));
637
638 if (IS_DEBUG_OSPF_SR)
7743f2f8 639 zlog_debug(" |- %s LSP %u/%u for %s/%u via %u",
cf9b9f77
OD
640 cmd == ZEBRA_MPLS_LABELS_ADD ? "Add" : "Delete",
641 nhlfe.label_in, nhlfe.label_out,
642 inet_ntoa(nhlfe.prefv4.prefix),
643 nhlfe.prefv4.prefixlen, nhlfe.ifindex);
644
7743f2f8 645 return zclient_send_message(zclient);
cf9b9f77
OD
646}
647
648/* Request zebra to install/remove FEC in FIB */
649static int ospf_zebra_send_mpls_ftn(int cmd, struct sr_nhlfe nhlfe)
650{
651 struct zapi_route api;
652 struct zapi_nexthop *api_nh;
653
654 /* Support only IPv4 */
655 if (nhlfe.prefv4.family != AF_INET)
656 return -1;
657
658 memset(&api, 0, sizeof(api));
659 api.vrf_id = VRF_DEFAULT;
93f0a26e 660 api.type = ZEBRA_ROUTE_OSPF;
cf9b9f77
OD
661 api.safi = SAFI_UNICAST;
662 memcpy(&api.prefix, &nhlfe.prefv4, sizeof(struct prefix_ipv4));
663
664 if (cmd == ZEBRA_ROUTE_ADD) {
665 /* Metric value. */
666 SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
667 api.metric = OSPF_SR_DEFAULT_METRIC;
668 /* Nexthop */
669 SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
670 api_nh = &api.nexthops[0];
671 IPV4_ADDR_COPY(&api_nh->gate.ipv4, &nhlfe.nexthop);
672 api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
673 api_nh->ifindex = nhlfe.ifindex;
674 /* MPLS labels */
675 SET_FLAG(api.message, ZAPI_MESSAGE_LABEL);
676 api_nh->labels[0] = nhlfe.label_out;
677 api_nh->label_num = 1;
f56ee10f 678 api_nh->vrf_id = VRF_DEFAULT;
cf9b9f77
OD
679 api.nexthop_num = 1;
680 }
681
682 if (IS_DEBUG_OSPF_SR)
7743f2f8 683 zlog_debug(" |- %s FEC %u for %s/%u via %u",
cf9b9f77
OD
684 cmd == ZEBRA_ROUTE_ADD ? "Add" : "Delete",
685 nhlfe.label_out, inet_ntoa(nhlfe.prefv4.prefix),
686 nhlfe.prefv4.prefixlen, nhlfe.ifindex);
687
7743f2f8 688 return zclient_route_send(cmd, zclient, &api);
cf9b9f77
OD
689}
690
691/* Add new NHLFE entry for SID */
692static inline void add_sid_nhlfe(struct sr_nhlfe nhlfe)
693{
694 if ((nhlfe.label_in != 0) && (nhlfe.label_out != 0)) {
695 ospf_zebra_send_mpls_labels(ZEBRA_MPLS_LABELS_ADD, nhlfe);
70e98a7f 696 if (nhlfe.label_out != MPLS_LABEL_IMPLICIT_NULL)
cf9b9f77
OD
697 ospf_zebra_send_mpls_ftn(ZEBRA_ROUTE_ADD, nhlfe);
698 }
699}
700
701/* Remove NHLFE entry for SID */
702static inline void del_sid_nhlfe(struct sr_nhlfe nhlfe)
703{
704 if ((nhlfe.label_in != 0) && (nhlfe.label_out != 0)) {
705 ospf_zebra_send_mpls_labels(ZEBRA_MPLS_LABELS_DELETE, nhlfe);
70e98a7f 706 if (nhlfe.label_out != MPLS_LABEL_IMPLICIT_NULL)
cf9b9f77
OD
707 ospf_zebra_send_mpls_ftn(ZEBRA_ROUTE_DELETE, nhlfe);
708 }
709}
710
711/* Update NHLFE entry for SID */
712static inline void update_sid_nhlfe(struct sr_nhlfe n1, struct sr_nhlfe n2)
713{
714
715 del_sid_nhlfe(n1);
716 add_sid_nhlfe(n2);
717}
718
719/*
720 * Functions to parse and get Extended Link / Prefix
721 * TLVs and SubTLVs
722 */
723
724/* Extended Link SubTLVs Getter */
725static struct sr_link *get_ext_link_sid(struct tlv_header *tlvh)
726{
727
728 struct sr_link *srl;
729 struct ext_tlv_link *link = (struct ext_tlv_link *)tlvh;
730 struct ext_subtlv_adj_sid *adj_sid;
731 struct ext_subtlv_lan_adj_sid *lan_sid;
732 struct ext_subtlv_rmt_itf_addr *rmt_itf;
733
734 struct tlv_header *sub_tlvh;
93f0a26e 735 uint16_t length = 0, sum = 0, i = 0;
cf9b9f77
OD
736
737 srl = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_link));
738
739 if (srl == NULL)
740 return NULL;
741
742 /* Initialize TLV browsing */
743 length = ntohs(tlvh->length) - EXT_TLV_LINK_SIZE;
744 sub_tlvh = (struct tlv_header *)((char *)(tlvh) + TLV_HDR_SIZE
745 + EXT_TLV_LINK_SIZE);
746 for (; sum < length; sub_tlvh = TLV_HDR_NEXT(sub_tlvh)) {
747 switch (ntohs(sub_tlvh->type)) {
748 case EXT_SUBTLV_ADJ_SID:
749 adj_sid = (struct ext_subtlv_adj_sid *)sub_tlvh;
750 srl->type = ADJ_SID;
751 i = CHECK_FLAG(adj_sid->flags,
752 EXT_SUBTLV_LINK_ADJ_SID_BFLG)
753 ? 1
754 : 0;
755 srl->flags[i] = adj_sid->flags;
756 if (CHECK_FLAG(adj_sid->flags,
757 EXT_SUBTLV_LINK_ADJ_SID_VFLG))
758 srl->sid[i] = GET_LABEL(ntohl(adj_sid->value));
759 else
760 srl->sid[i] = ntohl(adj_sid->value);
761 IPV4_ADDR_COPY(&srl->nhlfe[i].nexthop, &link->link_id);
762 break;
763 case EXT_SUBTLV_LAN_ADJ_SID:
764 lan_sid = (struct ext_subtlv_lan_adj_sid *)sub_tlvh;
765 srl->type = LAN_ADJ_SID;
766 i = CHECK_FLAG(lan_sid->flags,
767 EXT_SUBTLV_LINK_ADJ_SID_BFLG)
768 ? 1
769 : 0;
770 srl->flags[i] = lan_sid->flags;
771 if (CHECK_FLAG(lan_sid->flags,
772 EXT_SUBTLV_LINK_ADJ_SID_VFLG))
773 srl->sid[i] = GET_LABEL(ntohl(lan_sid->value));
774 else
775 srl->sid[i] = ntohl(lan_sid->value);
776 IPV4_ADDR_COPY(&srl->nhlfe[i].nexthop,
777 &lan_sid->neighbor_id);
778 break;
779 case EXT_SUBTLV_RMT_ITF_ADDR:
780 rmt_itf = (struct ext_subtlv_rmt_itf_addr *)sub_tlvh;
781 IPV4_ADDR_COPY(&srl->nhlfe[0].nexthop, &rmt_itf->value);
782 IPV4_ADDR_COPY(&srl->nhlfe[1].nexthop, &rmt_itf->value);
783 break;
784 default:
785 break;
786 }
787 sum += TLV_SIZE(sub_tlvh);
788 }
789
790 IPV4_ADDR_COPY(&srl->nhlfe[0].prefv4.prefix, &link->link_data);
791 srl->nhlfe[0].prefv4.prefixlen = IPV4_MAX_PREFIXLEN;
792 srl->nhlfe[0].prefv4.family = AF_INET;
793 apply_mask_ipv4(&srl->nhlfe[0].prefv4);
794 IPV4_ADDR_COPY(&srl->nhlfe[1].prefv4.prefix, &link->link_data);
795 srl->nhlfe[1].prefv4.prefixlen = IPV4_MAX_PREFIXLEN;
796 srl->nhlfe[1].prefv4.family = AF_INET;
797 apply_mask_ipv4(&srl->nhlfe[1].prefv4);
798
799 if (IS_DEBUG_OSPF_SR) {
7743f2f8 800 zlog_debug(" |- Found primary Adj/Lan Sid %u for %s/%u",
cf9b9f77
OD
801 srl->sid[0], inet_ntoa(srl->nhlfe[0].prefv4.prefix),
802 srl->nhlfe[0].prefv4.prefixlen);
7743f2f8 803 zlog_debug(" |- Found backup Adj/Lan Sid %u for %s/%u",
cf9b9f77
OD
804 srl->sid[1], inet_ntoa(srl->nhlfe[1].prefv4.prefix),
805 srl->nhlfe[1].prefv4.prefixlen);
806 }
807
808 return srl;
809}
810
811/* Extended Prefix SubTLVs Getter */
812static struct sr_prefix *get_ext_prefix_sid(struct tlv_header *tlvh)
813{
814
815 struct sr_prefix *srp;
816 struct ext_tlv_prefix *pref = (struct ext_tlv_prefix *)tlvh;
817 struct ext_subtlv_prefix_sid *psid;
818
819 struct tlv_header *sub_tlvh;
93f0a26e 820 uint16_t length = 0, sum = 0;
cf9b9f77
OD
821
822 srp = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_prefix));
823
824 if (srp == NULL)
825 return NULL;
826
827 /* Initialize TLV browsing */
828 length = ntohs(tlvh->length) - EXT_TLV_PREFIX_SIZE;
829 sub_tlvh = (struct tlv_header *)((char *)(tlvh) + TLV_HDR_SIZE
830 + EXT_TLV_PREFIX_SIZE);
831 for (; sum < length; sub_tlvh = TLV_HDR_NEXT(sub_tlvh)) {
832 switch (ntohs(sub_tlvh->type)) {
833 case EXT_SUBTLV_PREFIX_SID:
834 psid = (struct ext_subtlv_prefix_sid *)sub_tlvh;
835 if (psid->algorithm != SR_ALGORITHM_SPF) {
836 zlog_err(
7743f2f8
OD
837 "SR (%s): Unsupported Algorithm",
838 __func__);
cf9b9f77
OD
839 XFREE(MTYPE_OSPF_SR_PARAMS, srp);
840 return NULL;
841 }
842 srp->type = PREF_SID;
843 srp->flags = psid->flags;
844 if (CHECK_FLAG(psid->flags, EXT_SUBTLV_PREFIX_SID_VFLG))
845 srp->sid = GET_LABEL(ntohl(psid->value));
846 else
847 srp->sid = ntohl(psid->value);
848 IPV4_ADDR_COPY(&srp->nhlfe.prefv4.prefix,
849 &pref->address);
850 srp->nhlfe.prefv4.prefixlen = pref->pref_length;
851 srp->nhlfe.prefv4.family = AF_INET;
852 apply_mask_ipv4(&srp->nhlfe.prefv4);
853 break;
854 default:
855 break;
856 }
857 sum += TLV_SIZE(sub_tlvh);
858 }
859
860 if (IS_DEBUG_OSPF_SR)
7743f2f8 861 zlog_debug(" |- Found SID %u for prefix %s/%u", srp->sid,
cf9b9f77
OD
862 inet_ntoa(srp->nhlfe.prefv4.prefix),
863 srp->nhlfe.prefv4.prefixlen);
864 return srp;
865}
866
867/*
868 * Functions to manipulate Segment Routing Link & Prefix structures
869 */
870
871/* Compare two Segment Link: return 0 if equal, 1 otherwise */
872static inline int sr_link_cmp(struct sr_link *srl1, struct sr_link *srl2)
873{
874 if ((srl1->sid[0] == srl2->sid[0]) && (srl1->sid[1] == srl2->sid[1])
875 && (srl1->type == srl2->type) && (srl1->flags[0] == srl2->flags[0])
876 && (srl1->flags[1] == srl2->flags[1]))
877 return 0;
878 else
879 return 1;
880}
881
882/* Compare two Segment Prefix: return 0 if equal, 1 otherwise */
883static inline int sr_prefix_cmp(struct sr_prefix *srp1, struct sr_prefix *srp2)
884{
885 if ((srp1->sid == srp2->sid) && (srp1->flags == srp2->flags))
886 return 0;
887 else
888 return 1;
889}
890
891/* Update Segment Link of given Segment Routing Node */
892static void update_ext_link_sid(struct sr_node *srn, struct sr_link *srl,
893 u_char lsa_flags)
894{
895 struct listnode *node;
896 struct sr_link *lk;
897 bool found = false;
898
899 /* Sanity check */
900 if ((srn == NULL) || (srl == NULL))
901 return;
902
903 if (IS_DEBUG_OSPF_SR)
904 zlog_debug(" |- Process Extended Link Adj/Lan-SID");
905
906 /* Process only Local Adj/Lan_Adj SID coming from LSA SELF */
907 if (!CHECK_FLAG(srl->flags[0], EXT_SUBTLV_LINK_ADJ_SID_LFLG)
908 || !CHECK_FLAG(srl->flags[1], EXT_SUBTLV_LINK_ADJ_SID_LFLG)
909 || !CHECK_FLAG(lsa_flags, OSPF_LSA_SELF))
910 return;
911
912 /* Search for existing Segment Link */
913 for (ALL_LIST_ELEMENTS_RO(srn->ext_link, node, lk))
914 if (lk->instance == srl->instance) {
915 found = true;
916 break;
917 }
918
919 if (IS_DEBUG_OSPF_SR)
7743f2f8 920 zlog_debug(" |- %s SR Link 8.0.0.%u for SR node %s",
cf9b9f77
OD
921 found ? "Update" : "Add",
922 GET_OPAQUE_ID(srl->instance),
923 inet_ntoa(srn->adv_router));
924
925 /* if not found, add new Segment Link and install NHLFE */
926 if (!found) {
927 /* Complete SR-Link and add it to SR-Node list */
928 srl->srn = srn;
929 IPV4_ADDR_COPY(&srl->adv_router, &srn->adv_router);
930 listnode_add(srn->ext_link, srl);
931 /* Try to set MPLS table */
932 if (compute_link_nhlfe(srl)) {
933 add_sid_nhlfe(srl->nhlfe[0]);
934 add_sid_nhlfe(srl->nhlfe[1]);
935 }
936 } else {
937 if (sr_link_cmp(lk, srl)) {
938 if (compute_link_nhlfe(srl)) {
939 update_sid_nhlfe(lk->nhlfe[0], srl->nhlfe[0]);
940 update_sid_nhlfe(lk->nhlfe[1], srl->nhlfe[1]);
941 /* Replace Segment List */
942 listnode_delete(srn->ext_link, lk);
943 XFREE(MTYPE_OSPF_SR_PARAMS, lk);
944 srl->srn = srn;
945 IPV4_ADDR_COPY(&srl->adv_router,
946 &srn->adv_router);
947 listnode_add(srn->ext_link, srl);
948 } else {
7743f2f8
OD
949 /* New NHLFE was not found.
950 * Just free the SR Link
951 */
cf9b9f77
OD
952 XFREE(MTYPE_OSPF_SR_PARAMS, srl);
953 }
954 } else {
7743f2f8
OD
955 /*
956 * This is just an LSA refresh.
957 * Stop processing and free SR Link
958 */
cf9b9f77
OD
959 XFREE(MTYPE_OSPF_SR_PARAMS, srl);
960 }
961 }
962}
963
964/* Update Segment Prefix of given Segment Routing Node */
965static void update_ext_prefix_sid(struct sr_node *srn, struct sr_prefix *srp)
966{
967
968 struct listnode *node;
969 struct sr_prefix *pref;
970 bool found = false;
971
972 /* Sanity check */
973 if (srn == NULL || srp == NULL)
974 return;
975
976 if (IS_DEBUG_OSPF_SR)
7743f2f8 977 zlog_debug(" |- Process Extended Prefix SID %u", srp->sid);
cf9b9f77
OD
978
979 /* Process only Global Prefix SID */
980 if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_LFLG))
981 return;
982
983 /* Search for existing Segment Prefix */
984 for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, pref))
985 if (pref->instance == srp->instance) {
986 found = true;
987 break;
988 }
989
990 if (IS_DEBUG_OSPF_SR)
7743f2f8 991 zlog_debug(" |- %s SR LSA ID 7.0.0.%u for SR node %s",
cf9b9f77
OD
992 found ? "Update" : "Add",
993 GET_OPAQUE_ID(srp->instance),
994 inet_ntoa(srn->adv_router));
995
996 /* if not found, add new Segment Prefix and install NHLFE */
997 if (!found) {
998 /* Complete SR-Prefix and add it to SR-Node list */
999 srp->srn = srn;
1000 IPV4_ADDR_COPY(&srp->adv_router, &srn->adv_router);
1001 listnode_add(srn->ext_prefix, srp);
1002 /* Try to set MPLS table */
7743f2f8 1003 if (compute_prefix_nhlfe(srp) == 1)
cf9b9f77 1004 add_sid_nhlfe(srp->nhlfe);
cf9b9f77
OD
1005 } else {
1006 if (sr_prefix_cmp(pref, srp)) {
1007 if (compute_prefix_nhlfe(srp) == 1) {
1008 update_sid_nhlfe(pref->nhlfe, srp->nhlfe);
1009 /* Replace Segment Prefix */
1010 listnode_delete(srn->ext_prefix, pref);
1011 XFREE(MTYPE_OSPF_SR_PARAMS, pref);
1012 srp->srn = srn;
1013 IPV4_ADDR_COPY(&srp->adv_router,
1014 &srn->adv_router);
1015 listnode_add(srn->ext_prefix, srp);
1016 } else {
1017 /* New NHLFE was not found.
7743f2f8
OD
1018 * Just free the SR Prefix
1019 */
cf9b9f77
OD
1020 XFREE(MTYPE_OSPF_SR_PARAMS, srp);
1021 }
1022 } else {
1023 /* This is just an LSA refresh.
7743f2f8
OD
1024 * Stop processing and free SR Prefix
1025 */
cf9b9f77
OD
1026 XFREE(MTYPE_OSPF_SR_PARAMS, srp);
1027 }
1028 }
1029}
1030
1031/*
1032 * When change the FRR Self SRGB, update the NHLFE Input Label
1033 * for all Extended Prefix with SID index through hash_iterate()
1034 */
1035static void update_in_nhlfe(struct hash_backet *backet, void *args)
1036{
1037 struct listnode *node;
1038 struct sr_node *srn = (struct sr_node *)backet->data;
1039 struct sr_prefix *srp;
1040 struct sr_nhlfe new;
1041
cf9b9f77
OD
1042 /* Process Every Extended Prefix for this SR-Node */
1043 for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) {
7743f2f8
OD
1044 /* Process Self SRN only if NO-PHP is requested */
1045 if ((srn == OspfSR.self)
1046 && !CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG))
1047 continue;
1048
cf9b9f77
OD
1049 /* Process only SID Index */
1050 if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_VFLG))
1051 continue;
7743f2f8
OD
1052
1053 /* OK. Compute new NHLFE */
cf9b9f77
OD
1054 memcpy(&new, &srp->nhlfe, sizeof(struct sr_nhlfe));
1055 new.label_in = index2label(srp->sid, OspfSR.srgb);
1056 /* Update MPLS LFIB */
1057 update_sid_nhlfe(srp->nhlfe, new);
1058 /* Finally update Input Label */
1059 srp->nhlfe.label_in = new.label_in;
1060 }
1061}
1062
1063/*
1064 * When SRGB has changed, update NHLFE Output Label for all Extended Prefix
1065 * with SID index which use the given SR-Node as nexthop though hash_iterate()
1066 */
1067static void update_out_nhlfe(struct hash_backet *backet, void *args)
1068{
1069 struct listnode *node;
1070 struct sr_node *srn = (struct sr_node *)backet->data;
1071 struct sr_node *srnext = (struct sr_node *)args;
1072 struct sr_prefix *srp;
1073 struct sr_nhlfe new;
1074
1075 for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) {
1076 /* Process only SID Index for next hop without PHP */
1077 if ((srp->nexthop == NULL)
1078 && (!CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG)))
1079 continue;
1080 memcpy(&new, &srp->nhlfe, sizeof(struct sr_nhlfe));
1081 new.label_out = index2label(srp->sid, srnext->srgb);
1082 update_sid_nhlfe(srp->nhlfe, new);
1083 srp->nhlfe.label_out = new.label_out;
1084 }
1085}
1086
1087/*
1088 * Following functions are call when new Segment Routing LSA are received
1089 * - Router Information: ospf_sr_ri_lsa_update() & ospf_sr_ri_lsa_delete()
1090 * - Extended Link: ospf_sr_ext_link_update() & ospf_sr_ext_link_delete()
1091 * - Extended Prefix: ospf_ext_prefix_update() & ospf_sr_ext_prefix_delete()
1092 */
1093
1094/* Update Segment Routing from Router Information LSA */
1095void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa)
1096{
1097 struct sr_node *srn;
1098 struct tlv_header *tlvh;
1099 struct lsa_header *lsah = (struct lsa_header *)lsa->data;
1100 struct ri_sr_tlv_sid_label_range *ri_srgb;
1101 struct ri_sr_tlv_sr_algorithm *algo;
1102 struct sr_srgb srgb;
93f0a26e 1103 uint16_t length = 0, sum = 0;
cf9b9f77
OD
1104
1105 if (IS_DEBUG_OSPF_SR)
1106 zlog_debug(
7743f2f8
OD
1107 "SR (%s): Process Router "
1108 "Information LSA 4.0.0.%u from %s",
1109 __func__,
cf9b9f77
OD
1110 GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
1111 inet_ntoa(lsah->adv_router));
1112
1113 /* Sanity check */
1114 if (IS_LSA_SELF(lsa))
1115 return;
1116
1117 if (OspfSR.neighbors == NULL) {
7743f2f8 1118 zlog_err("SR (%s): Abort! no valid SR DataBase", __func__);
cf9b9f77
OD
1119 return;
1120 }
1121
1122 /* Get SR Node in hash table from Router ID */
1123 srn = hash_get(OspfSR.neighbors, (void *)&(lsah->adv_router),
1124 (void *)sr_node_new);
1125
1126 /* Sanity check */
1127 if (srn == NULL) {
1128 zlog_err(
7743f2f8
OD
1129 "SR (%s): Abort! can't create SR node in hash table",
1130 __func__);
cf9b9f77
OD
1131 return;
1132 }
1133
1134 if ((srn->instance != 0) && (srn->instance != ntohl(lsah->id.s_addr))) {
1135 zlog_err(
7743f2f8
OD
1136 "SR (%s): Abort! Wrong "
1137 "LSA ID 4.0.0.%u for SR node %s/%u",
1138 __func__,
cf9b9f77
OD
1139 GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
1140 inet_ntoa(lsah->adv_router), srn->instance);
1141 return;
1142 }
1143
1144 /* Collect Router Information Sub TLVs */
1145 /* Initialize TLV browsing */
1146 length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE;
1147 srgb.range_size = 0;
1148 srgb.lower_bound = 0;
1149
6aaf0fdd 1150 for (tlvh = TLV_HDR_TOP(lsah); (sum < length) && (tlvh != NULL);
cf9b9f77
OD
1151 tlvh = TLV_HDR_NEXT(tlvh)) {
1152 switch (ntohs(tlvh->type)) {
1153 case RI_SR_TLV_SR_ALGORITHM:
1154 algo = (struct ri_sr_tlv_sr_algorithm *)tlvh;
1155 int i;
7743f2f8 1156
cf9b9f77
OD
1157 for (i = 0; i < ntohs(algo->header.length); i++)
1158 srn->algo[i] = algo->value[0];
1159 for (; i < ALGORITHM_COUNT; i++)
1160 srn->algo[i] = SR_ALGORITHM_UNSET;
1161 sum += TLV_SIZE(tlvh);
1162 break;
1163 case RI_SR_TLV_SID_LABEL_RANGE:
1164 ri_srgb = (struct ri_sr_tlv_sid_label_range *)tlvh;
1165 srgb.range_size = GET_RANGE_SIZE(ntohl(ri_srgb->size));
1166 srgb.lower_bound =
1167 GET_LABEL(ntohl(ri_srgb->lower.value));
1168 sum += TLV_SIZE(tlvh);
1169 break;
1170 case RI_SR_TLV_NODE_MSD:
1171 srn->msd = ((struct ri_sr_tlv_node_msd *)(tlvh))->value;
1172 sum += TLV_SIZE(tlvh);
1173 break;
1174 default:
1175 sum += TLV_SIZE(tlvh);
1176 break;
1177 }
1178 }
1179
1180 /* Check that we collect mandatory parameters */
1181 if (srn->algo[0] == SR_ALGORITHM_UNSET || srgb.range_size == 0
1182 || srgb.lower_bound == 0) {
1183 zlog_warn(
7743f2f8
OD
1184 "SR (%s): Missing mandatory parameters. Abort!",
1185 __func__);
cf9b9f77
OD
1186 hash_release(OspfSR.neighbors, &(srn->adv_router));
1187 XFREE(MTYPE_OSPF_SR_PARAMS, srn);
1188 return;
1189 }
1190
1191 /* Check if it is a new SR Node or not */
1192 if (srn->instance == 0) {
1193 /* update LSA ID */
1194 srn->instance = ntohl(lsah->id.s_addr);
1195 /* Copy SRGB */
1196 srn->srgb.range_size = srgb.range_size;
1197 srn->srgb.lower_bound = srgb.lower_bound;
1198 }
1199
1200 /* Check if SRGB has changed */
1201 if ((srn->srgb.range_size != srgb.range_size)
1202 || (srn->srgb.lower_bound != srgb.lower_bound)) {
1203 srn->srgb.range_size = srgb.range_size;
1204 srn->srgb.lower_bound = srgb.lower_bound;
1205 /* Update NHLFE if it is a neighbor SR node */
1206 if (srn->neighbor == OspfSR.self)
1207 hash_iterate(OspfSR.neighbors,
1208 (void (*)(struct hash_backet *,
1209 void *))update_out_nhlfe,
1210 (void *)srn);
1211 }
1212
cf9b9f77
OD
1213}
1214
1215/*
1216 * Delete SR Node entry in hash table information corresponding to an expired
1217 * Router Information LSA
1218 */
1219void ospf_sr_ri_lsa_delete(struct ospf_lsa *lsa)
1220{
1221 struct sr_node *srn;
1222 struct lsa_header *lsah = (struct lsa_header *)lsa->data;
1223
1224 if (IS_DEBUG_OSPF_SR)
1225 zlog_debug(
7743f2f8
OD
1226 "SR (%s): Remove SR node %s from lsa_id 4.0.0.%u",
1227 __func__, inet_ntoa(lsah->adv_router),
cf9b9f77
OD
1228 GET_OPAQUE_ID(ntohl(lsah->id.s_addr)));
1229
1230 /* Sanity check */
1231 if (OspfSR.neighbors == NULL) {
7743f2f8 1232 zlog_err("SR (%s): Abort! no valid SR Data Base", __func__);
cf9b9f77
OD
1233 return;
1234 }
1235
1236 /* Release Router ID entry in SRDB hash table */
1237 srn = hash_release(OspfSR.neighbors, &(lsah->adv_router));
1238
1239 /* Sanity check */
1240 if (srn == NULL) {
1241 zlog_err(
7743f2f8
OD
1242 "SR (%s): Abort! no entry in SRDB for SR Node %s",
1243 __func__, inet_ntoa(lsah->adv_router));
cf9b9f77
OD
1244 return;
1245 }
1246
1247 if ((srn->instance != 0) && (srn->instance != ntohl(lsah->id.s_addr))) {
1248 zlog_err(
7743f2f8
OD
1249 "SR (%s): Abort! Wrong LSA ID 4.0.0.%u for SR node %s",
1250 __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
cf9b9f77
OD
1251 inet_ntoa(lsah->adv_router));
1252 return;
1253 }
1254
1255 /* Remove SR node */
1256 sr_node_del(srn);
1257
cf9b9f77
OD
1258}
1259
1260/* Update Segment Routing from Extended Link LSA */
1261void ospf_sr_ext_link_lsa_update(struct ospf_lsa *lsa)
1262{
1263 struct sr_node *srn;
1264 struct tlv_header *tlvh;
1265 struct lsa_header *lsah = (struct lsa_header *)lsa->data;
1266 struct sr_link *srl;
1267
93f0a26e 1268 uint16_t length, sum;
cf9b9f77
OD
1269
1270 if (IS_DEBUG_OSPF_SR)
1271 zlog_debug(
7743f2f8
OD
1272 "SR (%s): Process Extended Link LSA 8.0.0.%u from %s",
1273 __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
cf9b9f77
OD
1274 inet_ntoa(lsah->adv_router));
1275
1276 /* Sanity check */
1277 if (OspfSR.neighbors == NULL) {
7743f2f8 1278 zlog_err("SR (%s): Abort! no valid SR DataBase", __func__);
cf9b9f77
OD
1279 return;
1280 }
1281
1282 /* Get SR Node in hash table from Router ID */
1283 srn = (struct sr_node *)hash_get(OspfSR.neighbors,
1284 (void *)&(lsah->adv_router),
1285 (void *)sr_node_new);
1286
1287 /* Sanity check */
1288 if (srn == NULL) {
1289 zlog_err(
7743f2f8
OD
1290 "SR (%s): Abort! can't create SR node in hash table",
1291 __func__);
cf9b9f77
OD
1292 return;
1293 }
1294
1295 /* Initialize TLV browsing */
1296 length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE;
1297 sum = 0;
6aaf0fdd 1298 for (tlvh = TLV_HDR_TOP(lsah); (sum < length) && (tlvh != NULL);
cf9b9f77
OD
1299 tlvh = TLV_HDR_NEXT(tlvh)) {
1300 if (ntohs(tlvh->type) == EXT_TLV_LINK) {
1301 /* Got Extended Link information */
1302 srl = get_ext_link_sid(tlvh);
1303 /* Update SID if not null */
1304 if (srl != NULL) {
1305 srl->instance = ntohl(lsah->id.s_addr);
1306 update_ext_link_sid(srn, srl, lsa->flags);
1307 }
1308 }
1309 sum += TLV_SIZE(tlvh);
1310 }
1311}
1312
1313/* Delete Segment Routing from Extended Link LSA */
1314void ospf_sr_ext_link_lsa_delete(struct ospf_lsa *lsa)
1315{
1316 struct listnode *node;
1317 struct sr_link *srl;
1318 struct sr_node *srn;
1319 struct lsa_header *lsah = (struct lsa_header *)lsa->data;
93f0a26e 1320 uint32_t instance = ntohl(lsah->id.s_addr);
cf9b9f77
OD
1321
1322 if (IS_DEBUG_OSPF_SR)
1323 zlog_debug(
7743f2f8
OD
1324 "SR (%s): Remove Extended Link LSA 8.0.0.%u from %s",
1325 __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
cf9b9f77
OD
1326 inet_ntoa(lsah->adv_router));
1327
1328 /* Sanity check */
1329 if (OspfSR.neighbors == NULL) {
7743f2f8 1330 zlog_err("SR (%s): Abort! no valid SR DataBase", __func__);
cf9b9f77
OD
1331 return;
1332 }
1333
1334 /* Search SR Node in hash table from Router ID */
1335 srn = (struct sr_node *)hash_lookup(OspfSR.neighbors,
1336 (void *)&(lsah->adv_router));
1337
7743f2f8
OD
1338 /*
1339 * SR-Node may be NULL if it has been remove previously when
1340 * processing Router Information LSA deletion
1341 */
cf9b9f77 1342 if (srn == NULL) {
fd3b19f2 1343 zlog_warn(
7743f2f8
OD
1344 "SR (%s): Stop! no entry in SRDB for SR Node %s",
1345 __func__, inet_ntoa(lsah->adv_router));
cf9b9f77
OD
1346 return;
1347 }
1348
1349 /* Search for corresponding Segment Link */
1350 for (ALL_LIST_ELEMENTS_RO(srn->ext_link, node, srl))
1351 if (srl->instance == instance)
1352 break;
1353
1354 /* Remove Segment Link if found */
fd3b19f2 1355 if ((srl != NULL) && (srl->instance == instance)) {
cf9b9f77
OD
1356 del_sid_nhlfe(srl->nhlfe[0]);
1357 del_sid_nhlfe(srl->nhlfe[1]);
1358 listnode_delete(srn->ext_link, srl);
1359 XFREE(MTYPE_OSPF_SR_PARAMS, srl);
1360 } else {
1361 zlog_warn(
7743f2f8
OD
1362 "SR (%s): Didn't found corresponding SR Link 8.0.0.%u "
1363 "for SR Node %s", __func__,
cf9b9f77
OD
1364 GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
1365 inet_ntoa(lsah->adv_router));
1366 }
1367
cf9b9f77
OD
1368}
1369
1370/* Update Segment Routing from Extended Prefix LSA */
1371void ospf_sr_ext_prefix_lsa_update(struct ospf_lsa *lsa)
1372{
1373 struct sr_node *srn;
1374 struct tlv_header *tlvh;
1375 struct lsa_header *lsah = (struct lsa_header *)lsa->data;
1376 struct sr_prefix *srp;
1377
93f0a26e 1378 uint16_t length, sum;
cf9b9f77
OD
1379
1380 if (IS_DEBUG_OSPF_SR)
1381 zlog_debug(
7743f2f8
OD
1382 "SR (%s): Process Extended Prefix LSA "
1383 "7.0.0.%u from %s", __func__,
cf9b9f77
OD
1384 GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
1385 inet_ntoa(lsah->adv_router));
1386
1387 /* Sanity check */
1388 if (OspfSR.neighbors == NULL) {
7743f2f8 1389 zlog_err("SR (%s): Abort! no valid SR DataBase", __func__);
cf9b9f77
OD
1390 return;
1391 }
1392
1393 /* Get SR Node in hash table from Router ID */
1394 srn = (struct sr_node *)hash_get(OspfSR.neighbors,
1395 (void *)&(lsah->adv_router),
1396 (void *)sr_node_new);
1397
1398 /* Sanity check */
1399 if (srn == NULL) {
1400 zlog_err(
7743f2f8
OD
1401 "SR (%s): Abort! can't create SR node in hash table",
1402 __func__);
cf9b9f77
OD
1403 return;
1404 }
1405
1406 /* Initialize TLV browsing */
1407 length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE;
1408 sum = 0;
1409 for (tlvh = TLV_HDR_TOP(lsah); sum < length;
1410 tlvh = TLV_HDR_NEXT(tlvh)) {
1411 if (ntohs(tlvh->type) == EXT_TLV_LINK) {
1412 /* Got Extended Link information */
1413 srp = get_ext_prefix_sid(tlvh);
1414 /* Update SID if not null */
1415 if (srp != NULL) {
1416 srp->instance = ntohl(lsah->id.s_addr);
1417 update_ext_prefix_sid(srn, srp);
1418 }
1419 }
1420 sum += TLV_SIZE(tlvh);
1421 }
1422}
1423
1424/* Delete Segment Routing from Extended Prefix LSA */
1425void ospf_sr_ext_prefix_lsa_delete(struct ospf_lsa *lsa)
1426{
1427 struct listnode *node;
1428 struct sr_prefix *srp;
1429 struct sr_node *srn;
1430 struct lsa_header *lsah = (struct lsa_header *)lsa->data;
93f0a26e 1431 uint32_t instance = ntohl(lsah->id.s_addr);
cf9b9f77
OD
1432
1433 if (IS_DEBUG_OSPF_SR)
1434 zlog_debug(
7743f2f8
OD
1435 "SR (%s): Remove Extended Prefix LSA 7.0.0.%u from %s",
1436 __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
cf9b9f77
OD
1437 inet_ntoa(lsah->adv_router));
1438
1439 /* Sanity check */
1440 if (OspfSR.neighbors == NULL) {
7743f2f8 1441 zlog_err("SR (%s): Abort! no valid SR DataBase", __func__);
cf9b9f77
OD
1442 return;
1443 }
1444
1445 /* Search SR Node in hash table from Router ID */
1446 srn = (struct sr_node *)hash_lookup(OspfSR.neighbors,
1447 (void *)&(lsah->adv_router));
1448
7743f2f8
OD
1449 /*
1450 * SR-Node may be NULL if it has been remove previously when
1451 * processing Router Information LSA deletion
1452 */
cf9b9f77 1453 if (srn == NULL) {
fd3b19f2 1454 zlog_warn(
7743f2f8
OD
1455 "SR (%s): Stop! no entry in SRDB for SR Node %s",
1456 __func__, inet_ntoa(lsah->adv_router));
cf9b9f77
OD
1457 return;
1458 }
1459
1460 /* Search for corresponding Segment Link */
1461 for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp))
1462 if (srp->instance == instance)
1463 break;
1464
1465 /* Remove Segment Link if found */
fd3b19f2 1466 if ((srp != NULL) && (srp->instance == instance)) {
cf9b9f77
OD
1467 del_sid_nhlfe(srp->nhlfe);
1468 listnode_delete(srn->ext_link, srp);
1469 XFREE(MTYPE_OSPF_SR_PARAMS, srp);
1470 } else {
1471 zlog_warn(
7743f2f8
OD
1472 "SR (%s): Didn't found corresponding SR Prefix "
1473 "7.0.0.%u for SR Node %s", __func__,
cf9b9f77
OD
1474 GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
1475 inet_ntoa(lsah->adv_router));
1476 }
1477
cf9b9f77
OD
1478}
1479
1480/* Get Label for Extended Link SID */
1481/* TODO: To be replace by Zebra Label Manager */
93f0a26e 1482uint32_t get_ext_link_label_value(void)
cf9b9f77 1483{
93f0a26e 1484 static uint32_t label = ADJ_SID_MIN - 1;
cf9b9f77
OD
1485
1486 if (label < ADJ_SID_MAX)
1487 label += 1;
1488
1489 return label;
1490}
1491
7743f2f8
OD
1492/*
1493 * Update Prefix SID. Call by ospf_ext_pref_ism_change to
1494 * complete initial CLI command at startutp.
1495 *
1496 * @param ifp - Loopback interface
1497 * @param pref - Prefix address of this interface
1498 *
1499 * @return - void
1500 */
1501void ospf_sr_update_prefix(struct interface *ifp, struct prefix *p)
1502{
1503 struct listnode *node;
1504 struct sr_prefix *srp;
7743f2f8
OD
1505
1506 /* Sanity Check */
1507 if ((ifp == NULL) || (p == NULL))
1508 return;
1509
1510 /*
1511 * Search if there is a Segment Prefix that correspond to this
1512 * interface or prefix, and update it if found
1513 */
1514 for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node, srp)) {
1515 if ((srp->nhlfe.ifindex == ifp->ifindex)
1516 || ((IPV4_ADDR_SAME(&srp->nhlfe.prefv4.prefix,
1517 &p->u.prefix4))
1518 && (srp->nhlfe.prefv4.prefixlen == p->prefixlen))) {
1519
1520 /* Update Interface & Prefix info */
1521 srp->nhlfe.ifindex = ifp->ifindex;
1522 IPV4_ADDR_COPY(&srp->nhlfe.prefv4.prefix,
1523 &p->u.prefix4);
1524 srp->nhlfe.prefv4.prefixlen = p->prefixlen;
1525 srp->nhlfe.prefv4.family = p->family;
1526 IPV4_ADDR_COPY(&srp->nhlfe.nexthop, &p->u.prefix4);
1527
1528 /* OK. Let's Schedule Extended Prefix LSA */
db28a51f
OD
1529 srp->instance = ospf_ext_schedule_prefix_index(ifp,
1530 srp->sid, &srp->nhlfe.prefv4, srp->flags);
7743f2f8
OD
1531
1532 /* Install NHLFE if NO-PHP is requested */
1533 if (CHECK_FLAG(srp->flags,
1534 EXT_SUBTLV_PREFIX_SID_NPFLG)) {
1535 srp->nhlfe.label_in = index2label(srp->sid,
1536 OspfSR.self->srgb);
70e98a7f 1537 srp->nhlfe.label_out = MPLS_LABEL_IMPLICIT_NULL;
7743f2f8
OD
1538 add_sid_nhlfe(srp->nhlfe);
1539 }
1540 }
1541 }
1542}
1543
cf9b9f77
OD
1544/*
1545 * Following functions are used to update MPLS LFIB after a SPF run
1546 */
1547
1548static void ospf_sr_nhlfe_update(struct hash_backet *backet, void *args)
1549{
1550
1551 struct sr_node *srn = (struct sr_node *)backet->data;
1552 struct listnode *node;
1553 struct sr_prefix *srp;
1554 struct sr_nhlfe old;
cf9b9f77
OD
1555 int rc;
1556
1557 /* Sanity Check */
1558 if (srn == NULL)
1559 return;
1560
1561 if (IS_DEBUG_OSPF_SR)
1562 zlog_debug(" |- Update Prefix for SR Node %s",
1563 inet_ntoa(srn->adv_router));
1564
7743f2f8
OD
1565 /* Skip Self SR Node */
1566 if (srn == OspfSR.self)
cf9b9f77 1567 return;
cf9b9f77
OD
1568
1569 /* Update Extended Prefix */
1570 for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) {
1571
1572 /* Backup current NHLFE */
1573 memcpy(&old, &srp->nhlfe, sizeof(struct sr_nhlfe));
1574
1575 /* Compute the new NHLFE */
1576 rc = compute_prefix_nhlfe(srp);
1577
1578 /* Check computation result */
1579 switch (rc) {
1580 /* next hop is not know, remove old NHLFE to avoid loop */
1581 case -1:
1582 del_sid_nhlfe(srp->nhlfe);
1583 break;
1584 /* next hop has not changed, skip it */
1585 case 0:
1586 break;
1587 /* there is a new next hop, update NHLFE */
1588 case 1:
1589 update_sid_nhlfe(old, srp->nhlfe);
1590 break;
1591 default:
1592 break;
1593 }
1594 }
1595}
1596
1597static int ospf_sr_update_schedule(struct thread *t)
1598{
1599
1600 struct ospf *ospf;
1601 struct timeval start_time, stop_time;
1602
1603 ospf = THREAD_ARG(t);
1604 ospf->t_sr_update = NULL;
1605
1606 if (!OspfSR.update)
1607 return 0;
1608
1609 monotime(&start_time);
1610
1611 if (IS_DEBUG_OSPF_SR)
7743f2f8 1612 zlog_debug("SR (%s): Start SPF update", __func__);
cf9b9f77
OD
1613
1614 hash_iterate(OspfSR.neighbors, (void (*)(struct hash_backet *,
1615 void *))ospf_sr_nhlfe_update,
1616 NULL);
1617
1618 monotime(&stop_time);
1619
1620 zlog_info(
7743f2f8
OD
1621 "SR (%s): SPF Processing Time(usecs): %lld\n",
1622 __func__,
cf9b9f77
OD
1623 (stop_time.tv_sec - start_time.tv_sec) * 1000000LL
1624 + (stop_time.tv_usec - start_time.tv_usec));
1625
1626 OspfSR.update = false;
1627 return 1;
1628}
1629
1630#define OSPF_SR_UPDATE_INTERVAL 1
1631
1632void ospf_sr_update_timer_add(struct ospf *ospf)
1633{
1634
1635 if (ospf == NULL)
1636 return;
1637
1638 /* Check if an update is not alreday engage */
1639 if (OspfSR.update)
1640 return;
1641
1642 OspfSR.update = true;
1643
1644 thread_add_timer(master, ospf_sr_update_schedule, ospf,
1645 OSPF_SR_UPDATE_INTERVAL, &ospf->t_sr_update);
1646}
1647
7743f2f8
OD
1648/*
1649 * --------------------------------------
cf9b9f77 1650 * Followings are vty command functions.
7743f2f8
OD
1651 * --------------------------------------
1652 */
cf9b9f77
OD
1653
1654/*
1655 * Segment Routing Router configuration
1656 *
1657 * Must be centralize as it concerns both Extended Link/Prefix LSA
1658 * and Router Information LSA. Choose to call it from Extended Prefix
1659 * write_config() call back.
1660 *
1661 * @param vty VTY output
1662 *
1663 * @return none
1664 */
1665void ospf_sr_config_write_router(struct vty *vty)
1666{
1667 struct listnode *node;
1668 struct sr_prefix *srp;
1669
1670 if (OspfSR.enabled) {
1671 vty_out(vty, " segment-routing on\n");
1672
7743f2f8
OD
1673 if ((OspfSR.srgb.lower_bound != MPLS_DEFAULT_MIN_SRGB_LABEL)
1674 || (OspfSR.srgb.range_size != MPLS_DEFAULT_MAX_SRGB_SIZE)) {
1675 vty_out(vty, " segment-routing global-block %u %u\n",
1676 OspfSR.srgb.lower_bound,
1677 OspfSR.srgb.lower_bound +
1678 OspfSR.srgb.range_size - 1);
1679 }
cf9b9f77 1680 if (OspfSR.msd != 0)
7743f2f8 1681 vty_out(vty, " segment-routing node-msd %u\n",
cf9b9f77
OD
1682 OspfSR.msd);
1683
1684 if (OspfSR.self != NULL) {
1685 for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node,
1686 srp)) {
1687 vty_out(vty,
7743f2f8
OD
1688 " segment-routing prefix %s/%u "
1689 "index %u%s\n",
cf9b9f77 1690 inet_ntoa(srp->nhlfe.prefv4.prefix),
7743f2f8
OD
1691 srp->nhlfe.prefv4.prefixlen, srp->sid,
1692 CHECK_FLAG(srp->flags,
1693 EXT_SUBTLV_PREFIX_SID_NPFLG) ?
1694 " no-php-flag" : "");
cf9b9f77
OD
1695 }
1696 }
1697 }
1698}
1699
1700DEFUN(ospf_sr_enable,
1701 ospf_sr_enable_cmd,
1702 "segment-routing on",
1703 SR_STR
1704 "Enable Segment Routing\n")
1705{
1706
1707 VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
1708
1709 if (OspfSR.enabled)
1710 return CMD_SUCCESS;
1711
7726c479
OD
1712 if (ospf->vrf_id != VRF_DEFAULT) {
1713 vty_out(vty, "Segment Routing is only supported in default "
1714 "VRF\n");
1715 return CMD_WARNING_CONFIG_FAILED;
1716 }
1717
cf9b9f77
OD
1718 if (IS_DEBUG_OSPF_EVENT)
1719 zlog_debug("SR: Segment Routing: OFF -> ON");
1720
1721 /* Start Segment Routing */
1722 OspfSR.enabled = true;
1723 if (!ospf_sr_start(ospf)) {
1724 zlog_warn("SR: Unable to start Segment Routing. Abort!");
1725 return CMD_WARNING;
1726 }
1727
1728 /* Set Router Information SR parameters */
1729 if (IS_DEBUG_OSPF_EVENT)
1730 zlog_debug("SR: Activate SR for Router Information LSA");
1731
1732 ospf_router_info_update_sr(true, OspfSR.srgb, OspfSR.msd);
1733
1734 /* Update Ext LSA */
1735 if (IS_DEBUG_OSPF_EVENT)
1736 zlog_debug("SR: Activate SR for Extended Link/Prefix LSA");
1737
1738 ospf_ext_update_sr(true);
1739
1740 return CMD_SUCCESS;
1741}
1742
1743DEFUN (no_ospf_sr_enable,
1744 no_ospf_sr_enable_cmd,
1745 "no segment-routing [on]",
1746 NO_STR
1747 SR_STR
1748 "Disable Segment Routing\n")
1749{
1750
1751 if (!OspfSR.enabled)
1752 return CMD_SUCCESS;
1753
1754 if (IS_DEBUG_OSPF_EVENT)
1755 zlog_debug("SR: Segment Routing: ON -> OFF");
1756
1757 /* Start by Disabling Extended Link & Prefix LSA */
1758 ospf_ext_update_sr(false);
1759
1760 /* then, disable Router Information SR parameters */
1761 ospf_router_info_update_sr(false, OspfSR.srgb, OspfSR.msd);
1762
1763 /* Finally, stop Segment Routing */
1764 ospf_sr_stop();
1765 OspfSR.enabled = false;
1766
1767 return CMD_SUCCESS;
1768}
1769
1770static int ospf_sr_enabled(struct vty *vty)
1771{
1772 if (OspfSR.enabled)
1773 return 1;
1774
1775 if (vty)
1776 vty_out(vty, "%% OSPF SR is not turned on\n");
1777
1778 return 0;
1779}
1780
1781DEFUN (sr_sid_label_range,
1782 sr_sid_label_range_cmd,
1783 "segment-routing global-block (0-1048575) (0-1048575)",
1784 SR_STR
1785 "Segment Routing Global Block label range\n"
1786 "Lower-bound range in decimal (0-1048575)\n"
1787 "Upper-bound range in decimal (0-1048575)\n")
1788{
93f0a26e
OD
1789 uint32_t upper;
1790 uint32_t lower;
1791 uint32_t size;
cf9b9f77
OD
1792 int idx_low = 2;
1793 int idx_up = 3;
1794
1795 if (!ospf_sr_enabled(vty))
1796 return CMD_WARNING_CONFIG_FAILED;
1797
7743f2f8
OD
1798 /* Get lower and upper bound */
1799 lower = strtoul(argv[idx_low]->arg, NULL, 10);
1800 upper = strtoul(argv[idx_up]->arg, NULL, 10);
cf9b9f77
OD
1801 size = upper - lower + 1;
1802
1803 if (size > MPLS_DEFAULT_MAX_SRGB_SIZE || size <= 0) {
1804 vty_out(vty,
7743f2f8 1805 "Range size cannot be less than 0 or more than %u\n",
cf9b9f77
OD
1806 MPLS_DEFAULT_MAX_SRGB_SIZE);
1807 return CMD_WARNING_CONFIG_FAILED;
1808 }
1809
1810 if (upper > MPLS_DEFAULT_MAX_SRGB_LABEL) {
7743f2f8 1811 vty_out(vty, "Upper-bound cannot exceed %u\n",
cf9b9f77
OD
1812 MPLS_DEFAULT_MAX_SRGB_LABEL);
1813 return CMD_WARNING_CONFIG_FAILED;
1814 }
1815
1816 if (upper < MPLS_DEFAULT_MIN_SRGB_LABEL) {
7743f2f8 1817 vty_out(vty, "Upper-bound cannot be lower than %u\n",
cf9b9f77
OD
1818 MPLS_DEFAULT_MIN_SRGB_LABEL);
1819 return CMD_WARNING_CONFIG_FAILED;
1820 }
1821
7743f2f8
OD
1822 /* Check if values have changed */
1823 if ((OspfSR.srgb.range_size == size)
1824 && (OspfSR.srgb.lower_bound == lower))
1825 return CMD_SUCCESS;
1826
cf9b9f77
OD
1827 /* Set SID/Label range SRGB */
1828 OspfSR.srgb.range_size = size;
1829 OspfSR.srgb.lower_bound = lower;
7743f2f8
OD
1830 if (OspfSR.self != NULL) {
1831 OspfSR.self->srgb.range_size = size;
1832 OspfSR.self->srgb.lower_bound = lower;
1833 }
cf9b9f77
OD
1834
1835 /* Set Router Information SR parameters */
1836 ospf_router_info_update_sr(true, OspfSR.srgb, OspfSR.msd);
1837
1838 /* Update NHLFE entries */
1839 hash_iterate(OspfSR.neighbors,
1840 (void (*)(struct hash_backet *, void *))update_in_nhlfe,
1841 NULL);
1842
1843 return CMD_SUCCESS;
1844}
1845
1846DEFUN (no_sr_sid_label_range,
1847 no_sr_sid_label_range_cmd,
7743f2f8 1848 "no segment-routing global-block [(0-1048575) (0-1048575)]",
cf9b9f77
OD
1849 NO_STR
1850 SR_STR
7743f2f8
OD
1851 "Segment Routing Global Block label range\n"
1852 "Lower-bound range in decimal (0-1048575)\n"
1853 "Upper-bound range in decimal (0-1048575)\n")
cf9b9f77
OD
1854{
1855
1856 if (!ospf_sr_enabled(vty))
1857 return CMD_WARNING_CONFIG_FAILED;
1858
1859 /* Revert to default SRGB value */
1860 OspfSR.srgb.range_size = MPLS_DEFAULT_MIN_SRGB_SIZE;
1861 OspfSR.srgb.lower_bound = MPLS_DEFAULT_MIN_SRGB_LABEL;
7743f2f8
OD
1862 if (OspfSR.self != NULL) {
1863 OspfSR.self->srgb.range_size = OspfSR.srgb.range_size;
1864 OspfSR.self->srgb.lower_bound = OspfSR.srgb.lower_bound;
1865 }
cf9b9f77
OD
1866
1867 /* Set Router Information SR parameters */
1868 ospf_router_info_update_sr(true, OspfSR.srgb, OspfSR.msd);
1869
1870 /* Update NHLFE entries */
1871 hash_iterate(OspfSR.neighbors,
1872 (void (*)(struct hash_backet *, void *))update_in_nhlfe,
1873 NULL);
1874
1875 return CMD_SUCCESS;
1876}
1877
1878DEFUN (sr_node_msd,
1879 sr_node_msd_cmd,
1880 "segment-routing node-msd (1-16)",
1881 SR_STR
1882 "Maximum Stack Depth for this router\n"
1883 "Maximum number of label that could be stack (1-16)\n")
1884{
93f0a26e 1885 uint32_t msd;
62c99790 1886 int idx = 1;
cf9b9f77
OD
1887
1888 if (!ospf_sr_enabled(vty))
1889 return CMD_WARNING_CONFIG_FAILED;
1890
7743f2f8
OD
1891 /* Get MSD */
1892 argv_find(argv, argc, "(1-16)", &idx);
1893 msd = strtoul(argv[idx]->arg, NULL, 10);
cf9b9f77 1894 if (msd < 1 || msd > MPLS_MAX_LABELS) {
7743f2f8 1895 vty_out(vty, "MSD must be comprise between 1 and %u\n",
cf9b9f77
OD
1896 MPLS_MAX_LABELS);
1897 return CMD_WARNING_CONFIG_FAILED;
1898 }
1899
7743f2f8
OD
1900 /* Check if value has changed */
1901 if (OspfSR.msd == msd)
1902 return CMD_SUCCESS;
1903
cf9b9f77
OD
1904 /* Set this router MSD */
1905 OspfSR.msd = msd;
7743f2f8
OD
1906 if (OspfSR.self != NULL)
1907 OspfSR.self->msd = msd;
cf9b9f77
OD
1908
1909 /* Set Router Information SR parameters */
1910 ospf_router_info_update_sr(true, OspfSR.srgb, OspfSR.msd);
1911
1912 return CMD_SUCCESS;
1913}
1914
1915DEFUN (no_sr_node_msd,
1916 no_sr_node_msd_cmd,
7743f2f8 1917 "no segment-routing node-msd [(1-16)]",
cf9b9f77
OD
1918 NO_STR
1919 SR_STR
7743f2f8
OD
1920 "Maximum Stack Depth for this router\n"
1921 "Maximum number of label that could be stack (1-16)\n")
cf9b9f77
OD
1922{
1923
1924 if (!ospf_sr_enabled(vty))
1925 return CMD_WARNING_CONFIG_FAILED;
1926
1927 /* unset this router MSD */
1928 OspfSR.msd = 0;
7743f2f8
OD
1929 if (OspfSR.self != NULL)
1930 OspfSR.self->msd = 0;
cf9b9f77
OD
1931
1932 /* Set Router Information SR parameters */
1933 ospf_router_info_update_sr(true, OspfSR.srgb, 0);
1934
1935 return CMD_SUCCESS;
1936}
1937
1938DEFUN (sr_prefix_sid,
1939 sr_prefix_sid_cmd,
7743f2f8 1940 "segment-routing prefix A.B.C.D/M index (0-65535) [no-php-flag]",
cf9b9f77
OD
1941 SR_STR
1942 "Prefix SID\n"
1943 "IPv4 Prefix as A.B.C.D/M\n"
1944 "SID index for this prefix in decimal (0-65535)\n"
7743f2f8
OD
1945 "Index value inside SRGB (lower_bound < index < upper_bound)\n"
1946 "Don't request Penultimate Hop Popping (PHP)\n")
cf9b9f77 1947{
7743f2f8 1948 int idx = 0;
cf9b9f77
OD
1949 struct prefix p;
1950 uint32_t index;
1951 struct listnode *node;
6aaf0fdd 1952 struct sr_prefix *srp, *new;
cf9b9f77
OD
1953 struct interface *ifp;
1954
1955 if (!ospf_sr_enabled(vty))
1956 return CMD_WARNING_CONFIG_FAILED;
1957
1958 /* Get network prefix */
7743f2f8 1959 argv_find(argv, argc, "A.B.C.D/M", &idx);
6aaf0fdd 1960 if (!str2prefix(argv[idx]->arg, &p)) {
7743f2f8
OD
1961 vty_out(vty, "Invalid prefix format %s\n",
1962 argv[idx]->arg);
1963 return CMD_WARNING_CONFIG_FAILED;
1964 }
cf9b9f77
OD
1965
1966 /* Get & verify index value */
7743f2f8
OD
1967 argv_find(argv, argc, "(0-65535)", &idx);
1968 index = strtoul(argv[idx]->arg, NULL, 10);
cf9b9f77 1969 if (index > OspfSR.srgb.range_size - 1) {
7743f2f8 1970 vty_out(vty, "Index %u must be lower than range size %u\n",
cf9b9f77
OD
1971 index, OspfSR.srgb.range_size);
1972 return CMD_WARNING_CONFIG_FAILED;
1973 }
1974
1975 /* check that the index is not already used */
1976 for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node, srp)) {
1977 if (srp->sid == index) {
7743f2f8 1978 vty_out(vty, "Index %u is already used\n", index);
cf9b9f77
OD
1979 return CMD_WARNING_CONFIG_FAILED;
1980 }
1981 }
1982
6aaf0fdd
OD
1983 /* Create new Extended Prefix to SRDB if not found */
1984 new = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_prefix));
1985 IPV4_ADDR_COPY(&new->nhlfe.prefv4.prefix, &p.u.prefix4);
1986 IPV4_ADDR_COPY(&new->nhlfe.nexthop, &p.u.prefix4);
1987 new->nhlfe.prefv4.prefixlen = p.prefixlen;
1988 new->nhlfe.prefv4.family = p.family;
1989 new->sid = index;
1990 /* Set NO PHP flag if present and compute NHLFE */
1991 if (argv_find(argv, argc, "no-php-flag", &idx)) {
1992 SET_FLAG(new->flags, EXT_SUBTLV_PREFIX_SID_NPFLG);
1993 new->nhlfe.label_in = index2label(new->sid, OspfSR.self->srgb);
70e98a7f 1994 new->nhlfe.label_out = MPLS_LABEL_IMPLICIT_NULL;
6aaf0fdd 1995 }
7743f2f8
OD
1996
1997 if (IS_DEBUG_OSPF_SR)
1998 zlog_debug(
6aaf0fdd
OD
1999 "SR (%s): Add new index %u to Prefix %s/%u",
2000 __func__, index, inet_ntoa(new->nhlfe.prefv4.prefix),
2001 new->nhlfe.prefv4.prefixlen);
7743f2f8 2002
cf9b9f77
OD
2003 /* Get Interface and check if it is a Loopback */
2004 ifp = if_lookup_prefix(&p, VRF_DEFAULT);
2005 if (ifp == NULL) {
7743f2f8
OD
2006 /*
2007 * Interface could be not yet available i.e. when this
cf9b9f77
OD
2008 * command is in the configuration file, OSPF is not yet
2009 * ready. In this case, store the prefix SID for latter
7743f2f8
OD
2010 * update of this Extended Prefix
2011 */
6aaf0fdd 2012 listnode_add(OspfSR.self->ext_prefix, new);
7743f2f8
OD
2013 zlog_warn(
2014 "Interface for prefix %s/%u not found. Deferred LSA "
2015 "flooding", inet_ntoa(p.u.prefix4), p.prefixlen);
cf9b9f77
OD
2016 return CMD_SUCCESS;
2017 }
7743f2f8 2018
cf9b9f77
OD
2019 if (!if_is_loopback(ifp)) {
2020 vty_out(vty, "interface %s is not a Loopback\n", ifp->name);
6aaf0fdd 2021 XFREE(MTYPE_OSPF_SR_PARAMS, new);
cf9b9f77
OD
2022 return CMD_WARNING_CONFIG_FAILED;
2023 }
6aaf0fdd 2024 new->nhlfe.ifindex = ifp->ifindex;
cf9b9f77 2025
6aaf0fdd
OD
2026 /* Search if this prefix already exist */
2027 for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node, srp)) {
2028 if ((IPV4_ADDR_SAME(&srp->nhlfe.prefv4.prefix, &p.u.prefix4)
2029 && srp->nhlfe.prefv4.prefixlen == p.prefixlen))
2030 break;
2031 else
2032 srp = NULL;
2033 }
2034
2035 /* Update or Add this new SR Prefix */
2036 if (srp) {
2037 update_sid_nhlfe(srp->nhlfe, new->nhlfe);
2038 listnode_delete(OspfSR.self->ext_prefix, srp);
2039 listnode_add(OspfSR.self->ext_prefix, new);
2040 } else {
2041 listnode_add(OspfSR.self->ext_prefix, new);
2042 add_sid_nhlfe(new->nhlfe);
7743f2f8
OD
2043 }
2044
2045 /* Finally, update Extended Prefix LSA */
6aaf0fdd
OD
2046 new->instance = ospf_ext_schedule_prefix_index(ifp, new->sid,
2047 &new->nhlfe.prefv4, new->flags);
2048 if (new->instance == 0) {
7743f2f8
OD
2049 vty_out(vty, "Unable to set index %u for prefix %s/%u\n", index,
2050 inet_ntoa(p.u.prefix4), p.prefixlen);
cf9b9f77
OD
2051 return CMD_WARNING;
2052 }
2053
2054 return CMD_SUCCESS;
2055}
2056
2057DEFUN (no_sr_prefix_sid,
2058 no_sr_prefix_sid_cmd,
7743f2f8 2059 "no segment-routing prefix A.B.C.D/M [index (0-65535) no-php-flag]",
cf9b9f77
OD
2060 NO_STR
2061 SR_STR
2062 "Prefix SID\n"
7743f2f8
OD
2063 "IPv4 Prefix as A.B.C.D/M\n"
2064 "SID index for this prefix in decimal (0-65535)\n"
2065 "Index value inside SRGB (lower_bound < index < upper_bound)\n"
2066 "Don't request Penultimate Hop Popping (PHP)\n")
cf9b9f77 2067{
7743f2f8 2068 int idx = 0;
cf9b9f77
OD
2069 struct prefix p;
2070 struct listnode *node;
2071 struct sr_prefix *srp;
2072 struct interface *ifp;
2073 bool found = false;
7743f2f8 2074 int rc;
cf9b9f77
OD
2075
2076 /* Get network prefix */
7743f2f8
OD
2077 argv_find(argv, argc, "A.B.C.D/M", &idx);
2078 rc = str2prefix(argv[idx]->arg, &p);
2079 if (!rc) {
2080 vty_out(vty, "Invalid prefix format %s\n",
2081 argv[idx]->arg);
2082 return CMD_WARNING_CONFIG_FAILED;
2083 }
cf9b9f77
OD
2084
2085 /* check that the prefix is already set */
2086 for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node, srp))
2087 if (IPV4_ADDR_SAME(&srp->nhlfe.prefv4.prefix, &p.u.prefix4)
7743f2f8 2088 && (srp->nhlfe.prefv4.prefixlen == p.prefixlen)) {
cf9b9f77 2089 found = true;
7743f2f8
OD
2090 break;
2091 }
cf9b9f77
OD
2092
2093 if (!found) {
2094 vty_out(vty, "Prefix %s is not found. Abort!\n",
7743f2f8 2095 argv[idx]->arg);
cf9b9f77
OD
2096 return CMD_WARNING_CONFIG_FAILED;
2097 }
2098
7743f2f8
OD
2099 /* Get Interface */
2100 ifp = if_lookup_by_index(srp->nhlfe.ifindex, VRF_DEFAULT);
cf9b9f77
OD
2101 if (ifp == NULL) {
2102 vty_out(vty, "interface for prefix %s not found.\n",
7743f2f8 2103 argv[idx]->arg);
cf9b9f77
OD
2104 return CMD_WARNING_CONFIG_FAILED;
2105 }
7743f2f8 2106
cf9b9f77 2107 /* Update Extended Prefix LSA */
7743f2f8 2108 if (!ospf_ext_schedule_prefix_index(ifp, 0, NULL, 0)) {
cf9b9f77
OD
2109 vty_out(vty, "No corresponding loopback interface. Abort!\n");
2110 return CMD_WARNING;
2111 }
2112
7743f2f8
OD
2113 if (IS_DEBUG_OSPF_SR)
2114 zlog_debug(
2115 "SR (%s): Remove Prefix %s/%u with index %u",
2116 __func__, inet_ntoa(srp->nhlfe.prefv4.prefix),
2117 srp->nhlfe.prefv4.prefixlen, srp->sid);
2118
2119 /* Delete NHLFE is NO-PHP is set */
2120 if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG))
2121 del_sid_nhlfe(srp->nhlfe);
2122
2123 /* OK, all is clean, remove SRP from SRDB */
2124 listnode_delete(OspfSR.self->ext_prefix, srp);
2125 XFREE(MTYPE_OSPF_SR_PARAMS, srp);
2126
cf9b9f77
OD
2127 return CMD_SUCCESS;
2128}
2129
7743f2f8
OD
2130
2131
cf9b9f77
OD
2132static void show_vty_sr_node(struct vty *vty, struct sr_node *srn)
2133{
2134
2135 struct listnode *node;
2136 struct sr_link *srl;
2137 struct sr_prefix *srp;
2138 struct interface *itf;
2139 char pref[16];
7743f2f8 2140 char sid[22];
cf9b9f77
OD
2141 char label[8];
2142
2143 /* Sanity Check */
2144 if (srn == NULL)
2145 return;
2146
2147 vty_out(vty, "SR-Node: %s", inet_ntoa(srn->adv_router));
7743f2f8 2148 vty_out(vty, "\tSRGB (Size/Label): %u/%u", srn->srgb.range_size,
cf9b9f77
OD
2149 srn->srgb.lower_bound);
2150 vty_out(vty, "\tAlgorithm(s): %s",
2151 srn->algo[0] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF");
2152 for (int i = 1; i < ALGORITHM_COUNT; i++) {
2153 if (srn->algo[i] == SR_ALGORITHM_UNSET)
2154 continue;
2155 vty_out(vty, "/%s",
2156 srn->algo[i] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF");
2157 }
2158 if (srn->msd != 0)
7743f2f8 2159 vty_out(vty, "\tMSD: %u", srn->msd);
cf9b9f77
OD
2160
2161 vty_out(vty,
7743f2f8 2162 "\n\n Prefix or Link Label In Label Out "
cf9b9f77
OD
2163 "Node or Adj. SID Interface Nexthop\n");
2164 vty_out(vty,
2165 "------------------ -------- --------- "
7743f2f8 2166 "--------------------- --------- ---------------\n");
cf9b9f77
OD
2167 for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) {
2168 strncpy(pref, inet_ntoa(srp->nhlfe.prefv4.prefix), 16);
7743f2f8 2169 snprintf(sid, 22, "SR Pfx (idx %u)", srp->sid);
70e98a7f 2170 if (srp->nhlfe.label_out == MPLS_LABEL_IMPLICIT_NULL)
cf9b9f77
OD
2171 sprintf(label, "pop");
2172 else
7743f2f8 2173 sprintf(label, "%u", srp->nhlfe.label_out);
cf9b9f77 2174 itf = if_lookup_by_index(srp->nhlfe.ifindex, VRF_DEFAULT);
7743f2f8 2175 vty_out(vty, "%15s/%u %8u %9s %21s %9s %15s\n", pref,
cf9b9f77
OD
2176 srp->nhlfe.prefv4.prefixlen, srp->nhlfe.label_in, label,
2177 sid, itf ? itf->name : "-",
2178 inet_ntoa(srp->nhlfe.nexthop));
2179 }
2180
2181 for (ALL_LIST_ELEMENTS_RO(srn->ext_link, node, srl)) {
2182 strncpy(pref, inet_ntoa(srl->nhlfe[0].prefv4.prefix), 16);
7743f2f8 2183 snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[0]);
70e98a7f 2184 if (srl->nhlfe[0].label_out == MPLS_LABEL_IMPLICIT_NULL)
cf9b9f77
OD
2185 sprintf(label, "pop");
2186 else
7743f2f8 2187 sprintf(label, "%u", srl->nhlfe[0].label_out);
cf9b9f77 2188 itf = if_lookup_by_index(srl->nhlfe[0].ifindex, VRF_DEFAULT);
7743f2f8 2189 vty_out(vty, "%15s/%u %8u %9s %21s %9s %15s\n", pref,
cf9b9f77
OD
2190 srl->nhlfe[0].prefv4.prefixlen, srl->nhlfe[0].label_in,
2191 label, sid, itf ? itf->name : "-",
2192 inet_ntoa(srl->nhlfe[0].nexthop));
7743f2f8 2193 snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[1]);
70e98a7f 2194 if (srl->nhlfe[1].label_out == MPLS_LABEL_IMPLICIT_NULL)
cf9b9f77
OD
2195 sprintf(label, "pop");
2196 else
7743f2f8
OD
2197 sprintf(label, "%u", srl->nhlfe[0].label_out);
2198 vty_out(vty, "%15s/%u %8u %9s %21s %9s %15s\n", pref,
cf9b9f77
OD
2199 srl->nhlfe[1].prefv4.prefixlen, srl->nhlfe[1].label_in,
2200 label, sid, itf ? itf->name : "-",
2201 inet_ntoa(srl->nhlfe[1].nexthop));
2202 }
2203 vty_out(vty, "\n");
2204}
2205
2206static void show_srdb_entry(struct hash_backet *backet, void *args)
2207{
2208 struct vty *vty = (struct vty *)args;
2209 struct sr_node *srn = (struct sr_node *)backet->data;
2210
2211 show_vty_sr_node(vty, srn);
2212}
2213
2214DEFUN (show_ip_opsf_srdb,
2215 show_ip_ospf_srdb_cmd,
2216 "show ip ospf database segment-routing [adv-router A.B.C.D|self-originate]",
2217 SHOW_STR
2218 IP_STR
2219 OSPF_STR
2220 "Database summary\n"
2221 "Show Segment Routing Data Base\n"
2222 "Advertising SR node\n"
2223 "Advertising SR node ID (as an IP address)\n"
2224 "Self-originated SR node\n")
2225{
7743f2f8 2226 int idx = 0;
cf9b9f77
OD
2227 struct in_addr rid;
2228 struct sr_node *srn;
2229
2230 if (!OspfSR.enabled) {
2231 vty_out(vty, "Segment Routing is disabled on this router\n");
7726c479 2232 return CMD_WARNING;
cf9b9f77
OD
2233 }
2234
2235 vty_out(vty, "\n OSPF Segment Routing database for ID %s\n\n",
2236 inet_ntoa(OspfSR.self->adv_router));
2237
7743f2f8
OD
2238 if (argv_find(argv, argc, "self-originate", &idx)) {
2239 srn = OspfSR.self;
2240 show_vty_sr_node(vty, srn);
2241 return CMD_SUCCESS;
2242 }
2243
2244 if (argv_find(argv, argc, "A.B.C.D", &idx)) {
2245 if (!inet_aton(argv[idx]->arg, &rid)) {
2246 vty_out(vty,
2247 "Specified Router ID %s is invalid\n",
2248 argv[idx]->arg);
2249 return CMD_WARNING_CONFIG_FAILED;
cf9b9f77 2250 }
7743f2f8
OD
2251 /* Get the SR Node from the SRDB */
2252 srn = (struct sr_node *)hash_lookup(OspfSR.neighbors,
2253 (void *)&rid);
cf9b9f77 2254 show_vty_sr_node(vty, srn);
7743f2f8 2255 return CMD_SUCCESS;
cf9b9f77 2256 }
7743f2f8
OD
2257
2258 /* No parameters have been provided, Iterate through all the SRDB */
2259 hash_iterate(
2260 OspfSR.neighbors,
2261 (void (*)(struct hash_backet *, void *))show_srdb_entry,
2262 (void *)vty);
cf9b9f77
OD
2263 return CMD_SUCCESS;
2264}
2265
2266/* Install new CLI commands */
2267void ospf_sr_register_vty(void)
2268{
2269 install_element(VIEW_NODE, &show_ip_ospf_srdb_cmd);
2270
2271 install_element(OSPF_NODE, &ospf_sr_enable_cmd);
2272 install_element(OSPF_NODE, &no_ospf_sr_enable_cmd);
2273 install_element(OSPF_NODE, &sr_sid_label_range_cmd);
2274 install_element(OSPF_NODE, &no_sr_sid_label_range_cmd);
2275 install_element(OSPF_NODE, &sr_node_msd_cmd);
2276 install_element(OSPF_NODE, &no_sr_node_msd_cmd);
2277 install_element(OSPF_NODE, &sr_prefix_sid_cmd);
2278 install_element(OSPF_NODE, &no_sr_prefix_sid_cmd);
2279
cf9b9f77 2280}