]>
Commit | Line | Data |
---|---|---|
0ef4bcdc OD |
1 | /* |
2 | * This is an implementation of RFC4970 Router Information | |
3 | * with support of RFC5088 PCE Capabilites announcement | |
4 | * | |
5 | * Module name: Router Information | |
cf9b9f77 OD |
6 | * Author: Olivier Dugeon <olivier.dugeon@orange.com> |
7 | * Copyright (C) 2012 - 2017 Orange Labs http://www.orange.com/ | |
0ef4bcdc OD |
8 | * |
9 | * This file is part of GNU Quagga. | |
10 | * | |
11 | * GNU Zebra is free software; you can redistribute it and/or modify it | |
12 | * under the terms of the GNU General Public License as published by the | |
13 | * Free Software Foundation; either version 2, or (at your option) any | |
14 | * later version. | |
15 | * | |
16 | * GNU Quagga is distributed in the hope that it will be useful, but | |
17 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * General Public License for more details. | |
20 | * | |
896014f4 DL |
21 | * You should have received a copy of the GNU General Public License along |
22 | * with this program; see the file COPYING; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
0ef4bcdc OD |
24 | */ |
25 | ||
26 | #include <zebra.h> | |
27 | #include <math.h> | |
28 | ||
29 | #include "linklist.h" | |
30 | #include "prefix.h" | |
31 | #include "if.h" | |
32 | #include "table.h" | |
33 | #include "memory.h" | |
34 | #include "command.h" | |
35 | #include "vty.h" | |
36 | #include "stream.h" | |
37 | #include "log.h" | |
38 | #include "thread.h" | |
39 | #include "hash.h" | |
d62a17ae | 40 | #include "sockunion.h" /* for inet_aton() */ |
cf9b9f77 | 41 | #include "mpls.h" |
0ef4bcdc OD |
42 | |
43 | #include "ospfd/ospfd.h" | |
44 | #include "ospfd/ospf_interface.h" | |
45 | #include "ospfd/ospf_ism.h" | |
46 | #include "ospfd/ospf_asbr.h" | |
47 | #include "ospfd/ospf_lsa.h" | |
48 | #include "ospfd/ospf_lsdb.h" | |
49 | #include "ospfd/ospf_neighbor.h" | |
50 | #include "ospfd/ospf_nsm.h" | |
51 | #include "ospfd/ospf_flood.h" | |
52 | #include "ospfd/ospf_packet.h" | |
53 | #include "ospfd/ospf_spf.h" | |
54 | #include "ospfd/ospf_dump.h" | |
55 | #include "ospfd/ospf_route.h" | |
56 | #include "ospfd/ospf_ase.h" | |
57 | #include "ospfd/ospf_zebra.h" | |
cf9b9f77 | 58 | #include "ospfd/ospf_sr.h" |
0ef4bcdc | 59 | #include "ospfd/ospf_ri.h" |
85c9b439 | 60 | #include "ospfd/ospf_errors.h" |
0ef4bcdc | 61 | |
0ef4bcdc OD |
62 | /* |
63 | * Global variable to manage Opaque-LSA/Router Information on this node. | |
64 | * Note that all parameter values are stored in network byte order. | |
65 | */ | |
66 | static struct ospf_router_info OspfRI; | |
67 | ||
68 | /*------------------------------------------------------------------------------* | |
d62a17ae | 69 | * Followings are initialize/terminate functions for Router Information |
70 | *handling. | |
0ef4bcdc OD |
71 | *------------------------------------------------------------------------------*/ |
72 | ||
d62a17ae | 73 | static void ospf_router_info_ism_change(struct ospf_interface *oi, |
74 | int old_status); | |
d62a17ae | 75 | static void ospf_router_info_config_write_router(struct vty *vty); |
76 | static void ospf_router_info_show_info(struct vty *vty, struct ospf_lsa *lsa); | |
77 | static int ospf_router_info_lsa_originate(void *arg); | |
78 | static struct ospf_lsa *ospf_router_info_lsa_refresh(struct ospf_lsa *lsa); | |
ddd73a96 OD |
79 | static void ospf_router_info_lsa_schedule(struct ospf_ri_area_info *ai, |
80 | enum lsa_opcode opcode); | |
d62a17ae | 81 | static void ospf_router_info_register_vty(void); |
cf9b9f77 | 82 | static int ospf_router_info_lsa_update(struct ospf_lsa *lsa); |
ddd73a96 | 83 | static void del_area_info(void *val); |
d62a17ae | 84 | static void del_pce_info(void *val); |
85 | ||
86 | int ospf_router_info_init(void) | |
0ef4bcdc OD |
87 | { |
88 | ||
ddd73a96 | 89 | zlog_info("RI (%s): Initialize Router Information", __func__); |
cf9b9f77 | 90 | |
d62a17ae | 91 | memset(&OspfRI, 0, sizeof(struct ospf_router_info)); |
32ab5cf4 | 92 | OspfRI.enabled = false; |
d62a17ae | 93 | OspfRI.registered = 0; |
94 | OspfRI.scope = OSPF_OPAQUE_AS_LSA; | |
ddd73a96 OD |
95 | OspfRI.as_flags = RIFLG_LSA_INACTIVE; |
96 | OspfRI.area_info = list_new(); | |
97 | OspfRI.area_info->del = del_area_info; | |
0ef4bcdc | 98 | |
d62a17ae | 99 | /* Initialize pce domain and neighbor list */ |
32ab5cf4 | 100 | OspfRI.pce_info.enabled = false; |
d62a17ae | 101 | OspfRI.pce_info.pce_domain = list_new(); |
102 | OspfRI.pce_info.pce_domain->del = del_pce_info; | |
103 | OspfRI.pce_info.pce_neighbor = list_new(); | |
104 | OspfRI.pce_info.pce_neighbor->del = del_pce_info; | |
0ef4bcdc | 105 | |
cf9b9f77 OD |
106 | /* Initialize Segment Routing information structure */ |
107 | OspfRI.sr_info.enabled = false; | |
108 | ||
d62a17ae | 109 | ospf_router_info_register_vty(); |
0ef4bcdc | 110 | |
d62a17ae | 111 | return 0; |
0ef4bcdc OD |
112 | } |
113 | ||
d7c0a89a | 114 | static int ospf_router_info_register(uint8_t scope) |
0ef4bcdc | 115 | { |
d62a17ae | 116 | int rc = 0; |
117 | ||
118 | if (OspfRI.registered) | |
ead99d5f | 119 | return rc; |
d62a17ae | 120 | |
ddd73a96 OD |
121 | zlog_info("RI (%s): Register Router Information with scope %s(%d)", |
122 | __func__, | |
d62a17ae | 123 | scope == OSPF_OPAQUE_AREA_LSA ? "Area" : "AS", scope); |
124 | rc = ospf_register_opaque_functab( | |
125 | scope, OPAQUE_TYPE_ROUTER_INFORMATION_LSA, | |
126 | NULL, /* new interface */ | |
127 | NULL, /* del interface */ | |
ddd73a96 OD |
128 | ospf_router_info_ism_change, |
129 | NULL, /* NSM change */ | |
d62a17ae | 130 | ospf_router_info_config_write_router, |
131 | NULL, /* Config. write interface */ | |
132 | NULL, /* Config. write debug */ | |
996c9314 LB |
133 | ospf_router_info_show_info, ospf_router_info_lsa_originate, |
134 | ospf_router_info_lsa_refresh, ospf_router_info_lsa_update, | |
cf9b9f77 | 135 | NULL); /* del_lsa_hook */ |
d62a17ae | 136 | |
137 | if (rc != 0) { | |
ade6974d | 138 | flog_warn( |
cf444bcf | 139 | EC_OSPF_OPAQUE_REGISTRATION, |
ddd73a96 | 140 | "RI (%s): Failed to register functions", __func__); |
d62a17ae | 141 | return rc; |
142 | } | |
143 | ||
144 | OspfRI.registered = 1; | |
145 | OspfRI.scope = scope; | |
ead99d5f | 146 | return rc; |
0ef4bcdc OD |
147 | } |
148 | ||
4d762f26 | 149 | static int ospf_router_info_unregister(void) |
bcf4475e OD |
150 | { |
151 | ||
152 | if ((OspfRI.scope != OSPF_OPAQUE_AS_LSA) | |
153 | && (OspfRI.scope != OSPF_OPAQUE_AREA_LSA)) { | |
ade6974d QY |
154 | assert("Unable to unregister Router Info functions: Wrong scope!" |
155 | == NULL); | |
bcf4475e OD |
156 | return -1; |
157 | } | |
158 | ||
159 | ospf_delete_opaque_functab(OspfRI.scope, | |
160 | OPAQUE_TYPE_ROUTER_INFORMATION_LSA); | |
161 | ||
162 | OspfRI.registered = 0; | |
163 | return 0; | |
164 | } | |
165 | ||
d62a17ae | 166 | void ospf_router_info_term(void) |
0ef4bcdc OD |
167 | { |
168 | ||
6a154c88 DL |
169 | list_delete(&OspfRI.pce_info.pce_domain); |
170 | list_delete(&OspfRI.pce_info.pce_neighbor); | |
0ef4bcdc | 171 | |
32ab5cf4 | 172 | OspfRI.enabled = false; |
0ef4bcdc | 173 | |
bcf4475e OD |
174 | ospf_router_info_unregister(); |
175 | ||
d62a17ae | 176 | return; |
0ef4bcdc OD |
177 | } |
178 | ||
bcf4475e OD |
179 | void ospf_router_info_finish(void) |
180 | { | |
731271b0 OD |
181 | struct listnode *node, *nnode; |
182 | struct ospf_ri_area_info *ai; | |
183 | ||
184 | /* Flush Router Info LSA */ | |
185 | for (ALL_LIST_ELEMENTS(OspfRI.area_info, node, nnode, ai)) | |
186 | if (CHECK_FLAG(ai->flags, RIFLG_LSA_ENGAGED)) | |
187 | ospf_router_info_lsa_schedule(ai, FLUSH_THIS_LSA); | |
188 | ||
bcf4475e OD |
189 | list_delete_all_node(OspfRI.pce_info.pce_domain); |
190 | list_delete_all_node(OspfRI.pce_info.pce_neighbor); | |
191 | ||
192 | OspfRI.enabled = false; | |
193 | } | |
194 | ||
ddd73a96 OD |
195 | static void del_area_info(void *val) |
196 | { | |
197 | XFREE(MTYPE_OSPF_ROUTER_INFO, val); | |
198 | } | |
199 | ||
d62a17ae | 200 | static void del_pce_info(void *val) |
0ef4bcdc | 201 | { |
d62a17ae | 202 | XFREE(MTYPE_OSPF_PCE_PARAMS, val); |
0ef4bcdc OD |
203 | } |
204 | ||
cf9b9f77 OD |
205 | /* Catch RI LSA flooding Scope for ospf_ext.[h,c] code */ |
206 | struct scope_info ospf_router_info_get_flooding_scope(void) | |
207 | { | |
208 | struct scope_info flooding_scope; | |
7743f2f8 | 209 | |
cf9b9f77 OD |
210 | if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) { |
211 | flooding_scope.scope = OSPF_OPAQUE_AS_LSA; | |
ddd73a96 | 212 | flooding_scope.areas = NULL; |
cf9b9f77 OD |
213 | return flooding_scope; |
214 | } | |
215 | flooding_scope.scope = OSPF_OPAQUE_AREA_LSA; | |
ddd73a96 | 216 | flooding_scope.areas = OspfRI.area_info; |
cf9b9f77 OD |
217 | return flooding_scope; |
218 | } | |
219 | ||
ddd73a96 OD |
220 | static struct ospf_ri_area_info *lookup_by_area(struct ospf_area *area) |
221 | { | |
222 | struct listnode *node, *nnode; | |
223 | struct ospf_ri_area_info *ai; | |
224 | ||
225 | for (ALL_LIST_ELEMENTS(OspfRI.area_info, node, nnode, ai)) | |
226 | if (ai->area == area) | |
227 | return ai; | |
228 | ||
229 | return NULL; | |
230 | } | |
231 | ||
0ef4bcdc | 232 | /*------------------------------------------------------------------------* |
d62a17ae | 233 | * Followings are control functions for ROUTER INFORMATION parameters |
234 | *management. | |
0ef4bcdc OD |
235 | *------------------------------------------------------------------------*/ |
236 | ||
d62a17ae | 237 | static void set_router_info_capabilities(struct ri_tlv_router_cap *ric, |
d7c0a89a | 238 | uint32_t cap) |
0ef4bcdc | 239 | { |
d62a17ae | 240 | ric->header.type = htons(RI_TLV_CAPABILITIES); |
241 | ric->header.length = htons(RI_TLV_LENGTH); | |
242 | ric->value = htonl(cap); | |
243 | return; | |
0ef4bcdc OD |
244 | } |
245 | ||
d62a17ae | 246 | static int set_pce_header(struct ospf_pce_info *pce) |
0ef4bcdc | 247 | { |
d7c0a89a | 248 | uint16_t length = 0; |
d62a17ae | 249 | struct listnode *node; |
250 | struct ri_pce_subtlv_domain *domain; | |
251 | struct ri_pce_subtlv_neighbor *neighbor; | |
252 | ||
253 | /* PCE Address */ | |
254 | if (ntohs(pce->pce_address.header.type) != 0) | |
ead99d5f | 255 | length += TLV_SIZE(&pce->pce_address.header); |
d62a17ae | 256 | |
257 | /* PCE Path Scope */ | |
258 | if (ntohs(pce->pce_scope.header.type) != 0) | |
ead99d5f | 259 | length += TLV_SIZE(&pce->pce_scope.header); |
d62a17ae | 260 | |
261 | /* PCE Domain */ | |
262 | for (ALL_LIST_ELEMENTS_RO(pce->pce_domain, node, domain)) { | |
263 | if (ntohs(domain->header.type) != 0) | |
ead99d5f | 264 | length += TLV_SIZE(&domain->header); |
d62a17ae | 265 | } |
266 | ||
267 | /* PCE Neighbor */ | |
268 | for (ALL_LIST_ELEMENTS_RO(pce->pce_neighbor, node, neighbor)) { | |
269 | if (ntohs(neighbor->header.type) != 0) | |
ead99d5f | 270 | length += TLV_SIZE(&neighbor->header); |
d62a17ae | 271 | } |
272 | ||
273 | /* PCE Capabilities */ | |
274 | if (ntohs(pce->pce_cap_flag.header.type) != 0) | |
ead99d5f | 275 | length += TLV_SIZE(&pce->pce_cap_flag.header); |
d62a17ae | 276 | |
277 | if (length != 0) { | |
278 | pce->pce_header.header.type = htons(RI_TLV_PCE); | |
279 | pce->pce_header.header.length = htons(length); | |
32ab5cf4 | 280 | pce->enabled = true; |
d62a17ae | 281 | } else { |
282 | pce->pce_header.header.type = 0; | |
283 | pce->pce_header.header.length = 0; | |
32ab5cf4 | 284 | pce->enabled = false; |
d62a17ae | 285 | } |
286 | ||
287 | return length; | |
0ef4bcdc OD |
288 | } |
289 | ||
d62a17ae | 290 | static void set_pce_address(struct in_addr ipv4, struct ospf_pce_info *pce) |
0ef4bcdc OD |
291 | { |
292 | ||
d62a17ae | 293 | /* Enable PCE Info */ |
294 | pce->pce_header.header.type = htons(RI_TLV_PCE); | |
295 | /* Set PCE Address */ | |
296 | pce->pce_address.header.type = htons(RI_PCE_SUBTLV_ADDRESS); | |
297 | pce->pce_address.header.length = htons(PCE_ADDRESS_LENGTH_IPV4); | |
298 | pce->pce_address.address.type = htons(PCE_ADDRESS_TYPE_IPV4); | |
299 | pce->pce_address.address.value = ipv4; | |
0ef4bcdc | 300 | |
d62a17ae | 301 | return; |
0ef4bcdc OD |
302 | } |
303 | ||
d7c0a89a | 304 | static void set_pce_path_scope(uint32_t scope, struct ospf_pce_info *pce) |
0ef4bcdc OD |
305 | { |
306 | ||
d62a17ae | 307 | /* Set PCE Scope */ |
308 | pce->pce_scope.header.type = htons(RI_PCE_SUBTLV_PATH_SCOPE); | |
309 | pce->pce_scope.header.length = htons(RI_TLV_LENGTH); | |
310 | pce->pce_scope.value = htonl(scope); | |
0ef4bcdc | 311 | |
d62a17ae | 312 | return; |
0ef4bcdc OD |
313 | } |
314 | ||
d7c0a89a | 315 | static void set_pce_domain(uint16_t type, uint32_t domain, |
d62a17ae | 316 | struct ospf_pce_info *pce) |
0ef4bcdc OD |
317 | { |
318 | ||
d62a17ae | 319 | struct ri_pce_subtlv_domain *new; |
0ef4bcdc | 320 | |
d62a17ae | 321 | /* Create new domain info */ |
322 | new = XCALLOC(MTYPE_OSPF_PCE_PARAMS, | |
323 | sizeof(struct ri_pce_subtlv_domain)); | |
0ef4bcdc | 324 | |
d62a17ae | 325 | new->header.type = htons(RI_PCE_SUBTLV_DOMAIN); |
326 | new->header.length = htons(PCE_ADDRESS_LENGTH_IPV4); | |
327 | new->type = htons(type); | |
328 | new->value = htonl(domain); | |
0ef4bcdc | 329 | |
d62a17ae | 330 | /* Add new domain to the list */ |
331 | listnode_add(pce->pce_domain, new); | |
0ef4bcdc | 332 | |
d62a17ae | 333 | return; |
0ef4bcdc OD |
334 | } |
335 | ||
d7c0a89a | 336 | static void unset_pce_domain(uint16_t type, uint32_t domain, |
d62a17ae | 337 | struct ospf_pce_info *pce) |
0ef4bcdc | 338 | { |
d62a17ae | 339 | struct listnode *node; |
340 | struct ri_pce_subtlv_domain *old = NULL; | |
341 | int found = 0; | |
342 | ||
343 | /* Search the corresponding node */ | |
344 | for (ALL_LIST_ELEMENTS_RO(pce->pce_domain, node, old)) { | |
345 | if ((old->type == htons(type)) | |
346 | && (old->value == htonl(domain))) { | |
347 | found = 1; | |
348 | break; | |
349 | } | |
350 | } | |
351 | ||
352 | /* if found remove it */ | |
353 | if (found) { | |
354 | listnode_delete(pce->pce_domain, old); | |
355 | ||
d62a17ae | 356 | /* Finally free the old domain */ |
357 | XFREE(MTYPE_OSPF_PCE_PARAMS, old); | |
358 | } | |
0ef4bcdc OD |
359 | } |
360 | ||
d7c0a89a | 361 | static void set_pce_neighbor(uint16_t type, uint32_t domain, |
d62a17ae | 362 | struct ospf_pce_info *pce) |
0ef4bcdc OD |
363 | { |
364 | ||
d62a17ae | 365 | struct ri_pce_subtlv_neighbor *new; |
0ef4bcdc | 366 | |
d62a17ae | 367 | /* Create new neighbor info */ |
368 | new = XCALLOC(MTYPE_OSPF_PCE_PARAMS, | |
369 | sizeof(struct ri_pce_subtlv_neighbor)); | |
0ef4bcdc | 370 | |
d62a17ae | 371 | new->header.type = htons(RI_PCE_SUBTLV_NEIGHBOR); |
372 | new->header.length = htons(PCE_ADDRESS_LENGTH_IPV4); | |
373 | new->type = htons(type); | |
374 | new->value = htonl(domain); | |
0ef4bcdc | 375 | |
d62a17ae | 376 | /* Add new domain to the list */ |
377 | listnode_add(pce->pce_neighbor, new); | |
0ef4bcdc | 378 | |
d62a17ae | 379 | return; |
0ef4bcdc OD |
380 | } |
381 | ||
d7c0a89a | 382 | static void unset_pce_neighbor(uint16_t type, uint32_t domain, |
d62a17ae | 383 | struct ospf_pce_info *pce) |
0ef4bcdc | 384 | { |
d62a17ae | 385 | struct listnode *node; |
386 | struct ri_pce_subtlv_neighbor *old = NULL; | |
387 | int found = 0; | |
388 | ||
389 | /* Search the corresponding node */ | |
390 | for (ALL_LIST_ELEMENTS_RO(pce->pce_neighbor, node, old)) { | |
391 | if ((old->type == htons(type)) | |
392 | && (old->value == htonl(domain))) { | |
393 | found = 1; | |
394 | break; | |
395 | } | |
396 | } | |
397 | ||
398 | /* if found remove it */ | |
399 | if (found) { | |
400 | listnode_delete(pce->pce_neighbor, old); | |
401 | ||
d62a17ae | 402 | /* Finally free the old domain */ |
403 | XFREE(MTYPE_OSPF_PCE_PARAMS, old); | |
404 | } | |
0ef4bcdc OD |
405 | } |
406 | ||
d7c0a89a | 407 | static void set_pce_cap_flag(uint32_t cap, struct ospf_pce_info *pce) |
0ef4bcdc OD |
408 | { |
409 | ||
d62a17ae | 410 | /* Set PCE Capabilities flag */ |
411 | pce->pce_cap_flag.header.type = htons(RI_PCE_SUBTLV_CAP_FLAG); | |
412 | pce->pce_cap_flag.header.length = htons(RI_TLV_LENGTH); | |
413 | pce->pce_cap_flag.value = htonl(cap); | |
0ef4bcdc | 414 | |
d62a17ae | 415 | return; |
0ef4bcdc OD |
416 | } |
417 | ||
cf9b9f77 OD |
418 | /* Segment Routing TLV setter */ |
419 | ||
420 | /* Algorithm SubTLV - section 3.1 */ | |
93f0a26e | 421 | static void set_sr_algorithm(uint8_t algo) |
cf9b9f77 OD |
422 | { |
423 | ||
424 | OspfRI.sr_info.algo.value[0] = algo; | |
425 | for (int i = 1; i < ALGORITHM_COUNT; i++) | |
426 | OspfRI.sr_info.algo.value[i] = SR_ALGORITHM_UNSET; | |
427 | ||
428 | /* Set TLV type and length == only 1 Algorithm */ | |
429 | TLV_TYPE(OspfRI.sr_info.algo) = htons(RI_SR_TLV_SR_ALGORITHM); | |
93f0a26e | 430 | TLV_LEN(OspfRI.sr_info.algo) = htons(sizeof(uint8_t)); |
cf9b9f77 OD |
431 | } |
432 | ||
433 | /* unset Aglogithm SubTLV */ | |
93f0a26e | 434 | static void unset_sr_algorithm(uint8_t algo) |
cf9b9f77 OD |
435 | { |
436 | ||
437 | for (int i = 0; i < ALGORITHM_COUNT; i++) | |
438 | OspfRI.sr_info.algo.value[i] = SR_ALGORITHM_UNSET; | |
439 | ||
440 | /* Unset TLV type and length */ | |
441 | TLV_TYPE(OspfRI.sr_info.algo) = htons(0); | |
442 | TLV_LEN(OspfRI.sr_info.algo) = htons(0); | |
cf9b9f77 OD |
443 | } |
444 | ||
445 | /* Segment Routing Global Block SubTLV - section 3.2 */ | |
446 | static void set_sr_sid_label_range(struct sr_srgb srgb) | |
447 | { | |
448 | /* Set Header */ | |
449 | TLV_TYPE(OspfRI.sr_info.range) = htons(RI_SR_TLV_SID_LABEL_RANGE); | |
450 | TLV_LEN(OspfRI.sr_info.range) = | |
93f0a26e | 451 | htons(SUBTLV_SID_LABEL_SIZE + sizeof(uint32_t)); |
cf9b9f77 OD |
452 | /* Set Range Size */ |
453 | OspfRI.sr_info.range.size = htonl(SET_RANGE_SIZE(srgb.range_size)); | |
454 | /* Set Lower bound label SubTLV */ | |
455 | TLV_TYPE(OspfRI.sr_info.range.lower) = htons(SUBTLV_SID_LABEL); | |
456 | TLV_LEN(OspfRI.sr_info.range.lower) = htons(SID_RANGE_LABEL_LENGTH); | |
457 | OspfRI.sr_info.range.lower.value = htonl(SET_LABEL(srgb.lower_bound)); | |
cf9b9f77 OD |
458 | } |
459 | ||
460 | /* Unset this SRGB SubTLV */ | |
7743f2f8 | 461 | static void unset_sr_sid_label_range(void) |
cf9b9f77 OD |
462 | { |
463 | ||
464 | TLV_TYPE(OspfRI.sr_info.range) = htons(0); | |
465 | TLV_LEN(OspfRI.sr_info.range) = htons(0); | |
466 | TLV_TYPE(OspfRI.sr_info.range.lower) = htons(0); | |
467 | TLV_LEN(OspfRI.sr_info.range.lower) = htons(0); | |
cf9b9f77 OD |
468 | } |
469 | ||
470 | /* Set Maximum Stack Depth for this router */ | |
93f0a26e | 471 | static void set_sr_node_msd(uint8_t msd) |
cf9b9f77 OD |
472 | { |
473 | TLV_TYPE(OspfRI.sr_info.msd) = htons(RI_SR_TLV_NODE_MSD); | |
93f0a26e | 474 | TLV_LEN(OspfRI.sr_info.msd) = htons(sizeof(uint32_t)); |
cf9b9f77 | 475 | OspfRI.sr_info.msd.value = msd; |
cf9b9f77 OD |
476 | } |
477 | ||
478 | /* Unset this router MSD */ | |
7743f2f8 | 479 | static void unset_sr_node_msd(void) |
cf9b9f77 OD |
480 | { |
481 | TLV_TYPE(OspfRI.sr_info.msd) = htons(0); | |
482 | TLV_LEN(OspfRI.sr_info.msd) = htons(0); | |
cf9b9f77 | 483 | } |
0ef4bcdc | 484 | |
9ffaacb0 | 485 | static void unset_param(void *tlv_buffer) |
0ef4bcdc | 486 | { |
9ffaacb0 | 487 | struct tlv_header *tlv = (struct tlv_header *)tlv_buffer; |
0ef4bcdc | 488 | |
d62a17ae | 489 | tlv->type = 0; |
490 | /* Fill the Value to 0 */ | |
9ffaacb0 | 491 | memset(TLV_DATA(tlv_buffer), 0, TLV_BODY_SIZE(tlv)); |
d62a17ae | 492 | tlv->length = 0; |
0ef4bcdc | 493 | |
d62a17ae | 494 | return; |
0ef4bcdc OD |
495 | } |
496 | ||
d62a17ae | 497 | static void initialize_params(struct ospf_router_info *ori) |
0ef4bcdc | 498 | { |
d7c0a89a | 499 | uint32_t cap = 0; |
d62a17ae | 500 | struct ospf *top; |
ddd73a96 OD |
501 | struct listnode *node, *nnode; |
502 | struct ospf_area *area; | |
503 | struct ospf_ri_area_info *new; | |
d62a17ae | 504 | |
505 | /* | |
506 | * Initialize default Router Information Capabilities. | |
507 | */ | |
ead99d5f | 508 | cap = RI_TE_SUPPORT; |
d62a17ae | 509 | |
510 | set_router_info_capabilities(&ori->router_cap, cap); | |
511 | ||
512 | /* If Area address is not null and exist, retrieve corresponding | |
513 | * structure */ | |
b5a8894d | 514 | top = ospf_lookup_by_vrf_id(VRF_DEFAULT); |
ddd73a96 OD |
515 | zlog_info("RI (%s): Initialize Router Info for %s scope", __func__, |
516 | OspfRI.scope == OSPF_OPAQUE_AREA_LSA ? "Area" : "AS"); | |
d62a17ae | 517 | |
ddd73a96 OD |
518 | /* Try to get available Area's context from ospf at this step. |
519 | * Do it latter if not available */ | |
520 | if (OspfRI.scope == OSPF_OPAQUE_AREA_LSA) { | |
731271b0 OD |
521 | if (!list_isempty(OspfRI.area_info)) |
522 | list_delete_all_node(OspfRI.area_info); | |
ddd73a96 OD |
523 | for (ALL_LIST_ELEMENTS(top->areas, node, nnode, area)) { |
524 | zlog_debug("RI (%s): Add area %s to Router Information", | |
525 | __func__, inet_ntoa(area->area_id)); | |
526 | new = XCALLOC(MTYPE_OSPF_ROUTER_INFO, | |
527 | sizeof(struct ospf_ri_area_info)); | |
528 | new->area = area; | |
529 | new->flags = RIFLG_LSA_INACTIVE; | |
530 | listnode_add(OspfRI.area_info, new); | |
531 | } | |
532 | } | |
d62a17ae | 533 | |
534 | /* | |
535 | * Initialize default PCE Information values | |
536 | */ | |
537 | /* PCE address == OSPF Router ID */ | |
538 | set_pce_address(top->router_id, &ori->pce_info); | |
539 | ||
540 | /* PCE scope */ | |
541 | cap = 7; /* Set L, R and Rd bits to one = intra & inter-area path | |
542 | computation */ | |
543 | set_pce_path_scope(cap, &ori->pce_info); | |
544 | ||
545 | /* PCE Capabilities */ | |
546 | cap = PCE_CAP_BIDIRECTIONAL | PCE_CAP_DIVERSE_PATH | PCE_CAP_OBJECTIVES | |
547 | | PCE_CAP_ADDITIVE | PCE_CAP_MULTIPLE_REQ; | |
548 | set_pce_cap_flag(cap, &ori->pce_info); | |
549 | ||
d62a17ae | 550 | return; |
0ef4bcdc OD |
551 | } |
552 | ||
d62a17ae | 553 | static int is_mandated_params_set(struct ospf_router_info ori) |
0ef4bcdc | 554 | { |
d62a17ae | 555 | int rc = 0; |
0ef4bcdc | 556 | |
d62a17ae | 557 | if (ntohs(ori.router_cap.header.type) == 0) |
ead99d5f | 558 | return rc; |
0ef4bcdc | 559 | |
d62a17ae | 560 | if ((ntohs(ori.pce_info.pce_header.header.type) == RI_TLV_PCE) |
561 | && (ntohs(ori.pce_info.pce_address.header.type) == 0) | |
562 | && (ntohs(ori.pce_info.pce_cap_flag.header.type) == 0)) | |
ead99d5f | 563 | return rc; |
0ef4bcdc | 564 | |
cf9b9f77 OD |
565 | if ((ori.sr_info.enabled) && (ntohs(TLV_TYPE(ori.sr_info.algo)) == 0) |
566 | && (ntohs(TLV_TYPE(ori.sr_info.range)) == 0)) | |
567 | return rc; | |
568 | ||
d62a17ae | 569 | rc = 1; |
0ef4bcdc | 570 | |
d62a17ae | 571 | return rc; |
0ef4bcdc OD |
572 | } |
573 | ||
cf9b9f77 OD |
574 | /* |
575 | * Used by Segment Routing to set new TLVs and Sub-TLVs values | |
576 | * | |
577 | * @param enable To activate or not Segment Routing router Information flooding | |
578 | * @param size Size of Label Range i.e. SRGB size | |
579 | * @param lower Lower bound of the Label Range i.e. SRGB first label | |
0437e105 | 580 | * @param msd Maximum label Stack Depth supported by the router |
cf9b9f77 OD |
581 | * |
582 | * @return none | |
583 | */ | |
93f0a26e | 584 | void ospf_router_info_update_sr(bool enable, struct sr_srgb srgb, uint8_t msd) |
cf9b9f77 | 585 | { |
ddd73a96 OD |
586 | struct listnode *node, *nnode; |
587 | struct ospf_ri_area_info *ai; | |
588 | ||
589 | /* First, check if Router Information is registered or not */ | |
590 | if (!OspfRI.registered) | |
591 | ospf_router_info_register(OSPF_OPAQUE_AREA_LSA); | |
592 | ||
593 | /* Verify that scope is AREA */ | |
594 | if (OspfRI.scope != OSPF_OPAQUE_AREA_LSA) { | |
595 | zlog_err( | |
596 | "RI (%s): Router Info is %s flooding: Change scope to Area flooding for Segment Routing", | |
597 | __func__, | |
598 | OspfRI.scope == OSPF_OPAQUE_AREA_LSA ? "Area" : "AS"); | |
599 | return; | |
600 | } | |
cf9b9f77 | 601 | |
ddd73a96 | 602 | /* Then, activate and initialize Router Information if necessary */ |
cf9b9f77 OD |
603 | if (!OspfRI.enabled) { |
604 | OspfRI.enabled = true; | |
605 | initialize_params(&OspfRI); | |
606 | } | |
607 | ||
608 | if (IS_DEBUG_OSPF_SR) | |
ddd73a96 OD |
609 | zlog_debug("RI (%s): %s Routing Information for Segment Routing", |
610 | __func__, enable ? "Enable" : "Disable"); | |
cf9b9f77 OD |
611 | |
612 | /* Unset or Set SR parameters */ | |
613 | if (!enable) { | |
614 | unset_sr_algorithm(SR_ALGORITHM_SPF); | |
615 | unset_sr_sid_label_range(); | |
616 | unset_sr_node_msd(); | |
617 | OspfRI.sr_info.enabled = false; | |
618 | } else { | |
619 | // Only SR_ALGORITHM_SPF is supported | |
620 | set_sr_algorithm(SR_ALGORITHM_SPF); | |
621 | set_sr_sid_label_range(srgb); | |
622 | if (msd != 0) | |
623 | set_sr_node_msd(msd); | |
624 | else | |
625 | unset_sr_node_msd(); | |
626 | OspfRI.sr_info.enabled = true; | |
627 | } | |
628 | ||
629 | /* Refresh if already engaged or originate RI LSA */ | |
ddd73a96 OD |
630 | for (ALL_LIST_ELEMENTS(OspfRI.area_info, node, nnode, ai)) { |
631 | if (CHECK_FLAG(ai->flags, RIFLG_LSA_ENGAGED)) | |
632 | ospf_router_info_lsa_schedule(ai, REFRESH_THIS_LSA); | |
633 | else | |
634 | ospf_router_info_lsa_schedule(ai, | |
635 | REORIGINATE_THIS_LSA); | |
636 | ||
637 | } | |
cf9b9f77 OD |
638 | } |
639 | ||
0ef4bcdc OD |
640 | /*------------------------------------------------------------------------* |
641 | * Followings are callback functions against generic Opaque-LSAs handling. | |
642 | *------------------------------------------------------------------------*/ | |
d62a17ae | 643 | static void ospf_router_info_ism_change(struct ospf_interface *oi, |
644 | int old_state) | |
0ef4bcdc | 645 | { |
0ef4bcdc | 646 | |
ddd73a96 OD |
647 | struct ospf_ri_area_info *ai; |
648 | ||
649 | /* Collect area information */ | |
650 | ai = lookup_by_area(oi->area); | |
651 | ||
652 | /* Check if area is not yet registered */ | |
653 | if (ai != NULL) | |
654 | return; | |
655 | ||
656 | /* Add this new area to the list */ | |
657 | ai = XCALLOC(MTYPE_OSPF_ROUTER_INFO, sizeof(struct ospf_ri_area_info)); | |
658 | ai->area = oi->area; | |
659 | ai->flags = RIFLG_LSA_INACTIVE; | |
660 | listnode_add(OspfRI.area_info, ai); | |
661 | ||
d62a17ae | 662 | return; |
0ef4bcdc OD |
663 | } |
664 | ||
665 | /*------------------------------------------------------------------------* | |
666 | * Followings are OSPF protocol processing functions for ROUTER INFORMATION | |
667 | *------------------------------------------------------------------------*/ | |
668 | ||
ead99d5f | 669 | static void build_tlv_header(struct stream *s, struct tlv_header *tlvh) |
0ef4bcdc OD |
670 | { |
671 | ||
ead99d5f | 672 | stream_put(s, tlvh, sizeof(struct tlv_header)); |
d62a17ae | 673 | return; |
0ef4bcdc OD |
674 | } |
675 | ||
ead99d5f | 676 | static void build_tlv(struct stream *s, struct tlv_header *tlvh) |
0ef4bcdc OD |
677 | { |
678 | ||
d62a17ae | 679 | if (ntohs(tlvh->type) != 0) { |
680 | build_tlv_header(s, tlvh); | |
5d0df50f | 681 | stream_put(s, TLV_DATA(tlvh), TLV_BODY_SIZE(tlvh)); |
d62a17ae | 682 | } |
683 | return; | |
0ef4bcdc OD |
684 | } |
685 | ||
d62a17ae | 686 | static void ospf_router_info_lsa_body_set(struct stream *s) |
0ef4bcdc OD |
687 | { |
688 | ||
d62a17ae | 689 | struct listnode *node; |
690 | struct ri_pce_subtlv_domain *domain; | |
691 | struct ri_pce_subtlv_neighbor *neighbor; | |
0ef4bcdc | 692 | |
d62a17ae | 693 | /* Build Router Information TLV */ |
694 | build_tlv(s, &OspfRI.router_cap.header); | |
0ef4bcdc | 695 | |
cf9b9f77 OD |
696 | /* Build Segment Routing TLVs if enabled */ |
697 | if (OspfRI.sr_info.enabled) { | |
698 | /* Build Algorithm TLV */ | |
699 | build_tlv(s, &TLV_HDR(OspfRI.sr_info.algo)); | |
700 | /* Build SRGB TLV */ | |
701 | build_tlv(s, &TLV_HDR(OspfRI.sr_info.range)); | |
702 | /* Build MSD TLV */ | |
703 | build_tlv(s, &TLV_HDR(OspfRI.sr_info.msd)); | |
704 | } | |
ead99d5f OD |
705 | |
706 | /* Add RI PCE TLV if it is set */ | |
32ab5cf4 | 707 | if (OspfRI.pce_info.enabled) { |
0ef4bcdc | 708 | |
cf9b9f77 | 709 | /* Compute PCE Info header first */ |
996c9314 | 710 | set_pce_header(&OspfRI.pce_info); |
cf9b9f77 | 711 | |
d62a17ae | 712 | /* Build PCE TLV */ |
713 | build_tlv_header(s, &OspfRI.pce_info.pce_header.header); | |
0ef4bcdc | 714 | |
d62a17ae | 715 | /* Build PCE address sub-tlv */ |
716 | build_tlv(s, &OspfRI.pce_info.pce_address.header); | |
0ef4bcdc | 717 | |
d62a17ae | 718 | /* Build PCE path scope sub-tlv */ |
719 | build_tlv(s, &OspfRI.pce_info.pce_scope.header); | |
0ef4bcdc | 720 | |
d62a17ae | 721 | /* Build PCE domain sub-tlv */ |
722 | for (ALL_LIST_ELEMENTS_RO(OspfRI.pce_info.pce_domain, node, | |
723 | domain)) | |
724 | build_tlv(s, &domain->header); | |
0ef4bcdc | 725 | |
d62a17ae | 726 | /* Build PCE neighbor sub-tlv */ |
727 | for (ALL_LIST_ELEMENTS_RO(OspfRI.pce_info.pce_neighbor, node, | |
728 | neighbor)) | |
729 | build_tlv(s, &neighbor->header); | |
0ef4bcdc | 730 | |
d62a17ae | 731 | /* Build PCE cap flag sub-tlv */ |
732 | build_tlv(s, &OspfRI.pce_info.pce_cap_flag.header); | |
733 | } | |
0ef4bcdc | 734 | |
d62a17ae | 735 | return; |
0ef4bcdc OD |
736 | } |
737 | ||
738 | /* Create new opaque-LSA. */ | |
ddd73a96 | 739 | static struct ospf_lsa *ospf_router_info_lsa_new(struct ospf_area *area) |
0ef4bcdc | 740 | { |
d62a17ae | 741 | struct ospf *top; |
742 | struct stream *s; | |
743 | struct lsa_header *lsah; | |
744 | struct ospf_lsa *new = NULL; | |
d7c0a89a | 745 | uint8_t options, lsa_type; |
d62a17ae | 746 | struct in_addr lsa_id; |
d7c0a89a QY |
747 | uint32_t tmp; |
748 | uint16_t length; | |
d62a17ae | 749 | |
750 | /* Create a stream for LSA. */ | |
266469eb DS |
751 | s = stream_new(OSPF_MAX_LSA_SIZE); |
752 | ||
d62a17ae | 753 | lsah = (struct lsa_header *)STREAM_DATA(s); |
754 | ||
755 | options = OSPF_OPTION_E; /* Enable AS external as we flood RI with | |
756 | Opaque Type 11 */ | |
757 | options |= OSPF_OPTION_O; /* Don't forget this :-) */ | |
758 | ||
759 | lsa_type = OspfRI.scope; | |
760 | /* LSA ID == 0 for Router Information see RFC 4970 */ | |
761 | tmp = SET_OPAQUE_LSID(OPAQUE_TYPE_ROUTER_INFORMATION_LSA, 0); | |
762 | lsa_id.s_addr = htonl(tmp); | |
763 | ||
764 | if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) | |
765 | zlog_debug( | |
766 | "LSA[Type%d:%s]: Create an Opaque-LSA/ROUTER INFORMATION instance", | |
767 | lsa_type, inet_ntoa(lsa_id)); | |
768 | ||
b5a8894d | 769 | top = ospf_lookup_by_vrf_id(VRF_DEFAULT); |
d62a17ae | 770 | |
771 | /* Set opaque-LSA header fields. */ | |
772 | lsa_header_set(s, options, lsa_type, lsa_id, top->router_id); | |
773 | ||
774 | /* Set opaque-LSA body fields. */ | |
775 | ospf_router_info_lsa_body_set(s); | |
776 | ||
777 | /* Set length. */ | |
778 | length = stream_get_endp(s); | |
779 | lsah->length = htons(length); | |
780 | ||
781 | /* Now, create an OSPF LSA instance. */ | |
5b3d4186 | 782 | new = ospf_lsa_new_and_data(length); |
d62a17ae | 783 | |
ddd73a96 | 784 | new->area = area; |
d62a17ae | 785 | |
b5a8894d CS |
786 | if (new->area && new->area->ospf) |
787 | new->vrf_id = new->area->ospf->vrf_id; | |
788 | else | |
789 | new->vrf_id = VRF_DEFAULT; | |
790 | ||
d62a17ae | 791 | SET_FLAG(new->flags, OSPF_LSA_SELF); |
792 | memcpy(new->data, lsah, length); | |
793 | stream_free(s); | |
794 | ||
d62a17ae | 795 | return new; |
0ef4bcdc OD |
796 | } |
797 | ||
ddd73a96 | 798 | static int ospf_router_info_lsa_originate_as(void *arg) |
0ef4bcdc | 799 | { |
d62a17ae | 800 | struct ospf_lsa *new; |
801 | struct ospf *top; | |
d62a17ae | 802 | int rc = -1; |
b5a8894d | 803 | vrf_id_t vrf_id = VRF_DEFAULT; |
d62a17ae | 804 | |
ddd73a96 | 805 | /* Sanity Check */ |
d62a17ae | 806 | if (OspfRI.scope == OSPF_OPAQUE_AREA_LSA) { |
ddd73a96 OD |
807 | flog_warn( |
808 | EC_OSPF_LSA_INSTALL_FAILURE, | |
809 | "RI (%s): wrong flooding scope AREA instead of AS ?", | |
810 | __func__); | |
811 | return rc; | |
d62a17ae | 812 | } |
813 | ||
814 | /* Create new Opaque-LSA/ROUTER INFORMATION instance. */ | |
ddd73a96 OD |
815 | new = ospf_router_info_lsa_new(NULL); |
816 | new->vrf_id = VRF_DEFAULT; | |
817 | top = (struct ospf *)arg; | |
d62a17ae | 818 | |
ddd73a96 | 819 | /* Check ospf info */ |
b5a8894d | 820 | if (top == NULL) { |
ddd73a96 OD |
821 | zlog_debug("RI (%s): ospf instance not found for vrf id %u", |
822 | __func__, vrf_id); | |
c2a2f37b | 823 | ospf_lsa_unlock(&new); |
b5a8894d CS |
824 | return rc; |
825 | } | |
d62a17ae | 826 | |
827 | /* Install this LSA into LSDB. */ | |
828 | if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) { | |
542a208f | 829 | flog_warn( |
cf444bcf | 830 | EC_OSPF_LSA_INSTALL_FAILURE, |
ddd73a96 OD |
831 | "RI (%s): ospf_lsa_install() ?", __func__); |
832 | ospf_lsa_unlock(&new); | |
833 | return rc; | |
834 | } | |
835 | ||
836 | /* Update new LSA origination count. */ | |
837 | top->lsa_originate_count++; | |
838 | ||
839 | /* Flood new LSA through AREA or AS. */ | |
840 | SET_FLAG(OspfRI.as_flags, RIFLG_LSA_ENGAGED); | |
841 | ospf_flood_through_as(top, NULL /*nbr */, new); | |
842 | ||
843 | if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) { | |
844 | zlog_debug( | |
845 | "LSA[Type%d:%s]: Originate Opaque-LSA/ROUTER INFORMATION", | |
846 | new->data->type, inet_ntoa(new->data->id)); | |
847 | ospf_lsa_header_dump(new->data); | |
848 | } | |
849 | ||
850 | rc = 0; | |
851 | return rc; | |
852 | } | |
853 | ||
854 | static int ospf_router_info_lsa_originate_area(void *arg) | |
855 | { | |
856 | struct ospf_lsa *new; | |
857 | struct ospf *top; | |
858 | struct ospf_ri_area_info *ai = NULL; | |
859 | int rc = -1; | |
860 | vrf_id_t vrf_id = VRF_DEFAULT; | |
861 | ||
862 | /* Sanity Check */ | |
863 | if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) { | |
864 | flog_warn( | |
865 | EC_OSPF_LSA_INSTALL_FAILURE, | |
866 | "RI (%s): wrong flooding scope AS instead of AREA ?", | |
867 | __func__); | |
868 | return rc; | |
869 | } | |
870 | ||
871 | /* Create new Opaque-LSA/ROUTER INFORMATION instance. */ | |
872 | ai = lookup_by_area((struct ospf_area *)arg); | |
873 | if (ai == NULL) { | |
874 | zlog_debug( | |
875 | "RI (%s): There is no context for this Router Information. Stop processing", | |
876 | __func__); | |
877 | return rc; | |
878 | } | |
879 | if (ai->area->ospf) { | |
880 | vrf_id = ai->area->ospf->vrf_id; | |
881 | top = ai->area->ospf; | |
882 | } else { | |
883 | top = ospf_lookup_by_vrf_id(vrf_id); | |
884 | } | |
885 | new = ospf_router_info_lsa_new(ai->area); | |
886 | new->vrf_id = vrf_id; | |
887 | ||
888 | /* Check ospf info */ | |
889 | if (top == NULL) { | |
890 | zlog_debug("RI (%s): ospf instance not found for vrf id %u", | |
891 | __func__, vrf_id); | |
d62a17ae | 892 | ospf_lsa_unlock(&new); |
ead99d5f | 893 | return rc; |
d62a17ae | 894 | } |
895 | ||
ddd73a96 OD |
896 | /* Install this LSA into LSDB. */ |
897 | if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) { | |
898 | flog_warn( | |
899 | EC_OSPF_LSA_INSTALL_FAILURE, | |
900 | "RI (%s): ospf_lsa_install() ?", __func__); | |
901 | ospf_lsa_unlock(&new); | |
902 | return rc; | |
903 | } | |
d62a17ae | 904 | |
905 | /* Update new LSA origination count. */ | |
906 | top->lsa_originate_count++; | |
907 | ||
ddd73a96 OD |
908 | /* Flood new LSA through AREA or AS. */ |
909 | SET_FLAG(ai->flags, RIFLG_LSA_ENGAGED); | |
910 | ospf_flood_through_area(ai->area, NULL /*nbr */, new); | |
d62a17ae | 911 | |
912 | if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) { | |
913 | zlog_debug( | |
914 | "LSA[Type%d:%s]: Originate Opaque-LSA/ROUTER INFORMATION", | |
915 | new->data->type, inet_ntoa(new->data->id)); | |
916 | ospf_lsa_header_dump(new->data); | |
917 | } | |
918 | ||
919 | rc = 0; | |
d62a17ae | 920 | return rc; |
0ef4bcdc OD |
921 | } |
922 | ||
d62a17ae | 923 | static int ospf_router_info_lsa_originate(void *arg) |
0ef4bcdc OD |
924 | { |
925 | ||
ddd73a96 | 926 | struct ospf_ri_area_info *ai; |
d62a17ae | 927 | int rc = -1; |
928 | ||
32ab5cf4 | 929 | if (!OspfRI.enabled) { |
ddd73a96 OD |
930 | zlog_info("RI (%s): ROUTER INFORMATION is disabled now.", |
931 | __func__); | |
d62a17ae | 932 | rc = 0; /* This is not an error case. */ |
ead99d5f | 933 | return rc; |
d62a17ae | 934 | } |
935 | ||
936 | /* Check if Router Information LSA is already engaged */ | |
ddd73a96 OD |
937 | if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) { |
938 | if ((CHECK_FLAG(OspfRI.as_flags, RIFLG_LSA_ENGAGED)) | |
939 | && (CHECK_FLAG(OspfRI.as_flags, | |
940 | RIFLG_LSA_FORCED_REFRESH))) { | |
941 | UNSET_FLAG(OspfRI.as_flags, RIFLG_LSA_FORCED_REFRESH); | |
942 | ospf_router_info_lsa_schedule(NULL, REFRESH_THIS_LSA); | |
943 | rc = 0; | |
944 | return rc; | |
d62a17ae | 945 | } |
946 | } else { | |
ddd73a96 OD |
947 | ai = lookup_by_area((struct ospf_area *)arg); |
948 | if (ai == NULL) { | |
239697e3 | 949 | flog_warn( |
cf444bcf | 950 | EC_OSPF_LSA, |
ddd73a96 | 951 | "RI (%s): Missing area information", __func__); |
ead99d5f | 952 | return rc; |
ddd73a96 OD |
953 | } |
954 | if ((CHECK_FLAG(ai->flags, RIFLG_LSA_ENGAGED)) | |
955 | && (CHECK_FLAG(ai->flags, RIFLG_LSA_FORCED_REFRESH))) { | |
956 | UNSET_FLAG(ai->flags, RIFLG_LSA_FORCED_REFRESH); | |
957 | ospf_router_info_lsa_schedule(ai, REFRESH_THIS_LSA); | |
958 | rc = 0; | |
959 | return rc; | |
960 | } | |
d62a17ae | 961 | } |
962 | ||
ddd73a96 OD |
963 | /* Router Information is not yet Engaged, check parameters */ |
964 | if (!is_mandated_params_set(OspfRI)) | |
965 | flog_warn( | |
966 | EC_OSPF_LSA, | |
967 | "RI (%s): lacks mandated ROUTER INFORMATION parameters", | |
968 | __func__); | |
969 | ||
970 | /* Ok, let's try to originate an LSA */ | |
971 | if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) | |
972 | rc = ospf_router_info_lsa_originate_as(arg); | |
973 | else | |
974 | rc = ospf_router_info_lsa_originate_area(arg); | |
975 | ||
d62a17ae | 976 | return rc; |
0ef4bcdc OD |
977 | } |
978 | ||
d62a17ae | 979 | static struct ospf_lsa *ospf_router_info_lsa_refresh(struct ospf_lsa *lsa) |
0ef4bcdc | 980 | { |
ddd73a96 | 981 | struct ospf_ri_area_info *ai = NULL; |
d62a17ae | 982 | struct ospf_lsa *new = NULL; |
983 | struct ospf *top; | |
984 | ||
32ab5cf4 | 985 | if (!OspfRI.enabled) { |
d62a17ae | 986 | /* |
987 | * This LSA must have flushed before due to ROUTER INFORMATION | |
988 | * status change. | |
989 | * It seems a slip among routers in the routing domain. | |
990 | */ | |
ddd73a96 OD |
991 | zlog_info("RI (%s): ROUTER INFORMATION is disabled now.", |
992 | __func__); | |
d62a17ae | 993 | lsa->data->ls_age = |
994 | htons(OSPF_LSA_MAXAGE); /* Flush it anyway. */ | |
995 | } | |
996 | ||
997 | /* Verify that the Router Information ID is supported */ | |
998 | if (GET_OPAQUE_ID(ntohl(lsa->data->id.s_addr)) != 0) { | |
239697e3 | 999 | flog_warn( |
cf444bcf | 1000 | EC_OSPF_LSA, |
ddd73a96 OD |
1001 | "RI (%s): Unsupported Router Information ID", |
1002 | __func__); | |
ead99d5f | 1003 | return NULL; |
d62a17ae | 1004 | } |
1005 | ||
ddd73a96 OD |
1006 | /* Process LSA depending of the flooding scope */ |
1007 | if (OspfRI.scope == OSPF_OPAQUE_AREA_LSA) { | |
1008 | /* Get context AREA context */ | |
1009 | ai = lookup_by_area(lsa->area); | |
1010 | if (ai == NULL) { | |
1011 | flog_warn( | |
1012 | EC_OSPF_LSA, | |
1013 | "RI (%s): No associated Area", __func__); | |
1014 | return NULL; | |
1015 | } | |
1016 | /* Flush LSA, if the lsa's age reached to MaxAge. */ | |
1017 | if (IS_LSA_MAXAGE(lsa)) { | |
1018 | UNSET_FLAG(ai->flags, RIFLG_LSA_ENGAGED); | |
1019 | ospf_opaque_lsa_flush_schedule(lsa); | |
1020 | return NULL; | |
1021 | } | |
1022 | /* Create new Opaque-LSA/ROUTER INFORMATION instance. */ | |
1023 | new = ospf_router_info_lsa_new(ai->area); | |
1024 | new->data->ls_seqnum = lsa_seqnum_increment(lsa); | |
1025 | new->vrf_id = lsa->vrf_id; | |
1026 | /* Install this LSA into LSDB. */ | |
1027 | /* Given "lsa" will be freed in the next function. */ | |
1028 | top = ospf_lookup_by_vrf_id(lsa->vrf_id); | |
1029 | if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) { | |
1030 | flog_warn(EC_OSPF_LSA_INSTALL_FAILURE, | |
1031 | "RI (%s): ospf_lsa_install() ?", __func__); | |
1032 | ospf_lsa_unlock(&new); | |
1033 | return new; | |
1034 | } | |
1035 | /* Flood updated LSA through AREA */ | |
1036 | ospf_flood_through_area(ai->area, NULL /*nbr */, new); | |
1037 | ||
1038 | } else { /* AS Flooding scope */ | |
1039 | /* Flush LSA, if the lsa's age reached to MaxAge. */ | |
1040 | if (IS_LSA_MAXAGE(lsa)) { | |
1041 | UNSET_FLAG(OspfRI.as_flags, RIFLG_LSA_ENGAGED); | |
1042 | ospf_opaque_lsa_flush_schedule(lsa); | |
1043 | return NULL; | |
1044 | } | |
1045 | /* Create new Opaque-LSA/ROUTER INFORMATION instance. */ | |
1046 | new = ospf_router_info_lsa_new(NULL); | |
1047 | new->data->ls_seqnum = lsa_seqnum_increment(lsa); | |
1048 | new->vrf_id = lsa->vrf_id; | |
1049 | /* Install this LSA into LSDB. */ | |
1050 | /* Given "lsa" will be freed in the next function. */ | |
1051 | top = ospf_lookup_by_vrf_id(lsa->vrf_id); | |
1052 | if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) { | |
1053 | flog_warn(EC_OSPF_LSA_INSTALL_FAILURE, | |
1054 | "RI (%s): ospf_lsa_install() ?", __func__); | |
1055 | ospf_lsa_unlock(&new); | |
1056 | return new; | |
1057 | } | |
1058 | /* Flood updated LSA through AS */ | |
d62a17ae | 1059 | ospf_flood_through_as(top, NULL /*nbr */, new); |
ddd73a96 | 1060 | } |
d62a17ae | 1061 | |
1062 | /* Debug logging. */ | |
1063 | if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) { | |
1064 | zlog_debug( | |
1065 | "LSA[Type%d:%s]: Refresh Opaque-LSA/ROUTER INFORMATION", | |
1066 | new->data->type, inet_ntoa(new->data->id)); | |
1067 | ospf_lsa_header_dump(new->data); | |
1068 | } | |
1069 | ||
d62a17ae | 1070 | return new; |
0ef4bcdc OD |
1071 | } |
1072 | ||
ddd73a96 OD |
1073 | static void ospf_router_info_lsa_schedule(struct ospf_ri_area_info *ai, |
1074 | enum lsa_opcode opcode) | |
0ef4bcdc | 1075 | { |
d62a17ae | 1076 | struct ospf_lsa lsa; |
1077 | struct lsa_header lsah; | |
1078 | struct ospf *top; | |
d7c0a89a | 1079 | uint32_t tmp; |
d62a17ae | 1080 | |
1081 | memset(&lsa, 0, sizeof(lsa)); | |
1082 | memset(&lsah, 0, sizeof(lsah)); | |
1083 | ||
ddd73a96 | 1084 | zlog_debug("RI (%s): LSA schedule %s%s%s", __func__, |
d62a17ae | 1085 | opcode == REORIGINATE_THIS_LSA ? "Re-Originate" : "", |
1086 | opcode == REFRESH_THIS_LSA ? "Refresh" : "", | |
1087 | opcode == FLUSH_THIS_LSA ? "Flush" : ""); | |
1088 | ||
ddd73a96 OD |
1089 | /* Check LSA flags state coherence and collect area information */ |
1090 | if (OspfRI.scope == OSPF_OPAQUE_AREA_LSA) { | |
1091 | if ((ai == NULL) || (ai->area == NULL)) { | |
1092 | flog_warn( | |
1093 | EC_OSPF_LSA, | |
1094 | "RI (%s): Router Info is Area scope flooding but area is not set", | |
1095 | __func__); | |
1096 | return; | |
1097 | } | |
ead99d5f | 1098 | |
ddd73a96 OD |
1099 | if (!CHECK_FLAG(ai->flags, RIFLG_LSA_ENGAGED) |
1100 | && (opcode != REORIGINATE_THIS_LSA)) | |
1101 | return; | |
ead99d5f | 1102 | |
ddd73a96 OD |
1103 | if (CHECK_FLAG(ai->flags, RIFLG_LSA_ENGAGED) |
1104 | && (opcode == REORIGINATE_THIS_LSA)) | |
1105 | opcode = REFRESH_THIS_LSA; | |
1106 | ||
1107 | lsa.area = ai->area; | |
1108 | top = ai->area->ospf; | |
1109 | } else { | |
1110 | if (!CHECK_FLAG(OspfRI.as_flags, RIFLG_LSA_ENGAGED) | |
1111 | && (opcode != REORIGINATE_THIS_LSA)) | |
1112 | return; | |
1113 | ||
1114 | if (CHECK_FLAG(OspfRI.as_flags, RIFLG_LSA_ENGAGED) | |
1115 | && (opcode == REORIGINATE_THIS_LSA)) | |
1116 | opcode = REFRESH_THIS_LSA; | |
1117 | ||
1118 | top = ospf_lookup_by_vrf_id(VRF_DEFAULT); | |
1119 | lsa.area = NULL; | |
d62a17ae | 1120 | } |
ddd73a96 | 1121 | |
d62a17ae | 1122 | lsa.data = &lsah; |
1123 | lsah.type = OspfRI.scope; | |
1124 | ||
1125 | /* LSA ID is set to 0 for the Router Information. See RFC 4970 */ | |
1126 | tmp = SET_OPAQUE_LSID(OPAQUE_TYPE_ROUTER_INFORMATION_LSA, 0); | |
1127 | lsah.id.s_addr = htonl(tmp); | |
1128 | ||
1129 | switch (opcode) { | |
1130 | case REORIGINATE_THIS_LSA: | |
1131 | if (OspfRI.scope == OSPF_OPAQUE_AREA_LSA) | |
1132 | ospf_opaque_lsa_reoriginate_schedule( | |
ddd73a96 | 1133 | (void *)ai->area, OSPF_OPAQUE_AREA_LSA, |
d62a17ae | 1134 | OPAQUE_TYPE_ROUTER_INFORMATION_LSA); |
1135 | else | |
1136 | ospf_opaque_lsa_reoriginate_schedule( | |
1137 | (void *)top, OSPF_OPAQUE_AS_LSA, | |
1138 | OPAQUE_TYPE_ROUTER_INFORMATION_LSA); | |
1139 | break; | |
1140 | case REFRESH_THIS_LSA: | |
1141 | ospf_opaque_lsa_refresh_schedule(&lsa); | |
1142 | break; | |
1143 | case FLUSH_THIS_LSA: | |
ddd73a96 OD |
1144 | if (OspfRI.scope == OSPF_OPAQUE_AREA_LSA) |
1145 | UNSET_FLAG(ai->flags, RIFLG_LSA_ENGAGED); | |
1146 | else | |
1147 | UNSET_FLAG(OspfRI.as_flags, RIFLG_LSA_ENGAGED); | |
d62a17ae | 1148 | ospf_opaque_lsa_flush_schedule(&lsa); |
1149 | break; | |
d62a17ae | 1150 | } |
1151 | ||
1152 | return; | |
0ef4bcdc OD |
1153 | } |
1154 | ||
cf9b9f77 OD |
1155 | /* Callback to handle Segment Routing information */ |
1156 | static int ospf_router_info_lsa_update(struct ospf_lsa *lsa) | |
1157 | { | |
1158 | ||
1159 | /* Sanity Check */ | |
1160 | if (lsa == NULL) { | |
ddd73a96 | 1161 | flog_warn(EC_OSPF_LSA, "RI (%s): Abort! LSA is NULL", |
239697e3 | 1162 | __func__); |
cf9b9f77 OD |
1163 | return -1; |
1164 | } | |
1165 | ||
6aaf0fdd OD |
1166 | /* Process only Opaque LSA */ |
1167 | if ((lsa->data->type != OSPF_OPAQUE_AREA_LSA) | |
1168 | && (lsa->data->type != OSPF_OPAQUE_AS_LSA)) | |
cf9b9f77 OD |
1169 | return 0; |
1170 | ||
1171 | /* Process only Router Information LSA */ | |
996c9314 LB |
1172 | if (GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr)) |
1173 | != OPAQUE_TYPE_ROUTER_INFORMATION_LSA) | |
cf9b9f77 OD |
1174 | return 0; |
1175 | ||
6aaf0fdd OD |
1176 | /* Check if it is not my LSA */ |
1177 | if (IS_LSA_SELF(lsa)) | |
1178 | return 0; | |
1179 | ||
cf9b9f77 OD |
1180 | /* Check if Router Info & Segment Routing are enable */ |
1181 | if (!OspfRI.enabled || !OspfRI.sr_info.enabled) | |
1182 | return 0; | |
1183 | ||
1184 | /* Call Segment Routing LSA update or deletion */ | |
1185 | if (!IS_LSA_MAXAGE(lsa)) | |
1186 | ospf_sr_ri_lsa_update(lsa); | |
1187 | else | |
1188 | ospf_sr_ri_lsa_delete(lsa); | |
1189 | ||
1190 | return 0; | |
1191 | } | |
1192 | ||
0ef4bcdc OD |
1193 | /*------------------------------------------------------------------------* |
1194 | * Followings are vty session control functions. | |
1195 | *------------------------------------------------------------------------*/ | |
1196 | ||
d7c0a89a | 1197 | static uint16_t show_vty_router_cap(struct vty *vty, struct tlv_header *tlvh) |
0ef4bcdc | 1198 | { |
d62a17ae | 1199 | struct ri_tlv_router_cap *top = (struct ri_tlv_router_cap *)tlvh; |
0ef4bcdc | 1200 | |
d62a17ae | 1201 | if (vty != NULL) |
1202 | vty_out(vty, " Router Capabilities: 0x%x\n", | |
1203 | ntohl(top->value)); | |
1204 | else | |
1205 | zlog_debug(" Router Capabilities: 0x%x", ntohl(top->value)); | |
0ef4bcdc | 1206 | |
ead99d5f | 1207 | return TLV_SIZE(tlvh); |
0ef4bcdc OD |
1208 | } |
1209 | ||
d7c0a89a QY |
1210 | static uint16_t show_vty_pce_subtlv_address(struct vty *vty, |
1211 | struct tlv_header *tlvh) | |
0ef4bcdc | 1212 | { |
d62a17ae | 1213 | struct ri_pce_subtlv_address *top = |
1214 | (struct ri_pce_subtlv_address *)tlvh; | |
1215 | ||
1216 | if (ntohs(top->address.type) == PCE_ADDRESS_TYPE_IPV4) { | |
1217 | if (vty != NULL) | |
1218 | vty_out(vty, " PCE Address: %s\n", | |
1219 | inet_ntoa(top->address.value)); | |
1220 | else | |
1221 | zlog_debug(" PCE Address: %s", | |
1222 | inet_ntoa(top->address.value)); | |
1223 | } else { | |
1224 | /* TODO: Add support to IPv6 with inet_ntop() */ | |
1225 | if (vty != NULL) | |
1226 | vty_out(vty, " PCE Address: 0x%x\n", | |
1227 | ntohl(top->address.value.s_addr)); | |
1228 | else | |
1229 | zlog_debug(" PCE Address: 0x%x", | |
1230 | ntohl(top->address.value.s_addr)); | |
1231 | } | |
1232 | ||
ead99d5f | 1233 | return TLV_SIZE(tlvh); |
0ef4bcdc OD |
1234 | } |
1235 | ||
d7c0a89a QY |
1236 | static uint16_t show_vty_pce_subtlv_path_scope(struct vty *vty, |
1237 | struct tlv_header *tlvh) | |
0ef4bcdc | 1238 | { |
d62a17ae | 1239 | struct ri_pce_subtlv_path_scope *top = |
1240 | (struct ri_pce_subtlv_path_scope *)tlvh; | |
0ef4bcdc | 1241 | |
d62a17ae | 1242 | if (vty != NULL) |
1243 | vty_out(vty, " PCE Path Scope: 0x%x\n", ntohl(top->value)); | |
1244 | else | |
1245 | zlog_debug(" PCE Path Scope: 0x%x", ntohl(top->value)); | |
0ef4bcdc | 1246 | |
ead99d5f | 1247 | return TLV_SIZE(tlvh); |
0ef4bcdc OD |
1248 | } |
1249 | ||
d7c0a89a QY |
1250 | static uint16_t show_vty_pce_subtlv_domain(struct vty *vty, |
1251 | struct tlv_header *tlvh) | |
0ef4bcdc | 1252 | { |
d62a17ae | 1253 | struct ri_pce_subtlv_domain *top = (struct ri_pce_subtlv_domain *)tlvh; |
1254 | struct in_addr tmp; | |
1255 | ||
1256 | if (ntohs(top->type) == PCE_DOMAIN_TYPE_AREA) { | |
1257 | tmp.s_addr = top->value; | |
1258 | if (vty != NULL) | |
1259 | vty_out(vty, " PCE domain Area: %s\n", inet_ntoa(tmp)); | |
1260 | else | |
1261 | zlog_debug(" PCE domain Area: %s", inet_ntoa(tmp)); | |
1262 | } else { | |
1263 | if (vty != NULL) | |
1264 | vty_out(vty, " PCE domain AS: %d\n", | |
1265 | ntohl(top->value)); | |
1266 | else | |
1267 | zlog_debug(" PCE domain AS: %d", ntohl(top->value)); | |
1268 | } | |
ead99d5f | 1269 | return TLV_SIZE(tlvh); |
0ef4bcdc OD |
1270 | } |
1271 | ||
d7c0a89a QY |
1272 | static uint16_t show_vty_pce_subtlv_neighbor(struct vty *vty, |
1273 | struct tlv_header *tlvh) | |
0ef4bcdc OD |
1274 | { |
1275 | ||
d62a17ae | 1276 | struct ri_pce_subtlv_neighbor *top = |
1277 | (struct ri_pce_subtlv_neighbor *)tlvh; | |
1278 | struct in_addr tmp; | |
1279 | ||
1280 | if (ntohs(top->type) == PCE_DOMAIN_TYPE_AREA) { | |
1281 | tmp.s_addr = top->value; | |
1282 | if (vty != NULL) | |
1283 | vty_out(vty, " PCE neighbor Area: %s\n", | |
1284 | inet_ntoa(tmp)); | |
1285 | else | |
1286 | zlog_debug(" PCE neighbor Area: %s", inet_ntoa(tmp)); | |
1287 | } else { | |
1288 | if (vty != NULL) | |
1289 | vty_out(vty, " PCE neighbor AS: %d\n", | |
1290 | ntohl(top->value)); | |
1291 | else | |
1292 | zlog_debug(" PCE neighbor AS: %d", | |
1293 | ntohl(top->value)); | |
1294 | } | |
ead99d5f | 1295 | return TLV_SIZE(tlvh); |
0ef4bcdc OD |
1296 | } |
1297 | ||
d7c0a89a QY |
1298 | static uint16_t show_vty_pce_subtlv_cap_flag(struct vty *vty, |
1299 | struct tlv_header *tlvh) | |
0ef4bcdc | 1300 | { |
d62a17ae | 1301 | struct ri_pce_subtlv_cap_flag *top = |
1302 | (struct ri_pce_subtlv_cap_flag *)tlvh; | |
0ef4bcdc | 1303 | |
d62a17ae | 1304 | if (vty != NULL) |
1305 | vty_out(vty, " PCE Capabilities Flag: 0x%x\n", | |
1306 | ntohl(top->value)); | |
1307 | else | |
1308 | zlog_debug(" PCE Capabilities Flag: 0x%x", | |
1309 | ntohl(top->value)); | |
0ef4bcdc | 1310 | |
ead99d5f | 1311 | return TLV_SIZE(tlvh); |
0ef4bcdc OD |
1312 | } |
1313 | ||
d7c0a89a | 1314 | static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh) |
0ef4bcdc | 1315 | { |
d62a17ae | 1316 | if (vty != NULL) |
1317 | vty_out(vty, " Unknown TLV: [type(0x%x), length(0x%x)]\n", | |
1318 | ntohs(tlvh->type), ntohs(tlvh->length)); | |
1319 | else | |
1320 | zlog_debug(" Unknown TLV: [type(0x%x), length(0x%x)]", | |
1321 | ntohs(tlvh->type), ntohs(tlvh->length)); | |
1322 | ||
ead99d5f | 1323 | return TLV_SIZE(tlvh); |
0ef4bcdc OD |
1324 | } |
1325 | ||
d7c0a89a QY |
1326 | static uint16_t show_vty_pce_info(struct vty *vty, struct tlv_header *ri, |
1327 | uint32_t total) | |
0ef4bcdc | 1328 | { |
ead99d5f | 1329 | struct tlv_header *tlvh; |
d7c0a89a | 1330 | uint16_t sum = 0; |
d62a17ae | 1331 | |
ead99d5f | 1332 | for (tlvh = ri; sum < total; tlvh = TLV_HDR_NEXT(tlvh)) { |
d62a17ae | 1333 | switch (ntohs(tlvh->type)) { |
1334 | case RI_PCE_SUBTLV_ADDRESS: | |
1335 | sum += show_vty_pce_subtlv_address(vty, tlvh); | |
1336 | break; | |
1337 | case RI_PCE_SUBTLV_PATH_SCOPE: | |
1338 | sum += show_vty_pce_subtlv_path_scope(vty, tlvh); | |
1339 | break; | |
1340 | case RI_PCE_SUBTLV_DOMAIN: | |
1341 | sum += show_vty_pce_subtlv_domain(vty, tlvh); | |
1342 | break; | |
1343 | case RI_PCE_SUBTLV_NEIGHBOR: | |
1344 | sum += show_vty_pce_subtlv_neighbor(vty, tlvh); | |
1345 | break; | |
1346 | case RI_PCE_SUBTLV_CAP_FLAG: | |
1347 | sum += show_vty_pce_subtlv_cap_flag(vty, tlvh); | |
1348 | break; | |
1349 | default: | |
1350 | sum += show_vty_unknown_tlv(vty, tlvh); | |
1351 | break; | |
1352 | } | |
1353 | } | |
1354 | return sum; | |
0ef4bcdc OD |
1355 | } |
1356 | ||
cf9b9f77 | 1357 | /* Display Segment Routing Algorithm TLV information */ |
93f0a26e | 1358 | static uint16_t show_vty_sr_algorithm(struct vty *vty, struct tlv_header *tlvh) |
cf9b9f77 OD |
1359 | { |
1360 | struct ri_sr_tlv_sr_algorithm *algo = | |
1361 | (struct ri_sr_tlv_sr_algorithm *)tlvh; | |
1362 | int i; | |
7743f2f8 | 1363 | |
cf9b9f77 OD |
1364 | if (vty != NULL) { |
1365 | vty_out(vty, " Segment Routing Algorithm TLV:\n"); | |
1366 | for (i = 0; i < ntohs(algo->header.length); i++) { | |
1367 | switch (algo->value[i]) { | |
1368 | case 0: | |
1369 | vty_out(vty, " Algorithm %d: SPF\n", i); | |
1370 | break; | |
1371 | case 1: | |
1372 | vty_out(vty, " Algorithm %d: Strict SPF\n", | |
1373 | i); | |
1374 | break; | |
1375 | default: | |
1376 | vty_out(vty, | |
1377 | " Algorithm %d: Unknown value %d\n", i, | |
1378 | algo->value[i]); | |
1379 | break; | |
1380 | } | |
1381 | } | |
1382 | } | |
1383 | ||
1384 | else { | |
9165c5f5 | 1385 | zlog_debug(" Segment Routing Algorithm TLV:"); |
cf9b9f77 OD |
1386 | for (i = 0; i < ntohs(algo->header.length); i++) |
1387 | switch (algo->value[i]) { | |
1388 | case 0: | |
9165c5f5 | 1389 | zlog_debug(" Algorithm %d: SPF", i); |
cf9b9f77 OD |
1390 | break; |
1391 | case 1: | |
9165c5f5 | 1392 | zlog_debug(" Algorithm %d: Strict SPF", i); |
cf9b9f77 OD |
1393 | break; |
1394 | default: | |
63efca0e DL |
1395 | zlog_debug(" Algorithm %d: Unknown value %d", |
1396 | i, algo->value[i]); | |
cf9b9f77 OD |
1397 | break; |
1398 | } | |
1399 | } | |
1400 | ||
1401 | return TLV_SIZE(tlvh); | |
1402 | } | |
1403 | ||
1404 | /* Display Segment Routing SID/Label Range TLV information */ | |
93f0a26e | 1405 | static uint16_t show_vty_sr_range(struct vty *vty, struct tlv_header *tlvh) |
cf9b9f77 OD |
1406 | { |
1407 | struct ri_sr_tlv_sid_label_range *range = | |
1408 | (struct ri_sr_tlv_sid_label_range *)tlvh; | |
1409 | ||
1410 | if (vty != NULL) { | |
1411 | vty_out(vty, | |
1412 | " Segment Routing Range TLV:\n" | |
1413 | " Range Size = %d\n" | |
1414 | " SID Label = %d\n\n", | |
1415 | GET_RANGE_SIZE(ntohl(range->size)), | |
1416 | GET_LABEL(ntohl(range->lower.value))); | |
1417 | } else { | |
1418 | zlog_debug( | |
1419 | " Segment Routing Range TLV:\n" | |
1420 | " Range Size = %d\n" | |
1421 | " SID Label = %d\n\n", | |
1422 | GET_RANGE_SIZE(ntohl(range->size)), | |
1423 | GET_LABEL(ntohl(range->lower.value))); | |
1424 | } | |
1425 | ||
1426 | return TLV_SIZE(tlvh); | |
1427 | } | |
1428 | ||
1429 | /* Display Segment Routing Maximum Stack Depth TLV information */ | |
93f0a26e | 1430 | static uint16_t show_vty_sr_msd(struct vty *vty, struct tlv_header *tlvh) |
cf9b9f77 OD |
1431 | { |
1432 | struct ri_sr_tlv_node_msd *msd = (struct ri_sr_tlv_node_msd *)tlvh; | |
1433 | ||
1434 | if (vty != NULL) { | |
1435 | vty_out(vty, | |
1436 | " Segment Routing MSD TLV:\n" | |
1437 | " Node Maximum Stack Depth = %d\n", | |
1438 | msd->value); | |
1439 | } else { | |
1440 | zlog_debug( | |
1441 | " Segment Routing MSD TLV:\n" | |
1442 | " Node Maximum Stack Depth = %d\n", | |
1443 | msd->value); | |
1444 | } | |
1445 | ||
1446 | return TLV_SIZE(tlvh); | |
1447 | } | |
1448 | ||
d62a17ae | 1449 | static void ospf_router_info_show_info(struct vty *vty, struct ospf_lsa *lsa) |
0ef4bcdc | 1450 | { |
c4efd0f4 | 1451 | struct lsa_header *lsah = lsa->data; |
ead99d5f | 1452 | struct tlv_header *tlvh; |
d7c0a89a | 1453 | uint16_t length = 0, sum = 0; |
d62a17ae | 1454 | |
1455 | /* Initialize TLV browsing */ | |
1456 | length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE; | |
1457 | ||
ead99d5f OD |
1458 | for (tlvh = TLV_HDR_TOP(lsah); sum < length; |
1459 | tlvh = TLV_HDR_NEXT(tlvh)) { | |
d62a17ae | 1460 | switch (ntohs(tlvh->type)) { |
1461 | case RI_TLV_CAPABILITIES: | |
1462 | sum += show_vty_router_cap(vty, tlvh); | |
1463 | break; | |
1464 | case RI_TLV_PCE: | |
1465 | tlvh++; | |
ead99d5f | 1466 | sum += TLV_HDR_SIZE; |
d62a17ae | 1467 | sum += show_vty_pce_info(vty, tlvh, length - sum); |
1468 | break; | |
cf9b9f77 OD |
1469 | case RI_SR_TLV_SR_ALGORITHM: |
1470 | sum += show_vty_sr_algorithm(vty, tlvh); | |
1471 | break; | |
1472 | case RI_SR_TLV_SID_LABEL_RANGE: | |
1473 | sum += show_vty_sr_range(vty, tlvh); | |
1474 | break; | |
1475 | case RI_SR_TLV_NODE_MSD: | |
1476 | sum += show_vty_sr_msd(vty, tlvh); | |
1477 | break; | |
1478 | ||
d62a17ae | 1479 | default: |
1480 | sum += show_vty_unknown_tlv(vty, tlvh); | |
1481 | break; | |
1482 | } | |
1483 | } | |
1484 | ||
1485 | return; | |
0ef4bcdc OD |
1486 | } |
1487 | ||
d62a17ae | 1488 | static void ospf_router_info_config_write_router(struct vty *vty) |
0ef4bcdc | 1489 | { |
d62a17ae | 1490 | struct ospf_pce_info *pce = &OspfRI.pce_info; |
1491 | struct listnode *node; | |
1492 | struct ri_pce_subtlv_domain *domain; | |
1493 | struct ri_pce_subtlv_neighbor *neighbor; | |
1494 | struct in_addr tmp; | |
1495 | ||
cf9b9f77 OD |
1496 | if (!OspfRI.enabled) |
1497 | return; | |
1498 | ||
1499 | if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) | |
1500 | vty_out(vty, " router-info as\n"); | |
1501 | else | |
ddd73a96 | 1502 | vty_out(vty, " router-info area\n"); |
cf9b9f77 OD |
1503 | |
1504 | if (OspfRI.pce_info.enabled) { | |
1505 | ||
1506 | if (pce->pce_address.header.type != 0) | |
1507 | vty_out(vty, " pce address %s\n", | |
1508 | inet_ntoa(pce->pce_address.address.value)); | |
1509 | ||
1510 | if (pce->pce_cap_flag.header.type != 0) | |
1511 | vty_out(vty, " pce flag 0x%x\n", | |
1512 | ntohl(pce->pce_cap_flag.value)); | |
1513 | ||
1514 | for (ALL_LIST_ELEMENTS_RO(pce->pce_domain, node, domain)) { | |
1515 | if (domain->header.type != 0) { | |
1516 | if (domain->type == PCE_DOMAIN_TYPE_AREA) { | |
1517 | tmp.s_addr = domain->value; | |
1518 | vty_out(vty, " pce domain area %s\n", | |
1519 | inet_ntoa(tmp)); | |
1520 | } else { | |
1521 | vty_out(vty, " pce domain as %d\n", | |
1522 | ntohl(domain->value)); | |
d62a17ae | 1523 | } |
1524 | } | |
cf9b9f77 | 1525 | } |
d62a17ae | 1526 | |
cf9b9f77 OD |
1527 | for (ALL_LIST_ELEMENTS_RO(pce->pce_neighbor, node, neighbor)) { |
1528 | if (neighbor->header.type != 0) { | |
1529 | if (neighbor->type == PCE_DOMAIN_TYPE_AREA) { | |
1530 | tmp.s_addr = neighbor->value; | |
1531 | vty_out(vty, " pce neighbor area %s\n", | |
1532 | inet_ntoa(tmp)); | |
1533 | } else { | |
1534 | vty_out(vty, " pce neighbor as %d\n", | |
1535 | ntohl(neighbor->value)); | |
d62a17ae | 1536 | } |
1537 | } | |
ead99d5f | 1538 | } |
cf9b9f77 OD |
1539 | |
1540 | if (pce->pce_scope.header.type != 0) | |
1541 | vty_out(vty, " pce scope 0x%x\n", | |
1542 | ntohl(OspfRI.pce_info.pce_scope.value)); | |
d62a17ae | 1543 | } |
1544 | return; | |
0ef4bcdc OD |
1545 | } |
1546 | ||
1547 | /*------------------------------------------------------------------------* | |
1548 | * Followings are vty command functions. | |
1549 | *------------------------------------------------------------------------*/ | |
ddd73a96 OD |
1550 | /* Simple wrapper schedule RI LSA action in function of the scope */ |
1551 | static void ospf_router_info_schedule(enum lsa_opcode opcode) | |
1552 | { | |
1553 | struct listnode *node, *nnode; | |
1554 | struct ospf_ri_area_info *ai; | |
1555 | ||
1556 | if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) { | |
1557 | if (CHECK_FLAG(OspfRI.as_flags, RIFLG_LSA_ENGAGED)) | |
1558 | ospf_router_info_lsa_schedule(NULL, opcode); | |
1559 | else if (opcode == REORIGINATE_THIS_LSA) | |
1560 | ospf_router_info_lsa_schedule(NULL, opcode); | |
1561 | } else { | |
1562 | for (ALL_LIST_ELEMENTS(OspfRI.area_info, node, nnode, ai)) { | |
1563 | if (CHECK_FLAG(ai->flags, RIFLG_LSA_ENGAGED)) | |
1564 | ospf_router_info_lsa_schedule(ai, opcode); | |
1565 | } | |
1566 | } | |
1567 | } | |
0ef4bcdc OD |
1568 | |
1569 | DEFUN (router_info, | |
1570 | router_info_area_cmd, | |
ddd73a96 | 1571 | "router-info <as|area [A.B.C.D]>", |
0ef4bcdc | 1572 | OSPF_RI_STR |
692b4c65 | 1573 | "Enable the Router Information functionality with AS flooding scope\n" |
0ef4bcdc | 1574 | "Enable the Router Information functionality with Area flooding scope\n" |
ddd73a96 | 1575 | "OSPF area ID in IP format (deprecated)\n") |
0ef4bcdc | 1576 | { |
ddd73a96 | 1577 | int idx_mode = 1; |
d7c0a89a | 1578 | uint8_t scope; |
d62a17ae | 1579 | |
32ab5cf4 | 1580 | if (OspfRI.enabled) |
d62a17ae | 1581 | return CMD_SUCCESS; |
1582 | ||
1583 | /* Check and get Area value if present */ | |
ddd73a96 | 1584 | if (strncmp(argv[idx_mode]->arg, "as", 2) == 0) |
d62a17ae | 1585 | scope = OSPF_OPAQUE_AS_LSA; |
ddd73a96 OD |
1586 | else |
1587 | scope = OSPF_OPAQUE_AREA_LSA; | |
d62a17ae | 1588 | |
1589 | /* First start to register Router Information callbacks */ | |
ddd73a96 | 1590 | if (!OspfRI.registered && (ospf_router_info_register(scope)) != 0) { |
239697e3 DS |
1591 | vty_out(vty, |
1592 | "%% Unable to register Router Information callbacks."); | |
1593 | flog_err( | |
cf444bcf | 1594 | EC_OSPF_INIT_FAIL, |
ddd73a96 OD |
1595 | "RI (%s): Unable to register Router Information callbacks. Abort!", |
1596 | __func__); | |
d62a17ae | 1597 | return CMD_WARNING_CONFIG_FAILED; |
1598 | } | |
1599 | ||
32ab5cf4 | 1600 | OspfRI.enabled = true; |
d62a17ae | 1601 | |
1602 | if (IS_DEBUG_OSPF_EVENT) | |
1603 | zlog_debug("RI-> Router Information (%s flooding): OFF -> ON", | |
1604 | OspfRI.scope == OSPF_OPAQUE_AREA_LSA ? "Area" | |
1605 | : "AS"); | |
1606 | ||
1607 | /* | |
1608 | * Following code is intended to handle two cases; | |
1609 | * | |
1610 | * 1) Router Information was disabled at startup time, but now become | |
1611 | * enabled. | |
1612 | * 2) Router Information was once enabled then disabled, and now enabled | |
1613 | * again. | |
1614 | */ | |
1615 | ||
1616 | initialize_params(&OspfRI); | |
1617 | ||
ddd73a96 OD |
1618 | /* Originate or Refresh RI LSA if already engaged */ |
1619 | ospf_router_info_schedule(REORIGINATE_THIS_LSA); | |
d62a17ae | 1620 | return CMD_SUCCESS; |
0ef4bcdc OD |
1621 | } |
1622 | ||
0ef4bcdc OD |
1623 | |
1624 | DEFUN (no_router_info, | |
1625 | no_router_info_cmd, | |
1626 | "no router-info", | |
1627 | NO_STR | |
1628 | "Disable the Router Information functionality\n") | |
1629 | { | |
1630 | ||
32ab5cf4 | 1631 | if (!OspfRI.enabled) |
d62a17ae | 1632 | return CMD_SUCCESS; |
0ef4bcdc | 1633 | |
d62a17ae | 1634 | if (IS_DEBUG_OSPF_EVENT) |
1635 | zlog_debug("RI-> Router Information: ON -> OFF"); | |
0ef4bcdc | 1636 | |
ddd73a96 | 1637 | ospf_router_info_schedule(FLUSH_THIS_LSA); |
0ef4bcdc | 1638 | |
32ab5cf4 | 1639 | OspfRI.enabled = false; |
0ef4bcdc | 1640 | |
d62a17ae | 1641 | return CMD_SUCCESS; |
0ef4bcdc OD |
1642 | } |
1643 | ||
d62a17ae | 1644 | static int ospf_ri_enabled(struct vty *vty) |
284a4a0c | 1645 | { |
32ab5cf4 | 1646 | if (OspfRI.enabled) |
d62a17ae | 1647 | return 1; |
284a4a0c | 1648 | |
d62a17ae | 1649 | if (vty) |
1650 | vty_out(vty, "%% OSPF RI is not turned on\n"); | |
284a4a0c | 1651 | |
d62a17ae | 1652 | return 0; |
284a4a0c DS |
1653 | } |
1654 | ||
0ef4bcdc OD |
1655 | DEFUN (pce_address, |
1656 | pce_address_cmd, | |
1657 | "pce address A.B.C.D", | |
1658 | PCE_STR | |
1659 | "Stable IP address of the PCE\n" | |
1660 | "PCE address in IPv4 address format\n") | |
1661 | { | |
d62a17ae | 1662 | int idx_ipv4 = 2; |
1663 | struct in_addr value; | |
1664 | struct ospf_pce_info *pi = &OspfRI.pce_info; | |
0ef4bcdc | 1665 | |
d62a17ae | 1666 | if (!ospf_ri_enabled(vty)) |
1667 | return CMD_WARNING_CONFIG_FAILED; | |
284a4a0c | 1668 | |
d62a17ae | 1669 | if (!inet_aton(argv[idx_ipv4]->arg, &value)) { |
1670 | vty_out(vty, "Please specify PCE Address by A.B.C.D\n"); | |
1671 | return CMD_WARNING_CONFIG_FAILED; | |
1672 | } | |
0ef4bcdc | 1673 | |
d62a17ae | 1674 | if (ntohs(pi->pce_address.header.type) == 0 |
1675 | || ntohl(pi->pce_address.address.value.s_addr) | |
1676 | != ntohl(value.s_addr)) { | |
0ef4bcdc | 1677 | |
d62a17ae | 1678 | set_pce_address(value, pi); |
0ef4bcdc | 1679 | |
d62a17ae | 1680 | /* Refresh RI LSA if already engaged */ |
ddd73a96 | 1681 | ospf_router_info_schedule(REFRESH_THIS_LSA); |
d62a17ae | 1682 | } |
0ef4bcdc | 1683 | |
d62a17ae | 1684 | return CMD_SUCCESS; |
0ef4bcdc OD |
1685 | } |
1686 | ||
1687 | DEFUN (no_pce_address, | |
1688 | no_pce_address_cmd, | |
2328428d | 1689 | "no pce address [A.B.C.D]", |
0ef4bcdc OD |
1690 | NO_STR |
1691 | PCE_STR | |
59768a63 DS |
1692 | "Disable PCE address\n" |
1693 | "PCE address in IPv4 address format\n") | |
0ef4bcdc OD |
1694 | { |
1695 | ||
9ffaacb0 | 1696 | unset_param(&OspfRI.pce_info.pce_address); |
0ef4bcdc | 1697 | |
d62a17ae | 1698 | /* Refresh RI LSA if already engaged */ |
ddd73a96 | 1699 | ospf_router_info_schedule(REFRESH_THIS_LSA); |
0ef4bcdc | 1700 | |
d62a17ae | 1701 | return CMD_SUCCESS; |
0ef4bcdc OD |
1702 | } |
1703 | ||
1704 | DEFUN (pce_path_scope, | |
1705 | pce_path_scope_cmd, | |
1706 | "pce scope BITPATTERN", | |
1707 | PCE_STR | |
1708 | "Path scope visibilities of the PCE for path computation\n" | |
1709 | "32-bit Hexadecimal value\n") | |
1710 | { | |
d62a17ae | 1711 | int idx_bitpattern = 2; |
1712 | uint32_t scope; | |
1713 | struct ospf_pce_info *pi = &OspfRI.pce_info; | |
0ef4bcdc | 1714 | |
d62a17ae | 1715 | if (!ospf_ri_enabled(vty)) |
1716 | return CMD_WARNING_CONFIG_FAILED; | |
284a4a0c | 1717 | |
d62a17ae | 1718 | if (sscanf(argv[idx_bitpattern]->arg, "0x%x", &scope) != 1) { |
1719 | vty_out(vty, "pce_path_scope: fscanf: %s\n", | |
1720 | safe_strerror(errno)); | |
1721 | return CMD_WARNING_CONFIG_FAILED; | |
1722 | } | |
0ef4bcdc | 1723 | |
d62a17ae | 1724 | if (ntohl(pi->pce_scope.header.type) == 0 |
1725 | || scope != pi->pce_scope.value) { | |
1726 | set_pce_path_scope(scope, pi); | |
0ef4bcdc | 1727 | |
d62a17ae | 1728 | /* Refresh RI LSA if already engaged */ |
ddd73a96 | 1729 | ospf_router_info_schedule(REFRESH_THIS_LSA); |
d62a17ae | 1730 | } |
0ef4bcdc | 1731 | |
d62a17ae | 1732 | return CMD_SUCCESS; |
0ef4bcdc OD |
1733 | } |
1734 | ||
1735 | DEFUN (no_pce_path_scope, | |
1736 | no_pce_path_scope_cmd, | |
2328428d | 1737 | "no pce scope [BITPATTERN]", |
0ef4bcdc OD |
1738 | NO_STR |
1739 | PCE_STR | |
59768a63 DS |
1740 | "Disable PCE path scope\n" |
1741 | "32-bit Hexadecimal value\n") | |
0ef4bcdc OD |
1742 | { |
1743 | ||
9ffaacb0 | 1744 | unset_param(&OspfRI.pce_info.pce_address); |
0ef4bcdc | 1745 | |
d62a17ae | 1746 | /* Refresh RI LSA if already engaged */ |
ddd73a96 | 1747 | ospf_router_info_schedule(REFRESH_THIS_LSA); |
0ef4bcdc | 1748 | |
d62a17ae | 1749 | return CMD_SUCCESS; |
0ef4bcdc OD |
1750 | } |
1751 | ||
1752 | DEFUN (pce_domain, | |
1753 | pce_domain_cmd, | |
6147e2c6 | 1754 | "pce domain as (0-65535)", |
0ef4bcdc OD |
1755 | PCE_STR |
1756 | "Configure PCE domain AS number\n" | |
1757 | "AS number where the PCE as visibilities for path computation\n" | |
1758 | "AS number in decimal <0-65535>\n") | |
1759 | { | |
d62a17ae | 1760 | int idx_number = 3; |
0ef4bcdc | 1761 | |
d62a17ae | 1762 | uint32_t as; |
1763 | struct ospf_pce_info *pce = &OspfRI.pce_info; | |
1764 | struct listnode *node; | |
1765 | struct ri_pce_subtlv_domain *domain; | |
0ef4bcdc | 1766 | |
d62a17ae | 1767 | if (!ospf_ri_enabled(vty)) |
1768 | return CMD_WARNING_CONFIG_FAILED; | |
284a4a0c | 1769 | |
0651460e | 1770 | if (sscanf(argv[idx_number]->arg, "%" SCNu32, &as) != 1) { |
d62a17ae | 1771 | vty_out(vty, "pce_domain: fscanf: %s\n", safe_strerror(errno)); |
1772 | return CMD_WARNING_CONFIG_FAILED; | |
1773 | } | |
0ef4bcdc | 1774 | |
d62a17ae | 1775 | /* Check if the domain is not already in the domain list */ |
1776 | for (ALL_LIST_ELEMENTS_RO(pce->pce_domain, node, domain)) { | |
1777 | if (ntohl(domain->header.type) == 0 && as == domain->value) | |
1778 | return CMD_SUCCESS; | |
1779 | } | |
0ef4bcdc | 1780 | |
d62a17ae | 1781 | /* Create new domain if not found */ |
1782 | set_pce_domain(PCE_DOMAIN_TYPE_AS, as, pce); | |
0ef4bcdc | 1783 | |
d62a17ae | 1784 | /* Refresh RI LSA if already engaged */ |
ddd73a96 | 1785 | ospf_router_info_schedule(REFRESH_THIS_LSA); |
0ef4bcdc | 1786 | |
d62a17ae | 1787 | return CMD_SUCCESS; |
0ef4bcdc OD |
1788 | } |
1789 | ||
1790 | DEFUN (no_pce_domain, | |
1791 | no_pce_domain_cmd, | |
6147e2c6 | 1792 | "no pce domain as (0-65535)", |
0ef4bcdc OD |
1793 | NO_STR |
1794 | PCE_STR | |
1795 | "Disable PCE domain AS number\n" | |
1796 | "AS number where the PCE as visibilities for path computation\n" | |
1797 | "AS number in decimal <0-65535>\n") | |
1798 | { | |
d62a17ae | 1799 | int idx_number = 4; |
0ef4bcdc | 1800 | |
d62a17ae | 1801 | uint32_t as; |
1802 | struct ospf_pce_info *pce = &OspfRI.pce_info; | |
0ef4bcdc | 1803 | |
0651460e | 1804 | if (sscanf(argv[idx_number]->arg, "%" SCNu32, &as) != 1) { |
d62a17ae | 1805 | vty_out(vty, "no_pce_domain: fscanf: %s\n", |
1806 | safe_strerror(errno)); | |
1807 | return CMD_WARNING_CONFIG_FAILED; | |
1808 | } | |
0ef4bcdc | 1809 | |
d62a17ae | 1810 | /* Unset corresponding PCE domain */ |
1811 | unset_pce_domain(PCE_DOMAIN_TYPE_AS, as, pce); | |
0ef4bcdc | 1812 | |
d62a17ae | 1813 | /* Refresh RI LSA if already engaged */ |
ddd73a96 | 1814 | ospf_router_info_schedule(REFRESH_THIS_LSA); |
0ef4bcdc | 1815 | |
d62a17ae | 1816 | return CMD_SUCCESS; |
0ef4bcdc OD |
1817 | } |
1818 | ||
1819 | DEFUN (pce_neigbhor, | |
1820 | pce_neighbor_cmd, | |
6147e2c6 | 1821 | "pce neighbor as (0-65535)", |
0ef4bcdc OD |
1822 | PCE_STR |
1823 | "Configure PCE neighbor domain AS number\n" | |
1824 | "AS number of PCE neighbors\n" | |
1825 | "AS number in decimal <0-65535>\n") | |
1826 | { | |
d62a17ae | 1827 | int idx_number = 3; |
0ef4bcdc | 1828 | |
d62a17ae | 1829 | uint32_t as; |
1830 | struct ospf_pce_info *pce = &OspfRI.pce_info; | |
1831 | struct listnode *node; | |
1832 | struct ri_pce_subtlv_neighbor *neighbor; | |
0ef4bcdc | 1833 | |
d62a17ae | 1834 | if (!ospf_ri_enabled(vty)) |
1835 | return CMD_WARNING_CONFIG_FAILED; | |
284a4a0c | 1836 | |
0651460e | 1837 | if (sscanf(argv[idx_number]->arg, "%" SCNu32, &as) != 1) { |
d62a17ae | 1838 | vty_out(vty, "pce_neighbor: fscanf: %s\n", |
1839 | safe_strerror(errno)); | |
1840 | return CMD_WARNING_CONFIG_FAILED; | |
1841 | } | |
0ef4bcdc | 1842 | |
d62a17ae | 1843 | /* Check if the domain is not already in the domain list */ |
1844 | for (ALL_LIST_ELEMENTS_RO(pce->pce_neighbor, node, neighbor)) { | |
1845 | if (ntohl(neighbor->header.type) == 0 && as == neighbor->value) | |
1846 | return CMD_SUCCESS; | |
1847 | } | |
0ef4bcdc | 1848 | |
d62a17ae | 1849 | /* Create new domain if not found */ |
1850 | set_pce_neighbor(PCE_DOMAIN_TYPE_AS, as, pce); | |
0ef4bcdc | 1851 | |
d62a17ae | 1852 | /* Refresh RI LSA if already engaged */ |
ddd73a96 | 1853 | ospf_router_info_schedule(REFRESH_THIS_LSA); |
0ef4bcdc | 1854 | |
d62a17ae | 1855 | return CMD_SUCCESS; |
0ef4bcdc OD |
1856 | } |
1857 | ||
1858 | DEFUN (no_pce_neighbor, | |
1859 | no_pce_neighbor_cmd, | |
6147e2c6 | 1860 | "no pce neighbor as (0-65535)", |
0ef4bcdc OD |
1861 | NO_STR |
1862 | PCE_STR | |
1863 | "Disable PCE neighbor AS number\n" | |
1864 | "AS number of PCE neighbor\n" | |
1865 | "AS number in decimal <0-65535>\n") | |
1866 | { | |
d62a17ae | 1867 | int idx_number = 4; |
0ef4bcdc | 1868 | |
d62a17ae | 1869 | uint32_t as; |
1870 | struct ospf_pce_info *pce = &OspfRI.pce_info; | |
0ef4bcdc | 1871 | |
0651460e | 1872 | if (sscanf(argv[idx_number]->arg, "%" SCNu32, &as) != 1) { |
d62a17ae | 1873 | vty_out(vty, "no_pce_neighbor: fscanf: %s\n", |
1874 | safe_strerror(errno)); | |
1875 | return CMD_WARNING_CONFIG_FAILED; | |
1876 | } | |
0ef4bcdc | 1877 | |
d62a17ae | 1878 | /* Unset corresponding PCE domain */ |
1879 | unset_pce_neighbor(PCE_DOMAIN_TYPE_AS, as, pce); | |
0ef4bcdc | 1880 | |
d62a17ae | 1881 | /* Refresh RI LSA if already engaged */ |
ddd73a96 | 1882 | ospf_router_info_schedule(REFRESH_THIS_LSA); |
0ef4bcdc | 1883 | |
d62a17ae | 1884 | return CMD_SUCCESS; |
0ef4bcdc OD |
1885 | } |
1886 | ||
1887 | DEFUN (pce_cap_flag, | |
1888 | pce_cap_flag_cmd, | |
1889 | "pce flag BITPATTERN", | |
1890 | PCE_STR | |
1891 | "Capabilities of the PCE for path computation\n" | |
1892 | "32-bit Hexadecimal value\n") | |
1893 | { | |
d62a17ae | 1894 | int idx_bitpattern = 2; |
0ef4bcdc | 1895 | |
d62a17ae | 1896 | uint32_t cap; |
1897 | struct ospf_pce_info *pce = &OspfRI.pce_info; | |
0ef4bcdc | 1898 | |
d62a17ae | 1899 | if (!ospf_ri_enabled(vty)) |
1900 | return CMD_WARNING_CONFIG_FAILED; | |
284a4a0c | 1901 | |
d62a17ae | 1902 | if (sscanf(argv[idx_bitpattern]->arg, "0x%x", &cap) != 1) { |
1903 | vty_out(vty, "pce_cap_flag: fscanf: %s\n", | |
1904 | safe_strerror(errno)); | |
1905 | return CMD_WARNING_CONFIG_FAILED; | |
1906 | } | |
0ef4bcdc | 1907 | |
d62a17ae | 1908 | if (ntohl(pce->pce_cap_flag.header.type) == 0 |
1909 | || cap != pce->pce_cap_flag.value) { | |
1910 | set_pce_cap_flag(cap, pce); | |
0ef4bcdc | 1911 | |
d62a17ae | 1912 | /* Refresh RI LSA if already engaged */ |
ddd73a96 | 1913 | ospf_router_info_schedule(REFRESH_THIS_LSA); |
d62a17ae | 1914 | } |
0ef4bcdc | 1915 | |
d62a17ae | 1916 | return CMD_SUCCESS; |
0ef4bcdc OD |
1917 | } |
1918 | ||
1919 | DEFUN (no_pce_cap_flag, | |
1920 | no_pce_cap_flag_cmd, | |
1921 | "no pce flag", | |
1922 | NO_STR | |
1923 | PCE_STR | |
1924 | "Disable PCE capabilities\n") | |
1925 | { | |
1926 | ||
9ffaacb0 | 1927 | unset_param(&OspfRI.pce_info.pce_cap_flag); |
0ef4bcdc | 1928 | |
d62a17ae | 1929 | /* Refresh RI LSA if already engaged */ |
ddd73a96 | 1930 | ospf_router_info_schedule(REFRESH_THIS_LSA); |
0ef4bcdc | 1931 | |
d62a17ae | 1932 | return CMD_SUCCESS; |
0ef4bcdc OD |
1933 | } |
1934 | ||
1935 | DEFUN (show_ip_ospf_router_info, | |
1936 | show_ip_ospf_router_info_cmd, | |
1937 | "show ip ospf router-info", | |
1938 | SHOW_STR | |
1939 | IP_STR | |
1940 | OSPF_STR | |
1941 | "Router Information\n") | |
1942 | { | |
1943 | ||
32ab5cf4 | 1944 | if (OspfRI.enabled) { |
d62a17ae | 1945 | vty_out(vty, "--- Router Information parameters ---\n"); |
1946 | show_vty_router_cap(vty, &OspfRI.router_cap.header); | |
1947 | } else { | |
1948 | if (vty != NULL) | |
1949 | vty_out(vty, | |
1950 | " Router Information is disabled on this router\n"); | |
1951 | } | |
1952 | return CMD_SUCCESS; | |
0ef4bcdc OD |
1953 | } |
1954 | ||
1955 | DEFUN (show_ip_opsf_router_info_pce, | |
1956 | show_ip_ospf_router_info_pce_cmd, | |
1957 | "show ip ospf router-info pce", | |
1958 | SHOW_STR | |
1959 | IP_STR | |
1960 | OSPF_STR | |
1961 | "Router Information\n" | |
1962 | "PCE information\n") | |
1963 | { | |
1964 | ||
d62a17ae | 1965 | struct ospf_pce_info *pce = &OspfRI.pce_info; |
1966 | struct listnode *node; | |
1967 | struct ri_pce_subtlv_domain *domain; | |
1968 | struct ri_pce_subtlv_neighbor *neighbor; | |
0ef4bcdc | 1969 | |
cf9b9f77 | 1970 | if ((OspfRI.enabled) && (OspfRI.pce_info.enabled)) { |
d62a17ae | 1971 | vty_out(vty, "--- PCE parameters ---\n"); |
0ef4bcdc | 1972 | |
d62a17ae | 1973 | if (pce->pce_address.header.type != 0) |
1974 | show_vty_pce_subtlv_address(vty, | |
1975 | &pce->pce_address.header); | |
0ef4bcdc | 1976 | |
d62a17ae | 1977 | if (pce->pce_scope.header.type != 0) |
1978 | show_vty_pce_subtlv_path_scope(vty, | |
1979 | &pce->pce_scope.header); | |
0ef4bcdc | 1980 | |
d62a17ae | 1981 | for (ALL_LIST_ELEMENTS_RO(pce->pce_domain, node, domain)) { |
1982 | if (domain->header.type != 0) | |
1983 | show_vty_pce_subtlv_domain(vty, | |
1984 | &domain->header); | |
1985 | } | |
0ef4bcdc | 1986 | |
d62a17ae | 1987 | for (ALL_LIST_ELEMENTS_RO(pce->pce_neighbor, node, neighbor)) { |
1988 | if (neighbor->header.type != 0) | |
1989 | show_vty_pce_subtlv_neighbor(vty, | |
1990 | &neighbor->header); | |
1991 | } | |
0ef4bcdc | 1992 | |
d62a17ae | 1993 | if (pce->pce_cap_flag.header.type != 0) |
1994 | show_vty_pce_subtlv_cap_flag(vty, | |
1995 | &pce->pce_cap_flag.header); | |
0ef4bcdc | 1996 | |
d62a17ae | 1997 | } else { |
996c9314 | 1998 | vty_out(vty, " PCE info is disabled on this router\n"); |
d62a17ae | 1999 | } |
0ef4bcdc | 2000 | |
d62a17ae | 2001 | return CMD_SUCCESS; |
0ef4bcdc OD |
2002 | } |
2003 | ||
2004 | /* Install new CLI commands */ | |
d62a17ae | 2005 | static void ospf_router_info_register_vty(void) |
0ef4bcdc | 2006 | { |
d62a17ae | 2007 | install_element(VIEW_NODE, &show_ip_ospf_router_info_cmd); |
2008 | install_element(VIEW_NODE, &show_ip_ospf_router_info_pce_cmd); | |
2009 | ||
2010 | install_element(OSPF_NODE, &router_info_area_cmd); | |
2011 | install_element(OSPF_NODE, &no_router_info_cmd); | |
2012 | install_element(OSPF_NODE, &pce_address_cmd); | |
2013 | install_element(OSPF_NODE, &no_pce_address_cmd); | |
2014 | install_element(OSPF_NODE, &pce_path_scope_cmd); | |
2015 | install_element(OSPF_NODE, &no_pce_path_scope_cmd); | |
2016 | install_element(OSPF_NODE, &pce_domain_cmd); | |
2017 | install_element(OSPF_NODE, &no_pce_domain_cmd); | |
2018 | install_element(OSPF_NODE, &pce_neighbor_cmd); | |
2019 | install_element(OSPF_NODE, &no_pce_neighbor_cmd); | |
2020 | install_element(OSPF_NODE, &pce_cap_flag_cmd); | |
2021 | install_element(OSPF_NODE, &no_pce_cap_flag_cmd); | |
2022 | ||
2023 | return; | |
0ef4bcdc | 2024 | } |