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 DEFINE_MTYPE_STATIC(LIB
, DISTRIBUTE
, "Distribute list")
32 DEFINE_MTYPE_STATIC(LIB
, DISTRIBUTE_IFNAME
, "Dist-list ifname")
33 DEFINE_MTYPE_STATIC(LIB
, DISTRIBUTE_NAME
, "Dist-list name")
35 /* Hash of distribute list. */
36 struct hash
*disthash
;
39 void (*distribute_add_hook
) (struct distribute
*);
40 void (*distribute_delete_hook
) (struct distribute
*);
42 static struct distribute
*
45 return XCALLOC (MTYPE_DISTRIBUTE
, sizeof (struct distribute
));
48 /* Free distribute object. */
50 distribute_free (struct distribute
*dist
)
55 XFREE (MTYPE_DISTRIBUTE_IFNAME
, dist
->ifname
);
57 for (i
= 0; i
< DISTRIBUTE_MAX
; i
++)
59 XFREE(MTYPE_DISTRIBUTE_NAME
, dist
->list
[i
]);
61 for (i
= 0; i
< DISTRIBUTE_MAX
; i
++)
63 XFREE(MTYPE_DISTRIBUTE_NAME
, dist
->prefix
[i
]);
65 XFREE (MTYPE_DISTRIBUTE
, dist
);
69 distribute_free_if_empty(struct distribute
*dist
)
73 for (i
= 0; i
< DISTRIBUTE_MAX
; i
++)
74 if (dist
->list
[i
] != NULL
|| dist
->prefix
[i
] != NULL
)
77 hash_release (disthash
, dist
);
78 distribute_free (dist
);
81 /* Lookup interface's distribute list. */
83 distribute_lookup (const char *ifname
)
85 struct distribute key
;
86 struct distribute
*dist
;
88 /* temporary reference */
89 key
.ifname
= (ifname
) ? XSTRDUP(MTYPE_DISTRIBUTE_IFNAME
, ifname
) : NULL
;
91 dist
= hash_lookup (disthash
, &key
);
94 XFREE(MTYPE_DISTRIBUTE_IFNAME
, key
.ifname
);
100 distribute_list_add_hook (void (*func
) (struct distribute
*))
102 distribute_add_hook
= func
;
106 distribute_list_delete_hook (void (*func
) (struct distribute
*))
108 distribute_delete_hook
= func
;
112 distribute_hash_alloc (struct distribute
*arg
)
114 struct distribute
*dist
;
116 dist
= distribute_new ();
118 dist
->ifname
= XSTRDUP (MTYPE_DISTRIBUTE_IFNAME
, arg
->ifname
);
124 /* Make new distribute list and push into hash. */
125 static struct distribute
*
126 distribute_get (const char *ifname
)
128 struct distribute key
;
129 struct distribute
*ret
;
131 /* temporary reference */
132 key
.ifname
= (ifname
) ? XSTRDUP(MTYPE_DISTRIBUTE_IFNAME
, ifname
) : NULL
;
134 ret
= hash_get (disthash
, &key
, (void * (*) (void *))distribute_hash_alloc
);
137 XFREE(MTYPE_DISTRIBUTE_IFNAME
, key
.ifname
);
143 distribute_hash_make (void *arg
)
145 const struct distribute
*dist
= arg
;
147 return dist
->ifname
? string_hash_make (dist
->ifname
) : 0;
150 /* If two distribute-list have same value then return 1 else return
151 0. This function is used by hash package. */
153 distribute_cmp (const struct distribute
*dist1
, const struct distribute
*dist2
)
155 if (dist1
->ifname
&& dist2
->ifname
)
156 if (strcmp (dist1
->ifname
, dist2
->ifname
) == 0)
158 if (! dist1
->ifname
&& ! dist2
->ifname
)
163 /* Set access-list name to the distribute list. */
165 distribute_list_set (const char *ifname
, enum distribute_type type
,
166 const char *alist_name
)
168 struct distribute
*dist
;
170 dist
= distribute_get (ifname
);
172 if (dist
->list
[type
])
173 XFREE(MTYPE_DISTRIBUTE_NAME
, dist
->list
[type
]);
174 dist
->list
[type
] = XSTRDUP(MTYPE_DISTRIBUTE_NAME
, alist_name
);
176 /* Apply this distribute-list to the interface. */
177 (*distribute_add_hook
) (dist
);
180 /* Unset distribute-list. If matched distribute-list exist then
183 distribute_list_unset (const char *ifname
, enum distribute_type type
,
184 const char *alist_name
)
186 struct distribute
*dist
;
188 dist
= distribute_lookup (ifname
);
192 if (!dist
->list
[type
])
194 if (strcmp (dist
->list
[type
], alist_name
) != 0)
197 XFREE(MTYPE_DISTRIBUTE_NAME
, dist
->list
[type
]);
198 dist
->list
[type
] = NULL
;
200 /* Apply this distribute-list to the interface. */
201 (*distribute_delete_hook
) (dist
);
203 /* If all dist are NULL, then free distribute list. */
204 distribute_free_if_empty(dist
);
208 /* Set access-list name to the distribute list. */
210 distribute_list_prefix_set (const char *ifname
, enum distribute_type type
,
211 const char *plist_name
)
213 struct distribute
*dist
;
215 dist
= distribute_get (ifname
);
217 if (dist
->prefix
[type
])
218 XFREE(MTYPE_DISTRIBUTE_NAME
, dist
->prefix
[type
]);
219 dist
->prefix
[type
] = XSTRDUP(MTYPE_DISTRIBUTE_NAME
, plist_name
);
221 /* Apply this distribute-list to the interface. */
222 (*distribute_add_hook
) (dist
);
225 /* Unset distribute-list. If matched distribute-list exist then
228 distribute_list_prefix_unset (const char *ifname
, enum distribute_type type
,
229 const char *plist_name
)
231 struct distribute
*dist
;
233 dist
= distribute_lookup (ifname
);
237 if (!dist
->prefix
[type
])
239 if (strcmp (dist
->prefix
[type
], plist_name
) != 0)
242 XFREE(MTYPE_DISTRIBUTE_NAME
, dist
->prefix
[type
]);
243 dist
->prefix
[type
] = NULL
;
245 /* Apply this distribute-list to the interface. */
246 (*distribute_delete_hook
) (dist
);
248 /* If all dist are NULL, then free distribute list. */
249 distribute_free_if_empty(dist
);
253 DEFUN (distribute_list
,
255 "distribute-list [prefix] WORD <in|out> [WORD]",
256 "Filter networks in routing updates\n"
259 "Filter incoming routing updates\n"
260 "Filter outgoing routing updates\n"
263 int prefix
= (argv
[1]->type
== WORD_TKN
) ? 1 : 0;
265 /* Check of distribute list type. */
266 enum distribute_type type
= argv
[2 + prefix
]->arg
[0] == 'i' ?
267 DISTRIBUTE_V4_IN
: DISTRIBUTE_V4_OUT
;
269 /* Set appropriate function call */
270 void (*distfn
)(const char *, enum distribute_type
, const char *) = prefix
?
271 &distribute_list_prefix_set
: &distribute_list_set
;
273 /* if interface is present, get name */
274 const char *ifname
= NULL
;
275 if (argv
[argc
- 1]->type
== VARIABLE_TKN
)
276 ifname
= argv
[argc
- 1]->arg
;
278 /* Get interface name corresponding distribute list. */
279 distfn (ifname
, type
, argv
[1 + prefix
]->arg
);
284 DEFUN (ipv6_distribute_list
,
285 ipv6_distribute_list_cmd
,
286 "ipv6 distribute-list [prefix] WORD <in|out> [WORD]",
288 "Filter networks in routing updates\n"
291 "Filter incoming routing updates\n"
292 "Filter outgoing routing updates\n"
295 int prefix
= (argv
[2]->type
== WORD_TKN
) ? 1 : 0;
297 /* Check of distribute list type. */
298 enum distribute_type type
= argv
[3 + prefix
]->arg
[0] == 'i' ?
299 DISTRIBUTE_V6_IN
: DISTRIBUTE_V6_OUT
;
301 /* Set appropriate function call */
302 void (*distfn
)(const char *, enum distribute_type
, const char *) = prefix
?
303 &distribute_list_prefix_set
: &distribute_list_set
;
305 /* if interface is present, get name */
306 const char *ifname
= NULL
;
307 if (argv
[argc
- 1]->type
== VARIABLE_TKN
)
308 ifname
= argv
[argc
- 1]->arg
;
310 /* Get interface name corresponding distribute list. */
311 distfn (ifname
, type
, argv
[1 + prefix
]->arg
);
316 DEFUN (no_distribute_list
,
317 no_distribute_list_cmd
,
318 "no [ipv6] distribute-list [prefix] WORD <in|out> [WORD]",
321 "Filter networks in routing updates\n"
324 "Filter incoming routing updates\n"
325 "Filter outgoing routing updates\n"
328 int ipv6
= strmatch(argv
[1]->text
, "ipv6");
329 int prefix
= (argv
[2 + ipv6
]->type
== WORD_TKN
) ? 1 : 0;
331 int idx_alname
= 2 + ipv6
+ prefix
;
332 int idx_disttype
= idx_alname
+ 1;
334 /* Check of distribute list type. */
335 enum distribute_type distin
= (ipv6
) ? DISTRIBUTE_V6_IN
: DISTRIBUTE_V4_IN
;
336 enum distribute_type distout
= (ipv6
) ? DISTRIBUTE_V6_OUT
: DISTRIBUTE_V4_OUT
;
338 enum distribute_type type
= argv
[idx_disttype
]->arg
[0] == 'i' ? distin
: distout
;
340 /* Set appropriate function call */
341 int (*distfn
)(const char *, enum distribute_type
, const char *) = prefix
?
342 &distribute_list_prefix_unset
: &distribute_list_unset
;
344 /* if interface is present, get name */
345 const char *ifname
= NULL
;
346 if (argv
[argc
- 1]->type
== VARIABLE_TKN
)
347 ifname
= argv
[argc
- 1]->arg
;
348 /* Get interface name corresponding distribute list. */
349 int ret
= distfn (ifname
, type
, argv
[2 + prefix
]->arg
);
353 vty_out (vty
, "distribute list doesn't exist%s", VTY_NEWLINE
);
360 distribute_print (struct vty
*vty
, char *tab
[], int is_prefix
,
361 enum distribute_type type
, int has_print
)
364 vty_out (vty
, "%s %s%s",
365 has_print
? "," : "",
366 is_prefix
? "(prefix-list) " : "",
374 config_show_distribute (struct vty
*vty
)
378 struct hash_backet
*mp
;
379 struct distribute
*dist
;
381 /* Output filter configuration. */
382 dist
= distribute_lookup (NULL
);
383 vty_out (vty
, " Outgoing update filter list for all interface is");
387 has_print
= distribute_print(vty
, dist
->list
, 0,
388 DISTRIBUTE_V4_OUT
, has_print
);
389 has_print
= distribute_print(vty
, dist
->prefix
, 1,
390 DISTRIBUTE_V4_OUT
, has_print
);
391 has_print
= distribute_print(vty
, dist
->list
, 0,
392 DISTRIBUTE_V6_OUT
, has_print
);
393 has_print
= distribute_print(vty
, dist
->prefix
, 1,
394 DISTRIBUTE_V6_OUT
, has_print
);
397 vty_out (vty
, "%s", VTY_NEWLINE
);
399 vty_out (vty
, " not set%s", VTY_NEWLINE
);
401 for (i
= 0; i
< disthash
->size
; i
++)
402 for (mp
= disthash
->index
[i
]; mp
; mp
= mp
->next
)
407 vty_out (vty
, " %s filtered by", dist
->ifname
);
409 has_print
= distribute_print(vty
, dist
->list
, 0,
410 DISTRIBUTE_V4_OUT
, has_print
);
411 has_print
= distribute_print(vty
, dist
->prefix
, 1,
412 DISTRIBUTE_V4_OUT
, has_print
);
413 has_print
= distribute_print(vty
, dist
->list
, 0,
414 DISTRIBUTE_V6_OUT
, has_print
);
415 has_print
= distribute_print(vty
, dist
->prefix
, 1,
416 DISTRIBUTE_V6_OUT
, has_print
);
418 vty_out (vty
, "%s", VTY_NEWLINE
);
420 vty_out(vty
, " nothing%s", VTY_NEWLINE
);
425 /* Input filter configuration. */
426 dist
= distribute_lookup (NULL
);
427 vty_out (vty
, " Incoming update filter list for all interface is");
431 has_print
= distribute_print(vty
, dist
->list
, 0,
432 DISTRIBUTE_V4_IN
, has_print
);
433 has_print
= distribute_print(vty
, dist
->prefix
, 1,
434 DISTRIBUTE_V4_IN
, has_print
);
435 has_print
= distribute_print(vty
, dist
->list
, 0,
436 DISTRIBUTE_V6_IN
, has_print
);
437 has_print
= distribute_print(vty
, dist
->prefix
, 1,
438 DISTRIBUTE_V6_IN
, has_print
);
441 vty_out (vty
, "%s", VTY_NEWLINE
);
443 vty_out (vty
, " not set%s", VTY_NEWLINE
);
445 for (i
= 0; i
< disthash
->size
; i
++)
446 for (mp
= disthash
->index
[i
]; mp
; mp
= mp
->next
)
451 vty_out (vty
, " %s filtered by", dist
->ifname
);
453 has_print
= distribute_print(vty
, dist
->list
, 0,
454 DISTRIBUTE_V4_IN
, has_print
);
455 has_print
= distribute_print(vty
, dist
->prefix
, 1,
456 DISTRIBUTE_V4_IN
, has_print
);
457 has_print
= distribute_print(vty
, dist
->list
, 0,
458 DISTRIBUTE_V6_IN
, has_print
);
459 has_print
= distribute_print(vty
, dist
->prefix
, 1,
460 DISTRIBUTE_V6_IN
, has_print
);
462 vty_out (vty
, "%s", VTY_NEWLINE
);
464 vty_out(vty
, " nothing%s", VTY_NEWLINE
);
470 /* Configuration write function. */
472 config_write_distribute (struct vty
*vty
)
477 struct hash_backet
*mp
;
480 for (i
= 0; i
< disthash
->size
; i
++)
481 for (mp
= disthash
->index
[i
]; mp
; mp
= mp
->next
)
483 struct distribute
*dist
;
487 for (j
= 0; j
< DISTRIBUTE_MAX
; j
++)
489 output
= j
== DISTRIBUTE_V4_OUT
|| j
== DISTRIBUTE_V6_OUT
;
490 v6
= j
== DISTRIBUTE_V6_IN
|| j
== DISTRIBUTE_V6_OUT
;
491 vty_out (vty
, " %sdistribute-list %s %s %s%s",
494 output
? "out" : "in",
495 dist
->ifname
? dist
->ifname
: "",
500 for (j
= 0; j
< DISTRIBUTE_MAX
; j
++)
501 if (dist
->prefix
[j
]) {
502 output
= j
== DISTRIBUTE_V4_OUT
|| j
== DISTRIBUTE_V6_OUT
;
503 v6
= j
== DISTRIBUTE_V6_IN
|| j
== DISTRIBUTE_V6_OUT
;
504 vty_out (vty
, " %sdistribute-list prefix %s %s %s%s",
507 output
? "out" : "in",
508 dist
->ifname
? dist
->ifname
: "",
516 /* Clear all distribute list. */
518 distribute_list_reset ()
520 hash_clean (disthash
, (void (*) (void *)) distribute_free
);
523 /* Initialize distribute list related hash. */
525 distribute_list_init (int node
)
527 disthash
= hash_create (distribute_hash_make
,
528 (int (*) (const void *, const void *)) distribute_cmp
);
530 /* vtysh command-extraction doesn't grok install_element(node, ) */
531 if (node
== RIP_NODE
) {
532 install_element (RIP_NODE
, &distribute_list_cmd
);
533 install_element (RIP_NODE
, &no_distribute_list_cmd
);
534 } else if (node
== RIPNG_NODE
) {
535 install_element (RIPNG_NODE
, &distribute_list_cmd
);
536 install_element (RIPNG_NODE
, &no_distribute_list_cmd
);
540 if (node
== RIPNG_NODE
) {
541 install_element (RIPNG_NODE
, &ipv6_distribute_list_cmd
);
544 /* TODO: install v4 syntax command for v6 only protocols. */
545 /* if (node == RIPNG_NODE) {
546 * install_element (node, &ipv6_as_v4_distribute_list_all_cmd);
547 * install_element (node, &no_ipv6_as_v4_distribute_list_all_cmd);
548 * install_element (node, &ipv6_as_v4_distribute_list_cmd);
549 * install_element (node, &no_ipv6_as_v4_distribute_list_cmd);
550 * install_element (node, &ipv6_as_v4_distribute_list_prefix_all_cmd);
551 * install_element (node, &no_ipv6_as_v4_distribute_list_prefix_all_cmd);
552 * install_element (node, &ipv6_as_v4_distribute_list_prefix_cmd);
553 * install_element (node, &no_ipv6_as_v4_distribute_list_prefix_cmd);