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 along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27 #include "distribute.h"
30 DEFINE_MTYPE_STATIC(LIB
, DISTRIBUTE
, "Distribute list")
31 DEFINE_MTYPE_STATIC(LIB
, DISTRIBUTE_IFNAME
, "Dist-list ifname")
32 DEFINE_MTYPE_STATIC(LIB
, DISTRIBUTE_NAME
, "Dist-list name")
34 /* Hash of distribute list. */
35 struct hash
*disthash
;
38 void (*distribute_add_hook
) (struct distribute
*);
39 void (*distribute_delete_hook
) (struct distribute
*);
41 static struct distribute
*
44 return XCALLOC (MTYPE_DISTRIBUTE
, sizeof (struct distribute
));
47 /* Free distribute object. */
49 distribute_free (struct distribute
*dist
)
54 XFREE (MTYPE_DISTRIBUTE_IFNAME
, dist
->ifname
);
56 for (i
= 0; i
< DISTRIBUTE_MAX
; i
++)
58 XFREE(MTYPE_DISTRIBUTE_NAME
, dist
->list
[i
]);
60 for (i
= 0; i
< DISTRIBUTE_MAX
; i
++)
62 XFREE(MTYPE_DISTRIBUTE_NAME
, dist
->prefix
[i
]);
64 XFREE (MTYPE_DISTRIBUTE
, dist
);
68 distribute_free_if_empty(struct distribute
*dist
)
72 for (i
= 0; i
< DISTRIBUTE_MAX
; i
++)
73 if (dist
->list
[i
] != NULL
|| dist
->prefix
[i
] != NULL
)
76 hash_release (disthash
, dist
);
77 distribute_free (dist
);
80 /* Lookup interface's distribute list. */
82 distribute_lookup (const char *ifname
)
84 struct distribute key
;
85 struct distribute
*dist
;
87 /* temporary reference */
88 key
.ifname
= (ifname
) ? XSTRDUP(MTYPE_DISTRIBUTE_IFNAME
, ifname
) : NULL
;
90 dist
= hash_lookup (disthash
, &key
);
93 XFREE(MTYPE_DISTRIBUTE_IFNAME
, key
.ifname
);
99 distribute_list_add_hook (void (*func
) (struct distribute
*))
101 distribute_add_hook
= func
;
105 distribute_list_delete_hook (void (*func
) (struct distribute
*))
107 distribute_delete_hook
= func
;
111 distribute_hash_alloc (struct distribute
*arg
)
113 struct distribute
*dist
;
115 dist
= distribute_new ();
117 dist
->ifname
= XSTRDUP (MTYPE_DISTRIBUTE_IFNAME
, arg
->ifname
);
123 /* Make new distribute list and push into hash. */
124 static struct distribute
*
125 distribute_get (const char *ifname
)
127 struct distribute key
;
128 struct distribute
*ret
;
130 /* temporary reference */
131 key
.ifname
= (ifname
) ? XSTRDUP(MTYPE_DISTRIBUTE_IFNAME
, ifname
) : NULL
;
133 ret
= hash_get (disthash
, &key
, (void * (*) (void *))distribute_hash_alloc
);
136 XFREE(MTYPE_DISTRIBUTE_IFNAME
, key
.ifname
);
142 distribute_hash_make (void *arg
)
144 const struct distribute
*dist
= arg
;
146 return dist
->ifname
? string_hash_make (dist
->ifname
) : 0;
149 /* If two distribute-list have same value then return 1 else return
150 0. This function is used by hash package. */
152 distribute_cmp (const struct distribute
*dist1
, const struct distribute
*dist2
)
154 if (dist1
->ifname
&& dist2
->ifname
)
155 if (strcmp (dist1
->ifname
, dist2
->ifname
) == 0)
157 if (! dist1
->ifname
&& ! dist2
->ifname
)
162 /* Set access-list name to the distribute list. */
164 distribute_list_set (const char *ifname
, enum distribute_type type
,
165 const char *alist_name
)
167 struct distribute
*dist
;
169 dist
= distribute_get (ifname
);
171 if (dist
->list
[type
])
172 XFREE(MTYPE_DISTRIBUTE_NAME
, dist
->list
[type
]);
173 dist
->list
[type
] = XSTRDUP(MTYPE_DISTRIBUTE_NAME
, alist_name
);
175 /* Apply this distribute-list to the interface. */
176 (*distribute_add_hook
) (dist
);
179 /* Unset distribute-list. If matched distribute-list exist then
182 distribute_list_unset (const char *ifname
, enum distribute_type type
,
183 const char *alist_name
)
185 struct distribute
*dist
;
187 dist
= distribute_lookup (ifname
);
191 if (!dist
->list
[type
])
193 if (strcmp (dist
->list
[type
], alist_name
) != 0)
196 XFREE(MTYPE_DISTRIBUTE_NAME
, dist
->list
[type
]);
197 dist
->list
[type
] = NULL
;
199 /* Apply this distribute-list to the interface. */
200 (*distribute_delete_hook
) (dist
);
202 /* If all dist are NULL, then free distribute list. */
203 distribute_free_if_empty(dist
);
207 /* Set access-list name to the distribute list. */
209 distribute_list_prefix_set (const char *ifname
, enum distribute_type type
,
210 const char *plist_name
)
212 struct distribute
*dist
;
214 dist
= distribute_get (ifname
);
216 if (dist
->prefix
[type
])
217 XFREE(MTYPE_DISTRIBUTE_NAME
, dist
->prefix
[type
]);
218 dist
->prefix
[type
] = XSTRDUP(MTYPE_DISTRIBUTE_NAME
, plist_name
);
220 /* Apply this distribute-list to the interface. */
221 (*distribute_add_hook
) (dist
);
224 /* Unset distribute-list. If matched distribute-list exist then
227 distribute_list_prefix_unset (const char *ifname
, enum distribute_type type
,
228 const char *plist_name
)
230 struct distribute
*dist
;
232 dist
= distribute_lookup (ifname
);
236 if (!dist
->prefix
[type
])
238 if (strcmp (dist
->prefix
[type
], plist_name
) != 0)
241 XFREE(MTYPE_DISTRIBUTE_NAME
, dist
->prefix
[type
]);
242 dist
->prefix
[type
] = NULL
;
244 /* Apply this distribute-list to the interface. */
245 (*distribute_delete_hook
) (dist
);
247 /* If all dist are NULL, then free distribute list. */
248 distribute_free_if_empty(dist
);
252 DEFUN (distribute_list
,
254 "distribute-list [prefix] WORD <in|out> [WORD]",
255 "Filter networks in routing updates\n"
258 "Filter incoming routing updates\n"
259 "Filter outgoing routing updates\n"
262 int prefix
= (argv
[1]->type
== WORD_TKN
) ? 1 : 0;
264 /* Check of distribute list type. */
265 enum distribute_type type
= argv
[2 + prefix
]->arg
[0] == 'i' ?
266 DISTRIBUTE_V4_IN
: DISTRIBUTE_V4_OUT
;
268 /* Set appropriate function call */
269 void (*distfn
)(const char *, enum distribute_type
, const char *) = prefix
?
270 &distribute_list_prefix_set
: &distribute_list_set
;
272 /* if interface is present, get name */
273 const char *ifname
= NULL
;
274 if (argv
[argc
- 1]->type
== VARIABLE_TKN
)
275 ifname
= argv
[argc
- 1]->arg
;
277 /* Get interface name corresponding distribute list. */
278 distfn (ifname
, type
, argv
[1 + prefix
]->arg
);
283 DEFUN (ipv6_distribute_list
,
284 ipv6_distribute_list_cmd
,
285 "ipv6 distribute-list [prefix] WORD <in|out> [WORD]",
287 "Filter networks in routing updates\n"
290 "Filter incoming routing updates\n"
291 "Filter outgoing routing updates\n"
294 int prefix
= (argv
[2]->type
== WORD_TKN
) ? 1 : 0;
296 /* Check of distribute list type. */
297 enum distribute_type type
= argv
[3 + prefix
]->arg
[0] == 'i' ?
298 DISTRIBUTE_V6_IN
: DISTRIBUTE_V6_OUT
;
300 /* Set appropriate function call */
301 void (*distfn
)(const char *, enum distribute_type
, const char *) = prefix
?
302 &distribute_list_prefix_set
: &distribute_list_set
;
304 /* if interface is present, get name */
305 const char *ifname
= NULL
;
306 if (argv
[argc
- 1]->type
== VARIABLE_TKN
)
307 ifname
= argv
[argc
- 1]->arg
;
309 /* Get interface name corresponding distribute list. */
310 distfn (ifname
, type
, argv
[1 + prefix
]->arg
);
315 DEFUN (no_distribute_list
,
316 no_distribute_list_cmd
,
317 "no [ipv6] distribute-list [prefix] WORD <in|out> [WORD]",
320 "Filter networks in routing updates\n"
323 "Filter incoming routing updates\n"
324 "Filter outgoing routing updates\n"
327 int ipv6
= strmatch(argv
[1]->text
, "ipv6");
328 int prefix
= (argv
[2 + ipv6
]->type
== WORD_TKN
) ? 1 : 0;
330 int idx_alname
= 2 + ipv6
+ prefix
;
331 int idx_disttype
= idx_alname
+ 1;
333 /* Check of distribute list type. */
334 enum distribute_type distin
= (ipv6
) ? DISTRIBUTE_V6_IN
: DISTRIBUTE_V4_IN
;
335 enum distribute_type distout
= (ipv6
) ? DISTRIBUTE_V6_OUT
: DISTRIBUTE_V4_OUT
;
337 enum distribute_type type
= argv
[idx_disttype
]->arg
[0] == 'i' ? distin
: distout
;
339 /* Set appropriate function call */
340 int (*distfn
)(const char *, enum distribute_type
, const char *) = prefix
?
341 &distribute_list_prefix_unset
: &distribute_list_unset
;
343 /* if interface is present, get name */
344 const char *ifname
= NULL
;
345 if (argv
[argc
- 1]->type
== VARIABLE_TKN
)
346 ifname
= argv
[argc
- 1]->arg
;
347 /* Get interface name corresponding distribute list. */
348 int ret
= distfn (ifname
, type
, argv
[2 + prefix
]->arg
);
352 vty_out (vty
, "distribute list doesn't exist%s", VTY_NEWLINE
);
359 distribute_print (struct vty
*vty
, char *tab
[], int is_prefix
,
360 enum distribute_type type
, int has_print
)
363 vty_out (vty
, "%s %s%s",
364 has_print
? "," : "",
365 is_prefix
? "(prefix-list) " : "",
373 config_show_distribute (struct vty
*vty
)
377 struct hash_backet
*mp
;
378 struct distribute
*dist
;
380 /* Output filter configuration. */
381 dist
= distribute_lookup (NULL
);
382 vty_out (vty
, " Outgoing update filter list for all interface is");
386 has_print
= distribute_print(vty
, dist
->list
, 0,
387 DISTRIBUTE_V4_OUT
, has_print
);
388 has_print
= distribute_print(vty
, dist
->prefix
, 1,
389 DISTRIBUTE_V4_OUT
, has_print
);
390 has_print
= distribute_print(vty
, dist
->list
, 0,
391 DISTRIBUTE_V6_OUT
, has_print
);
392 has_print
= distribute_print(vty
, dist
->prefix
, 1,
393 DISTRIBUTE_V6_OUT
, has_print
);
396 vty_out (vty
, "%s", VTY_NEWLINE
);
398 vty_out (vty
, " not set%s", VTY_NEWLINE
);
400 for (i
= 0; i
< disthash
->size
; i
++)
401 for (mp
= disthash
->index
[i
]; mp
; mp
= mp
->next
)
406 vty_out (vty
, " %s filtered by", dist
->ifname
);
408 has_print
= distribute_print(vty
, dist
->list
, 0,
409 DISTRIBUTE_V4_OUT
, has_print
);
410 has_print
= distribute_print(vty
, dist
->prefix
, 1,
411 DISTRIBUTE_V4_OUT
, has_print
);
412 has_print
= distribute_print(vty
, dist
->list
, 0,
413 DISTRIBUTE_V6_OUT
, has_print
);
414 has_print
= distribute_print(vty
, dist
->prefix
, 1,
415 DISTRIBUTE_V6_OUT
, has_print
);
417 vty_out (vty
, "%s", VTY_NEWLINE
);
419 vty_out(vty
, " nothing%s", VTY_NEWLINE
);
424 /* Input filter configuration. */
425 dist
= distribute_lookup (NULL
);
426 vty_out (vty
, " Incoming update filter list for all interface is");
430 has_print
= distribute_print(vty
, dist
->list
, 0,
431 DISTRIBUTE_V4_IN
, has_print
);
432 has_print
= distribute_print(vty
, dist
->prefix
, 1,
433 DISTRIBUTE_V4_IN
, has_print
);
434 has_print
= distribute_print(vty
, dist
->list
, 0,
435 DISTRIBUTE_V6_IN
, has_print
);
436 has_print
= distribute_print(vty
, dist
->prefix
, 1,
437 DISTRIBUTE_V6_IN
, has_print
);
440 vty_out (vty
, "%s", VTY_NEWLINE
);
442 vty_out (vty
, " not set%s", VTY_NEWLINE
);
444 for (i
= 0; i
< disthash
->size
; i
++)
445 for (mp
= disthash
->index
[i
]; mp
; mp
= mp
->next
)
450 vty_out (vty
, " %s filtered by", dist
->ifname
);
452 has_print
= distribute_print(vty
, dist
->list
, 0,
453 DISTRIBUTE_V4_IN
, has_print
);
454 has_print
= distribute_print(vty
, dist
->prefix
, 1,
455 DISTRIBUTE_V4_IN
, has_print
);
456 has_print
= distribute_print(vty
, dist
->list
, 0,
457 DISTRIBUTE_V6_IN
, has_print
);
458 has_print
= distribute_print(vty
, dist
->prefix
, 1,
459 DISTRIBUTE_V6_IN
, has_print
);
461 vty_out (vty
, "%s", VTY_NEWLINE
);
463 vty_out(vty
, " nothing%s", VTY_NEWLINE
);
469 /* Configuration write function. */
471 config_write_distribute (struct vty
*vty
)
476 struct hash_backet
*mp
;
479 for (i
= 0; i
< disthash
->size
; i
++)
480 for (mp
= disthash
->index
[i
]; mp
; mp
= mp
->next
)
482 struct distribute
*dist
;
486 for (j
= 0; j
< DISTRIBUTE_MAX
; j
++)
488 output
= j
== DISTRIBUTE_V4_OUT
|| j
== DISTRIBUTE_V6_OUT
;
489 v6
= j
== DISTRIBUTE_V6_IN
|| j
== DISTRIBUTE_V6_OUT
;
490 vty_out (vty
, " %sdistribute-list %s %s %s%s",
493 output
? "out" : "in",
494 dist
->ifname
? dist
->ifname
: "",
499 for (j
= 0; j
< DISTRIBUTE_MAX
; j
++)
500 if (dist
->prefix
[j
]) {
501 output
= j
== DISTRIBUTE_V4_OUT
|| j
== DISTRIBUTE_V6_OUT
;
502 v6
= j
== DISTRIBUTE_V6_IN
|| j
== DISTRIBUTE_V6_OUT
;
503 vty_out (vty
, " %sdistribute-list prefix %s %s %s%s",
506 output
? "out" : "in",
507 dist
->ifname
? dist
->ifname
: "",
515 /* Clear all distribute list. */
517 distribute_list_reset ()
519 hash_clean (disthash
, (void (*) (void *)) distribute_free
);
522 /* Initialize distribute list related hash. */
524 distribute_list_init (int node
)
526 disthash
= hash_create (distribute_hash_make
,
527 (int (*) (const void *, const void *)) distribute_cmp
);
529 /* vtysh command-extraction doesn't grok install_element(node, ) */
530 if (node
== RIP_NODE
) {
531 install_element (RIP_NODE
, &distribute_list_cmd
);
532 install_element (RIP_NODE
, &no_distribute_list_cmd
);
533 } else if (node
== RIPNG_NODE
) {
534 install_element (RIPNG_NODE
, &distribute_list_cmd
);
535 install_element (RIPNG_NODE
, &no_distribute_list_cmd
);
539 if (node
== RIPNG_NODE
) {
540 install_element (RIPNG_NODE
, &ipv6_distribute_list_cmd
);
543 /* TODO: install v4 syntax command for v6 only protocols. */
544 /* if (node == RIPNG_NODE) {
545 * install_element (node, &ipv6_as_v4_distribute_list_all_cmd);
546 * install_element (node, &no_ipv6_as_v4_distribute_list_all_cmd);
547 * install_element (node, &ipv6_as_v4_distribute_list_cmd);
548 * install_element (node, &no_ipv6_as_v4_distribute_list_cmd);
549 * install_element (node, &ipv6_as_v4_distribute_list_prefix_all_cmd);
550 * install_element (node, &no_ipv6_as_v4_distribute_list_prefix_all_cmd);
551 * install_element (node, &ipv6_as_v4_distribute_list_prefix_cmd);
552 * install_element (node, &no_ipv6_as_v4_distribute_list_prefix_cmd);