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