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
*distribute_new(void)
43 return XCALLOC(MTYPE_DISTRIBUTE
, sizeof(struct distribute
));
46 /* Free distribute object. */
47 static void distribute_free(struct distribute
*dist
)
52 XFREE(MTYPE_DISTRIBUTE_IFNAME
, dist
->ifname
);
54 for (i
= 0; i
< DISTRIBUTE_MAX
; i
++)
56 XFREE(MTYPE_DISTRIBUTE_NAME
, dist
->list
[i
]);
58 for (i
= 0; i
< DISTRIBUTE_MAX
; i
++)
60 XFREE(MTYPE_DISTRIBUTE_NAME
, dist
->prefix
[i
]);
62 XFREE(MTYPE_DISTRIBUTE
, dist
);
65 static void distribute_free_if_empty(struct distribute
*dist
)
69 for (i
= 0; i
< DISTRIBUTE_MAX
; i
++)
70 if (dist
->list
[i
] != NULL
|| dist
->prefix
[i
] != NULL
)
73 hash_release(disthash
, dist
);
74 distribute_free(dist
);
77 /* Lookup interface's distribute list. */
78 struct distribute
*distribute_lookup(const char *ifname
)
80 struct distribute key
;
81 struct distribute
*dist
;
83 /* temporary reference */
84 key
.ifname
= (ifname
) ? XSTRDUP(MTYPE_DISTRIBUTE_IFNAME
, ifname
) : NULL
;
86 dist
= hash_lookup(disthash
, &key
);
89 XFREE(MTYPE_DISTRIBUTE_IFNAME
, key
.ifname
);
94 void distribute_list_add_hook(void (*func
)(struct distribute
*))
96 distribute_add_hook
= func
;
99 void distribute_list_delete_hook(void (*func
)(struct distribute
*))
101 distribute_delete_hook
= func
;
104 static void *distribute_hash_alloc(struct distribute
*arg
)
106 struct distribute
*dist
;
108 dist
= distribute_new();
110 dist
->ifname
= XSTRDUP(MTYPE_DISTRIBUTE_IFNAME
, arg
->ifname
);
116 /* Make new distribute list and push into hash. */
117 static struct distribute
*distribute_get(const char *ifname
)
119 struct distribute key
;
120 struct distribute
*ret
;
122 /* temporary reference */
123 key
.ifname
= (ifname
) ? XSTRDUP(MTYPE_DISTRIBUTE_IFNAME
, ifname
) : NULL
;
125 ret
= hash_get(disthash
, &key
,
126 (void *(*)(void *))distribute_hash_alloc
);
129 XFREE(MTYPE_DISTRIBUTE_IFNAME
, key
.ifname
);
134 static unsigned int distribute_hash_make(void *arg
)
136 const struct distribute
*dist
= arg
;
138 return dist
->ifname
? string_hash_make(dist
->ifname
) : 0;
141 /* If two distribute-list have same value then return 1 else return
142 0. This function is used by hash package. */
143 static int distribute_cmp(const struct distribute
*dist1
,
144 const struct distribute
*dist2
)
146 if (dist1
->ifname
&& dist2
->ifname
)
147 if (strcmp(dist1
->ifname
, dist2
->ifname
) == 0)
149 if (!dist1
->ifname
&& !dist2
->ifname
)
154 /* Set access-list name to the distribute list. */
155 static void distribute_list_set(const char *ifname
, enum distribute_type type
,
156 const char *alist_name
)
158 struct distribute
*dist
;
160 dist
= distribute_get(ifname
);
162 if (dist
->list
[type
])
163 XFREE(MTYPE_DISTRIBUTE_NAME
, dist
->list
[type
]);
164 dist
->list
[type
] = XSTRDUP(MTYPE_DISTRIBUTE_NAME
, alist_name
);
166 /* Apply this distribute-list to the interface. */
167 (*distribute_add_hook
)(dist
);
170 /* Unset distribute-list. If matched distribute-list exist then
172 static int distribute_list_unset(const char *ifname
, enum distribute_type type
,
173 const char *alist_name
)
175 struct distribute
*dist
;
177 dist
= distribute_lookup(ifname
);
181 if (!dist
->list
[type
])
183 if (strcmp(dist
->list
[type
], alist_name
) != 0)
186 XFREE(MTYPE_DISTRIBUTE_NAME
, dist
->list
[type
]);
187 dist
->list
[type
] = NULL
;
189 /* Apply this distribute-list to the interface. */
190 (*distribute_delete_hook
)(dist
);
192 /* If all dist are NULL, then free distribute list. */
193 distribute_free_if_empty(dist
);
197 /* Set access-list name to the distribute list. */
198 static void distribute_list_prefix_set(const char *ifname
,
199 enum distribute_type type
,
200 const char *plist_name
)
202 struct distribute
*dist
;
204 dist
= distribute_get(ifname
);
206 if (dist
->prefix
[type
])
207 XFREE(MTYPE_DISTRIBUTE_NAME
, dist
->prefix
[type
]);
208 dist
->prefix
[type
] = XSTRDUP(MTYPE_DISTRIBUTE_NAME
, plist_name
);
210 /* Apply this distribute-list to the interface. */
211 (*distribute_add_hook
)(dist
);
214 /* Unset distribute-list. If matched distribute-list exist then
216 static int distribute_list_prefix_unset(const char *ifname
,
217 enum distribute_type type
,
218 const char *plist_name
)
220 struct distribute
*dist
;
222 dist
= distribute_lookup(ifname
);
226 if (!dist
->prefix
[type
])
228 if (strcmp(dist
->prefix
[type
], plist_name
) != 0)
231 XFREE(MTYPE_DISTRIBUTE_NAME
, dist
->prefix
[type
]);
232 dist
->prefix
[type
] = NULL
;
234 /* Apply this distribute-list to the interface. */
235 (*distribute_delete_hook
)(dist
);
237 /* If all dist are NULL, then free distribute list. */
238 distribute_free_if_empty(dist
);
242 DEFUN (distribute_list
,
244 "distribute-list [prefix] WORD <in|out> [WORD]",
245 "Filter networks in routing updates\n"
248 "Filter incoming routing updates\n"
249 "Filter outgoing routing updates\n"
252 int prefix
= (argv
[1]->type
== WORD_TKN
) ? 1 : 0;
254 /* Check of distribute list type. */
255 enum distribute_type type
= argv
[2 + prefix
]->arg
[0] == 'i'
259 /* Set appropriate function call */
260 void (*distfn
)(const char *, enum distribute_type
, const char *) =
261 prefix
? &distribute_list_prefix_set
: &distribute_list_set
;
263 /* if interface is present, get name */
264 const char *ifname
= NULL
;
265 if (argv
[argc
- 1]->type
== VARIABLE_TKN
)
266 ifname
= argv
[argc
- 1]->arg
;
268 /* Get interface name corresponding distribute list. */
269 distfn(ifname
, type
, argv
[1 + prefix
]->arg
);
274 DEFUN (ipv6_distribute_list
,
275 ipv6_distribute_list_cmd
,
276 "ipv6 distribute-list [prefix] WORD <in|out> [WORD]",
278 "Filter networks in routing updates\n"
281 "Filter incoming routing updates\n"
282 "Filter outgoing routing updates\n"
285 int prefix
= (argv
[2]->type
== WORD_TKN
) ? 1 : 0;
287 /* Check of distribute list type. */
288 enum distribute_type type
= argv
[3 + prefix
]->arg
[0] == 'i'
292 /* Set appropriate function call */
293 void (*distfn
)(const char *, enum distribute_type
, const char *) =
294 prefix
? &distribute_list_prefix_set
: &distribute_list_set
;
296 /* if interface is present, get name */
297 const char *ifname
= NULL
;
298 if (argv
[argc
- 1]->type
== VARIABLE_TKN
)
299 ifname
= argv
[argc
- 1]->arg
;
301 /* Get interface name corresponding distribute list. */
302 distfn(ifname
, type
, argv
[1 + prefix
]->arg
);
307 DEFUN (no_distribute_list
,
308 no_distribute_list_cmd
,
309 "no [ipv6] distribute-list [prefix] WORD <in|out> [WORD]",
312 "Filter networks in routing updates\n"
315 "Filter incoming routing updates\n"
316 "Filter outgoing routing updates\n"
319 int ipv6
= strmatch(argv
[1]->text
, "ipv6");
320 int prefix
= (argv
[2 + ipv6
]->type
== WORD_TKN
) ? 1 : 0;
322 int idx_alname
= 2 + ipv6
+ prefix
;
323 int idx_disttype
= idx_alname
+ 1;
325 /* Check of distribute list type. */
326 enum distribute_type distin
=
327 (ipv6
) ? DISTRIBUTE_V6_IN
: DISTRIBUTE_V4_IN
;
328 enum distribute_type distout
=
329 (ipv6
) ? DISTRIBUTE_V6_OUT
: DISTRIBUTE_V4_OUT
;
331 enum distribute_type type
=
332 argv
[idx_disttype
]->arg
[0] == 'i' ? distin
: distout
;
334 /* Set appropriate function call */
335 int (*distfn
)(const char *, enum distribute_type
, const char *) =
336 prefix
? &distribute_list_prefix_unset
: &distribute_list_unset
;
338 /* if interface is present, get name */
339 const char *ifname
= NULL
;
340 if (argv
[argc
- 1]->type
== VARIABLE_TKN
)
341 ifname
= argv
[argc
- 1]->arg
;
342 /* Get interface name corresponding distribute list. */
343 int ret
= distfn(ifname
, type
, argv
[2 + prefix
]->arg
);
346 vty_out(vty
, "distribute list doesn't exist\n");
347 return CMD_WARNING_CONFIG_FAILED
;
352 static int distribute_print(struct vty
*vty
, char *tab
[], int is_prefix
,
353 enum distribute_type type
, int has_print
)
356 vty_out(vty
, "%s %s%s", has_print
? "," : "",
357 is_prefix
? "(prefix-list) " : "", tab
[type
]);
363 int config_show_distribute(struct vty
*vty
)
367 struct hash_backet
*mp
;
368 struct distribute
*dist
;
370 /* Output filter configuration. */
371 dist
= distribute_lookup(NULL
);
372 vty_out(vty
, " Outgoing update filter list for all interface is");
375 has_print
= distribute_print(vty
, dist
->list
, 0,
376 DISTRIBUTE_V4_OUT
, has_print
);
377 has_print
= distribute_print(vty
, dist
->prefix
, 1,
378 DISTRIBUTE_V4_OUT
, has_print
);
379 has_print
= distribute_print(vty
, dist
->list
, 0,
380 DISTRIBUTE_V6_OUT
, has_print
);
381 has_print
= distribute_print(vty
, dist
->prefix
, 1,
382 DISTRIBUTE_V6_OUT
, has_print
);
387 vty_out(vty
, " not set\n");
389 for (i
= 0; i
< disthash
->size
; i
++)
390 for (mp
= disthash
->index
[i
]; mp
; mp
= mp
->next
) {
393 vty_out(vty
, " %s filtered by",
396 has_print
= distribute_print(vty
, dist
->list
, 0,
399 has_print
= distribute_print(
400 vty
, dist
->prefix
, 1, DISTRIBUTE_V4_OUT
,
402 has_print
= distribute_print(vty
, dist
->list
, 0,
405 has_print
= distribute_print(
406 vty
, dist
->prefix
, 1, DISTRIBUTE_V6_OUT
,
411 vty_out(vty
, " nothing\n");
416 /* Input filter configuration. */
417 dist
= distribute_lookup(NULL
);
418 vty_out(vty
, " Incoming update filter list for all interface is");
421 has_print
= distribute_print(vty
, dist
->list
, 0,
422 DISTRIBUTE_V4_IN
, has_print
);
423 has_print
= distribute_print(vty
, dist
->prefix
, 1,
424 DISTRIBUTE_V4_IN
, has_print
);
425 has_print
= distribute_print(vty
, dist
->list
, 0,
426 DISTRIBUTE_V6_IN
, has_print
);
427 has_print
= distribute_print(vty
, dist
->prefix
, 1,
428 DISTRIBUTE_V6_IN
, has_print
);
433 vty_out(vty
, " not set\n");
435 for (i
= 0; i
< disthash
->size
; i
++)
436 for (mp
= disthash
->index
[i
]; mp
; mp
= mp
->next
) {
439 vty_out(vty
, " %s filtered by",
442 has_print
= distribute_print(vty
, dist
->list
, 0,
445 has_print
= distribute_print(
446 vty
, dist
->prefix
, 1, DISTRIBUTE_V4_IN
,
448 has_print
= distribute_print(vty
, dist
->list
, 0,
451 has_print
= distribute_print(
452 vty
, dist
->prefix
, 1, DISTRIBUTE_V6_IN
,
457 vty_out(vty
, " nothing\n");
463 /* Configuration write function. */
464 int config_write_distribute(struct vty
*vty
)
469 struct hash_backet
*mp
;
472 for (i
= 0; i
< disthash
->size
; i
++)
473 for (mp
= disthash
->index
[i
]; mp
; mp
= mp
->next
) {
474 struct distribute
*dist
;
478 for (j
= 0; j
< DISTRIBUTE_MAX
; j
++)
480 output
= j
== DISTRIBUTE_V4_OUT
481 || j
== DISTRIBUTE_V6_OUT
;
482 v6
= j
== DISTRIBUTE_V6_IN
483 || j
== DISTRIBUTE_V6_OUT
;
485 " %sdistribute-list %s %s %s\n",
488 output
? "out" : "in",
489 dist
->ifname
? dist
->ifname
494 for (j
= 0; j
< DISTRIBUTE_MAX
; j
++)
495 if (dist
->prefix
[j
]) {
496 output
= j
== DISTRIBUTE_V4_OUT
497 || j
== DISTRIBUTE_V6_OUT
;
498 v6
= j
== DISTRIBUTE_V6_IN
499 || j
== DISTRIBUTE_V6_OUT
;
501 " %sdistribute-list prefix %s %s %s\n",
504 output
? "out" : "in",
505 dist
->ifname
? dist
->ifname
513 /* Clear all distribute list. */
514 void distribute_list_reset()
516 hash_clean(disthash
, (void (*)(void *))distribute_free
);
519 /* Initialize distribute list related hash. */
520 void distribute_list_init(int node
)
522 disthash
= hash_create(
523 distribute_hash_make
,
524 (int (*)(const void *, const void *))distribute_cmp
, NULL
);
526 /* vtysh command-extraction doesn't grok install_element(node, ) */
527 if (node
== RIP_NODE
) {
528 install_element(RIP_NODE
, &distribute_list_cmd
);
529 install_element(RIP_NODE
, &no_distribute_list_cmd
);
530 } else if (node
== RIPNG_NODE
) {
531 install_element(RIPNG_NODE
, &distribute_list_cmd
);
532 install_element(RIPNG_NODE
, &no_distribute_list_cmd
);
536 if (node
== RIPNG_NODE
) {
537 install_element(RIPNG_NODE
, &ipv6_distribute_list_cmd
);
540 /* TODO: install v4 syntax command for v6 only protocols. */
541 /* if (node == RIPNG_NODE) {
542 * install_element (node, &ipv6_as_v4_distribute_list_all_cmd);
543 * install_element (node, &no_ipv6_as_v4_distribute_list_all_cmd);
544 * install_element (node, &ipv6_as_v4_distribute_list_cmd);
545 * install_element (node, &no_ipv6_as_v4_distribute_list_cmd);
546 * install_element (node, &ipv6_as_v4_distribute_list_prefix_all_cmd);
547 * install_element (node,
548 &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);