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"
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"
289 "Filter incoming routing updates\n"
290 "Filter outgoing routing updates\n"
293 int prefix
= (argv
[2]->type
== WORD_TKN
) ? 1 : 0;
295 /* Check of distribute list type. */
296 enum distribute_type type
= argv
[3 + prefix
]->arg
[0] == 'i' ?
297 DISTRIBUTE_V6_IN
: DISTRIBUTE_V6_OUT
;
299 /* Set appropriate function call */
300 void (*distfn
)(const char *, enum distribute_type
, const char *) = prefix
?
301 &distribute_list_prefix_set
: &distribute_list_set
;
303 /* if interface is present, get name */
304 const char *ifname
= NULL
;
305 if (argv
[argc
- 1]->type
== VARIABLE_TKN
)
306 ifname
= argv
[argc
- 1]->arg
;
308 /* Get interface name corresponding distribute list. */
309 distfn (ifname
, type
, argv
[1 + prefix
]->arg
);
314 DEFUN (no_distribute_list
,
315 no_distribute_list_cmd
,
316 "no [ipv6] distribute-list [prefix] WORD <in|out> [WORD]",
318 "Filter networks in routing updates\n"
320 "Filter incoming routing updates\n"
321 "Filter outgoing routing updates\n"
324 int ipv6
= strmatch(argv
[1]->text
, "ipv6");
325 int prefix
= (argv
[2 + ipv6
]->type
== WORD_TKN
) ? 1 : 0;
327 int idx_alname
= 2 + ipv6
+ prefix
;
328 int idx_disttype
= idx_alname
+ 1;
330 /* Check of distribute list type. */
331 enum distribute_type distin
= (ipv6
) ? DISTRIBUTE_V6_IN
: DISTRIBUTE_V4_IN
;
332 enum distribute_type distout
= (ipv6
) ? DISTRIBUTE_V6_OUT
: DISTRIBUTE_V4_OUT
;
334 enum distribute_type type
= argv
[idx_disttype
]->arg
[0] == 'i' ? distin
: distout
;
336 /* Set appropriate function call */
337 int (*distfn
)(const char *, enum distribute_type
, const char *) = prefix
?
338 &distribute_list_prefix_unset
: &distribute_list_unset
;
340 /* if interface is present, get name */
341 const char *ifname
= NULL
;
342 if (argv
[argc
- 1]->type
== VARIABLE_TKN
)
343 ifname
= argv
[argc
- 1]->arg
;
344 /* Get interface name corresponding distribute list. */
345 int ret
= distfn (ifname
, type
, argv
[2 + prefix
]->arg
);
349 vty_out (vty
, "distribute list doesn't exist%s", VTY_NEWLINE
);
356 distribute_print (struct vty
*vty
, char *tab
[], int is_prefix
,
357 enum distribute_type type
, int has_print
)
360 vty_out (vty
, "%s %s%s",
361 has_print
? "," : "",
362 is_prefix
? "(prefix-list) " : "",
370 config_show_distribute (struct vty
*vty
)
374 struct hash_backet
*mp
;
375 struct distribute
*dist
;
377 /* Output filter configuration. */
378 dist
= distribute_lookup (NULL
);
379 vty_out (vty
, " Outgoing update filter list for all interface is");
383 has_print
= distribute_print(vty
, dist
->list
, 0,
384 DISTRIBUTE_V4_OUT
, has_print
);
385 has_print
= distribute_print(vty
, dist
->prefix
, 1,
386 DISTRIBUTE_V4_OUT
, has_print
);
387 has_print
= distribute_print(vty
, dist
->list
, 0,
388 DISTRIBUTE_V6_OUT
, has_print
);
389 has_print
= distribute_print(vty
, dist
->prefix
, 1,
390 DISTRIBUTE_V6_OUT
, has_print
);
393 vty_out (vty
, "%s", VTY_NEWLINE
);
395 vty_out (vty
, " not set%s", VTY_NEWLINE
);
397 for (i
= 0; i
< disthash
->size
; i
++)
398 for (mp
= disthash
->index
[i
]; mp
; mp
= mp
->next
)
403 vty_out (vty
, " %s filtered by", dist
->ifname
);
405 has_print
= distribute_print(vty
, dist
->list
, 0,
406 DISTRIBUTE_V4_OUT
, has_print
);
407 has_print
= distribute_print(vty
, dist
->prefix
, 1,
408 DISTRIBUTE_V4_OUT
, has_print
);
409 has_print
= distribute_print(vty
, dist
->list
, 0,
410 DISTRIBUTE_V6_OUT
, has_print
);
411 has_print
= distribute_print(vty
, dist
->prefix
, 1,
412 DISTRIBUTE_V6_OUT
, has_print
);
414 vty_out (vty
, "%s", VTY_NEWLINE
);
416 vty_out(vty
, " nothing%s", VTY_NEWLINE
);
421 /* Input filter configuration. */
422 dist
= distribute_lookup (NULL
);
423 vty_out (vty
, " Incoming update filter list for all interface is");
427 has_print
= distribute_print(vty
, dist
->list
, 0,
428 DISTRIBUTE_V4_IN
, has_print
);
429 has_print
= distribute_print(vty
, dist
->prefix
, 1,
430 DISTRIBUTE_V4_IN
, has_print
);
431 has_print
= distribute_print(vty
, dist
->list
, 0,
432 DISTRIBUTE_V6_IN
, has_print
);
433 has_print
= distribute_print(vty
, dist
->prefix
, 1,
434 DISTRIBUTE_V6_IN
, has_print
);
437 vty_out (vty
, "%s", VTY_NEWLINE
);
439 vty_out (vty
, " not set%s", VTY_NEWLINE
);
441 for (i
= 0; i
< disthash
->size
; i
++)
442 for (mp
= disthash
->index
[i
]; mp
; mp
= mp
->next
)
447 vty_out (vty
, " %s filtered by", dist
->ifname
);
449 has_print
= distribute_print(vty
, dist
->list
, 0,
450 DISTRIBUTE_V4_IN
, has_print
);
451 has_print
= distribute_print(vty
, dist
->prefix
, 1,
452 DISTRIBUTE_V4_IN
, has_print
);
453 has_print
= distribute_print(vty
, dist
->list
, 0,
454 DISTRIBUTE_V6_IN
, has_print
);
455 has_print
= distribute_print(vty
, dist
->prefix
, 1,
456 DISTRIBUTE_V6_IN
, has_print
);
458 vty_out (vty
, "%s", VTY_NEWLINE
);
460 vty_out(vty
, " nothing%s", VTY_NEWLINE
);
466 /* Configuration write function. */
468 config_write_distribute (struct vty
*vty
)
473 struct hash_backet
*mp
;
476 for (i
= 0; i
< disthash
->size
; i
++)
477 for (mp
= disthash
->index
[i
]; mp
; mp
= mp
->next
)
479 struct distribute
*dist
;
483 for (j
= 0; j
< DISTRIBUTE_MAX
; j
++)
485 output
= j
== DISTRIBUTE_V4_OUT
|| j
== DISTRIBUTE_V6_OUT
;
486 v6
= j
== DISTRIBUTE_V6_IN
|| j
== DISTRIBUTE_V6_OUT
;
487 vty_out (vty
, " %sdistribute-list %s %s %s%s",
490 output
? "out" : "in",
491 dist
->ifname
? dist
->ifname
: "",
496 for (j
= 0; j
< DISTRIBUTE_MAX
; j
++)
497 if (dist
->prefix
[j
]) {
498 output
= j
== DISTRIBUTE_V4_OUT
|| j
== DISTRIBUTE_V6_OUT
;
499 v6
= j
== DISTRIBUTE_V6_IN
|| j
== DISTRIBUTE_V6_OUT
;
500 vty_out (vty
, " %sdistribute-list prefix %s %s %s%s",
503 output
? "out" : "in",
504 dist
->ifname
? dist
->ifname
: "",
512 /* Clear all distribute list. */
514 distribute_list_reset ()
516 hash_clean (disthash
, (void (*) (void *)) distribute_free
);
519 /* Initialize distribute list related hash. */
521 distribute_list_init (int node
)
523 disthash
= hash_create (distribute_hash_make
,
524 (int (*) (const void *, const void *)) distribute_cmp
);
526 install_element (node
, &distribute_list_cmd
);
527 install_element (node
, &no_distribute_list_cmd
);
530 if (node
== RIPNG_NODE
) {
531 install_element (node
, &ipv6_distribute_list_cmd
);
534 /* TODO: install v4 syntax command for v6 only protocols. */
535 /* if (node == RIPNG_NODE) {
536 * install_element (node, &ipv6_as_v4_distribute_list_all_cmd);
537 * install_element (node, &no_ipv6_as_v4_distribute_list_all_cmd);
538 * install_element (node, &ipv6_as_v4_distribute_list_cmd);
539 * install_element (node, &no_ipv6_as_v4_distribute_list_cmd);
540 * install_element (node, &ipv6_as_v4_distribute_list_prefix_all_cmd);
541 * install_element (node, &no_ipv6_as_v4_distribute_list_prefix_all_cmd);
542 * install_element (node, &ipv6_as_v4_distribute_list_prefix_cmd);
543 * install_element (node, &no_ipv6_as_v4_distribute_list_prefix_cmd);