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"
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]",
319 "Filter networks in routing updates\n"
321 "Filter incoming routing updates\n"
322 "Filter outgoing routing updates\n"
325 int ipv6
= strmatch(argv
[1]->text
, "ipv6");
326 int prefix
= (argv
[2 + ipv6
]->type
== WORD_TKN
) ? 1 : 0;
328 int idx_alname
= 2 + ipv6
+ prefix
;
329 int idx_disttype
= idx_alname
+ 1;
331 /* Check of distribute list type. */
332 enum distribute_type distin
= (ipv6
) ? DISTRIBUTE_V6_IN
: DISTRIBUTE_V4_IN
;
333 enum distribute_type distout
= (ipv6
) ? DISTRIBUTE_V6_OUT
: DISTRIBUTE_V4_OUT
;
335 enum distribute_type type
= argv
[idx_disttype
]->arg
[0] == 'i' ? distin
: distout
;
337 /* Set appropriate function call */
338 int (*distfn
)(const char *, enum distribute_type
, const char *) = prefix
?
339 &distribute_list_prefix_unset
: &distribute_list_unset
;
341 /* if interface is present, get name */
342 const char *ifname
= NULL
;
343 if (argv
[argc
- 1]->type
== VARIABLE_TKN
)
344 ifname
= argv
[argc
- 1]->arg
;
345 /* Get interface name corresponding distribute list. */
346 int ret
= distfn (ifname
, type
, argv
[2 + prefix
]->arg
);
350 vty_out (vty
, "distribute list doesn't exist%s", VTY_NEWLINE
);
357 distribute_print (struct vty
*vty
, char *tab
[], int is_prefix
,
358 enum distribute_type type
, int has_print
)
361 vty_out (vty
, "%s %s%s",
362 has_print
? "," : "",
363 is_prefix
? "(prefix-list) " : "",
371 config_show_distribute (struct vty
*vty
)
375 struct hash_backet
*mp
;
376 struct distribute
*dist
;
378 /* Output filter configuration. */
379 dist
= distribute_lookup (NULL
);
380 vty_out (vty
, " Outgoing update filter list for all interface is");
384 has_print
= distribute_print(vty
, dist
->list
, 0,
385 DISTRIBUTE_V4_OUT
, has_print
);
386 has_print
= distribute_print(vty
, dist
->prefix
, 1,
387 DISTRIBUTE_V4_OUT
, has_print
);
388 has_print
= distribute_print(vty
, dist
->list
, 0,
389 DISTRIBUTE_V6_OUT
, has_print
);
390 has_print
= distribute_print(vty
, dist
->prefix
, 1,
391 DISTRIBUTE_V6_OUT
, has_print
);
394 vty_out (vty
, "%s", VTY_NEWLINE
);
396 vty_out (vty
, " not set%s", VTY_NEWLINE
);
398 for (i
= 0; i
< disthash
->size
; i
++)
399 for (mp
= disthash
->index
[i
]; mp
; mp
= mp
->next
)
404 vty_out (vty
, " %s filtered by", dist
->ifname
);
406 has_print
= distribute_print(vty
, dist
->list
, 0,
407 DISTRIBUTE_V4_OUT
, has_print
);
408 has_print
= distribute_print(vty
, dist
->prefix
, 1,
409 DISTRIBUTE_V4_OUT
, has_print
);
410 has_print
= distribute_print(vty
, dist
->list
, 0,
411 DISTRIBUTE_V6_OUT
, has_print
);
412 has_print
= distribute_print(vty
, dist
->prefix
, 1,
413 DISTRIBUTE_V6_OUT
, has_print
);
415 vty_out (vty
, "%s", VTY_NEWLINE
);
417 vty_out(vty
, " nothing%s", VTY_NEWLINE
);
422 /* Input filter configuration. */
423 dist
= distribute_lookup (NULL
);
424 vty_out (vty
, " Incoming update filter list for all interface is");
428 has_print
= distribute_print(vty
, dist
->list
, 0,
429 DISTRIBUTE_V4_IN
, has_print
);
430 has_print
= distribute_print(vty
, dist
->prefix
, 1,
431 DISTRIBUTE_V4_IN
, has_print
);
432 has_print
= distribute_print(vty
, dist
->list
, 0,
433 DISTRIBUTE_V6_IN
, has_print
);
434 has_print
= distribute_print(vty
, dist
->prefix
, 1,
435 DISTRIBUTE_V6_IN
, has_print
);
438 vty_out (vty
, "%s", VTY_NEWLINE
);
440 vty_out (vty
, " not set%s", VTY_NEWLINE
);
442 for (i
= 0; i
< disthash
->size
; i
++)
443 for (mp
= disthash
->index
[i
]; mp
; mp
= mp
->next
)
448 vty_out (vty
, " %s filtered by", dist
->ifname
);
450 has_print
= distribute_print(vty
, dist
->list
, 0,
451 DISTRIBUTE_V4_IN
, has_print
);
452 has_print
= distribute_print(vty
, dist
->prefix
, 1,
453 DISTRIBUTE_V4_IN
, has_print
);
454 has_print
= distribute_print(vty
, dist
->list
, 0,
455 DISTRIBUTE_V6_IN
, has_print
);
456 has_print
= distribute_print(vty
, dist
->prefix
, 1,
457 DISTRIBUTE_V6_IN
, has_print
);
459 vty_out (vty
, "%s", VTY_NEWLINE
);
461 vty_out(vty
, " nothing%s", VTY_NEWLINE
);
467 /* Configuration write function. */
469 config_write_distribute (struct vty
*vty
)
474 struct hash_backet
*mp
;
477 for (i
= 0; i
< disthash
->size
; i
++)
478 for (mp
= disthash
->index
[i
]; mp
; mp
= mp
->next
)
480 struct distribute
*dist
;
484 for (j
= 0; j
< DISTRIBUTE_MAX
; j
++)
486 output
= j
== DISTRIBUTE_V4_OUT
|| j
== DISTRIBUTE_V6_OUT
;
487 v6
= j
== DISTRIBUTE_V6_IN
|| j
== DISTRIBUTE_V6_OUT
;
488 vty_out (vty
, " %sdistribute-list %s %s %s%s",
491 output
? "out" : "in",
492 dist
->ifname
? dist
->ifname
: "",
497 for (j
= 0; j
< DISTRIBUTE_MAX
; j
++)
498 if (dist
->prefix
[j
]) {
499 output
= j
== DISTRIBUTE_V4_OUT
|| j
== DISTRIBUTE_V6_OUT
;
500 v6
= j
== DISTRIBUTE_V6_IN
|| j
== DISTRIBUTE_V6_OUT
;
501 vty_out (vty
, " %sdistribute-list prefix %s %s %s%s",
504 output
? "out" : "in",
505 dist
->ifname
? dist
->ifname
: "",
513 /* Clear all distribute list. */
515 distribute_list_reset ()
517 hash_clean (disthash
, (void (*) (void *)) distribute_free
);
520 /* Initialize distribute list related hash. */
522 distribute_list_init (int node
)
524 disthash
= hash_create (distribute_hash_make
,
525 (int (*) (const void *, const void *)) distribute_cmp
);
527 install_element (node
, &distribute_list_cmd
);
528 install_element (node
, &no_distribute_list_cmd
);
530 install_element (RIP_NODE, &distribute_list_cmd);
531 install_element (RIP_NODE, &no_distribute_list_cmd);
532 install_element (RIPNG_NODE, &distribute_list_cmd);
533 install_element (RIPNG_NODE, &no_distribute_list_cmd);
537 if (node
== RIPNG_NODE
) {
538 install_element (RIPNG_NODE
, &ipv6_distribute_list_cmd
);
541 /* TODO: install v4 syntax command for v6 only protocols. */
542 /* if (node == RIPNG_NODE) {
543 * install_element (node, &ipv6_as_v4_distribute_list_all_cmd);
544 * install_element (node, &no_ipv6_as_v4_distribute_list_all_cmd);
545 * install_element (node, &ipv6_as_v4_distribute_list_cmd);
546 * install_element (node, &no_ipv6_as_v4_distribute_list_cmd);
547 * install_element (node, &ipv6_as_v4_distribute_list_prefix_all_cmd);
548 * install_element (node, &no_ipv6_as_v4_distribute_list_prefix_all_cmd);
549 * install_element (node, &ipv6_as_v4_distribute_list_prefix_cmd);
550 * install_element (node, &no_ipv6_as_v4_distribute_list_prefix_cmd);