]>
Commit | Line | Data |
---|---|---|
718e3744 | 1 | /* |
2 | * Copyright (C) 2001-2002 Yasuhiro Ohara | |
3 | * | |
4 | * This file is part of GNU Zebra. | |
5 | * | |
6 | * GNU Zebra is free software; you can redistribute it and/or modify it | |
7 | * under the terms of the GNU General Public License as published by the | |
8 | * Free Software Foundation; either version 2, or (at your option) any | |
9 | * later version. | |
10 | * | |
11 | * GNU Zebra is distributed in the hope that it will be useful, but | |
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with GNU Zebra; see the file COPYING. If not, write to the | |
18 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
19 | * Boston, MA 02111-1307, USA. | |
20 | */ | |
21 | ||
22 | #include <zebra.h> | |
23 | ||
24 | #include "log.h" | |
25 | #include "memory.h" | |
26 | #include "prefix.h" | |
27 | #include "command.h" | |
28 | #include "vty.h" | |
29 | #include "routemap.h" | |
30 | #include "table.h" | |
31 | #include "plist.h" | |
32 | #include "thread.h" | |
33 | ||
34 | #include "ospf6_prefix.h" /* xxx for ospf6_asbr.h */ | |
35 | #include "ospf6_lsa.h" /* xxx for ospf6_asbr.h */ | |
36 | #include "ospf6_route.h" /* xxx for ospf6_asbr.h, ospf6_zebra.h */ | |
37 | #include "ospf6_zebra.h" | |
38 | #include "ospf6_asbr.h" | |
39 | #include "ospf6_damp.h" | |
40 | #include "ospf6_top.h" | |
41 | #include "ospf6_lsdb.h" | |
42 | #include "ospf6_proto.h" | |
43 | ||
44 | extern struct thread_master *master; | |
45 | ||
46 | struct route_table *external_table; | |
47 | struct | |
48 | { | |
49 | char *name; | |
50 | struct route_map *map; | |
51 | } rmap [ZEBRA_ROUTE_MAX]; | |
52 | ||
53 | static u_int32_t link_state_id = 0; | |
54 | ||
55 | char * | |
56 | zroute_name[] = | |
57 | { | |
58 | "system", "kernel", "connected", "static", | |
59 | "rip", "ripng", "ospf", "ospf6", "bgp", "unknown" | |
60 | }; | |
61 | char * | |
62 | zroute_abname[] = | |
63 | { | |
64 | "X", "K", "C", "S", "R", "R", "O", "O", "B", "?" | |
65 | }; | |
66 | ||
67 | #define ZROUTE_NAME(x) \ | |
68 | (0 < (x) && (x) < ZEBRA_ROUTE_MAX ? \ | |
69 | zroute_name[(x)] : zroute_name[ZEBRA_ROUTE_MAX]) | |
70 | ||
71 | #define ZROUTE_ABNAME(x) \ | |
72 | (0 < (x) && (x) < ZEBRA_ROUTE_MAX ? \ | |
73 | zroute_abname[(x)] : zroute_abname[ZEBRA_ROUTE_MAX]) | |
74 | ||
75 | /* redistribute function */ | |
76 | void | |
77 | ospf6_asbr_routemap_set (int type, char *mapname) | |
78 | { | |
79 | if (rmap[type].name) | |
80 | free (rmap[type].name); | |
81 | ||
82 | rmap[type].name = strdup (mapname); | |
83 | rmap[type].map = route_map_lookup_by_name (mapname); | |
84 | } | |
85 | ||
86 | void | |
87 | ospf6_asbr_routemap_unset (int type) | |
88 | { | |
89 | if (rmap[type].name) | |
90 | free (rmap[type].name); | |
91 | rmap[type].name = NULL; | |
92 | rmap[type].map = NULL; | |
93 | } | |
94 | ||
95 | void | |
96 | ospf6_asbr_routemap_update () | |
97 | { | |
98 | int i; | |
99 | for (i = 0; i < ZEBRA_ROUTE_MAX; i++) | |
100 | { | |
101 | if (rmap[i].name) | |
102 | rmap[i].map = route_map_lookup_by_name (rmap[i].name); | |
103 | else | |
104 | rmap[i].map = NULL; | |
105 | } | |
106 | } | |
107 | ||
108 | DEFUN (ospf6_redistribute, | |
109 | ospf6_redistribute_cmd, | |
110 | "redistribute (static|kernel|connected|ripng|bgp)", | |
111 | "Redistribute\n" | |
112 | "Static route\n" | |
113 | "Kernel route\n" | |
114 | "Connected route\n" | |
115 | "RIPng route\n" | |
116 | "BGP route\n" | |
117 | ) | |
118 | { | |
119 | int type = 0; | |
120 | ||
121 | if (strncmp (argv[0], "sta", 3) == 0) | |
122 | type = ZEBRA_ROUTE_STATIC; | |
123 | else if (strncmp (argv[0], "ker", 3) == 0) | |
124 | type = ZEBRA_ROUTE_KERNEL; | |
125 | else if (strncmp (argv[0], "con", 3) == 0) | |
126 | type = ZEBRA_ROUTE_CONNECT; | |
127 | else if (strncmp (argv[0], "rip", 3) == 0) | |
128 | type = ZEBRA_ROUTE_RIPNG; | |
129 | else if (strncmp (argv[0], "bgp", 3) == 0) | |
130 | type = ZEBRA_ROUTE_BGP; | |
131 | ||
132 | ospf6_zebra_no_redistribute (type); | |
133 | ospf6_asbr_routemap_unset (type); | |
134 | ospf6_zebra_redistribute (type); | |
135 | return CMD_SUCCESS; | |
136 | } | |
137 | ||
138 | DEFUN (ospf6_redistribute_routemap, | |
139 | ospf6_redistribute_routemap_cmd, | |
140 | "redistribute (static|kernel|connected|ripng|bgp) route-map WORD", | |
141 | "Redistribute\n" | |
142 | "Static routes\n" | |
143 | "Kernel route\n" | |
144 | "Connected route\n" | |
145 | "RIPng route\n" | |
146 | "BGP route\n" | |
147 | "Route map reference\n" | |
148 | "Route map name\n" | |
149 | ) | |
150 | { | |
151 | int type = 0; | |
152 | ||
153 | if (strncmp (argv[0], "sta", 3) == 0) | |
154 | type = ZEBRA_ROUTE_STATIC; | |
155 | else if (strncmp (argv[0], "ker", 3) == 0) | |
156 | type = ZEBRA_ROUTE_KERNEL; | |
157 | else if (strncmp (argv[0], "con", 3) == 0) | |
158 | type = ZEBRA_ROUTE_CONNECT; | |
159 | else if (strncmp (argv[0], "rip", 3) == 0) | |
160 | type = ZEBRA_ROUTE_RIPNG; | |
161 | else if (strncmp (argv[0], "bgp", 3) == 0) | |
162 | type = ZEBRA_ROUTE_BGP; | |
163 | ||
164 | ospf6_zebra_no_redistribute (type); | |
165 | ospf6_asbr_routemap_set (type, argv[1]); | |
166 | ospf6_zebra_redistribute (type); | |
167 | return CMD_SUCCESS; | |
168 | } | |
169 | ||
170 | DEFUN (no_ospf6_redistribute, | |
171 | no_ospf6_redistribute_cmd, | |
172 | "no redistribute (static|kernel|connected|ripng|bgp)", | |
173 | NO_STR | |
174 | "Redistribute\n" | |
175 | "Static route\n" | |
176 | "Kernel route\n" | |
177 | "Connected route\n" | |
178 | "RIPng route\n" | |
179 | "BGP route\n" | |
180 | ) | |
181 | { | |
182 | int type = 0; | |
183 | struct route_node *node; | |
184 | struct ospf6_external_route *route; | |
185 | struct ospf6_external_info *info, *info_next = NULL; | |
186 | ||
187 | if (strncmp (argv[0], "sta", 3) == 0) | |
188 | type = ZEBRA_ROUTE_STATIC; | |
189 | else if (strncmp (argv[0], "ker", 3) == 0) | |
190 | type = ZEBRA_ROUTE_KERNEL; | |
191 | else if (strncmp (argv[0], "con", 3) == 0) | |
192 | type = ZEBRA_ROUTE_CONNECT; | |
193 | else if (strncmp (argv[0], "rip", 3) == 0) | |
194 | type = ZEBRA_ROUTE_RIPNG; | |
195 | else if (strncmp (argv[0], "bgp", 3) == 0) | |
196 | type = ZEBRA_ROUTE_BGP; | |
197 | ||
198 | ospf6_zebra_no_redistribute (type); | |
199 | ospf6_asbr_routemap_unset (type); | |
200 | ||
201 | /* remove redistributed route */ | |
202 | for (node = route_top (external_table); node; node = route_next (node)) | |
203 | { | |
204 | route = node->info; | |
205 | if (! route) | |
206 | continue; | |
207 | for (info = route->info_head; info; info = info_next) | |
208 | { | |
209 | info_next = info->next; | |
210 | if (info->type != type) | |
211 | continue; | |
212 | ospf6_asbr_route_remove (info->type, info->ifindex, | |
213 | &route->prefix); | |
214 | } | |
215 | } | |
216 | ||
217 | return CMD_SUCCESS; | |
218 | } | |
219 | ||
220 | ||
221 | int | |
222 | ospf6_redistribute_config_write (struct vty *vty) | |
223 | { | |
224 | int i; | |
225 | ||
226 | for (i = 0; i < ZEBRA_ROUTE_MAX; i++) | |
227 | { | |
228 | if (i == ZEBRA_ROUTE_OSPF6) | |
229 | continue; | |
230 | ||
231 | if (! ospf6_zebra_is_redistribute (i)) | |
232 | continue; | |
233 | ||
234 | if (rmap[i].map) | |
235 | vty_out (vty, " redistribute %s route-map %s%s", | |
236 | ZROUTE_NAME(i), rmap[i].name, VTY_NEWLINE); | |
237 | else | |
238 | vty_out (vty, " redistribute %s%s", | |
239 | ZROUTE_NAME(i), VTY_NEWLINE); | |
240 | } | |
241 | ||
242 | return 0; | |
243 | } | |
244 | ||
245 | void | |
246 | ospf6_redistribute_show_config (struct vty *vty) | |
247 | { | |
248 | int i; | |
249 | ||
250 | if (! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_SYSTEM) && | |
251 | ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_KERNEL) && | |
252 | ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_STATIC) && | |
253 | ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_RIPNG) && | |
254 | ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_BGP)) | |
255 | return; | |
256 | ||
257 | vty_out (vty, " Redistributing External Routes from,%s", VTY_NEWLINE); | |
258 | for (i = 0; i < ZEBRA_ROUTE_MAX; i++) | |
259 | { | |
260 | if (i == ZEBRA_ROUTE_OSPF6) | |
261 | continue; | |
262 | if (! ospf6_zebra_is_redistribute (i)) | |
263 | continue; | |
264 | ||
265 | if (rmap[i].map) | |
266 | vty_out (vty, " %s with route-map %s%s", | |
267 | ZROUTE_NAME(i), rmap[i].name, VTY_NEWLINE); | |
268 | else | |
269 | vty_out (vty, " %s%s", ZROUTE_NAME(i), VTY_NEWLINE); | |
270 | } | |
271 | } | |
272 | ||
273 | /* AS External LSA origination */ | |
274 | int | |
275 | ospf6_asbr_external_lsa_originate (struct thread *thread) | |
276 | { | |
277 | struct ospf6_external_info *info; | |
278 | char buffer [MAXLSASIZE]; | |
279 | struct ospf6_lsa_as_external *e; | |
280 | char *p; | |
281 | ||
282 | info = THREAD_ARG (thread); | |
283 | ||
284 | /* clear thread */ | |
285 | info->thread_originate = NULL; | |
286 | ||
287 | if (info->is_removed) | |
288 | { | |
289 | if (IS_OSPF6_DUMP_ASBR) | |
290 | { | |
291 | char pbuf[64]; | |
292 | prefix2str (&info->route->prefix, pbuf, sizeof (pbuf)); | |
293 | zlog_info ("ASBR: quit redistribution %s: state is down", | |
294 | pbuf); | |
295 | } | |
296 | return 0; | |
297 | } | |
298 | ||
299 | /* prepare buffer */ | |
300 | memset (buffer, 0, sizeof (buffer)); | |
301 | e = (struct ospf6_lsa_as_external *) buffer; | |
302 | p = (char *) (e + 1); | |
303 | ||
304 | if (info->metric_type == 2) | |
305 | SET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_E); /* type2 */ | |
306 | else | |
307 | UNSET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_E); /* type1, default */ | |
308 | ||
309 | /* forwarding address */ | |
310 | if (! IN6_IS_ADDR_UNSPECIFIED (&info->forwarding)) | |
311 | SET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_F); | |
312 | else | |
313 | UNSET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_F); | |
314 | ||
315 | /* external route tag */ | |
316 | UNSET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_T); | |
317 | ||
318 | /* set metric. note: related to E bit */ | |
319 | OSPF6_ASBR_METRIC_SET (e, info->metric); | |
320 | ||
321 | /* prefixlen */ | |
322 | e->prefix.prefix_length = info->route->prefix.prefixlen; | |
323 | ||
324 | /* PrefixOptions */ | |
325 | e->prefix.prefix_options = info->prefix_options; | |
326 | ||
327 | /* don't use refer LS-type */ | |
328 | e->prefix.prefix_refer_lstype = htons (0); | |
329 | ||
330 | /* set Prefix */ | |
331 | memcpy (p, &info->route->prefix.u.prefix6, | |
332 | OSPF6_PREFIX_SPACE (info->route->prefix.prefixlen)); | |
333 | ospf6_prefix_apply_mask (&e->prefix); | |
334 | p += OSPF6_PREFIX_SPACE (info->route->prefix.prefixlen); | |
335 | ||
336 | /* Forwarding address */ | |
337 | if (CHECK_FLAG (e->bits_metric, OSPF6_ASBR_BIT_F)) | |
338 | { | |
339 | memcpy (p, &info->forwarding, sizeof (struct in6_addr)); | |
340 | p += sizeof (struct in6_addr); | |
341 | } | |
342 | ||
343 | /* External Route Tag */ | |
344 | if (CHECK_FLAG (e->bits_metric, OSPF6_ASBR_BIT_T)) | |
345 | { | |
346 | /* xxx */ | |
347 | } | |
348 | ||
349 | ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_AS_EXTERNAL), | |
350 | htonl (info->id), ospf6->router_id, | |
351 | (char *) buffer, p - buffer, ospf6); | |
352 | return 0; | |
353 | } | |
354 | ||
355 | int | |
356 | ospf6_asbr_schedule_external (void *data) | |
357 | { | |
358 | struct ospf6_external_info *info = data; | |
359 | u_long elasped_time, time = 0; | |
360 | ||
361 | if (info->thread_originate) | |
362 | { | |
363 | if (IS_OSPF6_DUMP_ASBR) | |
364 | { | |
365 | char pbuf[64]; | |
366 | prefix2str (&info->route->prefix, pbuf, sizeof (pbuf)); | |
367 | zlog_info ("ASBR: schedule redistribution %s: another thread", | |
368 | pbuf); | |
369 | } | |
370 | return 0; | |
371 | } | |
372 | ||
373 | elasped_time = | |
374 | ospf6_lsa_has_elasped (htons (OSPF6_LSA_TYPE_AS_EXTERNAL), | |
375 | htonl (info->id), ospf6->router_id, ospf6); | |
376 | if (elasped_time < OSPF6_MIN_LS_INTERVAL) | |
377 | time = OSPF6_MIN_LS_INTERVAL - elasped_time; | |
378 | else | |
379 | time = 0; | |
380 | ||
381 | //if (IS_OSPF6_DUMP_ASBR) | |
382 | { | |
383 | char pbuf[64]; | |
384 | prefix2str (&info->route->prefix, pbuf, sizeof (pbuf)); | |
385 | zlog_info ("ASBR: schedule redistribution %s as LS-ID %ld after %lu sec", | |
386 | pbuf, (u_long) info->id, time); | |
387 | } | |
388 | ||
389 | if (time) | |
390 | info->thread_originate = | |
391 | thread_add_timer (master, ospf6_asbr_external_lsa_originate, info, time); | |
392 | else | |
393 | info->thread_originate = | |
394 | thread_add_timer (master, ospf6_asbr_external_lsa_originate, info, 0); | |
395 | ||
396 | return 0; | |
397 | } | |
398 | ||
399 | int | |
400 | ospf6_asbr_external_lsa_flush (void *data) | |
401 | { | |
402 | struct ospf6_lsa *lsa = data; | |
403 | if (lsa) | |
404 | ospf6_lsa_premature_aging (lsa); | |
405 | return 0; | |
406 | } | |
407 | ||
408 | int | |
409 | ospf6_asbr_external_lsa_refresh (void *data) | |
410 | { | |
411 | struct ospf6_lsa *lsa = data; | |
412 | struct ospf6_lsa_as_external *e; | |
413 | struct prefix prefix; | |
414 | struct route_node *node; | |
415 | struct ospf6_external_route *route; | |
416 | struct ospf6_external_info *info; | |
417 | ||
418 | if (IS_OSPF6_DUMP_ASBR) | |
419 | zlog_info ("ASBR: refresh %s", lsa->str); | |
420 | ||
421 | e = (struct ospf6_lsa_as_external *) (lsa->header + 1); | |
422 | ospf6_prefix_in6_addr (&e->prefix, &prefix.u.prefix6); | |
423 | prefix.prefixlen = e->prefix.prefix_length; | |
424 | prefix.family = AF_INET6; | |
425 | apply_mask_ipv6 ((struct prefix_ipv6 *) &prefix); | |
426 | ||
427 | node = route_node_lookup (external_table, &prefix); | |
428 | if (! node || ! node->info) | |
429 | { | |
430 | char pname[64]; | |
431 | ||
432 | prefix2str (&prefix, pname, sizeof (pname)); | |
433 | if (IS_OSPF6_DUMP_ASBR) | |
434 | zlog_info ("ASBR: could not find %s: premature age", pname); | |
435 | ospf6_lsa_premature_aging (lsa); | |
436 | return 0; | |
437 | } | |
438 | ||
439 | /* find external_info */ | |
440 | route = node->info; | |
441 | for (info = route->info_head; info; info = info->next) | |
442 | { | |
443 | if (lsa->header->id == htonl (info->id)) | |
444 | break; | |
445 | } | |
446 | ||
447 | if (info) | |
448 | ospf6_asbr_schedule_external (info); | |
449 | else | |
450 | ospf6_lsa_premature_aging (lsa); | |
451 | ||
452 | return 0; | |
453 | } | |
454 | ||
455 | void | |
456 | ospf6_asbr_route_add (int type, int ifindex, struct prefix *prefix, | |
457 | u_int nexthop_num, struct in6_addr *nexthop) | |
458 | { | |
459 | int ret; | |
460 | struct route_node *node; | |
461 | struct ospf6_external_route *route; | |
462 | struct ospf6_external_info *info, tinfo; | |
463 | ||
464 | if (! ospf6_zebra_is_redistribute (type)) | |
465 | return; | |
466 | ||
467 | /* apply route-map */ | |
468 | memset (&tinfo, 0, sizeof (struct ospf6_external_info)); | |
469 | if (rmap[type].map) | |
470 | { | |
471 | ret = route_map_apply (rmap[type].map, prefix, RMAP_OSPF6, &tinfo); | |
472 | if (ret == RMAP_DENYMATCH) | |
473 | { | |
474 | if (IS_OSPF6_DUMP_ASBR) | |
475 | zlog_info ("ASBR: denied by route-map %s", rmap[type].name); | |
476 | return; | |
477 | } | |
478 | } | |
479 | ||
480 | node = route_node_get (external_table, prefix); | |
481 | route = node->info; | |
482 | ||
483 | if (! route) | |
484 | { | |
485 | route = XMALLOC (MTYPE_OSPF6_EXTERNAL_INFO, | |
486 | sizeof (struct ospf6_external_route)); | |
487 | memset (route, 0, sizeof (struct ospf6_external_route)); | |
488 | ||
489 | memcpy (&route->prefix, prefix, sizeof (struct prefix)); | |
490 | ||
491 | node->info = route; | |
492 | route->node = node; | |
493 | } | |
494 | ||
495 | for (info = route->info_head; info; info = info->next) | |
496 | { | |
497 | if (info->type == type && info->ifindex == ifindex) | |
498 | break; | |
499 | } | |
500 | ||
501 | if (! info) | |
502 | { | |
503 | info = XMALLOC (MTYPE_OSPF6_EXTERNAL_INFO, | |
504 | sizeof (struct ospf6_external_info)); | |
505 | memset (info, 0, sizeof (struct ospf6_external_info)); | |
506 | ||
507 | info->route = route; | |
508 | /* add tail */ | |
509 | info->prev = route->info_tail; | |
510 | if (route->info_tail) | |
511 | route->info_tail->next = info; | |
512 | else | |
513 | route->info_head = info; | |
514 | route->info_tail = info; | |
515 | ||
516 | info->id = link_state_id++; | |
517 | } | |
518 | ||
519 | /* copy result of route-map */ | |
520 | info->metric_type = tinfo.metric_type; | |
521 | info->metric = tinfo.metric; | |
522 | memcpy (&info->forwarding, &tinfo.forwarding, | |
523 | sizeof (struct in6_addr)); | |
524 | ||
525 | info->type = type; | |
526 | info->ifindex = ifindex; | |
527 | ||
528 | if (nexthop_num && nexthop) | |
529 | { | |
530 | info->nexthop_num = nexthop_num; | |
531 | ||
532 | if (info->nexthop) | |
533 | XFREE (MTYPE_OSPF6_EXTERNAL_INFO, info->nexthop); | |
534 | ||
535 | info->nexthop = (struct in6_addr *) | |
536 | XMALLOC (MTYPE_OSPF6_EXTERNAL_INFO, | |
537 | nexthop_num * sizeof (struct in6_addr)); | |
538 | memcpy (info->nexthop, nexthop, | |
539 | nexthop_num * sizeof (struct in6_addr)); | |
540 | } | |
541 | ||
542 | info->is_removed = 0; | |
543 | ||
544 | //if (IS_OSPF6_DUMP_ASBR) | |
545 | { | |
546 | char pbuf[64]; | |
547 | struct timeval now; | |
548 | prefix2str (&info->route->prefix, pbuf, sizeof (pbuf)); | |
549 | gettimeofday (&now, NULL); | |
550 | zlog_info ("ASBR: start redistributing %s as LS-ID %ld: %ld.%06ld", | |
551 | pbuf, (u_long) info->id, now.tv_sec, now.tv_usec); | |
552 | } | |
553 | ||
554 | #ifdef HAVE_OSPF6_DAMP | |
555 | ospf6_damp_event_up (OSPF6_DAMP_TYPE_ROUTE, prefix, | |
556 | ospf6_asbr_schedule_external, info); | |
557 | #else /*HAVE_OSPF6_DAMP*/ | |
558 | ospf6_asbr_schedule_external (info); | |
559 | #endif /*HAVE_OSPF6_DAMP*/ | |
560 | } | |
561 | ||
562 | void | |
563 | ospf6_asbr_route_remove (int type, int ifindex, struct prefix *prefix) | |
564 | { | |
565 | struct route_node *node; | |
566 | struct ospf6_external_route *route; | |
567 | struct ospf6_external_info *info; | |
568 | struct ospf6_lsa *lsa; | |
569 | ||
570 | node = route_node_get (external_table, prefix); | |
571 | route = node->info; | |
572 | ||
573 | if (! route) | |
574 | return; | |
575 | ||
576 | for (info = route->info_head; info; info = info->next) | |
577 | { | |
578 | if (info->type == type && info->ifindex == ifindex) | |
579 | break; | |
580 | } | |
581 | ||
582 | if (! info) | |
583 | return; | |
584 | ||
585 | //if (IS_OSPF6_DUMP_ASBR) | |
586 | { | |
587 | char pbuf[64]; | |
588 | struct timeval now; | |
589 | prefix2str (&info->route->prefix, pbuf, sizeof (pbuf)); | |
590 | gettimeofday (&now, NULL); | |
591 | zlog_info ("ASBR: quit redistributing %s as LS-ID %ld: %ld.%06ld", | |
592 | pbuf, (u_long) info->id, now.tv_sec, now.tv_usec); | |
593 | } | |
594 | ||
595 | if (info->thread_originate) | |
596 | thread_cancel (info->thread_originate); | |
597 | info->thread_originate = NULL; | |
598 | ||
599 | lsa = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_AS_EXTERNAL), | |
600 | htonl (info->id), ospf6->router_id, ospf6); | |
601 | #ifdef HAVE_OSPF6_DAMP | |
602 | ospf6_damp_event_down (OSPF6_DAMP_TYPE_ROUTE, &info->route->prefix, | |
603 | ospf6_asbr_external_lsa_flush, lsa); | |
604 | #else /*HAVE_OSPF6_DAMP*/ | |
605 | ospf6_asbr_external_lsa_flush (lsa); | |
606 | #endif /*HAVE_OSPF6_DAMP*/ | |
607 | ||
608 | #if 1 | |
609 | info->is_removed = 1; | |
610 | #else | |
611 | /* remove from route */ | |
612 | if (info->prev) | |
613 | info->prev->next = info->next; | |
614 | else | |
615 | info->route->info_head = info->next; | |
616 | if (info->next) | |
617 | info->next->prev = info->prev; | |
618 | else | |
619 | info->route->info_tail = info->prev; | |
620 | ||
621 | /* if no info, free route */ | |
622 | if (! info->route->info_head && ! info->route->info_tail) | |
623 | { | |
624 | info->route->node->info = NULL; | |
625 | free (info->route); | |
626 | } | |
627 | ||
628 | if (info->nexthop) | |
629 | free (info->nexthop); | |
630 | free (info); | |
631 | #endif /*0*/ | |
632 | } | |
633 | ||
634 | void | |
635 | ospf6_asbr_external_lsa_add (struct ospf6_lsa *lsa) | |
636 | { | |
637 | struct ospf6_lsa_as_external *external; | |
638 | struct prefix_ls asbr_id; | |
639 | struct ospf6_route_req asbr_entry; | |
640 | struct ospf6_route_req request; | |
641 | ||
642 | external = OSPF6_LSA_HEADER_END (lsa->header); | |
643 | ||
644 | if (IS_LSA_MAXAGE (lsa)) | |
645 | { | |
646 | if (IS_OSPF6_DUMP_ASBR) | |
647 | zlog_info ("ASBR: maxage external lsa: %s seq: %lx", | |
648 | lsa->str, (u_long)ntohl (lsa->header->seqnum)); | |
649 | ospf6_asbr_external_lsa_remove (lsa); | |
650 | return; | |
651 | } | |
652 | ||
653 | if (IS_OSPF6_DUMP_ASBR) | |
654 | zlog_info ("ASBR: new external lsa: %s seq: %lx", | |
655 | lsa->str, (u_long)ntohl (lsa->header->seqnum)); | |
656 | ||
657 | if (lsa->header->adv_router == ospf6->router_id) | |
658 | { | |
659 | if (IS_OSPF6_DUMP_ASBR) | |
660 | zlog_info ("ASBR: my external LSA, ignore"); | |
661 | return; | |
662 | } | |
663 | ||
664 | if (OSPF6_ASBR_METRIC (external) == LS_INFINITY) | |
665 | { | |
666 | if (IS_OSPF6_DUMP_ASBR) | |
667 | zlog_info ("ASBR: metric is infinity, ignore"); | |
668 | return; | |
669 | } | |
670 | ||
671 | memset (&asbr_id, 0, sizeof (asbr_id)); | |
672 | asbr_id.family = AF_UNSPEC; | |
673 | asbr_id.prefixlen = 64; /* xxx */ | |
674 | asbr_id.adv_router.s_addr = lsa->header->adv_router; | |
675 | ||
676 | ospf6_route_lookup (&asbr_entry, (struct prefix *) &asbr_id, | |
677 | ospf6->topology_table); | |
678 | ||
679 | if (ospf6_route_end (&asbr_entry)) | |
680 | { | |
681 | if (IS_OSPF6_DUMP_ASBR) | |
682 | { | |
683 | char buf[64]; | |
684 | inet_ntop (AF_INET, &asbr_id.adv_router, buf, sizeof (buf)); | |
685 | zlog_info ("ASBR: router %s not found, ignore", buf); | |
686 | } | |
687 | return; | |
688 | } | |
689 | ||
690 | memset (&request, 0, sizeof (request)); | |
691 | request.route.type = OSPF6_DEST_TYPE_NETWORK; | |
692 | request.route.prefix.family = AF_INET6; | |
693 | request.route.prefix.prefixlen = external->prefix.prefix_length; | |
694 | memcpy (&request.route.prefix.u.prefix6, (char *)(external + 1), | |
695 | OSPF6_PREFIX_SPACE (request.route.prefix.prefixlen)); | |
696 | ||
697 | request.path.area_id = asbr_entry.path.area_id; | |
698 | request.path.origin.type = htons (OSPF6_LSA_TYPE_AS_EXTERNAL); | |
699 | request.path.origin.id = lsa->header->id; | |
700 | request.path.origin.adv_router = lsa->header->adv_router; | |
701 | if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E)) | |
702 | { | |
703 | request.path.type = OSPF6_PATH_TYPE_EXTERNAL2; | |
704 | request.path.metric_type = 2; | |
705 | request.path.cost = asbr_entry.path.cost; | |
706 | request.path.cost_e2 = OSPF6_ASBR_METRIC (external); | |
707 | } | |
708 | else | |
709 | { | |
710 | request.path.type = OSPF6_PATH_TYPE_EXTERNAL1; | |
711 | request.path.metric_type = 1; | |
712 | request.path.cost = asbr_entry.path.cost | |
713 | + OSPF6_ASBR_METRIC (external); | |
714 | request.path.cost_e2 = 0; | |
715 | } | |
716 | request.path.prefix_options = external->prefix.prefix_options; | |
717 | ||
718 | while (((struct prefix_ls *)&asbr_entry.route.prefix)->adv_router.s_addr == | |
719 | asbr_id.adv_router.s_addr && | |
720 | asbr_entry.route.type == OSPF6_DEST_TYPE_ROUTER) | |
721 | { | |
722 | memcpy (&request.nexthop, &asbr_entry.nexthop, | |
723 | sizeof (struct ospf6_nexthop)); | |
724 | if (IS_OSPF6_DUMP_ASBR) | |
725 | { | |
726 | char buf[64], nhop[64], ifname[IFNAMSIZ]; | |
727 | prefix2str (&request.route.prefix, buf, sizeof (buf)); | |
728 | inet_ntop (AF_INET6, &request.nexthop.address, nhop, sizeof (nhop)); | |
729 | if_indextoname (request.nexthop.ifindex, ifname); | |
730 | zlog_info ("ASBR: add route: %s %s%%%s", buf, nhop, ifname); | |
731 | } | |
732 | ospf6_route_add (&request, ospf6->route_table); | |
733 | ospf6_route_next (&asbr_entry); | |
734 | } | |
735 | } | |
736 | ||
737 | void | |
738 | ospf6_asbr_external_lsa_remove (struct ospf6_lsa *lsa) | |
739 | { | |
740 | struct ospf6_lsa_as_external *external; | |
741 | struct prefix dest; | |
742 | char buf[64]; | |
743 | struct ospf6_route_req request; | |
744 | ||
745 | if (IS_OSPF6_DUMP_ASBR) | |
746 | zlog_info ("ASBR: withdraw external lsa: %s seq: %lx", | |
747 | lsa->str, (u_long)ntohl (lsa->header->seqnum)); | |
748 | ||
749 | if (lsa->header->adv_router == ospf6->router_id) | |
750 | { | |
751 | if (IS_OSPF6_DUMP_ASBR) | |
752 | zlog_info ("ASBR: my external LSA, ignore"); | |
753 | return; | |
754 | } | |
755 | ||
756 | external = OSPF6_LSA_HEADER_END (lsa->header); | |
757 | memset (&dest, 0, sizeof (dest)); | |
758 | dest.family = AF_INET6; | |
759 | dest.prefixlen = external->prefix.prefix_length; | |
760 | memcpy (&dest.u.prefix6, (char *)(external + 1), | |
761 | OSPF6_PREFIX_SPACE (dest.prefixlen)); | |
762 | ||
763 | ospf6_route_lookup (&request, &dest, ospf6->route_table); | |
764 | if (ospf6_route_end (&request)) | |
765 | { | |
766 | if (IS_OSPF6_DUMP_ASBR) | |
767 | { | |
768 | prefix2str (&dest, buf, sizeof (buf)); | |
769 | zlog_info ("ASBR: %s not found", buf); | |
770 | } | |
771 | return; | |
772 | } | |
773 | ||
774 | while (request.path.origin.id != lsa->header->id || | |
775 | request.path.origin.adv_router != lsa->header->adv_router) | |
776 | { | |
777 | if (prefix_same (&request.route.prefix, &dest) != 1) | |
778 | { | |
779 | if (IS_OSPF6_DUMP_ASBR) | |
780 | zlog_info ("ASBR: Can't find the entry matches the origin"); | |
781 | return; | |
782 | } | |
783 | ospf6_route_next (&request); | |
784 | } | |
785 | assert (request.path.origin.id == lsa->header->id); | |
786 | assert (request.path.origin.adv_router == request.path.origin.adv_router); | |
787 | ||
788 | while (request.path.origin.id == lsa->header->id && | |
789 | request.path.origin.adv_router == lsa->header->adv_router && | |
790 | prefix_same (&request.route.prefix, &dest) == 1) | |
791 | { | |
792 | if (IS_OSPF6_DUMP_ASBR) | |
793 | { | |
794 | char nhop[64], ifname[IFNAMSIZ]; | |
795 | prefix2str (&dest, buf, sizeof (buf)); | |
796 | inet_ntop (AF_INET6, &request.nexthop.address, nhop, sizeof (nhop)); | |
797 | if_indextoname (request.nexthop.ifindex, ifname); | |
798 | zlog_info ("ASBR: remove route: %s %s%%%s", buf, nhop, ifname); | |
799 | } | |
800 | ||
801 | ospf6_route_remove (&request, ospf6->route_table); | |
802 | ospf6_route_next (&request); | |
803 | } | |
804 | } | |
805 | ||
806 | void | |
807 | ospf6_asbr_external_lsa_change (struct ospf6_lsa *old, struct ospf6_lsa *new) | |
808 | { | |
809 | assert (old || new); | |
810 | ||
811 | if (old == NULL) | |
812 | ospf6_asbr_external_lsa_add (new); | |
813 | else if (new == NULL) | |
814 | ospf6_asbr_external_lsa_remove (old); | |
815 | else | |
816 | { | |
817 | ospf6_route_table_freeze (ospf6->route_table); | |
818 | ospf6_asbr_external_lsa_remove (old); | |
819 | ospf6_asbr_external_lsa_add (new); | |
820 | ospf6_route_table_thaw (ospf6->route_table); | |
821 | } | |
822 | } | |
823 | ||
824 | void | |
825 | ospf6_asbr_asbr_entry_add (struct ospf6_route_req *topo_entry) | |
826 | { | |
827 | struct ospf6_lsdb_node node; | |
828 | ||
829 | struct prefix_ls *inter_router; | |
830 | u_int32_t id, adv_router; | |
831 | ||
832 | inter_router = (struct prefix_ls *) &topo_entry->route.prefix; | |
833 | id = inter_router->id.s_addr; | |
834 | adv_router = inter_router->adv_router.s_addr; | |
835 | ||
836 | if (IS_OSPF6_DUMP_ASBR) | |
837 | { | |
838 | char buf[64]; | |
839 | inet_ntop (AF_INET, &inter_router->adv_router, buf, sizeof (buf)); | |
840 | zlog_info ("ASBR: new router found: %s", buf); | |
841 | } | |
842 | ||
843 | if (ntohl (id) != 0 || | |
844 | ! OSPF6_OPT_ISSET (topo_entry->path.capability, OSPF6_OPT_E)) | |
845 | { | |
846 | zlog_warn ("ASBR: Inter topology table malformed"); | |
847 | return; | |
848 | } | |
849 | ||
850 | for (ospf6_lsdb_type_router (&node, htons (OSPF6_LSA_TYPE_AS_EXTERNAL), | |
851 | adv_router, ospf6->lsdb); | |
852 | ! ospf6_lsdb_is_end (&node); | |
853 | ospf6_lsdb_next (&node)) | |
854 | ospf6_asbr_external_lsa_add (node.lsa); | |
855 | } | |
856 | ||
857 | void | |
858 | ospf6_asbr_asbr_entry_remove (struct ospf6_route_req *topo_entry) | |
859 | { | |
860 | struct prefix_ls *inter_router; | |
861 | u_int32_t id, adv_router; | |
862 | struct ospf6_route_req request; | |
863 | ||
864 | inter_router = (struct prefix_ls *) &topo_entry->route.prefix; | |
865 | id = inter_router->id.s_addr; | |
866 | adv_router = inter_router->adv_router.s_addr; | |
867 | ||
868 | if (IS_OSPF6_DUMP_ASBR) | |
869 | { | |
870 | char buf[64]; | |
871 | inet_ntop (AF_INET, &inter_router->adv_router, buf, sizeof (buf)); | |
872 | zlog_info ("ASBR: router disappearing: %s", buf); | |
873 | } | |
874 | ||
875 | if (ntohl (id) != 0 || | |
876 | ! OSPF6_OPT_ISSET (topo_entry->path.capability, OSPF6_OPT_E)) | |
877 | { | |
878 | zlog_warn ("ASBR: Inter topology table malformed"); | |
879 | } | |
880 | ||
881 | for (ospf6_route_head (&request, ospf6->route_table); | |
882 | ! ospf6_route_end (&request); | |
883 | ospf6_route_next (&request)) | |
884 | { | |
885 | if (request.path.type != OSPF6_PATH_TYPE_EXTERNAL1 && | |
886 | request.path.type != OSPF6_PATH_TYPE_EXTERNAL2) | |
887 | continue; | |
888 | if (request.path.area_id != topo_entry->path.area_id) | |
889 | continue; | |
890 | if (request.path.origin.adv_router != topo_entry->path.origin.adv_router) | |
891 | continue; | |
892 | if (memcmp (&topo_entry->nexthop, &request.nexthop, | |
893 | sizeof (struct ospf6_nexthop))) | |
894 | continue; | |
895 | ||
896 | ospf6_route_remove (&request, ospf6->route_table); | |
897 | } | |
898 | } | |
899 | ||
900 | int | |
901 | ospf6_asbr_external_show (struct vty *vty, struct ospf6_lsa *lsa) | |
902 | { | |
903 | struct ospf6_lsa_as_external *external; | |
904 | char buf[128], *ptr; | |
905 | struct in6_addr in6; | |
906 | ||
907 | assert (lsa->header); | |
908 | external = (struct ospf6_lsa_as_external *)(lsa->header + 1); | |
909 | ||
910 | /* bits */ | |
911 | snprintf (buf, sizeof (buf), "%s%s%s", | |
912 | (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E) ? | |
913 | "E" : "-"), | |
914 | (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F) ? | |
915 | "F" : "-"), | |
916 | (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_T) ? | |
917 | "T" : "-")); | |
918 | ||
919 | vty_out (vty, " Bits: %s%s", buf, VTY_NEWLINE); | |
920 | vty_out (vty, " Metric: %5lu%s", (u_long)OSPF6_ASBR_METRIC (external), | |
921 | VTY_NEWLINE); | |
922 | ||
923 | ospf6_prefix_options_str (external->prefix.prefix_options, | |
924 | buf, sizeof (buf)); | |
925 | vty_out (vty, " Prefix Options: %s%s", buf, VTY_NEWLINE); | |
926 | ||
927 | vty_out (vty, " Referenced LSType: %d%s", | |
928 | ntohs (external->prefix.prefix_refer_lstype), VTY_NEWLINE); | |
929 | ||
930 | ospf6_prefix_in6_addr (&external->prefix, &in6); | |
931 | inet_ntop (AF_INET6, &in6, buf, sizeof (buf)); | |
932 | vty_out (vty, " Prefix: %s/%d%s", | |
933 | buf, external->prefix.prefix_length, VTY_NEWLINE); | |
934 | ||
935 | /* Forwarding-Address */ | |
936 | if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F)) | |
937 | { | |
938 | ptr = ((char *)(external + 1)) | |
939 | + OSPF6_PREFIX_SPACE (external->prefix.prefix_length); | |
940 | inet_ntop (AF_INET6, (struct in6_addr *) ptr, buf, sizeof (buf)); | |
941 | vty_out (vty, " Forwarding-Address: %s%s", buf, VTY_NEWLINE); | |
942 | } | |
943 | ||
944 | return 0; | |
945 | } | |
946 | ||
947 | void | |
948 | ospf6_asbr_database_hook (struct ospf6_lsa *old, struct ospf6_lsa *new) | |
949 | { | |
950 | if (old) | |
951 | ospf6_asbr_external_lsa_remove (old); | |
952 | if (new && ! IS_LSA_MAXAGE (new)) | |
953 | ospf6_asbr_external_lsa_add (new); | |
954 | } | |
955 | ||
956 | void | |
957 | ospf6_asbr_register_as_external () | |
958 | { | |
959 | struct ospf6_lsa_slot slot; | |
960 | ||
961 | memset (&slot, 0, sizeof (slot)); | |
962 | slot.type = htons (OSPF6_LSA_TYPE_AS_EXTERNAL); | |
963 | slot.name = "AS-External"; | |
964 | slot.func_show = ospf6_asbr_external_show; | |
965 | slot.func_refresh = ospf6_asbr_external_lsa_refresh; | |
966 | ospf6_lsa_slot_register (&slot); | |
967 | ||
968 | ospf6_lsdb_hook[OSPF6_LSA_TYPE_AS_EXTERNAL & OSPF6_LSTYPE_CODE_MASK].hook = | |
969 | ospf6_asbr_database_hook; | |
970 | } | |
971 | ||
972 | void | |
973 | ospf6_asbr_external_info_show (struct vty *vty, | |
974 | struct ospf6_external_info *info) | |
975 | { | |
976 | char prefix_buf[64], id_buf[16]; | |
977 | struct in_addr id; | |
978 | ||
979 | if (info->is_removed) | |
980 | return; | |
981 | ||
982 | id.s_addr = ntohl (info->id); | |
983 | inet_ntop (AF_INET, &id, id_buf, sizeof (id_buf)); | |
984 | prefix2str (&info->route->prefix, prefix_buf, sizeof (prefix_buf)); | |
985 | vty_out (vty, "%s %-32s %3d %-15s %3d %lu(type-%d)%s", | |
986 | ZROUTE_ABNAME(info->type), prefix_buf, info->ifindex, id_buf, | |
987 | info->nexthop_num, (u_long) info->metric, info->metric_type, | |
988 | VTY_NEWLINE); | |
989 | } | |
990 | ||
991 | void | |
992 | ospf6_asbr_external_route_show (struct vty *vty, | |
993 | struct ospf6_external_route *route) | |
994 | { | |
995 | struct ospf6_external_info *info; | |
996 | for (info = route->info_head; info; info = info->next) | |
997 | ospf6_asbr_external_info_show (vty, info); | |
998 | } | |
999 | ||
1000 | DEFUN (show_ipv6_route_ospf6_external, | |
1001 | show_ipv6_route_ospf6_external_cmd, | |
1002 | "show ipv6 ospf6 route redistribute", | |
1003 | SHOW_STR | |
1004 | IP6_STR | |
1005 | ROUTE_STR | |
1006 | OSPF6_STR | |
1007 | "redistributing External information\n" | |
1008 | ) | |
1009 | { | |
1010 | struct route_node *node; | |
1011 | struct ospf6_external_route *route; | |
1012 | ||
1013 | vty_out (vty, "%s %-32s %3s %-15s %3s %s%s", | |
1014 | " ", "Prefix", "I/F", "LS-Id", "#NH", "Metric", | |
1015 | VTY_NEWLINE); | |
1016 | for (node = route_top (external_table); node; node = route_next (node)) | |
1017 | { | |
1018 | route = node->info; | |
1019 | if (route) | |
1020 | ospf6_asbr_external_route_show (vty, route); | |
1021 | } | |
1022 | return CMD_SUCCESS; | |
1023 | } | |
1024 | ||
1025 | void | |
1026 | ospf6_asbr_init () | |
1027 | { | |
1028 | external_table = route_table_init (); | |
1029 | link_state_id = 0; | |
1030 | ||
1031 | ospf6_asbr_register_as_external (); | |
1032 | ||
1033 | install_element (VIEW_NODE, &show_ipv6_route_ospf6_external_cmd); | |
1034 | install_element (ENABLE_NODE, &show_ipv6_route_ospf6_external_cmd); | |
1035 | install_element (OSPF6_NODE, &ospf6_redistribute_cmd); | |
1036 | install_element (OSPF6_NODE, &ospf6_redistribute_routemap_cmd); | |
1037 | install_element (OSPF6_NODE, &no_ospf6_redistribute_cmd); | |
1038 | } | |
1039 | ||
1040 |