Import Upstream version 1.2.2
[quagga-debian.git] / isisd / isis_redist.c
1 /*
2  * IS-IS Rout(e)ing protocol - isis_redist.c
3  *
4  * Copyright (C) 2013-2015 Christian Franke <chris@opensourcerouting.org>
5  *
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) 
9  * any later version.
10  *
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 
14  * more details.
15
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.
19  */
20
21 #include <zebra.h>
22
23 #include "command.h"
24 #include "if.h"
25 #include "linklist.h"
26 #include "memory.h"
27 #include "memtypes.h"
28 #include "prefix.h"
29 #include "routemap.h"
30 #include "stream.h"
31 #include "table.h"
32 #include "vty.h"
33
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"
45
46 static int
47 redist_protocol(int family)
48 {
49   if (family == AF_INET)
50     return 0;
51   if (family == AF_INET6)
52     return 1;
53
54   assert(!"Unsupported address family!");
55   return 0;
56 }
57
58 static int
59 is_default(struct prefix *p)
60 {
61   if (p->family == AF_INET)
62     if (p->u.prefix4.s_addr == 0 && p->prefixlen == 0)
63       return 1;
64   if (p->family == AF_INET6)
65     if (IN6_IS_ADDR_UNSPECIFIED(&p->u.prefix6) && p->prefixlen == 0)
66       return 1;
67   return 0;
68 }
69
70 static struct route_table*
71 get_ext_info(struct isis *i, int family)
72 {
73   int protocol = redist_protocol(family);
74
75   return i->ext_info[protocol];
76 }
77
78 static struct isis_redist*
79 get_redist_settings(struct isis_area *area, int family, int type, int level)
80 {
81   int protocol = redist_protocol(family);
82
83   return &area->redist_settings[protocol][type][level-1];
84 }
85
86 struct route_table*
87 get_ext_reach(struct isis_area *area, int family, int level)
88 {
89   int protocol = redist_protocol(family);
90
91   return area->ext_reach[protocol][level-1];
92 }
93
94 static struct route_node *
95 isis_redist_route_node_create(route_table_delegate_t *delegate,
96                               struct route_table *table)
97 {
98   struct route_node *node;
99   node = XCALLOC(MTYPE_ROUTE_NODE, sizeof(*node));
100   return node;
101 }
102
103 static void
104 isis_redist_route_node_destroy(route_table_delegate_t *delegate,
105                                struct route_table *table,
106                                struct route_node *node)
107 {
108   if (node->info)
109     XFREE(MTYPE_ISIS, node->info);
110   XFREE (MTYPE_ROUTE_NODE, node);
111 }
112
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
116 };
117
118 /* Install external reachability information into a
119  * specific area for a specific level.
120  * Schedule an lsp regenerate if necessary */
121 static void
122 isis_redist_install(struct isis_area *area, int level,
123                     struct prefix *p, struct isis_ext_info *info)
124 {
125   int family = p->family;
126   struct route_table *er_table = get_ext_reach(area, family, level);
127   struct route_node *er_node;
128
129   if (!er_table)
130     {
131       zlog_warn("%s: External reachability table of area %s"
132                 " is not initialized.", __func__, area->area_tag);
133       return;
134     }
135
136   er_node = route_node_get(er_table, p);
137   if (er_node->info)
138     {
139       route_unlock_node(er_node);
140
141       /* Don't update/reschedule lsp generation if nothing changed. */
142       if (!memcmp(er_node->info, info, sizeof(*info)))
143         return;
144     }
145   else
146     {
147       er_node->info = XMALLOC(MTYPE_ISIS, sizeof(*info));
148     }
149
150   memcpy(er_node->info, info, sizeof(*info));
151   lsp_regenerate_schedule(area, level, 0);
152 }
153
154 /* Remove external reachability information from a
155  * specific area for a specific level.
156  * Schedule an lsp regenerate if necessary. */
157 static void
158 isis_redist_uninstall(struct isis_area *area, int level, struct prefix *p)
159 {
160   int family = p->family;
161   struct route_table *er_table = get_ext_reach(area, family, level);
162   struct route_node *er_node;
163
164   if (!er_table)
165     {
166       zlog_warn("%s: External reachability table of area %s"
167                 " is not initialized.", __func__, area->area_tag);
168       return;
169     }
170
171   er_node = route_node_lookup(er_table, p);
172   if (!er_node)
173     return;
174   else
175     route_unlock_node(er_node);
176
177   if (!er_node->info)
178     return;
179
180   XFREE(MTYPE_ISIS, er_node->info);
181   route_unlock_node(er_node);
182   lsp_regenerate_schedule(area, level, 0);
183 }
184
185 /* Update external reachability info of area for a given level
186  * and prefix, using the given redistribution settings. */
187 static void
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)
191 {
192   struct isis_ext_info area_info;
193   route_map_result_t map_ret;
194
195   memcpy(&area_info, info, sizeof(area_info));
196   if (redist->metric != 0xffffffff)
197     area_info.metric = redist->metric;
198
199   if (redist->map_name)
200     {
201       map_ret = route_map_apply(redist->map, p, RMAP_ISIS, &area_info);
202       if (map_ret == RMAP_DENYMATCH)
203         area_info.distance = 255;
204     }
205
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;
210
211   if (area_info.distance < 255)
212     isis_redist_install(area, level, p, &area_info);
213   else
214     isis_redist_uninstall(area, level, p);
215 }
216
217 static void
218 isis_redist_ensure_default(struct isis *isis, int family)
219 {
220   struct prefix p;
221   struct route_table *ei_table = get_ext_info(isis, family);
222   struct route_node *ei_node;
223   struct isis_ext_info *info;
224
225   if (family == AF_INET)
226     {
227       p.family = AF_INET;
228       p.prefixlen = 0;
229       memset(&p.u.prefix4, 0, sizeof(p.u.prefix4));
230     }
231   else if (family == AF_INET6)
232     {
233       p.family = AF_INET6;
234       p.prefixlen = 0;
235       memset(&p.u.prefix6, 0, sizeof(p.u.prefix6));
236     }
237   else
238     assert(!"Unknown family!");
239
240   ei_node = route_node_get(ei_table, &p);
241   if (ei_node->info)
242     {
243       route_unlock_node(ei_node);
244       return;
245     }
246
247   ei_node->info = XCALLOC(MTYPE_ISIS, sizeof(struct isis_ext_info));
248
249   info = ei_node->info;
250   info->origin = DEFAULT_ROUTE;
251   info->distance = 254;
252   info->metric = MAX_WIDE_PATH_METRIC;
253 }
254
255 /* Handle notification about route being added */
256 void
257 isis_redist_add(int type, struct prefix *p, u_char distance, uint32_t metric)
258 {
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;
265   int level;
266   struct isis_redist *redist;
267
268   char debug_buf[BUFSIZ];
269   prefix2str(p, debug_buf, sizeof(debug_buf));
270
271   zlog_debug("%s: New route %s from %s.", __func__, debug_buf,
272              zebra_route_string(type));
273
274   if (!ei_table)
275     {
276       zlog_warn("%s: External information table not initialized.",
277                 __func__);
278       return;
279     }
280
281   ei_node = route_node_get(ei_table, p);
282   if (ei_node->info)
283     route_unlock_node(ei_node);
284   else
285     ei_node->info = XCALLOC(MTYPE_ISIS, sizeof(struct isis_ext_info));
286
287   info = ei_node->info;
288   info->origin = type;
289   info->distance = distance;
290   info->metric = metric;
291
292   if (is_default(p))
293     type = DEFAULT_ROUTE;
294
295   for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area))
296     for (level = 1; level <= ISIS_LEVELS; level++)
297       {
298         redist = get_redist_settings(area, family, type, level);
299         if (!redist->redist)
300           continue;
301
302         isis_redist_update_ext_reach(area, level, redist, p, info);
303       }
304 }
305
306 void
307 isis_redist_delete(int type, struct prefix *p)
308 {
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;
314   int level;
315   struct isis_redist *redist;
316
317   char debug_buf[BUFSIZ];
318   prefix2str(p, debug_buf, sizeof(debug_buf));
319
320   zlog_debug("%s: Removing route %s from %s.", __func__, debug_buf,
321              zebra_route_string(type));
322
323   if (is_default(p))
324     {
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);
329       return;
330     }
331
332   if (!ei_table)
333     {
334       zlog_warn("%s: External information table not initialized.",
335                 __func__);
336       return;
337     }
338
339   ei_node = route_node_lookup(ei_table, p);
340   if (!ei_node || !ei_node->info)
341     {
342       char buf[BUFSIZ];
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),
346                 buf);
347       if (ei_node)
348         route_unlock_node(ei_node);
349       return;
350     }
351   route_unlock_node(ei_node);
352
353   for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area))
354     for (level = 1; level < ISIS_LEVELS; level++)
355       {
356         redist = get_redist_settings(area, family, type, level);
357         if (!redist->redist)
358           continue;
359
360         isis_redist_uninstall(area, level, p);
361       }
362
363   XFREE(MTYPE_ISIS, ei_node->info);
364   route_unlock_node(ei_node);
365 }
366
367 static void
368 isis_redist_routemap_set(struct isis_redist *redist, const char *routemap)
369 {
370   if (redist->map_name) {
371     XFREE(MTYPE_ISIS, redist->map_name);
372     redist->map = NULL;
373   }
374
375   if (routemap && strlen(routemap)) {
376     redist->map_name = XSTRDUP(MTYPE_ISIS, routemap);
377     redist->map = route_map_lookup_by_name(routemap);
378   }
379 }
380
381 static void
382 isis_redist_update_zebra_subscriptions(struct isis *isis)
383 {
384   struct listnode *node;
385   struct isis_area *area;
386   int type;
387   int level;
388   int protocol;
389
390   char do_subscribe[ZEBRA_ROUTE_MAX + 1];
391
392   memset(do_subscribe, 0, sizeof(do_subscribe));
393
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;
400
401   for (type = 0; type < ZEBRA_ROUTE_MAX + 1; type++)
402     {
403       /* This field is actually controlling transmission of the IS-IS
404        * routes to Zebra and has nothing to do with redistribution,
405        * so skip it. */
406       if (type == ZEBRA_ROUTE_ISIS)
407         continue;
408
409       if (do_subscribe[type])
410         isis_zebra_redistribute_set(type);
411       else
412         isis_zebra_redistribute_unset(type);
413     }
414 }
415
416 static void
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)
420 {
421   int protocol = redist_protocol(family);
422   struct isis_redist *redist = get_redist_settings(area, family, type, level);
423   int i;
424   struct route_table *ei_table;
425   struct route_node *rn;
426   struct isis_ext_info *info;
427
428   redist->redist = (type == DEFAULT_ROUTE) ? originate_type : 1;
429   redist->metric = metric;
430   isis_redist_routemap_set(redist, routemap);
431
432   if (!area->ext_reach[protocol][level-1])
433     {
434       area->ext_reach[protocol][level-1] =
435           route_table_init_with_delegate(&isis_redist_rt_delegate);
436     }
437
438   for (i = 0; i < REDIST_PROTOCOL_COUNT; i++)
439     if (!area->isis->ext_info[i])
440       {
441         area->isis->ext_info[i] =
442             route_table_init_with_delegate(&isis_redist_rt_delegate);
443       }
444
445   isis_redist_update_zebra_subscriptions(area->isis);
446
447   if (type == DEFAULT_ROUTE && originate_type == DEFAULT_ORIGINATE_ALWAYS)
448     isis_redist_ensure_default(area->isis, family);
449
450   ei_table = get_ext_info(area->isis, family);
451   for (rn = route_top(ei_table); rn; rn = route_next(rn))
452     {
453       if (!rn->info)
454         continue;
455       info = rn->info;
456
457       if (type == DEFAULT_ROUTE)
458         {
459           if (!is_default(&rn->p))
460             continue;
461         }
462       else
463         {
464           if (info->origin != type)
465             continue;
466         }
467
468       isis_redist_update_ext_reach(area, level, redist, &rn->p, info);
469     }
470 }
471
472 static void
473 isis_redist_unset(struct isis_area *area, int level,
474                   int family, int type)
475 {
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;
480
481   if (!redist->redist)
482     return;
483
484   redist->redist = 0;
485   if (!er_table)
486     {
487       zlog_warn("%s: External reachability table uninitialized.", __func__);
488       return;
489     }
490
491   for (rn = route_top(er_table); rn; rn = route_next(rn))
492     {
493       if (!rn->info)
494         continue;
495       info = rn->info;
496
497       if (type == DEFAULT_ROUTE)
498         {
499           if (!is_default(&rn->p))
500             continue;
501         }
502       else
503         {
504           if (info->origin != type)
505             continue;
506         }
507
508       XFREE(MTYPE_ISIS, rn->info);
509       route_unlock_node(rn);
510     }
511
512   lsp_regenerate_schedule(area, level, 0);
513   isis_redist_update_zebra_subscriptions(area->isis);
514 }
515
516 void
517 isis_redist_area_finish(struct isis_area *area)
518 {
519   int protocol;
520   int level;
521   int type;
522
523   for (protocol = 0; protocol < REDIST_PROTOCOL_COUNT; protocol++)
524     for (level = 0; level < ISIS_LEVELS; level++)
525       {
526         for (type = 0; type < ZEBRA_ROUTE_MAX + 1; type++)
527           {
528             struct isis_redist *redist;
529
530             redist = &area->redist_settings[protocol][type][level];
531             redist->redist = 0;
532             if (redist->map_name)
533               XFREE(MTYPE_ISIS, redist->map_name);
534           }
535         route_table_finish(area->ext_reach[protocol][level]);
536       }
537
538   isis_redist_update_zebra_subscriptions(area->isis);
539 }
540
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}",
545       REDIST_STR
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")
555 {
556   struct isis_area *area = vty->index;
557   int family;
558   int afi;
559   int type;
560   int level;
561   unsigned long metric;
562   const char *routemap;
563
564   if (argc < 5)
565     return CMD_WARNING;
566
567   family = str2family(argv[0]);
568   if (family < 0)
569     return CMD_WARNING;
570
571   afi = family2afi(family);
572   if (!afi)
573     return CMD_WARNING;
574
575   type = proto_redistnum(afi, argv[1]);
576   if (type < 0 || type == ZEBRA_ROUTE_ISIS)
577     return CMD_WARNING;
578
579   if (!strcmp("level-1", argv[2]))
580     level = 1;
581   else if (!strcmp("level-2", argv[2]))
582     level = 2;
583   else
584     return CMD_WARNING;
585
586   if ((area->is_type & level) != level)
587     {
588       vty_out(vty, "Node is not a level-%d IS%s", level, VTY_NEWLINE);
589       return CMD_WARNING;
590     }
591
592   if (argv[3])
593     {
594       char *endp;
595       metric = strtoul(argv[3], &endp, 10);
596       if (argv[3][0] == '\0' || *endp != '\0')
597         return CMD_WARNING;
598     }
599   else
600     {
601       metric = 0xffffffff;
602     }
603
604   routemap = argv[4];
605
606   isis_redist_set(area, level, family, type, metric, routemap, 0);
607   return 0;
608 }
609
610 DEFUN(no_isis_redistribute,
611       no_isis_redistribute_cmd,
612       "no redistribute (ipv4|ipv6) " QUAGGA_REDIST_STR_ISISD
613       " (level-1|level-2)",
614       NO_STR
615       REDIST_STR
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")
621 {
622   struct isis_area *area = vty->index;
623   int type;
624   int level;
625   int family;
626   int afi;
627
628   if (argc < 3)
629     return CMD_WARNING;
630
631   family = str2family(argv[0]);
632   if (family < 0)
633     return CMD_WARNING;
634
635   afi = family2afi(family);
636   if (!afi)
637     return CMD_WARNING;
638
639   type = proto_redistnum(afi, argv[1]);
640   if (type < 0 || type == ZEBRA_ROUTE_ISIS)
641     return CMD_WARNING;
642
643   if (!strcmp("level-1", argv[2]))
644     level = 1;
645   else if (!strcmp("level-2", argv[2]))
646     level = 2;
647   else
648     return CMD_WARNING;
649
650   isis_redist_unset(area, level, family, type);
651   return 0;
652 }
653
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")
669 {
670   struct isis_area *area = vty->index;
671   int family;
672   int originate_type;
673   int level;
674   unsigned long metric;
675   const char *routemap;
676
677   if (argc < 5)
678     return CMD_WARNING;
679
680   family = str2family(argv[0]);
681   if (family < 0)
682     return CMD_WARNING;
683
684   if (!strcmp("level-1", argv[1]))
685     level = 1;
686   else if (!strcmp("level-2", argv[1]))
687     level = 2;
688   else
689     return CMD_WARNING;
690
691   if ((area->is_type & level) != level)
692     {
693       vty_out(vty, "Node is not a level-%d IS%s", level, VTY_NEWLINE);
694       return CMD_WARNING;
695     }
696
697   if (argv[2] && *argv[2] != '\0')
698     originate_type = DEFAULT_ORIGINATE_ALWAYS;
699   else
700     originate_type = DEFAULT_ORIGINATE;
701
702   if (family == AF_INET6 && originate_type != DEFAULT_ORIGINATE_ALWAYS)
703     {
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);
706     }
707
708   if (argv[3])
709     {
710       char *endp;
711       metric = strtoul(argv[3], &endp, 10);
712       if (argv[3][0] == '\0' || *endp != '\0')
713         return CMD_WARNING;
714     }
715   else
716     {
717       metric = 0xffffffff;
718     }
719
720   routemap = argv[4];
721
722   isis_redist_set(area, level, family, DEFAULT_ROUTE, metric, routemap, originate_type);
723   return 0;
724 }
725
726 DEFUN(no_isis_default_originate,
727       no_isis_default_originate_cmd,
728       "no default-information originate (ipv4|ipv6) (level-1|level-2)",
729       NO_STR
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")
736 {
737   struct isis_area *area = vty->index;
738
739   int family;
740   int level;
741
742   if (argc < 2)
743     return CMD_WARNING;
744
745   family = str2family(argv[0]);
746   if (family < 0)
747     return CMD_WARNING;
748
749   if (!strcmp("level-1", argv[1]))
750     level = 1;
751   else if (!strcmp("level-2", argv[1]))
752     level = 2;
753   else
754     return CMD_WARNING;
755
756   isis_redist_unset(area, level, family, DEFAULT_ROUTE);
757   return 0;
758 }
759
760 int
761 isis_redist_config_write(struct vty *vty, struct isis_area *area,
762                          int family)
763 {
764   int type;
765   int level;
766   int write = 0;
767   struct isis_redist *redist;
768   const char *family_str;
769
770   if (family == AF_INET)
771     family_str = "ipv4";
772   else if (family == AF_INET6)
773     family_str = "ipv6";
774   else
775     return 0;
776
777   for (type = 0; type < ZEBRA_ROUTE_MAX; type++)
778     {
779       if (type == ZEBRA_ROUTE_ISIS)
780         continue;
781
782       for (level = 1; level <= ISIS_LEVELS; level++)
783         {
784           redist = get_redist_settings(area, family, type, level);
785           if (!redist->redist)
786             continue;
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);
794           write++;
795         }
796     }
797
798   for (level = 1; level <= ISIS_LEVELS; level++)
799     {
800       redist = get_redist_settings(area, family, DEFAULT_ROUTE, level);
801       if (!redist->redist)
802         continue;
803       vty_out(vty, " default-information originate %s level-%d",
804               family_str, level);
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);
812       write++;
813     }
814
815   return write;
816 }
817
818 void
819 isis_redist_init(void)
820 {
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);
825 }