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.
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!");
59 is_default(struct prefix *p)
61 if (p->family == AF_INET)
62 if (p->u.prefix4.s_addr == 0 && p->prefixlen == 0)
64 if (p->family == AF_INET6)
65 if (IN6_IS_ADDR_UNSPECIFIED(&p->u.prefix6) && p->prefixlen == 0)
70 static struct route_table*
71 get_ext_info(struct isis *i, int family)
73 int protocol = redist_protocol(family);
75 return i->ext_info[protocol];
78 static struct isis_redist*
79 get_redist_settings(struct isis_area *area, int family, int type, int level)
81 int protocol = redist_protocol(family);
83 return &area->redist_settings[protocol][type][level-1];
87 get_ext_reach(struct isis_area *area, int family, int level)
89 int protocol = redist_protocol(family);
91 return area->ext_reach[protocol][level-1];
94 static struct route_node *
95 isis_redist_route_node_create(route_table_delegate_t *delegate,
96 struct route_table *table)
98 struct route_node *node;
99 node = XCALLOC(MTYPE_ROUTE_NODE, sizeof(*node));
104 isis_redist_route_node_destroy(route_table_delegate_t *delegate,
105 struct route_table *table,
106 struct route_node *node)
109 XFREE(MTYPE_ISIS, node->info);
110 XFREE (MTYPE_ROUTE_NODE, node);
113 static route_table_delegate_t isis_redist_rt_delegate = {
114 .create_node = isis_redist_route_node_create,
115 .destroy_node = isis_redist_route_node_destroy
118 /* Install external reachability information into a
119 * specific area for a specific level.
120 * Schedule an lsp regenerate if necessary */
122 isis_redist_install(struct isis_area *area, int level,
123 struct prefix *p, struct isis_ext_info *info)
125 int family = p->family;
126 struct route_table *er_table = get_ext_reach(area, family, level);
127 struct route_node *er_node;
131 zlog_warn("%s: External reachability table of area %s"
132 " is not initialized.", __func__, area->area_tag);
136 er_node = route_node_get(er_table, p);
139 route_unlock_node(er_node);
141 /* Don't update/reschedule lsp generation if nothing changed. */
142 if (!memcmp(er_node->info, info, sizeof(*info)))
147 er_node->info = XMALLOC(MTYPE_ISIS, sizeof(*info));
150 memcpy(er_node->info, info, sizeof(*info));
151 lsp_regenerate_schedule(area, level, 0);
154 /* Remove external reachability information from a
155 * specific area for a specific level.
156 * Schedule an lsp regenerate if necessary. */
158 isis_redist_uninstall(struct isis_area *area, int level, struct prefix *p)
160 int family = p->family;
161 struct route_table *er_table = get_ext_reach(area, family, level);
162 struct route_node *er_node;
166 zlog_warn("%s: External reachability table of area %s"
167 " is not initialized.", __func__, area->area_tag);
171 er_node = route_node_lookup(er_table, p);
175 route_unlock_node(er_node);
180 XFREE(MTYPE_ISIS, er_node->info);
181 route_unlock_node(er_node);
182 lsp_regenerate_schedule(area, level, 0);
185 /* Update external reachability info of area for a given level
186 * and prefix, using the given redistribution settings. */
188 isis_redist_update_ext_reach(struct isis_area *area, int level,
189 struct isis_redist *redist, struct prefix *p,
190 struct isis_ext_info *info)
192 struct isis_ext_info area_info;
193 route_map_result_t map_ret;
195 memcpy(&area_info, info, sizeof(area_info));
196 if (redist->metric != 0xffffffff)
197 area_info.metric = redist->metric;
199 if (redist->map_name)
201 map_ret = route_map_apply(redist->map, p, RMAP_ISIS, &area_info);
202 if (map_ret == RMAP_DENYMATCH)
203 area_info.distance = 255;
206 /* Allow synthesized default routes only on always orignate */
207 if (area_info.origin == DEFAULT_ROUTE
208 && redist->redist != DEFAULT_ORIGINATE_ALWAYS)
209 area_info.distance = 255;
211 if (area_info.distance < 255)
212 isis_redist_install(area, level, p, &area_info);
214 isis_redist_uninstall(area, level, p);
218 isis_redist_ensure_default(struct isis *isis, int family)
221 struct route_table *ei_table = get_ext_info(isis, family);
222 struct route_node *ei_node;
223 struct isis_ext_info *info;
225 if (family == AF_INET)
229 memset(&p.u.prefix4, 0, sizeof(p.u.prefix4));
231 else if (family == AF_INET6)
235 memset(&p.u.prefix6, 0, sizeof(p.u.prefix6));
238 assert(!"Unknown family!");
240 ei_node = route_node_get(ei_table, &p);
243 route_unlock_node(ei_node);
247 ei_node->info = XCALLOC(MTYPE_ISIS, sizeof(struct isis_ext_info));
249 info = ei_node->info;
250 info->origin = DEFAULT_ROUTE;
251 info->distance = 254;
252 info->metric = MAX_WIDE_PATH_METRIC;
255 /* Handle notification about route being added */
257 isis_redist_add(int type, struct prefix *p, u_char distance, uint32_t metric)
259 int family = p->family;
260 struct route_table *ei_table = get_ext_info(isis, family);
261 struct route_node *ei_node;
262 struct isis_ext_info *info;
263 struct listnode *node;
264 struct isis_area *area;
266 struct isis_redist *redist;
268 char debug_buf[BUFSIZ];
269 prefix2str(p, debug_buf, sizeof(debug_buf));
271 zlog_debug("%s: New route %s from %s.", __func__, debug_buf,
272 zebra_route_string(type));
276 zlog_warn("%s: External information table not initialized.",
281 ei_node = route_node_get(ei_table, p);
283 route_unlock_node(ei_node);
285 ei_node->info = XCALLOC(MTYPE_ISIS, sizeof(struct isis_ext_info));
287 info = ei_node->info;
289 info->distance = distance;
290 info->metric = metric;
293 type = DEFAULT_ROUTE;
295 for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area))
296 for (level = 1; level <= ISIS_LEVELS; level++)
298 redist = get_redist_settings(area, family, type, level);
302 isis_redist_update_ext_reach(area, level, redist, p, info);
307 isis_redist_delete(int type, struct prefix *p)
309 int family = p->family;
310 struct route_table *ei_table = get_ext_info(isis, family);
311 struct route_node *ei_node;
312 struct listnode *node;
313 struct isis_area *area;
315 struct isis_redist *redist;
317 char debug_buf[BUFSIZ];
318 prefix2str(p, debug_buf, sizeof(debug_buf));
320 zlog_debug("%s: Removing route %s from %s.", __func__, debug_buf,
321 zebra_route_string(type));
325 /* Don't remove default route but add synthetic route for use
326 * by "default-information originate always". Areas without the
327 * "always" setting will ignore routes with origin DEFAULT_ROUTE. */
328 isis_redist_add(DEFAULT_ROUTE, p, 254, MAX_WIDE_PATH_METRIC);
334 zlog_warn("%s: External information table not initialized.",
339 ei_node = route_node_lookup(ei_table, p);
340 if (!ei_node || !ei_node->info)
343 prefix2str(p, buf, sizeof(buf));
344 zlog_warn("%s: Got a delete for %s route %s, but that route"
345 " was never added.", __func__, zebra_route_string(type),
348 route_unlock_node(ei_node);
351 route_unlock_node(ei_node);
353 for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area))
354 for (level = 1; level < ISIS_LEVELS; level++)
356 redist = get_redist_settings(area, family, type, level);
360 isis_redist_uninstall(area, level, p);
363 XFREE(MTYPE_ISIS, ei_node->info);
364 route_unlock_node(ei_node);
368 isis_redist_routemap_set(struct isis_redist *redist, const char *routemap)
370 if (redist->map_name) {
371 XFREE(MTYPE_ISIS, redist->map_name);
375 if (routemap && strlen(routemap)) {
376 redist->map_name = XSTRDUP(MTYPE_ISIS, routemap);
377 redist->map = route_map_lookup_by_name(routemap);
382 isis_redist_update_zebra_subscriptions(struct isis *isis)
384 struct listnode *node;
385 struct isis_area *area;
390 char do_subscribe[ZEBRA_ROUTE_MAX + 1];
392 memset(do_subscribe, 0, sizeof(do_subscribe));
394 for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area))
395 for (protocol = 0; protocol < REDIST_PROTOCOL_COUNT; protocol++)
396 for (type = 0; type < ZEBRA_ROUTE_MAX + 1; type++)
397 for (level = 0; level < ISIS_LEVELS; level++)
398 if (area->redist_settings[protocol][type][level].redist)
399 do_subscribe[type] = 1;
401 for (type = 0; type < ZEBRA_ROUTE_MAX + 1; type++)
403 /* This field is actually controlling transmission of the IS-IS
404 * routes to Zebra and has nothing to do with redistribution,
406 if (type == ZEBRA_ROUTE_ISIS)
409 if (do_subscribe[type])
410 isis_zebra_redistribute_set(type);
412 isis_zebra_redistribute_unset(type);
417 isis_redist_set(struct isis_area *area, int level,
418 int family, int type, uint32_t metric,
419 const char *routemap, int originate_type)
421 int protocol = redist_protocol(family);
422 struct isis_redist *redist = get_redist_settings(area, family, type, level);
424 struct route_table *ei_table;
425 struct route_node *rn;
426 struct isis_ext_info *info;
428 redist->redist = (type == DEFAULT_ROUTE) ? originate_type : 1;
429 redist->metric = metric;
430 isis_redist_routemap_set(redist, routemap);
432 if (!area->ext_reach[protocol][level-1])
434 area->ext_reach[protocol][level-1] =
435 route_table_init_with_delegate(&isis_redist_rt_delegate);
438 for (i = 0; i < REDIST_PROTOCOL_COUNT; i++)
439 if (!area->isis->ext_info[i])
441 area->isis->ext_info[i] =
442 route_table_init_with_delegate(&isis_redist_rt_delegate);
445 isis_redist_update_zebra_subscriptions(area->isis);
447 if (type == DEFAULT_ROUTE && originate_type == DEFAULT_ORIGINATE_ALWAYS)
448 isis_redist_ensure_default(area->isis, family);
450 ei_table = get_ext_info(area->isis, family);
451 for (rn = route_top(ei_table); rn; rn = route_next(rn))
457 if (type == DEFAULT_ROUTE)
459 if (!is_default(&rn->p))
464 if (info->origin != type)
468 isis_redist_update_ext_reach(area, level, redist, &rn->p, info);
473 isis_redist_unset(struct isis_area *area, int level,
474 int family, int type)
476 struct isis_redist *redist = get_redist_settings(area, family, type, level);
477 struct route_table *er_table = get_ext_reach(area, family, level);
478 struct route_node *rn;
479 struct isis_ext_info *info;
487 zlog_warn("%s: External reachability table uninitialized.", __func__);
491 for (rn = route_top(er_table); rn; rn = route_next(rn))
497 if (type == DEFAULT_ROUTE)
499 if (!is_default(&rn->p))
504 if (info->origin != type)
508 XFREE(MTYPE_ISIS, rn->info);
509 route_unlock_node(rn);
512 lsp_regenerate_schedule(area, level, 0);
513 isis_redist_update_zebra_subscriptions(area->isis);
517 isis_redist_area_finish(struct isis_area *area)
523 for (protocol = 0; protocol < REDIST_PROTOCOL_COUNT; protocol++)
524 for (level = 0; level < ISIS_LEVELS; level++)
526 for (type = 0; type < ZEBRA_ROUTE_MAX + 1; type++)
528 struct isis_redist *redist;
530 redist = &area->redist_settings[protocol][type][level];
532 if (redist->map_name)
533 XFREE(MTYPE_ISIS, redist->map_name);
535 route_table_finish(area->ext_reach[protocol][level]);
538 isis_redist_update_zebra_subscriptions(area->isis);
541 DEFUN(isis_redistribute,
542 isis_redistribute_cmd,
543 "redistribute (ipv4|ipv6) " QUAGGA_REDIST_STR_ISISD
544 " (level-1|level-2) {metric <0-16777215>|route-map WORD}",
546 "Redistribute IPv4 routes\n"
547 "Redistribute IPv6 routes\n"
548 QUAGGA_REDIST_HELP_STR_ISISD
549 "Redistribute into level-1\n"
550 "Redistribute into level-2\n"
551 "Metric for redistributed routes\n"
552 "ISIS default metric\n"
553 "Route map reference\n"
554 "Pointer to route-map entries\n")
556 struct isis_area *area = vty->index;
561 unsigned long metric;
562 const char *routemap;
567 family = str2family(argv[0]);
571 afi = family2afi(family);
575 type = proto_redistnum(afi, argv[1]);
576 if (type < 0 || type == ZEBRA_ROUTE_ISIS)
579 if (!strcmp("level-1", argv[2]))
581 else if (!strcmp("level-2", argv[2]))
586 if ((area->is_type & level) != level)
588 vty_out(vty, "Node is not a level-%d IS%s", level, VTY_NEWLINE);
595 metric = strtoul(argv[3], &endp, 10);
596 if (argv[3][0] == '\0' || *endp != '\0')
606 isis_redist_set(area, level, family, type, metric, routemap, 0);
610 DEFUN(no_isis_redistribute,
611 no_isis_redistribute_cmd,
612 "no redistribute (ipv4|ipv6) " QUAGGA_REDIST_STR_ISISD
613 " (level-1|level-2)",
616 "Redistribute IPv4 routes\n"
617 "Redistribute IPv6 routes\n"
618 QUAGGA_REDIST_HELP_STR_ISISD
619 "Redistribute into level-1\n"
620 "Redistribute into level-2\n")
622 struct isis_area *area = vty->index;
631 family = str2family(argv[0]);
635 afi = family2afi(family);
639 type = proto_redistnum(afi, argv[1]);
640 if (type < 0 || type == ZEBRA_ROUTE_ISIS)
643 if (!strcmp("level-1", argv[2]))
645 else if (!strcmp("level-2", argv[2]))
650 isis_redist_unset(area, level, family, type);
654 DEFUN(isis_default_originate,
655 isis_default_originate_cmd,
656 "default-information originate (ipv4|ipv6) (level-1|level-2) "
657 "{always|metric <0-16777215>|route-map WORD}",
658 "Control distribution of default information\n"
659 "Distribute a default route\n"
660 "Distribute default route for IPv4\n"
661 "Distribute default route for IPv6\n"
662 "Distribute default route into level-1\n"
663 "Distribute default route into level-2\n"
664 "Always advertise default route\n"
665 "Metric for default route\n"
666 "ISIS default metric\n"
667 "Route map reference\n"
668 "Pointer to route-map entries\n")
670 struct isis_area *area = vty->index;
674 unsigned long metric;
675 const char *routemap;
680 family = str2family(argv[0]);
684 if (!strcmp("level-1", argv[1]))
686 else if (!strcmp("level-2", argv[1]))
691 if ((area->is_type & level) != level)
693 vty_out(vty, "Node is not a level-%d IS%s", level, VTY_NEWLINE);
697 if (argv[2] && *argv[2] != '\0')
698 originate_type = DEFAULT_ORIGINATE_ALWAYS;
700 originate_type = DEFAULT_ORIGINATE;
702 if (family == AF_INET6 && originate_type != DEFAULT_ORIGINATE_ALWAYS)
704 vty_out(vty, "Zebra doesn't implement default-originate for IPv6 yet%s", VTY_NEWLINE);
705 vty_out(vty, "so use with care or use default-originate always.%s", VTY_NEWLINE);
711 metric = strtoul(argv[3], &endp, 10);
712 if (argv[3][0] == '\0' || *endp != '\0')
722 isis_redist_set(area, level, family, DEFAULT_ROUTE, metric, routemap, originate_type);
726 DEFUN(no_isis_default_originate,
727 no_isis_default_originate_cmd,
728 "no default-information originate (ipv4|ipv6) (level-1|level-2)",
730 "Control distribution of default information\n"
731 "Distribute a default route\n"
732 "Distribute default route for IPv4\n"
733 "Distribute default route for IPv6\n"
734 "Distribute default route into level-1\n"
735 "Distribute default route into level-2\n")
737 struct isis_area *area = vty->index;
745 family = str2family(argv[0]);
749 if (!strcmp("level-1", argv[1]))
751 else if (!strcmp("level-2", argv[1]))
756 isis_redist_unset(area, level, family, DEFAULT_ROUTE);
761 isis_redist_config_write(struct vty *vty, struct isis_area *area,
767 struct isis_redist *redist;
768 const char *family_str;
770 if (family == AF_INET)
772 else if (family == AF_INET6)
777 for (type = 0; type < ZEBRA_ROUTE_MAX; type++)
779 if (type == ZEBRA_ROUTE_ISIS)
782 for (level = 1; level <= ISIS_LEVELS; level++)
784 redist = get_redist_settings(area, family, type, level);
787 vty_out(vty, " redistribute %s %s level-%d",
788 family_str, zebra_route_string(type), level);
789 if (redist->metric != 0xffffffff)
790 vty_out(vty, " metric %u", redist->metric);
791 if (redist->map_name)
792 vty_out(vty, " route-map %s", redist->map_name);
793 vty_out(vty, "%s", VTY_NEWLINE);
798 for (level = 1; level <= ISIS_LEVELS; level++)
800 redist = get_redist_settings(area, family, DEFAULT_ROUTE, level);
803 vty_out(vty, " default-information originate %s level-%d",
805 if (redist->redist == DEFAULT_ORIGINATE_ALWAYS)
806 vty_out(vty, " always");
807 if (redist->metric != 0xffffffff)
808 vty_out(vty, " metric %u", redist->metric);
809 if (redist->map_name)
810 vty_out(vty, " route-map %s", redist->map_name);
811 vty_out(vty, "%s", VTY_NEWLINE);
819 isis_redist_init(void)
821 install_element(ISIS_NODE, &isis_redistribute_cmd);
822 install_element(ISIS_NODE, &no_isis_redistribute_cmd);
823 install_element(ISIS_NODE, &isis_default_originate_cmd);
824 install_element(ISIS_NODE, &no_isis_default_originate_cmd);