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