Import Upstream version 1.2.2
[quagga-debian.git] / lib / distribute.c
1 /* Distribute list functions
2  * Copyright (C) 1998, 1999 Kunihiro Ishiguro
3  *
4  * This file is part of GNU Zebra.
5  *
6  * GNU Zebra is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published
8  * by the Free Software Foundation; either version 2, or (at your
9  * option) any 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 "hash.h"
25 #include "if.h"
26 #include "filter.h"
27 #include "command.h"
28 #include "distribute.h"
29 #include "memory.h"
30
31 /* Hash of distribute list. */
32 struct hash *disthash;
33
34 /* Hook functions. */
35 void (*distribute_add_hook) (struct distribute *);
36 void (*distribute_delete_hook) (struct distribute *);
37
38 static struct distribute *
39 distribute_new (void)
40 {
41   return XCALLOC (MTYPE_DISTRIBUTE, sizeof (struct distribute));
42 }
43
44 /* Free distribute object. */
45 static void
46 distribute_free (struct distribute *dist)
47 {
48   int i = 0;
49   if (dist->ifname)
50     XFREE (MTYPE_DISTRIBUTE_IFNAME, dist->ifname);
51
52   for (i=0; i < DISTRIBUTE_MAX; i++)
53     if (dist->list[i])
54       free(dist->list[i]);
55
56   for (i=0; i < DISTRIBUTE_MAX; i++)
57     if (dist->prefix[i])
58       free(dist->prefix[i]);
59
60   XFREE (MTYPE_DISTRIBUTE, dist);
61 }
62
63 static void
64 distribute_free_if_empty(struct distribute *dist)
65 {
66   int i;
67   for (i=0; i < DISTRIBUTE_MAX; i++)
68     if (dist->list[i] != NULL || dist->prefix[i] != NULL)
69       return;
70
71   hash_release (disthash, dist);
72   distribute_free (dist);
73 }
74
75 /* Lookup interface's distribute list. */
76 struct distribute *
77 distribute_lookup (const char *ifname)
78 {
79   struct distribute key;
80   struct distribute *dist;
81
82   /* temporary reference */
83   key.ifname = (char *)ifname;
84
85   dist = hash_lookup (disthash, &key);
86   
87   return dist;
88 }
89
90 void
91 distribute_list_add_hook (void (*func) (struct distribute *))
92 {
93   distribute_add_hook = func;
94 }
95
96 void
97 distribute_list_delete_hook (void (*func) (struct distribute *))
98 {
99   distribute_delete_hook = func;
100 }
101
102 static void *
103 distribute_hash_alloc (struct distribute *arg)
104 {
105   struct distribute *dist;
106
107   dist = distribute_new ();
108   if (arg->ifname)
109     dist->ifname = XSTRDUP (MTYPE_DISTRIBUTE_IFNAME, arg->ifname);
110   else
111     dist->ifname = NULL;
112   return dist;
113 }
114
115 /* Make new distribute list and push into hash. */
116 static struct distribute *
117 distribute_get (const char *ifname)
118 {
119   struct distribute key;
120
121   /* temporary reference */
122   key.ifname = (char *)ifname;
123   
124   return hash_get (disthash, &key, (void * (*) (void *))distribute_hash_alloc);
125 }
126
127 static unsigned int
128 distribute_hash_make (void *arg)
129 {
130   const struct distribute *dist = arg;
131
132   return dist->ifname ? string_hash_make (dist->ifname) : 0;
133 }
134
135 /* If two distribute-list have same value then return 1 else return
136    0. This function is used by hash package. */
137 static int
138 distribute_cmp (const struct distribute *dist1, const struct distribute *dist2)
139 {
140   if (dist1->ifname && dist2->ifname)
141     if (strcmp (dist1->ifname, dist2->ifname) == 0)
142       return 1;
143   if (! dist1->ifname && ! dist2->ifname)
144     return 1;
145   return 0;
146 }
147
148 /* Set access-list name to the distribute list. */
149 static struct distribute *
150 distribute_list_set (const char *ifname, enum distribute_type type,
151                      const char *alist_name)
152 {
153   struct distribute *dist;
154
155   dist = distribute_get (ifname);
156
157   if (dist->list[type])
158     free (dist->list[type]);
159   dist->list[type] = strdup (alist_name);
160
161   /* Apply this distribute-list to the interface. */
162   (*distribute_add_hook) (dist);
163
164   return dist;
165 }
166
167 /* Unset distribute-list.  If matched distribute-list exist then
168    return 1. */
169 static int
170 distribute_list_unset (const char *ifname, enum distribute_type type,
171                        const char *alist_name)
172 {
173   struct distribute *dist;
174
175   dist = distribute_lookup (ifname);
176   if (!dist)
177     return 0;
178
179   if (!dist->list[type])
180     return 0;
181   if (strcmp (dist->list[type], alist_name) != 0)
182     return 0;
183
184   free (dist->list[type]);
185   dist->list[type] = NULL;
186
187   /* Apply this distribute-list to the interface. */
188   (*distribute_delete_hook) (dist);
189
190   /* If all dist are NULL, then free distribute list. */
191   distribute_free_if_empty(dist);
192   return 1;
193 }
194
195 /* Set access-list name to the distribute list. */
196 static struct distribute *
197 distribute_list_prefix_set (const char *ifname, enum distribute_type type,
198                             const char *plist_name)
199 {
200   struct distribute *dist;
201
202   dist = distribute_get (ifname);
203
204   if (dist->prefix[type])
205     free (dist->prefix[type]);
206   dist->prefix[type] = strdup (plist_name);
207
208   /* Apply this distribute-list to the interface. */
209   (*distribute_add_hook) (dist);
210   
211   return dist;
212 }
213
214 /* Unset distribute-list.  If matched distribute-list exist then
215    return 1. */
216 static int
217 distribute_list_prefix_unset (const char *ifname, enum distribute_type type,
218                               const char *plist_name)
219 {
220   struct distribute *dist;
221
222   dist = distribute_lookup (ifname);
223   if (!dist)
224     return 0;
225
226   if (!dist->prefix[type])
227     return 0;
228   if (strcmp (dist->prefix[type], plist_name) != 0)
229     return 0;
230
231   free (dist->prefix[type]);
232   dist->prefix[type] = NULL;
233
234   /* Apply this distribute-list to the interface. */
235   (*distribute_delete_hook) (dist);
236
237   /* If all dist are NULL, then free distribute list. */
238   distribute_free_if_empty(dist);
239   return 1;
240 }
241
242 DEFUN (distribute_list_all,
243        distribute_list_all_cmd,
244        "distribute-list WORD (in|out)",
245        "Filter networks in routing updates\n"
246        "Access-list name\n"
247        "Filter incoming routing updates\n"
248        "Filter outgoing routing updates\n")
249 {
250   enum distribute_type type;
251
252   /* Check of distribute list type. */
253   if (strncmp (argv[1], "i", 1) == 0)
254     type = DISTRIBUTE_V4_IN;
255   else if (strncmp (argv[1], "o", 1) == 0)
256     type = DISTRIBUTE_V4_OUT;
257   else
258     {
259       vty_out (vty, "distribute list direction must be [in|out]%s",
260                VTY_NEWLINE);
261       return CMD_WARNING;
262     }
263
264   /* Get interface name corresponding distribute list. */
265   distribute_list_set (NULL, type, argv[0]);
266
267   return CMD_SUCCESS;
268 }
269
270 DEFUN (ipv6_distribute_list_all,
271        ipv6_distribute_list_all_cmd,
272        "ipv6 distribute-list WORD (in|out)",
273        "Filter networks in routing updates\n"
274        "Access-list name\n"
275        "Filter incoming routing updates\n"
276        "Filter outgoing routing updates\n")
277 {
278   enum distribute_type type;
279
280   /* Check of distribute list type. */
281   if (strncmp (argv[1], "i", 1) == 0)
282     type = DISTRIBUTE_V6_IN;
283   else if (strncmp (argv[1], "o", 1) == 0)
284     type = DISTRIBUTE_V6_OUT;
285   else
286   {
287     vty_out (vty, "distribute list direction must be [in|out]%s",
288              VTY_NEWLINE);
289     return CMD_WARNING;
290   }
291
292   /* Get interface name corresponding distribute list. */
293   distribute_list_set (NULL, type, argv[0]);
294
295   return CMD_SUCCESS;
296 }
297
298 ALIAS (ipv6_distribute_list_all,
299        ipv6_as_v4_distribute_list_all_cmd,
300        "distribute-list WORD (in|out)",
301        "Filter networks in routing updates\n"
302        "Access-list name\n"
303        "Filter incoming routing updates\n"
304        "Filter outgoing routing updates\n")
305
306 DEFUN (no_distribute_list_all,
307        no_distribute_list_all_cmd,
308        "no distribute-list WORD (in|out)",
309        NO_STR
310        "Filter networks in routing updates\n"
311        "Access-list name\n"
312        "Filter incoming routing updates\n"
313        "Filter outgoing routing updates\n")
314 {
315   int ret;
316   enum distribute_type type;
317
318   /* Check of distribute list type. */
319   if (strncmp (argv[1], "i", 1) == 0)
320     type = DISTRIBUTE_V4_IN;
321   else if (strncmp (argv[1], "o", 1) == 0)
322     type = DISTRIBUTE_V4_OUT;
323   else
324     {
325       vty_out (vty, "distribute list direction must be [in|out]%s",
326                VTY_NEWLINE);
327       return CMD_WARNING;
328     }
329
330   ret = distribute_list_unset (NULL, type, argv[0]);
331   if (! ret)
332     {
333       vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE);
334       return CMD_WARNING;
335     }
336   return CMD_SUCCESS;
337 }
338
339 DEFUN (no_ipv6_distribute_list_all,
340        no_ipv6_distribute_list_all_cmd,
341        "no ipv6 distribute-list WORD (in|out)",
342        NO_STR
343        "Filter networks in routing updates\n"
344        "Access-list name\n"
345        "Filter incoming routing updates\n"
346        "Filter outgoing routing updates\n")
347 {
348   int ret;
349   enum distribute_type type;
350
351   /* Check of distribute list type. */
352   if (strncmp (argv[1], "i", 1) == 0)
353     type = DISTRIBUTE_V6_IN;
354   else if (strncmp (argv[1], "o", 1) == 0)
355     type = DISTRIBUTE_V6_OUT;
356   else
357   {
358     vty_out (vty, "distribute list direction must be [in|out]%s",
359              VTY_NEWLINE);
360     return CMD_WARNING;
361   }
362
363   ret = distribute_list_unset (NULL, type, argv[0]);
364   if (! ret)
365   {
366     vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE);
367     return CMD_WARNING;
368   }
369   return CMD_SUCCESS;
370 }
371
372 ALIAS (no_ipv6_distribute_list_all,
373        no_ipv6_as_v4_distribute_list_all_cmd,
374        "no distribute-list WORD (in|out)",
375        NO_STR
376        "Filter networks in routing updates\n"
377        "Access-list name\n"
378        "Filter incoming routing updates\n"
379        "Filter outgoing routing updates\n")
380
381 DEFUN (distribute_list,
382        distribute_list_cmd,
383        "distribute-list WORD (in|out) WORD",
384        "Filter networks in routing updates\n"
385        "Access-list name\n"
386        "Filter incoming routing updates\n"
387        "Filter outgoing routing updates\n"
388        "Interface name\n")
389 {
390   enum distribute_type type;
391
392   /* Check of distribute list type. */
393   if (strncmp (argv[1], "i", 1) == 0)
394     type = DISTRIBUTE_V4_IN;
395   else if (strncmp (argv[1], "o", 1) == 0)
396     type = DISTRIBUTE_V4_OUT;
397   else
398     {
399       vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE);
400       return CMD_WARNING;
401     }
402
403   /* Get interface name corresponding distribute list. */
404   distribute_list_set (argv[2], type, argv[0]);
405
406   return CMD_SUCCESS;
407 }
408
409 DEFUN (ipv6_distribute_list,
410        ipv6_distribute_list_cmd,
411        "ipv6 distribute-list WORD (in|out) WORD",
412        "Filter networks in routing updates\n"
413        "Access-list name\n"
414        "Filter incoming routing updates\n"
415        "Filter outgoing routing updates\n"
416        "Interface name\n")
417 {
418   enum distribute_type type;
419
420   /* Check of distribute list type. */
421   if (strncmp (argv[1], "i", 1) == 0)
422     type = DISTRIBUTE_V6_IN;
423   else if (strncmp (argv[1], "o", 1) == 0)
424     type = DISTRIBUTE_V6_OUT;
425   else
426   {
427     vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE);
428     return CMD_WARNING;
429   }
430
431   /* Get interface name corresponding distribute list. */
432   distribute_list_set (argv[2], type, argv[0]);
433
434   return CMD_SUCCESS;
435 }
436
437 ALIAS (ipv6_distribute_list,
438        ipv6_as_v4_distribute_list_cmd,
439        "distribute-list WORD (in|out) WORD",
440        "Filter networks in routing updates\n"
441        "Access-list name\n"
442        "Filter incoming routing updates\n"
443        "Filter outgoing routing updates\n"
444        "Interface name\n")
445
446 DEFUN (no_distribute_list, no_distribute_list_cmd,
447        "no distribute-list WORD (in|out) WORD",
448        NO_STR
449        "Filter networks in routing updates\n"
450        "Access-list name\n"
451        "Filter incoming routing updates\n"
452        "Filter outgoing routing updates\n"
453        "Interface name\n")
454 {
455   int ret;
456   enum distribute_type type;
457
458   /* Check of distribute list type. */
459   if (strncmp (argv[1], "i", 1) == 0)
460     type = DISTRIBUTE_V4_IN;
461   else if (strncmp (argv[1], "o", 1) == 0)
462     type = DISTRIBUTE_V4_OUT;
463   else
464     {
465       vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE);
466       return CMD_WARNING;
467     }
468
469   ret = distribute_list_unset (argv[2], type, argv[0]);
470   if (! ret)
471     {
472       vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE);
473       return CMD_WARNING;
474     }
475   return CMD_SUCCESS;
476 }
477
478 DEFUN (no_ipv6_distribute_list,
479        no_ipv6_distribute_list_cmd,
480        "no ipv6 distribute-list WORD (in|out) WORD",
481        NO_STR
482        "Filter networks in routing updates\n"
483        "Access-list name\n"
484        "Filter incoming routing updates\n"
485        "Filter outgoing routing updates\n"
486        "Interface name\n")
487 {
488   int ret;
489   enum distribute_type type;
490
491   /* Check of distribute list type. */
492   if (strncmp (argv[1], "i", 1) == 0)
493     type = DISTRIBUTE_V6_IN;
494   else if (strncmp (argv[1], "o", 1) == 0)
495     type = DISTRIBUTE_V6_OUT;
496   else
497   {
498     vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE);
499     return CMD_WARNING;
500   }
501
502   ret = distribute_list_unset (argv[2], type, argv[0]);
503   if (! ret)
504   {
505     vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE);
506     return CMD_WARNING;
507   }
508   return CMD_SUCCESS;
509 }
510
511 ALIAS (no_ipv6_distribute_list,
512        no_ipv6_as_v4_distribute_list_cmd,
513        "no distribute-list WORD (in|out) WORD",
514        NO_STR
515        "Filter networks in routing updates\n"
516        "Access-list name\n"
517        "Filter incoming routing updates\n"
518        "Filter outgoing routing updates\n"
519        "Interface name\n")
520
521 DEFUN (distribute_list_prefix_all,
522        distribute_list_prefix_all_cmd,
523        "distribute-list prefix WORD (in|out)",
524        "Filter networks in routing updates\n"
525        "Filter prefixes in routing updates\n"
526        "Name of an IP prefix-list\n"
527        "Filter incoming routing updates\n"
528        "Filter outgoing routing updates\n")
529 {
530   enum distribute_type type;
531
532   /* Check of distribute list type. */
533   if (strncmp (argv[1], "i", 1) == 0)
534     type = DISTRIBUTE_V4_IN;
535   else if (strncmp (argv[1], "o", 1) == 0)
536     type = DISTRIBUTE_V4_OUT;
537   else
538     {
539       vty_out (vty, "distribute list direction must be [in|out]%s",
540                VTY_NEWLINE);
541       return CMD_WARNING;
542     }
543
544   /* Get interface name corresponding distribute list. */
545   distribute_list_prefix_set (NULL, type, argv[0]);
546
547   return CMD_SUCCESS;
548 }
549
550 DEFUN (ipv6_distribute_list_prefix_all,
551        ipv6_distribute_list_prefix_all_cmd,
552        "ipv6 distribute-list prefix WORD (in|out)",
553        "Filter networks in routing updates\n"
554        "Filter prefixes in routing updates\n"
555        "Name of an IP prefix-list\n"
556        "Filter incoming routing updates\n"
557        "Filter outgoing routing updates\n")
558 {
559   enum distribute_type type;
560
561   /* Check of distribute list type. */
562   if (strncmp (argv[1], "i", 1) == 0)
563     type = DISTRIBUTE_V6_IN;
564   else if (strncmp (argv[1], "o", 1) == 0)
565     type = DISTRIBUTE_V6_OUT;
566   else
567   {
568     vty_out (vty, "distribute list direction must be [in|out]%s",
569              VTY_NEWLINE);
570     return CMD_WARNING;
571   }
572
573   /* Get interface name corresponding distribute list. */
574   distribute_list_prefix_set (NULL, type, argv[0]);
575
576   return CMD_SUCCESS;
577 }
578
579 ALIAS (ipv6_distribute_list_prefix_all,
580        ipv6_as_v4_distribute_list_prefix_all_cmd,
581        "distribute-list prefix WORD (in|out)",
582        "Filter networks in routing updates\n"
583        "Filter prefixes in routing updates\n"
584        "Name of an IP prefix-list\n"
585        "Filter incoming routing updates\n"
586        "Filter outgoing routing updates\n")
587
588 DEFUN (no_distribute_list_prefix_all,
589        no_distribute_list_prefix_all_cmd,
590        "no distribute-list prefix WORD (in|out)",
591        NO_STR
592        "Filter networks in routing updates\n"
593        "Filter prefixes in routing updates\n"
594        "Name of an IP prefix-list\n"
595        "Filter incoming routing updates\n"
596        "Filter outgoing routing updates\n")
597 {
598   int ret;
599   enum distribute_type type;
600
601   /* Check of distribute list type. */
602   if (strncmp (argv[1], "i", 1) == 0)
603     type = DISTRIBUTE_V4_IN;
604   else if (strncmp (argv[1], "o", 1) == 0)
605     type = DISTRIBUTE_V4_OUT;
606   else
607     {
608       vty_out (vty, "distribute list direction must be [in|out]%s",
609                VTY_NEWLINE);
610       return CMD_WARNING;
611     }
612
613   ret = distribute_list_prefix_unset (NULL, type, argv[0]);
614   if (! ret)
615     {
616       vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE);
617       return CMD_WARNING;
618     }
619   return CMD_SUCCESS;
620 }
621
622 DEFUN (no_ipv6_distribute_list_prefix_all,
623        no_ipv6_distribute_list_prefix_all_cmd,
624        "no ipv6 distribute-list prefix WORD (in|out)",
625        NO_STR
626        "Filter networks in routing updates\n"
627        "Filter prefixes in routing updates\n"
628        "Name of an IP prefix-list\n"
629        "Filter incoming routing updates\n"
630        "Filter outgoing routing updates\n")
631 {
632   int ret;
633   enum distribute_type type;
634
635   /* Check of distribute list type. */
636   if (strncmp (argv[1], "i", 1) == 0)
637     type = DISTRIBUTE_V6_IN;
638   else if (strncmp (argv[1], "o", 1) == 0)
639     type = DISTRIBUTE_V6_OUT;
640   else
641   {
642     vty_out (vty, "distribute list direction must be [in|out]%s",
643              VTY_NEWLINE);
644     return CMD_WARNING;
645   }
646
647   ret = distribute_list_prefix_unset (NULL, type, argv[0]);
648   if (! ret)
649   {
650     vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE);
651     return CMD_WARNING;
652   }
653   return CMD_SUCCESS;
654 }
655
656 ALIAS (no_ipv6_distribute_list_prefix_all,
657        no_ipv6_as_v4_distribute_list_prefix_all_cmd,
658        "no distribute-list prefix WORD (in|out)",
659        NO_STR
660        "Filter networks in routing updates\n"
661        "Filter prefixes in routing updates\n"
662        "Name of an IP prefix-list\n"
663        "Filter incoming routing updates\n"
664        "Filter outgoing routing updates\n")
665
666 DEFUN (distribute_list_prefix, distribute_list_prefix_cmd,
667        "distribute-list prefix WORD (in|out) WORD",
668        "Filter networks in routing updates\n"
669        "Filter prefixes in routing updates\n"
670        "Name of an IP prefix-list\n"
671        "Filter incoming routing updates\n"
672        "Filter outgoing routing updates\n"
673        "Interface name\n")
674 {
675   enum distribute_type type;
676
677   /* Check of distribute list type. */
678   if (strncmp (argv[1], "i", 1) == 0)
679     type = DISTRIBUTE_V4_IN;
680   else if (strncmp (argv[1], "o", 1) == 0)
681     type = DISTRIBUTE_V4_OUT;
682   else
683     {
684       vty_out (vty, "distribute list direction must be [in|out]%s",
685                VTY_NEWLINE);
686       return CMD_WARNING;
687     }
688
689   /* Get interface name corresponding distribute list. */
690   distribute_list_prefix_set (argv[2], type, argv[0]);
691
692   return CMD_SUCCESS;
693 }
694
695 DEFUN (ipv6_distribute_list_prefix,
696        ipv6_distribute_list_prefix_cmd,
697        "ipv6 distribute-list prefix WORD (in|out) WORD",
698        "Filter networks in routing updates\n"
699        "Filter prefixes in routing updates\n"
700        "Name of an IP prefix-list\n"
701        "Filter incoming routing updates\n"
702        "Filter outgoing routing updates\n"
703        "Interface name\n")
704 {
705   enum distribute_type type;
706
707   /* Check of distribute list type. */
708   if (strncmp (argv[1], "i", 1) == 0)
709     type = DISTRIBUTE_V6_IN;
710   else if (strncmp (argv[1], "o", 1) == 0)
711     type = DISTRIBUTE_V6_OUT;
712   else
713   {
714     vty_out (vty, "distribute list direction must be [in|out]%s",
715              VTY_NEWLINE);
716     return CMD_WARNING;
717   }
718
719   /* Get interface name corresponding distribute list. */
720   distribute_list_prefix_set (argv[2], type, argv[0]);
721
722   return CMD_SUCCESS;
723 }
724
725 ALIAS (ipv6_distribute_list_prefix,
726        ipv6_as_v4_distribute_list_prefix_cmd,
727        "distribute-list prefix WORD (in|out) WORD",
728        "Filter networks in routing updates\n"
729        "Filter prefixes in routing updates\n"
730        "Name of an IP prefix-list\n"
731        "Filter incoming routing updates\n"
732        "Filter outgoing routing updates\n"
733        "Interface name\n")
734
735 DEFUN (no_distribute_list_prefix, no_distribute_list_prefix_cmd,
736        "no distribute-list prefix WORD (in|out) WORD",
737        NO_STR
738        "Filter networks in routing updates\n"
739        "Filter prefixes in routing updates\n"
740        "Name of an IP prefix-list\n"
741        "Filter incoming routing updates\n"
742        "Filter outgoing routing updates\n"
743        "Interface name\n")
744 {
745   int ret;
746   enum distribute_type type;
747
748   /* Check of distribute list type. */
749   if (strncmp (argv[1], "i", 1) == 0)
750     type = DISTRIBUTE_V4_IN;
751   else if (strncmp (argv[1], "o", 1) == 0)
752     type = DISTRIBUTE_V4_OUT;
753   else
754     {
755       vty_out (vty, "distribute list direction must be [in|out]%s",
756                VTY_NEWLINE);
757       return CMD_WARNING;
758     }
759
760   ret = distribute_list_prefix_unset (argv[2], type, argv[0]);
761   if (! ret)
762     {
763       vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE);
764       return CMD_WARNING;
765     }
766   return CMD_SUCCESS;
767 }
768
769 DEFUN (no_ipv6_distribute_list_prefix,
770        no_ipv6_distribute_list_prefix_cmd,
771        "no ipv6 distribute-list prefix WORD (in|out) WORD",
772        NO_STR
773        "Filter networks in routing updates\n"
774        "Filter prefixes in routing updates\n"
775        "Name of an IP prefix-list\n"
776        "Filter incoming routing updates\n"
777        "Filter outgoing routing updates\n"
778        "Interface name\n")
779 {
780   int ret;
781   enum distribute_type type;
782
783   /* Check of distribute list type. */
784   if (strncmp (argv[1], "i", 1) == 0)
785     type = DISTRIBUTE_V6_IN;
786   else if (strncmp (argv[1], "o", 1) == 0)
787     type = DISTRIBUTE_V6_OUT;
788   else
789   {
790     vty_out (vty, "distribute list direction must be [in|out]%s",
791              VTY_NEWLINE);
792     return CMD_WARNING;
793   }
794
795   ret = distribute_list_prefix_unset (argv[2], type, argv[0]);
796   if (! ret)
797   {
798     vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE);
799     return CMD_WARNING;
800   }
801   return CMD_SUCCESS;
802 }
803
804 ALIAS (no_ipv6_distribute_list_prefix,
805        no_ipv6_as_v4_distribute_list_prefix_cmd,
806        "no distribute-list prefix WORD (in|out) WORD",
807        NO_STR
808        "Filter networks in routing updates\n"
809        "Filter prefixes in routing updates\n"
810        "Name of an IP prefix-list\n"
811        "Filter incoming routing updates\n"
812        "Filter outgoing routing updates\n"
813        "Interface name\n")
814
815 static int
816 distribute_print (struct vty *vty, char *tab[], int is_prefix,
817                   enum distribute_type type, int has_print)
818 {
819   if (tab[type]) {
820     vty_out (vty, "%s %s%s",
821              has_print ? "," : "",
822              is_prefix ? "(prefix-list) " : "",
823              tab[type]);
824     return 1;
825   }
826   return has_print;
827 }
828
829 int
830 config_show_distribute (struct vty *vty)
831 {
832   unsigned int i;
833   int has_print = 0;
834   struct hash_backet *mp;
835   struct distribute *dist;
836
837   /* Output filter configuration. */
838   dist = distribute_lookup (NULL);
839   vty_out(vty, "  Outgoing update filter list for all interface is");
840   has_print = 0;
841   if (dist)
842     {
843       has_print = distribute_print(vty, dist->list,   0,
844                                    DISTRIBUTE_V4_OUT, has_print);
845       has_print = distribute_print(vty, dist->prefix, 1,
846                                    DISTRIBUTE_V4_OUT, has_print);
847       has_print = distribute_print(vty, dist->list,   0,
848                                    DISTRIBUTE_V6_OUT, has_print);
849       has_print = distribute_print(vty, dist->prefix, 1,
850                                    DISTRIBUTE_V6_OUT, has_print);
851     }
852   if (has_print)
853     vty_out (vty, "%s", VTY_NEWLINE);
854   else
855     vty_out (vty, " not set%s", VTY_NEWLINE);
856
857   for (i = 0; i < disthash->size; i++)
858     for (mp = disthash->index[i]; mp; mp = mp->next)
859       {
860         dist = mp->data;
861         if (dist->ifname)
862           {
863             vty_out (vty, "    %s filtered by", dist->ifname);
864             has_print = 0;
865             has_print = distribute_print(vty, dist->list,   0,
866                                          DISTRIBUTE_V4_OUT, has_print);
867             has_print = distribute_print(vty, dist->prefix, 1,
868                                          DISTRIBUTE_V4_OUT, has_print);
869             has_print = distribute_print(vty, dist->list,   0,
870                                          DISTRIBUTE_V6_OUT, has_print);
871             has_print = distribute_print(vty, dist->prefix, 1,
872                                          DISTRIBUTE_V6_OUT, has_print);
873             if (has_print)
874               vty_out (vty, "%s", VTY_NEWLINE);
875             else
876               vty_out(vty, " nothing%s", VTY_NEWLINE);
877           }
878       }
879
880
881   /* Input filter configuration. */
882   dist = distribute_lookup (NULL);
883   vty_out(vty, "  Incoming update filter list for all interface is");
884   has_print = 0;
885   if (dist)
886     {
887       has_print = distribute_print(vty, dist->list,   0,
888                                    DISTRIBUTE_V4_IN, has_print);
889       has_print = distribute_print(vty, dist->prefix, 1,
890                                    DISTRIBUTE_V4_IN, has_print);
891       has_print = distribute_print(vty, dist->list,   0,
892                                    DISTRIBUTE_V6_IN, has_print);
893       has_print = distribute_print(vty, dist->prefix, 1,
894                                    DISTRIBUTE_V6_IN, has_print);
895     }
896   if (has_print)
897     vty_out (vty, "%s", VTY_NEWLINE);
898   else
899     vty_out (vty, " not set%s", VTY_NEWLINE);
900
901   for (i = 0; i < disthash->size; i++)
902     for (mp = disthash->index[i]; mp; mp = mp->next)
903       {
904         dist = mp->data;
905         if (dist->ifname)
906           {
907             vty_out (vty, "    %s filtered by", dist->ifname);
908             has_print = 0;
909             has_print = distribute_print(vty, dist->list,   0,
910                                          DISTRIBUTE_V4_IN, has_print);
911             has_print = distribute_print(vty, dist->prefix, 1,
912                                          DISTRIBUTE_V4_IN, has_print);
913             has_print = distribute_print(vty, dist->list,   0,
914                                          DISTRIBUTE_V6_IN, has_print);
915             has_print = distribute_print(vty, dist->prefix, 1,
916                                          DISTRIBUTE_V6_IN, has_print);
917             if (has_print)
918               vty_out (vty, "%s", VTY_NEWLINE);
919             else
920               vty_out(vty, " nothing%s", VTY_NEWLINE);
921           }
922       }
923   return 0;
924 }
925
926 /* Configuration write function. */
927 int
928 config_write_distribute (struct vty *vty)
929 {
930   unsigned int i;
931   int j;
932   int output, v6;
933   struct hash_backet *mp;
934   int write = 0;
935
936   for (i = 0; i < disthash->size; i++)
937     for (mp = disthash->index[i]; mp; mp = mp->next)
938       {
939         struct distribute *dist;
940
941         dist = mp->data;
942
943         for (j=0; j < DISTRIBUTE_MAX; j++)
944           if (dist->list[j]) {
945             output = j == DISTRIBUTE_V4_OUT || j == DISTRIBUTE_V6_OUT;
946             v6 = j == DISTRIBUTE_V6_IN || j == DISTRIBUTE_V6_OUT;
947             vty_out (vty, " %sdistribute-list %s %s %s%s",
948                      v6 ? "ipv6 " : "",
949                      dist->list[j],
950                      output ? "out" : "in",
951                      dist->ifname ? dist->ifname : "",
952                      VTY_NEWLINE);
953             write++;
954           }
955
956         for (j=0; j < DISTRIBUTE_MAX; j++)
957           if (dist->prefix[j]) {
958             output = j == DISTRIBUTE_V4_OUT || j == DISTRIBUTE_V6_OUT;
959             v6 = j == DISTRIBUTE_V6_IN || j == DISTRIBUTE_V6_OUT;
960             vty_out (vty, " %sdistribute-list prefix %s %s %s%s",
961                      v6 ? "ipv6 " : "",
962                      dist->prefix[j],
963                      output ? "out" : "in",
964                      dist->ifname ? dist->ifname : "",
965                      VTY_NEWLINE);
966             write++;
967           }
968       }
969   return write;
970 }
971
972 /* Clear all distribute list. */
973 void
974 distribute_list_reset ()
975 {
976   hash_clean (disthash, (void (*) (void *)) distribute_free);
977 }
978
979 /* Initialize distribute list related hash. */
980 void
981 distribute_list_init (int node)
982 {
983   disthash = hash_create (distribute_hash_make,
984                           (int (*) (const void *, const void *)) distribute_cmp);
985   /* install v4 */
986   if (node == RIP_NODE || node == BABEL_NODE) {
987     install_element (node, &distribute_list_all_cmd);
988     install_element (node, &no_distribute_list_all_cmd);
989     install_element (node, &distribute_list_cmd);
990     install_element (node, &no_distribute_list_cmd);
991     install_element (node, &distribute_list_prefix_all_cmd);
992     install_element (node, &no_distribute_list_prefix_all_cmd);
993     install_element (node, &distribute_list_prefix_cmd);
994     install_element (node, &no_distribute_list_prefix_cmd);
995   }
996
997   /* install v6 */
998   if (node == RIPNG_NODE || node == BABEL_NODE) {
999     install_element (node, &ipv6_distribute_list_all_cmd);
1000     install_element (node, &no_ipv6_distribute_list_all_cmd);
1001     install_element (node, &ipv6_distribute_list_cmd);
1002     install_element (node, &no_ipv6_distribute_list_cmd);
1003     install_element (node, &ipv6_distribute_list_prefix_all_cmd);
1004     install_element (node, &no_ipv6_distribute_list_prefix_all_cmd);
1005     install_element (node, &ipv6_distribute_list_prefix_cmd);
1006     install_element (node, &no_ipv6_distribute_list_prefix_cmd);
1007   }
1008
1009   /* install v4 syntax command for v6 only protocols. */
1010   if (node == RIPNG_NODE) {
1011     install_element (node, &ipv6_as_v4_distribute_list_all_cmd);
1012     install_element (node, &no_ipv6_as_v4_distribute_list_all_cmd);
1013     install_element (node, &ipv6_as_v4_distribute_list_cmd);
1014     install_element (node, &no_ipv6_as_v4_distribute_list_cmd);
1015     install_element (node, &ipv6_as_v4_distribute_list_prefix_all_cmd);
1016     install_element (node, &no_ipv6_as_v4_distribute_list_prefix_all_cmd);
1017     install_element (node, &ipv6_as_v4_distribute_list_prefix_cmd);
1018     install_element (node, &no_ipv6_as_v4_distribute_list_prefix_cmd);
1019   }
1020 }