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