]> git.proxmox.com Git - mirror_frr.git/blame - ospf6d/ospf6_asbr.c
*: Convert a bunch of thread_XX to event_XX
[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"
cb37cb33 16#include "event.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
e6685141 183void ospf6_orig_as_external_lsa(struct event *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
e6685141 1068static void ospf6_asbr_routemap_update_timer(struct event *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
5f6eaa9b 1107 if (event_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
907a2395
DS
1113 event_add_timer_msec(master, ospf6_asbr_routemap_update_timer, ospf6,
1114 OSPF_MIN_LS_INTERVAL, &ospf6->t_distribute_update);
856ae1eb
CS
1115}
1116
ad500b22 1117void ospf6_asbr_routemap_update(const char *mapname)
508e53e2 1118{
d62a17ae 1119 int type;
beadc736 1120 struct listnode *node, *nnode;
1121 struct ospf6 *ospf6 = NULL;
a069482f 1122 struct ospf6_redist *red;
d62a17ae 1123
beadc736 1124 if (om6 == NULL)
d62a17ae 1125 return;
1126
beadc736 1127 for (ALL_LIST_ELEMENTS(om6->ospf6, node, nnode, ospf6)) {
1128 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
a069482f
K
1129 red = ospf6_redist_lookup(ospf6, type, 0);
1130 if (!red || (ROUTEMAP_NAME(red) == NULL))
96117716 1131 continue;
a069482f
K
1132 ROUTEMAP(red) =
1133 route_map_lookup_by_name(ROUTEMAP_NAME(red));
c600ce45 1134
a069482f
K
1135 if (mapname == NULL
1136 || strcmp(ROUTEMAP_NAME(red), mapname))
96117716 1137 continue;
a069482f 1138 if (ROUTEMAP(red)) {
96117716 1139 if (IS_OSPF6_DEBUG_ASBR)
1140 zlog_debug(
780d4bdd 1141 "%s: route-map %s update, reset redist %s",
96117716 1142 __func__,
1143 mapname,
1144 ZROUTE_NAME(
1145 type));
64957b27 1146
a069482f 1147 route_map_counter_increment(ROUTEMAP(red));
2f43e34d 1148 ospf6_asbr_distribute_list_update(ospf6, red);
96117716 1149 } else {
1150 /*
1151 * if the mapname matches a
1152 * route-map on ospf6 but the
1153 * map doesn't exist, it is
1154 * being deleted. flush and then
1155 * readvertise
1156 */
1157 if (IS_OSPF6_DEBUG_ASBR)
1158 zlog_debug(
780d4bdd 1159 "%s: route-map %s deleted, reset redist %s",
96117716 1160 __func__,
1161 mapname,
1162 ZROUTE_NAME(
1163 type));
a069482f
K
1164 ospf6_asbr_redistribute_unset(ospf6, red, type);
1165 ospf6_asbr_routemap_set(red, mapname);
2fdc4f8d 1166 ospf6_asbr_redistribute_set(ospf6, type);
c600ce45 1167 }
beadc736 1168 }
d62a17ae 1169 }
718e3744 1170}
1171
097b5973 1172static void ospf6_asbr_routemap_event(const char *name)
856ae1eb
CS
1173{
1174 int type;
beadc736 1175 struct listnode *node, *nnode;
1176 struct ospf6 *ospf6;
a069482f 1177 struct ospf6_redist *red;
856ae1eb 1178
beadc736 1179 if (om6 == NULL)
856ae1eb 1180 return;
beadc736 1181 for (ALL_LIST_ELEMENTS(om6->ospf6, node, nnode, ospf6)) {
1182 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
a069482f
K
1183 red = ospf6_redist_lookup(ospf6, type, 0);
1184 if (red && ROUTEMAP_NAME(red)
1185 && (strcmp(ROUTEMAP_NAME(red), name) == 0))
2f43e34d 1186 ospf6_asbr_distribute_list_update(ospf6, red);
856ae1eb
CS
1187 }
1188 }
1189}
1190
d62a17ae 1191int ospf6_asbr_is_asbr(struct ospf6 *o)
508e53e2 1192{
ad500b22 1193 return (o->external_table->count || IS_OSPF6_ASBR(o));
508e53e2 1194}
1195
a069482f
K
1196struct ospf6_redist *ospf6_redist_lookup(struct ospf6 *ospf6, int type,
1197 unsigned short instance)
1198{
1199 struct list *red_list;
1200 struct listnode *node;
1201 struct ospf6_redist *red;
1202
1203 red_list = ospf6->redist[type];
1204 if (!red_list)
1205 return (NULL);
1206
1207 for (ALL_LIST_ELEMENTS_RO(red_list, node, red))
1208 if (red->instance == instance)
1209 return red;
1210
1211 return NULL;
1212}
1213
1214static struct ospf6_redist *ospf6_redist_add(struct ospf6 *ospf6, int type,
1215 uint8_t instance)
1216{
1217 struct ospf6_redist *red;
1218
1219 red = ospf6_redist_lookup(ospf6, type, instance);
1220 if (red)
1221 return red;
1222
1223 if (!ospf6->redist[type])
1224 ospf6->redist[type] = list_new();
1225
1226 red = XCALLOC(MTYPE_OSPF6_REDISTRIBUTE, sizeof(struct ospf6_redist));
1227 red->instance = instance;
a5bc334b
YR
1228 red->dmetric.type = -1;
1229 red->dmetric.value = -1;
a069482f
K
1230 ROUTEMAP_NAME(red) = NULL;
1231 ROUTEMAP(red) = NULL;
1232
1233 listnode_add(ospf6->redist[type], red);
b8212e03 1234 ospf6->redistribute++;
a069482f
K
1235
1236 return red;
1237}
1238
1239static void ospf6_redist_del(struct ospf6 *ospf6, struct ospf6_redist *red,
1240 int type)
1241{
1242 if (red) {
1243 listnode_delete(ospf6->redist[type], red);
1244 if (!ospf6->redist[type]->count) {
1245 list_delete(&ospf6->redist[type]);
1246 }
1247 XFREE(MTYPE_OSPF6_REDISTRIBUTE, red);
b8212e03 1248 ospf6->redistribute--;
a069482f
K
1249 }
1250}
1251
ad500b22
K
1252/*Set the status of the ospf instance to ASBR based on the status parameter,
1253 * rechedule SPF calculation, originate router LSA*/
1254void ospf6_asbr_status_update(struct ospf6 *ospf6, int status)
1255{
1256 struct listnode *lnode, *lnnode;
1257 struct ospf6_area *oa;
1258
1259 zlog_info("ASBR[%s:Status:%d]: Update", ospf6->name, status);
1260
1261 if (status) {
1262 if (IS_OSPF6_ASBR(ospf6)) {
1263 zlog_info("ASBR[%s:Status:%d]: Already ASBR",
1264 ospf6->name, status);
1265 return;
1266 }
1267 SET_FLAG(ospf6->flag, OSPF6_FLAG_ASBR);
1268 } else {
1269 if (!IS_OSPF6_ASBR(ospf6)) {
1270 zlog_info("ASBR[%s:Status:%d]: Already non ASBR",
1271 ospf6->name, status);
1272 return;
1273 }
1274 UNSET_FLAG(ospf6->flag, OSPF6_FLAG_ASBR);
1275 }
1276
1277 /* Transition from/to status ASBR, schedule timer. */
1278 ospf6_spf_schedule(ospf6, OSPF6_SPF_FLAGS_ASBR_STATUS_CHANGE);
1279
1280 /* Reoriginate router LSA for all areas */
1281 for (ALL_LIST_ELEMENTS(ospf6->area_list, lnode, lnnode, oa))
1282 OSPF6_ROUTER_LSA_SCHEDULE(oa);
1283}
1284
2fdc4f8d 1285static void ospf6_asbr_redistribute_set(struct ospf6 *ospf6, int type)
718e3744 1286{
2fdc4f8d 1287 ospf6_zebra_redistribute(type, ospf6->vrf_id);
ad500b22 1288
d214b64a
MN
1289 ++ospf6->redist_count;
1290 ospf6_asbr_status_update(ospf6, ospf6->redist_count);
508e53e2 1291}
1292
a069482f
K
1293static void ospf6_asbr_redistribute_unset(struct ospf6 *ospf6,
1294 struct ospf6_redist *red, int type)
508e53e2 1295{
d62a17ae 1296 struct ospf6_route *route;
1297 struct ospf6_external_info *info;
beadc736 1298
a069482f 1299 ospf6_zebra_no_redistribute(type, ospf6->vrf_id);
508e53e2 1300
d62a17ae 1301 for (route = ospf6_route_head(ospf6->external_table); route;
1302 route = ospf6_route_next(route)) {
1303 info = route->route_option;
1304 if (info->type != type)
1305 continue;
718e3744 1306
beadc736 1307 ospf6_asbr_redistribute_remove(info->type, 0, &route->prefix,
1308 ospf6);
d62a17ae 1309 }
d9628728 1310
a069482f 1311 ospf6_asbr_routemap_unset(red);
d214b64a
MN
1312 --ospf6->redist_count;
1313 ospf6_asbr_status_update(ospf6, ospf6->redist_count);
508e53e2 1314}
718e3744 1315
ca1f4309 1316/* When an area is unstubified, flood all the external LSAs in the area */
d62a17ae 1317void ospf6_asbr_send_externals_to_area(struct ospf6_area *oa)
ca1f4309 1318{
2e37407f 1319 struct ospf6_lsa *lsa, *lsanext;
d62a17ae 1320
2e37407f 1321 for (ALL_LSDB(oa->ospf6->lsdb, lsa, lsanext)) {
d62a17ae 1322 if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL) {
ee6ccc96
MS
1323 if (IS_OSPF6_DEBUG_ASBR)
1324 zlog_debug("%s: Flooding AS-External LSA %s",
1325 __func__, lsa->name);
1326
d62a17ae 1327 ospf6_flood_area(NULL, lsa, oa);
1328 }
ca1f4309 1329 }
ca1f4309
DS
1330}
1331
bac66c5c 1332/* When an area is stubified, remove all the external LSAs in the area */
1333void ospf6_asbr_remove_externals_from_area(struct ospf6_area *oa)
1334{
1335 struct ospf6_lsa *lsa, *lsanext;
1336 struct listnode *node, *nnode;
1337 struct ospf6_area *area;
1338 struct ospf6 *ospf6 = oa->ospf6;
1f4a8543 1339 const struct route_node *iterend;
bac66c5c 1340
dd551b9d 1341 /* skip if router is in other non-stub/non-NSSA areas */
bac66c5c 1342 for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, area))
dd551b9d 1343 if (!IS_AREA_STUB(area) && !IS_AREA_NSSA(area))
bac66c5c 1344 return;
1345
1346 /* if router is only in a stub area then purge AS-External LSAs */
1f4a8543 1347 iterend = ospf6_lsdb_head(ospf6->lsdb, 0, 0, 0, &lsa);
1348 while (lsa != NULL) {
4ff390e7 1349 assert(lsa->lock > 1);
1f4a8543 1350 lsanext = ospf6_lsdb_next(iterend, lsa);
bac66c5c 1351 if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL)
1352 ospf6_lsdb_remove(lsa, ospf6->lsdb);
1f4a8543 1353 lsa = lsanext;
bac66c5c 1354 }
1355}
1356
4dc43886
MR
1357static struct ospf6_external_aggr_rt *
1358ospf6_external_aggr_match(struct ospf6 *ospf6, struct prefix *p)
1359{
1360 struct route_node *node;
1361
78982818
MR
1362 node = route_node_match(ospf6->rt_aggr_tbl, p);
1363 if (node == NULL)
1364 return NULL;
4dc43886 1365
78982818
MR
1366 if (IS_OSPF6_DEBUG_AGGR) {
1367 struct ospf6_external_aggr_rt *ag = node->info;
1368 zlog_debug("%s: Matching aggregator found.prefix: %pFX Aggregator %pFX",
1369 __func__,
1370 p,
1371 &ag->p);
4dc43886 1372 }
78982818
MR
1373
1374 route_unlock_node(node);
1375
1376 return node->info;
4dc43886
MR
1377}
1378
d62a17ae 1379void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
d7c0a89a
QY
1380 struct prefix *prefix,
1381 unsigned int nexthop_num,
6861a5e4
RW
1382 const struct in6_addr *nexthop,
1383 route_tag_t tag, struct ospf6 *ospf6)
508e53e2 1384{
b68885f9 1385 route_map_result_t ret;
d62a17ae 1386 struct ospf6_route troute;
1387 struct ospf6_external_info tinfo;
1388 struct ospf6_route *route, *match;
1389 struct ospf6_external_info *info;
a069482f
K
1390 struct ospf6_redist *red;
1391
1392 red = ospf6_redist_lookup(ospf6, type, 0);
1393
1394 if (!red)
1395 return;
d62a17ae 1396
b19502d3
YR
1397 if ((type != DEFAULT_ROUTE)
1398 && !ospf6_zebra_is_redistribute(type, ospf6->vrf_id))
d62a17ae 1399 return;
1400
6e38a9ec
VJ
1401 memset(&troute, 0, sizeof(troute));
1402 memset(&tinfo, 0, sizeof(tinfo));
1403
2dbe669b 1404 if (IS_OSPF6_DEBUG_ASBR)
210429c7
RW
1405 zlog_debug("Redistribute %pFX (%s)", prefix,
1406 type == DEFAULT_ROUTE
1407 ? "default-information-originate"
1408 : ZROUTE_NAME(type));
d62a17ae 1409
1410 /* if route-map was specified but not found, do not advertise */
a069482f
K
1411 if (ROUTEMAP_NAME(red)) {
1412 if (ROUTEMAP(red) == NULL)
d62a17ae 1413 ospf6_asbr_routemap_update(NULL);
a069482f 1414 if (ROUTEMAP(red) == NULL) {
d62a17ae 1415 zlog_warn(
1416 "route-map \"%s\" not found, suppress redistributing",
a069482f 1417 ROUTEMAP_NAME(red));
d62a17ae 1418 return;
1419 }
1420 }
1421
1422 /* apply route-map */
a069482f 1423 if (ROUTEMAP(red)) {
d62a17ae 1424 troute.route_option = &tinfo;
68618ebc 1425 troute.ospf6 = ospf6;
d62a17ae 1426 tinfo.ifindex = ifindex;
1427 tinfo.tag = tag;
1428
a069482f 1429 ret = route_map_apply(ROUTEMAP(red), prefix, &troute);
d62a17ae 1430 if (ret == RMAP_DENYMATCH) {
1431 if (IS_OSPF6_DEBUG_ASBR)
1432 zlog_debug("Denied by route-map \"%s\"",
a069482f 1433 ROUTEMAP_NAME(red));
beadc736 1434 ospf6_asbr_redistribute_remove(type, ifindex, prefix,
1435 ospf6);
d62a17ae 1436 return;
1437 }
1438 }
1439
1440 match = ospf6_route_lookup(prefix, ospf6->external_table);
1441 if (match) {
1442 info = match->route_option;
d62a17ae 1443 /* copy result of route-map */
a069482f 1444 if (ROUTEMAP(red)) {
d62a17ae 1445 if (troute.path.metric_type)
1446 match->path.metric_type =
1447 troute.path.metric_type;
f84504e6
YR
1448 else
1449 match->path.metric_type =
1450 metric_type(ospf6, type, 0);
d62a17ae 1451 if (troute.path.cost)
1452 match->path.cost = troute.path.cost;
f84504e6
YR
1453 else
1454 match->path.cost = metric_value(ospf6, type, 0);
4dc43886 1455
d62a17ae 1456 if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo.forwarding))
1457 memcpy(&info->forwarding, &tinfo.forwarding,
1458 sizeof(struct in6_addr));
1459 info->tag = tinfo.tag;
1460 } else {
c4122b55
YR
1461 /* If there is no route-map, simply update the tag and
1462 * metric fields
1463 */
1464 match->path.metric_type = metric_type(ospf6, type, 0);
1465 match->path.cost = metric_value(ospf6, type, 0);
d62a17ae 1466 info->tag = tag;
1467 }
1468
1469 info->type = type;
1470
73d9d322 1471 if (nexthop_num && nexthop) {
d62a17ae 1472 ospf6_route_add_nexthop(match, ifindex, nexthop);
73d9d322
RW
1473 if (!IN6_IS_ADDR_UNSPECIFIED(nexthop)
1474 && !IN6_IS_ADDR_LINKLOCAL(nexthop))
1475 memcpy(&info->forwarding, nexthop,
1476 sizeof(struct in6_addr));
1477 } else
d62a17ae 1478 ospf6_route_add_nexthop(match, ifindex, NULL);
1479
d62a17ae 1480 match->path.origin.id = htonl(info->id);
4dc43886
MR
1481 ospf6_handle_external_lsa_origination(ospf6, match, prefix);
1482
b8212e03 1483 ospf6_asbr_status_update(ospf6, ospf6->redistribute);
ad500b22 1484
d62a17ae 1485 return;
1486 }
1487
1488 /* create new entry */
22813fdb 1489 route = ospf6_route_create(ospf6);
d62a17ae 1490 route->type = OSPF6_DEST_TYPE_NETWORK;
0f844365 1491 prefix_copy(&route->prefix, prefix);
d62a17ae 1492
1493 info = (struct ospf6_external_info *)XCALLOC(
1494 MTYPE_OSPF6_EXTERNAL_INFO, sizeof(struct ospf6_external_info));
1495 route->route_option = info;
d62a17ae 1496
1497 /* copy result of route-map */
a069482f 1498 if (ROUTEMAP(red)) {
d62a17ae 1499 if (troute.path.metric_type)
1500 route->path.metric_type = troute.path.metric_type;
f84504e6
YR
1501 else
1502 route->path.metric_type = metric_type(ospf6, type, 0);
d62a17ae 1503 if (troute.path.cost)
1504 route->path.cost = troute.path.cost;
f84504e6
YR
1505 else
1506 route->path.cost = metric_value(ospf6, type, 0);
d62a17ae 1507 if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo.forwarding))
1508 memcpy(&info->forwarding, &tinfo.forwarding,
1509 sizeof(struct in6_addr));
1510 info->tag = tinfo.tag;
1511 } else {
c4122b55
YR
1512 /* If there is no route-map, simply update the tag and metric
1513 * fields
1514 */
1515 route->path.metric_type = metric_type(ospf6, type, 0);
1516 route->path.cost = metric_value(ospf6, type, 0);
d62a17ae 1517 info->tag = tag;
1518 }
1519
1520 info->type = type;
73d9d322 1521 if (nexthop_num && nexthop) {
d62a17ae 1522 ospf6_route_add_nexthop(route, ifindex, nexthop);
73d9d322
RW
1523 if (!IN6_IS_ADDR_UNSPECIFIED(nexthop)
1524 && !IN6_IS_ADDR_LINKLOCAL(nexthop))
1525 memcpy(&info->forwarding, nexthop,
1526 sizeof(struct in6_addr));
1527 } else
d62a17ae 1528 ospf6_route_add_nexthop(route, ifindex, NULL);
1529
e285b70d 1530 route = ospf6_route_add(route, ospf6->external_table);
4dc43886 1531 ospf6_handle_external_lsa_origination(ospf6, route, prefix);
d62a17ae 1532
b8212e03 1533 ospf6_asbr_status_update(ospf6, ospf6->redistribute);
4dc43886 1534
4dc43886
MR
1535}
1536
1537static void ospf6_asbr_external_lsa_remove_by_id(struct ospf6 *ospf6,
1538 uint32_t id)
1539{
1540 struct ospf6_lsa *lsa;
1541
1542 lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
1543 htonl(id), ospf6->router_id, ospf6->lsdb);
1544 if (!lsa)
1545 return;
1546
1547 ospf6_external_lsa_purge(ospf6, lsa);
1548
4dc43886
MR
1549}
1550
1551static void
1552ospf6_link_route_to_aggr(struct ospf6_external_aggr_rt *aggr,
1553 struct ospf6_route *rt)
1554{
8e3aae66 1555 (void)hash_get(aggr->match_extnl_hash, rt, hash_alloc_intern);
4dc43886
MR
1556 rt->aggr_route = aggr;
1557}
1558
c405b00f
MR
1559static void
1560ospf6_asbr_summary_remove_lsa_and_route(struct ospf6 *ospf6,
1561 struct ospf6_external_aggr_rt *aggr)
1562{
1563
1564 /* Send a Max age LSA if it is already originated.*/
1565 if (!CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED))
1566 return;
1567
1568 if (IS_OSPF6_DEBUG_AGGR)
1569 zlog_debug("%s: Flushing Aggregate route (%pFX)",
1570 __func__,
1571 &aggr->p);
1572
1573 ospf6_asbr_external_lsa_remove_by_id(ospf6, aggr->id);
1574
1575 if (aggr->route) {
1576 if (IS_OSPF6_DEBUG_AGGR)
1577 zlog_debug(
1578 "%s: Remove the blackhole route",
1579 __func__);
a28474d3 1580
c405b00f 1581 ospf6_zebra_route_update_remove(aggr->route, ospf6);
a28474d3
MN
1582 if (aggr->route->route_option)
1583 XFREE(MTYPE_OSPF6_EXTERNAL_INFO,
1584 aggr->route->route_option);
c405b00f
MR
1585 ospf6_route_delete(aggr->route);
1586 aggr->route = NULL;
ad500b22 1587 }
c405b00f
MR
1588
1589 aggr->id = 0;
1590 /* Unset the Origination flag */
1591 UNSET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED);
1592}
1593
4dc43886 1594static void
c3a70f65
MR
1595ospf6_unlink_route_from_aggr(struct ospf6 *ospf6,
1596 struct ospf6_external_aggr_rt *aggr,
1597 struct ospf6_route *rt)
4dc43886
MR
1598{
1599 if (IS_OSPF6_DEBUG_AGGR)
1600 zlog_debug("%s: Unlinking external route(%pFX) from aggregator(%pFX), external route count:%ld",
1601 __func__,
1602 &rt->prefix,
1603 &aggr->p,
1604 OSPF6_EXTERNAL_RT_COUNT(aggr));
1605
1606 hash_release(aggr->match_extnl_hash, rt);
1607 rt->aggr_route = NULL;
1608
1609 /* Flush the aggregate route if matching
1610 * external route count becomes zero.
1611 */
c405b00f
MR
1612 if (!OSPF6_EXTERNAL_RT_COUNT(aggr))
1613 ospf6_asbr_summary_remove_lsa_and_route(ospf6, aggr);
718e3744 1614}
1615
d62a17ae 1616void ospf6_asbr_redistribute_remove(int type, ifindex_t ifindex,
beadc736 1617 struct prefix *prefix, struct ospf6 *ospf6)
718e3744 1618{
d62a17ae 1619 struct ospf6_route *match;
1620 struct ospf6_external_info *info = NULL;
d62a17ae 1621
1622 match = ospf6_route_lookup(prefix, ospf6->external_table);
1623 if (match == NULL) {
2dbe669b
DA
1624 if (IS_OSPF6_DEBUG_ASBR)
1625 zlog_debug("No such route %pFX to withdraw", prefix);
d62a17ae 1626 return;
1627 }
1628
1629 info = match->route_option;
1630 assert(info);
1631
1632 if (info->type != type) {
2dbe669b
DA
1633 if (IS_OSPF6_DEBUG_ASBR)
1634 zlog_debug("Original protocol mismatch: %pFX", prefix);
d62a17ae 1635 return;
1636 }
1637
4dc43886
MR
1638 /* This means aggregation on this route was not done, hence remove LSA
1639 * if any originated for this prefix
1640 */
1641 if (!match->aggr_route)
1642 ospf6_asbr_external_lsa_remove_by_id(ospf6, info->id);
1643 else
1644 ospf6_unlink_route_from_aggr(ospf6, match->aggr_route, match);
d62a17ae 1645
c3a70f65
MR
1646 if (IS_OSPF6_DEBUG_ASBR)
1647 zlog_debug("Removing route from external table %pFX",
1648 prefix);
d62a17ae 1649
e285b70d 1650 ospf6_route_remove(match, ospf6->external_table);
d62a17ae 1651 XFREE(MTYPE_OSPF6_EXTERNAL_INFO, info);
1652
b8212e03 1653 ospf6_asbr_status_update(ospf6, ospf6->redistribute);
718e3744 1654}
1655
476e9575 1656DEFPY (ospf6_redistribute,
508e53e2 1657 ospf6_redistribute_cmd,
70dd370f 1658 "redistribute " FRR_REDIST_STR_OSPF6D "[{metric (0-16777214)|metric-type (1-2)$metric_type|route-map RMAP_NAME$rmap_str}]",
508e53e2 1659 "Redistribute\n"
ab0181ee 1660 FRR_REDIST_HELP_STR_OSPF6D
476e9575
RW
1661 "Metric for redistributed routes\n"
1662 "OSPF default metric\n"
1663 "OSPF exterior metric type for redistributed routes\n"
1664 "Set OSPF External Type 1/2 metrics\n"
508e53e2 1665 "Route map reference\n"
e52702f2 1666 "Route map name\n")
508e53e2 1667{
d62a17ae 1668 int type;
a069482f 1669 struct ospf6_redist *red;
476e9575
RW
1670 int idx_protocol = 1;
1671 char *proto = argv[idx_protocol]->text;
d62a17ae 1672
beadc736 1673 VTY_DECLVAR_CONTEXT(ospf6, ospf6);
c5d28568 1674
d62a17ae 1675 type = proto_redistnum(AFI_IP6, proto);
1676 if (type < 0)
1677 return CMD_WARNING_CONFIG_FAILED;
1678
476e9575
RW
1679 if (!metric_str)
1680 metric = -1;
1681 if (!metric_type_str)
1682 metric_type = -1;
1683
bf84c96d 1684 red = ospf6_redist_lookup(ospf6, type, 0);
058c4c78 1685 if (!red) {
bf84c96d 1686 red = ospf6_redist_add(ospf6, type, 0);
058c4c78 1687 } else {
476e9575
RW
1688 /* Check if nothing has changed. */
1689 if (red->dmetric.value == metric
1690 && red->dmetric.type == metric_type
1691 && ((!ROUTEMAP_NAME(red) && !rmap_str)
1692 || (ROUTEMAP_NAME(red) && rmap_str
1693 && strmatch(ROUTEMAP_NAME(red), rmap_str))))
058c4c78
MR
1694 return CMD_SUCCESS;
1695
bf84c96d 1696 ospf6_asbr_redistribute_unset(ospf6, red, type);
058c4c78 1697 }
a069482f 1698
476e9575
RW
1699 red->dmetric.value = metric;
1700 red->dmetric.type = metric_type;
1701 if (rmap_str)
1702 ospf6_asbr_routemap_set(red, rmap_str);
1703 else
1704 ospf6_asbr_routemap_unset(red);
2fdc4f8d 1705 ospf6_asbr_redistribute_set(ospf6, type);
a069482f 1706
d62a17ae 1707 return CMD_SUCCESS;
508e53e2 1708}
1709
1710DEFUN (no_ospf6_redistribute,
1711 no_ospf6_redistribute_cmd,
70dd370f 1712 "no redistribute " FRR_REDIST_STR_OSPF6D "[{metric (0-16777214)|metric-type (1-2)|route-map RMAP_NAME}]",
508e53e2 1713 NO_STR
1714 "Redistribute\n"
ab0181ee 1715 FRR_REDIST_HELP_STR_OSPF6D
476e9575
RW
1716 "Metric for redistributed routes\n"
1717 "OSPF default metric\n"
1718 "OSPF exterior metric type for redistributed routes\n"
1719 "Set OSPF External Type 1/2 metrics\n"
1d68dbfe
DW
1720 "Route map reference\n"
1721 "Route map name\n")
508e53e2 1722{
d62a17ae 1723 int type;
a069482f 1724 struct ospf6_redist *red;
476e9575
RW
1725 int idx_protocol = 2;
1726 char *proto = argv[idx_protocol]->text;
e0ca5fde 1727
beadc736 1728 VTY_DECLVAR_CONTEXT(ospf6, ospf6);
1729
d62a17ae 1730 type = proto_redistnum(AFI_IP6, proto);
1731 if (type < 0)
1732 return CMD_WARNING_CONFIG_FAILED;
e26bbeba 1733
a069482f
K
1734 red = ospf6_redist_lookup(ospf6, type, 0);
1735 if (!red)
1736 return CMD_SUCCESS;
1737
1738 ospf6_asbr_redistribute_unset(ospf6, red, type);
1739 ospf6_redist_del(ospf6, red, type);
e26bbeba 1740
d62a17ae 1741 return CMD_SUCCESS;
508e53e2 1742}
718e3744 1743
beadc736 1744int ospf6_redistribute_config_write(struct vty *vty, struct ospf6 *ospf6)
508e53e2 1745{
d62a17ae 1746 int type;
a069482f 1747 struct ospf6_redist *red;
d62a17ae 1748
1749 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
a069482f
K
1750 red = ospf6_redist_lookup(ospf6, type, 0);
1751 if (!red)
d62a17ae 1752 continue;
a069482f 1753 if (type == ZEBRA_ROUTE_OSPF6)
d62a17ae 1754 continue;
1755
476e9575
RW
1756 vty_out(vty, " redistribute %s", ZROUTE_NAME(type));
1757 if (red->dmetric.value >= 0)
1758 vty_out(vty, " metric %d", red->dmetric.value);
16727fd7 1759 if (red->dmetric.type == 1)
476e9575 1760 vty_out(vty, " metric-type 1");
a069482f 1761 if (ROUTEMAP_NAME(red))
476e9575
RW
1762 vty_out(vty, " route-map %s", ROUTEMAP_NAME(red));
1763 vty_out(vty, "\n");
d62a17ae 1764 }
1765
1766 return 0;
718e3744 1767}
1768
dd726234 1769static void ospf6_redistribute_show_config(struct vty *vty, struct ospf6 *ospf6,
1770 json_object *json_array,
1771 json_object *json, bool use_json)
718e3744 1772{
d62a17ae 1773 int type;
1774 int nroute[ZEBRA_ROUTE_MAX];
1775 int total;
1776 struct ospf6_route *route;
1777 struct ospf6_external_info *info;
dd726234 1778 json_object *json_route;
a069482f 1779 struct ospf6_redist *red;
d62a17ae 1780
1781 total = 0;
8f17f6eb 1782 memset(nroute, 0, sizeof(nroute));
d62a17ae 1783 for (route = ospf6_route_head(ospf6->external_table); route;
1784 route = ospf6_route_next(route)) {
1785 info = route->route_option;
1786 nroute[info->type]++;
1787 total++;
1788 }
718e3744 1789
8f17f6eb 1790 if (!use_json)
dd726234 1791 vty_out(vty, "Redistributing External Routes from:\n");
1792
d62a17ae 1793 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
8f17f6eb 1794
a069482f
K
1795 red = ospf6_redist_lookup(ospf6, type, 0);
1796
1797 if (!red)
d62a17ae 1798 continue;
a069482f 1799 if (type == ZEBRA_ROUTE_OSPF6)
d62a17ae 1800 continue;
1801
dd726234 1802 if (use_json) {
8f17f6eb 1803 json_route = json_object_new_object();
dd726234 1804 json_object_string_add(json_route, "routeType",
1805 ZROUTE_NAME(type));
1806 json_object_int_add(json_route, "numberOfRoutes",
1807 nroute[type]);
1808 json_object_boolean_add(json_route,
1809 "routeMapNamePresent",
a069482f 1810 ROUTEMAP_NAME(red));
dd726234 1811 }
1812
a069482f 1813 if (ROUTEMAP_NAME(red)) {
dd726234 1814 if (use_json) {
1815 json_object_string_add(json_route,
1816 "routeMapName",
a069482f 1817 ROUTEMAP_NAME(red));
dd726234 1818 json_object_boolean_add(json_route,
1819 "routeMapFound",
a069482f 1820 ROUTEMAP(red));
dd726234 1821 } else
1822 vty_out(vty,
1823 " %d: %s with route-map \"%s\"%s\n",
1824 nroute[type], ZROUTE_NAME(type),
a069482f
K
1825 ROUTEMAP_NAME(red),
1826 (ROUTEMAP(red) ? ""
1827 : " (not found !)"));
dd726234 1828 } else {
1829 if (!use_json)
1830 vty_out(vty, " %d: %s\n", nroute[type],
1831 ZROUTE_NAME(type));
1832 }
1833
1834 if (use_json)
1835 json_object_array_add(json_array, json_route);
d62a17ae 1836 }
dd726234 1837 if (use_json) {
1838 json_object_object_add(json, "redistributedRoutes", json_array);
1839 json_object_int_add(json, "totalRoutes", total);
1840 } else
1841 vty_out(vty, "Total %d routes\n", total);
d62a17ae 1842}
718e3744 1843
b19502d3
YR
1844static void ospf6_redistribute_default_set(struct ospf6 *ospf6, int originate)
1845{
1846 struct prefix_ipv6 p = {};
1847 struct in6_addr nexthop = {};
1848 int cur_originate = ospf6->default_originate;
1849
1850 p.family = AF_INET6;
1851 p.prefixlen = 0;
1852
1853 ospf6->default_originate = originate;
1854
1855 switch (cur_originate) {
1856 case DEFAULT_ORIGINATE_NONE:
1857 break;
1858 case DEFAULT_ORIGINATE_ZEBRA:
1859 zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_DELETE,
1860 zclient, AFI_IP6, ospf6->vrf_id);
1861 ospf6_asbr_redistribute_remove(DEFAULT_ROUTE, 0,
1862 (struct prefix *)&p, ospf6);
1863
1864 break;
1865 case DEFAULT_ORIGINATE_ALWAYS:
1866 ospf6_asbr_redistribute_remove(DEFAULT_ROUTE, 0,
1867 (struct prefix *)&p, ospf6);
1868 break;
1869 }
1870
1871 switch (originate) {
1872 case DEFAULT_ORIGINATE_NONE:
1873 break;
1874 case DEFAULT_ORIGINATE_ZEBRA:
1875 zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD,
1876 zclient, AFI_IP6, ospf6->vrf_id);
1877
1878 break;
1879 case DEFAULT_ORIGINATE_ALWAYS:
1880 ospf6_asbr_redistribute_add(DEFAULT_ROUTE, 0,
1881 (struct prefix *)&p, 0, &nexthop, 0,
1882 ospf6);
1883 break;
1884 }
1885}
1886
1887/* Default Route originate. */
1888DEFPY (ospf6_default_route_originate,
1889 ospf6_default_route_originate_cmd,
70dd370f 1890 "default-information originate [{always$always|metric (0-16777214)$mval|metric-type (1-2)$mtype|route-map RMAP_NAME$rtmap}]",
b19502d3
YR
1891 "Control distribution of default route\n"
1892 "Distribute a default route\n"
1893 "Always advertise default route\n"
1894 "OSPFv3 default metric\n"
1895 "OSPFv3 metric\n"
1896 "OSPFv3 metric type for default routes\n"
1897 "Set OSPFv3 External Type 1/2 metrics\n"
1898 "Route map reference\n"
1899 "Pointer to route-map entries\n")
1900{
1901 int default_originate = DEFAULT_ORIGINATE_ZEBRA;
1902 struct ospf6_redist *red;
1903 bool sameRtmap = false;
1904
1905 VTY_DECLVAR_CONTEXT(ospf6, ospf6);
1906
1907 int cur_originate = ospf6->default_originate;
1908
b19502d3
YR
1909 red = ospf6_redist_add(ospf6, DEFAULT_ROUTE, 0);
1910
1911 if (always != NULL)
1912 default_originate = DEFAULT_ORIGINATE_ALWAYS;
1913
1914 if (mval_str == NULL)
1915 mval = -1;
1916
1917 if (mtype_str == NULL)
1918 mtype = -1;
1919
ff5c476d 1920 /* To check if user is providing same route map */
1921 if ((!rtmap && !ROUTEMAP_NAME(red)) ||
1922 (rtmap && ROUTEMAP_NAME(red) &&
1923 (strcmp(rtmap, ROUTEMAP_NAME(red)) == 0)))
b19502d3
YR
1924 sameRtmap = true;
1925
ff5c476d 1926 /* Don't allow if the same lsa is already originated. */
b19502d3
YR
1927 if ((sameRtmap) && (red->dmetric.type == mtype)
1928 && (red->dmetric.value == mval)
1929 && (cur_originate == default_originate))
1930 return CMD_SUCCESS;
1931
1932 /* Updating Metric details */
1933 red->dmetric.type = mtype;
1934 red->dmetric.value = mval;
1935
1936 /* updating route map details */
1937 if (rtmap)
1938 ospf6_asbr_routemap_set(red, rtmap);
1939 else
1940 ospf6_asbr_routemap_unset(red);
1941
1942 ospf6_redistribute_default_set(ospf6, default_originate);
1943 return CMD_SUCCESS;
1944}
1945
1946DEFPY (no_ospf6_default_information_originate,
1947 no_ospf6_default_information_originate_cmd,
70dd370f 1948 "no default-information originate [{always|metric (0-16777214)|metric-type (1-2)|route-map RMAP_NAME}]",
b19502d3
YR
1949 NO_STR
1950 "Control distribution of default information\n"
1951 "Distribute a default route\n"
1952 "Always advertise default route\n"
1953 "OSPFv3 default metric\n"
1954 "OSPFv3 metric\n"
1955 "OSPFv3 metric type for default routes\n"
1956 "Set OSPFv3 External Type 1/2 metrics\n"
1957 "Route map reference\n"
1958 "Pointer to route-map entries\n")
1959{
1960 struct ospf6_redist *red;
1961
1962 VTY_DECLVAR_CONTEXT(ospf6, ospf6);
1963
b19502d3
YR
1964 red = ospf6_redist_lookup(ospf6, DEFAULT_ROUTE, 0);
1965 if (!red)
1966 return CMD_SUCCESS;
1967
1968 ospf6_asbr_routemap_unset(red);
1969 ospf6_redist_del(ospf6, red, DEFAULT_ROUTE);
1970
1971 ospf6_redistribute_default_set(ospf6, DEFAULT_ORIGINATE_NONE);
1972 return CMD_SUCCESS;
1973}
6b0655a2 1974
508e53e2 1975/* Routemap Functions */
b68885f9 1976static enum route_map_cmd_result_t
123214ef
MS
1977ospf6_routemap_rule_match_address_prefixlist(void *rule,
1978 const struct prefix *prefix,
1782514f 1979
d62a17ae 1980 void *object)
508e53e2 1981{
d62a17ae 1982 struct prefix_list *plist;
718e3744 1983
d62a17ae 1984 plist = prefix_list_lookup(AFI_IP6, (char *)rule);
1985 if (plist == NULL)
1986 return RMAP_NOMATCH;
718e3744 1987
d62a17ae 1988 return (prefix_list_apply(plist, prefix) == PREFIX_DENY ? RMAP_NOMATCH
1989 : RMAP_MATCH);
508e53e2 1990}
718e3744 1991
6ac29a51 1992static void *
d62a17ae 1993ospf6_routemap_rule_match_address_prefixlist_compile(const char *arg)
508e53e2 1994{
d62a17ae 1995 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
718e3744 1996}
1997
d62a17ae 1998static void ospf6_routemap_rule_match_address_prefixlist_free(void *rule)
718e3744 1999{
d62a17ae 2000 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
508e53e2 2001}
718e3744 2002
364deb04
DL
2003static const struct route_map_rule_cmd
2004 ospf6_routemap_rule_match_address_prefixlist_cmd = {
d62a17ae 2005 "ipv6 address prefix-list",
2006 ospf6_routemap_rule_match_address_prefixlist,
2007 ospf6_routemap_rule_match_address_prefixlist_compile,
2008 ospf6_routemap_rule_match_address_prefixlist_free,
508e53e2 2009};
718e3744 2010
42a7debf
VT
2011/* `match interface IFNAME' */
2012/* Match function should return 1 if match is success else return
2013 zero. */
b68885f9 2014static enum route_map_cmd_result_t
123214ef 2015ospf6_routemap_rule_match_interface(void *rule, const struct prefix *prefix,
1782514f 2016 void *object)
42a7debf 2017{
d62a17ae 2018 struct interface *ifp;
198ef12a 2019 struct ospf6_route *route;
d62a17ae 2020 struct ospf6_external_info *ei;
42a7debf 2021
198ef12a
IR
2022 route = object;
2023 ei = route->route_option;
2024 ifp = if_lookup_by_name((char *)rule, route->ospf6->vrf_id);
42a7debf 2025
1782514f
DS
2026 if (ifp != NULL && ei->ifindex == ifp->ifindex)
2027 return RMAP_MATCH;
42a7debf 2028
d62a17ae 2029 return RMAP_NOMATCH;
42a7debf
VT
2030}
2031
2032/* Route map `interface' match statement. `arg' should be
2033 interface name. */
d62a17ae 2034static void *ospf6_routemap_rule_match_interface_compile(const char *arg)
42a7debf 2035{
d62a17ae 2036 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
42a7debf
VT
2037}
2038
2039/* Free route map's compiled `interface' value. */
d62a17ae 2040static void ospf6_routemap_rule_match_interface_free(void *rule)
42a7debf 2041{
d62a17ae 2042 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
42a7debf
VT
2043}
2044
2045/* Route map commands for interface matching. */
364deb04
DL
2046static const struct route_map_rule_cmd
2047 ospf6_routemap_rule_match_interface_cmd = {
2048 "interface",
2049 ospf6_routemap_rule_match_interface,
d62a17ae 2050 ospf6_routemap_rule_match_interface_compile,
364deb04
DL
2051 ospf6_routemap_rule_match_interface_free
2052};
42a7debf 2053
464015fa 2054/* Match function for matching route tags */
b68885f9 2055static enum route_map_cmd_result_t
1782514f 2056ospf6_routemap_rule_match_tag(void *rule, const struct prefix *p, void *object)
464015fa 2057{
d62a17ae 2058 route_tag_t *tag = rule;
2059 struct ospf6_route *route = object;
2060 struct ospf6_external_info *info = route->route_option;
464015fa 2061
1782514f 2062 if (info->tag == *tag)
d62a17ae 2063 return RMAP_MATCH;
464015fa 2064
d62a17ae 2065 return RMAP_NOMATCH;
464015fa
CF
2066}
2067
364deb04
DL
2068static const struct route_map_rule_cmd
2069 ospf6_routemap_rule_match_tag_cmd = {
2070 "tag",
2071 ospf6_routemap_rule_match_tag,
2072 route_map_rule_tag_compile,
d62a17ae 2073 route_map_rule_tag_free,
464015fa
CF
2074};
2075
b68885f9 2076static enum route_map_cmd_result_t
123214ef 2077ospf6_routemap_rule_set_metric_type(void *rule, const struct prefix *prefix,
1782514f 2078 void *object)
508e53e2 2079{
d62a17ae 2080 char *metric_type = rule;
2081 struct ospf6_route *route = object;
718e3744 2082
d62a17ae 2083 if (strcmp(metric_type, "type-2") == 0)
2084 route->path.metric_type = 2;
2085 else
2086 route->path.metric_type = 1;
718e3744 2087
d62a17ae 2088 return RMAP_OKAY;
508e53e2 2089}
718e3744 2090
d62a17ae 2091static void *ospf6_routemap_rule_set_metric_type_compile(const char *arg)
508e53e2 2092{
d62a17ae 2093 if (strcmp(arg, "type-2") && strcmp(arg, "type-1"))
2094 return NULL;
2095 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
718e3744 2096}
2097
d62a17ae 2098static void ospf6_routemap_rule_set_metric_type_free(void *rule)
718e3744 2099{
d62a17ae 2100 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
508e53e2 2101}
718e3744 2102
364deb04
DL
2103static const struct route_map_rule_cmd
2104 ospf6_routemap_rule_set_metric_type_cmd = {
2105 "metric-type",
2106 ospf6_routemap_rule_set_metric_type,
d62a17ae 2107 ospf6_routemap_rule_set_metric_type_compile,
2108 ospf6_routemap_rule_set_metric_type_free,
508e53e2 2109};
718e3744 2110
b68885f9 2111static enum route_map_cmd_result_t
123214ef 2112ospf6_routemap_rule_set_metric(void *rule, const struct prefix *prefix,
1782514f 2113 void *object)
508e53e2 2114{
d62a17ae 2115 char *metric = rule;
2116 struct ospf6_route *route = object;
718e3744 2117
d62a17ae 2118 route->path.cost = atoi(metric);
2119 return RMAP_OKAY;
508e53e2 2120}
718e3744 2121
d62a17ae 2122static void *ospf6_routemap_rule_set_metric_compile(const char *arg)
508e53e2 2123{
d7c0a89a 2124 uint32_t metric;
d62a17ae 2125 char *endp;
2126 metric = strtoul(arg, &endp, 0);
2127 if (metric > OSPF_LS_INFINITY || *endp != '\0')
2128 return NULL;
2129 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
718e3744 2130}
2131
d62a17ae 2132static void ospf6_routemap_rule_set_metric_free(void *rule)
718e3744 2133{
d62a17ae 2134 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
508e53e2 2135}
718e3744 2136
364deb04
DL
2137static const struct route_map_rule_cmd
2138 ospf6_routemap_rule_set_metric_cmd = {
2139 "metric",
2140 ospf6_routemap_rule_set_metric,
d62a17ae 2141 ospf6_routemap_rule_set_metric_compile,
2142 ospf6_routemap_rule_set_metric_free,
508e53e2 2143};
718e3744 2144
b68885f9 2145static enum route_map_cmd_result_t
123214ef 2146ospf6_routemap_rule_set_forwarding(void *rule, const struct prefix *prefix,
1782514f 2147 void *object)
508e53e2 2148{
d62a17ae 2149 char *forwarding = rule;
2150 struct ospf6_route *route = object;
2151 struct ospf6_external_info *info = route->route_option;
718e3744 2152
d62a17ae 2153 if (inet_pton(AF_INET6, forwarding, &info->forwarding) != 1) {
2154 memset(&info->forwarding, 0, sizeof(struct in6_addr));
2155 return RMAP_ERROR;
2156 }
718e3744 2157
d62a17ae 2158 return RMAP_OKAY;
718e3744 2159}
2160
d62a17ae 2161static void *ospf6_routemap_rule_set_forwarding_compile(const char *arg)
718e3744 2162{
d62a17ae 2163 struct in6_addr a;
2164 if (inet_pton(AF_INET6, arg, &a) != 1)
2165 return NULL;
2166 return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
718e3744 2167}
2168
d62a17ae 2169static void ospf6_routemap_rule_set_forwarding_free(void *rule)
718e3744 2170{
d62a17ae 2171 XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
508e53e2 2172}
718e3744 2173
364deb04
DL
2174static const struct route_map_rule_cmd
2175 ospf6_routemap_rule_set_forwarding_cmd = {
2176 "forwarding-address",
2177 ospf6_routemap_rule_set_forwarding,
d62a17ae 2178 ospf6_routemap_rule_set_forwarding_compile,
2179 ospf6_routemap_rule_set_forwarding_free,
508e53e2 2180};
718e3744 2181
b68885f9 2182static enum route_map_cmd_result_t
1782514f 2183ospf6_routemap_rule_set_tag(void *rule, const struct prefix *p, void *object)
464015fa 2184{
d62a17ae 2185 route_tag_t *tag = rule;
2186 struct ospf6_route *route = object;
2187 struct ospf6_external_info *info = route->route_option;
464015fa 2188
d62a17ae 2189 info->tag = *tag;
2190 return RMAP_OKAY;
464015fa
CF
2191}
2192
078110ca 2193static const struct route_map_rule_cmd ospf6_routemap_rule_set_tag_cmd = {
364deb04
DL
2194 "tag",
2195 ospf6_routemap_rule_set_tag,
2196 route_map_rule_tag_compile,
d62a17ae 2197 route_map_rule_tag_free,
464015fa
CF
2198};
2199
508e53e2 2200/* add "set metric-type" */
078110ca
SP
2201DEFUN_YANG (ospf6_routemap_set_metric_type, ospf6_routemap_set_metric_type_cmd,
2202 "set metric-type <type-1|type-2>",
e53dac2f
DL
2203 SET_STR
2204 "Type of metric for destination routing protocol\n"
2205 "OSPF[6] external type 1 metric\n"
2206 "OSPF[6] external type 2 metric\n")
508e53e2 2207{
078110ca
SP
2208 char *ext = argv[2]->text;
2209
2210 const char *xpath =
2211 "./set-action[action='frr-ospf-route-map:metric-type']";
2212 char xpath_value[XPATH_MAXLEN];
cda7187d 2213
078110ca
SP
2214 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
2215 snprintf(xpath_value, sizeof(xpath_value),
2216 "%s/rmap-set-action/frr-ospf-route-map:metric-type", xpath);
2217 nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, ext);
2218 return nb_cli_apply_changes(vty, NULL);
718e3744 2219}
2220
508e53e2 2221/* delete "set metric-type" */
078110ca
SP
2222DEFUN_YANG (ospf6_routemap_no_set_metric_type, ospf6_routemap_no_set_metric_type_cmd,
2223 "no set metric-type [<type-1|type-2>]",
2224 NO_STR
e53dac2f
DL
2225 SET_STR
2226 "Type of metric for destination routing protocol\n"
2227 "OSPF[6] external type 1 metric\n"
2228 "OSPF[6] external type 2 metric\n")
718e3744 2229{
078110ca
SP
2230 const char *xpath =
2231 "./set-action[action='frr-ospf-route-map:metric-type']";
cda7187d 2232
078110ca
SP
2233 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
2234 return nb_cli_apply_changes(vty, NULL);
508e53e2 2235}
718e3744 2236
508e53e2 2237/* add "set forwarding-address" */
078110ca
SP
2238DEFUN_YANG (ospf6_routemap_set_forwarding, ospf6_routemap_set_forwarding_cmd,
2239 "set forwarding-address X:X::X:X",
2240 "Set value\n"
2241 "Forwarding Address\n"
2242 "IPv6 Address\n")
508e53e2 2243{
d62a17ae 2244 int idx_ipv6 = 2;
078110ca
SP
2245 const char *xpath =
2246 "./set-action[action='frr-ospf6-route-map:forwarding-address']";
2247 char xpath_value[XPATH_MAXLEN];
2248
2249 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
2250 snprintf(xpath_value, sizeof(xpath_value),
2251 "%s/rmap-set-action/frr-ospf6-route-map:ipv6-address", xpath);
2252 nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
2253 argv[idx_ipv6]->arg);
2254 return nb_cli_apply_changes(vty, NULL);
508e53e2 2255}
718e3744 2256
508e53e2 2257/* delete "set forwarding-address" */
078110ca
SP
2258DEFUN_YANG (ospf6_routemap_no_set_forwarding, ospf6_routemap_no_set_forwarding_cmd,
2259 "no set forwarding-address [X:X::X:X]",
2260 NO_STR
2261 "Set value\n"
2262 "Forwarding Address\n"
2263 "IPv6 Address\n")
508e53e2 2264{
078110ca
SP
2265 const char *xpath =
2266 "./set-action[action='frr-ospf6-route-map:forwarding-address']";
cda7187d 2267
078110ca
SP
2268 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
2269 return nb_cli_apply_changes(vty, NULL);
508e53e2 2270}
718e3744 2271
d62a17ae 2272static void ospf6_routemap_init(void)
508e53e2 2273{
d62a17ae 2274 route_map_init();
b2575bc0 2275
d62a17ae 2276 route_map_add_hook(ospf6_asbr_routemap_update);
2277 route_map_delete_hook(ospf6_asbr_routemap_update);
856ae1eb 2278 route_map_event_hook(ospf6_asbr_routemap_event);
508e53e2 2279
d62a17ae 2280 route_map_set_metric_hook(generic_set_add);
2281 route_map_no_set_metric_hook(generic_set_delete);
82f97584 2282
45024ca0
MB
2283 route_map_set_tag_hook(generic_set_add);
2284 route_map_no_set_tag_hook(generic_set_delete);
2285
d62a17ae 2286 route_map_match_tag_hook(generic_match_add);
2287 route_map_no_match_tag_hook(generic_match_delete);
e1a1b2ed 2288
d62a17ae 2289 route_map_match_ipv6_address_prefix_list_hook(generic_match_add);
2290 route_map_no_match_ipv6_address_prefix_list_hook(generic_match_delete);
e1a1b2ed 2291
d62a17ae 2292 route_map_match_interface_hook(generic_match_add);
2293 route_map_no_match_interface_hook(generic_match_delete);
e1a1b2ed 2294
d62a17ae 2295 route_map_install_match(
2296 &ospf6_routemap_rule_match_address_prefixlist_cmd);
2297 route_map_install_match(&ospf6_routemap_rule_match_interface_cmd);
2298 route_map_install_match(&ospf6_routemap_rule_match_tag_cmd);
42a7debf 2299
d62a17ae 2300 route_map_install_set(&ospf6_routemap_rule_set_metric_type_cmd);
2301 route_map_install_set(&ospf6_routemap_rule_set_metric_cmd);
2302 route_map_install_set(&ospf6_routemap_rule_set_forwarding_cmd);
2303 route_map_install_set(&ospf6_routemap_rule_set_tag_cmd);
508e53e2 2304
d62a17ae 2305 /* ASE Metric Type (e.g. Type-1/Type-2) */
2306 install_element(RMAP_NODE, &ospf6_routemap_set_metric_type_cmd);
2307 install_element(RMAP_NODE, &ospf6_routemap_no_set_metric_type_cmd);
508e53e2 2308
d62a17ae 2309 /* ASE Metric */
2310 install_element(RMAP_NODE, &ospf6_routemap_set_forwarding_cmd);
2311 install_element(RMAP_NODE, &ospf6_routemap_no_set_forwarding_cmd);
718e3744 2312}
2313
6b0655a2 2314
508e53e2 2315/* Display functions */
d62a17ae 2316static char *ospf6_as_external_lsa_get_prefix_str(struct ospf6_lsa *lsa,
2317 char *buf, int buflen,
2318 int pos)
e68a6767 2319{
d62a17ae 2320 struct ospf6_as_external_lsa *external;
2321 struct in6_addr in6;
2322 int prefix_length = 0;
7533cad7 2323 char tbuf[16];
d62a17ae 2324
2325 if (lsa) {
2326 external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
2327 lsa->header);
2328
2329 if (pos == 0) {
b8ce0c36 2330 ospf6_prefix_in6_addr(&in6, external,
2331 &external->prefix);
d62a17ae 2332 prefix_length = external->prefix.prefix_length;
2333 } else {
2334 in6 = *((struct in6_addr
2335 *)((caddr_t)external
2336 + sizeof(struct
2337 ospf6_as_external_lsa)
2338 + OSPF6_PREFIX_SPACE(
2339 external->prefix
2340 .prefix_length)));
2341 }
2342 if (buf) {
2343 inet_ntop(AF_INET6, &in6, buf, buflen);
7533cad7
QY
2344 if (prefix_length) {
2345 snprintf(tbuf, sizeof(tbuf), "/%d",
2346 prefix_length);
2347 strlcat(buf, tbuf, buflen);
2348 }
d62a17ae 2349 }
e68a6767 2350 }
d62a17ae 2351 return (buf);
e68a6767
DD
2352}
2353
e4bacbaa
YR
2354static int ospf6_as_external_lsa_show(struct vty *vty, struct ospf6_lsa *lsa,
2355 json_object *json_obj, bool use_json)
718e3744 2356{
d62a17ae 2357 struct ospf6_as_external_lsa *external;
2358 char buf[64];
2359
2360 assert(lsa->header);
2361 external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
2362 lsa->header);
2363
2364 /* bits */
2365 snprintf(buf, sizeof(buf), "%c%c%c",
2366 (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_E) ? 'E'
2367 : '-'),
2368 (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F) ? 'F'
2369 : '-'),
2370 (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T) ? 'T'
2371 : '-'));
2372
e4bacbaa
YR
2373 if (use_json) {
2374 json_object_string_add(json_obj, "bits", buf);
2375 json_object_int_add(json_obj, "metric",
2376 (unsigned long)OSPF6_ASBR_METRIC(external));
2377 ospf6_prefix_options_printbuf(external->prefix.prefix_options,
2378 buf, sizeof(buf));
2379 json_object_string_add(json_obj, "prefixOptions", buf);
2380 json_object_int_add(
2381 json_obj, "referenceLsType",
2382 ntohs(external->prefix.prefix_refer_lstype));
2383 json_object_string_add(json_obj, "prefix",
2384 ospf6_as_external_lsa_get_prefix_str(
2385 lsa, buf, sizeof(buf), 0));
2386
2387 /* Forwarding-Address */
2388 json_object_boolean_add(
2389 json_obj, "forwardingAddressPresent",
2390 CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F));
2391 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F))
2392 json_object_string_add(
2393 json_obj, "forwardingAddress",
2394 ospf6_as_external_lsa_get_prefix_str(
2395 lsa, buf, sizeof(buf), 1));
2396
2397 /* Tag */
2398 json_object_boolean_add(
2399 json_obj, "tagPresent",
2400 CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T));
2401 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T))
2402 json_object_int_add(json_obj, "tag",
2403 ospf6_as_external_lsa_get_tag(lsa));
2404 } else {
2405 vty_out(vty, " Bits: %s\n", buf);
2406 vty_out(vty, " Metric: %5lu\n",
2407 (unsigned long)OSPF6_ASBR_METRIC(external));
d62a17ae 2408
e4bacbaa
YR
2409 ospf6_prefix_options_printbuf(external->prefix.prefix_options,
2410 buf, sizeof(buf));
2411 vty_out(vty, " Prefix Options: %s\n", buf);
d62a17ae 2412
e4bacbaa
YR
2413 vty_out(vty, " Referenced LSType: %d\n",
2414 ntohs(external->prefix.prefix_refer_lstype));
d62a17ae 2415
e4bacbaa 2416 vty_out(vty, " Prefix: %s\n",
d62a17ae 2417 ospf6_as_external_lsa_get_prefix_str(lsa, buf,
e4bacbaa 2418 sizeof(buf), 0));
d62a17ae 2419
e4bacbaa
YR
2420 /* Forwarding-Address */
2421 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F)) {
2422 vty_out(vty, " Forwarding-Address: %s\n",
2423 ospf6_as_external_lsa_get_prefix_str(
2424 lsa, buf, sizeof(buf), 1));
2425 }
2426
2427 /* Tag */
2428 if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T)) {
2429 vty_out(vty, " Tag: %" ROUTE_TAG_PRI "\n",
2430 ospf6_as_external_lsa_get_tag(lsa));
2431 }
d62a17ae 2432 }
2433
2434 return 0;
718e3744 2435}
2436
d62a17ae 2437static void ospf6_asbr_external_route_show(struct vty *vty,
dd726234 2438 struct ospf6_route *route,
2439 json_object *json_array,
2440 bool use_json)
718e3744 2441{
d62a17ae 2442 struct ospf6_external_info *info = route->route_option;
dd726234 2443 char prefix[PREFIX2STR_BUFFER], id[16], forwarding[64];
d7c0a89a 2444 uint32_t tmp_id;
dd726234 2445 json_object *json_route;
2446 char route_type[2];
d62a17ae 2447
dd726234 2448 prefix2str(&route->prefix, prefix, sizeof(prefix));
d62a17ae 2449 tmp_id = ntohl(info->id);
2450 inet_ntop(AF_INET, &tmp_id, id, sizeof(id));
2451 if (!IN6_IS_ADDR_UNSPECIFIED(&info->forwarding))
2452 inet_ntop(AF_INET6, &info->forwarding, forwarding,
2453 sizeof(forwarding));
2454 else
2455 snprintf(forwarding, sizeof(forwarding), ":: (ifindex %d)",
2456 ospf6_route_get_first_nh_index(route));
2457
dd726234 2458 if (use_json) {
2459 json_route = json_object_new_object();
2460 snprintf(route_type, sizeof(route_type), "%c",
2461 zebra_route_char(info->type));
2462 json_object_string_add(json_route, "routeType", route_type);
2463 json_object_string_add(json_route, "destination", prefix);
2464 json_object_string_add(json_route, "id", id);
2465 json_object_int_add(json_route, "metricType",
2466 route->path.metric_type);
2467 json_object_int_add(
2468 json_route, "routeCost",
2469 (unsigned long)(route->path.metric_type == 2
2470 ? route->path.u.cost_e2
2471 : route->path.cost));
2472 json_object_string_add(json_route, "forwarding", forwarding);
2473
2474 json_object_array_add(json_array, json_route);
2475 } else
2476
2477 vty_out(vty, "%c %-32pFX %-15s type-%d %5lu %s\n",
2478 zebra_route_char(info->type), &route->prefix, id,
2479 route->path.metric_type,
2480 (unsigned long)(route->path.metric_type == 2
2481 ? route->path.u.cost_e2
2482 : route->path.cost),
2483 forwarding);
718e3744 2484}
2485
d48ef099 2486DEFUN(show_ipv6_ospf6_redistribute, show_ipv6_ospf6_redistribute_cmd,
2487 "show ipv6 ospf6 [vrf <NAME|all>] redistribute [json]",
2488 SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR
2489 "All VRFs\n"
2490 "redistributing External information\n" JSON_STR)
718e3744 2491{
d62a17ae 2492 struct ospf6_route *route;
beadc736 2493 struct ospf6 *ospf6 = NULL;
dd726234 2494 json_object *json = NULL;
2495 bool uj = use_json(argc, argv);
d48ef099 2496 struct listnode *node;
2497 const char *vrf_name = NULL;
2498 bool all_vrf = false;
2499 int idx_vrf = 0;
2500
dd726234 2501 json_object *json_array_routes = NULL;
2502 json_object *json_array_redistribute = NULL;
718e3744 2503
d48ef099 2504 OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
b52a8a52 2505
dd726234 2506 if (uj) {
2507 json = json_object_new_object();
2508 json_array_routes = json_object_new_array();
2509 json_array_redistribute = json_object_new_array();
2510 }
718e3744 2511
d48ef099 2512 for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
2513 if (all_vrf
2514 || ((ospf6->name == NULL && vrf_name == NULL)
2515 || (ospf6->name && vrf_name
2516 && strcmp(ospf6->name, vrf_name) == 0))) {
2517 ospf6_redistribute_show_config(
2518 vty, ospf6, json_array_redistribute, json, uj);
2519
2520 for (route = ospf6_route_head(ospf6->external_table);
2521 route; route = ospf6_route_next(route)) {
2522 ospf6_asbr_external_route_show(
2523 vty, route, json_array_routes, uj);
2524 }
508e53e2 2525
d48ef099 2526 if (uj) {
2527 json_object_object_add(json, "routes",
2528 json_array_routes);
5a6c232b 2529 vty_json(vty, json);
d48ef099 2530 }
2531
2532 if (!all_vrf)
2533 break;
2534 }
dd726234 2535 }
d48ef099 2536
d6b901ac 2537 OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6);
2538
d62a17ae 2539 return CMD_SUCCESS;
718e3744 2540}
2541
4062abfa 2542static struct ospf6_lsa_handler as_external_handler = {
3981b5c7
VJ
2543 .lh_type = OSPF6_LSTYPE_AS_EXTERNAL,
2544 .lh_name = "AS-External",
2545 .lh_short_name = "ASE",
2546 .lh_show = ospf6_as_external_lsa_show,
2547 .lh_get_prefix_str = ospf6_as_external_lsa_get_prefix_str,
996c9314 2548 .lh_debug = 0};
508e53e2 2549
ad500b22
K
2550static struct ospf6_lsa_handler nssa_external_handler = {
2551 .lh_type = OSPF6_LSTYPE_TYPE_7,
2552 .lh_name = "NSSA",
2553 .lh_short_name = "Type7",
2554 .lh_show = ospf6_as_external_lsa_show,
2555 .lh_get_prefix_str = ospf6_as_external_lsa_get_prefix_str,
2556 .lh_debug = 0};
2557
d62a17ae 2558void ospf6_asbr_init(void)
718e3744 2559{
d62a17ae 2560 ospf6_routemap_init();
508e53e2 2561
d62a17ae 2562 ospf6_install_lsa_handler(&as_external_handler);
ad500b22 2563 ospf6_install_lsa_handler(&nssa_external_handler);
718e3744 2564
d62a17ae 2565 install_element(VIEW_NODE, &show_ipv6_ospf6_redistribute_cmd);
508e53e2 2566
b19502d3
YR
2567 install_element(OSPF6_NODE, &ospf6_default_route_originate_cmd);
2568 install_element(OSPF6_NODE,
2569 &no_ospf6_default_information_originate_cmd);
d62a17ae 2570 install_element(OSPF6_NODE, &ospf6_redistribute_cmd);
d62a17ae 2571 install_element(OSPF6_NODE, &no_ospf6_redistribute_cmd);
718e3744 2572}
2573
f71ed6df 2574void ospf6_asbr_redistribute_disable(struct ospf6 *ospf6)
d9628728 2575{
d62a17ae 2576 int type;
a069482f 2577 struct ospf6_redist *red;
d62a17ae 2578
30885c70 2579 for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
a069482f
K
2580 red = ospf6_redist_lookup(ospf6, type, 0);
2581 if (!red)
2582 continue;
30885c70 2583 if (type == ZEBRA_ROUTE_OSPF6)
d62a17ae 2584 continue;
8696e8be
IR
2585 ospf6_asbr_redistribute_unset(ospf6, red, type);
2586 ospf6_redist_del(ospf6, red, type);
d62a17ae 2587 }
30885c70
DS
2588 red = ospf6_redist_lookup(ospf6, DEFAULT_ROUTE, 0);
2589 if (red) {
2590 ospf6_asbr_routemap_unset(red);
2591 ospf6_redist_del(ospf6, red, type);
2592 ospf6_redistribute_default_set(ospf6, DEFAULT_ORIGINATE_NONE);
2593 }
d9628728
CF
2594}
2595
f71ed6df
YR
2596void ospf6_asbr_redistribute_reset(struct ospf6 *ospf6)
2597{
2598 int type;
2599 struct ospf6_redist *red;
2600 char buf[RMAP_NAME_MAXLEN];
2601
2602 for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) {
2603 buf[0] = '\0';
2604 if (type == ZEBRA_ROUTE_OSPF6)
2605 continue;
2606 red = ospf6_redist_lookup(ospf6, type, 0);
2607 if (!red)
2608 continue;
2609
2610 if (type == DEFAULT_ROUTE) {
2611 ospf6_redistribute_default_set(
2612 ospf6, ospf6->default_originate);
2613 continue;
2614 }
2615 if (ROUTEMAP_NAME(red))
2616 strlcpy(buf, ROUTEMAP_NAME(red), sizeof(buf));
2617
2618 ospf6_asbr_redistribute_unset(ospf6, red, type);
2619 if (buf[0])
2620 ospf6_asbr_routemap_set(red, buf);
2621 ospf6_asbr_redistribute_set(ospf6, type);
2622 }
2623}
2624
d62a17ae 2625void ospf6_asbr_terminate(void)
ae2254aa 2626{
856ae1eb 2627 /* Cleanup route maps */
d62a17ae 2628 route_map_finish();
ae2254aa 2629}
718e3744 2630
508e53e2 2631DEFUN (debug_ospf6_asbr,
2632 debug_ospf6_asbr_cmd,
2633 "debug ospf6 asbr",
2634 DEBUG_STR
2635 OSPF6_STR
2636 "Debug OSPFv3 ASBR function\n"
2637 )
2638{
d62a17ae 2639 OSPF6_DEBUG_ASBR_ON();
2640 return CMD_SUCCESS;
508e53e2 2641}
2642
2643DEFUN (no_debug_ospf6_asbr,
2644 no_debug_ospf6_asbr_cmd,
2645 "no debug ospf6 asbr",
2646 NO_STR
2647 DEBUG_STR
2648 OSPF6_STR
2649 "Debug OSPFv3 ASBR function\n"
2650 )
2651{
d62a17ae 2652 OSPF6_DEBUG_ASBR_OFF();
2653 return CMD_SUCCESS;
508e53e2 2654}
2655
d62a17ae 2656int config_write_ospf6_debug_asbr(struct vty *vty)
508e53e2 2657{
d62a17ae 2658 if (IS_OSPF6_DEBUG_ASBR)
2659 vty_out(vty, "debug ospf6 asbr\n");
2660 return 0;
508e53e2 2661}
2662
a0fbad58 2663static void ospf6_default_originate_write(struct vty *vty, struct ospf6 *o)
b19502d3
YR
2664{
2665 struct ospf6_redist *red;
2666
a0fbad58
RZ
2667 vty_out(vty, " default-information originate");
2668 if (o->default_originate == DEFAULT_ORIGINATE_ALWAYS)
2669 vty_out(vty, " always");
b19502d3 2670
a0fbad58
RZ
2671 red = ospf6_redist_lookup(o, DEFAULT_ROUTE, 0);
2672 if (red == NULL) {
2673 vty_out(vty, "\n");
2674 return;
b19502d3 2675 }
a0fbad58
RZ
2676
2677 if (red->dmetric.value >= 0)
2678 vty_out(vty, " metric %d", red->dmetric.value);
2679
2680 if (red->dmetric.type >= 0)
2681 vty_out(vty, " metric-type %d", red->dmetric.type);
2682
2683 if (ROUTEMAP_NAME(red))
2684 vty_out(vty, " route-map %s", ROUTEMAP_NAME(red));
2685
2686 vty_out(vty, "\n");
2687}
2688
2689int ospf6_distribute_config_write(struct vty *vty, struct ospf6 *o)
2690{
2691 if (o == NULL)
2692 return 0;
2693
2694 /* Print default originate configuration. */
2695 if (o->default_originate != DEFAULT_ORIGINATE_NONE)
2696 ospf6_default_originate_write(vty, o);
2697
b19502d3
YR
2698 return 0;
2699}
2700
4d762f26 2701void install_element_ospf6_debug_asbr(void)
92300491 2702{
d62a17ae 2703 install_element(ENABLE_NODE, &debug_ospf6_asbr_cmd);
2704 install_element(ENABLE_NODE, &no_debug_ospf6_asbr_cmd);
2705 install_element(CONFIG_NODE, &debug_ospf6_asbr_cmd);
2706 install_element(CONFIG_NODE, &no_debug_ospf6_asbr_cmd);
92300491 2707}
4dc43886
MR
2708
2709/* ASBR Summarisation */
c405b00f
MR
2710void ospf6_fill_aggr_route_details(struct ospf6 *ospf6,
2711 struct ospf6_external_aggr_rt *aggr)
2712{
2713 struct ospf6_route *rt_aggr = aggr->route;
2714 struct ospf6_external_info *ei_aggr = rt_aggr->route_option;
2715
2716 rt_aggr->prefix = aggr->p;
2717 ei_aggr->tag = aggr->tag;
2718 ei_aggr->type = 0;
2719 ei_aggr->id = aggr->id;
2720
2721 /* When metric is not configured, apply the default metric */
2722 rt_aggr->path.cost = ((aggr->metric == -1) ?
2723 DEFAULT_DEFAULT_METRIC
2724 : (unsigned int)(aggr->metric));
2725 rt_aggr->path.metric_type = aggr->mtype;
2726
2727 rt_aggr->path.origin.id = htonl(aggr->id);
2728}
2729
4e0702dc
MR
2730static void
2731ospf6_summary_add_aggr_route_and_blackhole(struct ospf6 *ospf6,
2732 struct ospf6_external_aggr_rt *aggr)
2733{
2734 struct ospf6_route *rt_aggr;
a28474d3 2735 struct ospf6_route *old_rt = NULL;
4e0702dc
MR
2736 struct ospf6_external_info *info;
2737
a28474d3
MN
2738 /* Check if a route is already present. */
2739 if (aggr->route)
2740 old_rt = aggr->route;
2741
4e0702dc
MR
2742 /* Create summary route and save it. */
2743 rt_aggr = ospf6_route_create(ospf6);
2744 rt_aggr->type = OSPF6_DEST_TYPE_NETWORK;
2745 /* Needed to install route while calling zebra api */
2746 SET_FLAG(rt_aggr->flag, OSPF6_ROUTE_BEST);
2747
2748 info = XCALLOC(MTYPE_OSPF6_EXTERNAL_INFO, sizeof(*info));
2749 rt_aggr->route_option = info;
2750 aggr->route = rt_aggr;
2751
2752 /* Prepare the external_info for aggregator
2753 * Fill all the details which will get advertised
2754 */
2755 ospf6_fill_aggr_route_details(ospf6, aggr);
2756
2757 /* Add next-hop to Null interface. */
2758 ospf6_add_route_nexthop_blackhole(rt_aggr);
2759
a28474d3
MN
2760 /* Free the old route, if any. */
2761 if (old_rt) {
2762 ospf6_zebra_route_update_remove(old_rt, ospf6);
2763
2764 if (old_rt->route_option)
2765 XFREE(MTYPE_OSPF6_EXTERNAL_INFO, old_rt->route_option);
2766
2767 ospf6_route_delete(old_rt);
2768 }
2769
4e0702dc
MR
2770 ospf6_zebra_route_update_add(rt_aggr, ospf6);
2771}
2772
4dc43886 2773static void ospf6_originate_new_aggr_lsa(struct ospf6 *ospf6,
c405b00f 2774 struct ospf6_external_aggr_rt *aggr)
4dc43886 2775{
4dc43886 2776 struct prefix prefix_id;
4dc43886
MR
2777 struct ospf6_lsa *lsa = NULL;
2778
2779 if (IS_OSPF6_DEBUG_AGGR)
2780 zlog_debug("%s: Originate new aggregate route(%pFX)", __func__,
2781 &aggr->p);
2782
2783 aggr->id = ospf6->external_id++;
4e0702dc 2784
4dc43886
MR
2785 if (IS_OSPF6_DEBUG_AGGR)
2786 zlog_debug(
2787 "Advertise AS-External Id:%pI4 prefix %pFX metric %u",
c405b00f 2788 &prefix_id.u.prefix4, &aggr->p, aggr->metric);
4dc43886 2789
4e0702dc 2790 ospf6_summary_add_aggr_route_and_blackhole(ospf6, aggr);
4dc43886
MR
2791
2792 /* Originate summary LSA */
4e0702dc 2793 lsa = ospf6_originate_type5_type7_lsas(aggr->route, ospf6);
4dc43886
MR
2794 if (lsa) {
2795 if (IS_OSPF6_DEBUG_AGGR)
2796 zlog_debug("%s: Set the origination bit for aggregator",
2797 __func__);
2798 SET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED);
2799 }
4dc43886
MR
2800}
2801
4dc43886
MR
2802static void
2803ospf6_aggr_handle_advertise_change(struct ospf6 *ospf6,
2804 struct ospf6_external_aggr_rt *aggr)
2805{
4dc43886
MR
2806 /* Check if advertise option modified. */
2807 if (CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE)) {
2808 if (IS_OSPF6_DEBUG_AGGR)
2809 zlog_debug("%s: Don't originate the summary address,It is configured to not-advertise.",
2810 __func__);
c405b00f 2811 ospf6_asbr_summary_remove_lsa_and_route(ospf6, aggr);
4dc43886 2812
4dc43886
MR
2813 return;
2814 }
2815
2816 /* There are no routes present under this aggregation config, hence
c3a70f65
MR
2817 * nothing to originate here
2818 */
4dc43886
MR
2819 if (OSPF6_EXTERNAL_RT_COUNT(aggr) == 0) {
2820 if (IS_OSPF6_DEBUG_AGGR)
2821 zlog_debug("%s: No routes present under this aggregation",
2822 __func__);
2823 return;
2824 }
2825
2826 if (!CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED)) {
2827 if (IS_OSPF6_DEBUG_AGGR)
2828 zlog_debug("%s: Now it is advertisable",
2829 __func__);
2830
c405b00f 2831 ospf6_originate_new_aggr_lsa(ospf6, aggr);
4dc43886
MR
2832
2833 return;
2834 }
2835}
2836
2837static void
2838ospf6_originate_summary_lsa(struct ospf6 *ospf6,
78982818
MR
2839 struct ospf6_external_aggr_rt *aggr,
2840 struct ospf6_route *rt)
4dc43886
MR
2841{
2842 struct ospf6_lsa *lsa = NULL, *aggr_lsa = NULL;
c405b00f 2843 struct ospf6_external_info *info = NULL;
4dc43886
MR
2844 struct ospf6_external_aggr_rt *old_aggr;
2845 struct ospf6_as_external_lsa *external;
c405b00f 2846 struct ospf6_route *rt_aggr = NULL;
4dc43886
MR
2847 route_tag_t tag = 0;
2848 unsigned int metric = 0;
2849 int mtype;
2850
2851 if (IS_OSPF6_DEBUG_AGGR)
2852 zlog_debug("%s: Prepare to originate Summary route(%pFX)",
2853 __func__, &aggr->p);
2854
2855 /* This case to handle when the overlapping aggregator address
2856 * is available. Best match will be considered.So need to delink
2857 * from old aggregator and link to the new aggr.
2858 */
2859 if (rt->aggr_route) {
2860 if (rt->aggr_route != aggr) {
2861 old_aggr = rt->aggr_route;
2862 ospf6_unlink_route_from_aggr(ospf6, old_aggr, rt);
2863 }
2864 }
2865
2866 /* Add the external route to hash table */
2867 ospf6_link_route_to_aggr(aggr, rt);
2868
2869 /* The key for ID field is a running number and not prefix */
2870 info = rt->route_option;
2871 assert(info);
4e0702dc 2872 if (info->id)
4dc43886 2873 lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
c3a70f65
MR
2874 htonl(info->id), ospf6->router_id,
2875 ospf6->lsdb);
4dc43886
MR
2876
2877 aggr_lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
2878 htonl(aggr->id), ospf6->router_id, ospf6->lsdb);
2879
2880 if (IS_OSPF6_DEBUG_AGGR)
2881 zlog_debug("%s: Aggr LSA ID: %d flags %x.",
2882 __func__, aggr->id, aggr->aggrflags);
bbf5104c 2883 /* Don't originate external LSA,
4dc43886
MR
2884 * If it is configured not to advertise.
2885 */
2886 if (CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE)) {
2887 /* If it is already originated as external LSA,
2888 * But, it is configured not to advertise then
2889 * flush the originated external lsa.
2890 */
2891 if (lsa) {
2892 if (IS_OSPF6_DEBUG_AGGR)
2893 zlog_debug("%s: Purge the external LSA %s.",
2894 __func__, lsa->name);
2895 ospf6_external_lsa_purge(ospf6, lsa);
2896 info->id = 0;
2897 rt->path.origin.id = 0;
2898 }
2899
2900 if (aggr_lsa) {
2901 if (IS_OSPF6_DEBUG_AGGR)
2902 zlog_debug("%s: Purge the aggr external LSA %s.",
2903 __func__, lsa->name);
c405b00f 2904 ospf6_asbr_summary_remove_lsa_and_route(ospf6, aggr);
4dc43886
MR
2905 }
2906
2907 UNSET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED);
2908
2909 if (IS_OSPF6_DEBUG_AGGR)
2910 zlog_debug("%s: Don't originate the summary address,It is configured to not-advertise.",
2911 __func__);
2912 return;
2913 }
2914
4dc43886
MR
2915 /* Summary route already originated,
2916 * So, Do nothing.
2917 */
2918 if (CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED)) {
2919 if (!aggr_lsa) {
2920 zlog_warn(
2921 "%s: Could not refresh/originate %pFX",
2922 __func__,
2923 &aggr->p);
2924 /* Remove the assert later */
2925 assert(aggr_lsa);
2926 return;
2927 }
2928
c3a70f65
MR
2929 external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END
2930 (aggr_lsa->header);
4dc43886
MR
2931 metric = (unsigned long)OSPF6_ASBR_METRIC(external);
2932 tag = ospf6_as_external_lsa_get_tag(aggr_lsa);
c3a70f65
MR
2933 mtype = CHECK_FLAG(external->bits_metric,
2934 OSPF6_ASBR_BIT_E) ? 2 : 1;
4dc43886 2935
c405b00f
MR
2936 /* Prepare the external_info for aggregator */
2937 ospf6_fill_aggr_route_details(ospf6, aggr);
2938 rt_aggr = aggr->route;
4dc43886
MR
2939 /* If tag/metric/metric-type modified , then re-originate the
2940 * route with modified tag/metric/metric-type details.
2941 */
c405b00f
MR
2942 if ((tag != aggr->tag)
2943 || (metric != (unsigned int)rt_aggr->path.cost)
4dc43886
MR
2944 || (mtype != aggr->mtype)) {
2945
2946 if (IS_OSPF6_DEBUG_AGGR)
2947 zlog_debug(
2948 "%s: Routetag(old:%d new:%d)/Metric(o:%u,n:%u)/mtype(o:%d n:%d) modified,So refresh the summary route.(%pFX)",
c405b00f 2949 __func__, tag, aggr->tag,
4dc43886
MR
2950 metric,
2951 aggr->metric,
2952 mtype, aggr->mtype,
2953 &aggr->p);
2954
c405b00f 2955 aggr_lsa = ospf6_originate_type5_type7_lsas(aggr->route,
c3a70f65 2956 ospf6);
4dc43886
MR
2957 if (aggr_lsa)
2958 SET_FLAG(aggr->aggrflags,
2959 OSPF6_EXTERNAL_AGGRT_ORIGINATED);
2960 }
2961
2962 return;
2963 }
2964
2965 /* If the external route prefix same as aggregate route
2966 * and if external route is already originated as TYPE-5
4e0702dc 2967 * then just update the aggr info and remove the route info
4dc43886 2968 */
78982818 2969 if (lsa && prefix_same(&aggr->p, &rt->prefix)) {
4dc43886 2970 if (IS_OSPF6_DEBUG_AGGR)
4e0702dc
MR
2971 zlog_debug(
2972 "%s: Route prefix is same as aggr so no need to re-originate LSA(%pFX)",
2973 __PRETTY_FUNCTION__, &aggr->p);
4dc43886 2974
4dc43886 2975 aggr->id = info->id;
4e0702dc
MR
2976 info->id = 0;
2977 rt->path.origin.id = 0;
2978
2979 ospf6_summary_add_aggr_route_and_blackhole(ospf6, aggr);
2980
4dc43886 2981 SET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED);
4e0702dc 2982
4dc43886
MR
2983 return;
2984 }
2985
c405b00f 2986 ospf6_originate_new_aggr_lsa(ospf6, aggr);
4dc43886
MR
2987}
2988
2989static void ospf6_aggr_handle_external_info(void *data)
2990{
2991 struct ospf6_route *rt = (struct ospf6_route *)data;
2992 struct ospf6_external_aggr_rt *aggr = NULL;
2993 struct ospf6_lsa *lsa = NULL;
2994 struct ospf6_external_info *info;
2995 struct ospf6 *ospf6 = NULL;
4dc43886
MR
2996
2997 rt->aggr_route = NULL;
2998
2999 rt->to_be_processed = true;
3000
3001 if (IS_OSPF6_DEBUG_ASBR || IS_OSPF6_DEBUG_ORIGINATE(AS_EXTERNAL))
3002 zlog_debug("%s: Handle external route for origination/refresh (%pFX)",
3003 __func__,
3004 &rt->prefix);
3005
ad21f6c2 3006 ospf6 = rt->ospf6;
4dc43886
MR
3007 assert(ospf6);
3008
3009 aggr = ospf6_external_aggr_match(ospf6,
3010 &rt->prefix);
3011 if (aggr) {
3012 ospf6_originate_summary_lsa(ospf6, aggr, rt);
3013 return;
3014 }
3015
3016 info = rt->route_option;
3017 if (info->id) {
3018 lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
c3a70f65
MR
3019 htonl(info->id), ospf6->router_id,
3020 ospf6->lsdb);
4dc43886
MR
3021 if (lsa) {
3022 if (IS_OSPF6_DEBUG_AGGR)
c3a70f65
MR
3023 zlog_debug("%s: LSA found, refresh it",
3024 __func__);
4dc43886 3025 THREAD_OFF(lsa->refresh);
907a2395
DS
3026 event_add_event(master, ospf6_lsa_refresh, lsa, 0,
3027 &lsa->refresh);
4dc43886
MR
3028 return;
3029 }
3030 }
3031
3032 info->id = ospf6->external_id++;
3033 rt->path.origin.id = htonl(info->id);
3034
c3a70f65 3035 (void)ospf6_originate_type5_type7_lsas(rt, ospf6);
4dc43886
MR
3036}
3037
a28474d3
MN
3038void ospf6_asbr_summary_config_delete(struct ospf6 *ospf6,
3039 struct route_node *rn)
4dc43886
MR
3040{
3041 struct ospf6_external_aggr_rt *aggr = rn->info;
3042
3043 if (IS_OSPF6_DEBUG_AGGR)
3044 zlog_debug("%s: Deleting Aggregate route (%pFX)",
3045 __func__,
3046 &aggr->p);
3047
c405b00f 3048 ospf6_asbr_summary_remove_lsa_and_route(ospf6, aggr);
4dc43886
MR
3049
3050 rn->info = NULL;
3051 route_unlock_node(rn);
3052}
3053
78982818
MR
3054static int
3055ospf6_handle_external_aggr_modify(struct ospf6 *ospf6,
3056 struct ospf6_external_aggr_rt *aggr)
4dc43886 3057{
78982818
MR
3058 struct ospf6_lsa *lsa = NULL;
3059 struct ospf6_as_external_lsa *asel = NULL;
3060 struct ospf6_route *rt_aggr;
4dc43886 3061 unsigned int metric = 0;
78982818 3062 route_tag_t tag = 0;
4dc43886
MR
3063 int mtype;
3064
78982818
MR
3065 lsa = ospf6_lsdb_lookup(
3066 htons(OSPF6_LSTYPE_AS_EXTERNAL),
3067 htonl(aggr->id), ospf6->router_id,
3068 ospf6->lsdb);
3069 if (!lsa) {
3070 zlog_warn(
3071 "%s: Could not refresh/originate %pFX",
3072 __func__,
3073 &aggr->p);
3074
3075 return OSPF6_FAILURE;
3076 }
3077
3078 asel = (struct ospf6_as_external_lsa *)
3079 OSPF6_LSA_HEADER_END(lsa->header);
3080 metric = (unsigned long)OSPF6_ASBR_METRIC(asel);
3081 tag = ospf6_as_external_lsa_get_tag(lsa);
3082 mtype = CHECK_FLAG(asel->bits_metric,
3083 OSPF6_ASBR_BIT_E) ? 2 : 1;
3084
3085 /* Fill all the details for advertisement */
3086 ospf6_fill_aggr_route_details(ospf6, aggr);
3087 rt_aggr = aggr->route;
3088 /* If tag/metric/metric-type modified , then
3089 * re-originate the route with modified
3090 * tag/metric/metric-type details.
3091 */
3092 if ((tag != aggr->tag)
3093 || (metric
3094 != (unsigned int)rt_aggr->path.cost)
3095 || (mtype
3096 != aggr->mtype)) {
3097 if (IS_OSPF6_DEBUG_AGGR)
3098 zlog_debug(
3099 "%s: Changed tag(old:%d new:%d)/metric(o:%u n:%d)/mtype(o:%d n:%d),So refresh the summary route.(%pFX)",
3100 __func__, tag,
3101 aggr->tag,
3102 metric,
3103 (unsigned int)rt_aggr->path.cost,
3104 mtype, aggr->mtype,
3105 &aggr->p);
3106
3107 (void)ospf6_originate_type5_type7_lsas(
3108 aggr->route,
3109 ospf6);
3110 }
3111
3112 return OSPF6_SUCCESS;
3113}
3114
3115static void ospf6_handle_external_aggr_update(struct ospf6 *ospf6)
3116{
3117 struct route_node *rn = NULL;
3118 int ret;
3119
4dc43886
MR
3120 if (IS_OSPF6_DEBUG_AGGR)
3121 zlog_debug("%s: Process modified aggregators.", __func__);
3122
3123 for (rn = route_top(ospf6->rt_aggr_tbl); rn; rn = route_next(rn)) {
3124 struct ospf6_external_aggr_rt *aggr;
4dc43886
MR
3125
3126 if (!rn->info)
3127 continue;
3128
3129 aggr = rn->info;
3130
3131 if (aggr->action == OSPF6_ROUTE_AGGR_DEL) {
3132 aggr->action = OSPF6_ROUTE_AGGR_NONE;
3133 ospf6_asbr_summary_config_delete(ospf6, rn);
3134
d8bc11a5
DS
3135 hash_clean_and_free(&aggr->match_extnl_hash,
3136 ospf6_aggr_handle_external_info);
4dc43886 3137
4dc43886
MR
3138 XFREE(MTYPE_OSPF6_EXTERNAL_RT_AGGR, aggr);
3139
3140 } else if (aggr->action == OSPF6_ROUTE_AGGR_MODIFY) {
3141
3142 aggr->action = OSPF6_ROUTE_AGGR_NONE;
3143
3144 /* Check if tag/metric/metric-type modified */
3145 if (CHECK_FLAG(aggr->aggrflags,
3146 OSPF6_EXTERNAL_AGGRT_ORIGINATED)
3147 && !CHECK_FLAG(aggr->aggrflags,
3148 OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE)) {
3149
78982818
MR
3150 ret = ospf6_handle_external_aggr_modify(ospf6,
3151 aggr);
3152 if (ret == OSPF6_FAILURE)
4dc43886 3153 continue;
4dc43886
MR
3154 }
3155
3156 /* Advertise option modified ?
3157 * If so, handled it here.
3158 */
3159 ospf6_aggr_handle_advertise_change(ospf6, aggr);
3160 }
3161 }
3162}
3163
3164static void ospf6_aggr_unlink_external_info(void *data)
3165{
3166 struct ospf6_route *rt = (struct ospf6_route *)data;
3167
3168 rt->aggr_route = NULL;
3169
3170 rt->to_be_processed = true;
3171}
3172
3173void ospf6_external_aggregator_free(struct ospf6_external_aggr_rt *aggr)
3174{
d8bc11a5
DS
3175 hash_clean_and_free(&aggr->match_extnl_hash,
3176 ospf6_aggr_unlink_external_info);
4dc43886
MR
3177
3178 if (IS_OSPF6_DEBUG_AGGR)
3179 zlog_debug("%s: Release the aggregator Address(%pFX)",
3180 __func__,
3181 &aggr->p);
3182
4dc43886
MR
3183 XFREE(MTYPE_OSPF6_EXTERNAL_RT_AGGR, aggr);
3184}
3185
3186static void
3187ospf6_delete_all_marked_aggregators(struct ospf6 *ospf6)
3188{
3189 struct route_node *rn = NULL;
3190 struct ospf6_external_aggr_rt *aggr;
3191
3192 /* Loop through all the aggregators, Delete all aggregators
3193 * which are marked as DELETE. Set action to NONE for remaining
3194 * aggregators
3195 */
78982818
MR
3196 for (rn = route_top(ospf6->rt_aggr_tbl); rn; rn = route_next(rn)) {
3197 if (!rn->info)
3198 continue;
4dc43886 3199
78982818
MR
3200 aggr = rn->info;
3201
3202 if (aggr->action != OSPF6_ROUTE_AGGR_DEL) {
3203 aggr->action = OSPF6_ROUTE_AGGR_NONE;
3204 continue;
4dc43886 3205 }
78982818
MR
3206 ospf6_asbr_summary_config_delete(ospf6, rn);
3207 ospf6_external_aggregator_free(aggr);
3208 }
4dc43886
MR
3209}
3210
3211static void ospf6_handle_exnl_rt_after_aggr_del(struct ospf6 *ospf6,
3212 struct ospf6_route *rt)
3213{
3214 struct ospf6_lsa *lsa;
3215
3216 /* Process only marked external routes.
3217 * These routes were part of a deleted
3218 * aggregator.So, originate now.
3219 */
3220 if (!rt->to_be_processed)
3221 return;
3222
3223 rt->to_be_processed = false;
3224
3225 lsa = ospf6_find_external_lsa(ospf6, &rt->prefix);
3226
3227 if (lsa) {
3228 THREAD_OFF(lsa->refresh);
907a2395
DS
3229 event_add_event(master, ospf6_lsa_refresh, lsa, 0,
3230 &lsa->refresh);
c3a70f65 3231 } else {
4dc43886
MR
3232 if (IS_OSPF6_DEBUG_AGGR)
3233 zlog_debug("%s: Originate external route(%pFX)",
3234 __func__,
3235 &rt->prefix);
3236
c3a70f65 3237 (void)ospf6_originate_type5_type7_lsas(rt, ospf6);
4dc43886
MR
3238 }
3239}
3240
3241static void ospf6_handle_aggregated_exnl_rt(struct ospf6 *ospf6,
3242 struct ospf6_external_aggr_rt *aggr,
3243 struct ospf6_route *rt)
3244{
3245 struct ospf6_lsa *lsa;
3246 struct ospf6_as_external_lsa *ext_lsa;
3247 struct ospf6_external_info *info;
3248
3249 /* Handling the case where the external route prefix
3250 * and aggegate prefix is same
bbf5104c 3251 * If same don't flush the originated external LSA.
4dc43886 3252 */
78982818 3253 if (prefix_same(&aggr->p, &rt->prefix)) {
4dc43886 3254 if (IS_OSPF6_DEBUG_AGGR)
bbf5104c 3255 zlog_debug("%s: External Route prefix same as Aggregator(%pFX), so don't flush.",
4dc43886
MR
3256 __func__,
3257 &rt->prefix);
3258
3259 return;
3260 }
3261
3262 info = rt->route_option;
3263 assert(info);
3264
3265 lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
3266 htonl(info->id), ospf6->router_id, ospf6->lsdb);
3267 if (lsa) {
3268 ext_lsa = (struct ospf6_as_external_lsa
3269 *)((char *)(lsa->header)
3270 + sizeof(struct ospf6_lsa_header));
3271
3272 if (rt->prefix.prefixlen != ext_lsa->prefix.prefix_length)
3273 return;
3274
3275 ospf6_external_lsa_purge(ospf6, lsa);
3276
3277 /* Resetting the ID of route */
3278 rt->path.origin.id = 0;
3279 info->id = 0;
3280 }
3281}
3282
3283static void
3284ospf6_handle_external_aggr_add(struct ospf6 *ospf6)
3285{
3286 struct ospf6_route *rt = NULL;
3287 struct ospf6_external_info *ei = NULL;
3288 struct ospf6_external_aggr_rt *aggr;
3289
3290 /* Delete all the aggregators which are marked as
3291 * OSPF6_ROUTE_AGGR_DEL.
3292 */
3293 ospf6_delete_all_marked_aggregators(ospf6);
3294
c3a70f65
MR
3295 for (rt = ospf6_route_head(ospf6->external_table); rt;
3296 rt = ospf6_route_next(rt)) {
4dc43886 3297 ei = rt->route_option;
78982818
MR
3298 if (ei == NULL)
3299 continue;
4dc43886 3300
78982818
MR
3301 if (is_default_prefix(&rt->prefix))
3302 continue;
4dc43886 3303
78982818
MR
3304 aggr = ospf6_external_aggr_match(ospf6,
3305 &rt->prefix);
4dc43886 3306
78982818
MR
3307 /* If matching aggregator found, Add
3308 * the external route refrenace to the
3309 * aggregator and originate the aggr
3310 * route if it is advertisable.
3311 * flush the external LSA if it is
3312 * already originated for this external
3313 * prefix.
3314 */
3315 if (aggr) {
3316 ospf6_originate_summary_lsa(ospf6, aggr, rt);
4dc43886 3317
78982818
MR
3318 /* All aggregated external rts
3319 * are handled here.
4dc43886 3320 */
78982818
MR
3321 ospf6_handle_aggregated_exnl_rt(
3322 ospf6, aggr, rt);
3323 continue;
4dc43886 3324 }
78982818
MR
3325
3326 /* External routes which are only out
3327 * of aggregation will be handled here.
3328 */
3329 ospf6_handle_exnl_rt_after_aggr_del(
3330 ospf6, rt);
4dc43886
MR
3331 }
3332}
3333
e6685141 3334static void ospf6_asbr_summary_process(struct event *thread)
4dc43886
MR
3335{
3336 struct ospf6 *ospf6 = THREAD_ARG(thread);
3337 int operation = 0;
3338
4dc43886
MR
3339 operation = ospf6->aggr_action;
3340
3341 if (IS_OSPF6_DEBUG_AGGR)
3342 zlog_debug("%s: operation:%d",
3343 __func__,
3344 operation);
3345
3346 switch (operation) {
3347 case OSPF6_ROUTE_AGGR_ADD:
3348 ospf6_handle_external_aggr_add(ospf6);
3349 break;
3350 case OSPF6_ROUTE_AGGR_DEL:
3351 case OSPF6_ROUTE_AGGR_MODIFY:
3352 ospf6_handle_external_aggr_update(ospf6);
3353 break;
3354 default:
3355 break;
3356 }
4dc43886
MR
3357}
3358
3359static void
3360ospf6_start_asbr_summary_delay_timer(struct ospf6 *ospf6,
3361 struct ospf6_external_aggr_rt *aggr,
3362 ospf6_aggr_action_t operation)
3363{
3364 aggr->action = operation;
3365
5f6eaa9b 3366 if (event_is_scheduled(ospf6->t_external_aggr)) {
4dc43886
MR
3367 if (ospf6->aggr_action == OSPF6_ROUTE_AGGR_ADD) {
3368
3369 if (IS_OSPF6_DEBUG_AGGR)
3370 zlog_debug("%s: Not required to restart timer,set is already added.",
3371 __func__);
3372 return;
3373 }
3374
3375 if (operation == OSPF6_ROUTE_AGGR_ADD) {
3376 if (IS_OSPF6_DEBUG_AGGR)
3377 zlog_debug("%s, Restarting Aggregator delay timer.",
3378 __func__);
3379 THREAD_OFF(ospf6->t_external_aggr);
3380 }
3381 }
3382
3383 if (IS_OSPF6_DEBUG_AGGR)
74e8311e 3384 zlog_debug("%s: Start Aggregator delay timer %u(in seconds).",
3385 __func__, ospf6->aggr_delay_interval);
4dc43886
MR
3386
3387 ospf6->aggr_action = operation;
907a2395
DS
3388 event_add_timer(master, ospf6_asbr_summary_process, ospf6,
3389 ospf6->aggr_delay_interval, &ospf6->t_external_aggr);
4dc43886
MR
3390}
3391
3392int ospf6_asbr_external_rt_advertise(struct ospf6 *ospf6,
3393 struct prefix *p)
3394{
3395 struct route_node *rn;
3396 struct ospf6_external_aggr_rt *aggr;
3397
78982818 3398 rn = route_node_lookup(ospf6->rt_aggr_tbl, p);
4dc43886
MR
3399 if (!rn)
3400 return OSPF6_INVALID;
3401
3402 aggr = rn->info;
3403
3404 route_unlock_node(rn);
3405
3406 if (!CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE))
3407 return OSPF6_INVALID;
3408
3409 UNSET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE);
3410
3411 if (!OSPF6_EXTERNAL_RT_COUNT(aggr))
3412 return OSPF6_SUCCESS;
3413
c3a70f65
MR
3414 ospf6_start_asbr_summary_delay_timer(ospf6, aggr,
3415 OSPF6_ROUTE_AGGR_MODIFY);
4dc43886
MR
3416
3417 return OSPF6_SUCCESS;
3418}
3419
74e8311e 3420int ospf6_external_aggr_delay_timer_set(struct ospf6 *ospf6, uint16_t interval)
4dc43886
MR
3421{
3422 ospf6->aggr_delay_interval = interval;
3423
3424 return OSPF6_SUCCESS;
3425}
3426
3427static unsigned int ospf6_external_rt_hash_key(const void *data)
3428{
3429 const struct ospf6_route *rt = data;
3430 unsigned int key = 0;
3431
3432 key = prefix_hash_key(&rt->prefix);
3433 return key;
3434}
3435
3436static bool ospf6_external_rt_hash_cmp(const void *d1, const void *d2)
3437{
3438 const struct ospf6_route *rt1 = d1;
3439 const struct ospf6_route *rt2 = d2;
3440
78982818 3441 return prefix_same(&rt1->prefix, &rt2->prefix);
4dc43886
MR
3442}
3443
3444static struct ospf6_external_aggr_rt *
3445ospf6_external_aggr_new(struct prefix *p)
3446{
3447 struct ospf6_external_aggr_rt *aggr;
3448
78982818
MR
3449 aggr = XCALLOC(MTYPE_OSPF6_EXTERNAL_RT_AGGR,
3450 sizeof(struct ospf6_external_aggr_rt));
4dc43886 3451
4dc43886 3452 prefix_copy(&aggr->p, p);
4dc43886
MR
3453 aggr->metric = -1;
3454 aggr->mtype = DEFAULT_METRIC_TYPE;
3455 aggr->match_extnl_hash = hash_create(ospf6_external_rt_hash_key,
3456 ospf6_external_rt_hash_cmp,
3457 "Ospf6 external route hash");
3458 return aggr;
3459}
3460
3461static void ospf6_external_aggr_add(struct ospf6 *ospf6,
3462 struct ospf6_external_aggr_rt *aggr)
3463{
3464 struct route_node *rn;
3465
3466 if (IS_OSPF6_DEBUG_AGGR)
3467 zlog_debug("%s: Adding Aggregate route to Aggr table (%pFX)",
3468 __func__,
3469 &aggr->p);
3470
78982818 3471 rn = route_node_get(ospf6->rt_aggr_tbl, &aggr->p);
4dc43886
MR
3472 if (rn->info)
3473 route_unlock_node(rn);
3474 else
3475 rn->info = aggr;
3476}
3477
3478int ospf6_asbr_external_rt_no_advertise(struct ospf6 *ospf6,
3479 struct prefix *p)
3480{
3481 struct ospf6_external_aggr_rt *aggr;
3482 route_tag_t tag = 0;
3483
3484 aggr = ospf6_external_aggr_config_lookup(ospf6, p);
3485 if (aggr) {
3486 if (CHECK_FLAG(aggr->aggrflags,
3487 OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE))
3488 return OSPF6_SUCCESS;
3489
3490 SET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE);
3491
3492 aggr->tag = tag;
3493 aggr->metric = -1;
3494
3495 if (!OSPF6_EXTERNAL_RT_COUNT(aggr))
3496 return OSPF6_SUCCESS;
3497
3498 ospf6_start_asbr_summary_delay_timer(ospf6, aggr,
3499 OSPF6_ROUTE_AGGR_MODIFY);
3500 } else {
3501 aggr = ospf6_external_aggr_new(p);
3502
3503 if (!aggr)
3504 return OSPF6_FAILURE;
3505
3506 SET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE);
3507 ospf6_external_aggr_add(ospf6, aggr);
3508 ospf6_start_asbr_summary_delay_timer(ospf6, aggr,
3509 OSPF6_ROUTE_AGGR_ADD);
3510 }
3511
3512 return OSPF6_SUCCESS;
3513}
3514
3515struct ospf6_external_aggr_rt *
3516ospf6_external_aggr_config_lookup(struct ospf6 *ospf6, struct prefix *p)
3517{
3518 struct route_node *rn;
3519
78982818 3520 rn = route_node_lookup(ospf6->rt_aggr_tbl, p);
4dc43886
MR
3521 if (rn) {
3522 route_unlock_node(rn);
3523 return rn->info;
3524 }
3525
3526 return NULL;
3527}
3528
3529
3530int ospf6_external_aggr_config_set(struct ospf6 *ospf6, struct prefix *p,
3531 route_tag_t tag, int metric, int mtype)
3532{
3533 struct ospf6_external_aggr_rt *aggregator;
3534
3535 aggregator = ospf6_external_aggr_config_lookup(ospf6, p);
3536
3537 if (aggregator) {
3538 if (CHECK_FLAG(aggregator->aggrflags,
3539 OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE))
3540 UNSET_FLAG(aggregator->aggrflags,
3541 OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE);
3542 else if ((aggregator->tag == tag)
3543 && (aggregator->metric == metric)
3544 && (aggregator->mtype == mtype))
3545 return OSPF6_SUCCESS;
3546
3547 aggregator->tag = tag;
3548 aggregator->metric = metric;
3549 aggregator->mtype = mtype;
3550
3551 ospf6_start_asbr_summary_delay_timer(ospf6, aggregator,
3552 OSPF6_ROUTE_AGGR_MODIFY);
3553 } else {
3554 aggregator = ospf6_external_aggr_new(p);
3555 if (!aggregator)
3556 return OSPF6_FAILURE;
3557
3558 aggregator->tag = tag;
3559 aggregator->metric = metric;
3560 aggregator->mtype = mtype;
3561
3562 ospf6_external_aggr_add(ospf6, aggregator);
3563 ospf6_start_asbr_summary_delay_timer(ospf6, aggregator,
3564 OSPF6_ROUTE_AGGR_ADD);
3565 }
3566
3567 return OSPF6_SUCCESS;
3568}
3569
3570int ospf6_external_aggr_config_unset(struct ospf6 *ospf6,
3571 struct prefix *p)
3572{
3573 struct route_node *rn;
3574 struct ospf6_external_aggr_rt *aggr;
3575
78982818 3576 rn = route_node_lookup(ospf6->rt_aggr_tbl, p);
4dc43886
MR
3577 if (!rn)
3578 return OSPF6_INVALID;
3579
3580 aggr = rn->info;
3581
3582 route_unlock_node(rn);
3583
3584 if (!OSPF6_EXTERNAL_RT_COUNT(aggr)) {
3585 ospf6_asbr_summary_config_delete(ospf6, rn);
3586 ospf6_external_aggregator_free(aggr);
3587 return OSPF6_SUCCESS;
3588 }
3589
3590 ospf6_start_asbr_summary_delay_timer(ospf6, aggr,
3591 OSPF6_ROUTE_AGGR_DEL);
3592
3593 return OSPF6_SUCCESS;
3594}
3595
3596void ospf6_handle_external_lsa_origination(struct ospf6 *ospf6,
3597 struct ospf6_route *rt,
3598 struct prefix *p)
3599{
3600
3601 struct ospf6_external_aggr_rt *aggr;
3602 struct ospf6_external_info *info;
3603 struct prefix prefix_id;
4dc43886
MR
3604
3605 if (!is_default_prefix(p)) {
3606 aggr = ospf6_external_aggr_match(ospf6,
3607 p);
3608
3609 if (aggr) {
3610
3611 if (IS_OSPF6_DEBUG_AGGR)
3612 zlog_debug("%s: Send Aggregate LSA (%pFX)",
3613 __func__,
3614 &aggr->p);
3615
3616 ospf6_originate_summary_lsa(
3617 ospf6, aggr, rt);
3618
3619 /* Handling the case where the
3620 * external route prefix
3621 * and aggegate prefix is same
bbf5104c 3622 * If same don't flush the
4dc43886
MR
3623 * originated
3624 * external LSA.
3625 */
3626 ospf6_handle_aggregated_exnl_rt(
3627 ospf6, aggr, rt);
3628 return;
3629 }
3630 }
3631
3632 info = rt->route_option;
3633
3634 /* When the info->id = 0, it means it is being originated for the
3635 * first time.
3636 */
3637 if (!info->id) {
3638 info->id = ospf6->external_id++;
c3a70f65 3639 } else {
4dc43886
MR
3640 prefix_id.family = AF_INET;
3641 prefix_id.prefixlen = 32;
3642 prefix_id.u.prefix4.s_addr = htonl(info->id);
3643 }
3644
3645 rt->path.origin.id = htonl(info->id);
3646
3647 if (IS_OSPF6_DEBUG_ASBR) {
c3a70f65
MR
3648 zlog_debug("Advertise new AS-External Id:%pI4 prefix %pFX metric %u",
3649 &prefix_id.u.prefix4, p, rt->path.metric_type);
4dc43886
MR
3650 }
3651
c3a70f65 3652 ospf6_originate_type5_type7_lsas(rt, ospf6);
4dc43886 3653
4dc43886
MR
3654}
3655
3656void ospf6_unset_all_aggr_flag(struct ospf6 *ospf6)
3657{
3658 struct route_node *rn = NULL;
3659 struct ospf6_external_aggr_rt *aggr;
3660
3661 if (IS_OSPF6_DEBUG_AGGR)
3662 zlog_debug("Unset the origination bit for all aggregator");
3663
3664 /* Resetting the running external ID counter so that the origination
c3a70f65
MR
3665 * of external LSAs starts from the beginning 0.0.0.1
3666 */
4dc43886
MR
3667 ospf6->external_id = OSPF6_EXT_INIT_LS_ID;
3668
3669 for (rn = route_top(ospf6->rt_aggr_tbl); rn; rn = route_next(rn)) {
3670 if (!rn->info)
3671 continue;
3672
3673 aggr = rn->info;
3674
3675 UNSET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED);
3676 }
3677}