2 * IS-IS Rout(e)ing protocol - isis_redist.c
4 * Copyright (C) 2013-2015 Christian Franke <chris@opensourcerouting.org>
6 * This program 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 Free
8 * Software Foundation; either version 2 of the License, or (at your option)
11 * This program is distributed in the hope that it will be useful,but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 #include "isis_memory.h"
34 #include "isisd/dict.h"
35 #include "isisd/isis_constants.h"
36 #include "isisd/isis_common.h"
37 #include "isisd/isis_flags.h"
38 #include "isisd/isis_misc.h"
39 #include "isisd/isis_circuit.h"
40 #include "isisd/isis_tlv.h"
41 #include "isisd/isisd.h"
42 #include "isisd/isis_lsp.h"
43 #include "isisd/isis_route.h"
44 #include "isisd/isis_zebra.h"
47 redist_protocol(int family
)
49 if (family
== AF_INET
)
51 if (family
== AF_INET6
)
54 assert(!"Unsupported address family!");
58 is_default(struct prefix
*p
)
60 if (p
->family
== AF_INET
)
61 if (p
->u
.prefix4
.s_addr
== 0 && p
->prefixlen
== 0)
63 if (p
->family
== AF_INET6
)
64 if (IN6_IS_ADDR_UNSPECIFIED(&p
->u
.prefix6
) && p
->prefixlen
== 0)
69 static struct route_table
*
70 get_ext_info(struct isis
*i
, int family
)
72 int protocol
= redist_protocol(family
);
74 return i
->ext_info
[protocol
];
77 static struct isis_redist
*
78 get_redist_settings(struct isis_area
*area
, int family
, int type
, int level
)
80 int protocol
= redist_protocol(family
);
82 return &area
->redist_settings
[protocol
][type
][level
-1];
86 get_ext_reach(struct isis_area
*area
, int family
, int level
)
88 int protocol
= redist_protocol(family
);
90 return area
->ext_reach
[protocol
][level
-1];
93 static struct route_node
*
94 isis_redist_route_node_create(route_table_delegate_t
*delegate
,
95 struct route_table
*table
)
97 struct route_node
*node
;
98 node
= XCALLOC(MTYPE_ISIS_EXT_ROUTE
, sizeof(*node
));
103 isis_redist_route_node_destroy(route_table_delegate_t
*delegate
,
104 struct route_table
*table
,
105 struct route_node
*node
)
108 XFREE(MTYPE_ISIS_EXT_INFO
, node
->info
);
109 XFREE (MTYPE_ISIS_EXT_ROUTE
, node
);
112 static route_table_delegate_t isis_redist_rt_delegate
= {
113 .create_node
= isis_redist_route_node_create
,
114 .destroy_node
= isis_redist_route_node_destroy
117 /* Install external reachability information into a
118 * specific area for a specific level.
119 * Schedule an lsp regenerate if necessary */
121 isis_redist_install(struct isis_area
*area
, int level
,
122 struct prefix
*p
, struct isis_ext_info
*info
)
124 int family
= p
->family
;
125 struct route_table
*er_table
= get_ext_reach(area
, family
, level
);
126 struct route_node
*er_node
;
130 zlog_warn("%s: External reachability table of area %s"
131 " is not initialized.", __func__
, area
->area_tag
);
135 er_node
= route_node_get(er_table
, p
);
138 route_unlock_node(er_node
);
140 /* Don't update/reschedule lsp generation if nothing changed. */
141 if (!memcmp(er_node
->info
, info
, sizeof(*info
)))
146 er_node
->info
= XMALLOC(MTYPE_ISIS_EXT_INFO
, sizeof(*info
));
149 memcpy(er_node
->info
, info
, sizeof(*info
));
150 lsp_regenerate_schedule(area
, level
, 0);
153 /* Remove external reachability information from a
154 * specific area for a specific level.
155 * Schedule an lsp regenerate if necessary. */
157 isis_redist_uninstall(struct isis_area
*area
, int level
, struct prefix
*p
)
159 int family
= p
->family
;
160 struct route_table
*er_table
= get_ext_reach(area
, family
, level
);
161 struct route_node
*er_node
;
165 zlog_warn("%s: External reachability table of area %s"
166 " is not initialized.", __func__
, area
->area_tag
);
170 er_node
= route_node_lookup(er_table
, p
);
174 route_unlock_node(er_node
);
179 XFREE(MTYPE_ISIS
, er_node
->info
);
180 route_unlock_node(er_node
);
181 lsp_regenerate_schedule(area
, level
, 0);
184 /* Update external reachability info of area for a given level
185 * and prefix, using the given redistribution settings. */
187 isis_redist_update_ext_reach(struct isis_area
*area
, int level
,
188 struct isis_redist
*redist
, struct prefix
*p
,
189 struct isis_ext_info
*info
)
191 struct isis_ext_info area_info
;
192 route_map_result_t map_ret
;
194 memcpy(&area_info
, info
, sizeof(area_info
));
195 if (redist
->metric
!= 0xffffffff)
196 area_info
.metric
= redist
->metric
;
198 if (redist
->map_name
)
200 map_ret
= route_map_apply(redist
->map
, p
, RMAP_ISIS
, &area_info
);
201 if (map_ret
== RMAP_DENYMATCH
)
202 area_info
.distance
= 255;
205 /* Allow synthesized default routes only on always orignate */
206 if (area_info
.origin
== DEFAULT_ROUTE
207 && redist
->redist
!= DEFAULT_ORIGINATE_ALWAYS
)
208 area_info
.distance
= 255;
210 if (area_info
.distance
< 255)
211 isis_redist_install(area
, level
, p
, &area_info
);
213 isis_redist_uninstall(area
, level
, p
);
217 isis_redist_ensure_default(struct isis
*isis
, int family
)
220 struct route_table
*ei_table
= get_ext_info(isis
, family
);
221 struct route_node
*ei_node
;
222 struct isis_ext_info
*info
;
224 if (family
== AF_INET
)
228 memset(&p
.u
.prefix4
, 0, sizeof(p
.u
.prefix4
));
230 else if (family
== AF_INET6
)
234 memset(&p
.u
.prefix6
, 0, sizeof(p
.u
.prefix6
));
237 assert(!"Unknown family!");
239 ei_node
= route_node_get(ei_table
, &p
);
242 route_unlock_node(ei_node
);
246 ei_node
->info
= XCALLOC(MTYPE_ISIS_EXT_INFO
, sizeof(struct isis_ext_info
));
248 info
= ei_node
->info
;
249 info
->origin
= DEFAULT_ROUTE
;
250 info
->distance
= 254;
251 info
->metric
= MAX_WIDE_PATH_METRIC
;
254 /* Handle notification about route being added */
256 isis_redist_add(int type
, struct prefix
*p
, u_char distance
, uint32_t metric
)
258 int family
= p
->family
;
259 struct route_table
*ei_table
= get_ext_info(isis
, family
);
260 struct route_node
*ei_node
;
261 struct isis_ext_info
*info
;
262 struct listnode
*node
;
263 struct isis_area
*area
;
265 struct isis_redist
*redist
;
267 char debug_buf
[BUFSIZ
];
268 prefix2str(p
, debug_buf
, sizeof(debug_buf
));
270 zlog_debug("%s: New route %s from %s.", __func__
, debug_buf
,
271 zebra_route_string(type
));
275 zlog_warn("%s: External information table not initialized.",
280 ei_node
= route_node_get(ei_table
, p
);
282 route_unlock_node(ei_node
);
284 ei_node
->info
= XCALLOC(MTYPE_ISIS_EXT_INFO
, sizeof(struct isis_ext_info
));
286 info
= ei_node
->info
;
288 info
->distance
= distance
;
289 info
->metric
= metric
;
292 type
= DEFAULT_ROUTE
;
294 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, node
, area
))
295 for (level
= 1; level
<= ISIS_LEVELS
; level
++)
297 redist
= get_redist_settings(area
, family
, type
, level
);
301 isis_redist_update_ext_reach(area
, level
, redist
, p
, info
);
306 isis_redist_delete(int type
, struct prefix
*p
)
308 int family
= p
->family
;
309 struct route_table
*ei_table
= get_ext_info(isis
, family
);
310 struct route_node
*ei_node
;
311 struct listnode
*node
;
312 struct isis_area
*area
;
314 struct isis_redist
*redist
;
316 char debug_buf
[BUFSIZ
];
317 prefix2str(p
, debug_buf
, sizeof(debug_buf
));
319 zlog_debug("%s: Removing route %s from %s.", __func__
, debug_buf
,
320 zebra_route_string(type
));
324 /* Don't remove default route but add synthetic route for use
325 * by "default-information originate always". Areas without the
326 * "always" setting will ignore routes with origin DEFAULT_ROUTE. */
327 isis_redist_add(DEFAULT_ROUTE
, p
, 254, MAX_WIDE_PATH_METRIC
);
333 zlog_warn("%s: External information table not initialized.",
338 ei_node
= route_node_lookup(ei_table
, p
);
339 if (!ei_node
|| !ei_node
->info
)
342 prefix2str(p
, buf
, sizeof(buf
));
343 zlog_warn("%s: Got a delete for %s route %s, but that route"
344 " was never added.", __func__
, zebra_route_string(type
),
347 route_unlock_node(ei_node
);
350 route_unlock_node(ei_node
);
352 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, node
, area
))
353 for (level
= 1; level
< ISIS_LEVELS
; level
++)
355 redist
= get_redist_settings(area
, family
, type
, level
);
359 isis_redist_uninstall(area
, level
, p
);
362 XFREE(MTYPE_ISIS
, ei_node
->info
);
363 route_unlock_node(ei_node
);
367 isis_redist_routemap_set(struct isis_redist
*redist
, const char *routemap
)
369 if (redist
->map_name
) {
370 XFREE(MTYPE_ISIS
, redist
->map_name
);
374 if (routemap
&& strlen(routemap
)) {
375 redist
->map_name
= XSTRDUP(MTYPE_ISIS
, routemap
);
376 redist
->map
= route_map_lookup_by_name(routemap
);
381 isis_redist_update_zebra_subscriptions(struct isis
*isis
)
383 struct listnode
*node
;
384 struct isis_area
*area
;
389 char do_subscribe
[ZEBRA_ROUTE_MAX
+ 1];
391 memset(do_subscribe
, 0, sizeof(do_subscribe
));
393 for (ALL_LIST_ELEMENTS_RO(isis
->area_list
, node
, area
))
394 for (protocol
= 0; protocol
< REDIST_PROTOCOL_COUNT
; protocol
++)
395 for (type
= 0; type
< ZEBRA_ROUTE_MAX
+ 1; type
++)
396 for (level
= 0; level
< ISIS_LEVELS
; level
++)
397 if (area
->redist_settings
[protocol
][type
][level
].redist
)
398 do_subscribe
[type
] = 1;
400 for (type
= 0; type
< ZEBRA_ROUTE_MAX
+ 1; type
++)
402 /* This field is actually controlling transmission of the IS-IS
403 * routes to Zebra and has nothing to do with redistribution,
405 if (type
== ZEBRA_ROUTE_ISIS
)
408 if (do_subscribe
[type
])
409 isis_zebra_redistribute_set(type
);
411 isis_zebra_redistribute_unset(type
);
416 isis_redist_set(struct isis_area
*area
, int level
,
417 int family
, int type
, uint32_t metric
,
418 const char *routemap
, int originate_type
)
420 int protocol
= redist_protocol(family
);
421 struct isis_redist
*redist
= get_redist_settings(area
, family
, type
, level
);
423 struct route_table
*ei_table
;
424 struct route_node
*rn
;
425 struct isis_ext_info
*info
;
427 redist
->redist
= (type
== DEFAULT_ROUTE
) ? originate_type
: 1;
428 redist
->metric
= metric
;
429 isis_redist_routemap_set(redist
, routemap
);
431 if (!area
->ext_reach
[protocol
][level
-1])
433 area
->ext_reach
[protocol
][level
-1] =
434 route_table_init_with_delegate(&isis_redist_rt_delegate
);
437 for (i
= 0; i
< REDIST_PROTOCOL_COUNT
; i
++)
438 if (!area
->isis
->ext_info
[i
])
440 area
->isis
->ext_info
[i
] =
441 route_table_init_with_delegate(&isis_redist_rt_delegate
);
444 isis_redist_update_zebra_subscriptions(area
->isis
);
446 if (type
== DEFAULT_ROUTE
&& originate_type
== DEFAULT_ORIGINATE_ALWAYS
)
447 isis_redist_ensure_default(area
->isis
, family
);
449 ei_table
= get_ext_info(area
->isis
, family
);
450 for (rn
= route_top(ei_table
); rn
; rn
= route_next(rn
))
456 if (type
== DEFAULT_ROUTE
)
458 if (!is_default(&rn
->p
))
463 if (info
->origin
!= type
)
467 isis_redist_update_ext_reach(area
, level
, redist
, &rn
->p
, info
);
472 isis_redist_unset(struct isis_area
*area
, int level
,
473 int family
, int type
)
475 struct isis_redist
*redist
= get_redist_settings(area
, family
, type
, level
);
476 struct route_table
*er_table
= get_ext_reach(area
, family
, level
);
477 struct route_node
*rn
;
478 struct isis_ext_info
*info
;
486 zlog_warn("%s: External reachability table uninitialized.", __func__
);
490 for (rn
= route_top(er_table
); rn
; rn
= route_next(rn
))
496 if (type
== DEFAULT_ROUTE
)
498 if (!is_default(&rn
->p
))
503 if (info
->origin
!= type
)
507 XFREE(MTYPE_ISIS
, rn
->info
);
508 route_unlock_node(rn
);
511 lsp_regenerate_schedule(area
, level
, 0);
512 isis_redist_update_zebra_subscriptions(area
->isis
);
516 isis_redist_area_finish(struct isis_area
*area
)
522 for (protocol
= 0; protocol
< REDIST_PROTOCOL_COUNT
; protocol
++)
523 for (level
= 0; level
< ISIS_LEVELS
; level
++)
525 for (type
= 0; type
< ZEBRA_ROUTE_MAX
+ 1; type
++)
527 struct isis_redist
*redist
;
529 redist
= &area
->redist_settings
[protocol
][type
][level
];
531 if (redist
->map_name
)
532 XFREE(MTYPE_ISIS
, redist
->map_name
);
534 route_table_finish(area
->ext_reach
[protocol
][level
]);
537 isis_redist_update_zebra_subscriptions(area
->isis
);
540 DEFUN (isis_redistribute
,
541 isis_redistribute_cmd
,
542 "redistribute <ipv4|ipv6> " QUAGGA_REDIST_STR_ISISD
" <level-1|level-2> [metric (0-16777215)|route-map WORD]",
544 "Redistribute IPv4 routes\n"
545 "Redistribute IPv6 routes\n"
546 QUAGGA_REDIST_HELP_STR_ISISD
547 "Redistribute into level-1\n"
548 "Redistribute into level-2\n"
549 "Metric for redistributed routes\n"
550 "ISIS default metric\n"
551 "Route map reference\n"
552 "Pointer to route-map entries\n")
554 struct isis_area
*area
= vty
->index
;
559 unsigned long metric
;
560 const char *routemap
;
565 family
= str2family(argv
[1]->arg
);
569 afi
= family2afi(family
);
573 type
= proto_redistnum(afi
, argv
[2]->arg
);
574 if (type
< 0 || type
== ZEBRA_ROUTE_ISIS
)
577 if (!strcmp("level-1", argv
[3]->arg
))
579 else if (!strcmp("level-2", argv
[3]->arg
))
584 if ((area
->is_type
& level
) != level
)
586 vty_out(vty
, "Node is not a level-%d IS%s", level
, VTY_NEWLINE
);
593 metric
= strtoul(argv
[4]->arg
, &endp
, 10);
594 if (argv
[4]->arg
[0] == '\0' || *endp
!= '\0')
604 isis_redist_set(area
, level
, family
, type
, metric
, routemap
, 0);
608 DEFUN (no_isis_redistribute
,
609 no_isis_redistribute_cmd
,
610 "no redistribute <ipv4|ipv6> " QUAGGA_REDIST_STR_ISISD
" <level-1|level-2>",
613 "Redistribute IPv4 routes\n"
614 "Redistribute IPv6 routes\n"
615 QUAGGA_REDIST_HELP_STR_ISISD
616 "Redistribute into level-1\n"
617 "Redistribute into level-2\n")
619 struct isis_area
*area
= vty
->index
;
628 family
= str2family(argv
[2]->arg
);
632 afi
= family2afi(family
);
636 type
= proto_redistnum(afi
, argv
[3]->arg
);
637 if (type
< 0 || type
== ZEBRA_ROUTE_ISIS
)
640 if (!strcmp("level-1", argv
[4]->arg
))
642 else if (!strcmp("level-2", argv
[4]->arg
))
647 isis_redist_unset(area
, level
, family
, type
);
651 DEFUN (isis_default_originate
,
652 isis_default_originate_cmd
,
653 "default-information originate <ipv4|ipv6> <level-1|level-2> [always|metric (0-16777215)|route-map WORD]",
654 "Control distribution of default information\n"
655 "Distribute a default route\n"
656 "Distribute default route for IPv4\n"
657 "Distribute default route for IPv6\n"
658 "Distribute default route into level-1\n"
659 "Distribute default route into level-2\n"
660 "Always advertise default route\n"
661 "Metric for default route\n"
662 "ISIS default metric\n"
663 "Route map reference\n"
664 "Pointer to route-map entries\n")
666 struct isis_area
*area
= vty
->index
;
670 unsigned long metric
;
671 const char *routemap
;
676 family
= str2family(argv
[2]->arg
);
680 if (!strcmp("level-1", argv
[3]->arg
))
682 else if (!strcmp("level-2", argv
[3]->arg
))
687 if ((area
->is_type
& level
) != level
)
689 vty_out(vty
, "Node is not a level-%d IS%s", level
, VTY_NEWLINE
);
693 if (argv
[4]->arg
&& *argv
[4]->arg
!= '\0')
694 originate_type
= DEFAULT_ORIGINATE_ALWAYS
;
696 originate_type
= DEFAULT_ORIGINATE
;
698 if (family
== AF_INET6
&& originate_type
!= DEFAULT_ORIGINATE_ALWAYS
)
700 vty_out(vty
, "Zebra doesn't implement default-originate for IPv6 yet%s", VTY_NEWLINE
);
701 vty_out(vty
, "so use with care or use default-originate always.%s", VTY_NEWLINE
);
707 metric
= strtoul(argv
[3], &endp
, 10);
708 if (argv
[3][0] == '\0' || *endp
!= '\0')
718 isis_redist_set(area
, level
, family
, DEFAULT_ROUTE
, metric
, routemap
, originate_type
);
722 DEFUN (no_isis_default_originate
,
723 no_isis_default_originate_cmd
,
724 "no default-information originate <ipv4|ipv6> <level-1|level-2>",
726 "Control distribution of default information\n"
727 "Distribute a default route\n"
728 "Distribute default route for IPv4\n"
729 "Distribute default route for IPv6\n"
730 "Distribute default route into level-1\n"
731 "Distribute default route into level-2\n")
733 struct isis_area
*area
= vty
->index
;
741 family
= str2family(argv
[3]->arg
);
745 if (!strcmp("level-1", argv
[4]->arg
))
747 else if (!strcmp("level-2", argv
[4]->arg
))
752 isis_redist_unset(area
, level
, family
, DEFAULT_ROUTE
);
757 isis_redist_config_write(struct vty
*vty
, struct isis_area
*area
,
763 struct isis_redist
*redist
;
764 const char *family_str
;
766 if (family
== AF_INET
)
768 else if (family
== AF_INET6
)
773 for (type
= 0; type
< ZEBRA_ROUTE_MAX
; type
++)
775 if (type
== ZEBRA_ROUTE_ISIS
)
778 for (level
= 1; level
<= ISIS_LEVELS
; level
++)
780 redist
= get_redist_settings(area
, family
, type
, level
);
783 vty_out(vty
, " redistribute %s %s level-%d",
784 family_str
, zebra_route_string(type
), level
);
785 if (redist
->metric
!= 0xffffffff)
786 vty_out(vty
, " metric %u", redist
->metric
);
787 if (redist
->map_name
)
788 vty_out(vty
, " route-map %s", redist
->map_name
);
789 vty_out(vty
, "%s", VTY_NEWLINE
);
794 for (level
= 1; level
<= ISIS_LEVELS
; level
++)
796 redist
= get_redist_settings(area
, family
, DEFAULT_ROUTE
, level
);
799 vty_out(vty
, " default-information originate %s level-%d",
801 if (redist
->redist
== DEFAULT_ORIGINATE_ALWAYS
)
802 vty_out(vty
, " always");
803 if (redist
->metric
!= 0xffffffff)
804 vty_out(vty
, " metric %u", redist
->metric
);
805 if (redist
->map_name
)
806 vty_out(vty
, " route-map %s", redist
->map_name
);
807 vty_out(vty
, "%s", VTY_NEWLINE
);
815 isis_redist_init(void)
817 install_element(ISIS_NODE
, &isis_redistribute_cmd
);
818 install_element(ISIS_NODE
, &no_isis_redistribute_cmd
);
819 install_element(ISIS_NODE
, &isis_default_originate_cmd
);
820 install_element(ISIS_NODE
, &no_isis_default_originate_cmd
);