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