]> git.proxmox.com Git - mirror_frr.git/blob - ospf6d/ospf6_asbr.c
Merge pull request #10447 from ton31337/fix/json_with_whitespaces
[mirror_frr.git] / ospf6d / ospf6_asbr.c
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 "memory.h"
25 #include "prefix.h"
26 #include "command.h"
27 #include "vty.h"
28 #include "routemap.h"
29 #include "table.h"
30 #include "plist.h"
31 #include "thread.h"
32 #include "linklist.h"
33 #include "lib/northbound_cli.h"
34
35 #include "ospf6_proto.h"
36 #include "ospf6_lsa.h"
37 #include "ospf6_lsdb.h"
38 #include "ospf6_route.h"
39 #include "ospf6_zebra.h"
40 #include "ospf6_message.h"
41 #include "ospf6_spf.h"
42
43 #include "ospf6_top.h"
44 #include "ospf6d.h"
45 #include "ospf6_area.h"
46 #include "ospf6_interface.h"
47 #include "ospf6_neighbor.h"
48 #include "ospf6_asbr.h"
49 #include "ospf6_abr.h"
50 #include "ospf6_intra.h"
51 #include "ospf6_flood.h"
52 #include "ospf6_nssa.h"
53 #include "ospf6d.h"
54 #include "ospf6_spf.h"
55 #include "ospf6_nssa.h"
56 #include "ospf6_gr.h"
57 #include "lib/json.h"
58
59 DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_EXTERNAL_INFO, "OSPF6 ext. info");
60 DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_DIST_ARGS, "OSPF6 Distribute arguments");
61 DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_REDISTRIBUTE, "OSPF6 Redistribute arguments");
62 DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_EXTERNAL_RT_AGGR, "OSPF6 ASBR Summarisation");
63
64 static void ospf6_asbr_redistribute_set(struct ospf6 *ospf6, int type);
65 static void ospf6_asbr_redistribute_unset(struct ospf6 *ospf6,
66 struct ospf6_redist *red, int type);
67
68 #ifndef VTYSH_EXTRACT_PL
69 #include "ospf6d/ospf6_asbr_clippy.c"
70 #endif
71
72 unsigned char conf_debug_ospf6_asbr = 0;
73
74 #define ZROUTE_NAME(x) zebra_route_string(x)
75
76 /* Originate Type-5 and Type-7 LSA */
77 static struct ospf6_lsa *ospf6_originate_type5_type7_lsas(
78 struct ospf6_route *route,
79 struct ospf6 *ospf6)
80 {
81 struct ospf6_lsa *lsa;
82 struct listnode *lnode;
83 struct ospf6_area *oa = NULL;
84
85 lsa = ospf6_as_external_lsa_originate(route, ospf6);
86
87 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, lnode, oa)) {
88 if (IS_AREA_NSSA(oa))
89 ospf6_nssa_lsa_originate(route, oa, true);
90 }
91
92 return lsa;
93 }
94
95 /* AS External LSA origination */
96 struct ospf6_lsa *ospf6_as_external_lsa_originate(struct ospf6_route *route,
97 struct ospf6 *ospf6)
98 {
99 char buffer[OSPF6_MAX_LSASIZE];
100 struct ospf6_lsa_header *lsa_header;
101 struct ospf6_lsa *lsa;
102 struct ospf6_external_info *info = route->route_option;
103
104 struct ospf6_as_external_lsa *as_external_lsa;
105 caddr_t p;
106
107 if (ospf6->gr_info.restart_in_progress) {
108 if (IS_DEBUG_OSPF6_GR)
109 zlog_debug(
110 "Graceful Restart in progress, don't originate LSA");
111 return NULL;
112 }
113
114 if (IS_OSPF6_DEBUG_ASBR || IS_OSPF6_DEBUG_ORIGINATE(AS_EXTERNAL))
115 zlog_debug("Originate AS-External-LSA for %pFX",
116 &route->prefix);
117
118 /* prepare buffer */
119 memset(buffer, 0, sizeof(buffer));
120 lsa_header = (struct ospf6_lsa_header *)buffer;
121 as_external_lsa = (struct ospf6_as_external_lsa
122 *)((caddr_t)lsa_header
123 + sizeof(struct ospf6_lsa_header));
124 p = (caddr_t)((caddr_t)as_external_lsa
125 + sizeof(struct ospf6_as_external_lsa));
126
127 /* Fill AS-External-LSA */
128 /* Metric type */
129 if (route->path.metric_type == 2)
130 SET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_E);
131 else
132 UNSET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_E);
133
134 /* forwarding address */
135 if (!IN6_IS_ADDR_UNSPECIFIED(&info->forwarding))
136 SET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F);
137 else
138 UNSET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F);
139
140 /* external route tag */
141 if (info->tag)
142 SET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T);
143 else
144 UNSET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T);
145
146 /* Set metric */
147 OSPF6_ASBR_METRIC_SET(as_external_lsa, route->path.cost);
148
149 /* prefixlen */
150 as_external_lsa->prefix.prefix_length = route->prefix.prefixlen;
151
152 /* PrefixOptions */
153 as_external_lsa->prefix.prefix_options = route->prefix_options;
154
155 /* don't use refer LS-type */
156 as_external_lsa->prefix.prefix_refer_lstype = htons(0);
157
158 /* set Prefix */
159 memcpy(p, &route->prefix.u.prefix6,
160 OSPF6_PREFIX_SPACE(route->prefix.prefixlen));
161 ospf6_prefix_apply_mask(&as_external_lsa->prefix);
162 p += OSPF6_PREFIX_SPACE(route->prefix.prefixlen);
163
164 /* Forwarding address */
165 if (CHECK_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F)) {
166 memcpy(p, &info->forwarding, sizeof(struct in6_addr));
167 p += sizeof(struct in6_addr);
168 }
169
170 /* External Route Tag */
171 if (CHECK_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T)) {
172 route_tag_t network_order = htonl(info->tag);
173
174 memcpy(p, &network_order, sizeof(network_order));
175 p += sizeof(network_order);
176 }
177
178 /* Fill LSA Header */
179 lsa_header->age = 0;
180 lsa_header->type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
181 lsa_header->id = route->path.origin.id;
182 lsa_header->adv_router = ospf6->router_id;
183 lsa_header->seqnum =
184 ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id,
185 lsa_header->adv_router, ospf6->lsdb);
186 lsa_header->length = htons((caddr_t)p - (caddr_t)lsa_header);
187
188 /* LSA checksum */
189 ospf6_lsa_checksum(lsa_header);
190
191 /* create LSA */
192 lsa = ospf6_lsa_create(lsa_header);
193
194 /* Originate */
195 ospf6_lsa_originate_process(lsa, ospf6);
196
197 return lsa;
198 }
199
200 void ospf6_orig_as_external_lsa(struct thread *thread)
201 {
202 struct ospf6_interface *oi;
203 struct ospf6_lsa *lsa;
204 uint32_t type, adv_router;
205
206 oi = (struct ospf6_interface *)THREAD_ARG(thread);
207
208 if (oi->state == OSPF6_INTERFACE_DOWN)
209 return;
210 if (IS_AREA_NSSA(oi->area) || IS_AREA_STUB(oi->area))
211 return;
212
213 type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
214 adv_router = oi->area->ospf6->router_id;
215 for (ALL_LSDB_TYPED_ADVRTR(oi->area->ospf6->lsdb, type, adv_router,
216 lsa)) {
217 if (IS_OSPF6_DEBUG_ASBR)
218 zlog_debug(
219 "%s: Send update of AS-External LSA %s seq 0x%x",
220 __func__, lsa->name,
221 ntohl(lsa->header->seqnum));
222
223 ospf6_flood_interface(NULL, lsa, oi);
224 }
225 }
226
227 static route_tag_t ospf6_as_external_lsa_get_tag(struct ospf6_lsa *lsa)
228 {
229 struct ospf6_as_external_lsa *external;
230 ptrdiff_t tag_offset;
231 route_tag_t network_order;
232
233 if (!lsa)
234 return 0;
235
236 external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
237 lsa->header);
238
239 if (!CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T))
240 return 0;
241
242 tag_offset = sizeof(*external)
243 + OSPF6_PREFIX_SPACE(external->prefix.prefix_length);
244 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F))
245 tag_offset += sizeof(struct in6_addr);
246
247 memcpy(&network_order, (caddr_t)external + tag_offset,
248 sizeof(network_order));
249 return ntohl(network_order);
250 }
251
252 void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
253 struct ospf6_route *route,
254 struct ospf6 *ospf6)
255 {
256 struct ospf6_route *old_route, *next_route;
257 struct ospf6_path *ecmp_path, *o_path = NULL;
258 struct listnode *anode, *anext;
259 struct listnode *nnode, *rnode, *rnext;
260 struct ospf6_nexthop *nh, *rnh;
261 bool route_found = false;
262
263 /* check for old entry match with new route origin,
264 * delete old entry.
265 */
266 for (old_route = old; old_route; old_route = next_route) {
267 bool route_updated = false;
268
269 next_route = old_route->next;
270
271 /* The route linked-list is grouped in batches of prefix.
272 * If the new prefix is not the same as the one of interest
273 * then we have walked over the end of the batch and so we
274 * should break rather than continuing unnecessarily.
275 */
276 if (!ospf6_route_is_same(old_route, route))
277 break;
278 if (old_route->path.type != route->path.type)
279 continue;
280
281 /* Current and New route has same origin,
282 * delete old entry.
283 */
284 for (ALL_LIST_ELEMENTS(old_route->paths, anode, anext,
285 o_path)) {
286 /* Check old route path and route has same
287 * origin.
288 */
289 if (o_path->area_id != route->path.area_id
290 || !ospf6_ls_origin_same(o_path, &route->path))
291 continue;
292
293 /* Cost is not same then delete current path */
294 if ((o_path->cost == route->path.cost)
295 && (o_path->u.cost_e2 == route->path.u.cost_e2))
296 continue;
297
298 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
299 zlog_debug(
300 "%s: route %pFX cost old %u new %u is not same, replace route",
301 __func__, &old_route->prefix, o_path->cost,
302 route->path.cost);
303 }
304
305 /* Remove selected current rout path's nh from
306 * effective nh list.
307 */
308 for (ALL_LIST_ELEMENTS_RO(o_path->nh_list, nnode, nh)) {
309 for (ALL_LIST_ELEMENTS(old_route->nh_list,
310 rnode, rnext, rnh)) {
311 if (!ospf6_nexthop_is_same(rnh, nh))
312 continue;
313 listnode_delete(old_route->nh_list,
314 rnh);
315 ospf6_nexthop_delete(rnh);
316 }
317 }
318
319 listnode_delete(old_route->paths, o_path);
320 ospf6_path_free(o_path);
321 route_updated = true;
322
323 /* Current route's path (adv_router info) is similar
324 * to route being added.
325 * Replace current route's path with paths list head.
326 * Update FIB with effective NHs.
327 */
328 if (listcount(old_route->paths)) {
329 for (ALL_LIST_ELEMENTS(old_route->paths,
330 anode, anext, o_path)) {
331 ospf6_merge_nexthops(
332 old_route->nh_list,
333 o_path->nh_list);
334 }
335 /* Update RIB/FIB with effective
336 * nh_list
337 */
338 if (ospf6->route_table->hook_add)
339 (*ospf6->route_table->hook_add)(
340 old_route);
341
342 if (old_route->path.origin.id
343 == route->path.origin.id
344 && old_route->path.origin.adv_router
345 == route->path.origin
346 .adv_router) {
347 struct ospf6_path *h_path;
348
349 h_path = (struct ospf6_path *)
350 listgetdata(listhead(
351 old_route->paths));
352 old_route->path.origin.type =
353 h_path->origin.type;
354 old_route->path.origin.id =
355 h_path->origin.id;
356 old_route->path.origin.adv_router =
357 h_path->origin.adv_router;
358 }
359 } else {
360 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
361 zlog_debug(
362 "%s: route %pFX old cost %u new cost %u, delete old entry.",
363 __func__, &old_route->prefix,
364 old_route->path.cost,
365 route->path.cost);
366 }
367 if (old == old_route)
368 old = next_route;
369 ospf6_route_remove(old_route,
370 ospf6->route_table);
371 }
372 }
373 if (route_updated)
374 break;
375 }
376
377 /* Add new route */
378 for (old_route = old; old_route; old_route = old_route->next) {
379
380 /* The route linked-list is grouped in batches of prefix.
381 * If the new prefix is not the same as the one of interest
382 * then we have walked over the end of the batch and so we
383 * should break rather than continuing unnecessarily.
384 */
385 if (!ospf6_route_is_same(old_route, route))
386 break;
387 if (old_route->path.type != route->path.type)
388 continue;
389
390 /* Old Route and New Route have Equal Cost, Merge NHs */
391 if ((old_route->path.cost == route->path.cost)
392 && (old_route->path.u.cost_e2 == route->path.u.cost_e2)) {
393
394 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
395 zlog_debug(
396 "%s: old route %pFX path cost %u e2 %u",
397 __func__, &old_route->prefix,
398 old_route->path.cost,
399 old_route->path.u.cost_e2);
400 }
401 route_found = true;
402 /* check if this path exists already in
403 * route->paths list, if so, replace nh_list
404 * from asbr_entry.
405 */
406 for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode,
407 o_path)) {
408 if (o_path->area_id == route->path.area_id
409 && ospf6_ls_origin_same(o_path, &route->path))
410 break;
411 }
412 /* If path is not found in old_route paths's list,
413 * add a new path to route paths list and merge
414 * nexthops in route->path->nh_list.
415 * Otherwise replace existing path's nh_list.
416 */
417 if (o_path == NULL) {
418 ecmp_path = ospf6_path_dup(&route->path);
419
420 /* Add a nh_list to new ecmp path */
421 ospf6_copy_nexthops(ecmp_path->nh_list,
422 route->nh_list);
423
424 /* Add the new path to route's path list */
425 listnode_add_sort(old_route->paths, ecmp_path);
426
427 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
428 zlog_debug(
429 "%s: route %pFX another path added with nh %u, effective paths %u nh %u",
430 __func__, &route->prefix,
431 listcount(ecmp_path->nh_list),
432 old_route->paths ? listcount(
433 old_route->paths)
434 : 0,
435 listcount(old_route->nh_list));
436 }
437 } else {
438 list_delete_all_node(o_path->nh_list);
439 ospf6_copy_nexthops(o_path->nh_list,
440 route->nh_list);
441 }
442
443 /* Reset nexthop lists, rebuild from brouter table
444 * for each adv. router.
445 */
446 list_delete_all_node(old_route->nh_list);
447
448 for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode,
449 o_path)) {
450 struct ospf6_route *asbr_entry;
451
452 asbr_entry = ospf6_route_lookup(
453 &o_path->ls_prefix,
454 ospf6->brouter_table);
455 if (asbr_entry == NULL) {
456 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
457 zlog_debug(
458 "%s: ls_prfix %pFX asbr_entry not found.",
459 __func__,
460 &old_route->prefix);
461 continue;
462 }
463 ospf6_route_merge_nexthops(old_route,
464 asbr_entry);
465 }
466
467 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
468 zlog_debug(
469 "%s: route %pFX with effective paths %u nh %u",
470 __func__, &route->prefix,
471 old_route->paths
472 ? listcount(old_route->paths)
473 : 0,
474 old_route->nh_list
475 ? listcount(old_route->nh_list)
476 : 0);
477
478 /* Update RIB/FIB */
479 if (ospf6->route_table->hook_add)
480 (*ospf6->route_table->hook_add)(old_route);
481
482 /* Delete the new route its info added to existing
483 * route.
484 */
485 ospf6_route_delete(route);
486
487 break;
488 }
489 }
490
491 if (!route_found) {
492 /* Add new route to existing node in ospf6 route table. */
493 ospf6_route_add(route, ospf6->route_table);
494 }
495 }
496
497 /* Check if the forwarding address is local address */
498 static int ospf6_ase_forward_address_check(struct ospf6 *ospf6,
499 struct in6_addr *fwd_addr)
500 {
501 struct listnode *anode, *node, *cnode;
502 struct ospf6_interface *oi;
503 struct ospf6_area *oa;
504 struct interface *ifp;
505 struct connected *c;
506
507 for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, anode, oa)) {
508 for (ALL_LIST_ELEMENTS_RO(oa->if_list, node, oi)) {
509 if (!if_is_operative(oi->interface)
510 || oi->type == OSPF_IFTYPE_VIRTUALLINK)
511 continue;
512
513 ifp = oi->interface;
514 for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) {
515 if (IPV6_ADDR_SAME(&c->address->u.prefix6,
516 fwd_addr))
517 return 0;
518 }
519 }
520 }
521
522 return 1;
523 }
524
525 void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa)
526 {
527 struct ospf6_as_external_lsa *external;
528 struct prefix asbr_id;
529 struct ospf6_route *asbr_entry, *route, *old = NULL;
530 struct ospf6_path *path;
531 struct ospf6 *ospf6;
532 int type;
533 struct ospf6_area *oa = NULL;
534 struct prefix fwd_addr;
535 ptrdiff_t offset;
536
537 type = ntohs(lsa->header->type);
538 oa = lsa->lsdb->data;
539
540 external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
541 lsa->header);
542
543 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
544 zlog_debug("Calculate AS-External route for %s", lsa->name);
545
546 ospf6 = ospf6_get_by_lsdb(lsa);
547
548 if (lsa->header->adv_router == ospf6->router_id) {
549 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
550 zlog_debug("Ignore self-originated AS-External-LSA");
551 return;
552 }
553
554 if (OSPF6_ASBR_METRIC(external) == OSPF_LS_INFINITY) {
555 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
556 zlog_debug("Ignore LSA with LSInfinity Metric");
557 return;
558 }
559
560 if (CHECK_FLAG(external->prefix.prefix_options,
561 OSPF6_PREFIX_OPTION_NU)) {
562 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
563 zlog_debug("Ignore LSA with NU bit set Metric");
564 return;
565 }
566
567 ospf6_linkstate_prefix(lsa->header->adv_router, htonl(0), &asbr_id);
568 asbr_entry = ospf6_route_lookup(&asbr_id, ospf6->brouter_table);
569 if (asbr_entry == NULL) {
570 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
571 zlog_debug("ASBR entry not found: %pFX", &asbr_id);
572 return;
573 } else {
574 /* The router advertising external LSA can be ASBR or ABR */
575 if (!CHECK_FLAG(asbr_entry->path.router_bits,
576 OSPF6_ROUTER_BIT_E)) {
577 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
578 zlog_debug(
579 "External bit reset ASBR route entry : %pFX",
580 &asbr_id);
581 return;
582 }
583
584 /*
585 * RFC 3101 - Section 2.5:
586 * "For a Type-7 LSA the matching routing table entry must
587 * specify an intra-area path through the LSA's originating
588 * NSSA".
589 */
590 if (ntohs(lsa->header->type) == OSPF6_LSTYPE_TYPE_7
591 && (asbr_entry->path.area_id != oa->area_id
592 || asbr_entry->path.type != OSPF6_PATH_TYPE_INTRA)) {
593 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
594 zlog_debug(
595 "Intra-area route to NSSA ASBR not found: %pFX",
596 &asbr_id);
597 return;
598 }
599 }
600
601 /*
602 * RFC 3101 - Section 2.5:
603 * "If the destination is a Type-7 default route (destination ID =
604 * DefaultDestination) and one of the following is true, then do
605 * nothing with this LSA and consider the next in the list:
606 *
607 * o The calculating router is a border router and the LSA has
608 * its P-bit clear. Appendix E describes a technique
609 * whereby an NSSA border router installs a Type-7 default
610 * LSA without propagating it.
611 *
612 * o The calculating router is a border router and is
613 * suppressing the import of summary routes as Type-3
614 * summary-LSAs".
615 */
616 if (ntohs(lsa->header->type) == OSPF6_LSTYPE_TYPE_7
617 && external->prefix.prefix_length == 0
618 && CHECK_FLAG(ospf6->flag, OSPF6_FLAG_ABR)
619 && (CHECK_FLAG(external->prefix.prefix_options,
620 OSPF6_PREFIX_OPTION_P)
621 || oa->no_summary)) {
622 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
623 zlog_debug("Skipping Type-7 default route");
624 return;
625 }
626
627 /* Check the forwarding address */
628 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F)) {
629 offset = sizeof(*external)
630 + OSPF6_PREFIX_SPACE(external->prefix.prefix_length);
631 memset(&fwd_addr, 0, sizeof(struct prefix));
632 fwd_addr.family = AF_INET6;
633 fwd_addr.prefixlen = IPV6_MAX_BITLEN;
634 memcpy(&fwd_addr.u.prefix6, (caddr_t)external + offset,
635 sizeof(struct in6_addr));
636
637 if (!IN6_IS_ADDR_UNSPECIFIED(&fwd_addr.u.prefix6)) {
638 if (!ospf6_ase_forward_address_check(
639 ospf6, &fwd_addr.u.prefix6)) {
640 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
641 zlog_debug(
642 "Fwd address %pFX is local address",
643 &fwd_addr);
644 return;
645 }
646
647 /* Find the forwarding entry */
648 asbr_entry = ospf6_route_lookup_bestmatch(
649 &fwd_addr, ospf6->route_table);
650 if (asbr_entry == NULL) {
651 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
652 zlog_debug(
653 "Fwd address not found: %pFX",
654 &fwd_addr);
655 return;
656 }
657 }
658 }
659
660 route = ospf6_route_create(ospf6);
661 route->type = OSPF6_DEST_TYPE_NETWORK;
662 route->prefix.family = AF_INET6;
663 route->prefix.prefixlen = external->prefix.prefix_length;
664 ospf6_prefix_in6_addr(&route->prefix.u.prefix6, external,
665 &external->prefix);
666 route->prefix_options = external->prefix.prefix_options;
667
668 route->path.area_id = asbr_entry->path.area_id;
669 route->path.origin.type = lsa->header->type;
670 route->path.origin.id = lsa->header->id;
671 route->path.origin.adv_router = lsa->header->adv_router;
672 memcpy(&route->path.ls_prefix, &asbr_id, sizeof(struct prefix));
673
674 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_E)) {
675 route->path.type = OSPF6_PATH_TYPE_EXTERNAL2;
676 route->path.metric_type = 2;
677 route->path.cost = asbr_entry->path.cost;
678 route->path.u.cost_e2 = OSPF6_ASBR_METRIC(external);
679 } else {
680 route->path.type = OSPF6_PATH_TYPE_EXTERNAL1;
681 route->path.metric_type = 1;
682 route->path.cost =
683 asbr_entry->path.cost + OSPF6_ASBR_METRIC(external);
684 route->path.u.cost_e2 = 0;
685 }
686
687 route->path.tag = ospf6_as_external_lsa_get_tag(lsa);
688
689 ospf6_route_copy_nexthops(route, asbr_entry);
690
691 path = ospf6_path_dup(&route->path);
692 ospf6_copy_nexthops(path->nh_list, asbr_entry->nh_list);
693 listnode_add_sort(route->paths, path);
694
695
696 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
697 zlog_debug(
698 "%s: %s %u route add %pFX cost %u(%u) nh %u", __func__,
699 (type == OSPF6_LSTYPE_AS_EXTERNAL) ? "AS-External"
700 : "NSSA",
701 (route->path.type == OSPF6_PATH_TYPE_EXTERNAL1) ? 1 : 2,
702 &route->prefix, route->path.cost, route->path.u.cost_e2,
703 listcount(route->nh_list));
704
705 if (type == OSPF6_LSTYPE_AS_EXTERNAL)
706 old = ospf6_route_lookup(&route->prefix, ospf6->route_table);
707 else if (type == OSPF6_LSTYPE_TYPE_7)
708 old = ospf6_route_lookup(&route->prefix, oa->route_table);
709 if (!old) {
710 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
711 zlog_debug("%s: Adding new route", __func__);
712 /* Add the new route to ospf6 instance route table. */
713 if (type == OSPF6_LSTYPE_AS_EXTERNAL)
714 ospf6_route_add(route, ospf6->route_table);
715 /* Add the route to the area route table */
716 else if (type == OSPF6_LSTYPE_TYPE_7) {
717 ospf6_route_add(route, oa->route_table);
718 }
719 } else {
720 /* RFC 2328 16.4 (6)
721 * ECMP: Keep new equal preference path in current
722 * route's path list, update zebra with new effective
723 * list along with addition of ECMP path.
724 */
725 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
726 zlog_debug("%s : old route %pFX cost %u(%u) nh %u",
727 __func__, &route->prefix, route->path.cost,
728 route->path.u.cost_e2,
729 listcount(route->nh_list));
730 ospf6_asbr_update_route_ecmp_path(old, route, ospf6);
731 }
732 }
733
734 void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa,
735 struct ospf6_route *asbr_entry)
736 {
737 struct ospf6_as_external_lsa *external;
738 struct prefix prefix;
739 struct ospf6_route *route, *nroute, *route_to_del;
740 struct ospf6_area *oa = NULL;
741 struct ospf6 *ospf6;
742 int type;
743 bool debug = false;
744
745 external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
746 lsa->header);
747
748 if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL) || (IS_OSPF6_DEBUG_NSSA))
749 debug = true;
750
751 ospf6 = ospf6_get_by_lsdb(lsa);
752 type = ntohs(lsa->header->type);
753
754 if (type == OSPF6_LSTYPE_TYPE_7) {
755 if (debug)
756 zlog_debug("%s: Withdraw Type 7 route for %s",
757 __func__, lsa->name);
758 oa = lsa->lsdb->data;
759 } else {
760 if (debug)
761 zlog_debug("%s: Withdraw AS-External route for %s",
762 __func__, lsa->name);
763
764 if (ospf6_check_and_set_router_abr(ospf6))
765 oa = ospf6->backbone;
766 else
767 oa = listnode_head(ospf6->area_list);
768 }
769
770 if (oa == NULL) {
771 if (debug)
772 zlog_debug("%s: Invalid area", __func__);
773 return;
774 }
775
776 if (lsa->header->adv_router == oa->ospf6->router_id) {
777 if (debug)
778 zlog_debug("Ignore self-originated AS-External-LSA");
779 return;
780 }
781
782 route_to_del = ospf6_route_create(ospf6);
783 route_to_del->type = OSPF6_DEST_TYPE_NETWORK;
784 route_to_del->prefix.family = AF_INET6;
785 route_to_del->prefix.prefixlen = external->prefix.prefix_length;
786 ospf6_prefix_in6_addr(&route_to_del->prefix.u.prefix6, external,
787 &external->prefix);
788
789 route_to_del->path.origin.type = lsa->header->type;
790 route_to_del->path.origin.id = lsa->header->id;
791 route_to_del->path.origin.adv_router = lsa->header->adv_router;
792
793 if (asbr_entry) {
794 route_to_del->path.area_id = asbr_entry->path.area_id;
795 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_E)) {
796 route_to_del->path.type = OSPF6_PATH_TYPE_EXTERNAL2;
797 route_to_del->path.metric_type = 2;
798 route_to_del->path.cost = asbr_entry->path.cost;
799 route_to_del->path.u.cost_e2 =
800 OSPF6_ASBR_METRIC(external);
801 } else {
802 route_to_del->path.type = OSPF6_PATH_TYPE_EXTERNAL1;
803 route_to_del->path.metric_type = 1;
804 route_to_del->path.cost = asbr_entry->path.cost
805 + OSPF6_ASBR_METRIC(external);
806 route_to_del->path.u.cost_e2 = 0;
807 }
808 }
809
810 memset(&prefix, 0, sizeof(struct prefix));
811 prefix.family = AF_INET6;
812 prefix.prefixlen = external->prefix.prefix_length;
813 ospf6_prefix_in6_addr(&prefix.u.prefix6, external, &external->prefix);
814
815 if (type == OSPF6_LSTYPE_TYPE_7)
816 route = ospf6_route_lookup(&prefix, oa->route_table);
817 else
818 route = ospf6_route_lookup(&prefix, oa->ospf6->route_table);
819
820 if (route == NULL) {
821 if (debug)
822 zlog_debug("AS-External route %pFX not found", &prefix);
823 ospf6_route_delete(route_to_del);
824 return;
825 }
826
827 if (debug)
828 zlog_debug(
829 "%s: Current route %pFX cost %u e2 %u, route to del cost %u e2 %u",
830 __func__, &prefix, route->path.cost, route->path.u.cost_e2,
831 route_to_del->path.cost, route_to_del->path.u.cost_e2);
832
833 for (ospf6_route_lock(route);
834 route && ospf6_route_is_prefix(&prefix, route); route = nroute) {
835 nroute = ospf6_route_next(route);
836
837 if (route->type != OSPF6_DEST_TYPE_NETWORK)
838 continue;
839
840 /* Route has multiple ECMP paths, remove matching
841 * path. Update current route's effective nh list
842 * after removal of one of the path.
843 */
844 if (listcount(route->paths) > 1) {
845 struct listnode *anode, *anext;
846 struct listnode *nnode, *rnode, *rnext;
847 struct ospf6_nexthop *nh, *rnh;
848 struct ospf6_path *o_path;
849 bool nh_updated = false;
850
851 /* Iterate all paths of route to find maching with LSA
852 * remove from route path list. If route->path is same,
853 * replace from paths list.
854 */
855 for (ALL_LIST_ELEMENTS(route->paths, anode, anext,
856 o_path)) {
857 if ((o_path->origin.type != lsa->header->type)
858 || (o_path->origin.adv_router
859 != lsa->header->adv_router)
860 || (o_path->origin.id != lsa->header->id))
861 continue;
862
863 /* Compare LSA cost with current
864 * route info.
865 */
866 if (asbr_entry
867 && (o_path->cost != route_to_del->path.cost
868 || o_path->u.cost_e2
869 != route_to_del->path.u
870 .cost_e2)) {
871 if (IS_OSPF6_DEBUG_EXAMIN(
872 AS_EXTERNAL)) {
873 zlog_debug(
874 "%s: route %pFX to delete is not same, cost %u del cost %u. skip",
875 __func__, &prefix,
876 route->path.cost,
877 route_to_del->path
878 .cost);
879 }
880 continue;
881 }
882
883 if (debug) {
884 zlog_debug(
885 "%s: route %pFX path found with cost %u nh %u to remove.",
886 __func__, &prefix, route->path.cost,
887 listcount(o_path->nh_list));
888 }
889
890 /* Remove found path's nh_list from
891 * the route's nh_list.
892 */
893 for (ALL_LIST_ELEMENTS_RO(o_path->nh_list,
894 nnode, nh)) {
895 for (ALL_LIST_ELEMENTS(route->nh_list,
896 rnode, rnext,
897 rnh)) {
898 if (!ospf6_nexthop_is_same(rnh,
899 nh))
900 continue;
901 listnode_delete(route->nh_list,
902 rnh);
903 ospf6_nexthop_delete(rnh);
904 }
905 }
906 /* Delete the path from route's path list */
907 listnode_delete(route->paths, o_path);
908 ospf6_path_free(o_path);
909 nh_updated = true;
910 }
911
912 if (nh_updated) {
913 /* Iterate all paths and merge nexthop,
914 * unlesss any of the nexthop similar to
915 * ones deleted as part of path deletion.
916 */
917
918 for (ALL_LIST_ELEMENTS(route->paths, anode,
919 anext, o_path)) {
920 ospf6_merge_nexthops(route->nh_list,
921 o_path->nh_list);
922 }
923
924 if (debug) {
925 zlog_debug(
926 "%s: AS-External %u route %pFX update paths %u nh %u",
927 __func__,
928 (route->path.type
929 == OSPF6_PATH_TYPE_EXTERNAL1)
930 ? 1
931 : 2,
932 &route->prefix, listcount(route->paths),
933 route->nh_list ? listcount(
934 route->nh_list)
935 : 0);
936 }
937
938 if (listcount(route->paths)) {
939 /* Update RIB/FIB with effective
940 * nh_list
941 */
942 if (oa->ospf6->route_table->hook_add)
943 (*oa->ospf6->route_table
944 ->hook_add)(route);
945
946 /* route's primary path is similar
947 * to LSA, replace route's primary
948 * path with route's paths list head.
949 */
950 if ((route->path.origin.id ==
951 lsa->header->id) &&
952 (route->path.origin.adv_router
953 == lsa->header->adv_router)) {
954 struct ospf6_path *h_path;
955
956 h_path = (struct ospf6_path *)
957 listgetdata(
958 listhead(route->paths));
959 route->path.origin.type =
960 h_path->origin.type;
961 route->path.origin.id =
962 h_path->origin.id;
963 route->path.origin.adv_router =
964 h_path->origin.adv_router;
965 }
966 } else {
967 if (type == OSPF6_LSTYPE_TYPE_7)
968 ospf6_route_remove(
969 route, oa->route_table);
970 else
971 ospf6_route_remove(
972 route,
973 oa->ospf6->route_table);
974 }
975 }
976 continue;
977
978 } else {
979 /* Compare LSA origin and cost with current route info.
980 * if any check fails skip del this route node.
981 */
982 if (asbr_entry
983 && (!ospf6_route_is_same_origin(route, route_to_del)
984 || (route->path.type != route_to_del->path.type)
985 || (route->path.cost != route_to_del->path.cost)
986 || (route->path.u.cost_e2
987 != route_to_del->path.u.cost_e2))) {
988 if (debug) {
989 zlog_debug(
990 "%s: route %pFX to delete is not same, cost %u del cost %u. skip",
991 __func__, &prefix, route->path.cost,
992 route_to_del->path.cost);
993 }
994 continue;
995 }
996
997 if ((route->path.origin.type != lsa->header->type)
998 || (route->path.origin.adv_router
999 != lsa->header->adv_router)
1000 || (route->path.origin.id != lsa->header->id))
1001 continue;
1002 }
1003 if (debug) {
1004 zlog_debug(
1005 "%s: AS-External %u route remove %pFX cost %u(%u) nh %u",
1006 __func__,
1007 route->path.type == OSPF6_PATH_TYPE_EXTERNAL1
1008 ? 1
1009 : 2,
1010 &route->prefix, route->path.cost, route->path.u.cost_e2,
1011 listcount(route->nh_list));
1012 }
1013 if (type == OSPF6_LSTYPE_TYPE_7)
1014 ospf6_route_remove(route, oa->route_table);
1015 else
1016 ospf6_route_remove(route, oa->ospf6->route_table);
1017 }
1018 if (route != NULL)
1019 ospf6_route_unlock(route);
1020
1021 ospf6_route_delete(route_to_del);
1022 }
1023
1024 void ospf6_asbr_lsentry_add(struct ospf6_route *asbr_entry, struct ospf6 *ospf6)
1025 {
1026 struct ospf6_lsa *lsa;
1027 uint16_t type;
1028 uint32_t router;
1029
1030 if (!CHECK_FLAG(asbr_entry->flag, OSPF6_ROUTE_BEST)) {
1031 char buf[16];
1032 inet_ntop(AF_INET, &ADV_ROUTER_IN_PREFIX(&asbr_entry->prefix),
1033 buf, sizeof(buf));
1034 zlog_info("ignore non-best path: lsentry %s add", buf);
1035 return;
1036 }
1037
1038 type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
1039 router = ospf6_linkstate_prefix_adv_router(&asbr_entry->prefix);
1040 for (ALL_LSDB_TYPED_ADVRTR(ospf6->lsdb, type, router, lsa)) {
1041 if (!OSPF6_LSA_IS_MAXAGE(lsa))
1042 ospf6_asbr_lsa_add(lsa);
1043 }
1044 }
1045
1046 void ospf6_asbr_lsentry_remove(struct ospf6_route *asbr_entry,
1047 struct ospf6 *ospf6)
1048 {
1049 struct ospf6_lsa *lsa;
1050 uint16_t type;
1051 uint32_t router;
1052
1053 type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
1054 router = ospf6_linkstate_prefix_adv_router(&asbr_entry->prefix);
1055 for (ALL_LSDB_TYPED_ADVRTR(ospf6->lsdb, type, router, lsa))
1056 ospf6_asbr_lsa_remove(lsa, asbr_entry);
1057 }
1058
1059
1060 /* redistribute function */
1061 static void ospf6_asbr_routemap_set(struct ospf6_redist *red,
1062 const char *mapname)
1063 {
1064 if (ROUTEMAP_NAME(red)) {
1065 route_map_counter_decrement(ROUTEMAP(red));
1066 free(ROUTEMAP_NAME(red));
1067 }
1068
1069 ROUTEMAP_NAME(red) = strdup(mapname);
1070 ROUTEMAP(red) = route_map_lookup_by_name(mapname);
1071 route_map_counter_increment(ROUTEMAP(red));
1072 }
1073
1074 static void ospf6_asbr_routemap_unset(struct ospf6_redist *red)
1075 {
1076 if (ROUTEMAP_NAME(red))
1077 free(ROUTEMAP_NAME(red));
1078
1079 route_map_counter_decrement(ROUTEMAP(red));
1080
1081 ROUTEMAP_NAME(red) = NULL;
1082 ROUTEMAP(red) = NULL;
1083 }
1084
1085 static void ospf6_asbr_routemap_update_timer(struct thread *thread)
1086 {
1087 struct ospf6 *ospf6 = THREAD_ARG(thread);
1088 struct ospf6_redist *red;
1089 int type;
1090
1091 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
1092 red = ospf6_redist_lookup(ospf6, type, 0);
1093
1094 if (!red)
1095 continue;
1096
1097 if (!CHECK_FLAG(red->flag, OSPF6_IS_RMAP_CHANGED))
1098 continue;
1099
1100 if (ROUTEMAP_NAME(red))
1101 ROUTEMAP(red) =
1102 route_map_lookup_by_name(ROUTEMAP_NAME(red));
1103
1104 if (ROUTEMAP(red)) {
1105 if (IS_OSPF6_DEBUG_ASBR)
1106 zlog_debug(
1107 "%s: route-map %s update, reset redist %s",
1108 __func__, ROUTEMAP_NAME(red),
1109 ZROUTE_NAME(type));
1110
1111 ospf6_zebra_no_redistribute(type, ospf6->vrf_id);
1112 ospf6_zebra_redistribute(type, ospf6->vrf_id);
1113 }
1114
1115 UNSET_FLAG(red->flag, OSPF6_IS_RMAP_CHANGED);
1116 }
1117 }
1118
1119 void ospf6_asbr_distribute_list_update(struct ospf6 *ospf6,
1120 struct ospf6_redist *red)
1121 {
1122 SET_FLAG(red->flag, OSPF6_IS_RMAP_CHANGED);
1123
1124 if (ospf6->t_distribute_update)
1125 return;
1126
1127 if (IS_OSPF6_DEBUG_ASBR)
1128 zlog_debug("%s: trigger redistribute reset thread", __func__);
1129
1130 thread_add_timer_msec(master, ospf6_asbr_routemap_update_timer, ospf6,
1131 OSPF_MIN_LS_INTERVAL,
1132 &ospf6->t_distribute_update);
1133 }
1134
1135 void ospf6_asbr_routemap_update(const char *mapname)
1136 {
1137 int type;
1138 struct listnode *node, *nnode;
1139 struct ospf6 *ospf6 = NULL;
1140 struct ospf6_redist *red;
1141
1142 if (om6 == NULL)
1143 return;
1144
1145 for (ALL_LIST_ELEMENTS(om6->ospf6, node, nnode, ospf6)) {
1146 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
1147 red = ospf6_redist_lookup(ospf6, type, 0);
1148 if (!red || (ROUTEMAP_NAME(red) == NULL))
1149 continue;
1150 ROUTEMAP(red) =
1151 route_map_lookup_by_name(ROUTEMAP_NAME(red));
1152
1153 if (mapname == NULL
1154 || strcmp(ROUTEMAP_NAME(red), mapname))
1155 continue;
1156 if (ROUTEMAP(red)) {
1157 if (IS_OSPF6_DEBUG_ASBR)
1158 zlog_debug(
1159 "%s: route-map %s update, reset redist %s",
1160 __func__,
1161 mapname,
1162 ZROUTE_NAME(
1163 type));
1164
1165 route_map_counter_increment(ROUTEMAP(red));
1166 ospf6_asbr_distribute_list_update(ospf6, red);
1167 } else {
1168 /*
1169 * if the mapname matches a
1170 * route-map on ospf6 but the
1171 * map doesn't exist, it is
1172 * being deleted. flush and then
1173 * readvertise
1174 */
1175 if (IS_OSPF6_DEBUG_ASBR)
1176 zlog_debug(
1177 "%s: route-map %s deleted, reset redist %s",
1178 __func__,
1179 mapname,
1180 ZROUTE_NAME(
1181 type));
1182 ospf6_asbr_redistribute_unset(ospf6, red, type);
1183 ospf6_asbr_routemap_set(red, mapname);
1184 ospf6_asbr_redistribute_set(ospf6, type);
1185 }
1186 }
1187 }
1188 }
1189
1190 static void ospf6_asbr_routemap_event(const char *name)
1191 {
1192 int type;
1193 struct listnode *node, *nnode;
1194 struct ospf6 *ospf6;
1195 struct ospf6_redist *red;
1196
1197 if (om6 == NULL)
1198 return;
1199 for (ALL_LIST_ELEMENTS(om6->ospf6, node, nnode, ospf6)) {
1200 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
1201 red = ospf6_redist_lookup(ospf6, type, 0);
1202 if (red && ROUTEMAP_NAME(red)
1203 && (strcmp(ROUTEMAP_NAME(red), name) == 0))
1204 ospf6_asbr_distribute_list_update(ospf6, red);
1205 }
1206 }
1207 }
1208
1209 int ospf6_asbr_is_asbr(struct ospf6 *o)
1210 {
1211 return (o->external_table->count || IS_OSPF6_ASBR(o));
1212 }
1213
1214 struct ospf6_redist *ospf6_redist_lookup(struct ospf6 *ospf6, int type,
1215 unsigned short instance)
1216 {
1217 struct list *red_list;
1218 struct listnode *node;
1219 struct ospf6_redist *red;
1220
1221 red_list = ospf6->redist[type];
1222 if (!red_list)
1223 return (NULL);
1224
1225 for (ALL_LIST_ELEMENTS_RO(red_list, node, red))
1226 if (red->instance == instance)
1227 return red;
1228
1229 return NULL;
1230 }
1231
1232 static struct ospf6_redist *ospf6_redist_add(struct ospf6 *ospf6, int type,
1233 uint8_t instance)
1234 {
1235 struct ospf6_redist *red;
1236
1237 red = ospf6_redist_lookup(ospf6, type, instance);
1238 if (red)
1239 return red;
1240
1241 if (!ospf6->redist[type])
1242 ospf6->redist[type] = list_new();
1243
1244 red = XCALLOC(MTYPE_OSPF6_REDISTRIBUTE, sizeof(struct ospf6_redist));
1245 red->instance = instance;
1246 red->dmetric.type = -1;
1247 red->dmetric.value = -1;
1248 ROUTEMAP_NAME(red) = NULL;
1249 ROUTEMAP(red) = NULL;
1250
1251 listnode_add(ospf6->redist[type], red);
1252 ospf6->redistribute++;
1253
1254 return red;
1255 }
1256
1257 static void ospf6_redist_del(struct ospf6 *ospf6, struct ospf6_redist *red,
1258 int type)
1259 {
1260 if (red) {
1261 listnode_delete(ospf6->redist[type], red);
1262 if (!ospf6->redist[type]->count) {
1263 list_delete(&ospf6->redist[type]);
1264 }
1265 XFREE(MTYPE_OSPF6_REDISTRIBUTE, red);
1266 ospf6->redistribute--;
1267 }
1268 }
1269
1270 /*Set the status of the ospf instance to ASBR based on the status parameter,
1271 * rechedule SPF calculation, originate router LSA*/
1272 void ospf6_asbr_status_update(struct ospf6 *ospf6, int status)
1273 {
1274 struct listnode *lnode, *lnnode;
1275 struct ospf6_area *oa;
1276
1277 zlog_info("ASBR[%s:Status:%d]: Update", ospf6->name, status);
1278
1279 if (status) {
1280 if (IS_OSPF6_ASBR(ospf6)) {
1281 zlog_info("ASBR[%s:Status:%d]: Already ASBR",
1282 ospf6->name, status);
1283 return;
1284 }
1285 SET_FLAG(ospf6->flag, OSPF6_FLAG_ASBR);
1286 } else {
1287 if (!IS_OSPF6_ASBR(ospf6)) {
1288 zlog_info("ASBR[%s:Status:%d]: Already non ASBR",
1289 ospf6->name, status);
1290 return;
1291 }
1292 UNSET_FLAG(ospf6->flag, OSPF6_FLAG_ASBR);
1293 }
1294
1295 /* Transition from/to status ASBR, schedule timer. */
1296 ospf6_spf_schedule(ospf6, OSPF6_SPF_FLAGS_ASBR_STATUS_CHANGE);
1297
1298 /* Reoriginate router LSA for all areas */
1299 for (ALL_LIST_ELEMENTS(ospf6->area_list, lnode, lnnode, oa))
1300 OSPF6_ROUTER_LSA_SCHEDULE(oa);
1301 }
1302
1303 static void ospf6_asbr_redistribute_set(struct ospf6 *ospf6, int type)
1304 {
1305 ospf6_zebra_redistribute(type, ospf6->vrf_id);
1306
1307 ++ospf6->redist_count;
1308 ospf6_asbr_status_update(ospf6, ospf6->redist_count);
1309 }
1310
1311 static void ospf6_asbr_redistribute_unset(struct ospf6 *ospf6,
1312 struct ospf6_redist *red, int type)
1313 {
1314 struct ospf6_route *route;
1315 struct ospf6_external_info *info;
1316
1317 ospf6_zebra_no_redistribute(type, ospf6->vrf_id);
1318
1319 for (route = ospf6_route_head(ospf6->external_table); route;
1320 route = ospf6_route_next(route)) {
1321 info = route->route_option;
1322 if (info->type != type)
1323 continue;
1324
1325 ospf6_asbr_redistribute_remove(info->type, 0, &route->prefix,
1326 ospf6);
1327 }
1328
1329 ospf6_asbr_routemap_unset(red);
1330 --ospf6->redist_count;
1331 ospf6_asbr_status_update(ospf6, ospf6->redist_count);
1332 }
1333
1334 /* When an area is unstubified, flood all the external LSAs in the area */
1335 void ospf6_asbr_send_externals_to_area(struct ospf6_area *oa)
1336 {
1337 struct ospf6_lsa *lsa, *lsanext;
1338
1339 for (ALL_LSDB(oa->ospf6->lsdb, lsa, lsanext)) {
1340 if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL) {
1341 if (IS_OSPF6_DEBUG_ASBR)
1342 zlog_debug("%s: Flooding AS-External LSA %s",
1343 __func__, lsa->name);
1344
1345 ospf6_flood_area(NULL, lsa, oa);
1346 }
1347 }
1348 }
1349
1350 /* When an area is stubified, remove all the external LSAs in the area */
1351 void ospf6_asbr_remove_externals_from_area(struct ospf6_area *oa)
1352 {
1353 struct ospf6_lsa *lsa, *lsanext;
1354 struct listnode *node, *nnode;
1355 struct ospf6_area *area;
1356 struct ospf6 *ospf6 = oa->ospf6;
1357 const struct route_node *iterend;
1358
1359 /* skip if router is in other non-stub/non-NSSA areas */
1360 for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, area))
1361 if (!IS_AREA_STUB(area) && !IS_AREA_NSSA(area))
1362 return;
1363
1364 /* if router is only in a stub area then purge AS-External LSAs */
1365 iterend = ospf6_lsdb_head(ospf6->lsdb, 0, 0, 0, &lsa);
1366 while (lsa != NULL) {
1367 assert(lsa->lock > 1);
1368 lsanext = ospf6_lsdb_next(iterend, lsa);
1369 if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL)
1370 ospf6_lsdb_remove(lsa, ospf6->lsdb);
1371 lsa = lsanext;
1372 }
1373 }
1374
1375 static struct ospf6_external_aggr_rt *
1376 ospf6_external_aggr_match(struct ospf6 *ospf6, struct prefix *p)
1377 {
1378 struct route_node *node;
1379
1380 node = route_node_match(ospf6->rt_aggr_tbl, p);
1381 if (node == NULL)
1382 return NULL;
1383
1384 if (IS_OSPF6_DEBUG_AGGR) {
1385 struct ospf6_external_aggr_rt *ag = node->info;
1386 zlog_debug("%s: Matching aggregator found.prefix: %pFX Aggregator %pFX",
1387 __func__,
1388 p,
1389 &ag->p);
1390 }
1391
1392 route_unlock_node(node);
1393
1394 return node->info;
1395 }
1396
1397 void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
1398 struct prefix *prefix,
1399 unsigned int nexthop_num,
1400 struct in6_addr *nexthop, route_tag_t tag,
1401 struct ospf6 *ospf6)
1402 {
1403 route_map_result_t ret;
1404 struct ospf6_route troute;
1405 struct ospf6_external_info tinfo;
1406 struct ospf6_route *route, *match;
1407 struct ospf6_external_info *info;
1408 struct ospf6_redist *red;
1409
1410 red = ospf6_redist_lookup(ospf6, type, 0);
1411
1412 if (!red)
1413 return;
1414
1415 if ((type != DEFAULT_ROUTE)
1416 && !ospf6_zebra_is_redistribute(type, ospf6->vrf_id))
1417 return;
1418
1419 memset(&troute, 0, sizeof(troute));
1420 memset(&tinfo, 0, sizeof(tinfo));
1421
1422 if (IS_OSPF6_DEBUG_ASBR)
1423 zlog_debug("Redistribute %pFX (%s)", prefix,
1424 type == DEFAULT_ROUTE
1425 ? "default-information-originate"
1426 : ZROUTE_NAME(type));
1427
1428 /* if route-map was specified but not found, do not advertise */
1429 if (ROUTEMAP_NAME(red)) {
1430 if (ROUTEMAP(red) == NULL)
1431 ospf6_asbr_routemap_update(NULL);
1432 if (ROUTEMAP(red) == NULL) {
1433 zlog_warn(
1434 "route-map \"%s\" not found, suppress redistributing",
1435 ROUTEMAP_NAME(red));
1436 return;
1437 }
1438 }
1439
1440 /* apply route-map */
1441 if (ROUTEMAP(red)) {
1442 troute.route_option = &tinfo;
1443 tinfo.ifindex = ifindex;
1444 tinfo.tag = tag;
1445
1446 ret = route_map_apply(ROUTEMAP(red), prefix, &troute);
1447 if (ret == RMAP_DENYMATCH) {
1448 if (IS_OSPF6_DEBUG_ASBR)
1449 zlog_debug("Denied by route-map \"%s\"",
1450 ROUTEMAP_NAME(red));
1451 ospf6_asbr_redistribute_remove(type, ifindex, prefix,
1452 ospf6);
1453 return;
1454 }
1455 }
1456
1457 match = ospf6_route_lookup(prefix, ospf6->external_table);
1458 if (match) {
1459 info = match->route_option;
1460 /* copy result of route-map */
1461 if (ROUTEMAP(red)) {
1462 if (troute.path.metric_type)
1463 match->path.metric_type =
1464 troute.path.metric_type;
1465 else
1466 match->path.metric_type =
1467 metric_type(ospf6, type, 0);
1468 if (troute.path.cost)
1469 match->path.cost = troute.path.cost;
1470 else
1471 match->path.cost = metric_value(ospf6, type, 0);
1472
1473 if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo.forwarding))
1474 memcpy(&info->forwarding, &tinfo.forwarding,
1475 sizeof(struct in6_addr));
1476 info->tag = tinfo.tag;
1477 } else {
1478 /* If there is no route-map, simply update the tag and
1479 * metric fields
1480 */
1481 match->path.metric_type = metric_type(ospf6, type, 0);
1482 match->path.cost = metric_value(ospf6, type, 0);
1483 info->tag = tag;
1484 }
1485
1486 info->type = type;
1487
1488 if (nexthop_num && nexthop)
1489 ospf6_route_add_nexthop(match, ifindex, nexthop);
1490 else
1491 ospf6_route_add_nexthop(match, ifindex, NULL);
1492
1493 match->path.origin.id = htonl(info->id);
1494 ospf6_handle_external_lsa_origination(ospf6, match, prefix);
1495
1496 ospf6_asbr_status_update(ospf6, ospf6->redistribute);
1497
1498 return;
1499 }
1500
1501 /* create new entry */
1502 route = ospf6_route_create(ospf6);
1503 route->type = OSPF6_DEST_TYPE_NETWORK;
1504 prefix_copy(&route->prefix, prefix);
1505
1506 info = (struct ospf6_external_info *)XCALLOC(
1507 MTYPE_OSPF6_EXTERNAL_INFO, sizeof(struct ospf6_external_info));
1508 route->route_option = info;
1509
1510 /* copy result of route-map */
1511 if (ROUTEMAP(red)) {
1512 if (troute.path.metric_type)
1513 route->path.metric_type = troute.path.metric_type;
1514 else
1515 route->path.metric_type = metric_type(ospf6, type, 0);
1516 if (troute.path.cost)
1517 route->path.cost = troute.path.cost;
1518 else
1519 route->path.cost = metric_value(ospf6, type, 0);
1520 if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo.forwarding))
1521 memcpy(&info->forwarding, &tinfo.forwarding,
1522 sizeof(struct in6_addr));
1523 info->tag = tinfo.tag;
1524 } else {
1525 /* If there is no route-map, simply update the tag and metric
1526 * fields
1527 */
1528 route->path.metric_type = metric_type(ospf6, type, 0);
1529 route->path.cost = metric_value(ospf6, type, 0);
1530 info->tag = tag;
1531 }
1532
1533 info->type = type;
1534 if (nexthop_num && nexthop)
1535 ospf6_route_add_nexthop(route, ifindex, nexthop);
1536 else
1537 ospf6_route_add_nexthop(route, ifindex, NULL);
1538
1539 route = ospf6_route_add(route, ospf6->external_table);
1540 ospf6_handle_external_lsa_origination(ospf6, route, prefix);
1541
1542 ospf6_asbr_status_update(ospf6, ospf6->redistribute);
1543
1544 }
1545
1546 static void ospf6_asbr_external_lsa_remove_by_id(struct ospf6 *ospf6,
1547 uint32_t id)
1548 {
1549 struct ospf6_lsa *lsa;
1550
1551 lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
1552 htonl(id), ospf6->router_id, ospf6->lsdb);
1553 if (!lsa)
1554 return;
1555
1556 ospf6_external_lsa_purge(ospf6, lsa);
1557
1558 }
1559
1560 static void
1561 ospf6_link_route_to_aggr(struct ospf6_external_aggr_rt *aggr,
1562 struct ospf6_route *rt)
1563 {
1564 hash_get(aggr->match_extnl_hash, rt, hash_alloc_intern);
1565 rt->aggr_route = aggr;
1566 }
1567
1568 static void
1569 ospf6_asbr_summary_remove_lsa_and_route(struct ospf6 *ospf6,
1570 struct ospf6_external_aggr_rt *aggr)
1571 {
1572
1573 /* Send a Max age LSA if it is already originated.*/
1574 if (!CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED))
1575 return;
1576
1577 if (IS_OSPF6_DEBUG_AGGR)
1578 zlog_debug("%s: Flushing Aggregate route (%pFX)",
1579 __func__,
1580 &aggr->p);
1581
1582 ospf6_asbr_external_lsa_remove_by_id(ospf6, aggr->id);
1583
1584 if (aggr->route) {
1585 if (IS_OSPF6_DEBUG_AGGR)
1586 zlog_debug(
1587 "%s: Remove the blackhole route",
1588 __func__);
1589 ospf6_zebra_route_update_remove(aggr->route, ospf6);
1590 ospf6_route_delete(aggr->route);
1591 aggr->route = NULL;
1592 }
1593
1594 aggr->id = 0;
1595 /* Unset the Origination flag */
1596 UNSET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED);
1597 }
1598
1599 static void
1600 ospf6_unlink_route_from_aggr(struct ospf6 *ospf6,
1601 struct ospf6_external_aggr_rt *aggr,
1602 struct ospf6_route *rt)
1603 {
1604 if (IS_OSPF6_DEBUG_AGGR)
1605 zlog_debug("%s: Unlinking external route(%pFX) from aggregator(%pFX), external route count:%ld",
1606 __func__,
1607 &rt->prefix,
1608 &aggr->p,
1609 OSPF6_EXTERNAL_RT_COUNT(aggr));
1610
1611 hash_release(aggr->match_extnl_hash, rt);
1612 rt->aggr_route = NULL;
1613
1614 /* Flush the aggregate route if matching
1615 * external route count becomes zero.
1616 */
1617 if (!OSPF6_EXTERNAL_RT_COUNT(aggr))
1618 ospf6_asbr_summary_remove_lsa_and_route(ospf6, aggr);
1619 }
1620
1621 void ospf6_asbr_redistribute_remove(int type, ifindex_t ifindex,
1622 struct prefix *prefix, struct ospf6 *ospf6)
1623 {
1624 struct ospf6_route *match;
1625 struct ospf6_external_info *info = NULL;
1626
1627 match = ospf6_route_lookup(prefix, ospf6->external_table);
1628 if (match == NULL) {
1629 if (IS_OSPF6_DEBUG_ASBR)
1630 zlog_debug("No such route %pFX to withdraw", prefix);
1631 return;
1632 }
1633
1634 info = match->route_option;
1635 assert(info);
1636
1637 if (info->type != type) {
1638 if (IS_OSPF6_DEBUG_ASBR)
1639 zlog_debug("Original protocol mismatch: %pFX", prefix);
1640 return;
1641 }
1642
1643 /* This means aggregation on this route was not done, hence remove LSA
1644 * if any originated for this prefix
1645 */
1646 if (!match->aggr_route)
1647 ospf6_asbr_external_lsa_remove_by_id(ospf6, info->id);
1648 else
1649 ospf6_unlink_route_from_aggr(ospf6, match->aggr_route, match);
1650
1651 if (IS_OSPF6_DEBUG_ASBR)
1652 zlog_debug("Removing route from external table %pFX",
1653 prefix);
1654
1655 ospf6_route_remove(match, ospf6->external_table);
1656 XFREE(MTYPE_OSPF6_EXTERNAL_INFO, info);
1657
1658 ospf6_asbr_status_update(ospf6, ospf6->redistribute);
1659 }
1660
1661 DEFPY (ospf6_redistribute,
1662 ospf6_redistribute_cmd,
1663 "redistribute " FRR_REDIST_STR_OSPF6D "[{metric (0-16777214)|metric-type (1-2)$metric_type|route-map WORD$rmap_str}]",
1664 "Redistribute\n"
1665 FRR_REDIST_HELP_STR_OSPF6D
1666 "Metric for redistributed routes\n"
1667 "OSPF default metric\n"
1668 "OSPF exterior metric type for redistributed routes\n"
1669 "Set OSPF External Type 1/2 metrics\n"
1670 "Route map reference\n"
1671 "Route map name\n")
1672 {
1673 int type;
1674 struct ospf6_redist *red;
1675 int idx_protocol = 1;
1676 char *proto = argv[idx_protocol]->text;
1677
1678 VTY_DECLVAR_CONTEXT(ospf6, ospf6);
1679
1680 type = proto_redistnum(AFI_IP6, proto);
1681 if (type < 0)
1682 return CMD_WARNING_CONFIG_FAILED;
1683
1684 if (!metric_str)
1685 metric = -1;
1686 if (!metric_type_str)
1687 metric_type = -1;
1688
1689 red = ospf6_redist_lookup(ospf6, type, 0);
1690 if (!red) {
1691 red = ospf6_redist_add(ospf6, type, 0);
1692 } else {
1693 /* Check if nothing has changed. */
1694 if (red->dmetric.value == metric
1695 && red->dmetric.type == metric_type
1696 && ((!ROUTEMAP_NAME(red) && !rmap_str)
1697 || (ROUTEMAP_NAME(red) && rmap_str
1698 && strmatch(ROUTEMAP_NAME(red), rmap_str))))
1699 return CMD_SUCCESS;
1700
1701 ospf6_asbr_redistribute_unset(ospf6, red, type);
1702 }
1703
1704 red->dmetric.value = metric;
1705 red->dmetric.type = metric_type;
1706 if (rmap_str)
1707 ospf6_asbr_routemap_set(red, rmap_str);
1708 else
1709 ospf6_asbr_routemap_unset(red);
1710 ospf6_asbr_redistribute_set(ospf6, type);
1711
1712 return CMD_SUCCESS;
1713 }
1714
1715 DEFUN (no_ospf6_redistribute,
1716 no_ospf6_redistribute_cmd,
1717 "no redistribute " FRR_REDIST_STR_OSPF6D "[{metric (0-16777214)|metric-type (1-2)|route-map WORD}]",
1718 NO_STR
1719 "Redistribute\n"
1720 FRR_REDIST_HELP_STR_OSPF6D
1721 "Metric for redistributed routes\n"
1722 "OSPF default metric\n"
1723 "OSPF exterior metric type for redistributed routes\n"
1724 "Set OSPF External Type 1/2 metrics\n"
1725 "Route map reference\n"
1726 "Route map name\n")
1727 {
1728 int type;
1729 struct ospf6_redist *red;
1730 int idx_protocol = 2;
1731 char *proto = argv[idx_protocol]->text;
1732
1733 VTY_DECLVAR_CONTEXT(ospf6, ospf6);
1734
1735 type = proto_redistnum(AFI_IP6, proto);
1736 if (type < 0)
1737 return CMD_WARNING_CONFIG_FAILED;
1738
1739 red = ospf6_redist_lookup(ospf6, type, 0);
1740 if (!red)
1741 return CMD_SUCCESS;
1742
1743 ospf6_asbr_redistribute_unset(ospf6, red, type);
1744 ospf6_redist_del(ospf6, red, type);
1745
1746 return CMD_SUCCESS;
1747 }
1748
1749 int ospf6_redistribute_config_write(struct vty *vty, struct ospf6 *ospf6)
1750 {
1751 int type;
1752 struct ospf6_redist *red;
1753
1754 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
1755 red = ospf6_redist_lookup(ospf6, type, 0);
1756 if (!red)
1757 continue;
1758 if (type == ZEBRA_ROUTE_OSPF6)
1759 continue;
1760
1761 vty_out(vty, " redistribute %s", ZROUTE_NAME(type));
1762 if (red->dmetric.value >= 0)
1763 vty_out(vty, " metric %d", red->dmetric.value);
1764 if (red->dmetric.type == 1)
1765 vty_out(vty, " metric-type 1");
1766 if (ROUTEMAP_NAME(red))
1767 vty_out(vty, " route-map %s", ROUTEMAP_NAME(red));
1768 vty_out(vty, "\n");
1769 }
1770
1771 return 0;
1772 }
1773
1774 static void ospf6_redistribute_show_config(struct vty *vty, struct ospf6 *ospf6,
1775 json_object *json_array,
1776 json_object *json, bool use_json)
1777 {
1778 int type;
1779 int nroute[ZEBRA_ROUTE_MAX];
1780 int total;
1781 struct ospf6_route *route;
1782 struct ospf6_external_info *info;
1783 json_object *json_route;
1784 struct ospf6_redist *red;
1785
1786 total = 0;
1787 memset(nroute, 0, sizeof(nroute));
1788 for (route = ospf6_route_head(ospf6->external_table); route;
1789 route = ospf6_route_next(route)) {
1790 info = route->route_option;
1791 nroute[info->type]++;
1792 total++;
1793 }
1794
1795 if (!use_json)
1796 vty_out(vty, "Redistributing External Routes from:\n");
1797
1798 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
1799
1800 red = ospf6_redist_lookup(ospf6, type, 0);
1801
1802 if (!red)
1803 continue;
1804 if (type == ZEBRA_ROUTE_OSPF6)
1805 continue;
1806
1807 if (use_json) {
1808 json_route = json_object_new_object();
1809 json_object_string_add(json_route, "routeType",
1810 ZROUTE_NAME(type));
1811 json_object_int_add(json_route, "numberOfRoutes",
1812 nroute[type]);
1813 json_object_boolean_add(json_route,
1814 "routeMapNamePresent",
1815 ROUTEMAP_NAME(red));
1816 }
1817
1818 if (ROUTEMAP_NAME(red)) {
1819 if (use_json) {
1820 json_object_string_add(json_route,
1821 "routeMapName",
1822 ROUTEMAP_NAME(red));
1823 json_object_boolean_add(json_route,
1824 "routeMapFound",
1825 ROUTEMAP(red));
1826 } else
1827 vty_out(vty,
1828 " %d: %s with route-map \"%s\"%s\n",
1829 nroute[type], ZROUTE_NAME(type),
1830 ROUTEMAP_NAME(red),
1831 (ROUTEMAP(red) ? ""
1832 : " (not found !)"));
1833 } else {
1834 if (!use_json)
1835 vty_out(vty, " %d: %s\n", nroute[type],
1836 ZROUTE_NAME(type));
1837 }
1838
1839 if (use_json)
1840 json_object_array_add(json_array, json_route);
1841 }
1842 if (use_json) {
1843 json_object_object_add(json, "redistributedRoutes", json_array);
1844 json_object_int_add(json, "totalRoutes", total);
1845 } else
1846 vty_out(vty, "Total %d routes\n", total);
1847 }
1848
1849 static void ospf6_redistribute_default_set(struct ospf6 *ospf6, int originate)
1850 {
1851 struct prefix_ipv6 p = {};
1852 struct in6_addr nexthop = {};
1853 int cur_originate = ospf6->default_originate;
1854
1855 p.family = AF_INET6;
1856 p.prefixlen = 0;
1857
1858 ospf6->default_originate = originate;
1859
1860 switch (cur_originate) {
1861 case DEFAULT_ORIGINATE_NONE:
1862 break;
1863 case DEFAULT_ORIGINATE_ZEBRA:
1864 zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_DELETE,
1865 zclient, AFI_IP6, ospf6->vrf_id);
1866 ospf6_asbr_redistribute_remove(DEFAULT_ROUTE, 0,
1867 (struct prefix *)&p, ospf6);
1868
1869 break;
1870 case DEFAULT_ORIGINATE_ALWAYS:
1871 ospf6_asbr_redistribute_remove(DEFAULT_ROUTE, 0,
1872 (struct prefix *)&p, ospf6);
1873 break;
1874 }
1875
1876 switch (originate) {
1877 case DEFAULT_ORIGINATE_NONE:
1878 break;
1879 case DEFAULT_ORIGINATE_ZEBRA:
1880 zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD,
1881 zclient, AFI_IP6, ospf6->vrf_id);
1882
1883 break;
1884 case DEFAULT_ORIGINATE_ALWAYS:
1885 ospf6_asbr_redistribute_add(DEFAULT_ROUTE, 0,
1886 (struct prefix *)&p, 0, &nexthop, 0,
1887 ospf6);
1888 break;
1889 }
1890 }
1891
1892 /* Default Route originate. */
1893 DEFPY (ospf6_default_route_originate,
1894 ospf6_default_route_originate_cmd,
1895 "default-information originate [{always$always|metric (0-16777214)$mval|metric-type (1-2)$mtype|route-map WORD$rtmap}]",
1896 "Control distribution of default route\n"
1897 "Distribute a default route\n"
1898 "Always advertise default route\n"
1899 "OSPFv3 default metric\n"
1900 "OSPFv3 metric\n"
1901 "OSPFv3 metric type for default routes\n"
1902 "Set OSPFv3 External Type 1/2 metrics\n"
1903 "Route map reference\n"
1904 "Pointer to route-map entries\n")
1905 {
1906 int default_originate = DEFAULT_ORIGINATE_ZEBRA;
1907 struct ospf6_redist *red;
1908 bool sameRtmap = false;
1909
1910 VTY_DECLVAR_CONTEXT(ospf6, ospf6);
1911
1912 int cur_originate = ospf6->default_originate;
1913
1914 red = ospf6_redist_add(ospf6, DEFAULT_ROUTE, 0);
1915
1916 if (always != NULL)
1917 default_originate = DEFAULT_ORIGINATE_ALWAYS;
1918
1919 if (mval_str == NULL)
1920 mval = -1;
1921
1922 if (mtype_str == NULL)
1923 mtype = -1;
1924
1925 /* To check if user is providing same route map */
1926 if ((!rtmap && !ROUTEMAP_NAME(red)) ||
1927 (rtmap && ROUTEMAP_NAME(red) &&
1928 (strcmp(rtmap, ROUTEMAP_NAME(red)) == 0)))
1929 sameRtmap = true;
1930
1931 /* Don't allow if the same lsa is already originated. */
1932 if ((sameRtmap) && (red->dmetric.type == mtype)
1933 && (red->dmetric.value == mval)
1934 && (cur_originate == default_originate))
1935 return CMD_SUCCESS;
1936
1937 /* Updating Metric details */
1938 red->dmetric.type = mtype;
1939 red->dmetric.value = mval;
1940
1941 /* updating route map details */
1942 if (rtmap)
1943 ospf6_asbr_routemap_set(red, rtmap);
1944 else
1945 ospf6_asbr_routemap_unset(red);
1946
1947 ospf6_redistribute_default_set(ospf6, default_originate);
1948 return CMD_SUCCESS;
1949 }
1950
1951 DEFPY (no_ospf6_default_information_originate,
1952 no_ospf6_default_information_originate_cmd,
1953 "no default-information originate [{always|metric (0-16777214)|metric-type (1-2)|route-map WORD}]",
1954 NO_STR
1955 "Control distribution of default information\n"
1956 "Distribute a default route\n"
1957 "Always advertise default route\n"
1958 "OSPFv3 default metric\n"
1959 "OSPFv3 metric\n"
1960 "OSPFv3 metric type for default routes\n"
1961 "Set OSPFv3 External Type 1/2 metrics\n"
1962 "Route map reference\n"
1963 "Pointer to route-map entries\n")
1964 {
1965 struct ospf6_redist *red;
1966
1967 VTY_DECLVAR_CONTEXT(ospf6, ospf6);
1968
1969 red = ospf6_redist_lookup(ospf6, DEFAULT_ROUTE, 0);
1970 if (!red)
1971 return CMD_SUCCESS;
1972
1973 ospf6_asbr_routemap_unset(red);
1974 ospf6_redist_del(ospf6, red, DEFAULT_ROUTE);
1975
1976 ospf6_redistribute_default_set(ospf6, DEFAULT_ORIGINATE_NONE);
1977 return CMD_SUCCESS;
1978 }
1979
1980 /* Routemap Functions */
1981 static enum route_map_cmd_result_t
1982 ospf6_routemap_rule_match_address_prefixlist(void *rule,
1983 const struct prefix *prefix,
1984
1985 void *object)
1986 {
1987 struct prefix_list *plist;
1988
1989 plist = prefix_list_lookup(AFI_IP6, (char *)rule);
1990 if (plist == NULL)
1991 return RMAP_NOMATCH;
1992
1993 return (prefix_list_apply(plist, prefix) == PREFIX_DENY ? RMAP_NOMATCH
1994 : RMAP_MATCH);
1995 }
1996
1997 static void *
1998 ospf6_routemap_rule_match_address_prefixlist_compile(const char *arg)
1999 {
2000 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
2001 }
2002
2003 static void ospf6_routemap_rule_match_address_prefixlist_free(void *rule)
2004 {
2005 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
2006 }
2007
2008 static const struct route_map_rule_cmd
2009 ospf6_routemap_rule_match_address_prefixlist_cmd = {
2010 "ipv6 address prefix-list",
2011 ospf6_routemap_rule_match_address_prefixlist,
2012 ospf6_routemap_rule_match_address_prefixlist_compile,
2013 ospf6_routemap_rule_match_address_prefixlist_free,
2014 };
2015
2016 /* `match interface IFNAME' */
2017 /* Match function should return 1 if match is success else return
2018 zero. */
2019 static enum route_map_cmd_result_t
2020 ospf6_routemap_rule_match_interface(void *rule, const struct prefix *prefix,
2021 void *object)
2022 {
2023 struct interface *ifp;
2024 struct ospf6_route *route;
2025 struct ospf6_external_info *ei;
2026
2027 route = object;
2028 ei = route->route_option;
2029 ifp = if_lookup_by_name((char *)rule, route->ospf6->vrf_id);
2030
2031 if (ifp != NULL && ei->ifindex == ifp->ifindex)
2032 return RMAP_MATCH;
2033
2034 return RMAP_NOMATCH;
2035 }
2036
2037 /* Route map `interface' match statement. `arg' should be
2038 interface name. */
2039 static void *ospf6_routemap_rule_match_interface_compile(const char *arg)
2040 {
2041 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
2042 }
2043
2044 /* Free route map's compiled `interface' value. */
2045 static void ospf6_routemap_rule_match_interface_free(void *rule)
2046 {
2047 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
2048 }
2049
2050 /* Route map commands for interface matching. */
2051 static const struct route_map_rule_cmd
2052 ospf6_routemap_rule_match_interface_cmd = {
2053 "interface",
2054 ospf6_routemap_rule_match_interface,
2055 ospf6_routemap_rule_match_interface_compile,
2056 ospf6_routemap_rule_match_interface_free
2057 };
2058
2059 /* Match function for matching route tags */
2060 static enum route_map_cmd_result_t
2061 ospf6_routemap_rule_match_tag(void *rule, const struct prefix *p, void *object)
2062 {
2063 route_tag_t *tag = rule;
2064 struct ospf6_route *route = object;
2065 struct ospf6_external_info *info = route->route_option;
2066
2067 if (info->tag == *tag)
2068 return RMAP_MATCH;
2069
2070 return RMAP_NOMATCH;
2071 }
2072
2073 static const struct route_map_rule_cmd
2074 ospf6_routemap_rule_match_tag_cmd = {
2075 "tag",
2076 ospf6_routemap_rule_match_tag,
2077 route_map_rule_tag_compile,
2078 route_map_rule_tag_free,
2079 };
2080
2081 static enum route_map_cmd_result_t
2082 ospf6_routemap_rule_set_metric_type(void *rule, const struct prefix *prefix,
2083 void *object)
2084 {
2085 char *metric_type = rule;
2086 struct ospf6_route *route = object;
2087
2088 if (strcmp(metric_type, "type-2") == 0)
2089 route->path.metric_type = 2;
2090 else
2091 route->path.metric_type = 1;
2092
2093 return RMAP_OKAY;
2094 }
2095
2096 static void *ospf6_routemap_rule_set_metric_type_compile(const char *arg)
2097 {
2098 if (strcmp(arg, "type-2") && strcmp(arg, "type-1"))
2099 return NULL;
2100 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
2101 }
2102
2103 static void ospf6_routemap_rule_set_metric_type_free(void *rule)
2104 {
2105 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
2106 }
2107
2108 static const struct route_map_rule_cmd
2109 ospf6_routemap_rule_set_metric_type_cmd = {
2110 "metric-type",
2111 ospf6_routemap_rule_set_metric_type,
2112 ospf6_routemap_rule_set_metric_type_compile,
2113 ospf6_routemap_rule_set_metric_type_free,
2114 };
2115
2116 static enum route_map_cmd_result_t
2117 ospf6_routemap_rule_set_metric(void *rule, const struct prefix *prefix,
2118 void *object)
2119 {
2120 char *metric = rule;
2121 struct ospf6_route *route = object;
2122
2123 route->path.cost = atoi(metric);
2124 return RMAP_OKAY;
2125 }
2126
2127 static void *ospf6_routemap_rule_set_metric_compile(const char *arg)
2128 {
2129 uint32_t metric;
2130 char *endp;
2131 metric = strtoul(arg, &endp, 0);
2132 if (metric > OSPF_LS_INFINITY || *endp != '\0')
2133 return NULL;
2134 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
2135 }
2136
2137 static void ospf6_routemap_rule_set_metric_free(void *rule)
2138 {
2139 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
2140 }
2141
2142 static const struct route_map_rule_cmd
2143 ospf6_routemap_rule_set_metric_cmd = {
2144 "metric",
2145 ospf6_routemap_rule_set_metric,
2146 ospf6_routemap_rule_set_metric_compile,
2147 ospf6_routemap_rule_set_metric_free,
2148 };
2149
2150 static enum route_map_cmd_result_t
2151 ospf6_routemap_rule_set_forwarding(void *rule, const struct prefix *prefix,
2152 void *object)
2153 {
2154 char *forwarding = rule;
2155 struct ospf6_route *route = object;
2156 struct ospf6_external_info *info = route->route_option;
2157
2158 if (inet_pton(AF_INET6, forwarding, &info->forwarding) != 1) {
2159 memset(&info->forwarding, 0, sizeof(struct in6_addr));
2160 return RMAP_ERROR;
2161 }
2162
2163 return RMAP_OKAY;
2164 }
2165
2166 static void *ospf6_routemap_rule_set_forwarding_compile(const char *arg)
2167 {
2168 struct in6_addr a;
2169 if (inet_pton(AF_INET6, arg, &a) != 1)
2170 return NULL;
2171 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
2172 }
2173
2174 static void ospf6_routemap_rule_set_forwarding_free(void *rule)
2175 {
2176 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
2177 }
2178
2179 static const struct route_map_rule_cmd
2180 ospf6_routemap_rule_set_forwarding_cmd = {
2181 "forwarding-address",
2182 ospf6_routemap_rule_set_forwarding,
2183 ospf6_routemap_rule_set_forwarding_compile,
2184 ospf6_routemap_rule_set_forwarding_free,
2185 };
2186
2187 static enum route_map_cmd_result_t
2188 ospf6_routemap_rule_set_tag(void *rule, const struct prefix *p, void *object)
2189 {
2190 route_tag_t *tag = rule;
2191 struct ospf6_route *route = object;
2192 struct ospf6_external_info *info = route->route_option;
2193
2194 info->tag = *tag;
2195 return RMAP_OKAY;
2196 }
2197
2198 static const struct route_map_rule_cmd ospf6_routemap_rule_set_tag_cmd = {
2199 "tag",
2200 ospf6_routemap_rule_set_tag,
2201 route_map_rule_tag_compile,
2202 route_map_rule_tag_free,
2203 };
2204
2205 /* add "set metric-type" */
2206 DEFUN_YANG (ospf6_routemap_set_metric_type, ospf6_routemap_set_metric_type_cmd,
2207 "set metric-type <type-1|type-2>",
2208 "Set value\n"
2209 "Type of metric\n"
2210 "OSPF6 external type 1 metric\n"
2211 "OSPF6 external type 2 metric\n")
2212 {
2213 char *ext = argv[2]->text;
2214
2215 const char *xpath =
2216 "./set-action[action='frr-ospf-route-map:metric-type']";
2217 char xpath_value[XPATH_MAXLEN];
2218
2219 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
2220 snprintf(xpath_value, sizeof(xpath_value),
2221 "%s/rmap-set-action/frr-ospf-route-map:metric-type", xpath);
2222 nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, ext);
2223 return nb_cli_apply_changes(vty, NULL);
2224 }
2225
2226 /* delete "set metric-type" */
2227 DEFUN_YANG (ospf6_routemap_no_set_metric_type, ospf6_routemap_no_set_metric_type_cmd,
2228 "no set metric-type [<type-1|type-2>]",
2229 NO_STR
2230 "Set value\n"
2231 "Type of metric\n"
2232 "OSPF6 external type 1 metric\n"
2233 "OSPF6 external type 2 metric\n")
2234 {
2235 const char *xpath =
2236 "./set-action[action='frr-ospf-route-map:metric-type']";
2237
2238 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
2239 return nb_cli_apply_changes(vty, NULL);
2240 }
2241
2242 /* add "set forwarding-address" */
2243 DEFUN_YANG (ospf6_routemap_set_forwarding, ospf6_routemap_set_forwarding_cmd,
2244 "set forwarding-address X:X::X:X",
2245 "Set value\n"
2246 "Forwarding Address\n"
2247 "IPv6 Address\n")
2248 {
2249 int idx_ipv6 = 2;
2250 const char *xpath =
2251 "./set-action[action='frr-ospf6-route-map:forwarding-address']";
2252 char xpath_value[XPATH_MAXLEN];
2253
2254 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
2255 snprintf(xpath_value, sizeof(xpath_value),
2256 "%s/rmap-set-action/frr-ospf6-route-map:ipv6-address", xpath);
2257 nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
2258 argv[idx_ipv6]->arg);
2259 return nb_cli_apply_changes(vty, NULL);
2260 }
2261
2262 /* delete "set forwarding-address" */
2263 DEFUN_YANG (ospf6_routemap_no_set_forwarding, ospf6_routemap_no_set_forwarding_cmd,
2264 "no set forwarding-address [X:X::X:X]",
2265 NO_STR
2266 "Set value\n"
2267 "Forwarding Address\n"
2268 "IPv6 Address\n")
2269 {
2270 const char *xpath =
2271 "./set-action[action='frr-ospf6-route-map:forwarding-address']";
2272
2273 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
2274 return nb_cli_apply_changes(vty, NULL);
2275 }
2276
2277 static void ospf6_routemap_init(void)
2278 {
2279 route_map_init();
2280
2281 route_map_add_hook(ospf6_asbr_routemap_update);
2282 route_map_delete_hook(ospf6_asbr_routemap_update);
2283 route_map_event_hook(ospf6_asbr_routemap_event);
2284
2285 route_map_set_metric_hook(generic_set_add);
2286 route_map_no_set_metric_hook(generic_set_delete);
2287
2288 route_map_set_tag_hook(generic_set_add);
2289 route_map_no_set_tag_hook(generic_set_delete);
2290
2291 route_map_match_tag_hook(generic_match_add);
2292 route_map_no_match_tag_hook(generic_match_delete);
2293
2294 route_map_match_ipv6_address_prefix_list_hook(generic_match_add);
2295 route_map_no_match_ipv6_address_prefix_list_hook(generic_match_delete);
2296
2297 route_map_match_interface_hook(generic_match_add);
2298 route_map_no_match_interface_hook(generic_match_delete);
2299
2300 route_map_install_match(
2301 &ospf6_routemap_rule_match_address_prefixlist_cmd);
2302 route_map_install_match(&ospf6_routemap_rule_match_interface_cmd);
2303 route_map_install_match(&ospf6_routemap_rule_match_tag_cmd);
2304
2305 route_map_install_set(&ospf6_routemap_rule_set_metric_type_cmd);
2306 route_map_install_set(&ospf6_routemap_rule_set_metric_cmd);
2307 route_map_install_set(&ospf6_routemap_rule_set_forwarding_cmd);
2308 route_map_install_set(&ospf6_routemap_rule_set_tag_cmd);
2309
2310 /* ASE Metric Type (e.g. Type-1/Type-2) */
2311 install_element(RMAP_NODE, &ospf6_routemap_set_metric_type_cmd);
2312 install_element(RMAP_NODE, &ospf6_routemap_no_set_metric_type_cmd);
2313
2314 /* ASE Metric */
2315 install_element(RMAP_NODE, &ospf6_routemap_set_forwarding_cmd);
2316 install_element(RMAP_NODE, &ospf6_routemap_no_set_forwarding_cmd);
2317 }
2318
2319
2320 /* Display functions */
2321 static char *ospf6_as_external_lsa_get_prefix_str(struct ospf6_lsa *lsa,
2322 char *buf, int buflen,
2323 int pos)
2324 {
2325 struct ospf6_as_external_lsa *external;
2326 struct in6_addr in6;
2327 int prefix_length = 0;
2328 char tbuf[16];
2329
2330 if (lsa) {
2331 external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
2332 lsa->header);
2333
2334 if (pos == 0) {
2335 ospf6_prefix_in6_addr(&in6, external,
2336 &external->prefix);
2337 prefix_length = external->prefix.prefix_length;
2338 } else {
2339 in6 = *((struct in6_addr
2340 *)((caddr_t)external
2341 + sizeof(struct
2342 ospf6_as_external_lsa)
2343 + OSPF6_PREFIX_SPACE(
2344 external->prefix
2345 .prefix_length)));
2346 }
2347 if (buf) {
2348 inet_ntop(AF_INET6, &in6, buf, buflen);
2349 if (prefix_length) {
2350 snprintf(tbuf, sizeof(tbuf), "/%d",
2351 prefix_length);
2352 strlcat(buf, tbuf, buflen);
2353 }
2354 }
2355 }
2356 return (buf);
2357 }
2358
2359 static int ospf6_as_external_lsa_show(struct vty *vty, struct ospf6_lsa *lsa,
2360 json_object *json_obj, bool use_json)
2361 {
2362 struct ospf6_as_external_lsa *external;
2363 char buf[64];
2364
2365 assert(lsa->header);
2366 external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
2367 lsa->header);
2368
2369 /* bits */
2370 snprintf(buf, sizeof(buf), "%c%c%c",
2371 (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_E) ? 'E'
2372 : '-'),
2373 (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F) ? 'F'
2374 : '-'),
2375 (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T) ? 'T'
2376 : '-'));
2377
2378 if (use_json) {
2379 json_object_string_add(json_obj, "bits", buf);
2380 json_object_int_add(json_obj, "metric",
2381 (unsigned long)OSPF6_ASBR_METRIC(external));
2382 ospf6_prefix_options_printbuf(external->prefix.prefix_options,
2383 buf, sizeof(buf));
2384 json_object_string_add(json_obj, "prefixOptions", buf);
2385 json_object_int_add(
2386 json_obj, "referenceLsType",
2387 ntohs(external->prefix.prefix_refer_lstype));
2388 json_object_string_add(json_obj, "prefix",
2389 ospf6_as_external_lsa_get_prefix_str(
2390 lsa, buf, sizeof(buf), 0));
2391
2392 /* Forwarding-Address */
2393 json_object_boolean_add(
2394 json_obj, "forwardingAddressPresent",
2395 CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F));
2396 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F))
2397 json_object_string_add(
2398 json_obj, "forwardingAddress",
2399 ospf6_as_external_lsa_get_prefix_str(
2400 lsa, buf, sizeof(buf), 1));
2401
2402 /* Tag */
2403 json_object_boolean_add(
2404 json_obj, "tagPresent",
2405 CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T));
2406 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T))
2407 json_object_int_add(json_obj, "tag",
2408 ospf6_as_external_lsa_get_tag(lsa));
2409 } else {
2410 vty_out(vty, " Bits: %s\n", buf);
2411 vty_out(vty, " Metric: %5lu\n",
2412 (unsigned long)OSPF6_ASBR_METRIC(external));
2413
2414 ospf6_prefix_options_printbuf(external->prefix.prefix_options,
2415 buf, sizeof(buf));
2416 vty_out(vty, " Prefix Options: %s\n", buf);
2417
2418 vty_out(vty, " Referenced LSType: %d\n",
2419 ntohs(external->prefix.prefix_refer_lstype));
2420
2421 vty_out(vty, " Prefix: %s\n",
2422 ospf6_as_external_lsa_get_prefix_str(lsa, buf,
2423 sizeof(buf), 0));
2424
2425 /* Forwarding-Address */
2426 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F)) {
2427 vty_out(vty, " Forwarding-Address: %s\n",
2428 ospf6_as_external_lsa_get_prefix_str(
2429 lsa, buf, sizeof(buf), 1));
2430 }
2431
2432 /* Tag */
2433 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T)) {
2434 vty_out(vty, " Tag: %" ROUTE_TAG_PRI "\n",
2435 ospf6_as_external_lsa_get_tag(lsa));
2436 }
2437 }
2438
2439 return 0;
2440 }
2441
2442 static void ospf6_asbr_external_route_show(struct vty *vty,
2443 struct ospf6_route *route,
2444 json_object *json_array,
2445 bool use_json)
2446 {
2447 struct ospf6_external_info *info = route->route_option;
2448 char prefix[PREFIX2STR_BUFFER], id[16], forwarding[64];
2449 uint32_t tmp_id;
2450 json_object *json_route;
2451 char route_type[2];
2452
2453 prefix2str(&route->prefix, prefix, sizeof(prefix));
2454 tmp_id = ntohl(info->id);
2455 inet_ntop(AF_INET, &tmp_id, id, sizeof(id));
2456 if (!IN6_IS_ADDR_UNSPECIFIED(&info->forwarding))
2457 inet_ntop(AF_INET6, &info->forwarding, forwarding,
2458 sizeof(forwarding));
2459 else
2460 snprintf(forwarding, sizeof(forwarding), ":: (ifindex %d)",
2461 ospf6_route_get_first_nh_index(route));
2462
2463 if (use_json) {
2464 json_route = json_object_new_object();
2465 snprintf(route_type, sizeof(route_type), "%c",
2466 zebra_route_char(info->type));
2467 json_object_string_add(json_route, "routeType", route_type);
2468 json_object_string_add(json_route, "destination", prefix);
2469 json_object_string_add(json_route, "id", id);
2470 json_object_int_add(json_route, "metricType",
2471 route->path.metric_type);
2472 json_object_int_add(
2473 json_route, "routeCost",
2474 (unsigned long)(route->path.metric_type == 2
2475 ? route->path.u.cost_e2
2476 : route->path.cost));
2477 json_object_string_add(json_route, "forwarding", forwarding);
2478
2479 json_object_array_add(json_array, json_route);
2480 } else
2481
2482 vty_out(vty, "%c %-32pFX %-15s type-%d %5lu %s\n",
2483 zebra_route_char(info->type), &route->prefix, id,
2484 route->path.metric_type,
2485 (unsigned long)(route->path.metric_type == 2
2486 ? route->path.u.cost_e2
2487 : route->path.cost),
2488 forwarding);
2489 }
2490
2491 DEFUN(show_ipv6_ospf6_redistribute, show_ipv6_ospf6_redistribute_cmd,
2492 "show ipv6 ospf6 [vrf <NAME|all>] redistribute [json]",
2493 SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR
2494 "All VRFs\n"
2495 "redistributing External information\n" JSON_STR)
2496 {
2497 struct ospf6_route *route;
2498 struct ospf6 *ospf6 = NULL;
2499 json_object *json = NULL;
2500 bool uj = use_json(argc, argv);
2501 struct listnode *node;
2502 const char *vrf_name = NULL;
2503 bool all_vrf = false;
2504 int idx_vrf = 0;
2505
2506 json_object *json_array_routes = NULL;
2507 json_object *json_array_redistribute = NULL;
2508
2509 OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
2510
2511 if (uj) {
2512 json = json_object_new_object();
2513 json_array_routes = json_object_new_array();
2514 json_array_redistribute = json_object_new_array();
2515 }
2516
2517 for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
2518 if (all_vrf
2519 || ((ospf6->name == NULL && vrf_name == NULL)
2520 || (ospf6->name && vrf_name
2521 && strcmp(ospf6->name, vrf_name) == 0))) {
2522 ospf6_redistribute_show_config(
2523 vty, ospf6, json_array_redistribute, json, uj);
2524
2525 for (route = ospf6_route_head(ospf6->external_table);
2526 route; route = ospf6_route_next(route)) {
2527 ospf6_asbr_external_route_show(
2528 vty, route, json_array_routes, uj);
2529 }
2530
2531 if (uj) {
2532 json_object_object_add(json, "routes",
2533 json_array_routes);
2534 vty_json(vty, json);
2535 }
2536
2537 if (!all_vrf)
2538 break;
2539 }
2540 }
2541
2542 OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6);
2543
2544 return CMD_SUCCESS;
2545 }
2546
2547 static struct ospf6_lsa_handler as_external_handler = {
2548 .lh_type = OSPF6_LSTYPE_AS_EXTERNAL,
2549 .lh_name = "AS-External",
2550 .lh_short_name = "ASE",
2551 .lh_show = ospf6_as_external_lsa_show,
2552 .lh_get_prefix_str = ospf6_as_external_lsa_get_prefix_str,
2553 .lh_debug = 0};
2554
2555 static struct ospf6_lsa_handler nssa_external_handler = {
2556 .lh_type = OSPF6_LSTYPE_TYPE_7,
2557 .lh_name = "NSSA",
2558 .lh_short_name = "Type7",
2559 .lh_show = ospf6_as_external_lsa_show,
2560 .lh_get_prefix_str = ospf6_as_external_lsa_get_prefix_str,
2561 .lh_debug = 0};
2562
2563 void ospf6_asbr_init(void)
2564 {
2565 ospf6_routemap_init();
2566
2567 ospf6_install_lsa_handler(&as_external_handler);
2568 ospf6_install_lsa_handler(&nssa_external_handler);
2569
2570 install_element(VIEW_NODE, &show_ipv6_ospf6_redistribute_cmd);
2571
2572 install_element(OSPF6_NODE, &ospf6_default_route_originate_cmd);
2573 install_element(OSPF6_NODE,
2574 &no_ospf6_default_information_originate_cmd);
2575 install_element(OSPF6_NODE, &ospf6_redistribute_cmd);
2576 install_element(OSPF6_NODE, &no_ospf6_redistribute_cmd);
2577 }
2578
2579 void ospf6_asbr_redistribute_disable(struct ospf6 *ospf6)
2580 {
2581 int type;
2582 struct ospf6_redist *red;
2583
2584 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
2585 red = ospf6_redist_lookup(ospf6, type, 0);
2586 if (!red)
2587 continue;
2588 if (type == ZEBRA_ROUTE_OSPF6)
2589 continue;
2590 ospf6_asbr_redistribute_unset(ospf6, red, type);
2591 ospf6_redist_del(ospf6, red, type);
2592 }
2593 red = ospf6_redist_lookup(ospf6, DEFAULT_ROUTE, 0);
2594 if (red) {
2595 ospf6_asbr_routemap_unset(red);
2596 ospf6_redist_del(ospf6, red, type);
2597 ospf6_redistribute_default_set(ospf6, DEFAULT_ORIGINATE_NONE);
2598 }
2599 }
2600
2601 void ospf6_asbr_redistribute_reset(struct ospf6 *ospf6)
2602 {
2603 int type;
2604 struct ospf6_redist *red;
2605 char buf[RMAP_NAME_MAXLEN];
2606
2607 for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) {
2608 buf[0] = '\0';
2609 if (type == ZEBRA_ROUTE_OSPF6)
2610 continue;
2611 red = ospf6_redist_lookup(ospf6, type, 0);
2612 if (!red)
2613 continue;
2614
2615 if (type == DEFAULT_ROUTE) {
2616 ospf6_redistribute_default_set(
2617 ospf6, ospf6->default_originate);
2618 continue;
2619 }
2620 if (ROUTEMAP_NAME(red))
2621 strlcpy(buf, ROUTEMAP_NAME(red), sizeof(buf));
2622
2623 ospf6_asbr_redistribute_unset(ospf6, red, type);
2624 if (buf[0])
2625 ospf6_asbr_routemap_set(red, buf);
2626 ospf6_asbr_redistribute_set(ospf6, type);
2627 }
2628 }
2629
2630 void ospf6_asbr_terminate(void)
2631 {
2632 /* Cleanup route maps */
2633 route_map_finish();
2634 }
2635
2636 DEFUN (debug_ospf6_asbr,
2637 debug_ospf6_asbr_cmd,
2638 "debug ospf6 asbr",
2639 DEBUG_STR
2640 OSPF6_STR
2641 "Debug OSPFv3 ASBR function\n"
2642 )
2643 {
2644 OSPF6_DEBUG_ASBR_ON();
2645 return CMD_SUCCESS;
2646 }
2647
2648 DEFUN (no_debug_ospf6_asbr,
2649 no_debug_ospf6_asbr_cmd,
2650 "no debug ospf6 asbr",
2651 NO_STR
2652 DEBUG_STR
2653 OSPF6_STR
2654 "Debug OSPFv3 ASBR function\n"
2655 )
2656 {
2657 OSPF6_DEBUG_ASBR_OFF();
2658 return CMD_SUCCESS;
2659 }
2660
2661 int config_write_ospf6_debug_asbr(struct vty *vty)
2662 {
2663 if (IS_OSPF6_DEBUG_ASBR)
2664 vty_out(vty, "debug ospf6 asbr\n");
2665 return 0;
2666 }
2667
2668 static void ospf6_default_originate_write(struct vty *vty, struct ospf6 *o)
2669 {
2670 struct ospf6_redist *red;
2671
2672 vty_out(vty, " default-information originate");
2673 if (o->default_originate == DEFAULT_ORIGINATE_ALWAYS)
2674 vty_out(vty, " always");
2675
2676 red = ospf6_redist_lookup(o, DEFAULT_ROUTE, 0);
2677 if (red == NULL) {
2678 vty_out(vty, "\n");
2679 return;
2680 }
2681
2682 if (red->dmetric.value >= 0)
2683 vty_out(vty, " metric %d", red->dmetric.value);
2684
2685 if (red->dmetric.type >= 0)
2686 vty_out(vty, " metric-type %d", red->dmetric.type);
2687
2688 if (ROUTEMAP_NAME(red))
2689 vty_out(vty, " route-map %s", ROUTEMAP_NAME(red));
2690
2691 vty_out(vty, "\n");
2692 }
2693
2694 int ospf6_distribute_config_write(struct vty *vty, struct ospf6 *o)
2695 {
2696 if (o == NULL)
2697 return 0;
2698
2699 /* Print default originate configuration. */
2700 if (o->default_originate != DEFAULT_ORIGINATE_NONE)
2701 ospf6_default_originate_write(vty, o);
2702
2703 return 0;
2704 }
2705
2706 void install_element_ospf6_debug_asbr(void)
2707 {
2708 install_element(ENABLE_NODE, &debug_ospf6_asbr_cmd);
2709 install_element(ENABLE_NODE, &no_debug_ospf6_asbr_cmd);
2710 install_element(CONFIG_NODE, &debug_ospf6_asbr_cmd);
2711 install_element(CONFIG_NODE, &no_debug_ospf6_asbr_cmd);
2712 }
2713
2714 /* ASBR Summarisation */
2715 void ospf6_fill_aggr_route_details(struct ospf6 *ospf6,
2716 struct ospf6_external_aggr_rt *aggr)
2717 {
2718 struct ospf6_route *rt_aggr = aggr->route;
2719 struct ospf6_external_info *ei_aggr = rt_aggr->route_option;
2720
2721 rt_aggr->prefix = aggr->p;
2722 ei_aggr->tag = aggr->tag;
2723 ei_aggr->type = 0;
2724 ei_aggr->id = aggr->id;
2725
2726 /* When metric is not configured, apply the default metric */
2727 rt_aggr->path.cost = ((aggr->metric == -1) ?
2728 DEFAULT_DEFAULT_METRIC
2729 : (unsigned int)(aggr->metric));
2730 rt_aggr->path.metric_type = aggr->mtype;
2731
2732 rt_aggr->path.origin.id = htonl(aggr->id);
2733 }
2734
2735 static void
2736 ospf6_summary_add_aggr_route_and_blackhole(struct ospf6 *ospf6,
2737 struct ospf6_external_aggr_rt *aggr)
2738 {
2739 struct ospf6_route *rt_aggr;
2740 struct ospf6_external_info *info;
2741
2742 /* Create summary route and save it. */
2743 rt_aggr = ospf6_route_create(ospf6);
2744 rt_aggr->type = OSPF6_DEST_TYPE_NETWORK;
2745 /* Needed to install route while calling zebra api */
2746 SET_FLAG(rt_aggr->flag, OSPF6_ROUTE_BEST);
2747
2748 info = XCALLOC(MTYPE_OSPF6_EXTERNAL_INFO, sizeof(*info));
2749 rt_aggr->route_option = info;
2750 aggr->route = rt_aggr;
2751
2752 /* Prepare the external_info for aggregator
2753 * Fill all the details which will get advertised
2754 */
2755 ospf6_fill_aggr_route_details(ospf6, aggr);
2756
2757 /* Add next-hop to Null interface. */
2758 ospf6_add_route_nexthop_blackhole(rt_aggr);
2759
2760 ospf6_zebra_route_update_add(rt_aggr, ospf6);
2761 }
2762
2763 static void ospf6_originate_new_aggr_lsa(struct ospf6 *ospf6,
2764 struct ospf6_external_aggr_rt *aggr)
2765 {
2766 struct prefix prefix_id;
2767 struct ospf6_lsa *lsa = NULL;
2768
2769 if (IS_OSPF6_DEBUG_AGGR)
2770 zlog_debug("%s: Originate new aggregate route(%pFX)", __func__,
2771 &aggr->p);
2772
2773 aggr->id = ospf6->external_id++;
2774
2775 if (IS_OSPF6_DEBUG_AGGR)
2776 zlog_debug(
2777 "Advertise AS-External Id:%pI4 prefix %pFX metric %u",
2778 &prefix_id.u.prefix4, &aggr->p, aggr->metric);
2779
2780 ospf6_summary_add_aggr_route_and_blackhole(ospf6, aggr);
2781
2782 /* Originate summary LSA */
2783 lsa = ospf6_originate_type5_type7_lsas(aggr->route, ospf6);
2784 if (lsa) {
2785 if (IS_OSPF6_DEBUG_AGGR)
2786 zlog_debug("%s: Set the origination bit for aggregator",
2787 __func__);
2788 SET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED);
2789 }
2790 }
2791
2792 static void
2793 ospf6_aggr_handle_advertise_change(struct ospf6 *ospf6,
2794 struct ospf6_external_aggr_rt *aggr)
2795 {
2796 /* Check if advertise option modified. */
2797 if (CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE)) {
2798 if (IS_OSPF6_DEBUG_AGGR)
2799 zlog_debug("%s: Don't originate the summary address,It is configured to not-advertise.",
2800 __func__);
2801 ospf6_asbr_summary_remove_lsa_and_route(ospf6, aggr);
2802
2803 return;
2804 }
2805
2806 /* There are no routes present under this aggregation config, hence
2807 * nothing to originate here
2808 */
2809 if (OSPF6_EXTERNAL_RT_COUNT(aggr) == 0) {
2810 if (IS_OSPF6_DEBUG_AGGR)
2811 zlog_debug("%s: No routes present under this aggregation",
2812 __func__);
2813 return;
2814 }
2815
2816 if (!CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED)) {
2817 if (IS_OSPF6_DEBUG_AGGR)
2818 zlog_debug("%s: Now it is advertisable",
2819 __func__);
2820
2821 ospf6_originate_new_aggr_lsa(ospf6, aggr);
2822
2823 return;
2824 }
2825 }
2826
2827 static void
2828 ospf6_originate_summary_lsa(struct ospf6 *ospf6,
2829 struct ospf6_external_aggr_rt *aggr,
2830 struct ospf6_route *rt)
2831 {
2832 struct ospf6_lsa *lsa = NULL, *aggr_lsa = NULL;
2833 struct ospf6_external_info *info = NULL;
2834 struct ospf6_external_aggr_rt *old_aggr;
2835 struct ospf6_as_external_lsa *external;
2836 struct ospf6_route *rt_aggr = NULL;
2837 route_tag_t tag = 0;
2838 unsigned int metric = 0;
2839 int mtype;
2840
2841 if (IS_OSPF6_DEBUG_AGGR)
2842 zlog_debug("%s: Prepare to originate Summary route(%pFX)",
2843 __func__, &aggr->p);
2844
2845 /* This case to handle when the overlapping aggregator address
2846 * is available. Best match will be considered.So need to delink
2847 * from old aggregator and link to the new aggr.
2848 */
2849 if (rt->aggr_route) {
2850 if (rt->aggr_route != aggr) {
2851 old_aggr = rt->aggr_route;
2852 ospf6_unlink_route_from_aggr(ospf6, old_aggr, rt);
2853 }
2854 }
2855
2856 /* Add the external route to hash table */
2857 ospf6_link_route_to_aggr(aggr, rt);
2858
2859 /* The key for ID field is a running number and not prefix */
2860 info = rt->route_option;
2861 assert(info);
2862 if (info->id)
2863 lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
2864 htonl(info->id), ospf6->router_id,
2865 ospf6->lsdb);
2866
2867 aggr_lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
2868 htonl(aggr->id), ospf6->router_id, ospf6->lsdb);
2869
2870 if (IS_OSPF6_DEBUG_AGGR)
2871 zlog_debug("%s: Aggr LSA ID: %d flags %x.",
2872 __func__, aggr->id, aggr->aggrflags);
2873 /* Don't originate external LSA,
2874 * If it is configured not to advertise.
2875 */
2876 if (CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE)) {
2877 /* If it is already originated as external LSA,
2878 * But, it is configured not to advertise then
2879 * flush the originated external lsa.
2880 */
2881 if (lsa) {
2882 if (IS_OSPF6_DEBUG_AGGR)
2883 zlog_debug("%s: Purge the external LSA %s.",
2884 __func__, lsa->name);
2885 ospf6_external_lsa_purge(ospf6, lsa);
2886 info->id = 0;
2887 rt->path.origin.id = 0;
2888 }
2889
2890 if (aggr_lsa) {
2891 if (IS_OSPF6_DEBUG_AGGR)
2892 zlog_debug("%s: Purge the aggr external LSA %s.",
2893 __func__, lsa->name);
2894 ospf6_asbr_summary_remove_lsa_and_route(ospf6, aggr);
2895 }
2896
2897 UNSET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED);
2898
2899 if (IS_OSPF6_DEBUG_AGGR)
2900 zlog_debug("%s: Don't originate the summary address,It is configured to not-advertise.",
2901 __func__);
2902 return;
2903 }
2904
2905 /* Summary route already originated,
2906 * So, Do nothing.
2907 */
2908 if (CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED)) {
2909 if (!aggr_lsa) {
2910 zlog_warn(
2911 "%s: Could not refresh/originate %pFX",
2912 __func__,
2913 &aggr->p);
2914 /* Remove the assert later */
2915 assert(aggr_lsa);
2916 return;
2917 }
2918
2919 external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END
2920 (aggr_lsa->header);
2921 metric = (unsigned long)OSPF6_ASBR_METRIC(external);
2922 tag = ospf6_as_external_lsa_get_tag(aggr_lsa);
2923 mtype = CHECK_FLAG(external->bits_metric,
2924 OSPF6_ASBR_BIT_E) ? 2 : 1;
2925
2926 /* Prepare the external_info for aggregator */
2927 ospf6_fill_aggr_route_details(ospf6, aggr);
2928 rt_aggr = aggr->route;
2929 /* If tag/metric/metric-type modified , then re-originate the
2930 * route with modified tag/metric/metric-type details.
2931 */
2932 if ((tag != aggr->tag)
2933 || (metric != (unsigned int)rt_aggr->path.cost)
2934 || (mtype != aggr->mtype)) {
2935
2936 if (IS_OSPF6_DEBUG_AGGR)
2937 zlog_debug(
2938 "%s: Routetag(old:%d new:%d)/Metric(o:%u,n:%u)/mtype(o:%d n:%d) modified,So refresh the summary route.(%pFX)",
2939 __func__, tag, aggr->tag,
2940 metric,
2941 aggr->metric,
2942 mtype, aggr->mtype,
2943 &aggr->p);
2944
2945 aggr_lsa = ospf6_originate_type5_type7_lsas(aggr->route,
2946 ospf6);
2947 if (aggr_lsa)
2948 SET_FLAG(aggr->aggrflags,
2949 OSPF6_EXTERNAL_AGGRT_ORIGINATED);
2950 }
2951
2952 return;
2953 }
2954
2955 /* If the external route prefix same as aggregate route
2956 * and if external route is already originated as TYPE-5
2957 * then just update the aggr info and remove the route info
2958 */
2959 if (lsa && prefix_same(&aggr->p, &rt->prefix)) {
2960 if (IS_OSPF6_DEBUG_AGGR)
2961 zlog_debug(
2962 "%s: Route prefix is same as aggr so no need to re-originate LSA(%pFX)",
2963 __PRETTY_FUNCTION__, &aggr->p);
2964
2965 aggr->id = info->id;
2966 info->id = 0;
2967 rt->path.origin.id = 0;
2968
2969 ospf6_summary_add_aggr_route_and_blackhole(ospf6, aggr);
2970
2971 SET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED);
2972
2973 return;
2974 }
2975
2976 ospf6_originate_new_aggr_lsa(ospf6, aggr);
2977 }
2978
2979 static void ospf6_aggr_handle_external_info(void *data)
2980 {
2981 struct ospf6_route *rt = (struct ospf6_route *)data;
2982 struct ospf6_external_aggr_rt *aggr = NULL;
2983 struct ospf6_lsa *lsa = NULL;
2984 struct ospf6_external_info *info;
2985 struct ospf6 *ospf6 = NULL;
2986
2987 rt->aggr_route = NULL;
2988
2989 rt->to_be_processed = true;
2990
2991 if (IS_OSPF6_DEBUG_ASBR || IS_OSPF6_DEBUG_ORIGINATE(AS_EXTERNAL))
2992 zlog_debug("%s: Handle external route for origination/refresh (%pFX)",
2993 __func__,
2994 &rt->prefix);
2995
2996 ospf6 = rt->ospf6;
2997 assert(ospf6);
2998
2999 aggr = ospf6_external_aggr_match(ospf6,
3000 &rt->prefix);
3001 if (aggr) {
3002 ospf6_originate_summary_lsa(ospf6, aggr, rt);
3003 return;
3004 }
3005
3006 info = rt->route_option;
3007 if (info->id) {
3008 lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
3009 htonl(info->id), ospf6->router_id,
3010 ospf6->lsdb);
3011 if (lsa) {
3012 if (IS_OSPF6_DEBUG_AGGR)
3013 zlog_debug("%s: LSA found, refresh it",
3014 __func__);
3015 THREAD_OFF(lsa->refresh);
3016 thread_add_event(master, ospf6_lsa_refresh, lsa, 0,
3017 &lsa->refresh);
3018 return;
3019 }
3020 }
3021
3022 info->id = ospf6->external_id++;
3023 rt->path.origin.id = htonl(info->id);
3024
3025 (void)ospf6_originate_type5_type7_lsas(rt, ospf6);
3026 }
3027
3028 static void
3029 ospf6_asbr_summary_config_delete(struct ospf6 *ospf6, struct route_node *rn)
3030 {
3031 struct ospf6_external_aggr_rt *aggr = rn->info;
3032
3033 if (IS_OSPF6_DEBUG_AGGR)
3034 zlog_debug("%s: Deleting Aggregate route (%pFX)",
3035 __func__,
3036 &aggr->p);
3037
3038 ospf6_asbr_summary_remove_lsa_and_route(ospf6, aggr);
3039
3040 rn->info = NULL;
3041 route_unlock_node(rn);
3042 }
3043
3044 static int
3045 ospf6_handle_external_aggr_modify(struct ospf6 *ospf6,
3046 struct ospf6_external_aggr_rt *aggr)
3047 {
3048 struct ospf6_lsa *lsa = NULL;
3049 struct ospf6_as_external_lsa *asel = NULL;
3050 struct ospf6_route *rt_aggr;
3051 unsigned int metric = 0;
3052 route_tag_t tag = 0;
3053 int mtype;
3054
3055 lsa = ospf6_lsdb_lookup(
3056 htons(OSPF6_LSTYPE_AS_EXTERNAL),
3057 htonl(aggr->id), ospf6->router_id,
3058 ospf6->lsdb);
3059 if (!lsa) {
3060 zlog_warn(
3061 "%s: Could not refresh/originate %pFX",
3062 __func__,
3063 &aggr->p);
3064
3065 return OSPF6_FAILURE;
3066 }
3067
3068 asel = (struct ospf6_as_external_lsa *)
3069 OSPF6_LSA_HEADER_END(lsa->header);
3070 metric = (unsigned long)OSPF6_ASBR_METRIC(asel);
3071 tag = ospf6_as_external_lsa_get_tag(lsa);
3072 mtype = CHECK_FLAG(asel->bits_metric,
3073 OSPF6_ASBR_BIT_E) ? 2 : 1;
3074
3075 /* Fill all the details for advertisement */
3076 ospf6_fill_aggr_route_details(ospf6, aggr);
3077 rt_aggr = aggr->route;
3078 /* If tag/metric/metric-type modified , then
3079 * re-originate the route with modified
3080 * tag/metric/metric-type details.
3081 */
3082 if ((tag != aggr->tag)
3083 || (metric
3084 != (unsigned int)rt_aggr->path.cost)
3085 || (mtype
3086 != aggr->mtype)) {
3087 if (IS_OSPF6_DEBUG_AGGR)
3088 zlog_debug(
3089 "%s: Changed tag(old:%d new:%d)/metric(o:%u n:%d)/mtype(o:%d n:%d),So refresh the summary route.(%pFX)",
3090 __func__, tag,
3091 aggr->tag,
3092 metric,
3093 (unsigned int)rt_aggr->path.cost,
3094 mtype, aggr->mtype,
3095 &aggr->p);
3096
3097 (void)ospf6_originate_type5_type7_lsas(
3098 aggr->route,
3099 ospf6);
3100 }
3101
3102 return OSPF6_SUCCESS;
3103 }
3104
3105 static void ospf6_handle_external_aggr_update(struct ospf6 *ospf6)
3106 {
3107 struct route_node *rn = NULL;
3108 int ret;
3109
3110 if (IS_OSPF6_DEBUG_AGGR)
3111 zlog_debug("%s: Process modified aggregators.", __func__);
3112
3113 for (rn = route_top(ospf6->rt_aggr_tbl); rn; rn = route_next(rn)) {
3114 struct ospf6_external_aggr_rt *aggr;
3115
3116 if (!rn->info)
3117 continue;
3118
3119 aggr = rn->info;
3120
3121 if (aggr->action == OSPF6_ROUTE_AGGR_DEL) {
3122 aggr->action = OSPF6_ROUTE_AGGR_NONE;
3123 ospf6_asbr_summary_config_delete(ospf6, rn);
3124
3125 if (OSPF6_EXTERNAL_RT_COUNT(aggr))
3126 hash_clean(aggr->match_extnl_hash,
3127 ospf6_aggr_handle_external_info);
3128
3129 hash_free(aggr->match_extnl_hash);
3130 XFREE(MTYPE_OSPF6_EXTERNAL_RT_AGGR, aggr);
3131
3132 } else if (aggr->action == OSPF6_ROUTE_AGGR_MODIFY) {
3133
3134 aggr->action = OSPF6_ROUTE_AGGR_NONE;
3135
3136 /* Check if tag/metric/metric-type modified */
3137 if (CHECK_FLAG(aggr->aggrflags,
3138 OSPF6_EXTERNAL_AGGRT_ORIGINATED)
3139 && !CHECK_FLAG(aggr->aggrflags,
3140 OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE)) {
3141
3142 ret = ospf6_handle_external_aggr_modify(ospf6,
3143 aggr);
3144 if (ret == OSPF6_FAILURE)
3145 continue;
3146 }
3147
3148 /* Advertise option modified ?
3149 * If so, handled it here.
3150 */
3151 ospf6_aggr_handle_advertise_change(ospf6, aggr);
3152 }
3153 }
3154 }
3155
3156 static void ospf6_aggr_unlink_external_info(void *data)
3157 {
3158 struct ospf6_route *rt = (struct ospf6_route *)data;
3159
3160 rt->aggr_route = NULL;
3161
3162 rt->to_be_processed = true;
3163 }
3164
3165 void ospf6_external_aggregator_free(struct ospf6_external_aggr_rt *aggr)
3166 {
3167 if (OSPF6_EXTERNAL_RT_COUNT(aggr))
3168 hash_clean(aggr->match_extnl_hash,
3169 ospf6_aggr_unlink_external_info);
3170
3171 if (IS_OSPF6_DEBUG_AGGR)
3172 zlog_debug("%s: Release the aggregator Address(%pFX)",
3173 __func__,
3174 &aggr->p);
3175
3176 hash_free(aggr->match_extnl_hash);
3177 aggr->match_extnl_hash = NULL;
3178
3179 XFREE(MTYPE_OSPF6_EXTERNAL_RT_AGGR, aggr);
3180 }
3181
3182 static void
3183 ospf6_delete_all_marked_aggregators(struct ospf6 *ospf6)
3184 {
3185 struct route_node *rn = NULL;
3186 struct ospf6_external_aggr_rt *aggr;
3187
3188 /* Loop through all the aggregators, Delete all aggregators
3189 * which are marked as DELETE. Set action to NONE for remaining
3190 * aggregators
3191 */
3192 for (rn = route_top(ospf6->rt_aggr_tbl); rn; rn = route_next(rn)) {
3193 if (!rn->info)
3194 continue;
3195
3196 aggr = rn->info;
3197
3198 if (aggr->action != OSPF6_ROUTE_AGGR_DEL) {
3199 aggr->action = OSPF6_ROUTE_AGGR_NONE;
3200 continue;
3201 }
3202 ospf6_asbr_summary_config_delete(ospf6, rn);
3203 ospf6_external_aggregator_free(aggr);
3204 }
3205 }
3206
3207 static void ospf6_handle_exnl_rt_after_aggr_del(struct ospf6 *ospf6,
3208 struct ospf6_route *rt)
3209 {
3210 struct ospf6_lsa *lsa;
3211
3212 /* Process only marked external routes.
3213 * These routes were part of a deleted
3214 * aggregator.So, originate now.
3215 */
3216 if (!rt->to_be_processed)
3217 return;
3218
3219 rt->to_be_processed = false;
3220
3221 lsa = ospf6_find_external_lsa(ospf6, &rt->prefix);
3222
3223 if (lsa) {
3224 THREAD_OFF(lsa->refresh);
3225 thread_add_event(master, ospf6_lsa_refresh, lsa, 0,
3226 &lsa->refresh);
3227 } else {
3228 if (IS_OSPF6_DEBUG_AGGR)
3229 zlog_debug("%s: Originate external route(%pFX)",
3230 __func__,
3231 &rt->prefix);
3232
3233 (void)ospf6_originate_type5_type7_lsas(rt, ospf6);
3234 }
3235 }
3236
3237 static void ospf6_handle_aggregated_exnl_rt(struct ospf6 *ospf6,
3238 struct ospf6_external_aggr_rt *aggr,
3239 struct ospf6_route *rt)
3240 {
3241 struct ospf6_lsa *lsa;
3242 struct ospf6_as_external_lsa *ext_lsa;
3243 struct ospf6_external_info *info;
3244
3245 /* Handling the case where the external route prefix
3246 * and aggegate prefix is same
3247 * If same don't flush the originated external LSA.
3248 */
3249 if (prefix_same(&aggr->p, &rt->prefix)) {
3250 if (IS_OSPF6_DEBUG_AGGR)
3251 zlog_debug("%s: External Route prefix same as Aggregator(%pFX), so don't flush.",
3252 __func__,
3253 &rt->prefix);
3254
3255 return;
3256 }
3257
3258 info = rt->route_option;
3259 assert(info);
3260
3261 lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
3262 htonl(info->id), ospf6->router_id, ospf6->lsdb);
3263 if (lsa) {
3264 ext_lsa = (struct ospf6_as_external_lsa
3265 *)((char *)(lsa->header)
3266 + sizeof(struct ospf6_lsa_header));
3267
3268 if (rt->prefix.prefixlen != ext_lsa->prefix.prefix_length)
3269 return;
3270
3271 ospf6_external_lsa_purge(ospf6, lsa);
3272
3273 /* Resetting the ID of route */
3274 rt->path.origin.id = 0;
3275 info->id = 0;
3276 }
3277 }
3278
3279 static void
3280 ospf6_handle_external_aggr_add(struct ospf6 *ospf6)
3281 {
3282 struct ospf6_route *rt = NULL;
3283 struct ospf6_external_info *ei = NULL;
3284 struct ospf6_external_aggr_rt *aggr;
3285
3286 /* Delete all the aggregators which are marked as
3287 * OSPF6_ROUTE_AGGR_DEL.
3288 */
3289 ospf6_delete_all_marked_aggregators(ospf6);
3290
3291 for (rt = ospf6_route_head(ospf6->external_table); rt;
3292 rt = ospf6_route_next(rt)) {
3293 ei = rt->route_option;
3294 if (ei == NULL)
3295 continue;
3296
3297 if (is_default_prefix(&rt->prefix))
3298 continue;
3299
3300 aggr = ospf6_external_aggr_match(ospf6,
3301 &rt->prefix);
3302
3303 /* If matching aggregator found, Add
3304 * the external route refrenace to the
3305 * aggregator and originate the aggr
3306 * route if it is advertisable.
3307 * flush the external LSA if it is
3308 * already originated for this external
3309 * prefix.
3310 */
3311 if (aggr) {
3312 ospf6_originate_summary_lsa(ospf6, aggr, rt);
3313
3314 /* All aggregated external rts
3315 * are handled here.
3316 */
3317 ospf6_handle_aggregated_exnl_rt(
3318 ospf6, aggr, rt);
3319 continue;
3320 }
3321
3322 /* External routes which are only out
3323 * of aggregation will be handled here.
3324 */
3325 ospf6_handle_exnl_rt_after_aggr_del(
3326 ospf6, rt);
3327 }
3328 }
3329
3330 static void ospf6_asbr_summary_process(struct thread *thread)
3331 {
3332 struct ospf6 *ospf6 = THREAD_ARG(thread);
3333 int operation = 0;
3334
3335 operation = ospf6->aggr_action;
3336
3337 if (IS_OSPF6_DEBUG_AGGR)
3338 zlog_debug("%s: operation:%d",
3339 __func__,
3340 operation);
3341
3342 switch (operation) {
3343 case OSPF6_ROUTE_AGGR_ADD:
3344 ospf6_handle_external_aggr_add(ospf6);
3345 break;
3346 case OSPF6_ROUTE_AGGR_DEL:
3347 case OSPF6_ROUTE_AGGR_MODIFY:
3348 ospf6_handle_external_aggr_update(ospf6);
3349 break;
3350 default:
3351 break;
3352 }
3353 }
3354
3355 static void
3356 ospf6_start_asbr_summary_delay_timer(struct ospf6 *ospf6,
3357 struct ospf6_external_aggr_rt *aggr,
3358 ospf6_aggr_action_t operation)
3359 {
3360 aggr->action = operation;
3361
3362 if (ospf6->t_external_aggr) {
3363 if (ospf6->aggr_action == OSPF6_ROUTE_AGGR_ADD) {
3364
3365 if (IS_OSPF6_DEBUG_AGGR)
3366 zlog_debug("%s: Not required to restart timer,set is already added.",
3367 __func__);
3368 return;
3369 }
3370
3371 if (operation == OSPF6_ROUTE_AGGR_ADD) {
3372 if (IS_OSPF6_DEBUG_AGGR)
3373 zlog_debug("%s, Restarting Aggregator delay timer.",
3374 __func__);
3375 THREAD_OFF(ospf6->t_external_aggr);
3376 }
3377 }
3378
3379 if (IS_OSPF6_DEBUG_AGGR)
3380 zlog_debug("%s: Start Aggregator delay timer %u(in seconds).",
3381 __func__, ospf6->aggr_delay_interval);
3382
3383 ospf6->aggr_action = operation;
3384 thread_add_timer(master,
3385 ospf6_asbr_summary_process,
3386 ospf6, ospf6->aggr_delay_interval,
3387 &ospf6->t_external_aggr);
3388 }
3389
3390 int ospf6_asbr_external_rt_advertise(struct ospf6 *ospf6,
3391 struct prefix *p)
3392 {
3393 struct route_node *rn;
3394 struct ospf6_external_aggr_rt *aggr;
3395
3396 rn = route_node_lookup(ospf6->rt_aggr_tbl, p);
3397 if (!rn)
3398 return OSPF6_INVALID;
3399
3400 aggr = rn->info;
3401
3402 route_unlock_node(rn);
3403
3404 if (!CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE))
3405 return OSPF6_INVALID;
3406
3407 UNSET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE);
3408
3409 if (!OSPF6_EXTERNAL_RT_COUNT(aggr))
3410 return OSPF6_SUCCESS;
3411
3412 ospf6_start_asbr_summary_delay_timer(ospf6, aggr,
3413 OSPF6_ROUTE_AGGR_MODIFY);
3414
3415 return OSPF6_SUCCESS;
3416 }
3417
3418 int ospf6_external_aggr_delay_timer_set(struct ospf6 *ospf6, uint16_t interval)
3419 {
3420 ospf6->aggr_delay_interval = interval;
3421
3422 return OSPF6_SUCCESS;
3423 }
3424
3425 static unsigned int ospf6_external_rt_hash_key(const void *data)
3426 {
3427 const struct ospf6_route *rt = data;
3428 unsigned int key = 0;
3429
3430 key = prefix_hash_key(&rt->prefix);
3431 return key;
3432 }
3433
3434 static bool ospf6_external_rt_hash_cmp(const void *d1, const void *d2)
3435 {
3436 const struct ospf6_route *rt1 = d1;
3437 const struct ospf6_route *rt2 = d2;
3438
3439 return prefix_same(&rt1->prefix, &rt2->prefix);
3440 }
3441
3442 static struct ospf6_external_aggr_rt *
3443 ospf6_external_aggr_new(struct prefix *p)
3444 {
3445 struct ospf6_external_aggr_rt *aggr;
3446
3447 aggr = XCALLOC(MTYPE_OSPF6_EXTERNAL_RT_AGGR,
3448 sizeof(struct ospf6_external_aggr_rt));
3449
3450 prefix_copy(&aggr->p, p);
3451 aggr->metric = -1;
3452 aggr->mtype = DEFAULT_METRIC_TYPE;
3453 aggr->match_extnl_hash = hash_create(ospf6_external_rt_hash_key,
3454 ospf6_external_rt_hash_cmp,
3455 "Ospf6 external route hash");
3456 return aggr;
3457 }
3458
3459 static void ospf6_external_aggr_add(struct ospf6 *ospf6,
3460 struct ospf6_external_aggr_rt *aggr)
3461 {
3462 struct route_node *rn;
3463
3464 if (IS_OSPF6_DEBUG_AGGR)
3465 zlog_debug("%s: Adding Aggregate route to Aggr table (%pFX)",
3466 __func__,
3467 &aggr->p);
3468
3469 rn = route_node_get(ospf6->rt_aggr_tbl, &aggr->p);
3470 if (rn->info)
3471 route_unlock_node(rn);
3472 else
3473 rn->info = aggr;
3474 }
3475
3476 int ospf6_asbr_external_rt_no_advertise(struct ospf6 *ospf6,
3477 struct prefix *p)
3478 {
3479 struct ospf6_external_aggr_rt *aggr;
3480 route_tag_t tag = 0;
3481
3482 aggr = ospf6_external_aggr_config_lookup(ospf6, p);
3483 if (aggr) {
3484 if (CHECK_FLAG(aggr->aggrflags,
3485 OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE))
3486 return OSPF6_SUCCESS;
3487
3488 SET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE);
3489
3490 aggr->tag = tag;
3491 aggr->metric = -1;
3492
3493 if (!OSPF6_EXTERNAL_RT_COUNT(aggr))
3494 return OSPF6_SUCCESS;
3495
3496 ospf6_start_asbr_summary_delay_timer(ospf6, aggr,
3497 OSPF6_ROUTE_AGGR_MODIFY);
3498 } else {
3499 aggr = ospf6_external_aggr_new(p);
3500
3501 if (!aggr)
3502 return OSPF6_FAILURE;
3503
3504 SET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE);
3505 ospf6_external_aggr_add(ospf6, aggr);
3506 ospf6_start_asbr_summary_delay_timer(ospf6, aggr,
3507 OSPF6_ROUTE_AGGR_ADD);
3508 }
3509
3510 return OSPF6_SUCCESS;
3511 }
3512
3513 struct ospf6_external_aggr_rt *
3514 ospf6_external_aggr_config_lookup(struct ospf6 *ospf6, struct prefix *p)
3515 {
3516 struct route_node *rn;
3517
3518 rn = route_node_lookup(ospf6->rt_aggr_tbl, p);
3519 if (rn) {
3520 route_unlock_node(rn);
3521 return rn->info;
3522 }
3523
3524 return NULL;
3525 }
3526
3527
3528 int ospf6_external_aggr_config_set(struct ospf6 *ospf6, struct prefix *p,
3529 route_tag_t tag, int metric, int mtype)
3530 {
3531 struct ospf6_external_aggr_rt *aggregator;
3532
3533 aggregator = ospf6_external_aggr_config_lookup(ospf6, p);
3534
3535 if (aggregator) {
3536 if (CHECK_FLAG(aggregator->aggrflags,
3537 OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE))
3538 UNSET_FLAG(aggregator->aggrflags,
3539 OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE);
3540 else if ((aggregator->tag == tag)
3541 && (aggregator->metric == metric)
3542 && (aggregator->mtype == mtype))
3543 return OSPF6_SUCCESS;
3544
3545 aggregator->tag = tag;
3546 aggregator->metric = metric;
3547 aggregator->mtype = mtype;
3548
3549 ospf6_start_asbr_summary_delay_timer(ospf6, aggregator,
3550 OSPF6_ROUTE_AGGR_MODIFY);
3551 } else {
3552 aggregator = ospf6_external_aggr_new(p);
3553 if (!aggregator)
3554 return OSPF6_FAILURE;
3555
3556 aggregator->tag = tag;
3557 aggregator->metric = metric;
3558 aggregator->mtype = mtype;
3559
3560 ospf6_external_aggr_add(ospf6, aggregator);
3561 ospf6_start_asbr_summary_delay_timer(ospf6, aggregator,
3562 OSPF6_ROUTE_AGGR_ADD);
3563 }
3564
3565 return OSPF6_SUCCESS;
3566 }
3567
3568 int ospf6_external_aggr_config_unset(struct ospf6 *ospf6,
3569 struct prefix *p)
3570 {
3571 struct route_node *rn;
3572 struct ospf6_external_aggr_rt *aggr;
3573
3574 rn = route_node_lookup(ospf6->rt_aggr_tbl, p);
3575 if (!rn)
3576 return OSPF6_INVALID;
3577
3578 aggr = rn->info;
3579
3580 route_unlock_node(rn);
3581
3582 if (!OSPF6_EXTERNAL_RT_COUNT(aggr)) {
3583 ospf6_asbr_summary_config_delete(ospf6, rn);
3584 ospf6_external_aggregator_free(aggr);
3585 return OSPF6_SUCCESS;
3586 }
3587
3588 ospf6_start_asbr_summary_delay_timer(ospf6, aggr,
3589 OSPF6_ROUTE_AGGR_DEL);
3590
3591 return OSPF6_SUCCESS;
3592 }
3593
3594 void ospf6_handle_external_lsa_origination(struct ospf6 *ospf6,
3595 struct ospf6_route *rt,
3596 struct prefix *p)
3597 {
3598
3599 struct ospf6_external_aggr_rt *aggr;
3600 struct ospf6_external_info *info;
3601 struct prefix prefix_id;
3602
3603 if (!is_default_prefix(p)) {
3604 aggr = ospf6_external_aggr_match(ospf6,
3605 p);
3606
3607 if (aggr) {
3608
3609 if (IS_OSPF6_DEBUG_AGGR)
3610 zlog_debug("%s: Send Aggregate LSA (%pFX)",
3611 __func__,
3612 &aggr->p);
3613
3614 ospf6_originate_summary_lsa(
3615 ospf6, aggr, rt);
3616
3617 /* Handling the case where the
3618 * external route prefix
3619 * and aggegate prefix is same
3620 * If same don't flush the
3621 * originated
3622 * external LSA.
3623 */
3624 ospf6_handle_aggregated_exnl_rt(
3625 ospf6, aggr, rt);
3626 return;
3627 }
3628 }
3629
3630 info = rt->route_option;
3631
3632 /* When the info->id = 0, it means it is being originated for the
3633 * first time.
3634 */
3635 if (!info->id) {
3636 info->id = ospf6->external_id++;
3637 } else {
3638 prefix_id.family = AF_INET;
3639 prefix_id.prefixlen = 32;
3640 prefix_id.u.prefix4.s_addr = htonl(info->id);
3641 }
3642
3643 rt->path.origin.id = htonl(info->id);
3644
3645 if (IS_OSPF6_DEBUG_ASBR) {
3646 zlog_debug("Advertise new AS-External Id:%pI4 prefix %pFX metric %u",
3647 &prefix_id.u.prefix4, p, rt->path.metric_type);
3648 }
3649
3650 ospf6_originate_type5_type7_lsas(rt, ospf6);
3651
3652 }
3653
3654 void ospf6_unset_all_aggr_flag(struct ospf6 *ospf6)
3655 {
3656 struct route_node *rn = NULL;
3657 struct ospf6_external_aggr_rt *aggr;
3658
3659 if (IS_OSPF6_DEBUG_AGGR)
3660 zlog_debug("Unset the origination bit for all aggregator");
3661
3662 /* Resetting the running external ID counter so that the origination
3663 * of external LSAs starts from the beginning 0.0.0.1
3664 */
3665 ospf6->external_id = OSPF6_EXT_INIT_LS_ID;
3666
3667 for (rn = route_top(ospf6->rt_aggr_tbl); rn; rn = route_next(rn)) {
3668 if (!rn->info)
3669 continue;
3670
3671 aggr = rn->info;
3672
3673 UNSET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED);
3674 }
3675 }