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