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