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