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