Line data Source code
1 : /*
2 : * Copyright (C) 2003 Yasuhiro Ohara
3 : *
4 : * This file is part of GNU Zebra.
5 : *
6 : * GNU Zebra is free software; you can redistribute it and/or modify it
7 : * under the terms of the GNU General Public License as published by the
8 : * Free Software Foundation; either version 2, or (at your option) any
9 : * later version.
10 : *
11 : * GNU Zebra is distributed in the hope that it will be useful, but
12 : * WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : * General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public License along
17 : * with this program; see the file COPYING; if not, write to the Free Software
18 : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 : */
20 :
21 : #include <zebra.h>
22 :
23 : #include "log.h"
24 : #include "linklist.h"
25 : #include "thread.h"
26 : #include "memory.h"
27 : #include "if.h"
28 : #include "prefix.h"
29 : #include "table.h"
30 : #include "vty.h"
31 : #include "command.h"
32 : #include "vrf.h"
33 :
34 : #include "ospf6_proto.h"
35 : #include "ospf6_message.h"
36 : #include "ospf6_route.h"
37 : #include "ospf6_lsa.h"
38 : #include "ospf6_lsdb.h"
39 :
40 : #include "ospf6_top.h"
41 : #include "ospf6_area.h"
42 : #include "ospf6_interface.h"
43 : #include "ospf6_neighbor.h"
44 : #include "ospf6_intra.h"
45 : #include "ospf6_asbr.h"
46 : #include "ospf6_abr.h"
47 : #include "ospf6_flood.h"
48 : #include "ospf6d.h"
49 : #include "ospf6_spf.h"
50 : #include "ospf6_gr.h"
51 : #include "ospf6_vlink.h"
52 :
53 : unsigned char conf_debug_ospf6_brouter = 0;
54 : uint32_t conf_debug_ospf6_brouter_specific_router_id;
55 : uint32_t conf_debug_ospf6_brouter_specific_area_id;
56 :
57 : #define MAX_LSA_PAYLOAD (1024 + 256)
58 : /******************************/
59 : /* RFC2740 3.4.3.1 Router-LSA */
60 : /******************************/
61 :
62 0 : static char *ospf6_router_lsa_get_nbr_id(struct ospf6_lsa *lsa, char *buf,
63 : int buflen, int pos)
64 : {
65 0 : struct ospf6_router_lsa *router_lsa;
66 0 : struct ospf6_router_lsdesc *lsdesc;
67 0 : char *start, *end;
68 0 : char buf1[INET_ADDRSTRLEN], buf2[INET_ADDRSTRLEN];
69 :
70 0 : if (lsa) {
71 0 : router_lsa = (struct ospf6_router_lsa
72 0 : *)((char *)lsa->header
73 : + sizeof(struct ospf6_lsa_header));
74 0 : start = (char *)router_lsa + sizeof(struct ospf6_router_lsa);
75 0 : end = (char *)lsa->header + ntohs(lsa->header->length);
76 :
77 0 : lsdesc = (struct ospf6_router_lsdesc
78 : *)(start
79 0 : + pos * (sizeof(struct
80 : ospf6_router_lsdesc)));
81 0 : if ((char *)lsdesc + sizeof(struct ospf6_router_lsdesc)
82 : <= end) {
83 0 : if (buf && (buflen > INET_ADDRSTRLEN * 2)) {
84 0 : inet_ntop(AF_INET,
85 0 : &lsdesc->neighbor_interface_id, buf1,
86 : sizeof(buf1));
87 0 : inet_ntop(AF_INET, &lsdesc->neighbor_router_id,
88 : buf2, sizeof(buf2));
89 0 : snprintf(buf, buflen, "%s/%s", buf2, buf1);
90 :
91 0 : return buf;
92 : }
93 : }
94 : }
95 :
96 : return NULL;
97 : }
98 :
99 292 : static int ospf6_router_lsa_show(struct vty *vty, struct ospf6_lsa *lsa,
100 : json_object *json_obj, bool use_json)
101 : {
102 292 : char *start, *end, *current;
103 292 : char buf[32], name[32], bits[16], options[32];
104 292 : struct ospf6_router_lsa *router_lsa;
105 292 : struct ospf6_router_lsdesc *lsdesc;
106 292 : json_object *json_arr;
107 292 : json_object *json_loop;
108 :
109 292 : router_lsa =
110 292 : (struct ospf6_router_lsa *)((char *)lsa->header
111 : + sizeof(struct ospf6_lsa_header));
112 :
113 292 : ospf6_capability_printbuf(router_lsa->bits, bits, sizeof(bits));
114 292 : ospf6_options_printbuf(router_lsa->options, options, sizeof(options));
115 292 : if (use_json) {
116 292 : json_object_string_add(json_obj, "bits", bits);
117 292 : json_object_string_add(json_obj, "options", options);
118 292 : json_arr = json_object_new_array();
119 : } else
120 0 : vty_out(vty, " Bits: %s Options: %s\n", bits, options);
121 :
122 292 : start = (char *)router_lsa + sizeof(struct ospf6_router_lsa);
123 292 : end = (char *)lsa->header + ntohs(lsa->header->length);
124 292 : for (current = start;
125 786 : current + sizeof(struct ospf6_router_lsdesc) <= end;
126 : current += sizeof(struct ospf6_router_lsdesc)) {
127 494 : lsdesc = (struct ospf6_router_lsdesc *)current;
128 :
129 494 : if (lsdesc->type == OSPF6_ROUTER_LSDESC_POINTTOPOINT)
130 408 : snprintf(name, sizeof(name), "Point-To-Point");
131 86 : else if (lsdesc->type == OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK)
132 86 : snprintf(name, sizeof(name), "Transit-Network");
133 0 : else if (lsdesc->type == OSPF6_ROUTER_LSDESC_STUB_NETWORK)
134 0 : snprintf(name, sizeof(name), "Stub-Network");
135 0 : else if (lsdesc->type == OSPF6_ROUTER_LSDESC_VIRTUAL_LINK)
136 0 : snprintf(name, sizeof(name), "Virtual-Link");
137 : else
138 0 : snprintf(name, sizeof(name), "Unknown (%#x)",
139 : lsdesc->type);
140 :
141 494 : if (use_json) {
142 494 : json_loop = json_object_new_object();
143 494 : json_object_string_add(json_loop, "type", name);
144 494 : json_object_int_add(json_loop, "metric",
145 494 : ntohs(lsdesc->metric));
146 494 : json_object_string_addf(
147 : json_loop, "interfaceId", "%pI4",
148 494 : (in_addr_t *)&lsdesc->interface_id);
149 494 : json_object_string_addf(
150 : json_loop, "neighborInterfaceId", "%pI4",
151 494 : (in_addr_t *)&lsdesc->neighbor_interface_id);
152 494 : json_object_string_addf(json_loop, "neighborRouterId",
153 : "%pI4",
154 : &lsdesc->neighbor_router_id);
155 494 : json_object_array_add(json_arr, json_loop);
156 : } else {
157 0 : vty_out(vty, " Type: %s Metric: %d\n", name,
158 0 : ntohs(lsdesc->metric));
159 0 : vty_out(vty, " Interface ID: %s\n",
160 0 : inet_ntop(AF_INET, &lsdesc->interface_id, buf,
161 : sizeof(buf)));
162 0 : vty_out(vty, " Neighbor Interface ID: %s\n",
163 : inet_ntop(AF_INET,
164 0 : &lsdesc->neighbor_interface_id, buf,
165 : sizeof(buf)));
166 0 : vty_out(vty, " Neighbor Router ID: %s\n",
167 0 : inet_ntop(AF_INET, &lsdesc->neighbor_router_id,
168 : buf, sizeof(buf)));
169 : }
170 : }
171 292 : if (use_json)
172 292 : json_object_object_add(json_obj, "lsaDescription", json_arr);
173 :
174 292 : return 0;
175 : }
176 :
177 15 : static void ospf6_router_lsa_options_set(struct ospf6_area *oa,
178 : struct ospf6_router_lsa *router_lsa)
179 : {
180 15 : OSPF6_OPT_CLEAR_ALL(router_lsa->options);
181 15 : memcpy(router_lsa->options, oa->options, 3);
182 :
183 15 : if (ospf6_check_and_set_router_abr(oa->ospf6))
184 0 : SET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_B);
185 : else
186 15 : UNSET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_B);
187 :
188 15 : if (!IS_AREA_STUB(oa) && ospf6_asbr_is_asbr(oa->ospf6)) {
189 0 : SET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_E);
190 : } else {
191 15 : UNSET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_E);
192 : }
193 :
194 : /* If the router is ASBR and the area-type is NSSA set the
195 : * translate bit in router LSA.
196 : */
197 15 : if (IS_AREA_NSSA(oa)
198 0 : && (ospf6_asbr_is_asbr(oa->ospf6) || IS_OSPF6_ABR(oa->ospf6))) {
199 0 : if (oa->NSSATranslatorRole == OSPF6_NSSA_ROLE_ALWAYS)
200 0 : SET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_NT);
201 : } else {
202 15 : UNSET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_NT);
203 : }
204 :
205 15 : if (oa->virtual_link_full)
206 0 : SET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_V);
207 : else
208 15 : UNSET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_V);
209 :
210 15 : UNSET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_W);
211 15 : }
212 :
213 90 : int ospf6_router_is_stub_router(struct ospf6_lsa *lsa)
214 : {
215 90 : struct ospf6_router_lsa *rtr_lsa;
216 :
217 90 : if (lsa != NULL && OSPF6_LSA_IS_TYPE(ROUTER, lsa)) {
218 90 : rtr_lsa = (struct ospf6_router_lsa
219 : *)((caddr_t)lsa->header
220 : + sizeof(struct ospf6_lsa_header));
221 :
222 90 : if (!OSPF6_OPT_ISSET(rtr_lsa->options, OSPF6_OPT_R)) {
223 : return OSPF6_IS_STUB_ROUTER;
224 90 : } else if (!OSPF6_OPT_ISSET(rtr_lsa->options, OSPF6_OPT_V6)) {
225 0 : return OSPF6_IS_STUB_ROUTER_V6;
226 : }
227 : }
228 :
229 : return OSPF6_NOT_STUB_ROUTER;
230 : }
231 :
232 15 : void ospf6_router_lsa_originate(struct thread *thread)
233 : {
234 15 : struct ospf6_area *oa;
235 :
236 15 : char buffer[OSPF6_MAX_LSASIZE];
237 15 : struct ospf6_lsa_header *lsa_header;
238 15 : struct ospf6_lsa *lsa;
239 :
240 15 : uint32_t link_state_id = 0;
241 15 : struct listnode *node, *nnode;
242 15 : struct listnode *j;
243 15 : struct ospf6_interface *oi;
244 15 : struct ospf6_neighbor *on, *drouter = NULL;
245 15 : struct ospf6_router_lsa *router_lsa;
246 15 : struct ospf6_router_lsdesc *lsdesc;
247 15 : uint16_t type;
248 15 : uint32_t router;
249 15 : int count;
250 :
251 15 : oa = (struct ospf6_area *)THREAD_ARG(thread);
252 :
253 15 : if (oa->ospf6->gr_info.restart_in_progress) {
254 0 : if (IS_DEBUG_OSPF6_GR)
255 0 : zlog_debug(
256 : "Graceful Restart in progress, don't originate LSA");
257 0 : return;
258 : }
259 :
260 15 : if (IS_OSPF6_DEBUG_ORIGINATE(ROUTER))
261 0 : zlog_debug("Originate Router-LSA for Area %s", oa->name);
262 :
263 15 : memset(buffer, 0, sizeof(buffer));
264 15 : lsa_header = (struct ospf6_lsa_header *)buffer;
265 15 : router_lsa =
266 : (struct ospf6_router_lsa *)((caddr_t)lsa_header
267 : + sizeof(struct ospf6_lsa_header));
268 :
269 15 : ospf6_router_lsa_options_set(oa, router_lsa);
270 :
271 : /* describe links for each interfaces */
272 15 : lsdesc = (struct ospf6_router_lsdesc
273 : *)((caddr_t)router_lsa
274 : + sizeof(struct ospf6_router_lsa));
275 :
276 51 : for (ALL_LIST_ELEMENTS(oa->if_list, node, nnode, oi)) {
277 : /* Interfaces in state Down or Loopback are not described */
278 22 : if (oi->state == OSPF6_INTERFACE_DOWN
279 21 : || oi->state == OSPF6_INTERFACE_LOOPBACK)
280 1 : continue;
281 :
282 : /* Nor are interfaces without any full adjacencies described */
283 20 : count = 0;
284 62 : for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, j, on))
285 22 : if (on->state == OSPF6_NEIGHBOR_FULL)
286 14 : count++;
287 :
288 20 : if (count == 0)
289 10 : continue;
290 :
291 : /* Multiple Router-LSA instance according to size limit setting
292 : */
293 10 : if ((oa->router_lsa_size_limit != 0)
294 10 : && ((size_t)((char *)lsdesc - buffer)
295 10 : + sizeof(struct ospf6_router_lsdesc)
296 10 : > oa->router_lsa_size_limit)) {
297 0 : if ((caddr_t)lsdesc
298 : == (caddr_t)router_lsa
299 : + sizeof(struct ospf6_router_lsa)) {
300 0 : zlog_warn(
301 : "Size limit setting for Router-LSA too short");
302 0 : return;
303 : }
304 :
305 : /* Fill LSA Header */
306 0 : lsa_header->age = 0;
307 0 : lsa_header->type = htons(OSPF6_LSTYPE_ROUTER);
308 0 : lsa_header->id = htonl(link_state_id);
309 0 : lsa_header->adv_router = oa->ospf6->router_id;
310 0 : lsa_header->seqnum = ospf6_new_ls_seqnum(
311 : lsa_header->type, lsa_header->id,
312 : lsa_header->adv_router, oa->lsdb);
313 0 : lsa_header->length =
314 0 : htons((caddr_t)lsdesc - (caddr_t)buffer);
315 :
316 : /* LSA checksum */
317 0 : ospf6_lsa_checksum(lsa_header);
318 :
319 : /* create LSA */
320 0 : lsa = ospf6_lsa_create(lsa_header);
321 :
322 : /* Originate */
323 0 : ospf6_lsa_originate_area(lsa, oa);
324 :
325 : /* Reset Buffer to fill next Router LSA */
326 0 : memset(buffer, 0, sizeof(buffer));
327 0 : lsa_header = (struct ospf6_lsa_header *)buffer;
328 0 : router_lsa =
329 : (struct ospf6_router_lsa
330 : *)((caddr_t)lsa_header
331 : + sizeof(struct ospf6_lsa_header));
332 :
333 0 : ospf6_router_lsa_options_set(oa, router_lsa);
334 :
335 : /* describe links for each interfaces */
336 0 : lsdesc = (struct ospf6_router_lsdesc
337 : *)((caddr_t)router_lsa
338 : + sizeof(struct ospf6_router_lsa));
339 :
340 0 : link_state_id++;
341 : }
342 :
343 : /* Point-to-Point interfaces */
344 10 : if (oi->type == OSPF_IFTYPE_POINTOPOINT
345 10 : || oi->type == OSPF_IFTYPE_POINTOMULTIPOINT
346 2 : || oi->type == OSPF_IFTYPE_VIRTUALLINK) {
347 31 : for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, j, on)) {
348 15 : if (on->state != OSPF6_NEIGHBOR_FULL)
349 3 : continue;
350 :
351 12 : if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
352 12 : lsdesc->type = OSPF6_ROUTER_LSDESC_POINTTOPOINT;
353 : else
354 0 : lsdesc->type = OSPF6_ROUTER_LSDESC_VIRTUAL_LINK;
355 12 : lsdesc->metric = htons(ospf6_neighbor_cost(on));
356 24 : lsdesc->interface_id =
357 12 : htonl(on->vlink ? on->vlink->v_ifindex
358 : : oi->interface->ifindex);
359 12 : lsdesc->neighbor_interface_id =
360 12 : htonl(on->ifindex);
361 12 : lsdesc->neighbor_router_id = on->router_id;
362 :
363 12 : lsdesc++;
364 : }
365 : }
366 :
367 : /* Broadcast and NBMA interfaces */
368 2 : else if (oi->type == OSPF_IFTYPE_BROADCAST) {
369 : /* If this router is not DR,
370 : and If this router not fully adjacent with DR,
371 : this interface is not transit yet: ignore. */
372 2 : if (oi->state != OSPF6_INTERFACE_DR) {
373 1 : drouter =
374 1 : ospf6_neighbor_lookup(oi->drouter, oi);
375 1 : if (drouter == NULL
376 1 : || drouter->state != OSPF6_NEIGHBOR_FULL)
377 0 : continue;
378 : }
379 :
380 2 : lsdesc->type = OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK;
381 2 : lsdesc->metric = htons(oi->cost);
382 2 : lsdesc->interface_id = htonl(oi->interface->ifindex);
383 2 : if (oi->state != OSPF6_INTERFACE_DR) {
384 1 : lsdesc->neighbor_interface_id =
385 1 : htonl(drouter->ifindex);
386 1 : lsdesc->neighbor_router_id = drouter->router_id;
387 : } else {
388 1 : lsdesc->neighbor_interface_id =
389 1 : htonl(oi->interface->ifindex);
390 1 : lsdesc->neighbor_router_id =
391 1 : oi->area->ospf6->router_id;
392 : }
393 :
394 2 : lsdesc++;
395 : } else {
396 0 : assert(0); /* Unknown interface type */
397 : }
398 :
399 : /* Virtual links */
400 : /* xxx */
401 : /* Point-to-Multipoint interfaces */
402 : /* xxx */
403 : }
404 :
405 : /* Fill LSA Header */
406 15 : lsa_header->age = 0;
407 15 : lsa_header->type = htons(OSPF6_LSTYPE_ROUTER);
408 15 : lsa_header->id = htonl(link_state_id);
409 15 : lsa_header->adv_router = oa->ospf6->router_id;
410 30 : lsa_header->seqnum =
411 15 : ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id,
412 : lsa_header->adv_router, oa->lsdb);
413 15 : lsa_header->length = htons((caddr_t)lsdesc - (caddr_t)buffer);
414 :
415 : /* LSA checksum */
416 15 : ospf6_lsa_checksum(lsa_header);
417 :
418 : /* create LSA */
419 15 : lsa = ospf6_lsa_create(lsa_header);
420 :
421 : /* Originate */
422 15 : ospf6_lsa_originate_area(lsa, oa);
423 :
424 15 : link_state_id++;
425 :
426 : /* Do premature-aging of rest, undesired Router-LSAs */
427 15 : type = ntohs(OSPF6_LSTYPE_ROUTER);
428 15 : router = oa->ospf6->router_id;
429 15 : count = 0;
430 30 : for (ALL_LSDB_TYPED_ADVRTR(oa->lsdb, type, router, lsa)) {
431 15 : if (ntohl(lsa->header->id) < link_state_id)
432 15 : continue;
433 0 : ospf6_lsa_purge(lsa);
434 0 : count++;
435 : }
436 :
437 : /*
438 : * Waiting till the LSA is actually removed from the database to trigger
439 : * SPF delays network convergence. Unlike IPv4, for an ABR, when all
440 : * interfaces associated with an area are gone, triggering an SPF right
441 : * away
442 : * helps convergence with inter-area routes.
443 : */
444 15 : if (count && !link_state_id)
445 0 : ospf6_spf_schedule(oa->ospf6,
446 : OSPF6_SPF_FLAGS_ROUTER_LSA_ORIGINATED);
447 : }
448 :
449 : /*******************************/
450 : /* RFC2740 3.4.3.2 Network-LSA */
451 : /*******************************/
452 :
453 0 : static char *ospf6_network_lsa_get_ar_id(struct ospf6_lsa *lsa, char *buf,
454 : int buflen, int pos)
455 : {
456 0 : char *start, *end, *current;
457 0 : struct ospf6_network_lsa *network_lsa;
458 0 : struct ospf6_network_lsdesc *lsdesc;
459 :
460 0 : if (lsa) {
461 0 : network_lsa = (struct ospf6_network_lsa
462 0 : *)((caddr_t)lsa->header
463 : + sizeof(struct ospf6_lsa_header));
464 :
465 0 : start = (char *)network_lsa + sizeof(struct ospf6_network_lsa);
466 0 : end = (char *)lsa->header + ntohs(lsa->header->length);
467 0 : current = start + pos * (sizeof(struct ospf6_network_lsdesc));
468 :
469 0 : if ((current + sizeof(struct ospf6_network_lsdesc)) <= end) {
470 0 : lsdesc = (struct ospf6_network_lsdesc *)current;
471 0 : if (buf) {
472 0 : inet_ntop(AF_INET, &lsdesc->router_id, buf,
473 : buflen);
474 0 : return buf;
475 : }
476 : }
477 : }
478 :
479 : return NULL;
480 : }
481 :
482 73 : static int ospf6_network_lsa_show(struct vty *vty, struct ospf6_lsa *lsa,
483 : json_object *json_obj, bool use_json)
484 : {
485 73 : char *start, *end, *current;
486 73 : struct ospf6_network_lsa *network_lsa;
487 73 : struct ospf6_network_lsdesc *lsdesc;
488 73 : char buf[128], options[32];
489 73 : json_object *json_arr;
490 :
491 73 : network_lsa =
492 73 : (struct ospf6_network_lsa *)((caddr_t)lsa->header
493 : + sizeof(struct ospf6_lsa_header));
494 :
495 73 : ospf6_options_printbuf(network_lsa->options, options, sizeof(options));
496 73 : if (use_json)
497 73 : json_object_string_add(json_obj, "options", options);
498 : else
499 0 : vty_out(vty, " Options: %s\n", options);
500 :
501 73 : start = (char *)network_lsa + sizeof(struct ospf6_network_lsa);
502 73 : end = (char *)lsa->header + ntohs(lsa->header->length);
503 73 : if (use_json)
504 73 : json_arr = json_object_new_array();
505 :
506 73 : for (current = start;
507 219 : current + sizeof(struct ospf6_network_lsdesc) <= end;
508 : current += sizeof(struct ospf6_network_lsdesc)) {
509 146 : lsdesc = (struct ospf6_network_lsdesc *)current;
510 146 : inet_ntop(AF_INET, &lsdesc->router_id, buf, sizeof(buf));
511 146 : if (use_json)
512 146 : json_object_array_add(json_arr,
513 : json_object_new_string(buf));
514 : else
515 0 : vty_out(vty, " Attached Router: %s\n", buf);
516 : }
517 73 : if (use_json)
518 73 : json_object_object_add(json_obj, "attachedRouter", json_arr);
519 :
520 73 : return 0;
521 : }
522 :
523 7 : void ospf6_network_lsa_originate(struct thread *thread)
524 : {
525 7 : struct ospf6_interface *oi;
526 :
527 7 : char buffer[OSPF6_MAX_LSASIZE];
528 7 : struct ospf6_lsa_header *lsa_header;
529 :
530 7 : int count;
531 7 : struct ospf6_lsa *old, *lsa;
532 7 : struct ospf6_network_lsa *network_lsa;
533 7 : struct ospf6_network_lsdesc *lsdesc;
534 7 : struct ospf6_neighbor *on;
535 7 : struct ospf6_link_lsa *link_lsa;
536 7 : struct listnode *i;
537 7 : uint16_t type;
538 :
539 7 : oi = (struct ospf6_interface *)THREAD_ARG(thread);
540 :
541 : /* The interface must be enabled until here. A Network-LSA of a
542 : disabled interface (but was once enabled) should be flushed
543 : by ospf6_lsa_refresh (), and does not come here. */
544 7 : assert(oi->area);
545 7 : assert(oi->type != OSPF_IFTYPE_VIRTUALLINK);
546 :
547 7 : if (oi->area->ospf6->gr_info.restart_in_progress) {
548 0 : if (IS_DEBUG_OSPF6_GR)
549 0 : zlog_debug(
550 : "Graceful Restart in progress, don't originate LSA");
551 6 : return;
552 : }
553 :
554 14 : old = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_NETWORK),
555 7 : htonl(oi->interface->ifindex),
556 : oi->area->ospf6->router_id, oi->area->lsdb);
557 :
558 : /* Do not originate Network-LSA if not DR */
559 7 : if (oi->state != OSPF6_INTERFACE_DR) {
560 5 : if (old) {
561 1 : ospf6_lsa_purge(old);
562 : /*
563 : * Waiting till the LSA is actually removed from the
564 : * database to
565 : * trigger SPF delays network convergence.
566 : */
567 1 : ospf6_spf_schedule(
568 1 : oi->area->ospf6,
569 : OSPF6_SPF_FLAGS_NETWORK_LSA_ORIGINATED);
570 : }
571 5 : return;
572 : }
573 :
574 2 : if (IS_OSPF6_DEBUG_ORIGINATE(NETWORK))
575 0 : zlog_debug("Originate Network-LSA for Interface %pOI", oi);
576 :
577 : /* If none of neighbor is adjacent to us */
578 2 : count = 0;
579 :
580 6 : for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, i, on))
581 2 : if (on->state == OSPF6_NEIGHBOR_FULL)
582 1 : count++;
583 :
584 2 : if (count == 0) {
585 1 : if (IS_OSPF6_DEBUG_ORIGINATE(NETWORK))
586 0 : zlog_debug("Interface stub, ignore");
587 1 : if (old)
588 0 : ospf6_lsa_purge(old);
589 1 : return;
590 : }
591 :
592 : /* prepare buffer */
593 1 : memset(buffer, 0, sizeof(buffer));
594 1 : lsa_header = (struct ospf6_lsa_header *)buffer;
595 1 : network_lsa =
596 : (struct ospf6_network_lsa *)((caddr_t)lsa_header
597 : + sizeof(struct ospf6_lsa_header));
598 :
599 : /* Collect the interface's Link-LSAs to describe
600 : network's optional capabilities */
601 1 : type = htons(OSPF6_LSTYPE_LINK);
602 3 : for (ALL_LSDB_TYPED(oi->lsdb, type, lsa)) {
603 2 : link_lsa = (struct ospf6_link_lsa
604 2 : *)((caddr_t)lsa->header
605 : + sizeof(struct ospf6_lsa_header));
606 2 : network_lsa->options[0] |= link_lsa->options[0];
607 2 : network_lsa->options[1] |= link_lsa->options[1];
608 2 : network_lsa->options[2] |= link_lsa->options[2];
609 : }
610 :
611 1 : lsdesc = (struct ospf6_network_lsdesc
612 : *)((caddr_t)network_lsa
613 : + sizeof(struct ospf6_network_lsa));
614 :
615 : /* set Link Description to the router itself */
616 1 : lsdesc->router_id = oi->area->ospf6->router_id;
617 1 : lsdesc++;
618 :
619 : /* Walk through the neighbors */
620 3 : for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, i, on)) {
621 1 : if (on->state != OSPF6_NEIGHBOR_FULL)
622 0 : continue;
623 :
624 : /* set this neighbor's Router-ID to LSA */
625 1 : lsdesc->router_id = on->router_id;
626 1 : lsdesc++;
627 : }
628 :
629 : /* Fill LSA Header */
630 1 : lsa_header->age = 0;
631 1 : lsa_header->type = htons(OSPF6_LSTYPE_NETWORK);
632 1 : lsa_header->id = htonl(oi->interface->ifindex);
633 1 : lsa_header->adv_router = oi->area->ospf6->router_id;
634 2 : lsa_header->seqnum =
635 1 : ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id,
636 : lsa_header->adv_router, oi->area->lsdb);
637 1 : lsa_header->length = htons((caddr_t)lsdesc - (caddr_t)buffer);
638 :
639 : /* LSA checksum */
640 1 : ospf6_lsa_checksum(lsa_header);
641 :
642 : /* create LSA */
643 1 : lsa = ospf6_lsa_create(lsa_header);
644 :
645 : /* Originate */
646 1 : ospf6_lsa_originate_area(lsa, oi->area);
647 : }
648 :
649 :
650 : /****************************/
651 : /* RFC2740 3.4.3.6 Link-LSA */
652 : /****************************/
653 :
654 0 : static char *ospf6_link_lsa_get_prefix_str(struct ospf6_lsa *lsa, char *buf,
655 : int buflen, int pos)
656 : {
657 0 : char *start, *end, *current;
658 0 : struct ospf6_link_lsa *link_lsa;
659 0 : struct in6_addr in6;
660 0 : struct ospf6_prefix *prefix;
661 0 : int cnt = 0, prefixnum;
662 :
663 0 : if (lsa) {
664 0 : link_lsa = (struct ospf6_link_lsa
665 0 : *)((caddr_t)lsa->header
666 : + sizeof(struct ospf6_lsa_header));
667 :
668 0 : if (pos == 0) {
669 0 : inet_ntop(AF_INET6, &link_lsa->linklocal_addr, buf,
670 : buflen);
671 0 : return (buf);
672 : }
673 :
674 0 : prefixnum = ntohl(link_lsa->prefix_num);
675 0 : if (pos > prefixnum)
676 : return NULL;
677 :
678 0 : start = (char *)link_lsa + sizeof(struct ospf6_link_lsa);
679 0 : end = (char *)lsa->header + ntohs(lsa->header->length);
680 0 : current = start;
681 :
682 0 : while (current + sizeof(struct ospf6_prefix) <= end) {
683 0 : prefix = (struct ospf6_prefix *)current;
684 0 : if (prefix->prefix_length == 0
685 0 : || current + OSPF6_PREFIX_SIZE(prefix) > end) {
686 : return NULL;
687 : }
688 :
689 0 : if (cnt < (pos - 1)) {
690 0 : current += OSPF6_PREFIX_SIZE(prefix);
691 0 : cnt++;
692 : } else {
693 0 : memset(&in6, 0, sizeof(in6));
694 0 : memcpy(&in6, OSPF6_PREFIX_BODY(prefix),
695 0 : OSPF6_PREFIX_SPACE(
696 : prefix->prefix_length));
697 0 : inet_ntop(AF_INET6, &in6, buf, buflen);
698 0 : return (buf);
699 : }
700 : }
701 : }
702 : return NULL;
703 : }
704 :
705 222 : static int ospf6_link_lsa_show(struct vty *vty, struct ospf6_lsa *lsa,
706 : json_object *json_obj, bool use_json)
707 : {
708 222 : char *start, *end, *current;
709 222 : struct ospf6_link_lsa *link_lsa;
710 222 : int prefixnum;
711 222 : char buf[128], options[32];
712 222 : struct ospf6_prefix *prefix;
713 222 : struct in6_addr in6;
714 222 : json_object *json_loop;
715 222 : json_object *json_arr = NULL;
716 222 : char prefix_string[133];
717 :
718 222 : link_lsa = (struct ospf6_link_lsa *)((caddr_t)lsa->header
719 : + sizeof(struct ospf6_lsa_header));
720 :
721 222 : ospf6_options_printbuf(link_lsa->options, options, sizeof(options));
722 222 : inet_ntop(AF_INET6, &link_lsa->linklocal_addr, buf, sizeof(buf));
723 222 : prefixnum = ntohl(link_lsa->prefix_num);
724 :
725 222 : if (use_json) {
726 222 : json_arr = json_object_new_array();
727 222 : json_object_int_add(json_obj, "priority", link_lsa->priority);
728 222 : json_object_string_add(json_obj, "options", options);
729 222 : json_object_string_add(json_obj, "linkLocalAddress", buf);
730 222 : json_object_int_add(json_obj, "numberOfPrefix", prefixnum);
731 : } else {
732 0 : vty_out(vty, " Priority: %d Options: %s\n",
733 0 : link_lsa->priority, options);
734 0 : vty_out(vty, " LinkLocal Address: %s\n", buf);
735 0 : vty_out(vty, " Number of Prefix: %d\n", prefixnum);
736 : }
737 :
738 222 : start = (char *)link_lsa + sizeof(struct ospf6_link_lsa);
739 222 : end = (char *)lsa->header + ntohs(lsa->header->length);
740 472 : for (current = start; current < end;
741 250 : current += OSPF6_PREFIX_SIZE(prefix)) {
742 250 : prefix = (struct ospf6_prefix *)current;
743 250 : if (prefix->prefix_length == 0
744 250 : || current + OSPF6_PREFIX_SIZE(prefix) > end)
745 : break;
746 :
747 250 : ospf6_prefix_options_printbuf(prefix->prefix_options, buf,
748 : sizeof(buf));
749 250 : if (use_json) {
750 250 : json_loop = json_object_new_object();
751 250 : json_object_string_add(json_loop, "prefixOption", buf);
752 : } else
753 0 : vty_out(vty, " Prefix Options: %s\n", buf);
754 :
755 250 : memset(&in6, 0, sizeof(in6));
756 250 : memcpy(&in6, OSPF6_PREFIX_BODY(prefix),
757 250 : OSPF6_PREFIX_SPACE(prefix->prefix_length));
758 250 : inet_ntop(AF_INET6, &in6, buf, sizeof(buf));
759 250 : if (use_json) {
760 250 : snprintf(prefix_string, sizeof(prefix_string), "%s/%d",
761 250 : buf, prefix->prefix_length);
762 250 : json_object_string_add(json_loop, "prefix",
763 : prefix_string);
764 250 : json_object_array_add(json_arr, json_loop);
765 : } else
766 0 : vty_out(vty, " Prefix: %s/%d\n", buf,
767 0 : prefix->prefix_length);
768 : }
769 222 : if (use_json)
770 222 : json_object_object_add(json_obj, "prefix", json_arr);
771 :
772 222 : return 0;
773 : }
774 :
775 18 : void ospf6_link_lsa_originate(struct thread *thread)
776 : {
777 18 : struct ospf6_interface *oi;
778 :
779 18 : char buffer[OSPF6_MAX_LSASIZE];
780 18 : struct ospf6_lsa_header *lsa_header;
781 18 : struct ospf6_lsa *old, *lsa;
782 :
783 18 : struct ospf6_link_lsa *link_lsa;
784 18 : struct ospf6_route *route;
785 18 : struct ospf6_prefix *op;
786 :
787 18 : oi = (struct ospf6_interface *)THREAD_ARG(thread);
788 :
789 18 : assert(oi->area);
790 18 : assert(oi->type != OSPF_IFTYPE_VIRTUALLINK);
791 :
792 18 : if (oi->area->ospf6->gr_info.restart_in_progress) {
793 0 : if (IS_DEBUG_OSPF6_GR)
794 0 : zlog_debug(
795 : "Graceful Restart in progress, don't originate LSA");
796 9 : return;
797 : }
798 :
799 :
800 : /* find previous LSA */
801 36 : old = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_LINK),
802 18 : htonl(oi->interface->ifindex),
803 : oi->area->ospf6->router_id, oi->lsdb);
804 :
805 18 : if (CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE)) {
806 0 : if (old)
807 0 : ospf6_lsa_purge(old);
808 0 : return;
809 : }
810 :
811 18 : if (IS_OSPF6_DEBUG_ORIGINATE(LINK))
812 0 : zlog_debug("Originate Link-LSA for Interface %pOI", oi);
813 :
814 : /* can't make Link-LSA if linklocal address not set */
815 18 : if (oi->linklocal_addr == NULL) {
816 9 : if (IS_OSPF6_DEBUG_ORIGINATE(LINK))
817 0 : zlog_debug(
818 : "No Linklocal address on %pOI, defer originating",
819 : oi);
820 9 : if (old)
821 0 : ospf6_lsa_purge(old);
822 9 : return;
823 : }
824 :
825 : /* prepare buffer */
826 9 : memset(buffer, 0, sizeof(buffer));
827 9 : lsa_header = (struct ospf6_lsa_header *)buffer;
828 9 : link_lsa = (struct ospf6_link_lsa *)((caddr_t)lsa_header
829 : + sizeof(struct ospf6_lsa_header));
830 :
831 : /* Fill Link-LSA */
832 9 : link_lsa->priority = oi->priority;
833 9 : memcpy(link_lsa->options, oi->area->options, 3);
834 9 : memcpy(&link_lsa->linklocal_addr, oi->linklocal_addr,
835 : sizeof(struct in6_addr));
836 9 : link_lsa->prefix_num = htonl(oi->route_connected->count);
837 :
838 9 : op = (struct ospf6_prefix *)((caddr_t)link_lsa
839 : + sizeof(struct ospf6_link_lsa));
840 :
841 : /* connected prefix to advertise */
842 16 : for (route = ospf6_route_head(oi->route_connected); route;
843 7 : route = ospf6_route_next(route)) {
844 7 : op->prefix_length = route->prefix.prefixlen;
845 7 : op->prefix_options = route->prefix_options;
846 7 : op->prefix_metric = htons(0);
847 7 : memcpy(OSPF6_PREFIX_BODY(op), &route->prefix.u.prefix6,
848 7 : OSPF6_PREFIX_SPACE(op->prefix_length));
849 7 : op = OSPF6_PREFIX_NEXT(op);
850 : }
851 :
852 : /* Fill LSA Header */
853 9 : lsa_header->age = 0;
854 9 : lsa_header->type = htons(OSPF6_LSTYPE_LINK);
855 9 : lsa_header->id = htonl(oi->interface->ifindex);
856 9 : lsa_header->adv_router = oi->area->ospf6->router_id;
857 18 : lsa_header->seqnum =
858 9 : ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id,
859 : lsa_header->adv_router, oi->lsdb);
860 9 : lsa_header->length = htons((caddr_t)op - (caddr_t)buffer);
861 :
862 : /* LSA checksum */
863 9 : ospf6_lsa_checksum(lsa_header);
864 :
865 : /* create LSA */
866 9 : lsa = ospf6_lsa_create(lsa_header);
867 :
868 : /* Originate */
869 9 : ospf6_lsa_originate_interface(lsa, oi);
870 : }
871 :
872 :
873 : /*****************************************/
874 : /* RFC2740 3.4.3.7 Intra-Area-Prefix-LSA */
875 : /*****************************************/
876 0 : static char *ospf6_intra_prefix_lsa_get_prefix_str(struct ospf6_lsa *lsa,
877 : char *buf, int buflen,
878 : int pos)
879 : {
880 0 : char *start, *end, *current;
881 0 : struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
882 0 : struct in6_addr in6;
883 0 : int prefixnum, cnt = 0;
884 0 : struct ospf6_prefix *prefix;
885 0 : char tbuf[16];
886 :
887 0 : if (lsa) {
888 0 : intra_prefix_lsa =
889 : (struct ospf6_intra_prefix_lsa
890 0 : *)((caddr_t)lsa->header
891 : + sizeof(struct ospf6_lsa_header));
892 :
893 0 : prefixnum = ntohs(intra_prefix_lsa->prefix_num);
894 0 : if ((pos + 1) > prefixnum)
895 : return NULL;
896 :
897 0 : start = (char *)intra_prefix_lsa
898 : + sizeof(struct ospf6_intra_prefix_lsa);
899 0 : end = (char *)lsa->header + ntohs(lsa->header->length);
900 0 : current = start;
901 :
902 0 : while (current + sizeof(struct ospf6_prefix) <= end) {
903 0 : prefix = (struct ospf6_prefix *)current;
904 0 : if (prefix->prefix_length == 0
905 0 : || current + OSPF6_PREFIX_SIZE(prefix) > end) {
906 : return NULL;
907 : }
908 :
909 0 : if (cnt < pos) {
910 0 : current += OSPF6_PREFIX_SIZE(prefix);
911 0 : cnt++;
912 : } else {
913 0 : memset(&in6, 0, sizeof(in6));
914 0 : memcpy(&in6, OSPF6_PREFIX_BODY(prefix),
915 0 : OSPF6_PREFIX_SPACE(
916 : prefix->prefix_length));
917 0 : inet_ntop(AF_INET6, &in6, buf, buflen);
918 0 : snprintf(tbuf, sizeof(tbuf), "/%d",
919 0 : prefix->prefix_length);
920 0 : strlcat(buf, tbuf, buflen);
921 0 : return (buf);
922 : }
923 : }
924 : }
925 : return NULL;
926 : }
927 :
928 219 : static int ospf6_intra_prefix_lsa_show(struct vty *vty, struct ospf6_lsa *lsa,
929 : json_object *json_obj, bool use_json)
930 : {
931 219 : char *start, *end, *current;
932 219 : struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
933 219 : int prefixnum;
934 219 : char buf[128];
935 219 : struct ospf6_prefix *prefix;
936 219 : char id[16], adv_router[16];
937 219 : struct in6_addr in6;
938 219 : json_object *json_loop;
939 219 : json_object *json_arr = NULL;
940 219 : char prefix_string[133];
941 :
942 219 : intra_prefix_lsa = (struct ospf6_intra_prefix_lsa
943 219 : *)((caddr_t)lsa->header
944 : + sizeof(struct ospf6_lsa_header));
945 :
946 219 : prefixnum = ntohs(intra_prefix_lsa->prefix_num);
947 :
948 219 : if (use_json) {
949 219 : json_arr = json_object_new_array();
950 219 : json_object_int_add(json_obj, "numberOfPrefix", prefixnum);
951 : } else
952 0 : vty_out(vty, " Number of Prefix: %d\n", prefixnum);
953 :
954 219 : inet_ntop(AF_INET, &intra_prefix_lsa->ref_id, id, sizeof(id));
955 219 : inet_ntop(AF_INET, &intra_prefix_lsa->ref_adv_router, adv_router,
956 : sizeof(adv_router));
957 219 : if (use_json) {
958 219 : json_object_string_add(
959 : json_obj, "reference",
960 219 : ospf6_lstype_name(intra_prefix_lsa->ref_type));
961 219 : json_object_string_add(json_obj, "referenceId", id);
962 219 : json_object_string_add(json_obj, "referenceAdv", adv_router);
963 : } else
964 0 : vty_out(vty, " Reference: %s Id: %s Adv: %s\n",
965 0 : ospf6_lstype_name(intra_prefix_lsa->ref_type), id,
966 : adv_router);
967 :
968 219 : start = (char *)intra_prefix_lsa
969 : + sizeof(struct ospf6_intra_prefix_lsa);
970 219 : end = (char *)lsa->header + ntohs(lsa->header->length);
971 450 : for (current = start; current < end;
972 231 : current += OSPF6_PREFIX_SIZE(prefix)) {
973 231 : prefix = (struct ospf6_prefix *)current;
974 231 : if (prefix->prefix_length == 0
975 231 : || current + OSPF6_PREFIX_SIZE(prefix) > end)
976 : break;
977 :
978 231 : ospf6_prefix_options_printbuf(prefix->prefix_options, buf,
979 : sizeof(buf));
980 231 : if (use_json) {
981 231 : json_loop = json_object_new_object();
982 231 : json_object_string_add(json_loop, "prefixOption", buf);
983 : } else
984 0 : vty_out(vty, " Prefix Options: %s\n", buf);
985 :
986 231 : memset(&in6, 0, sizeof(in6));
987 231 : memcpy(&in6, OSPF6_PREFIX_BODY(prefix),
988 231 : OSPF6_PREFIX_SPACE(prefix->prefix_length));
989 231 : inet_ntop(AF_INET6, &in6, buf, sizeof(buf));
990 231 : if (use_json) {
991 231 : snprintf(prefix_string, sizeof(prefix_string), "%s/%d",
992 231 : buf, prefix->prefix_length);
993 231 : json_object_string_add(json_loop, "prefix",
994 : prefix_string);
995 231 : json_object_int_add(json_loop, "metric",
996 231 : ntohs(prefix->prefix_metric));
997 231 : json_object_array_add(json_arr, json_loop);
998 : } else {
999 0 : vty_out(vty, " Prefix: %s/%d\n", buf,
1000 0 : prefix->prefix_length);
1001 0 : vty_out(vty, " Metric: %d\n",
1002 0 : ntohs(prefix->prefix_metric));
1003 : }
1004 : }
1005 219 : if (use_json)
1006 219 : json_object_object_add(json_obj, "prefix", json_arr);
1007 :
1008 219 : return 0;
1009 : }
1010 :
1011 0 : static struct ospf6_route *ospf6_intra_vlink_find_la(struct ospf6_area *oa)
1012 : {
1013 0 : bool debug = IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX);
1014 0 : struct connected *c;
1015 0 : struct listnode *i, *j;
1016 0 : struct in6_addr result, nh_addr;
1017 0 : struct ospf6_interface *oi, *oi_best = NULL;
1018 0 : struct ospf6_route *route;
1019 :
1020 0 : memset(&result, 0xff, sizeof(result));
1021 :
1022 0 : for (ALL_LIST_ELEMENTS_RO(oa->if_list, i, oi)) {
1023 0 : for (ALL_LIST_ELEMENTS_RO(oi->interface->connected, j, c)) {
1024 0 : if (!ospf6_interface_addr_valid(oi, c, debug))
1025 0 : continue;
1026 :
1027 0 : if (IPV6_ADDR_CMP(&c->address->u.prefix6, &result) >= 0)
1028 0 : continue;
1029 :
1030 0 : result = c->address->u.prefix6;
1031 0 : oi_best = oi;
1032 : }
1033 : }
1034 :
1035 0 : if (!oi_best) {
1036 0 : zlog_warn(
1037 : "area %pI4: %zu virtual links will not work, no viable global IPv6 address",
1038 : &oa->area_id, ospf6_vlink_area_vlcount(oa));
1039 0 : return NULL;
1040 : }
1041 :
1042 0 : if (debug)
1043 0 : zlog_debug(
1044 : "area %pI4: %zu virtual links; adding %pI6 as local address to Intra-Prefix LSA",
1045 : &oa->area_id, ospf6_vlink_area_vlcount(oa), &result);
1046 :
1047 0 : route = ospf6_route_create(oa->ospf6);
1048 0 : route->prefix.family = AF_INET6;
1049 0 : route->prefix.prefixlen = 128;
1050 0 : route->prefix.u.prefix6 = result;
1051 0 : route->prefix_options = OSPF6_PREFIX_OPTION_LA;
1052 0 : route->type = OSPF6_DEST_TYPE_NETWORK;
1053 0 : route->path.area_id = oa->area_id;
1054 0 : route->path.type = OSPF6_PATH_TYPE_INTRA;
1055 0 : route->path.cost = 0;
1056 0 : inet_pton(AF_INET6, "::1", &nh_addr);
1057 0 : ospf6_route_add_nexthop(route, oi_best->interface->ifindex, &nh_addr);
1058 :
1059 0 : return route;
1060 : }
1061 :
1062 25 : void ospf6_intra_prefix_lsa_originate_stub(struct thread *thread)
1063 : {
1064 25 : struct ospf6_area *oa;
1065 :
1066 25 : char buffer[OSPF6_MAX_LSASIZE];
1067 25 : struct ospf6_lsa_header *lsa_header;
1068 25 : struct ospf6_lsa *old, *lsa, *old_next = NULL;
1069 :
1070 25 : struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
1071 25 : struct ospf6_interface *oi;
1072 25 : struct ospf6_neighbor *on;
1073 25 : struct ospf6_route *route;
1074 25 : struct ospf6_prefix *op;
1075 25 : struct listnode *i, *j;
1076 25 : int full_count = 0;
1077 25 : unsigned short prefix_num = 0;
1078 25 : struct ospf6_route_table *route_advertise;
1079 25 : int ls_id = 0;
1080 25 : bool have_la = false;
1081 :
1082 25 : oa = (struct ospf6_area *)THREAD_ARG(thread);
1083 :
1084 25 : if (oa->ospf6->gr_info.restart_in_progress) {
1085 0 : if (IS_DEBUG_OSPF6_GR)
1086 0 : zlog_debug(
1087 : "Graceful Restart in progress, don't originate LSA");
1088 12 : return;
1089 : }
1090 :
1091 : /* find previous LSA */
1092 25 : old = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_INTRA_PREFIX), htonl(0),
1093 : oa->ospf6->router_id, oa->lsdb);
1094 :
1095 25 : if (!IS_AREA_ENABLED(oa)) {
1096 0 : if (old) {
1097 0 : ospf6_lsa_purge(old);
1098 : /* find previous LSA */
1099 0 : old_next = ospf6_lsdb_lookup(
1100 0 : htons(OSPF6_LSTYPE_INTRA_PREFIX),
1101 0 : htonl(++ls_id), oa->ospf6->router_id, oa->lsdb);
1102 :
1103 0 : while (old_next) {
1104 0 : ospf6_lsa_purge(old_next);
1105 0 : old_next = ospf6_lsdb_lookup(
1106 0 : htons(OSPF6_LSTYPE_INTRA_PREFIX),
1107 0 : htonl(++ls_id), oa->ospf6->router_id,
1108 : oa->lsdb);
1109 : }
1110 : }
1111 0 : return;
1112 : }
1113 :
1114 25 : if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
1115 0 : zlog_debug(
1116 : "Originate Intra-Area-Prefix-LSA for area %s's stub prefix",
1117 : oa->name);
1118 :
1119 : /* prepare buffer */
1120 25 : memset(buffer, 0, sizeof(buffer));
1121 25 : lsa_header = (struct ospf6_lsa_header *)buffer;
1122 25 : intra_prefix_lsa = (struct ospf6_intra_prefix_lsa
1123 : *)((caddr_t)lsa_header
1124 : + sizeof(struct ospf6_lsa_header));
1125 :
1126 : /* Fill Intra-Area-Prefix-LSA */
1127 25 : intra_prefix_lsa->ref_type = htons(OSPF6_LSTYPE_ROUTER);
1128 25 : intra_prefix_lsa->ref_id = htonl(0);
1129 25 : intra_prefix_lsa->ref_adv_router = oa->ospf6->router_id;
1130 :
1131 25 : route_advertise = ospf6_route_table_create(0, 0);
1132 :
1133 85 : for (ALL_LIST_ELEMENTS_RO(oa->if_list, i, oi)) {
1134 35 : if (oi->state == OSPF6_INTERFACE_DOWN) {
1135 13 : if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
1136 0 : zlog_debug(" Interface %pOI is down, ignore",
1137 : oi);
1138 13 : continue;
1139 : }
1140 :
1141 22 : full_count = 0;
1142 :
1143 70 : for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, j, on))
1144 26 : if (on->state == OSPF6_NEIGHBOR_FULL)
1145 19 : full_count++;
1146 :
1147 22 : if (oi->state != OSPF6_INTERFACE_LOOPBACK
1148 22 : && oi->state != OSPF6_INTERFACE_POINTTOPOINT
1149 22 : && oi->state != OSPF6_INTERFACE_POINTTOMULTIPOINT
1150 9 : && full_count != 0) {
1151 3 : if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
1152 0 : zlog_debug(" Interface %pOI is not stub, ignore",
1153 : oi);
1154 3 : continue;
1155 : }
1156 :
1157 19 : if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
1158 0 : zlog_debug(" Interface %pOI:", oi);
1159 :
1160 : /* connected prefix to advertise */
1161 34 : for (route = ospf6_route_head(oi->route_connected); route;
1162 15 : route = ospf6_route_best_next(route)) {
1163 15 : const char *la_flag = "";
1164 :
1165 15 : if (route->prefix_options & OSPF6_PREFIX_OPTION_LA) {
1166 13 : la_flag = " (LA)";
1167 13 : have_la = true;
1168 : }
1169 15 : if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
1170 0 : zlog_debug(" include %pFX%s",
1171 : &route->prefix, la_flag);
1172 15 : ospf6_route_add(ospf6_route_copy(route),
1173 : route_advertise);
1174 : }
1175 : }
1176 :
1177 25 : if (ospf6_vlink_area_vlcount(oa) && !have_la) {
1178 : /* if we're here, we have no loopback or ptp interfaces in
1179 : * the area (those always create LA=1 prefixes). So we need
1180 : * to grab a local addr somewhere else. Unfortunately,
1181 : * oi->route_connected contains masked prefixes, no addrs...
1182 : */
1183 :
1184 0 : route = ospf6_intra_vlink_find_la(oa);
1185 0 : if (route)
1186 0 : ospf6_route_add(route, route_advertise);
1187 : }
1188 :
1189 25 : if (route_advertise->count == 0) {
1190 12 : if (old) {
1191 0 : ls_id = 0;
1192 0 : ospf6_lsa_purge(old);
1193 : /* find previous LSA */
1194 0 : old_next = ospf6_lsdb_lookup(
1195 0 : htons(OSPF6_LSTYPE_INTRA_PREFIX),
1196 0 : htonl(++ls_id), oa->ospf6->router_id, oa->lsdb);
1197 :
1198 0 : while (old_next) {
1199 0 : ospf6_lsa_purge(old_next);
1200 0 : old_next = ospf6_lsdb_lookup(
1201 0 : htons(OSPF6_LSTYPE_INTRA_PREFIX),
1202 0 : htonl(++ls_id), oa->ospf6->router_id,
1203 : oa->lsdb);
1204 : }
1205 : }
1206 12 : ospf6_route_table_delete(route_advertise);
1207 12 : return;
1208 : }
1209 :
1210 : /* Neighbor change to FULL, if INTRA-AREA-PREFIX LSA
1211 : * has not change, Flush old LSA and Re-Originate INP,
1212 : * as ospf6_flood() checks if LSA is same as DB,
1213 : * it won't be updated to neighbor's DB.
1214 : */
1215 13 : if (oa->intra_prefix_originate) {
1216 7 : if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
1217 0 : zlog_debug(
1218 : "%s: Re-originate intra prefix LSA, Current full nbrs %u",
1219 : __func__, oa->full_nbrs);
1220 7 : if (old)
1221 7 : ospf6_lsa_purge_multi_ls_id(oa, old);
1222 7 : oa->intra_prefix_originate = 0;
1223 : }
1224 :
1225 : /* put prefixes to advertise */
1226 13 : prefix_num = 0;
1227 13 : op = (struct ospf6_prefix *)((caddr_t)intra_prefix_lsa
1228 : + sizeof(struct ospf6_intra_prefix_lsa));
1229 28 : for (route = ospf6_route_head(route_advertise); route;
1230 15 : route = ospf6_route_best_next(route)) {
1231 15 : if (((caddr_t)op - (caddr_t)lsa_header) > MAX_LSA_PAYLOAD) {
1232 :
1233 0 : intra_prefix_lsa->prefix_num = htons(prefix_num);
1234 :
1235 : /* Fill LSA Header */
1236 0 : lsa_header->age = 0;
1237 0 : lsa_header->type = htons(OSPF6_LSTYPE_INTRA_PREFIX);
1238 0 : lsa_header->id = htonl(ls_id++);
1239 0 : lsa_header->adv_router = oa->ospf6->router_id;
1240 0 : lsa_header->seqnum = ospf6_new_ls_seqnum(
1241 : lsa_header->type, lsa_header->id,
1242 : lsa_header->adv_router, oa->lsdb);
1243 0 : lsa_header->length =
1244 0 : htons((caddr_t)op - (caddr_t)lsa_header);
1245 :
1246 : /* LSA checksum */
1247 0 : ospf6_lsa_checksum(lsa_header);
1248 :
1249 : /* Create LSA */
1250 0 : lsa = ospf6_lsa_create(lsa_header);
1251 :
1252 : /* Originate */
1253 0 : ospf6_lsa_originate_area(lsa, oa);
1254 :
1255 : /* Prepare next buffer */
1256 0 : memset(buffer, 0, sizeof(buffer));
1257 0 : lsa_header = (struct ospf6_lsa_header *)buffer;
1258 0 : intra_prefix_lsa =
1259 : (struct ospf6_intra_prefix_lsa
1260 : *)((caddr_t)lsa_header
1261 : + sizeof(struct ospf6_lsa_header));
1262 :
1263 : /* Fill Intra-Area-Prefix-LSA */
1264 0 : intra_prefix_lsa->ref_type = htons(OSPF6_LSTYPE_ROUTER);
1265 0 : intra_prefix_lsa->ref_id = htonl(0);
1266 0 : intra_prefix_lsa->ref_adv_router = oa->ospf6->router_id;
1267 :
1268 : /* Put next set of prefixes to advertise */
1269 0 : prefix_num = 0;
1270 0 : op = (struct ospf6_prefix
1271 : *)((caddr_t)intra_prefix_lsa
1272 : + sizeof(struct
1273 : ospf6_intra_prefix_lsa));
1274 : }
1275 :
1276 15 : op->prefix_length = route->prefix.prefixlen;
1277 15 : op->prefix_options = route->prefix_options;
1278 15 : op->prefix_metric = htons(route->path.cost);
1279 15 : memcpy(OSPF6_PREFIX_BODY(op), &route->prefix.u.prefix6,
1280 15 : OSPF6_PREFIX_SPACE(op->prefix_length));
1281 15 : prefix_num++;
1282 :
1283 15 : op = OSPF6_PREFIX_NEXT(op);
1284 : }
1285 :
1286 13 : ospf6_route_table_delete(route_advertise);
1287 :
1288 13 : if (prefix_num == 0) {
1289 0 : if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
1290 0 : zlog_debug(
1291 : "Quit to Advertise Intra-Prefix: no route to advertise");
1292 0 : return;
1293 : }
1294 :
1295 13 : intra_prefix_lsa->prefix_num = htons(prefix_num);
1296 :
1297 : /* Fill LSA Header */
1298 13 : lsa_header->age = 0;
1299 13 : lsa_header->type = htons(OSPF6_LSTYPE_INTRA_PREFIX);
1300 13 : lsa_header->id = htonl(ls_id++);
1301 13 : lsa_header->adv_router = oa->ospf6->router_id;
1302 26 : lsa_header->seqnum =
1303 13 : ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id,
1304 : lsa_header->adv_router, oa->lsdb);
1305 13 : lsa_header->length = htons((caddr_t)op - (caddr_t)lsa_header);
1306 :
1307 : /* LSA checksum */
1308 13 : ospf6_lsa_checksum(lsa_header);
1309 :
1310 : /* create LSA */
1311 13 : lsa = ospf6_lsa_create(lsa_header);
1312 :
1313 : /* Originate */
1314 13 : ospf6_lsa_originate_area(lsa, oa);
1315 : }
1316 :
1317 :
1318 29 : void ospf6_intra_prefix_lsa_originate_transit(struct thread *thread)
1319 : {
1320 29 : struct ospf6_interface *oi;
1321 :
1322 29 : char buffer[OSPF6_MAX_LSASIZE];
1323 29 : struct ospf6_lsa_header *lsa_header;
1324 29 : struct ospf6_lsa *old, *lsa;
1325 :
1326 29 : struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
1327 29 : struct ospf6_neighbor *on;
1328 29 : struct ospf6_route *route;
1329 29 : struct ospf6_prefix *op;
1330 29 : struct listnode *i;
1331 29 : int full_count = 0;
1332 29 : unsigned short prefix_num = 0;
1333 29 : struct ospf6_route_table *route_advertise;
1334 29 : struct ospf6_link_lsa *link_lsa;
1335 29 : char *start, *end, *current;
1336 29 : uint16_t type;
1337 :
1338 29 : oi = (struct ospf6_interface *)THREAD_ARG(thread);
1339 :
1340 29 : assert(oi->area);
1341 29 : assert(oi->type != OSPF_IFTYPE_VIRTUALLINK);
1342 :
1343 29 : if (oi->area->ospf6->gr_info.restart_in_progress) {
1344 0 : if (IS_DEBUG_OSPF6_GR)
1345 0 : zlog_debug(
1346 : "Graceful Restart in progress, don't originate LSA");
1347 29 : return;
1348 : }
1349 :
1350 : /* find previous LSA */
1351 58 : old = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_INTRA_PREFIX),
1352 29 : htonl(oi->interface->ifindex),
1353 : oi->area->ospf6->router_id, oi->area->lsdb);
1354 :
1355 29 : if (CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE)) {
1356 10 : if (old)
1357 0 : ospf6_lsa_purge(old);
1358 10 : return;
1359 : }
1360 :
1361 19 : if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
1362 0 : zlog_debug(
1363 : "Originate Intra-Area-Prefix-LSA for interface %pOI's prefix",
1364 : oi);
1365 :
1366 : /* prepare buffer */
1367 19 : memset(buffer, 0, sizeof(buffer));
1368 19 : lsa_header = (struct ospf6_lsa_header *)buffer;
1369 19 : intra_prefix_lsa = (struct ospf6_intra_prefix_lsa
1370 : *)((caddr_t)lsa_header
1371 : + sizeof(struct ospf6_lsa_header));
1372 :
1373 : /* Fill Intra-Area-Prefix-LSA */
1374 19 : intra_prefix_lsa->ref_type = htons(OSPF6_LSTYPE_NETWORK);
1375 19 : intra_prefix_lsa->ref_id = htonl(oi->interface->ifindex);
1376 19 : intra_prefix_lsa->ref_adv_router = oi->area->ospf6->router_id;
1377 :
1378 19 : if (oi->state != OSPF6_INTERFACE_DR) {
1379 16 : if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
1380 0 : zlog_debug(" Interface is not DR");
1381 16 : if (old)
1382 0 : ospf6_lsa_purge(old);
1383 16 : return;
1384 : }
1385 :
1386 3 : full_count = 0;
1387 9 : for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, i, on))
1388 3 : if (on->state == OSPF6_NEIGHBOR_FULL)
1389 1 : full_count++;
1390 :
1391 3 : if (full_count == 0) {
1392 2 : if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
1393 0 : zlog_debug(" Interface is stub");
1394 2 : if (old)
1395 0 : ospf6_lsa_purge(old);
1396 2 : return;
1397 : }
1398 :
1399 : /* connected prefix to advertise */
1400 1 : route_advertise = ospf6_route_table_create(0, 0);
1401 :
1402 1 : type = ntohs(OSPF6_LSTYPE_LINK);
1403 3 : for (ALL_LSDB_TYPED(oi->lsdb, type, lsa)) {
1404 2 : if (OSPF6_LSA_IS_MAXAGE(lsa))
1405 0 : continue;
1406 :
1407 2 : if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
1408 0 : zlog_debug(" include prefix from %s", lsa->name);
1409 :
1410 2 : if (lsa->header->adv_router != oi->area->ospf6->router_id) {
1411 1 : on = ospf6_neighbor_lookup(lsa->header->adv_router, oi);
1412 1 : if (on == NULL || on->state != OSPF6_NEIGHBOR_FULL) {
1413 0 : if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
1414 0 : zlog_debug(
1415 : " Neighbor not found or not Full, ignore");
1416 0 : continue;
1417 : }
1418 : }
1419 :
1420 2 : link_lsa = (struct ospf6_link_lsa
1421 2 : *)((caddr_t)lsa->header
1422 : + sizeof(struct ospf6_lsa_header));
1423 :
1424 2 : prefix_num = (unsigned short)ntohl(link_lsa->prefix_num);
1425 2 : start = (char *)link_lsa + sizeof(struct ospf6_link_lsa);
1426 2 : end = (char *)lsa->header + ntohs(lsa->header->length);
1427 2 : for (current = start; current < end && prefix_num;
1428 0 : current += OSPF6_PREFIX_SIZE(op)) {
1429 0 : op = (struct ospf6_prefix *)current;
1430 0 : if (op->prefix_length == 0
1431 0 : || current + OSPF6_PREFIX_SIZE(op) > end)
1432 : break;
1433 :
1434 0 : route = ospf6_route_create(oi->area->ospf6);
1435 :
1436 0 : route->type = OSPF6_DEST_TYPE_NETWORK;
1437 0 : route->prefix.family = AF_INET6;
1438 0 : route->prefix.prefixlen = op->prefix_length;
1439 0 : memset(&route->prefix.u.prefix6, 0,
1440 : sizeof(struct in6_addr));
1441 0 : memcpy(&route->prefix.u.prefix6, OSPF6_PREFIX_BODY(op),
1442 0 : OSPF6_PREFIX_SPACE(op->prefix_length));
1443 0 : route->prefix_options = op->prefix_options;
1444 :
1445 0 : route->path.origin.type = lsa->header->type;
1446 0 : route->path.origin.id = lsa->header->id;
1447 0 : route->path.origin.adv_router = lsa->header->adv_router;
1448 0 : route->path.options[0] = link_lsa->options[0];
1449 0 : route->path.options[1] = link_lsa->options[1];
1450 0 : route->path.options[2] = link_lsa->options[2];
1451 0 : route->path.area_id = oi->area->area_id;
1452 0 : route->path.type = OSPF6_PATH_TYPE_INTRA;
1453 :
1454 0 : if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
1455 0 : zlog_debug(" include %pFX", &route->prefix);
1456 :
1457 0 : ospf6_route_add(route, route_advertise);
1458 0 : prefix_num--;
1459 : }
1460 2 : if (current != end && IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
1461 2 : zlog_debug("Trailing garbage in %s", lsa->name);
1462 : }
1463 :
1464 1 : op = (struct ospf6_prefix *)((caddr_t)intra_prefix_lsa
1465 : + sizeof(struct ospf6_intra_prefix_lsa));
1466 :
1467 1 : prefix_num = 0;
1468 1 : for (route = ospf6_route_head(route_advertise); route;
1469 0 : route = ospf6_route_best_next(route)) {
1470 0 : op->prefix_length = route->prefix.prefixlen;
1471 0 : op->prefix_options = route->prefix_options;
1472 0 : op->prefix_metric = htons(0);
1473 0 : memcpy(OSPF6_PREFIX_BODY(op), &route->prefix.u.prefix6,
1474 0 : OSPF6_PREFIX_SPACE(op->prefix_length));
1475 0 : op = OSPF6_PREFIX_NEXT(op);
1476 0 : prefix_num++;
1477 : }
1478 :
1479 1 : ospf6_route_table_delete(route_advertise);
1480 :
1481 1 : if (prefix_num == 0) {
1482 1 : if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
1483 0 : zlog_debug(
1484 : "Quit to Advertise Intra-Prefix: no route to advertise");
1485 1 : return;
1486 : }
1487 :
1488 0 : intra_prefix_lsa->prefix_num = htons(prefix_num);
1489 :
1490 : /* Fill LSA Header */
1491 0 : lsa_header->age = 0;
1492 0 : lsa_header->type = htons(OSPF6_LSTYPE_INTRA_PREFIX);
1493 0 : lsa_header->id = htonl(oi->interface->ifindex);
1494 0 : lsa_header->adv_router = oi->area->ospf6->router_id;
1495 0 : lsa_header->seqnum =
1496 0 : ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id,
1497 : lsa_header->adv_router, oi->area->lsdb);
1498 0 : lsa_header->length = htons((caddr_t)op - (caddr_t)lsa_header);
1499 :
1500 : /* LSA checksum */
1501 0 : ospf6_lsa_checksum(lsa_header);
1502 :
1503 : /* create LSA */
1504 0 : lsa = ospf6_lsa_create(lsa_header);
1505 :
1506 : /* Originate */
1507 0 : ospf6_lsa_originate_area(lsa, oi->area);
1508 : }
1509 :
1510 1 : static void ospf6_intra_prefix_update_route_origin(struct ospf6_route *oa_route,
1511 : struct ospf6 *ospf6)
1512 : {
1513 1 : struct ospf6_path *h_path;
1514 1 : struct ospf6_route *g_route, *nroute;
1515 :
1516 : /* Update Global ospf6 route path */
1517 1 : g_route = ospf6_route_lookup(&oa_route->prefix, ospf6->route_table);
1518 :
1519 1 : assert(g_route);
1520 :
1521 2 : for (ospf6_route_lock(g_route); g_route &&
1522 1 : ospf6_route_is_prefix(&oa_route->prefix, g_route);
1523 : g_route = nroute) {
1524 1 : nroute = ospf6_route_next(g_route);
1525 1 : if (g_route->type != oa_route->type)
1526 0 : continue;
1527 1 : if (g_route->path.area_id != oa_route->path.area_id)
1528 0 : continue;
1529 1 : if (g_route->path.type != OSPF6_PATH_TYPE_INTRA)
1530 0 : continue;
1531 1 : if (g_route->path.cost != oa_route->path.cost)
1532 0 : continue;
1533 :
1534 1 : if (ospf6_route_is_same_origin(g_route, oa_route)) {
1535 1 : h_path = (struct ospf6_path *)listgetdata(
1536 : listhead(g_route->paths));
1537 1 : g_route->path.origin.type = h_path->origin.type;
1538 1 : g_route->path.origin.id = h_path->origin.id;
1539 1 : g_route->path.origin.adv_router =
1540 1 : h_path->origin.adv_router;
1541 1 : if (nroute)
1542 1 : ospf6_route_unlock(nroute);
1543 : break;
1544 : }
1545 : }
1546 :
1547 1 : h_path = (struct ospf6_path *)listgetdata(
1548 : listhead(oa_route->paths));
1549 1 : oa_route->path.origin.type = h_path->origin.type;
1550 1 : oa_route->path.origin.id = h_path->origin.id;
1551 1 : oa_route->path.origin.adv_router = h_path->origin.adv_router;
1552 1 : }
1553 :
1554 83 : void ospf6_intra_prefix_route_ecmp_path(struct ospf6_area *oa,
1555 : struct ospf6_route *old,
1556 : struct ospf6_route *route)
1557 : {
1558 83 : struct ospf6_route *old_route, *ls_entry;
1559 83 : struct ospf6_path *ecmp_path, *o_path = NULL;
1560 83 : struct listnode *anode, *anext;
1561 83 : struct listnode *nnode, *rnode, *rnext;
1562 83 : struct ospf6_nexthop *nh, *rnh;
1563 83 : bool route_found = false;
1564 83 : struct interface *ifp = NULL;
1565 83 : struct ospf6_lsa *lsa;
1566 83 : struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
1567 :
1568 : /* check for old entry match with new route origin,
1569 : * delete old entry.
1570 : */
1571 169 : for (old_route = old; old_route; old_route = old_route->next) {
1572 135 : bool route_updated = false;
1573 :
1574 : /* The route linked-list is grouped in batches of prefix.
1575 : * If the new prefix is not the same as the one of interest
1576 : * then we have walked over the end of the batch and so we
1577 : * should break rather than continuing unnecessarily.
1578 : */
1579 135 : if (!ospf6_route_is_same(old_route, route))
1580 : break;
1581 87 : if (old_route->path.type != route->path.type)
1582 0 : continue;
1583 :
1584 : /* Current and New route has same origin,
1585 : * delete old entry.
1586 : */
1587 262 : for (ALL_LIST_ELEMENTS(old_route->paths, anode, anext,
1588 : o_path)) {
1589 : /* Check old route path and route has same
1590 : * origin.
1591 : */
1592 89 : if (o_path->area_id != route->path.area_id
1593 89 : || !ospf6_ls_origin_same(o_path, &route->path))
1594 10 : continue;
1595 :
1596 : /* Cost is not same then delete current path */
1597 79 : if (o_path->cost == route->path.cost)
1598 78 : continue;
1599 :
1600 1 : if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
1601 0 : zlog_debug(
1602 : "%s: route %pFX cost old %u new %u is not same, replace route",
1603 : __func__, &old_route->prefix, o_path->cost,
1604 : route->path.cost);
1605 : }
1606 :
1607 : /* Remove selected current path's nh from
1608 : * effective nh list.
1609 : */
1610 3 : for (ALL_LIST_ELEMENTS_RO(o_path->nh_list, nnode, nh)) {
1611 3 : for (ALL_LIST_ELEMENTS(old_route->nh_list,
1612 : rnode, rnext, rnh)) {
1613 1 : if (!ospf6_nexthop_is_same(rnh, nh))
1614 0 : continue;
1615 1 : listnode_delete(old_route->nh_list,
1616 : rnh);
1617 1 : ospf6_nexthop_delete(rnh);
1618 1 : route_updated = true;
1619 : }
1620 : }
1621 :
1622 1 : listnode_delete(old_route->paths, o_path);
1623 1 : ospf6_path_free(o_path);
1624 :
1625 : /* Current route's path (adv_router info) is similar
1626 : * to route being added.
1627 : * Replace current route's path with paths list head.
1628 : * Update FIB with effective NHs.
1629 : */
1630 1 : if (listcount(old_route->paths)) {
1631 0 : if (route_updated) {
1632 0 : for (ALL_LIST_ELEMENTS(old_route->paths,
1633 : anode, anext, o_path)) {
1634 0 : ospf6_merge_nexthops(
1635 : old_route->nh_list,
1636 : o_path->nh_list);
1637 : }
1638 : /* Update ospf6 route table and
1639 : * RIB/FIB with effective
1640 : * nh_list
1641 : */
1642 0 : if (oa->route_table->hook_add)
1643 0 : (*oa->route_table->hook_add)(
1644 : old_route);
1645 :
1646 0 : if (old_route->path.origin.id ==
1647 0 : route->path.origin.id &&
1648 0 : old_route->path.origin.adv_router ==
1649 0 : route->path.origin.adv_router) {
1650 0 : ospf6_intra_prefix_update_route_origin(
1651 : old_route, oa->ospf6);
1652 : }
1653 : break;
1654 : }
1655 : } else {
1656 1 : if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
1657 0 : zlog_debug(
1658 : "%s: route %pFX old cost %u new cost %u, delete old entry.",
1659 : __func__, &old_route->prefix,
1660 : old_route->path.cost,
1661 : route->path.cost);
1662 : }
1663 1 : if (oa->route_table->hook_remove)
1664 0 : ospf6_route_remove(old_route,
1665 : oa->route_table);
1666 : else
1667 1 : SET_FLAG(old_route->flag,
1668 : OSPF6_ROUTE_REMOVE);
1669 : break;
1670 : }
1671 : }
1672 87 : if (route_updated)
1673 : break;
1674 : }
1675 :
1676 89 : for (old_route = old; old_route; old_route = old_route->next) {
1677 :
1678 : /* The route linked-list is grouped in batches of prefix.
1679 : * If the new prefix is not the same as the one of interest
1680 : * then we have walked over the end of the batch and so we
1681 : * should break rather than continuing unnecessarily.
1682 : */
1683 88 : if (!ospf6_route_is_same(old_route, route))
1684 : break;
1685 85 : if (old_route->path.type != route->path.type)
1686 0 : continue;
1687 :
1688 : /* Old Route and New Route have Equal Cost, Merge NHs */
1689 85 : if (old_route->path.cost == route->path.cost) {
1690 79 : route_found = true;
1691 :
1692 : /* check if this path exists already in
1693 : * route->paths list, if so, replace nh_list.
1694 : */
1695 160 : for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode,
1696 : o_path)) {
1697 80 : if (o_path->area_id == route->path.area_id
1698 80 : && ospf6_ls_origin_same(o_path, &route->path))
1699 : break;
1700 : }
1701 : /* If path is not found in old_route paths's list,
1702 : * add a new path to route paths list and merge
1703 : * nexthops in route->path->nh_list.
1704 : * Otherwise replace existing path's nh_list.
1705 : */
1706 79 : if (o_path == NULL) {
1707 1 : ecmp_path = ospf6_path_dup(&route->path);
1708 :
1709 : /* Add a nh_list to new ecmp path */
1710 1 : ospf6_copy_nexthops(ecmp_path->nh_list,
1711 : route->nh_list);
1712 : /* Add the new path to route's path list */
1713 1 : listnode_add_sort(old_route->paths, ecmp_path);
1714 :
1715 1 : if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
1716 0 : zlog_debug(
1717 : "%s: route %pFX %p another path added with nh %u, effective paths %u nh %u",
1718 : __func__, &route->prefix,
1719 : (void *)old_route,
1720 : listcount(ecmp_path->nh_list),
1721 : old_route->paths ? listcount(
1722 : old_route->paths)
1723 : : 0,
1724 : listcount(old_route->nh_list));
1725 : }
1726 : } else {
1727 78 : list_delete_all_node(o_path->nh_list);
1728 78 : ospf6_copy_nexthops(o_path->nh_list,
1729 : route->nh_list);
1730 :
1731 : }
1732 :
1733 79 : list_delete_all_node(old_route->nh_list);
1734 :
1735 240 : for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode,
1736 : o_path)) {
1737 82 : ls_entry = ospf6_route_lookup(
1738 : &o_path->ls_prefix,
1739 : oa->spf_table);
1740 82 : if (ls_entry == NULL) {
1741 0 : if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
1742 0 : zlog_debug(
1743 : "%s: ls_prfix %pFX ls_entry not found.",
1744 : __func__,
1745 : &o_path->ls_prefix);
1746 0 : continue;
1747 : }
1748 82 : lsa = ospf6_lsdb_lookup(o_path->origin.type,
1749 : o_path->origin.id,
1750 : o_path->origin.adv_router,
1751 : oa->lsdb);
1752 82 : if (lsa == NULL) {
1753 0 : if (IS_OSPF6_DEBUG_EXAMIN(
1754 : INTRA_PREFIX)) {
1755 0 : struct prefix adv_prefix;
1756 :
1757 0 : ospf6_linkstate_prefix(
1758 : o_path->origin.adv_router,
1759 : o_path->origin.id, &adv_prefix);
1760 0 : zlog_debug(
1761 : "%s: adv_router %pFX lsa not found",
1762 : __func__, &adv_prefix);
1763 : }
1764 0 : continue;
1765 : }
1766 82 : intra_prefix_lsa =
1767 : (struct ospf6_intra_prefix_lsa *)
1768 82 : OSPF6_LSA_HEADER_END(lsa->header);
1769 :
1770 82 : if (intra_prefix_lsa->ref_adv_router
1771 82 : == oa->ospf6->router_id) {
1772 39 : ifp = if_lookup_prefix(
1773 : &old_route->prefix,
1774 : oa->ospf6->vrf_id);
1775 : }
1776 :
1777 82 : if (ifp) {
1778 : /* Nexthop interface found */
1779 4 : ospf6_route_add_nexthop(old_route,
1780 : ifp->ifindex,
1781 : NULL);
1782 : } else {
1783 : /* The connected interfaces between
1784 : * routers can be in different networks.
1785 : * In this case the matching interface
1786 : * is not found. Copy nexthops from the
1787 : * link state entry
1788 : */
1789 78 : ospf6_route_merge_nexthops(old_route,
1790 : ls_entry);
1791 : }
1792 : }
1793 :
1794 79 : if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
1795 0 : zlog_debug(
1796 : "%s: route %pFX %p with final effective paths %u nh %u",
1797 : __func__, &route->prefix,
1798 : (void *)old_route,
1799 : old_route->paths
1800 : ? listcount(old_route->paths)
1801 : : 0,
1802 : listcount(old_route->nh_list));
1803 :
1804 : /* used in intra_route_calculation() to add to
1805 : * global ospf6 route table.
1806 : */
1807 79 : UNSET_FLAG(old_route->flag, OSPF6_ROUTE_REMOVE);
1808 79 : SET_FLAG(old_route->flag, OSPF6_ROUTE_ADD);
1809 : /* Update ospf6 route table and RIB/FIB */
1810 79 : if (oa->route_table->hook_add)
1811 8 : (*oa->route_table->hook_add)(old_route);
1812 : /* Delete the new route its info added to existing
1813 : * route.
1814 : */
1815 79 : ospf6_route_delete(route);
1816 :
1817 79 : break;
1818 : }
1819 : }
1820 :
1821 79 : if (!route_found) {
1822 : /* Add new route to existing node in ospf6 route table. */
1823 4 : ospf6_route_add(route, oa->route_table);
1824 : }
1825 83 : }
1826 :
1827 123 : void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa)
1828 : {
1829 123 : struct ospf6_area *oa;
1830 123 : struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
1831 123 : struct prefix ls_prefix;
1832 123 : struct ospf6_route *route, *ls_entry, *old;
1833 123 : int prefix_num;
1834 123 : struct ospf6_prefix *op;
1835 123 : char *start, *current, *end;
1836 123 : char buf[PREFIX2STR_BUFFER];
1837 123 : struct interface *ifp = NULL;
1838 123 : int direct_connect = 0;
1839 123 : struct ospf6_path *path;
1840 :
1841 123 : if (OSPF6_LSA_IS_MAXAGE(lsa))
1842 34 : return;
1843 :
1844 118 : if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
1845 0 : zlog_debug("%s: LSA %s found", __func__, lsa->name);
1846 :
1847 118 : oa = OSPF6_AREA(lsa->lsdb->data);
1848 :
1849 118 : intra_prefix_lsa =
1850 118 : (struct ospf6_intra_prefix_lsa *)OSPF6_LSA_HEADER_END(
1851 : lsa->header);
1852 118 : if (intra_prefix_lsa->ref_type == htons(OSPF6_LSTYPE_ROUTER) ||
1853 0 : intra_prefix_lsa->ref_type == htons(OSPF6_LSTYPE_NETWORK))
1854 118 : ospf6_linkstate_prefix(intra_prefix_lsa->ref_adv_router,
1855 : intra_prefix_lsa->ref_id, &ls_prefix);
1856 : else {
1857 0 : if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
1858 0 : zlog_debug("Unknown reference LS-type: %#hx",
1859 : ntohs(intra_prefix_lsa->ref_type));
1860 0 : return;
1861 : }
1862 :
1863 118 : ls_entry = ospf6_route_lookup(&ls_prefix, oa->spf_table);
1864 118 : if (ls_entry == NULL) {
1865 29 : if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
1866 0 : ospf6_linkstate_prefix2str(&ls_prefix, buf,
1867 : sizeof(buf));
1868 0 : zlog_debug("LS entry does not exist: %s", buf);
1869 : }
1870 29 : return;
1871 : }
1872 :
1873 89 : if (intra_prefix_lsa->ref_adv_router == oa->ospf6->router_id) {
1874 : /* the intra-prefix are directly connected */
1875 40 : direct_connect = 1;
1876 : }
1877 :
1878 89 : prefix_num = ntohs(intra_prefix_lsa->prefix_num);
1879 89 : start = (caddr_t)intra_prefix_lsa
1880 : + sizeof(struct ospf6_intra_prefix_lsa);
1881 89 : end = OSPF6_LSA_END(lsa->header);
1882 196 : for (current = start; current < end; current += OSPF6_PREFIX_SIZE(op)) {
1883 107 : op = (struct ospf6_prefix *)current;
1884 107 : if (prefix_num == 0)
1885 : break;
1886 107 : if (end < current + OSPF6_PREFIX_SIZE(op))
1887 : break;
1888 :
1889 : /* Appendix A.4.1.1 */
1890 107 : if (CHECK_FLAG(op->prefix_options, OSPF6_PREFIX_OPTION_NU)) {
1891 0 : if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
1892 0 : ospf6_linkstate_prefix2str(
1893 : (struct prefix *)OSPF6_PREFIX_BODY(op),
1894 : buf, sizeof(buf));
1895 0 : zlog_debug(
1896 : "%s: Skipping Prefix %s has NU option set",
1897 : __func__, buf);
1898 : }
1899 0 : continue;
1900 : }
1901 :
1902 107 : route = ospf6_route_create(oa->ospf6);
1903 :
1904 107 : memset(&route->prefix, 0, sizeof(struct prefix));
1905 107 : route->prefix.family = AF_INET6;
1906 107 : route->prefix.prefixlen = op->prefix_length;
1907 107 : ospf6_prefix_in6_addr(&route->prefix.u.prefix6,
1908 : intra_prefix_lsa, op);
1909 107 : route->prefix_options = op->prefix_options;
1910 :
1911 107 : route->type = OSPF6_DEST_TYPE_NETWORK;
1912 107 : route->path.origin.type = lsa->header->type;
1913 107 : route->path.origin.id = lsa->header->id;
1914 107 : route->path.origin.adv_router = lsa->header->adv_router;
1915 107 : route->path.area_id = oa->area_id;
1916 107 : route->path.type = OSPF6_PATH_TYPE_INTRA;
1917 107 : route->path.metric_type = 1;
1918 107 : route->path.cost =
1919 107 : ls_entry->path.cost + ntohs(op->prefix_metric);
1920 107 : memcpy(&route->path.ls_prefix, &ls_prefix,
1921 : sizeof(struct prefix));
1922 107 : if (direct_connect) {
1923 46 : ifp = if_lookup_prefix(&route->prefix,
1924 46 : oa->ospf6->vrf_id);
1925 : }
1926 :
1927 107 : if (ifp) {
1928 : /* Nexthop interface found */
1929 6 : ospf6_route_add_nexthop(route, ifp->ifindex, NULL);
1930 : } else {
1931 : /* The connected interfaces between routers can be in
1932 : * different networks. In this case the matching
1933 : * interface is not found. Copy nexthops from the
1934 : * link state entry
1935 : */
1936 101 : ospf6_route_copy_nexthops(route, ls_entry);
1937 : }
1938 :
1939 107 : path = ospf6_path_dup(&route->path);
1940 107 : ospf6_copy_nexthops(path->nh_list, route->path.nh_list);
1941 107 : listnode_add_sort(route->paths, path);
1942 :
1943 107 : old = ospf6_route_lookup(&route->prefix, oa->route_table);
1944 107 : if (old) {
1945 83 : if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
1946 0 : prefix2str(&route->prefix, buf, sizeof(buf));
1947 0 : zlog_debug(
1948 : "%s Update route: %s old cost %u new cost %u paths %u nh %u",
1949 : __func__, buf, old->path.cost,
1950 : route->path.cost,
1951 : listcount(route->paths),
1952 : listcount(route->nh_list));
1953 : }
1954 83 : ospf6_intra_prefix_route_ecmp_path(oa, old, route);
1955 : } else {
1956 24 : if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
1957 0 : prefix2str(&route->prefix, buf, sizeof(buf));
1958 0 : zlog_debug(
1959 : "%s route %s add with cost %u paths %u nh %u",
1960 : __func__, buf, route->path.cost,
1961 : listcount(route->paths),
1962 : listcount(route->nh_list));
1963 : }
1964 24 : ospf6_route_add(route, oa->route_table);
1965 : }
1966 107 : prefix_num--;
1967 : }
1968 :
1969 89 : ospf6_vlink_prefix_update(oa, lsa->header->adv_router);
1970 :
1971 89 : if (current != end && IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
1972 89 : zlog_debug("Trailing garbage ignored");
1973 : }
1974 :
1975 1 : static void ospf6_intra_prefix_lsa_remove_update_route(struct ospf6_lsa *lsa,
1976 : struct ospf6_area *oa,
1977 : struct ospf6_route *route)
1978 : {
1979 1 : struct listnode *anode, *anext;
1980 1 : struct listnode *nnode, *rnode, *rnext;
1981 1 : struct ospf6_nexthop *nh, *rnh;
1982 1 : struct ospf6_path *o_path;
1983 1 : bool nh_updated = false;
1984 1 : char buf[PREFIX2STR_BUFFER];
1985 :
1986 : /* Iterate all paths of route to find maching
1987 : * with LSA remove info.
1988 : * If route->path is same, replace
1989 : * from paths list.
1990 : */
1991 2 : for (ALL_LIST_ELEMENTS(route->paths, anode, anext, o_path)) {
1992 1 : if ((o_path->origin.type != lsa->header->type) ||
1993 1 : (o_path->origin.adv_router != lsa->header->adv_router) ||
1994 1 : (o_path->origin.id != lsa->header->id))
1995 0 : continue;
1996 :
1997 1 : if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
1998 0 : prefix2str(&route->prefix, buf, sizeof(buf));
1999 0 : zlog_debug(
2000 : "%s: route %s path found with cost %u nh %u to remove.",
2001 : __func__, buf, o_path->cost,
2002 : listcount(o_path->nh_list));
2003 : }
2004 :
2005 : /* Remove found path's nh_list from
2006 : * the route's nh_list.
2007 : */
2008 3 : for (ALL_LIST_ELEMENTS_RO(o_path->nh_list, nnode, nh)) {
2009 4 : for (ALL_LIST_ELEMENTS(route->nh_list, rnode,
2010 : rnext, rnh)) {
2011 2 : if (!ospf6_nexthop_is_same(rnh, nh))
2012 1 : continue;
2013 1 : listnode_delete(route->nh_list, rnh);
2014 1 : ospf6_nexthop_delete(rnh);
2015 : }
2016 : }
2017 : /* Delete the path from route's
2018 : * path list
2019 : */
2020 1 : listnode_delete(route->paths, o_path);
2021 1 : ospf6_path_free(o_path);
2022 1 : nh_updated = true;
2023 1 : break;
2024 : }
2025 :
2026 1 : if (nh_updated) {
2027 : /* Iterate all paths and merge nexthop,
2028 : * unlesss any of the nexthop similar to
2029 : * ones deleted as part of path deletion.
2030 : */
2031 3 : for (ALL_LIST_ELEMENTS(route->paths, anode, anext, o_path))
2032 1 : ospf6_merge_nexthops(route->nh_list, o_path->nh_list);
2033 :
2034 :
2035 1 : if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
2036 0 : prefix2str(&route->prefix, buf, sizeof(buf));
2037 0 : zlog_debug(
2038 : "%s: route %s update paths %u nh %u", __func__,
2039 : buf, route->paths ? listcount(route->paths) : 0,
2040 : route->nh_list ? listcount(route->nh_list) : 0);
2041 : }
2042 :
2043 : /* Update Global Route table and
2044 : * RIB/FIB with effective
2045 : * nh_list
2046 : */
2047 1 : if (oa->route_table->hook_add)
2048 1 : (*oa->route_table->hook_add)(route);
2049 :
2050 : /* route's primary path is similar
2051 : * to LSA, replace route's primary
2052 : * path with route's paths list
2053 : * head.
2054 : */
2055 1 : if ((route->path.origin.id == lsa->header->id) &&
2056 1 : (route->path.origin.adv_router ==
2057 1 : lsa->header->adv_router)) {
2058 1 : ospf6_intra_prefix_update_route_origin(route,
2059 : oa->ospf6);
2060 : }
2061 : }
2062 :
2063 1 : }
2064 :
2065 28 : void ospf6_intra_prefix_lsa_remove(struct ospf6_lsa *lsa)
2066 : {
2067 28 : struct ospf6_area *oa;
2068 28 : struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
2069 28 : struct prefix prefix;
2070 28 : struct ospf6_route *route, *nroute;
2071 28 : int prefix_num;
2072 28 : struct ospf6_prefix *op;
2073 28 : char *start, *current, *end;
2074 28 : char buf[PREFIX2STR_BUFFER];
2075 :
2076 28 : if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
2077 0 : zlog_debug("%s: %s disappearing", __func__, lsa->name);
2078 :
2079 28 : oa = OSPF6_AREA(lsa->lsdb->data);
2080 :
2081 28 : intra_prefix_lsa =
2082 28 : (struct ospf6_intra_prefix_lsa *)OSPF6_LSA_HEADER_END(
2083 : lsa->header);
2084 :
2085 28 : prefix_num = ntohs(intra_prefix_lsa->prefix_num);
2086 28 : start = (caddr_t)intra_prefix_lsa
2087 : + sizeof(struct ospf6_intra_prefix_lsa);
2088 28 : end = OSPF6_LSA_END(lsa->header);
2089 68 : for (current = start; current < end; current += OSPF6_PREFIX_SIZE(op)) {
2090 40 : op = (struct ospf6_prefix *)current;
2091 40 : if (prefix_num == 0)
2092 : break;
2093 40 : if (end < current + OSPF6_PREFIX_SIZE(op))
2094 : break;
2095 40 : prefix_num--;
2096 :
2097 40 : memset(&prefix, 0, sizeof(prefix));
2098 40 : prefix.family = AF_INET6;
2099 40 : prefix.prefixlen = op->prefix_length;
2100 40 : ospf6_prefix_in6_addr(&prefix.u.prefix6, intra_prefix_lsa, op);
2101 :
2102 40 : route = ospf6_route_lookup(&prefix, oa->route_table);
2103 40 : if (route == NULL)
2104 11 : continue;
2105 :
2106 29 : for (ospf6_route_lock(route);
2107 61 : route && ospf6_route_is_prefix(&prefix, route);
2108 : route = nroute) {
2109 32 : nroute = ospf6_route_next(route);
2110 32 : if (route->type != OSPF6_DEST_TYPE_NETWORK)
2111 0 : continue;
2112 32 : if (route->path.area_id != oa->area_id)
2113 0 : continue;
2114 32 : if (route->path.type != OSPF6_PATH_TYPE_INTRA)
2115 0 : continue;
2116 : /* Route has multiple ECMP paths, remove matching
2117 : * path. Update current route's effective nh list
2118 : * after removal of one of the path.
2119 : */
2120 32 : if (listcount(route->paths) > 1) {
2121 1 : ospf6_intra_prefix_lsa_remove_update_route(
2122 : lsa, oa, route);
2123 : } else {
2124 :
2125 31 : if (route->path.origin.type != lsa->header->type
2126 31 : || route->path.origin.id != lsa->header->id
2127 31 : || route->path.origin.adv_router
2128 31 : != lsa->header->adv_router)
2129 6 : continue;
2130 :
2131 25 : if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
2132 0 : prefix2str(&route->prefix, buf,
2133 : sizeof(buf));
2134 0 : zlog_debug(
2135 : "%s: route remove %s with path type %u cost %u paths %u nh %u",
2136 : __func__, buf, route->path.type,
2137 : route->path.cost,
2138 : listcount(route->paths),
2139 : listcount(route->nh_list));
2140 : }
2141 25 : ospf6_route_remove(route, oa->route_table);
2142 : }
2143 : }
2144 29 : if (route)
2145 22 : ospf6_route_unlock(route);
2146 : }
2147 :
2148 28 : if (current != end && IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
2149 0 : zlog_debug("Trailing garbage ignored");
2150 28 : }
2151 :
2152 37 : void ospf6_intra_route_calculation(struct ospf6_area *oa)
2153 : {
2154 37 : struct ospf6_route *route, *nroute;
2155 37 : uint16_t type;
2156 37 : struct ospf6_lsa *lsa;
2157 37 : void (*hook_add)(struct ospf6_route *) = NULL;
2158 37 : void (*hook_remove)(struct ospf6_route *) = NULL;
2159 37 : char buf[PREFIX2STR_BUFFER];
2160 :
2161 37 : if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
2162 0 : zlog_debug("Re-examin intra-routes for area %s", oa->name);
2163 :
2164 37 : hook_add = oa->route_table->hook_add;
2165 37 : hook_remove = oa->route_table->hook_remove;
2166 37 : oa->route_table->hook_add = NULL;
2167 37 : oa->route_table->hook_remove = NULL;
2168 :
2169 110 : for (route = ospf6_route_head(oa->route_table); route;
2170 73 : route = ospf6_route_next(route))
2171 73 : route->flag = OSPF6_ROUTE_REMOVE;
2172 :
2173 37 : type = htons(OSPF6_LSTYPE_INTRA_PREFIX);
2174 133 : for (ALL_LSDB_TYPED(oa->lsdb, type, lsa))
2175 96 : ospf6_intra_prefix_lsa_add(lsa);
2176 :
2177 37 : oa->route_table->hook_add = hook_add;
2178 37 : oa->route_table->hook_remove = hook_remove;
2179 :
2180 121 : for (route = ospf6_route_head(oa->route_table); route; route = nroute) {
2181 84 : if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
2182 0 : prefix2str(&route->prefix, buf, sizeof(buf));
2183 0 : zlog_debug("%s: route %s, flag 0x%x", __func__, buf,
2184 : route->flag);
2185 : }
2186 :
2187 84 : nroute = ospf6_route_next(route);
2188 84 : if (CHECK_FLAG(route->flag, OSPF6_ROUTE_REMOVE)
2189 : && CHECK_FLAG(route->flag, OSPF6_ROUTE_ADD)) {
2190 0 : UNSET_FLAG(route->flag, OSPF6_ROUTE_REMOVE);
2191 0 : UNSET_FLAG(route->flag, OSPF6_ROUTE_ADD);
2192 : }
2193 :
2194 84 : if (CHECK_FLAG(route->flag, OSPF6_ROUTE_REMOVE))
2195 2 : ospf6_route_remove(route, oa->route_table);
2196 82 : else if (CHECK_FLAG(route->flag, OSPF6_ROUTE_ADD)
2197 : || CHECK_FLAG(route->flag, OSPF6_ROUTE_CHANGE)) {
2198 82 : if (hook_add)
2199 82 : (*hook_add)(route);
2200 82 : route->flag = 0;
2201 : } else {
2202 : /* Redo the summaries as things might have changed */
2203 0 : if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
2204 0 : zlog_debug("%s: Originate summary for route %s",
2205 : __func__, buf);
2206 0 : ospf6_abr_originate_summary(route, oa->ospf6);
2207 0 : route->flag = 0;
2208 : }
2209 : }
2210 :
2211 37 : if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
2212 0 : zlog_debug("Re-examin intra-routes for area %s: Done",
2213 : oa->name);
2214 37 : }
2215 :
2216 0 : static void ospf6_brouter_debug_print(struct ospf6_route *brouter)
2217 : {
2218 0 : uint32_t brouter_id;
2219 0 : char brouter_name[16];
2220 0 : char area_name[16];
2221 0 : char destination[64];
2222 0 : char installed[64], changed[64];
2223 0 : struct timeval now, res;
2224 0 : char id[16], adv_router[16];
2225 0 : char capa[16], options[32];
2226 :
2227 0 : brouter_id = ADV_ROUTER_IN_PREFIX(&brouter->prefix);
2228 0 : inet_ntop(AF_INET, &brouter_id, brouter_name, sizeof(brouter_name));
2229 0 : inet_ntop(AF_INET, &brouter->path.area_id, area_name,
2230 : sizeof(area_name));
2231 0 : ospf6_linkstate_prefix2str(&brouter->prefix, destination,
2232 : sizeof(destination));
2233 :
2234 0 : monotime(&now);
2235 0 : timersub(&now, &brouter->installed, &res);
2236 0 : timerstring(&res, installed, sizeof(installed));
2237 :
2238 0 : monotime(&now);
2239 0 : timersub(&now, &brouter->changed, &res);
2240 0 : timerstring(&res, changed, sizeof(changed));
2241 :
2242 0 : inet_ntop(AF_INET, &brouter->path.origin.id, id, sizeof(id));
2243 0 : inet_ntop(AF_INET, &brouter->path.origin.adv_router, adv_router,
2244 : sizeof(adv_router));
2245 :
2246 0 : ospf6_options_printbuf(brouter->path.options, options, sizeof(options));
2247 0 : ospf6_capability_printbuf(brouter->path.router_bits, capa,
2248 : sizeof(capa));
2249 :
2250 0 : zlog_info("Brouter: %s via area %s", brouter_name, area_name);
2251 0 : zlog_info(" memory: prev: %p this: %p next: %p parent rnode: %p",
2252 : (void *)brouter->prev, (void *)brouter, (void *)brouter->next,
2253 : (void *)brouter->rnode);
2254 0 : zlog_info(" type: %d prefix: %s installed: %s changed: %s",
2255 : brouter->type, destination, installed, changed);
2256 0 : zlog_info(" lock: %d flags: %s%s%s%s", brouter->lock,
2257 : (CHECK_FLAG(brouter->flag, OSPF6_ROUTE_BEST) ? "B" : "-"),
2258 : (CHECK_FLAG(brouter->flag, OSPF6_ROUTE_ADD) ? "A" : "-"),
2259 : (CHECK_FLAG(brouter->flag, OSPF6_ROUTE_REMOVE) ? "R" : "-"),
2260 : (CHECK_FLAG(brouter->flag, OSPF6_ROUTE_CHANGE) ? "C" : "-"));
2261 0 : zlog_info(" path type: %s ls-origin %s id: %s adv-router %s",
2262 : OSPF6_PATH_TYPE_NAME(brouter->path.type),
2263 : ospf6_lstype_name(brouter->path.origin.type), id, adv_router);
2264 0 : zlog_info(" options: %s router-bits: %s metric-type: %d metric: %d/%d",
2265 : options, capa, brouter->path.metric_type, brouter->path.cost,
2266 : brouter->path.u.cost_e2);
2267 0 : zlog_info(" paths %u nh %u", listcount(brouter->paths),
2268 : listcount(brouter->nh_list));
2269 0 : }
2270 :
2271 37 : void ospf6_intra_brouter_calculation(struct ospf6_area *oa)
2272 : {
2273 37 : struct ospf6_route *brouter, *nbrouter, *copy;
2274 37 : void (*hook_add)(struct ospf6_route *) = NULL;
2275 37 : void (*hook_remove)(struct ospf6_route *) = NULL;
2276 37 : uint32_t brouter_id;
2277 37 : char brouter_name[16];
2278 :
2279 37 : if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID(oa->area_id) ||
2280 37 : IS_OSPF6_DEBUG_ROUTE(MEMORY))
2281 0 : zlog_debug("%s: border-router calculation for area %s",
2282 : __func__, oa->name);
2283 :
2284 37 : hook_add = oa->ospf6->brouter_table->hook_add;
2285 37 : hook_remove = oa->ospf6->brouter_table->hook_remove;
2286 37 : oa->ospf6->brouter_table->hook_add = NULL;
2287 37 : oa->ospf6->brouter_table->hook_remove = NULL;
2288 :
2289 : /* withdraw the previous router entries for the area */
2290 37 : for (brouter = ospf6_route_head(oa->ospf6->brouter_table); brouter;
2291 0 : brouter = ospf6_route_next(brouter)) {
2292 0 : brouter_id = ADV_ROUTER_IN_PREFIX(&brouter->prefix);
2293 0 : inet_ntop(AF_INET, &brouter_id, brouter_name,
2294 : sizeof(brouter_name));
2295 :
2296 0 : if (brouter->path.area_id != oa->area_id)
2297 0 : continue;
2298 :
2299 0 : SET_FLAG(brouter->flag, OSPF6_ROUTE_REMOVE);
2300 :
2301 0 : if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID(brouter_id)
2302 0 : || IS_OSPF6_DEBUG_ROUTE(MEMORY)) {
2303 0 : zlog_debug("%p: mark as removing: area %s brouter %s",
2304 : (void *)brouter, oa->name, brouter_name);
2305 0 : ospf6_brouter_debug_print(brouter);
2306 : }
2307 : }
2308 :
2309 142 : for (brouter = ospf6_route_head(oa->spf_table); brouter;
2310 105 : brouter = ospf6_route_next(brouter)) {
2311 105 : brouter_id = ADV_ROUTER_IN_PREFIX(&brouter->prefix);
2312 105 : inet_ntop(AF_INET, &brouter_id, brouter_name,
2313 : sizeof(brouter_name));
2314 :
2315 105 : if (brouter->type != OSPF6_DEST_TYPE_LINKSTATE)
2316 0 : continue;
2317 :
2318 105 : if (ospf6_linkstate_prefix_id(&brouter->prefix) != htonl(0))
2319 15 : continue;
2320 :
2321 90 : if (!CHECK_FLAG(brouter->path.router_bits, OSPF6_ROUTER_BIT_E)
2322 : && !CHECK_FLAG(brouter->path.router_bits,
2323 : OSPF6_ROUTER_BIT_B))
2324 90 : continue;
2325 :
2326 0 : if (!OSPF6_OPT_ISSET(brouter->path.options, OSPF6_OPT_V6)
2327 : || !OSPF6_OPT_ISSET(brouter->path.options, OSPF6_OPT_R))
2328 0 : continue;
2329 :
2330 0 : copy = ospf6_route_copy(brouter);
2331 0 : copy->type = OSPF6_DEST_TYPE_ROUTER;
2332 0 : copy->path.area_id = oa->area_id;
2333 0 : ospf6_route_add(copy, oa->ospf6->brouter_table);
2334 :
2335 0 : if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID(brouter_id)
2336 0 : || IS_OSPF6_DEBUG_ROUTE(MEMORY)) {
2337 0 : zlog_debug("%p: transfer: area %s brouter %s",
2338 : (void *)brouter, oa->name, brouter_name);
2339 0 : ospf6_brouter_debug_print(brouter);
2340 : }
2341 : }
2342 :
2343 37 : oa->ospf6->brouter_table->hook_add = hook_add;
2344 37 : oa->ospf6->brouter_table->hook_remove = hook_remove;
2345 :
2346 37 : for (brouter = ospf6_route_head(oa->ospf6->brouter_table); brouter;
2347 : brouter = nbrouter) {
2348 :
2349 : /*
2350 : * brouter may have been "deleted" in the last loop iteration.
2351 : * If this is the case there is still 1 final refcount lock
2352 : * taken by ospf6_route_next, that will be released by the same
2353 : * call and result in deletion. To avoid heap UAF we must then
2354 : * skip processing the deleted route.
2355 : */
2356 0 : if (brouter->lock == 1) {
2357 0 : if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
2358 0 : ospf6_brouter_debug_print(brouter);
2359 0 : nbrouter = ospf6_route_next(brouter);
2360 0 : continue;
2361 : } else {
2362 0 : nbrouter = ospf6_route_next(brouter);
2363 : }
2364 :
2365 0 : brouter_id = ADV_ROUTER_IN_PREFIX(&brouter->prefix);
2366 0 : inet_ntop(AF_INET, &brouter_id, brouter_name,
2367 : sizeof(brouter_name));
2368 :
2369 0 : if (brouter->path.area_id != oa->area_id)
2370 0 : continue;
2371 :
2372 0 : if (CHECK_FLAG(brouter->flag, OSPF6_ROUTE_WAS_REMOVED))
2373 0 : continue;
2374 :
2375 : /* After iterating spf_table for all routers including
2376 : * intra brouter, clear mark for remove flag for
2377 : * inter border router if its adv router present in
2378 : * SPF table.
2379 : */
2380 0 : if (brouter->path.type == OSPF6_PATH_TYPE_INTER) {
2381 0 : struct prefix adv_prefix;
2382 :
2383 0 : ospf6_linkstate_prefix(brouter->path.origin.adv_router,
2384 : htonl(0), &adv_prefix);
2385 :
2386 0 : if (ospf6_route_lookup(&adv_prefix, oa->spf_table)) {
2387 0 : if (IS_OSPF6_DEBUG_BROUTER) {
2388 0 : zlog_debug(
2389 : "%s: keep inter brouter %s as adv router 0x%x found in spf",
2390 : __func__, brouter_name,
2391 : brouter->path.origin
2392 : .adv_router);
2393 0 : ospf6_brouter_debug_print(brouter);
2394 : }
2395 0 : UNSET_FLAG(brouter->flag, OSPF6_ROUTE_REMOVE);
2396 : }
2397 : }
2398 :
2399 0 : if (CHECK_FLAG(brouter->flag, OSPF6_ROUTE_REMOVE)
2400 : && CHECK_FLAG(brouter->flag, OSPF6_ROUTE_ADD)) {
2401 0 : UNSET_FLAG(brouter->flag, OSPF6_ROUTE_REMOVE);
2402 0 : UNSET_FLAG(brouter->flag, OSPF6_ROUTE_ADD);
2403 : }
2404 :
2405 0 : if (CHECK_FLAG(brouter->flag, OSPF6_ROUTE_REMOVE)) {
2406 0 : if (IS_OSPF6_DEBUG_BROUTER
2407 0 : || IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID(
2408 : brouter_id)
2409 0 : || IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID(
2410 : oa->area_id))
2411 0 : zlog_debug(
2412 : "%s: brouter %s disappears via area %s",
2413 : __func__, brouter_name, oa->name);
2414 : /* This is used to protect nbrouter from removed from
2415 : * the table. For an example, ospf6_abr_examin_summary,
2416 : * removes brouters which are marked for remove.
2417 : */
2418 0 : oa->intra_brouter_calc = true;
2419 0 : ospf6_route_remove(brouter, oa->ospf6->brouter_table);
2420 0 : brouter = NULL;
2421 0 : } else if (CHECK_FLAG(brouter->flag, OSPF6_ROUTE_ADD)
2422 : || CHECK_FLAG(brouter->flag, OSPF6_ROUTE_CHANGE)) {
2423 0 : if (IS_OSPF6_DEBUG_BROUTER
2424 0 : || IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID(
2425 : brouter_id)
2426 0 : || IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID(
2427 : oa->area_id))
2428 0 : zlog_info("%s: brouter %s appears via area %s",
2429 : __func__, brouter_name, oa->name);
2430 :
2431 : /* newly added */
2432 0 : if (hook_add)
2433 0 : (*hook_add)(brouter);
2434 : } else {
2435 0 : if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID(
2436 : brouter_id)
2437 0 : || IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID(
2438 : oa->area_id))
2439 0 : zlog_debug(
2440 : "brouter %s still exists via area %s",
2441 : brouter_name, oa->name);
2442 : /* But re-originate summaries */
2443 0 : ospf6_abr_originate_summary(brouter, oa->ospf6);
2444 : }
2445 :
2446 0 : if (brouter) {
2447 0 : UNSET_FLAG(brouter->flag, OSPF6_ROUTE_ADD);
2448 0 : UNSET_FLAG(brouter->flag, OSPF6_ROUTE_CHANGE);
2449 : }
2450 : /* Reset for nbrouter */
2451 0 : oa->intra_brouter_calc = false;
2452 : }
2453 :
2454 37 : if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID(oa->area_id) ||
2455 37 : IS_OSPF6_DEBUG_ROUTE(MEMORY))
2456 0 : zlog_debug("%s: border-router calculation for area %s: done",
2457 : __func__, oa->name);
2458 37 : }
2459 :
2460 : static struct ospf6_lsa_handler router_handler = {
2461 : .lh_type = OSPF6_LSTYPE_ROUTER,
2462 : .lh_name = "Router",
2463 : .lh_short_name = "Rtr",
2464 : .lh_show = ospf6_router_lsa_show,
2465 : .lh_get_prefix_str = ospf6_router_lsa_get_nbr_id,
2466 : .lh_debug = 0};
2467 :
2468 : static struct ospf6_lsa_handler network_handler = {
2469 : .lh_type = OSPF6_LSTYPE_NETWORK,
2470 : .lh_name = "Network",
2471 : .lh_short_name = "Net",
2472 : .lh_show = ospf6_network_lsa_show,
2473 : .lh_get_prefix_str = ospf6_network_lsa_get_ar_id,
2474 : .lh_debug = 0};
2475 :
2476 : static struct ospf6_lsa_handler link_handler = {
2477 : .lh_type = OSPF6_LSTYPE_LINK,
2478 : .lh_name = "Link",
2479 : .lh_short_name = "Lnk",
2480 : .lh_show = ospf6_link_lsa_show,
2481 : .lh_get_prefix_str = ospf6_link_lsa_get_prefix_str,
2482 : .lh_debug = 0};
2483 :
2484 : static struct ospf6_lsa_handler intra_prefix_handler = {
2485 : .lh_type = OSPF6_LSTYPE_INTRA_PREFIX,
2486 : .lh_name = "Intra-Prefix",
2487 : .lh_short_name = "INP",
2488 : .lh_show = ospf6_intra_prefix_lsa_show,
2489 : .lh_get_prefix_str = ospf6_intra_prefix_lsa_get_prefix_str,
2490 : .lh_debug = 0};
2491 :
2492 4 : void ospf6_intra_init(void)
2493 : {
2494 4 : ospf6_install_lsa_handler(&router_handler);
2495 4 : ospf6_install_lsa_handler(&network_handler);
2496 4 : ospf6_install_lsa_handler(&link_handler);
2497 4 : ospf6_install_lsa_handler(&intra_prefix_handler);
2498 4 : }
2499 :
2500 0 : DEFUN (debug_ospf6_brouter,
2501 : debug_ospf6_brouter_cmd,
2502 : "debug ospf6 border-routers",
2503 : DEBUG_STR
2504 : OSPF6_STR
2505 : "Debug border router\n"
2506 : )
2507 : {
2508 0 : OSPF6_DEBUG_BROUTER_ON();
2509 0 : return CMD_SUCCESS;
2510 : }
2511 :
2512 0 : DEFUN (no_debug_ospf6_brouter,
2513 : no_debug_ospf6_brouter_cmd,
2514 : "no debug ospf6 border-routers",
2515 : NO_STR
2516 : DEBUG_STR
2517 : OSPF6_STR
2518 : "Debug border router\n"
2519 : )
2520 : {
2521 0 : OSPF6_DEBUG_BROUTER_OFF();
2522 0 : return CMD_SUCCESS;
2523 : }
2524 :
2525 0 : DEFUN (debug_ospf6_brouter_router,
2526 : debug_ospf6_brouter_router_cmd,
2527 : "debug ospf6 border-routers router-id A.B.C.D",
2528 : DEBUG_STR
2529 : OSPF6_STR
2530 : "Debug border router\n"
2531 : "Debug specific border router\n"
2532 : "Specify border-router's router-id\n"
2533 : )
2534 : {
2535 0 : int idx_ipv4 = 4;
2536 0 : uint32_t router_id;
2537 0 : inet_pton(AF_INET, argv[idx_ipv4]->arg, &router_id);
2538 0 : OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ON(router_id);
2539 0 : return CMD_SUCCESS;
2540 : }
2541 :
2542 0 : DEFUN (no_debug_ospf6_brouter_router,
2543 : no_debug_ospf6_brouter_router_cmd,
2544 : "no debug ospf6 border-routers router-id [A.B.C.D]",
2545 : NO_STR
2546 : DEBUG_STR
2547 : OSPF6_STR
2548 : "Debug border router\n"
2549 : "Debug specific border router\n"
2550 : "Specify border-router's router-id\n"
2551 : )
2552 : {
2553 0 : OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_OFF();
2554 0 : return CMD_SUCCESS;
2555 : }
2556 :
2557 0 : DEFUN (debug_ospf6_brouter_area,
2558 : debug_ospf6_brouter_area_cmd,
2559 : "debug ospf6 border-routers area-id A.B.C.D",
2560 : DEBUG_STR
2561 : OSPF6_STR
2562 : "Debug border router\n"
2563 : "Debug border routers in specific Area\n"
2564 : "Specify Area-ID\n"
2565 : )
2566 : {
2567 0 : int idx_ipv4 = 4;
2568 0 : uint32_t area_id;
2569 0 : inet_pton(AF_INET, argv[idx_ipv4]->arg, &area_id);
2570 0 : OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ON(area_id);
2571 0 : return CMD_SUCCESS;
2572 : }
2573 :
2574 0 : DEFUN (no_debug_ospf6_brouter_area,
2575 : no_debug_ospf6_brouter_area_cmd,
2576 : "no debug ospf6 border-routers area-id [A.B.C.D]",
2577 : NO_STR
2578 : DEBUG_STR
2579 : OSPF6_STR
2580 : "Debug border router\n"
2581 : "Debug border routers in specific Area\n"
2582 : "Specify Area-ID\n"
2583 : )
2584 : {
2585 0 : OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_OFF();
2586 0 : return CMD_SUCCESS;
2587 : }
2588 :
2589 0 : int config_write_ospf6_debug_brouter(struct vty *vty)
2590 : {
2591 0 : char buf[16];
2592 0 : if (IS_OSPF6_DEBUG_BROUTER)
2593 0 : vty_out(vty, "debug ospf6 border-routers\n");
2594 0 : if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER) {
2595 0 : inet_ntop(AF_INET, &conf_debug_ospf6_brouter_specific_router_id,
2596 : buf, sizeof(buf));
2597 0 : vty_out(vty, "debug ospf6 border-routers router-id %s\n", buf);
2598 : }
2599 0 : if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA) {
2600 0 : inet_ntop(AF_INET, &conf_debug_ospf6_brouter_specific_area_id,
2601 : buf, sizeof(buf));
2602 0 : vty_out(vty, "debug ospf6 border-routers area-id %s\n", buf);
2603 : }
2604 0 : return 0;
2605 : }
2606 :
2607 4 : void install_element_ospf6_debug_brouter(void)
2608 : {
2609 4 : install_element(ENABLE_NODE, &debug_ospf6_brouter_cmd);
2610 4 : install_element(ENABLE_NODE, &debug_ospf6_brouter_router_cmd);
2611 4 : install_element(ENABLE_NODE, &debug_ospf6_brouter_area_cmd);
2612 4 : install_element(ENABLE_NODE, &no_debug_ospf6_brouter_cmd);
2613 4 : install_element(ENABLE_NODE, &no_debug_ospf6_brouter_router_cmd);
2614 4 : install_element(ENABLE_NODE, &no_debug_ospf6_brouter_area_cmd);
2615 4 : install_element(CONFIG_NODE, &debug_ospf6_brouter_cmd);
2616 4 : install_element(CONFIG_NODE, &debug_ospf6_brouter_router_cmd);
2617 4 : install_element(CONFIG_NODE, &debug_ospf6_brouter_area_cmd);
2618 4 : install_element(CONFIG_NODE, &no_debug_ospf6_brouter_cmd);
2619 4 : install_element(CONFIG_NODE, &no_debug_ospf6_brouter_router_cmd);
2620 4 : install_element(CONFIG_NODE, &no_debug_ospf6_brouter_area_cmd);
2621 4 : }
|