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