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