]> git.proxmox.com Git - mirror_frr.git/blame - ospfd/ospf_ext.c
tools, doc: update checkpatch for u_int_*
[mirror_frr.git] / ospfd / ospf_ext.c
CommitLineData
cf9b9f77
OD
1/*
2 * This is an implementation of RFC7684 OSPFv2 Prefix/Link Attribute
3 * Advertisement
4 *
5 * Module name: Extended Prefix/Link Opaque LSA
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 <zebra.h>
28#include <math.h>
29#include <stdio.h>
30#include <stdlib.h>
31
32#include "linklist.h"
33#include "prefix.h"
34#include "if.h"
35#include "table.h"
36#include "memory.h"
37#include "command.h"
38#include "vty.h"
39#include "stream.h"
40#include "log.h"
41#include "thread.h"
42#include "hash.h"
43#include "sockunion.h" /* for inet_aton() */
44#include "network.h"
45#include "if.h"
46#include "libospf.h" /* for ospf interface types */
47
48#include "ospfd/ospfd.h"
49#include "ospfd/ospf_interface.h"
50#include "ospfd/ospf_ism.h"
51#include "ospfd/ospf_asbr.h"
52#include "ospfd/ospf_lsa.h"
53#include "ospfd/ospf_lsdb.h"
54#include "ospfd/ospf_neighbor.h"
55#include "ospfd/ospf_nsm.h"
56#include "ospfd/ospf_flood.h"
57#include "ospfd/ospf_packet.h"
58#include "ospfd/ospf_spf.h"
59#include "ospfd/ospf_dump.h"
60#include "ospfd/ospf_route.h"
61#include "ospfd/ospf_ase.h"
62#include "ospfd/ospf_zebra.h"
63#include "ospfd/ospf_sr.h"
64#include "ospfd/ospf_ext.h"
65
66/* Following structure are internal use only. */
67
68/*
69 * Global variable to manage Extended Prefix/Link Opaque LSA on this node.
70 * Note that all parameter values are stored in network byte order.
71 */
72static struct ospf_ext_lp OspfEXT;
73
7743f2f8
OD
74/*
75 * -----------------------------------------------------------------------
76 * Followings are initialize/terminate functions for Extended Prefix/Link
77 * Opaque LSA handling.
78 * -----------------------------------------------------------------------
79 */
cf9b9f77
OD
80
81/* Extended Prefix Opaque LSA related callback functions */
7743f2f8 82static void ospf_ext_pref_ism_change(struct ospf_interface *oi, int old_status);
cf9b9f77
OD
83static void ospf_ext_pref_show_info(struct vty *vty, struct ospf_lsa *lsa);
84static int ospf_ext_pref_lsa_originate(void *arg);
85static struct ospf_lsa *ospf_ext_pref_lsa_refresh(struct ospf_lsa *lsa);
86static void ospf_ext_pref_lsa_schedule(struct ext_itf *exti,
87 enum lsa_opcode opcode);
88/* Extended Link Opaque LSA related callback functions */
89static int ospf_ext_link_new_if(struct interface *ifp);
90static int ospf_ext_link_del_if(struct interface *ifp);
91static void ospf_ext_link_ism_change(struct ospf_interface *oi, int old_status);
92static void ospf_ext_link_nsm_change(struct ospf_neighbor *nbr, int old_status);
93static void ospf_ext_link_show_info(struct vty *vty, struct ospf_lsa *lsa);
94static int ospf_ext_link_lsa_originate(void *arg);
95static struct ospf_lsa *ospf_ext_link_lsa_refresh(struct ospf_lsa *lsa);
96static void ospf_ext_link_lsa_schedule(struct ext_itf *exti,
97 enum lsa_opcode opcode);
98static void ospf_ext_lsa_schedule(struct ext_itf *exti, enum lsa_opcode op);
99static int ospf_ext_link_lsa_update(struct ospf_lsa *lsa);
100static int ospf_ext_pref_lsa_update(struct ospf_lsa *lsa);
101static void del_ext_info(void *val);
102
103/*
104 * Extended Link/Prefix initialization
105 *
106 * @param - none
107 *
108 * @return - 0 if OK, <> 0 otherwise
109 */
110int ospf_ext_init(void)
111{
112 int rc = 0;
113
114 memset(&OspfEXT, 0, sizeof(struct ospf_ext_lp));
115 OspfEXT.enabled = false;
116 /* Only Area flooding is supported yet */
117 OspfEXT.scope = OSPF_OPAQUE_AREA_LSA;
118 /* Initialize interface list */
119 OspfEXT.iflist = list_new();
120 OspfEXT.iflist->del = del_ext_info;
121
7743f2f8 122 zlog_info("EXT (%s): Register Extended Link Opaque LSA", __func__);
cf9b9f77
OD
123 rc = ospf_register_opaque_functab(
124 OSPF_OPAQUE_AREA_LSA, OPAQUE_TYPE_EXTENDED_LINK_LSA,
996c9314
LB
125 ospf_ext_link_new_if, /* new if */
126 ospf_ext_link_del_if, /* del if */
cf9b9f77
OD
127 ospf_ext_link_ism_change, /* ism change */
128 ospf_ext_link_nsm_change, /* nsm change */
129 NULL, /* Write router config. */
130 NULL, /* Write interface conf. */
131 NULL, /* Write debug config. */
132 ospf_ext_link_show_info, /* Show LSA info */
133 ospf_ext_link_lsa_originate, /* Originate LSA */
134 ospf_ext_link_lsa_refresh, /* Refresh LSA */
135 ospf_ext_link_lsa_update, /* new_lsa_hook */
136 NULL); /* del_lsa_hook */
137
138 if (rc != 0) {
7743f2f8
OD
139 zlog_warn("EXT (%s): Failed to register Extended Link LSA",
140 __func__);
cf9b9f77
OD
141 return rc;
142 }
143
7743f2f8 144 zlog_info("EXT (%s): Register Extended Prefix Opaque LSA", __func__);
cf9b9f77
OD
145 rc = ospf_register_opaque_functab(
146 OspfEXT.scope, OPAQUE_TYPE_EXTENDED_PREFIX_LSA,
7743f2f8
OD
147 NULL, /* new if handle by link */
148 NULL, /* del if handle by link */
149 ospf_ext_pref_ism_change, /* ism change */
cf9b9f77
OD
150 NULL, /* nsm change */
151 ospf_sr_config_write_router, /* Write router config. */
152 NULL, /* Write interface conf. */
153 NULL, /* Write debug config. */
154 ospf_ext_pref_show_info, /* Show LSA info */
155 ospf_ext_pref_lsa_originate, /* Originate LSA */
156 ospf_ext_pref_lsa_refresh, /* Refresh LSA */
157 ospf_ext_pref_lsa_update, /* new_lsa_hook */
158 NULL); /* del_lsa_hook */
159 if (rc != 0) {
7743f2f8
OD
160 zlog_warn("EXT (%s): Failed to register Extended Prefix LSA",
161 __func__);
cf9b9f77
OD
162 return rc;
163 }
164
165 return rc;
166}
167
168/*
169 * Extended Link/Prefix termination function
170 *
bcf4475e 171 * @param - none
cf9b9f77
OD
172 * @return - none
173 */
174void ospf_ext_term(void)
175{
176
bcf4475e 177 if ((OspfEXT.scope != OSPF_OPAQUE_AREA_LSA)
9b50aa1f 178 && (OspfEXT.scope != OSPF_OPAQUE_AS_LSA))
bcf4475e
OD
179 zlog_warn(
180 "EXT: Unable to unregister Extended Prefix "
181 "Opaque LSA functions: Wrong scope!");
182 else
183 ospf_delete_opaque_functab(OspfEXT.scope,
184 OPAQUE_TYPE_EXTENDED_PREFIX_LSA);
185
186 ospf_delete_opaque_functab(OSPF_OPAQUE_AREA_LSA,
187 OPAQUE_TYPE_EXTENDED_LINK_LSA);
188
cf9b9f77
OD
189 list_delete_and_null(&OspfEXT.iflist);
190 OspfEXT.scope = 0;
191 OspfEXT.enabled = false;
192
bcf4475e
OD
193 return;
194}
195
196/*
197 * Extended Link/Prefix finish function
198 *
199 * @param - none
200 * @return - none
201 */
202void ospf_ext_finish(void)
203{
204 // list_delete_all_node(OspfEXT.iflist);
205 OspfEXT.enabled = false;
cf9b9f77
OD
206}
207
7743f2f8
OD
208/*
209 * ---------------------------------------------------------------------
cf9b9f77
OD
210 * Followings are control functions for Extended Prefix/Link Opaque LSA
211 * parameters management.
7743f2f8
OD
212 * ---------------------------------------------------------------------
213 */
214
cf9b9f77
OD
215/* Functions to free memory space */
216static void del_ext_info(void *val)
217{
218 XFREE(MTYPE_OSPF_EXT_PARAMS, val);
cf9b9f77
OD
219}
220
221/* Increment instance value for Extended Prefix Opaque LSAs Opaque ID field */
93f0a26e 222static uint32_t get_ext_pref_instance_value(void)
cf9b9f77 223{
93f0a26e 224 static uint32_t seqno = 0;
cf9b9f77
OD
225
226 if (seqno < MAX_LEGAL_EXT_INSTANCE_NUM)
227 seqno += 1;
228 else
229 seqno = 1; /* Avoid zero. */
230
231 return seqno;
232}
233
234/* Increment instance value for Extended Link Opaque LSAs Opaque ID field */
93f0a26e 235static uint32_t get_ext_link_instance_value(void)
cf9b9f77 236{
93f0a26e 237 static uint32_t seqno = 0;
cf9b9f77
OD
238
239 if (seqno < MAX_LEGAL_EXT_INSTANCE_NUM)
240 seqno += 1;
241 else
242 seqno = 1; /* Avoid zero. */
243
244 return seqno;
245}
246
247/* Lookup Extended Prefix/Links by ifp from OspfEXT struct iflist */
248static struct ext_itf *lookup_ext_by_ifp(struct interface *ifp)
249{
250 struct listnode *node, *nnode;
251 struct ext_itf *exti;
252
253 for (ALL_LIST_ELEMENTS(OspfEXT.iflist, node, nnode, exti))
254 if (exti->ifp == ifp)
255 return exti;
256
257 return NULL;
258}
259
260/* Lookup Extended Prefix/Links by LSA ID from OspfEXT struct iflist */
261static struct ext_itf *lookup_ext_by_instance(struct ospf_lsa *lsa)
262{
263 struct listnode *node;
264 struct ext_itf *exti;
db28a51f
OD
265 uint32_t key = GET_OPAQUE_ID(ntohl(lsa->data->id.s_addr));
266 uint8_t type = GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr));
267
cf9b9f77
OD
268
269 for (ALL_LIST_ELEMENTS_RO(OspfEXT.iflist, node, exti))
db28a51f 270 if ((exti->instance == key) && (exti->type == type))
cf9b9f77
OD
271 return exti;
272
cf9b9f77
OD
273 return NULL;
274}
275
7743f2f8
OD
276/*
277 * ----------------------------------------------------------------------
cf9b9f77
OD
278 * The underlying subsection defines setters and unsetters to create and
279 * delete tlvs and subtlvs
7743f2f8
OD
280 * ----------------------------------------------------------------------
281 */
cf9b9f77
OD
282
283/* Extended Prefix TLV - RFC7684 section 2.1 */
93f0a26e
OD
284static void set_ext_prefix(struct ext_itf *exti, uint8_t route_type,
285 uint8_t flags, struct prefix_ipv4 p)
cf9b9f77
OD
286{
287
288 TLV_TYPE(exti->prefix) = htons(EXT_TLV_PREFIX);
289 /* Warning: Size must be adjust depending of subTLV's */
290 TLV_LEN(exti->prefix) = htons(EXT_TLV_PREFIX_SIZE);
291 exti->prefix.route_type = route_type;
292 exti->prefix.flags = flags;
293 /* Only Address Family Ipv4 (0) is defined in RFC 7684 */
294 exti->prefix.af = 0;
295 exti->prefix.pref_length = p.prefixlen;
296 exti->prefix.address = p.prefix;
297}
298
299/* Extended Link TLV - RFC7684 section 3.1 */
93f0a26e 300static void set_ext_link(struct ext_itf *exti, uint8_t type, struct in_addr id,
cf9b9f77
OD
301 struct in_addr data)
302{
303
304 TLV_TYPE(exti->link) = htons(EXT_TLV_LINK);
305 /* Warning: Size must be adjust depending of subTLV's */
306 TLV_LEN(exti->link) = htons(EXT_TLV_LINK_SIZE);
307 exti->link.link_type = type;
308 exti->link.link_id = id;
309 exti->link.link_data = data;
310}
311
312/* Prefix SID SubTLV - section 5 */
93f0a26e 313static void set_prefix_sid(struct ext_itf *exti, uint8_t algorithm,
7743f2f8 314 uint32_t value, int value_type, uint8_t flags)
cf9b9f77
OD
315{
316
cf9b9f77
OD
317 if ((algorithm != SR_ALGORITHM_SPF)
318 && (algorithm != SR_ALGORITHM_STRICT_SPF)) {
996c9314
LB
319 zlog_warn("EXT (%s): unrecognized algorithm, not SPF or S-SPF",
320 __func__);
cf9b9f77
OD
321 return;
322 }
323
7743f2f8 324 /* Update flags according to the type of value field: label or index */
cf9b9f77 325 if (value_type == SID_LABEL)
7743f2f8 326 SET_FLAG(flags, EXT_SUBTLV_PREFIX_SID_VFLG);
cf9b9f77
OD
327
328 /* set prefix sid subtlv for an extended prefix tlv */
329 TLV_TYPE(exti->node_sid) = htons(EXT_SUBTLV_PREFIX_SID);
330 exti->node_sid.algorithm = algorithm;
331 exti->node_sid.flags = flags;
332 exti->node_sid.mtid = 0; /* Multi-Topology is not supported */
333
334 /* Set Label or Index value */
335 if (value_type == SID_LABEL) {
d922605d
OD
336 TLV_LEN(exti->node_sid) =
337 htons(SID_LABEL_SIZE(EXT_SUBTLV_PREFIX_SID_SIZE));
cf9b9f77
OD
338 exti->node_sid.value = htonl(SET_LABEL(value));
339 } else {
d922605d
OD
340 TLV_LEN(exti->node_sid) =
341 htons(SID_INDEX_SIZE(EXT_SUBTLV_PREFIX_SID_SIZE));
cf9b9f77
OD
342 exti->node_sid.value = htonl(value);
343 }
cf9b9f77
OD
344}
345
346/* Adjacency SID SubTLV - section 6.1 */
93f0a26e 347static void set_adj_sid(struct ext_itf *exti, bool backup, uint32_t value,
cf9b9f77
OD
348 int value_type)
349{
350 int index;
93f0a26e 351 uint8_t flags;
cf9b9f77
OD
352
353 /* Determine which ADJ_SID must be set: nominal or backup */
354 if (backup) {
355 flags = EXT_SUBTLV_LINK_ADJ_SID_BFLG;
356 index = 1;
357 } else {
358 index = 0;
359 flags = 0;
360 }
361
362 /* Set Header */
363 TLV_TYPE(exti->adj_sid[index]) = htons(EXT_SUBTLV_ADJ_SID);
364
365 /* Only Local ADJ-SID is supported for the moment */
366 SET_FLAG(flags, EXT_SUBTLV_LINK_ADJ_SID_LFLG);
367
368 exti->adj_sid[index].mtid = 0; /* Multi-Topology is not supported */
369
370 /* Adjust Length, Flags and Value depending on the type of Label */
371 if (value_type == SID_LABEL) {
372 SET_FLAG(flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG);
d922605d
OD
373 TLV_LEN(exti->adj_sid[index]) =
374 htons(SID_LABEL_SIZE(EXT_SUBTLV_ADJ_SID_SIZE));
cf9b9f77
OD
375 exti->adj_sid[index].value = htonl(SET_LABEL(value));
376 } else {
377 UNSET_FLAG(flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG);
d922605d
OD
378 TLV_LEN(exti->adj_sid[index]) =
379 htons(SID_INDEX_SIZE(EXT_SUBTLV_ADJ_SID_SIZE));
cf9b9f77
OD
380 exti->adj_sid[index].value = htonl(value);
381 }
382
383 exti->adj_sid[index].flags = flags; /* Set computed flags */
384 exti->adj_sid[index].mtid = 0; /* Multi-Topology is not supported */
385 exti->adj_sid[index].weight = 0; /* Load-Balancing is not supported */
cf9b9f77
OD
386}
387
388/* LAN Adjacency SID SubTLV - section 6.2 */
93f0a26e 389static void set_lan_adj_sid(struct ext_itf *exti, bool backup, uint32_t value,
cf9b9f77
OD
390 int value_type, struct in_addr neighbor_id)
391{
392
393 int index;
93f0a26e 394 uint8_t flags;
cf9b9f77
OD
395
396 /* Determine which ADJ_SID must be set: nominal or backup */
397 if (backup) {
398 flags = EXT_SUBTLV_LINK_ADJ_SID_BFLG;
399 index = 1;
400 } else {
401 index = 0;
402 flags = 0;
403 }
404
405 /* Set Header */
d922605d 406 TLV_TYPE(exti->lan_sid[index]) = htons(EXT_SUBTLV_LAN_ADJ_SID);
cf9b9f77
OD
407
408 /* Only Local ADJ-SID is supported for the moment */
409 SET_FLAG(flags, EXT_SUBTLV_LINK_ADJ_SID_LFLG);
410
411 /* Adjust Length, Flags and Value depending on the type of Label */
412 if (value_type == SID_LABEL) {
413 SET_FLAG(flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG);
d922605d
OD
414 TLV_LEN(exti->lan_sid[index]) =
415 htons(SID_LABEL_SIZE(EXT_SUBTLV_PREFIX_RANGE_SIZE));
cf9b9f77
OD
416 exti->lan_sid[index].value = htonl(SET_LABEL(value));
417 } else {
418 UNSET_FLAG(flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG);
d922605d
OD
419 TLV_LEN(exti->lan_sid[index]) =
420 htons(SID_INDEX_SIZE(EXT_SUBTLV_PREFIX_RANGE_SIZE));
cf9b9f77
OD
421 exti->lan_sid[index].value = htonl(value);
422 }
423
424 exti->lan_sid[index].flags = flags; /* Set computed flags */
425 exti->lan_sid[index].mtid = 0; /* Multi-Topology is not supported */
426 exti->lan_sid[index].weight = 0; /* Load-Balancing is not supported */
427 exti->lan_sid[index].neighbor_id = neighbor_id;
cf9b9f77
OD
428}
429
430/* Experimental SubTLV from Cisco */
431static void set_rmt_itf_addr(struct ext_itf *exti, struct in_addr rmtif)
432{
433
434 TLV_TYPE(exti->rmt_itf_addr) = htons(EXT_SUBTLV_RMT_ITF_ADDR);
435 TLV_LEN(exti->rmt_itf_addr) = htons(sizeof(struct in_addr));
436 exti->rmt_itf_addr.value = rmtif;
cf9b9f77
OD
437}
438
439/*
440 * Update Extended prefix SID index for Loopback interface type
441 *
442 * @param ifname - Loopback interface name
443 * @param index - new value for the prefix SID of this interface
444 * @param p - prefix for this interface or NULL if Extended Prefix
445 * should be remove
446 *
447 * @return instance number if update is OK, 0 otherwise
448 */
db28a51f 449uint32_t ospf_ext_schedule_prefix_index(struct interface *ifp, uint32_t index,
996c9314 450 struct prefix_ipv4 *p, uint8_t flags)
cf9b9f77
OD
451{
452 int rc = 0;
453 struct ext_itf *exti;
454
455 /* Find Extended Prefix interface */
456 exti = lookup_ext_by_ifp(ifp);
457 if (exti == NULL)
458 return rc;
459
460 if (p != NULL) {
461 if (IS_DEBUG_OSPF_SR)
462 zlog_debug(
7743f2f8
OD
463 "EXT (%s): Schedule new prefix %s/%u with "
464 "index %u on interface %s",
465 __func__, inet_ntoa(p->prefix), p->prefixlen,
466 index, ifp->name);
cf9b9f77
OD
467
468 /* Set first Extended Prefix then the Prefix SID information */
469 set_ext_prefix(exti, OSPF_PATH_INTRA_AREA, EXT_TLV_PREF_NFLG,
470 *p);
7743f2f8 471 set_prefix_sid(exti, SR_ALGORITHM_SPF, index, SID_INDEX, flags);
cf9b9f77
OD
472
473 /* Try to Schedule LSA */
474 SET_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE);
475 if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED))
476 ospf_ext_pref_lsa_schedule(exti, REFRESH_THIS_LSA);
477 else
478 ospf_ext_pref_lsa_schedule(exti, REORIGINATE_THIS_LSA);
479 } else {
480 if (IS_DEBUG_OSPF_SR)
996c9314
LB
481 zlog_debug("EXT (%s): Remove prefix for interface %s",
482 __func__, ifp->name);
cf9b9f77
OD
483
484 if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED)) {
485 ospf_ext_pref_lsa_schedule(exti, FLUSH_THIS_LSA);
486 UNSET_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED);
487 UNSET_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE);
488 }
489 }
490
db28a51f 491 return SET_OPAQUE_LSID(exti->type, exti->instance);
cf9b9f77
OD
492}
493
494/*
495 * Used by Segment Routing to activate/deactivate Extended Link/Prefix flooding
496 *
497 * @param enable To activate or not Segment Routing Extended LSA flooding
498 *
499 * @return none
500 */
501void ospf_ext_update_sr(bool enable)
502{
503 struct listnode *node;
504 struct ext_itf *exti;
505
506 if (IS_DEBUG_OSPF_SR)
996c9314
LB
507 zlog_debug("EXT (%s): %s Extended LSAs for Segment Routing ",
508 __func__, enable ? "Enable" : "Disable");
cf9b9f77
OD
509
510 if (enable) {
511 OspfEXT.enabled = true;
512 /* Refresh LSAs if already engaged or originate */
513 for (ALL_LIST_ELEMENTS_RO(OspfEXT.iflist, node, exti))
514 if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED))
515 ospf_ext_lsa_schedule(exti, REFRESH_THIS_LSA);
516 else
517 ospf_ext_lsa_schedule(exti,
518 REORIGINATE_THIS_LSA);
519 } else {
520 /* Start by Flushing engaged LSAs */
521 for (ALL_LIST_ELEMENTS_RO(OspfEXT.iflist, node, exti))
522 if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED))
523 ospf_ext_lsa_schedule(exti, FLUSH_THIS_LSA);
524 /* And then disable Extended Link/Prefix */
525 OspfEXT.enabled = false;
526 }
527}
7743f2f8
OD
528/*
529 * -----------------------------------------------------------------------
530 * Followings are callback functions against generic Opaque-LSAs handling
531 * -----------------------------------------------------------------------
532 */
cf9b9f77
OD
533
534/* Add new Interface in Extended Interface List */
535static int ospf_ext_link_new_if(struct interface *ifp)
536{
537 struct ext_itf *new;
538 int rc = -1;
539
540 if (lookup_ext_by_ifp(ifp) != NULL) {
996c9314
LB
541 zlog_warn("EXT (%s): interface %s is already in use", __func__,
542 ifp ? ifp->name : "-");
cf9b9f77
OD
543 rc = 0; /* Do nothing here. */
544 return rc;
545 }
546
547 new = XCALLOC(MTYPE_OSPF_EXT_PARAMS, sizeof(struct ext_itf));
548 if (new == NULL) {
7743f2f8
OD
549 zlog_warn("EXT (%s): XCALLOC: %s", __func__,
550 safe_strerror(errno));
cf9b9f77
OD
551 return rc;
552 }
553
554 /* initialize new information and link back the interface */
555 new->ifp = ifp;
556 new->flags = EXT_LPFLG_LSA_INACTIVE;
557
558 listnode_add(OspfEXT.iflist, new);
559
560 rc = 0;
561 return rc;
562}
563
564/* Remove existing Interface from Extended Interface List */
565static int ospf_ext_link_del_if(struct interface *ifp)
566{
567 struct ext_itf *exti;
568 int rc = -1;
569
7743f2f8
OD
570 exti = lookup_ext_by_ifp(ifp);
571 if (exti != NULL) {
cf9b9f77
OD
572 struct list *iflist = OspfEXT.iflist;
573
cf9b9f77
OD
574 /* Dequeue listnode entry from the list. */
575 listnode_delete(iflist, exti);
576
cf9b9f77
OD
577 XFREE(MTYPE_OSPF_EXT_PARAMS, exti);
578
579 rc = 0;
580 } else {
996c9314
LB
581 zlog_warn("EXT (%s): interface %s is not found", __func__,
582 ifp ? ifp->name : "-");
cf9b9f77
OD
583 }
584
585 return rc;
586}
587
7743f2f8
OD
588/*
589 * Determine if an Interface belongs to an Extended Link Adjacency or LAN Adj.
590 * type and allocate new instance value accordingly
591 */
592static void ospf_ext_link_ism_change(struct ospf_interface *oi, int old_status)
cf9b9f77
OD
593{
594 struct ext_itf *exti;
cf9b9f77 595
7743f2f8
OD
596 /* Get interface information for Segment Routing */
597 exti = lookup_ext_by_ifp(oi->ifp);
598 if (exti == NULL) {
996c9314
LB
599 zlog_warn("EXT (%s): Cannot get Extended info. from OI(%s)",
600 __func__, IF_NAME(oi));
7743f2f8
OD
601 return;
602 }
cf9b9f77 603
7743f2f8
OD
604 /* Determine if interface is related to Adjacency or LAN Adj. SID */
605 if (oi->type != OSPF_IFTYPE_LOOPBACK) {
606 if (oi->state == ISM_DR)
607 exti->stype = LAN_ADJ_SID;
608 else
609 exti->stype = ADJ_SID;
cf9b9f77 610
7743f2f8 611 exti->instance = get_ext_link_instance_value();
db28a51f 612 exti->type = OPAQUE_TYPE_EXTENDED_LINK_LSA;
cf9b9f77 613
996c9314
LB
614 zlog_debug("EXT (%s): Set %s SID to interface %s ", __func__,
615 exti->stype == ADJ_SID ? "Adj." : "LAN Adj.",
616 oi->ifp->name);
cf9b9f77 617 }
cf9b9f77
OD
618}
619
620/*
7743f2f8 621 * Determine if an Interface belongs to an Extended Prefix and
cf9b9f77
OD
622 * allocate new instance value accordingly
623 */
7743f2f8 624static void ospf_ext_pref_ism_change(struct ospf_interface *oi, int old_status)
cf9b9f77
OD
625{
626 struct ext_itf *exti;
627
628 /* Get interface information for Segment Routing */
7743f2f8
OD
629 exti = lookup_ext_by_ifp(oi->ifp);
630 if (exti == NULL) {
996c9314
LB
631 zlog_warn("EXT (%s): Cannot get Extended info. from OI(%s)",
632 __func__, IF_NAME(oi));
cf9b9f77
OD
633 return;
634 }
635
7743f2f8 636 /* Determine if interface is related to a Node SID */
cf9b9f77
OD
637 if (oi->type == OSPF_IFTYPE_LOOPBACK) {
638 exti->stype = PREF_SID;
639 exti->instance = get_ext_pref_instance_value();
db28a51f 640 exti->type = OPAQUE_TYPE_EXTENDED_PREFIX_LSA;
7743f2f8 641
996c9314
LB
642 zlog_debug("EXT (%s): Set Node SID to interface %s ", __func__,
643 oi->ifp->name);
7743f2f8
OD
644
645 /* Complete SRDB if the interface belongs to a Prefix */
62c99790
OD
646 if (OspfEXT.enabled)
647 ospf_sr_update_prefix(oi->ifp, oi->address);
cf9b9f77 648 }
cf9b9f77
OD
649}
650
651/*
652 * Finish Extended Link configuration and flood corresponding LSA
653 * when OSPF adjacency on this link fire up
654 */
655static void ospf_ext_link_nsm_change(struct ospf_neighbor *nbr, int old_status)
656{
657 struct ospf_interface *oi = nbr->oi;
658 struct ext_itf *exti;
93f0a26e 659 uint32_t label;
cf9b9f77
OD
660
661 /* Process Neighbor only when its state is NSM Full */
662 if (nbr->state != NSM_Full)
663 return;
664
665 /* Get interface information for Segment Routing */
7743f2f8
OD
666 exti = lookup_ext_by_ifp(oi->ifp);
667 if (exti == NULL) {
996c9314
LB
668 zlog_warn("EXT (%s): Cannot get Extended info. from OI(%s)",
669 __func__, IF_NAME(oi));
cf9b9f77
OD
670 return;
671 }
672
673 if (oi->area == NULL || oi->area->ospf == NULL) {
996c9314
LB
674 zlog_warn("EXT (%s): Cannot refer to OSPF from OI(%s)",
675 __func__, IF_NAME(oi));
cf9b9f77
OD
676 return;
677 }
678
679 /* Keep Area information in combination with SR info. */
680 exti->area = oi->area;
681 OspfEXT.area = oi->area;
682
683 /* Process only Adjacency/LAN SID */
684 if (exti->stype == PREF_SID)
685 return;
686
687 switch (oi->state) {
688 case ISM_PointToPoint:
689 /* Segment ID is an Adjacency one */
690 exti->stype = ADJ_SID;
691
692 /* Set Extended Link TLV with link_id == Nbr Router ID */
693 set_ext_link(exti, OSPF_IFTYPE_POINTOPOINT, nbr->router_id,
694 oi->address->u.prefix4);
695
696 /* Set Extended Link Adjacency SubTLVs, backup first */
697 label = get_ext_link_label_value();
698 set_adj_sid(exti, true, label, SID_LABEL);
699 label = get_ext_link_label_value();
700 set_adj_sid(exti, false, label, SID_LABEL);
701 /* And Remote Interface address */
702 set_rmt_itf_addr(exti, nbr->address.u.prefix4);
703
704 break;
705
706 case ISM_DR:
707 /* Segment ID is a LAN Adjacency for the DR only */
708 exti->stype = LAN_ADJ_SID;
709
710 /* Set Extended Link TLV with link_id == DR */
711 set_ext_link(exti, OSPF_IFTYPE_BROADCAST, DR(oi),
712 oi->address->u.prefix4);
713
714 /* Set Extended Link Adjacency SubTLVs, backup first */
715 label = get_ext_link_label_value();
716 set_lan_adj_sid(exti, true, label, SID_LABEL, nbr->router_id);
717 label = get_ext_link_label_value();
718 set_lan_adj_sid(exti, false, label, SID_LABEL, nbr->router_id);
719
720 break;
721
722 case ISM_DROther:
723 case ISM_Backup:
724 /* Segment ID is an Adjacency if not the DR */
725 exti->stype = ADJ_SID;
726
727 /* Set Extended Link TLV with link_id == DR */
728 set_ext_link(exti, OSPF_IFTYPE_BROADCAST, DR(oi),
729 oi->address->u.prefix4);
730
731 /* Set Extended Link Adjacency SubTLVs, backup first */
732 label = get_ext_link_label_value();
733 set_adj_sid(exti, true, label, SID_LABEL);
734 label = get_ext_link_label_value();
735 set_adj_sid(exti, false, label, SID_LABEL);
736
737 break;
738
739 default:
740 if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED)) {
741 ospf_ext_link_lsa_schedule(exti, FLUSH_THIS_LSA);
742 UNSET_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED);
743 UNSET_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE);
744 }
745 return;
746 }
747
7743f2f8 748 if (IS_DEBUG_OSPF_SR)
996c9314
LB
749 zlog_debug("EXT (%s): Complete %s SID to interface %s ",
750 __func__,
751 exti->stype == ADJ_SID ? "Adj." : "LAN Adj.",
752 oi->ifp->name);
7743f2f8 753
cf9b9f77
OD
754 /* flood this links params if everything is ok */
755 SET_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE);
756 if (OspfEXT.enabled) {
757 if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED))
758 ospf_ext_link_lsa_schedule(exti, REFRESH_THIS_LSA);
759 else
760 ospf_ext_link_lsa_schedule(exti, REORIGINATE_THIS_LSA);
761 }
cf9b9f77
OD
762}
763
764/* Callbacks to handle Extended Link Segment Routing LSA information */
765static int ospf_ext_link_lsa_update(struct ospf_lsa *lsa)
766{
767 /* Sanity Check */
768 if (lsa == NULL) {
7743f2f8 769 zlog_warn("EXT (%s): Abort! LSA is NULL", __func__);
cf9b9f77
OD
770 return -1;
771 }
772
6aaf0fdd
OD
773 /* Process only Opaque LSA */
774 if ((lsa->data->type != OSPF_OPAQUE_AREA_LSA)
775 && (lsa->data->type != OSPF_OPAQUE_AS_LSA))
776 return 0;
777
cf9b9f77
OD
778 /* Process only Extended Link LSA */
779 if (GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr))
780 != OPAQUE_TYPE_EXTENDED_LINK_LSA)
781 return 0;
782
783 /* Check if Extended is enable */
784 if (!OspfEXT.enabled)
785 return 0;
786
787 /* Call Segment Routing LSA update or deletion */
788 if (!IS_LSA_MAXAGE(lsa))
789 ospf_sr_ext_link_lsa_update(lsa);
790 else
791 ospf_sr_ext_link_lsa_delete(lsa);
792
793 return 0;
794}
795
796/* Callbacks to handle Extended Prefix Segment Routing LSA information */
797static int ospf_ext_pref_lsa_update(struct ospf_lsa *lsa)
798{
799
800 /* Sanity Check */
801 if (lsa == NULL) {
7743f2f8 802 zlog_warn("EXT (%s): Abort! LSA is NULL", __func__);
cf9b9f77
OD
803 return -1;
804 }
805
6aaf0fdd
OD
806 /* Process only Opaque LSA */
807 if ((lsa->data->type != OSPF_OPAQUE_AREA_LSA)
808 && (lsa->data->type != OSPF_OPAQUE_AS_LSA))
7743f2f8
OD
809 return 0;
810
cf9b9f77
OD
811 /* Process only Extended Prefix LSA */
812 if (GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr))
813 != OPAQUE_TYPE_EXTENDED_PREFIX_LSA)
814 return 0;
815
6aaf0fdd
OD
816 /* Check if it is not my LSA */
817 if (IS_LSA_SELF(lsa))
818 return 0;
819
cf9b9f77
OD
820 /* Check if Extended is enable */
821 if (!OspfEXT.enabled)
822 return 0;
823
824 /* Call Segment Routing LSA update or deletion */
825 if (!IS_LSA_MAXAGE(lsa))
826 ospf_sr_ext_prefix_lsa_update(lsa);
827 else
828 ospf_sr_ext_prefix_lsa_delete(lsa);
829
830 return 0;
831}
832
7743f2f8
OD
833/*
834 * -------------------------------------------------------
cf9b9f77
OD
835 * Followings are OSPF protocol processing functions for
836 * Extended Prefix/Link Opaque LSA
7743f2f8
OD
837 * -------------------------------------------------------
838 */
cf9b9f77
OD
839
840static void build_tlv_header(struct stream *s, struct tlv_header *tlvh)
841{
842 stream_put(s, tlvh, sizeof(struct tlv_header));
cf9b9f77
OD
843}
844
845static void build_tlv(struct stream *s, struct tlv_header *tlvh)
846{
847
848 if ((tlvh != NULL) && (ntohs(tlvh->type) != 0)) {
849 build_tlv_header(s, tlvh);
850 stream_put(s, TLV_DATA(tlvh), TLV_BODY_SIZE(tlvh));
851 }
cf9b9f77
OD
852}
853
854/* Build an Extended Prefix Opaque LSA body for extended prefix TLV */
855static void ospf_ext_pref_lsa_body_set(struct stream *s, struct ext_itf *exti)
856{
857
858 /* Sanity check */
859 if ((exti == NULL) || (exti->stype != PREF_SID))
860 return;
861
862 /* Adjust Extended Prefix TLV size */
996c9314
LB
863 TLV_LEN(exti->prefix) = htons(ntohs(TLV_LEN(exti->node_sid))
864 + EXT_TLV_PREFIX_SIZE + TLV_HDR_SIZE);
cf9b9f77
OD
865
866 /* Build LSA body for an Extended Prefix TLV */
867 build_tlv_header(s, &exti->prefix.header);
868 stream_put(s, TLV_DATA(&exti->prefix.header), EXT_TLV_PREFIX_SIZE);
869 /* Then add Prefix SID SubTLV */
870 build_tlv(s, &exti->node_sid.header);
cf9b9f77
OD
871}
872
873/* Build an Extended Link Opaque LSA body for extended link TLV */
874static void ospf_ext_link_lsa_body_set(struct stream *s, struct ext_itf *exti)
875{
7743f2f8 876 size_t size;
cf9b9f77
OD
877
878 /* Sanity check */
879 if ((exti == NULL)
880 || ((exti->stype != ADJ_SID) && (exti->stype != LAN_ADJ_SID)))
881 return;
882
883 if (exti->stype == ADJ_SID) {
884 /* Adjust Extended Link TLV size for Adj. SID */
7743f2f8 885 size = EXT_TLV_LINK_SIZE + 2 * EXT_SUBTLV_ADJ_SID_SIZE
996c9314 886 + 2 * TLV_HDR_SIZE;
7743f2f8
OD
887 if (ntohs(TLV_TYPE(exti->rmt_itf_addr)) != 0)
888 size = size + EXT_SUBTLV_RMT_ITF_ADDR_SIZE
996c9314 889 + TLV_HDR_SIZE;
7743f2f8 890 TLV_LEN(exti->link) = htons(size);
cf9b9f77
OD
891
892 /* Build LSA body for an Extended Link TLV with Adj. SID */
893 build_tlv_header(s, &exti->link.header);
894 stream_put(s, TLV_DATA(&exti->link.header), EXT_TLV_LINK_SIZE);
d922605d 895 /* then add Adjacency SubTLVs */
cf9b9f77
OD
896 build_tlv(s, &exti->adj_sid[1].header);
897 build_tlv(s, &exti->adj_sid[0].header);
7743f2f8
OD
898
899 /* Add Cisco experimental SubTLV if interface is PtoP */
900 if (ntohs(TLV_TYPE(exti->rmt_itf_addr)) != 0)
901 build_tlv(s, &exti->rmt_itf_addr.header);
cf9b9f77
OD
902 } else {
903 /* Adjust Extended Link TLV size for LAN SID */
7743f2f8 904 size = EXT_TLV_LINK_SIZE
996c9314 905 + 2 * (EXT_SUBTLV_LAN_ADJ_SID_SIZE + TLV_HDR_SIZE);
7743f2f8 906 TLV_LEN(exti->link) = htons(size);
cf9b9f77
OD
907
908 /* Build LSA body for an Extended Link TLV with LAN SID */
909 build_tlv_header(s, &exti->link.header);
d922605d
OD
910 stream_put(s, TLV_DATA(&exti->link.header), EXT_TLV_LINK_SIZE);
911 /* then add LAN-Adjacency SubTLVs */
cf9b9f77
OD
912 build_tlv(s, &exti->lan_sid[1].header);
913 build_tlv(s, &exti->lan_sid[0].header);
914 }
cf9b9f77
OD
915}
916
917/* Create new Extended Prefix opaque-LSA for every extended prefix */
918static struct ospf_lsa *ospf_ext_pref_lsa_new(struct ospf_area *area,
919 struct ext_itf *exti)
920{
921 struct stream *s;
922 struct lsa_header *lsah;
923 struct ospf_lsa *new = NULL;
7743f2f8 924 struct ospf *top;
cf9b9f77
OD
925 u_char options, lsa_type;
926 struct in_addr lsa_id;
927 struct in_addr router_id;
93f0a26e
OD
928 uint32_t tmp;
929 uint16_t length;
cf9b9f77 930
fd3b19f2
OD
931 /* Sanity Check */
932 if (exti == NULL)
933 return NULL;
934
cf9b9f77 935 /* Create a stream for LSA. */
7743f2f8
OD
936 s = stream_new(OSPF_MAX_LSA_SIZE);
937 if (s == NULL) {
938 zlog_warn("EXT (%s): stream_new() error", __func__);
cf9b9f77
OD
939 return NULL;
940 }
941
942 /* Prepare LSA Header */
943 lsah = (struct lsa_header *)STREAM_DATA(s);
944
945 lsa_type = OspfEXT.scope;
946
7743f2f8
OD
947 /*
948 * LSA ID is a variable number identifying different instances of
949 * Extended Prefix Opaque LSA from the same router see RFC 7684
950 */
cf9b9f77
OD
951 tmp = SET_OPAQUE_LSID(OPAQUE_TYPE_EXTENDED_PREFIX_LSA, exti->instance);
952 lsa_id.s_addr = htonl(tmp);
953
954 options = OSPF_OPTION_O; /* Don't forget this :-) */
955
956 /* Fix Options and Router ID depending of the flooding scope */
957 if ((OspfEXT.scope == OSPF_OPAQUE_AS_LSA) || (area == NULL)) {
958 options = OSPF_OPTION_E;
7743f2f8
OD
959 top = ospf_lookup_by_vrf_id(VRF_DEFAULT);
960 router_id.s_addr = top ? top->router_id.s_addr : 0;
cf9b9f77
OD
961 } else {
962 options |= LSA_OPTIONS_GET(area); /* Get area default option */
963 options |= LSA_OPTIONS_NSSA_GET(area);
964 router_id = area->ospf->router_id;
965 }
966
967 /* Set opaque-LSA header fields. */
968 lsa_header_set(s, options, lsa_type, lsa_id, router_id);
969
970 if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
971 zlog_debug(
7743f2f8
OD
972 "EXT (%s): LSA[Type%u:%s]: Create an Opaque-LSA "
973 "Extended Prefix Opaque LSA instance",
974 __func__, lsa_type, inet_ntoa(lsa_id));
cf9b9f77
OD
975
976
977 /* Set opaque-LSA body fields. */
978 ospf_ext_pref_lsa_body_set(s, exti);
979
980 /* Set length. */
981 length = stream_get_endp(s);
982 lsah->length = htons(length);
983
984 /* Now, create an OSPF LSA instance. */
7743f2f8
OD
985 new = ospf_lsa_new();
986 if (new == NULL) {
987 zlog_warn("EXT (%s): ospf_lsa_new() error", __func__);
cf9b9f77
OD
988 stream_free(s);
989 return NULL;
990 }
7743f2f8
OD
991 new->data = ospf_lsa_data_new(length);
992 if (new->data == NULL) {
993 zlog_warn("EXT (%s): ospf_lsa_data_new() error", __func__);
cf9b9f77
OD
994 ospf_lsa_unlock(&new);
995 new = NULL;
996 stream_free(s);
997 return NULL;
998 }
999
7743f2f8
OD
1000 /* Segment Routing belongs only to default VRF */
1001 new->vrf_id = VRF_DEFAULT;
cf9b9f77
OD
1002 new->area = area;
1003 SET_FLAG(new->flags, OSPF_LSA_SELF);
1004 memcpy(new->data, lsah, length);
1005 stream_free(s);
1006
1007 return new;
1008}
1009
1010/* Create new Extended Link opaque-LSA for every extended link TLV */
1011static struct ospf_lsa *ospf_ext_link_lsa_new(struct ospf_area *area,
1012 struct ext_itf *exti)
1013{
1014 struct stream *s;
1015 struct lsa_header *lsah;
1016 struct ospf_lsa *new = NULL;
1017 u_char options, lsa_type;
1018 struct in_addr lsa_id;
93f0a26e
OD
1019 uint32_t tmp;
1020 uint16_t length;
cf9b9f77 1021
fd3b19f2
OD
1022 /* Sanity Check */
1023 if (exti == NULL)
1024 return NULL;
1025
cf9b9f77 1026 /* Create a stream for LSA. */
7743f2f8
OD
1027 s = stream_new(OSPF_MAX_LSA_SIZE);
1028 if (s == NULL) {
1029 zlog_warn("EXT (%s): stream_new() error", __func__);
cf9b9f77
OD
1030 return NULL;
1031 }
1032 lsah = (struct lsa_header *)STREAM_DATA(s);
1033
1034 options = OSPF_OPTION_O; /* Don't forget this :-) */
1035 options |= LSA_OPTIONS_GET(area); /* Get area default option */
1036 options |= LSA_OPTIONS_NSSA_GET(area);
1037 /* Extended Link Opaque LSA are only flooded within an area */
1038 lsa_type = OSPF_OPAQUE_AREA_LSA;
1039
7743f2f8
OD
1040 /*
1041 * LSA ID is a variable number identifying different instances of
1042 * Extended Link Opaque LSA from the same router see RFC 7684
1043 */
cf9b9f77
OD
1044 tmp = SET_OPAQUE_LSID(OPAQUE_TYPE_EXTENDED_LINK_LSA, exti->instance);
1045 lsa_id.s_addr = htonl(tmp);
1046
1047 if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
1048 zlog_debug(
7743f2f8
OD
1049 "EXT (%s) LSA[Type%u:%s]: Create an Opaque-LSA "
1050 "Extended Link Opaque LSA instance",
1051 __func__, lsa_type, inet_ntoa(lsa_id));
cf9b9f77
OD
1052
1053 /* Set opaque-LSA header fields. */
1054 lsa_header_set(s, options, lsa_type, lsa_id, area->ospf->router_id);
1055
1056 /* Set opaque-LSA body fields. */
1057 ospf_ext_link_lsa_body_set(s, exti);
1058
1059 /* Set length. */
1060 length = stream_get_endp(s);
1061 lsah->length = htons(length);
1062
1063 /* Now, create an OSPF LSA instance. */
7743f2f8
OD
1064 new = ospf_lsa_new();
1065 if (new == NULL) {
1066 zlog_warn("EXT (%s): ospf_lsa_new() error", __func__);
cf9b9f77
OD
1067 stream_free(s);
1068 return NULL;
1069 }
7743f2f8
OD
1070 new->data = ospf_lsa_data_new(length);
1071 if (new->data == NULL) {
1072 zlog_warn("EXT (%s): ospf_lsa_data_new() error", __func__);
cf9b9f77
OD
1073 ospf_lsa_unlock(&new);
1074 new = NULL;
1075 stream_free(s);
1076 return NULL;
1077 }
1078
7743f2f8
OD
1079 /* Segment Routing belongs only to default VRF */
1080 new->vrf_id = VRF_DEFAULT;
cf9b9f77
OD
1081 new->area = area;
1082 SET_FLAG(new->flags, OSPF_LSA_SELF);
1083 memcpy(new->data, lsah, length);
1084 stream_free(s);
1085
1086 return new;
1087}
1088
7743f2f8
OD
1089/*
1090 * Process the origination of an Extended Prefix Opaque LSA
1091 * for every extended prefix TLV
1092 */
cf9b9f77
OD
1093static int ospf_ext_pref_lsa_originate1(struct ospf_area *area,
1094 struct ext_itf *exti)
1095{
1096 struct ospf_lsa *new;
1097 int rc = -1;
1098
1099
1100 /* Create new Opaque-LSA/Extended Prefix Opaque LSA instance. */
7743f2f8
OD
1101 new = ospf_ext_pref_lsa_new(area, exti);
1102 if (new == NULL) {
1103 zlog_warn("EXT (%s): ospf_ext_pref_lsa_new() error", __func__);
cf9b9f77
OD
1104 return rc;
1105 }
1106
1107 /* Install this LSA into LSDB. */
1108 if (ospf_lsa_install(area->ospf, NULL /*oi */, new) == NULL) {
7743f2f8 1109 zlog_warn("EXT (%s): ospf_lsa_install() error", __func__);
cf9b9f77
OD
1110 ospf_lsa_unlock(&new);
1111 return rc;
1112 }
1113
1114 /* Now this Extended Prefix Opaque LSA info parameter entry has
7743f2f8
OD
1115 * associated LSA.
1116 */
cf9b9f77
OD
1117 SET_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED);
1118
1119 /* Update new LSA origination count. */
1120 area->ospf->lsa_originate_count++;
1121
1122 /* Flood new LSA through area. */
1123 ospf_flood_through_area(area, NULL /*nbr */, new);
1124
1125 if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) {
1126 char area_id[INET_ADDRSTRLEN];
7743f2f8 1127
cf9b9f77
OD
1128 strncpy(area_id, inet_ntoa(area->area_id), INET_ADDRSTRLEN);
1129 zlog_debug(
7743f2f8
OD
1130 "EXT (%s): LSA[Type%u:%s]: Originate Opaque-LSA "
1131 "Extended Prefix Opaque LSA: Area(%s), Link(%s)",
1132 __func__, new->data->type, inet_ntoa(new->data->id),
1133 area_id, exti->ifp->name);
cf9b9f77
OD
1134 ospf_lsa_header_dump(new->data);
1135 }
1136
1137 rc = 0;
1138
1139 return rc;
1140}
1141
7743f2f8
OD
1142/*
1143 * Process the origination of an Extended Link Opaque LSA
1144 * for every extended link TLV
1145 */
cf9b9f77
OD
1146static int ospf_ext_link_lsa_originate1(struct ospf_area *area,
1147 struct ext_itf *exti)
1148{
1149 struct ospf_lsa *new;
1150 int rc = -1;
1151
1152 /* Create new Opaque-LSA/Extended Link Opaque LSA instance. */
7743f2f8
OD
1153 new = ospf_ext_link_lsa_new(area, exti);
1154 if (new == NULL) {
1155 zlog_warn("EXT (%s): ospf_ext_link_lsa_new() error", __func__);
cf9b9f77
OD
1156 return rc;
1157 }
1158
1159 /* Install this LSA into LSDB. */
1160 if (ospf_lsa_install(area->ospf, NULL /*oi */, new) == NULL) {
7743f2f8 1161 zlog_warn("EXT (%s): ospf_lsa_install() error", __func__);
cf9b9f77
OD
1162 ospf_lsa_unlock(&new);
1163 return rc;
1164 }
1165
1166 /* Now this link-parameter entry has associated LSA. */
1167 SET_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED);
1168
1169 /* Update new LSA origination count. */
1170 area->ospf->lsa_originate_count++;
1171
1172 /* Flood new LSA through area. */
1173 ospf_flood_through_area(area, NULL /*nbr */, new);
1174
1175 if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) {
1176 char area_id[INET_ADDRSTRLEN];
7743f2f8 1177
cf9b9f77
OD
1178 strncpy(area_id, inet_ntoa(area->area_id), INET_ADDRSTRLEN);
1179 zlog_debug(
7743f2f8
OD
1180 "EXT (%s): LSA[Type%u:%s]: Originate Opaque-LSA "
1181 "Extended Link Opaque LSA: Area(%s), Link(%s)",
996c9314
LB
1182 __func__, new->data->type, inet_ntoa(new->data->id),
1183 area_id, exti->ifp->name);
cf9b9f77
OD
1184 ospf_lsa_header_dump(new->data);
1185 }
1186
1187 rc = 0;
1188
1189 return rc;
1190}
1191
1192/* Trigger the origination of Extended Prefix Opaque LSAs */
1193static int ospf_ext_pref_lsa_originate(void *arg)
1194{
1195 struct ospf_area *area = (struct ospf_area *)arg;
1196 struct listnode *node;
1197 struct ext_itf *exti;
1198 int rc = -1;
1199
1200 if (!OspfEXT.enabled) {
1201 zlog_info(
7743f2f8 1202 "EXT (%s): Segment Routing "
996c9314
LB
1203 "functionality is Disabled now",
1204 __func__);
cf9b9f77
OD
1205 rc = 0; /* This is not an error case. */
1206 return rc;
1207 }
1208 if (IS_DEBUG_OSPF_SR)
996c9314
LB
1209 zlog_debug("EXT (%s): Start Originate Prefix LSA for area %s",
1210 __func__, inet_ntoa(area->area_id));
cf9b9f77
OD
1211
1212 /* Check if Extended Prefix Opaque LSA is already engaged */
1213 for (ALL_LIST_ELEMENTS_RO(OspfEXT.iflist, node, exti)) {
1214
1215 /* Process only Prefix SID */
1216 if (exti->stype != PREF_SID)
1217 continue;
1218
1219 /* Process only Extended Prefix with valid Area ID */
1220 if ((exti->area == NULL)
1221 || (!IPV4_ADDR_SAME(&exti->area->area_id, &area->area_id)))
1222 continue;
1223
1224 if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED)) {
1225 if (CHECK_FLAG(exti->flags,
1226 EXT_LPFLG_LSA_FORCED_REFRESH)) {
7743f2f8
OD
1227 zlog_warn(
1228 "EXT (%s): Refresh instead of "
996c9314
LB
1229 "Originate",
1230 __func__);
cf9b9f77
OD
1231 UNSET_FLAG(exti->flags,
1232 EXT_LPFLG_LSA_FORCED_REFRESH);
1233 ospf_ext_pref_lsa_schedule(exti,
1234 REFRESH_THIS_LSA);
1235 }
1236 continue;
1237 }
1238
1239 /* Ok, let's try to originate an LSA */
1240 if (IS_DEBUG_OSPF_SR)
1241 zlog_debug(
7743f2f8
OD
1242 "EXT (%s): Let's finally reoriginate the "
1243 "LSA 7.0.0.%u for Itf %s",
1244 __func__, exti->instance,
cf9b9f77
OD
1245 exti->ifp ? exti->ifp->name : "");
1246 ospf_ext_pref_lsa_originate1(area, exti);
1247 }
1248
1249 rc = 0;
1250 return rc;
1251}
1252
1253/* Trigger the origination of Extended Link Opaque LSAs */
1254static int ospf_ext_link_lsa_originate(void *arg)
1255{
1256 struct ospf_area *area = (struct ospf_area *)arg;
1257 struct listnode *node;
1258 struct ext_itf *exti;
1259 int rc = -1;
1260
1261 if (!OspfEXT.enabled) {
1262 zlog_info(
7743f2f8 1263 "EXT (%s): Segment Routing "
996c9314
LB
1264 "functionality is Disabled now",
1265 __func__);
cf9b9f77
OD
1266 rc = 0; /* This is not an error case. */
1267 return rc;
1268 }
1269
1270 /* Check if Extended Prefix Opaque LSA is already engaged */
1271 for (ALL_LIST_ELEMENTS_RO(OspfEXT.iflist, node, exti)) {
1272 /* Process only Adjacency or LAN SID */
1273 if (exti->stype == PREF_SID)
1274 continue;
1275
1276 /* Process only Extended Link with valid Area ID */
1277 if ((exti->area == NULL)
1278 || (!IPV4_ADDR_SAME(&exti->area->area_id, &area->area_id)))
1279 continue;
1280
1281 /* Check if LSA not already engaged */
1282 if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED)) {
1283 if (CHECK_FLAG(exti->flags,
1284 EXT_LPFLG_LSA_FORCED_REFRESH)) {
7743f2f8
OD
1285 zlog_warn(
1286 "EXT (%s): Refresh instead of "
996c9314
LB
1287 "Originate",
1288 __func__);
cf9b9f77
OD
1289 UNSET_FLAG(exti->flags,
1290 EXT_LPFLG_LSA_FORCED_REFRESH);
1291 ospf_ext_link_lsa_schedule(exti,
1292 REFRESH_THIS_LSA);
1293 }
1294 continue;
1295 }
1296
1297 /* Ok, let's try to originate an LSA */
1298 if (IS_DEBUG_OSPF_SR)
1299 zlog_debug(
7743f2f8
OD
1300 "EXT (%s): Let's finally reoriginate the "
1301 "LSA 8.0.0.%u for Itf %s through the Area %s",
1302 __func__, exti->instance,
cf9b9f77
OD
1303 exti->ifp ? exti->ifp->name : "-",
1304 inet_ntoa(area->area_id));
1305 ospf_ext_link_lsa_originate1(area, exti);
1306 }
1307
1308 rc = 0;
1309 return rc;
1310}
1311
1312/* Refresh an Extended Prefix Opaque LSA */
1313static struct ospf_lsa *ospf_ext_pref_lsa_refresh(struct ospf_lsa *lsa)
1314{
1315 struct ospf_lsa *new = NULL;
1316 struct ospf_area *area = lsa->area;
1317 struct ospf *top;
1318 struct ext_itf *exti;
1319
1320 if (!OspfEXT.enabled) {
1321 /*
1322 * This LSA must have flushed before due to Extended Prefix
1323 * Opaque LSA status change.
1324 * It seems a slip among routers in the routing domain.
1325 */
7743f2f8
OD
1326 zlog_info(
1327 "EXT (%s): Segment Routing functionality is "
996c9314
LB
1328 "Disabled",
1329 __func__);
cf9b9f77
OD
1330 /* Flush it anyway. */
1331 lsa->data->ls_age = htons(OSPF_LSA_MAXAGE);
1332 }
1333
1334 /* Lookup this lsa corresponding Extended parameters */
7743f2f8
OD
1335 exti = lookup_ext_by_instance(lsa);
1336 if (exti == NULL) {
1337 zlog_warn("EXT (%s): Invalid parameter LSA ID", __func__);
cf9b9f77
OD
1338 /* Flush it anyway. */
1339 lsa->data->ls_age = htons(OSPF_LSA_MAXAGE);
1340 }
1341
1342 /* Check if Interface was not disable in the interval */
1343 if ((exti != NULL) && !CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE)) {
7743f2f8 1344 zlog_warn("EXT (%s): Interface was Disabled: Flush it!",
996c9314 1345 __func__);
cf9b9f77
OD
1346 /* Flush it anyway. */
1347 lsa->data->ls_age = htons(OSPF_LSA_MAXAGE);
1348 }
1349
1350 /* If the lsa's age reached to MaxAge, start flushing procedure. */
1351 if (IS_LSA_MAXAGE(lsa)) {
1352 if (exti)
1353 UNSET_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED);
1354 ospf_opaque_lsa_flush_schedule(lsa);
1355 return NULL;
1356 }
1357
1358 /* Create new Opaque-LSA/Extended Prefix Opaque LSA instance. */
db28a51f 1359 new = ospf_ext_pref_lsa_new(area, exti);
cf9b9f77
OD
1360
1361 if (new == NULL) {
7743f2f8 1362 zlog_warn("EXT (%s): ospf_ext_pref_lsa_new() error", __func__);
cf9b9f77
OD
1363 return NULL;
1364 }
1365 new->data->ls_seqnum = lsa_seqnum_increment(lsa);
1366
7743f2f8
OD
1367 /*
1368 * Install this LSA into LSDB
1369 * Given "lsa" will be freed in the next function
1370 * As area could be NULL i.e. when using OPAQUE_LSA_AS, we prefer to use
1371 * ospf_lookup() to get ospf instance
1372 */
cf9b9f77
OD
1373 if (area)
1374 top = area->ospf;
1375 else
1376 top = ospf_lookup_by_vrf_id(VRF_DEFAULT);
1377
1378 if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) {
7743f2f8 1379 zlog_warn("EXT (%s): ospf_lsa_install() error", __func__);
cf9b9f77
OD
1380 ospf_lsa_unlock(&new);
1381 return NULL;
1382 }
1383
1384 /* Flood updated LSA through the Prefix Area according to the RFC7684 */
1385 ospf_flood_through_area(area, NULL /*nbr */, new);
1386
1387 /* Debug logging. */
1388 if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) {
7743f2f8
OD
1389 zlog_debug(
1390 "EXT (%s): LSA[Type%u:%s] Refresh Extended Prefix LSA",
1391 __func__, new->data->type, inet_ntoa(new->data->id));
cf9b9f77
OD
1392 ospf_lsa_header_dump(new->data);
1393 }
1394
1395 return new;
1396}
1397
1398/* Refresh an Extended Link Opaque LSA */
1399static struct ospf_lsa *ospf_ext_link_lsa_refresh(struct ospf_lsa *lsa)
1400{
1401 struct ext_itf *exti;
1402 struct ospf_area *area = lsa->area;
1403 struct ospf *top = area->ospf;
1404 struct ospf_lsa *new = NULL;
1405
1406 if (!OspfEXT.enabled) {
1407 /*
1408 * This LSA must have flushed before due to OSPF-SR status
1409 * change. It seems a slip among routers in the routing domain.
1410 */
996c9314
LB
1411 zlog_info("EXT (%s): Segment Routing functionality is Disabled",
1412 __func__);
cf9b9f77
OD
1413 /* Flush it anyway. */
1414 lsa->data->ls_age = htons(OSPF_LSA_MAXAGE);
1415 }
1416
7743f2f8
OD
1417 /* Lookup this LSA corresponding Extended parameters */
1418 exti = lookup_ext_by_instance(lsa);
1419 if (exti == NULL) {
1420 zlog_warn("EXT (%s): Invalid parameter LSA ID", __func__);
cf9b9f77
OD
1421 /* Flush it anyway. */
1422 lsa->data->ls_age = htons(OSPF_LSA_MAXAGE);
1423 }
1424
1425 /* Check if Interface was not disable in the interval */
1426 if ((exti != NULL) && !CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE)) {
996c9314
LB
1427 zlog_warn("EXT (%s): Interface was Disabled: Flush it!",
1428 __func__);
cf9b9f77
OD
1429 lsa->data->ls_age = htons(OSPF_LSA_MAXAGE);
1430 }
1431
7743f2f8 1432 /* If the lsa's age reached to MaxAge, start flushing procedure */
cf9b9f77
OD
1433 if (IS_LSA_MAXAGE(lsa)) {
1434 if (exti)
1435 UNSET_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED);
1436 ospf_opaque_lsa_flush_schedule(lsa);
1437 return NULL;
1438 }
1439
7743f2f8
OD
1440 /* Create new Opaque-LSA/Extended Link instance */
1441 new = ospf_ext_link_lsa_new(area, exti);
1442 if (new == NULL) {
1443 zlog_warn("EXT (%s): Error creating new LSA", __func__);
cf9b9f77
OD
1444 return NULL;
1445 }
1446 new->data->ls_seqnum = lsa_seqnum_increment(lsa);
1447
1448 /* Install this LSA into LSDB. */
7743f2f8 1449 /* Given "lsa" will be freed in the next function */
cf9b9f77 1450 if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) {
7743f2f8 1451 zlog_warn("EXT (%s): Error installing new LSA", __func__);
cf9b9f77
OD
1452 ospf_lsa_unlock(&new);
1453 return NULL;
1454 }
1455
1456 /* Flood updated LSA through the link Area according to the RFC7684 */
1457 ospf_flood_through_area(area, NULL /*nbr */, new);
1458
1459 /* Debug logging. */
1460 if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) {
1461 zlog_debug(
7743f2f8
OD
1462 "EXT (%s): LSA[Type%u:%s]: Refresh Extended Link LSA",
1463 __func__, new->data->type, inet_ntoa(new->data->id));
cf9b9f77
OD
1464 ospf_lsa_header_dump(new->data);
1465 }
1466
1467 return new;
1468}
1469
1470/* Schedule Extended Prefix Opaque LSA origination/refreshment/flushing */
1471static void ospf_ext_pref_lsa_schedule(struct ext_itf *exti,
1472 enum lsa_opcode opcode)
1473{
1474 struct ospf_lsa lsa;
1475 struct lsa_header lsah;
1476 struct ospf *top;
93f0a26e 1477 uint32_t tmp;
cf9b9f77
OD
1478
1479 memset(&lsa, 0, sizeof(lsa));
1480 memset(&lsah, 0, sizeof(lsah));
1481
1482 /* Sanity Check */
1483 if (exti == NULL)
1484 return;
1485
1486 /* Check if the corresponding link is ready to be flooded */
1487 if (!(CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE)))
1488 return;
1489
996c9314
LB
1490 zlog_debug("EXT (%s): Schedule %s%s%s LSA for interface %s", __func__,
1491 opcode == REORIGINATE_THIS_LSA ? "Re-Originate" : "",
1492 opcode == REFRESH_THIS_LSA ? "Refresh" : "",
1493 opcode == FLUSH_THIS_LSA ? "Flush" : "",
1494 exti->ifp ? exti->ifp->name : "-");
cf9b9f77
OD
1495
1496 /* Set LSA header information */
1497 if (exti->area == NULL) {
1498 zlog_warn(
7743f2f8 1499 "EXT (%s): Flooding is Area scope but area is not yet "
996c9314
LB
1500 "set",
1501 __func__);
cf9b9f77
OD
1502 if (OspfEXT.area == NULL) {
1503 top = ospf_lookup_by_vrf_id(VRF_DEFAULT);
1504 OspfEXT.area = ospf_area_lookup_by_area_id(
1505 top, OspfEXT.area_id);
1506 }
1507 exti->area = OspfEXT.area;
1508 }
1509 lsa.area = exti->area;
1510 lsa.data = &lsah;
1511 lsah.type = OSPF_OPAQUE_AREA_LSA;
1512 tmp = SET_OPAQUE_LSID(OPAQUE_TYPE_EXTENDED_PREFIX_LSA, exti->instance);
1513 lsah.id.s_addr = htonl(tmp);
1514
1515 switch (opcode) {
1516 case REORIGINATE_THIS_LSA:
1517 ospf_opaque_lsa_reoriginate_schedule(
1518 (void *)exti->area, OSPF_OPAQUE_AREA_LSA,
1519 OPAQUE_TYPE_EXTENDED_PREFIX_LSA);
1520 break;
1521 case REFRESH_THIS_LSA:
1522 ospf_opaque_lsa_refresh_schedule(&lsa);
1523 break;
1524 case FLUSH_THIS_LSA:
1525 UNSET_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED);
1526 ospf_opaque_lsa_flush_schedule(&lsa);
1527 break;
1528 default:
7743f2f8 1529 zlog_warn("EXT (%s): Unknown opcode", __func__);
cf9b9f77
OD
1530 break;
1531 }
cf9b9f77
OD
1532}
1533
1534/* Schedule Extended Link Opaque LSA origination/refreshment/flushing */
1535static void ospf_ext_link_lsa_schedule(struct ext_itf *exti,
1536 enum lsa_opcode opcode)
1537{
1538 struct ospf_lsa lsa;
1539 struct lsa_header lsah;
1540 struct ospf *top;
93f0a26e 1541 uint32_t tmp;
cf9b9f77
OD
1542
1543 memset(&lsa, 0, sizeof(lsa));
1544 memset(&lsah, 0, sizeof(lsah));
1545
1546 /* Sanity Check */
1547 if (exti == NULL)
1548 return;
1549
1550 /* Check if the corresponding link is ready to be flooded */
1551 if (!(CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE)))
1552 return;
1553
996c9314
LB
1554 zlog_debug("EXT (%s): Schedule %s%s%s LSA for interface %s", __func__,
1555 opcode == REORIGINATE_THIS_LSA ? "Re-Originate" : "",
1556 opcode == REFRESH_THIS_LSA ? "Refresh" : "",
1557 opcode == FLUSH_THIS_LSA ? "Flush" : "",
1558 exti->ifp ? exti->ifp->name : "-");
cf9b9f77
OD
1559
1560 /* Set LSA header information */
1561 if (exti->area == NULL) {
1562 zlog_warn(
7743f2f8 1563 "EXT (%s): Flooding is Area scope but area is not "
996c9314
LB
1564 "yet set",
1565 __func__);
cf9b9f77
OD
1566 if (OspfEXT.area == NULL) {
1567 top = ospf_lookup_by_vrf_id(VRF_DEFAULT);
1568 OspfEXT.area = ospf_area_lookup_by_area_id(
1569 top, OspfEXT.area_id);
1570 }
1571 exti->area = OspfEXT.area;
1572 }
1573 lsa.area = exti->area;
1574 lsa.data = &lsah;
1575 lsah.type = OSPF_OPAQUE_AREA_LSA;
1576 tmp = SET_OPAQUE_LSID(OPAQUE_TYPE_EXTENDED_LINK_LSA, exti->instance);
1577 lsah.id.s_addr = htonl(tmp);
1578
1579 switch (opcode) {
1580 case REORIGINATE_THIS_LSA:
1581 ospf_opaque_lsa_reoriginate_schedule(
1582 (void *)exti->area, OSPF_OPAQUE_AREA_LSA,
1583 OPAQUE_TYPE_EXTENDED_LINK_LSA);
1584 break;
1585 case REFRESH_THIS_LSA:
1586 ospf_opaque_lsa_refresh_schedule(&lsa);
1587 break;
1588 case FLUSH_THIS_LSA:
1589 UNSET_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED);
1590 ospf_opaque_lsa_flush_schedule(&lsa);
1591 break;
1592 default:
7743f2f8 1593 zlog_warn("EXT (%s): Unknown opcode", __func__);
cf9b9f77
OD
1594 break;
1595 }
cf9b9f77
OD
1596}
1597
1598/* Schedule Extended Link or Prefix depending of the Type of LSA */
1599static void ospf_ext_lsa_schedule(struct ext_itf *exti, enum lsa_opcode op)
1600{
1601
1602 if (exti->stype == PREF_SID)
1603 ospf_ext_pref_lsa_schedule(exti, op);
1604 else
1605 ospf_ext_link_lsa_schedule(exti, op);
1606}
1607
7743f2f8
OD
1608/*
1609 * ------------------------------------
cf9b9f77 1610 * Followings are vty show functions.
7743f2f8
OD
1611 * ------------------------------------
1612 */
1613
cf9b9f77 1614/* Cisco experimental SubTLV */
93f0a26e 1615static uint16_t show_vty_ext_link_rmt_itf_addr(struct vty *vty,
996c9314 1616 struct tlv_header *tlvh)
cf9b9f77
OD
1617{
1618 struct ext_subtlv_rmt_itf_addr *top;
7743f2f8 1619
cf9b9f77
OD
1620 top = (struct ext_subtlv_rmt_itf_addr *)tlvh;
1621
1622 vty_out(vty,
7743f2f8 1623 " Remote Interface Address Sub-TLV: Length %u\n "
cf9b9f77
OD
1624 "Address: %s\n",
1625 ntohs(top->header.length), inet_ntoa(top->value));
1626
1627 return TLV_SIZE(tlvh);
1628}
1629
1630/* Adjacency SID SubTLV */
93f0a26e 1631static uint16_t show_vty_ext_link_adj_sid(struct vty *vty,
996c9314 1632 struct tlv_header *tlvh)
cf9b9f77
OD
1633{
1634 struct ext_subtlv_adj_sid *top = (struct ext_subtlv_adj_sid *)tlvh;
1635
1636 vty_out(vty,
7743f2f8
OD
1637 " Adj-SID Sub-TLV: Length %u\n\tFlags: "
1638 "0x%x\n\tMT-ID:0x%x\n\tWeight: 0x%x\n\t%s: %u\n",
cf9b9f77
OD
1639 ntohs(top->header.length), top->flags, top->mtid, top->weight,
1640 CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) ? "Label"
1641 : "Index",
1642 CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG)
1643 ? GET_LABEL(ntohl(top->value))
1644 : ntohl(top->value));
1645
1646 return TLV_SIZE(tlvh);
1647}
1648
1649/* LAN Adjacency SubTLV */
93f0a26e 1650static uint16_t show_vty_ext_link_lan_adj_sid(struct vty *vty,
996c9314 1651 struct tlv_header *tlvh)
cf9b9f77
OD
1652{
1653 struct ext_subtlv_lan_adj_sid *top =
1654 (struct ext_subtlv_lan_adj_sid *)tlvh;
1655
1656 vty_out(vty,
7743f2f8 1657 " LAN-Adj-SID Sub-TLV: Length %u\n\tFlags: "
cf9b9f77 1658 "0x%x\n\tMT-ID:0x%x\n\tWeight: 0x%x\n\tNeighbor ID: "
d922605d 1659 "%s\n\t%s: %u\n",
cf9b9f77 1660 ntohs(top->header.length), top->flags, top->mtid, top->weight,
d922605d 1661 inet_ntoa(top->neighbor_id),
cf9b9f77
OD
1662 CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) ? "Label"
1663 : "Index",
1664 CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG)
1665 ? GET_LABEL(ntohl(top->value))
1666 : ntohl(top->value));
1667
1668 return TLV_SIZE(tlvh);
1669}
1670
93f0a26e 1671static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh)
cf9b9f77
OD
1672{
1673 vty_out(vty, " Unknown TLV: [type(0x%x), length(0x%x)]\n",
1674 ntohs(tlvh->type), ntohs(tlvh->length));
1675
1676 return TLV_SIZE(tlvh);
1677}
1678
1679/* Extended Link Sub TLVs */
93f0a26e 1680static uint16_t show_vty_link_info(struct vty *vty, struct tlv_header *ext)
cf9b9f77
OD
1681{
1682 struct ext_tlv_link *top = (struct ext_tlv_link *)ext;
1683 struct tlv_header *tlvh;
93f0a26e
OD
1684 uint16_t length = ntohs(top->header.length) - 3 * sizeof(uint32_t);
1685 uint16_t sum = 0;
cf9b9f77
OD
1686
1687 vty_out(vty,
7743f2f8 1688 " Extended Link TLV: Length %u\n Link Type: 0x%x\n"
cf9b9f77
OD
1689 " Link ID: %s\n",
1690 ntohs(top->header.length), top->link_type,
1691 inet_ntoa(top->link_id));
1692 vty_out(vty, " Link data: %s\n", inet_ntoa(top->link_data));
1693
1694 tlvh = (struct tlv_header *)((char *)(ext) + TLV_HDR_SIZE
1695 + EXT_TLV_LINK_SIZE);
1696 for (; sum < length; tlvh = TLV_HDR_NEXT(tlvh)) {
1697 switch (ntohs(tlvh->type)) {
1698 case EXT_SUBTLV_ADJ_SID:
1699 sum += show_vty_ext_link_adj_sid(vty, tlvh);
1700 break;
1701 case EXT_SUBTLV_LAN_ADJ_SID:
1702 sum += show_vty_ext_link_lan_adj_sid(vty, tlvh);
1703 break;
1704 case EXT_SUBTLV_RMT_ITF_ADDR:
1705 sum += show_vty_ext_link_rmt_itf_addr(vty, tlvh);
1706 break;
1707 default:
1708 sum += show_vty_unknown_tlv(vty, tlvh);
1709 break;
1710 }
1711 }
1712
1713 return sum + sizeof(struct ext_tlv_link);
1714}
1715
1716/* Extended Link TLVs */
1717static void ospf_ext_link_show_info(struct vty *vty, struct ospf_lsa *lsa)
1718{
1719 struct lsa_header *lsah = (struct lsa_header *)lsa->data;
1720 struct tlv_header *tlvh;
93f0a26e 1721 uint16_t length = 0, sum = 0;
cf9b9f77
OD
1722
1723 /* Initialize TLV browsing */
1724 length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE;
1725
1726 for (tlvh = TLV_HDR_TOP(lsah); sum < length;
1727 tlvh = TLV_HDR_NEXT(tlvh)) {
1728 switch (ntohs(tlvh->type)) {
1729 case EXT_TLV_LINK:
1730 sum += show_vty_link_info(vty, tlvh);
1731 break;
1732 default:
1733 sum += show_vty_unknown_tlv(vty, tlvh);
1734 break;
1735 }
1736 }
cf9b9f77
OD
1737}
1738
1739/* Prefix SID SubTLV */
93f0a26e 1740static uint16_t show_vty_ext_pref_pref_sid(struct vty *vty,
996c9314 1741 struct tlv_header *tlvh)
cf9b9f77
OD
1742{
1743 struct ext_subtlv_prefix_sid *top =
1744 (struct ext_subtlv_prefix_sid *)tlvh;
1745
1746 vty_out(vty,
7743f2f8
OD
1747 " Prefix SID Sub-TLV: Length %u\n\tAlgorithm: "
1748 "%u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\t%s: %u\n",
cf9b9f77
OD
1749 ntohs(top->header.length), top->algorithm, top->flags,
1750 top->mtid,
1751 CHECK_FLAG(top->flags, EXT_SUBTLV_PREFIX_SID_VFLG) ? "Label"
1752 : "Index",
1753 CHECK_FLAG(top->flags, EXT_SUBTLV_PREFIX_SID_VFLG)
1754 ? GET_LABEL(ntohl(top->value))
1755 : ntohl(top->value));
1756
1757 return TLV_SIZE(tlvh);
1758}
1759
1760/* Extended Prefix SubTLVs */
93f0a26e 1761static uint16_t show_vty_pref_info(struct vty *vty, struct tlv_header *ext)
cf9b9f77
OD
1762{
1763 struct ext_tlv_prefix *top = (struct ext_tlv_prefix *)ext;
1764 struct tlv_header *tlvh;
93f0a26e
OD
1765 uint16_t length = ntohs(top->header.length) - 2 * sizeof(uint32_t);
1766 uint16_t sum = 0;
cf9b9f77
OD
1767
1768 vty_out(vty,
7743f2f8
OD
1769 " Extended Prefix TLV: Length %u\n\tRoute Type: %u\n"
1770 "\tAddress Family: 0x%x\n\tFlags: 0x%x\n\tAddress: %s/%u\n",
cf9b9f77
OD
1771 ntohs(top->header.length), top->route_type, top->af, top->flags,
1772 inet_ntoa(top->address), top->pref_length);
1773
1774 tlvh = (struct tlv_header *)((char *)(ext) + TLV_HDR_SIZE
1775 + EXT_TLV_PREFIX_SIZE);
1776 for (; sum < length; tlvh = TLV_HDR_NEXT(tlvh)) {
1777 switch (ntohs(tlvh->type)) {
1778 case EXT_SUBTLV_PREFIX_SID:
1779 sum += show_vty_ext_pref_pref_sid(vty, tlvh);
1780 break;
1781 default:
1782 sum += show_vty_unknown_tlv(vty, tlvh);
1783 break;
1784 }
1785 }
1786
1787 return sum + sizeof(struct ext_tlv_prefix);
1788}
1789
1790/* Extended Prefix TLVs */
1791static void ospf_ext_pref_show_info(struct vty *vty, struct ospf_lsa *lsa)
1792{
1793 struct lsa_header *lsah = (struct lsa_header *)lsa->data;
1794 struct tlv_header *tlvh;
93f0a26e 1795 uint16_t length = 0, sum = 0;
cf9b9f77
OD
1796
1797 /* Initialize TLV browsing */
1798 length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE;
1799
1800 for (tlvh = TLV_HDR_TOP(lsah); sum < length;
1801 tlvh = TLV_HDR_NEXT(tlvh)) {
1802 switch (ntohs(tlvh->type)) {
1803 case EXT_TLV_PREFIX:
1804 sum += show_vty_pref_info(vty, tlvh);
1805 break;
1806 default:
1807 sum += show_vty_unknown_tlv(vty, tlvh);
1808 break;
1809 }
1810 }
cf9b9f77 1811}