1 /* Distribute list functions
2 * Copyright (C) 1998, 1999 Kunihiro Ishiguro
4 * This file is part of GNU Zebra.
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.
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.
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.
28 #include "distribute.h"
31 /* Hash of distribute list. */
32 struct hash
*disthash
;
35 void (*distribute_add_hook
) (struct distribute
*);
36 void (*distribute_delete_hook
) (struct distribute
*);
38 static struct distribute
*
41 return XCALLOC (MTYPE_DISTRIBUTE
, sizeof (struct distribute
));
44 /* Free distribute object. */
46 distribute_free (struct distribute
*dist
)
49 XFREE (MTYPE_DISTRIBUTE_IFNAME
, dist
->ifname
);
51 if (dist
->list
[DISTRIBUTE_IN
])
52 free (dist
->list
[DISTRIBUTE_IN
]);
53 if (dist
->list
[DISTRIBUTE_OUT
])
54 free (dist
->list
[DISTRIBUTE_OUT
]);
56 if (dist
->prefix
[DISTRIBUTE_IN
])
57 free (dist
->prefix
[DISTRIBUTE_IN
]);
58 if (dist
->prefix
[DISTRIBUTE_OUT
])
59 free (dist
->prefix
[DISTRIBUTE_OUT
]);
61 XFREE (MTYPE_DISTRIBUTE
, dist
);
64 /* Lookup interface's distribute list. */
66 distribute_lookup (const char *ifname
)
68 struct distribute key
;
69 struct distribute
*dist
;
71 /* temporary reference */
72 key
.ifname
= (char *)ifname
;
74 dist
= hash_lookup (disthash
, &key
);
80 distribute_list_add_hook (void (*func
) (struct distribute
*))
82 distribute_add_hook
= func
;
86 distribute_list_delete_hook (void (*func
) (struct distribute
*))
88 distribute_delete_hook
= func
;
92 distribute_hash_alloc (struct distribute
*arg
)
94 struct distribute
*dist
;
96 dist
= distribute_new ();
98 dist
->ifname
= XSTRDUP (MTYPE_DISTRIBUTE_IFNAME
, arg
->ifname
);
104 /* Make new distribute list and push into hash. */
105 static struct distribute
*
106 distribute_get (const char *ifname
)
108 struct distribute key
;
110 /* temporary reference */
111 key
.ifname
= (char *)ifname
;
113 return hash_get (disthash
, &key
, (void * (*) (void *))distribute_hash_alloc
);
117 distribute_hash_make (void *arg
)
119 const struct distribute
*dist
= arg
;
121 return dist
->ifname
? string_hash_make (dist
->ifname
) : 0;
124 /* If two distribute-list have same value then return 1 else return
125 0. This function is used by hash package. */
127 distribute_cmp (const struct distribute
*dist1
, const struct distribute
*dist2
)
129 if (dist1
->ifname
&& dist2
->ifname
)
130 if (strcmp (dist1
->ifname
, dist2
->ifname
) == 0)
132 if (! dist1
->ifname
&& ! dist2
->ifname
)
137 /* Set access-list name to the distribute list. */
138 static struct distribute
*
139 distribute_list_set (const char *ifname
, enum distribute_type type
,
140 const char *alist_name
)
142 struct distribute
*dist
;
144 dist
= distribute_get (ifname
);
146 if (type
== DISTRIBUTE_IN
)
148 if (dist
->list
[DISTRIBUTE_IN
])
149 free (dist
->list
[DISTRIBUTE_IN
]);
150 dist
->list
[DISTRIBUTE_IN
] = strdup (alist_name
);
152 if (type
== DISTRIBUTE_OUT
)
154 if (dist
->list
[DISTRIBUTE_OUT
])
155 free (dist
->list
[DISTRIBUTE_OUT
]);
156 dist
->list
[DISTRIBUTE_OUT
] = strdup (alist_name
);
159 /* Apply this distribute-list to the interface. */
160 (*distribute_add_hook
) (dist
);
165 /* Unset distribute-list. If matched distribute-list exist then
168 distribute_list_unset (const char *ifname
, enum distribute_type type
,
169 const char *alist_name
)
171 struct distribute
*dist
;
173 dist
= distribute_lookup (ifname
);
177 if (type
== DISTRIBUTE_IN
)
179 if (!dist
->list
[DISTRIBUTE_IN
])
181 if (strcmp (dist
->list
[DISTRIBUTE_IN
], alist_name
) != 0)
184 free (dist
->list
[DISTRIBUTE_IN
]);
185 dist
->list
[DISTRIBUTE_IN
] = NULL
;
188 if (type
== DISTRIBUTE_OUT
)
190 if (!dist
->list
[DISTRIBUTE_OUT
])
192 if (strcmp (dist
->list
[DISTRIBUTE_OUT
], alist_name
) != 0)
195 free (dist
->list
[DISTRIBUTE_OUT
]);
196 dist
->list
[DISTRIBUTE_OUT
] = NULL
;
199 /* Apply this distribute-list to the interface. */
200 (*distribute_delete_hook
) (dist
);
202 /* If both out and in is NULL then free distribute list. */
203 if (dist
->list
[DISTRIBUTE_IN
] == NULL
&&
204 dist
->list
[DISTRIBUTE_OUT
] == NULL
&&
205 dist
->prefix
[DISTRIBUTE_IN
] == NULL
&&
206 dist
->prefix
[DISTRIBUTE_OUT
] == NULL
)
208 hash_release (disthash
, dist
);
209 distribute_free (dist
);
215 /* Set access-list name to the distribute list. */
216 static struct distribute
*
217 distribute_list_prefix_set (const char *ifname
, enum distribute_type type
,
218 const char *plist_name
)
220 struct distribute
*dist
;
222 dist
= distribute_get (ifname
);
224 if (type
== DISTRIBUTE_IN
)
226 if (dist
->prefix
[DISTRIBUTE_IN
])
227 free (dist
->prefix
[DISTRIBUTE_IN
]);
228 dist
->prefix
[DISTRIBUTE_IN
] = strdup (plist_name
);
230 if (type
== DISTRIBUTE_OUT
)
232 if (dist
->prefix
[DISTRIBUTE_OUT
])
233 free (dist
->prefix
[DISTRIBUTE_OUT
]);
234 dist
->prefix
[DISTRIBUTE_OUT
] = strdup (plist_name
);
237 /* Apply this distribute-list to the interface. */
238 (*distribute_add_hook
) (dist
);
243 /* Unset distribute-list. If matched distribute-list exist then
246 distribute_list_prefix_unset (const char *ifname
, enum distribute_type type
,
247 const char *plist_name
)
249 struct distribute
*dist
;
251 dist
= distribute_lookup (ifname
);
255 if (type
== DISTRIBUTE_IN
)
257 if (!dist
->prefix
[DISTRIBUTE_IN
])
259 if (strcmp (dist
->prefix
[DISTRIBUTE_IN
], plist_name
) != 0)
262 free (dist
->prefix
[DISTRIBUTE_IN
]);
263 dist
->prefix
[DISTRIBUTE_IN
] = NULL
;
266 if (type
== DISTRIBUTE_OUT
)
268 if (!dist
->prefix
[DISTRIBUTE_OUT
])
270 if (strcmp (dist
->prefix
[DISTRIBUTE_OUT
], plist_name
) != 0)
273 free (dist
->prefix
[DISTRIBUTE_OUT
]);
274 dist
->prefix
[DISTRIBUTE_OUT
] = NULL
;
277 /* Apply this distribute-list to the interface. */
278 (*distribute_delete_hook
) (dist
);
280 /* If both out and in is NULL then free distribute list. */
281 if (dist
->list
[DISTRIBUTE_IN
] == NULL
&&
282 dist
->list
[DISTRIBUTE_OUT
] == NULL
&&
283 dist
->prefix
[DISTRIBUTE_IN
] == NULL
&&
284 dist
->prefix
[DISTRIBUTE_OUT
] == NULL
)
286 hash_release (disthash
, dist
);
287 distribute_free (dist
);
293 DEFUN (distribute_list_all
,
294 distribute_list_all_cmd
,
295 "distribute-list WORD (in|out)",
296 "Filter networks in routing updates\n"
298 "Filter incoming routing updates\n"
299 "Filter outgoing routing updates\n")
301 enum distribute_type type
;
303 /* Check of distribute list type. */
304 if (strncmp (argv
[1], "i", 1) == 0)
305 type
= DISTRIBUTE_IN
;
306 else if (strncmp (argv
[1], "o", 1) == 0)
307 type
= DISTRIBUTE_OUT
;
310 vty_out (vty
, "distribute list direction must be [in|out]%s",
315 /* Get interface name corresponding distribute list. */
316 distribute_list_set (NULL
, type
, argv
[0]);
321 ALIAS (distribute_list_all
,
322 ipv6_distribute_list_all_cmd
,
323 "distribute-list WORD (in|out)",
324 "Filter networks in routing updates\n"
326 "Filter incoming routing updates\n"
327 "Filter outgoing routing updates\n")
329 DEFUN (no_distribute_list_all
,
330 no_distribute_list_all_cmd
,
331 "no distribute-list WORD (in|out)",
333 "Filter networks in routing updates\n"
335 "Filter incoming routing updates\n"
336 "Filter outgoing routing updates\n")
339 enum distribute_type type
;
341 /* Check of distribute list type. */
342 if (strncmp (argv
[1], "i", 1) == 0)
343 type
= DISTRIBUTE_IN
;
344 else if (strncmp (argv
[1], "o", 1) == 0)
345 type
= DISTRIBUTE_OUT
;
348 vty_out (vty
, "distribute list direction must be [in|out]%s",
353 ret
= distribute_list_unset (NULL
, type
, argv
[0]);
356 vty_out (vty
, "distribute list doesn't exist%s", VTY_NEWLINE
);
362 ALIAS (no_distribute_list_all
,
363 no_ipv6_distribute_list_all_cmd
,
364 "no distribute-list WORD (in|out)",
366 "Filter networks in routing updates\n"
368 "Filter incoming routing updates\n"
369 "Filter outgoing routing updates\n")
371 DEFUN (distribute_list
,
373 "distribute-list WORD (in|out) WORD",
374 "Filter networks in routing updates\n"
376 "Filter incoming routing updates\n"
377 "Filter outgoing routing updates\n"
380 enum distribute_type type
;
382 /* Check of distribute list type. */
383 if (strncmp (argv
[1], "i", 1) == 0)
384 type
= DISTRIBUTE_IN
;
385 else if (strncmp (argv
[1], "o", 1) == 0)
386 type
= DISTRIBUTE_OUT
;
389 vty_out (vty
, "distribute list direction must be [in|out]%s", VTY_NEWLINE
);
393 /* Get interface name corresponding distribute list. */
394 distribute_list_set (argv
[2], type
, argv
[0]);
399 ALIAS (distribute_list
,
400 ipv6_distribute_list_cmd
,
401 "distribute-list WORD (in|out) WORD",
402 "Filter networks in routing updates\n"
404 "Filter incoming routing updates\n"
405 "Filter outgoing routing updates\n"
408 DEFUN (no_distribute_list
, no_distribute_list_cmd
,
409 "no distribute-list WORD (in|out) WORD",
411 "Filter networks in routing updates\n"
413 "Filter incoming routing updates\n"
414 "Filter outgoing routing updates\n"
418 enum distribute_type type
;
420 /* Check of distribute list type. */
421 if (strncmp (argv
[1], "i", 1) == 0)
422 type
= DISTRIBUTE_IN
;
423 else if (strncmp (argv
[1], "o", 1) == 0)
424 type
= DISTRIBUTE_OUT
;
427 vty_out (vty
, "distribute list direction must be [in|out]%s", VTY_NEWLINE
);
431 ret
= distribute_list_unset (argv
[2], type
, argv
[0]);
434 vty_out (vty
, "distribute list doesn't exist%s", VTY_NEWLINE
);
440 ALIAS (no_distribute_list
, no_ipv6_distribute_list_cmd
,
441 "no distribute-list WORD (in|out) WORD",
443 "Filter networks in routing updates\n"
445 "Filter incoming routing updates\n"
446 "Filter outgoing routing updates\n"
449 DEFUN (distribute_list_prefix_all
,
450 distribute_list_prefix_all_cmd
,
451 "distribute-list prefix WORD (in|out)",
452 "Filter networks in routing updates\n"
453 "Filter prefixes in routing updates\n"
454 "Name of an IP prefix-list\n"
455 "Filter incoming routing updates\n"
456 "Filter outgoing routing updates\n")
458 enum distribute_type type
;
460 /* Check of distribute list type. */
461 if (strncmp (argv
[1], "i", 1) == 0)
462 type
= DISTRIBUTE_IN
;
463 else if (strncmp (argv
[1], "o", 1) == 0)
464 type
= DISTRIBUTE_OUT
;
467 vty_out (vty
, "distribute list direction must be [in|out]%s",
472 /* Get interface name corresponding distribute list. */
473 distribute_list_prefix_set (NULL
, type
, argv
[0]);
478 ALIAS (distribute_list_prefix_all
,
479 ipv6_distribute_list_prefix_all_cmd
,
480 "distribute-list prefix WORD (in|out)",
481 "Filter networks in routing updates\n"
482 "Filter prefixes in routing updates\n"
483 "Name of an IP prefix-list\n"
484 "Filter incoming routing updates\n"
485 "Filter outgoing routing updates\n")
487 DEFUN (no_distribute_list_prefix_all
,
488 no_distribute_list_prefix_all_cmd
,
489 "no distribute-list prefix WORD (in|out)",
491 "Filter networks in routing updates\n"
492 "Filter prefixes in routing updates\n"
493 "Name of an IP prefix-list\n"
494 "Filter incoming routing updates\n"
495 "Filter outgoing routing updates\n")
498 enum distribute_type type
;
500 /* Check of distribute list type. */
501 if (strncmp (argv
[1], "i", 1) == 0)
502 type
= DISTRIBUTE_IN
;
503 else if (strncmp (argv
[1], "o", 1) == 0)
504 type
= DISTRIBUTE_OUT
;
507 vty_out (vty
, "distribute list direction must be [in|out]%s",
512 ret
= distribute_list_prefix_unset (NULL
, type
, argv
[0]);
515 vty_out (vty
, "distribute list doesn't exist%s", VTY_NEWLINE
);
521 ALIAS (no_distribute_list_prefix_all
,
522 no_ipv6_distribute_list_prefix_all_cmd
,
523 "no distribute-list prefix WORD (in|out)",
525 "Filter networks in routing updates\n"
526 "Filter prefixes in routing updates\n"
527 "Name of an IP prefix-list\n"
528 "Filter incoming routing updates\n"
529 "Filter outgoing routing updates\n")
531 DEFUN (distribute_list_prefix
, distribute_list_prefix_cmd
,
532 "distribute-list prefix WORD (in|out) WORD",
533 "Filter networks in routing updates\n"
534 "Filter prefixes in routing updates\n"
535 "Name of an IP prefix-list\n"
536 "Filter incoming routing updates\n"
537 "Filter outgoing routing updates\n"
540 enum distribute_type type
;
542 /* Check of distribute list type. */
543 if (strncmp (argv
[1], "i", 1) == 0)
544 type
= DISTRIBUTE_IN
;
545 else if (strncmp (argv
[1], "o", 1) == 0)
546 type
= DISTRIBUTE_OUT
;
549 vty_out (vty
, "distribute list direction must be [in|out]%s",
554 /* Get interface name corresponding distribute list. */
555 distribute_list_prefix_set (argv
[2], type
, argv
[0]);
560 ALIAS (distribute_list_prefix
, ipv6_distribute_list_prefix_cmd
,
561 "distribute-list prefix WORD (in|out) WORD",
562 "Filter networks in routing updates\n"
563 "Filter prefixes in routing updates\n"
564 "Name of an IP prefix-list\n"
565 "Filter incoming routing updates\n"
566 "Filter outgoing routing updates\n"
569 DEFUN (no_distribute_list_prefix
, no_distribute_list_prefix_cmd
,
570 "no distribute-list prefix WORD (in|out) WORD",
572 "Filter networks in routing updates\n"
573 "Filter prefixes in routing updates\n"
574 "Name of an IP prefix-list\n"
575 "Filter incoming routing updates\n"
576 "Filter outgoing routing updates\n"
580 enum distribute_type type
;
582 /* Check of distribute list type. */
583 if (strncmp (argv
[1], "i", 1) == 0)
584 type
= DISTRIBUTE_IN
;
585 else if (strncmp (argv
[1], "o", 1) == 0)
586 type
= DISTRIBUTE_OUT
;
589 vty_out (vty
, "distribute list direction must be [in|out]%s",
594 ret
= distribute_list_prefix_unset (argv
[2], type
, argv
[0]);
597 vty_out (vty
, "distribute list doesn't exist%s", VTY_NEWLINE
);
603 ALIAS (no_distribute_list_prefix
, no_ipv6_distribute_list_prefix_cmd
,
604 "no distribute-list prefix WORD (in|out) WORD",
606 "Filter networks in routing updates\n"
607 "Filter prefixes in routing updates\n"
608 "Name of an IP prefix-list\n"
609 "Filter incoming routing updates\n"
610 "Filter outgoing routing updates\n"
614 config_show_distribute (struct vty
*vty
)
617 struct hash_backet
*mp
;
618 struct distribute
*dist
;
620 /* Output filter configuration. */
621 dist
= distribute_lookup (NULL
);
622 if (dist
&& (dist
->list
[DISTRIBUTE_OUT
] || dist
->prefix
[DISTRIBUTE_OUT
]))
624 vty_out (vty
, " Outgoing update filter list for all interface is");
625 if (dist
->list
[DISTRIBUTE_OUT
])
626 vty_out (vty
, " %s", dist
->list
[DISTRIBUTE_OUT
]);
627 if (dist
->prefix
[DISTRIBUTE_OUT
])
628 vty_out (vty
, "%s (prefix-list) %s",
629 dist
->list
[DISTRIBUTE_OUT
] ? "," : "",
630 dist
->prefix
[DISTRIBUTE_OUT
]);
631 vty_out (vty
, "%s", VTY_NEWLINE
);
634 vty_out (vty
, " Outgoing update filter list for all interface is not set%s", VTY_NEWLINE
);
636 for (i
= 0; i
< disthash
->size
; i
++)
637 for (mp
= disthash
->index
[i
]; mp
; mp
= mp
->next
)
641 if (dist
->list
[DISTRIBUTE_OUT
] || dist
->prefix
[DISTRIBUTE_OUT
])
643 vty_out (vty
, " %s filtered by", dist
->ifname
);
644 if (dist
->list
[DISTRIBUTE_OUT
])
645 vty_out (vty
, " %s", dist
->list
[DISTRIBUTE_OUT
]);
646 if (dist
->prefix
[DISTRIBUTE_OUT
])
647 vty_out (vty
, "%s (prefix-list) %s",
648 dist
->list
[DISTRIBUTE_OUT
] ? "," : "",
649 dist
->prefix
[DISTRIBUTE_OUT
]);
650 vty_out (vty
, "%s", VTY_NEWLINE
);
655 /* Input filter configuration. */
656 dist
= distribute_lookup (NULL
);
657 if (dist
&& (dist
->list
[DISTRIBUTE_IN
] || dist
->prefix
[DISTRIBUTE_IN
]))
659 vty_out (vty
, " Incoming update filter list for all interface is");
660 if (dist
->list
[DISTRIBUTE_IN
])
661 vty_out (vty
, " %s", dist
->list
[DISTRIBUTE_IN
]);
662 if (dist
->prefix
[DISTRIBUTE_IN
])
663 vty_out (vty
, "%s (prefix-list) %s",
664 dist
->list
[DISTRIBUTE_IN
] ? "," : "",
665 dist
->prefix
[DISTRIBUTE_IN
]);
666 vty_out (vty
, "%s", VTY_NEWLINE
);
669 vty_out (vty
, " Incoming update filter list for all interface is not set%s", VTY_NEWLINE
);
671 for (i
= 0; i
< disthash
->size
; i
++)
672 for (mp
= disthash
->index
[i
]; mp
; mp
= mp
->next
)
676 if (dist
->list
[DISTRIBUTE_IN
] || dist
->prefix
[DISTRIBUTE_IN
])
678 vty_out (vty
, " %s filtered by", dist
->ifname
);
679 if (dist
->list
[DISTRIBUTE_IN
])
680 vty_out (vty
, " %s", dist
->list
[DISTRIBUTE_IN
]);
681 if (dist
->prefix
[DISTRIBUTE_IN
])
682 vty_out (vty
, "%s (prefix-list) %s",
683 dist
->list
[DISTRIBUTE_IN
] ? "," : "",
684 dist
->prefix
[DISTRIBUTE_IN
]);
685 vty_out (vty
, "%s", VTY_NEWLINE
);
691 /* Configuration write function. */
693 config_write_distribute (struct vty
*vty
)
696 struct hash_backet
*mp
;
699 for (i
= 0; i
< disthash
->size
; i
++)
700 for (mp
= disthash
->index
[i
]; mp
; mp
= mp
->next
)
702 struct distribute
*dist
;
706 if (dist
->list
[DISTRIBUTE_IN
])
708 vty_out (vty
, " distribute-list %s in %s%s",
709 dist
->list
[DISTRIBUTE_IN
],
710 dist
->ifname
? dist
->ifname
: "",
715 if (dist
->list
[DISTRIBUTE_OUT
])
717 vty_out (vty
, " distribute-list %s out %s%s",
719 dist
->list
[DISTRIBUTE_OUT
],
720 dist
->ifname
? dist
->ifname
: "",
725 if (dist
->prefix
[DISTRIBUTE_IN
])
727 vty_out (vty
, " distribute-list prefix %s in %s%s",
728 dist
->prefix
[DISTRIBUTE_IN
],
729 dist
->ifname
? dist
->ifname
: "",
734 if (dist
->prefix
[DISTRIBUTE_OUT
])
736 vty_out (vty
, " distribute-list prefix %s out %s%s",
737 dist
->prefix
[DISTRIBUTE_OUT
],
738 dist
->ifname
? dist
->ifname
: "",
746 /* Clear all distribute list. */
748 distribute_list_reset ()
750 hash_clean (disthash
, (void (*) (void *)) distribute_free
);
753 /* Initialize distribute list related hash. */
755 distribute_list_init (int node
)
757 disthash
= hash_create (distribute_hash_make
,
758 (int (*) (const void *, const void *)) distribute_cmp
);
761 install_element (node
, &distribute_list_all_cmd
);
762 install_element (node
, &no_distribute_list_all_cmd
);
763 install_element (node
, &distribute_list_cmd
);
764 install_element (node
, &no_distribute_list_cmd
);
765 install_element (node
, &distribute_list_prefix_all_cmd
);
766 install_element (node
, &no_distribute_list_prefix_all_cmd
);
767 install_element (node
, &distribute_list_prefix_cmd
);
768 install_element (node
, &no_distribute_list_prefix_cmd
);
769 } else if (node
== RIPNG_NODE
|| node
== BABEL_NODE
) {
770 /* WARNING: two identical commands installed do a crash, so be worry with
771 aliases. For this reason, and because all these commands are aliases, Babel
772 is not set with RIP. */
773 install_element (node
, &ipv6_distribute_list_all_cmd
);
774 install_element (node
, &no_ipv6_distribute_list_all_cmd
);
775 install_element (node
, &ipv6_distribute_list_cmd
);
776 install_element (node
, &no_ipv6_distribute_list_cmd
);
777 install_element (node
, &ipv6_distribute_list_prefix_all_cmd
);
778 install_element (node
, &no_ipv6_distribute_list_prefix_all_cmd
);
779 install_element (node
, &ipv6_distribute_list_prefix_cmd
);
780 install_element (node
, &no_ipv6_distribute_list_prefix_cmd
);