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_CTX
, "Distribute ctx")
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 static struct list
*dist_ctx_list
;
37 static struct distribute
*distribute_new(void)
39 return XCALLOC(MTYPE_DISTRIBUTE
, sizeof(struct distribute
));
42 /* Free distribute object. */
43 static void distribute_free(struct distribute
*dist
)
47 XFREE(MTYPE_DISTRIBUTE_IFNAME
, dist
->ifname
);
49 for (i
= 0; i
< DISTRIBUTE_MAX
; i
++) {
50 XFREE(MTYPE_DISTRIBUTE_NAME
, dist
->list
[i
]);
53 for (i
= 0; i
< DISTRIBUTE_MAX
; i
++) {
54 XFREE(MTYPE_DISTRIBUTE_NAME
, dist
->prefix
[i
]);
57 XFREE(MTYPE_DISTRIBUTE
, dist
);
60 static void distribute_free_if_empty(struct distribute_ctx
*ctx
,
61 struct distribute
*dist
)
65 for (i
= 0; i
< DISTRIBUTE_MAX
; i
++)
66 if (dist
->list
[i
] != NULL
|| dist
->prefix
[i
] != NULL
)
69 hash_release(ctx
->disthash
, dist
);
70 distribute_free(dist
);
73 /* Lookup interface's distribute list. */
74 struct distribute
*distribute_lookup(struct distribute_ctx
*ctx
,
77 struct distribute key
;
78 struct distribute
*dist
;
80 /* temporary reference */
81 key
.ifname
= (ifname
) ? XSTRDUP(MTYPE_DISTRIBUTE_IFNAME
, ifname
) : NULL
;
83 dist
= hash_lookup(ctx
->disthash
, &key
);
85 XFREE(MTYPE_DISTRIBUTE_IFNAME
, key
.ifname
);
90 void distribute_list_add_hook(struct distribute_ctx
*ctx
,
91 void (*func
)(struct distribute_ctx
*ctx
,
94 ctx
->distribute_add_hook
= func
;
97 void distribute_list_delete_hook(struct distribute_ctx
*ctx
,
98 void (*func
)(struct distribute_ctx
*ctx
,
101 ctx
->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(struct distribute_ctx
*ctx
,
120 struct distribute key
;
121 struct distribute
*ret
;
123 /* temporary reference */
124 key
.ifname
= (ifname
) ? XSTRDUP(MTYPE_DISTRIBUTE_IFNAME
, ifname
) : NULL
;
126 ret
= hash_get(ctx
->disthash
, &key
,
127 (void *(*)(void *))distribute_hash_alloc
);
129 XFREE(MTYPE_DISTRIBUTE_IFNAME
, key
.ifname
);
134 static unsigned int distribute_hash_make(const 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 bool 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(struct distribute_ctx
*ctx
,
156 const char *ifname
, enum distribute_type type
,
157 const char *alist_name
)
159 struct distribute
*dist
;
161 dist
= distribute_get(ctx
, ifname
);
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 (ctx
->distribute_add_hook
)(ctx
, dist
);
170 /* Unset distribute-list. If matched distribute-list exist then
172 static int distribute_list_unset(struct distribute_ctx
*ctx
,
174 enum distribute_type type
,
175 const char *alist_name
)
177 struct distribute
*dist
;
179 dist
= distribute_lookup(ctx
, ifname
);
183 if (!dist
->list
[type
])
185 if (strcmp(dist
->list
[type
], alist_name
) != 0)
188 XFREE(MTYPE_DISTRIBUTE_NAME
, dist
->list
[type
]);
190 /* Apply this distribute-list to the interface. */
191 (ctx
->distribute_delete_hook
)(ctx
, dist
);
193 /* If all dist are NULL, then free distribute list. */
194 distribute_free_if_empty(ctx
, dist
);
198 /* Set access-list name to the distribute list. */
199 static void distribute_list_prefix_set(struct distribute_ctx
*ctx
,
201 enum distribute_type type
,
202 const char *plist_name
)
204 struct distribute
*dist
;
206 dist
= distribute_get(ctx
, ifname
);
208 XFREE(MTYPE_DISTRIBUTE_NAME
, dist
->prefix
[type
]);
209 dist
->prefix
[type
] = XSTRDUP(MTYPE_DISTRIBUTE_NAME
, plist_name
);
211 /* Apply this distribute-list to the interface. */
212 (ctx
->distribute_add_hook
)(ctx
, dist
);
215 /* Unset distribute-list. If matched distribute-list exist then
217 static int distribute_list_prefix_unset(struct distribute_ctx
*ctx
,
219 enum distribute_type type
,
220 const char *plist_name
)
222 struct distribute
*dist
;
224 dist
= distribute_lookup(ctx
, ifname
);
228 if (!dist
->prefix
[type
])
230 if (strcmp(dist
->prefix
[type
], plist_name
) != 0)
233 XFREE(MTYPE_DISTRIBUTE_NAME
, dist
->prefix
[type
]);
235 /* Apply this distribute-list to the interface. */
236 (ctx
->distribute_delete_hook
)(ctx
, dist
);
238 /* If all dist are NULL, then free distribute list. */
239 distribute_free_if_empty(ctx
, dist
);
243 DEFUN (distribute_list
,
245 "distribute-list [prefix] WORD <in|out> [WORD]",
246 "Filter networks in routing updates\n"
249 "Filter incoming routing updates\n"
250 "Filter outgoing routing updates\n"
253 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
)(struct distribute_ctx
*, const char *,
261 enum distribute_type
, const char *) =
262 prefix
? &distribute_list_prefix_set
: &distribute_list_set
;
263 struct distribute_ctx
*ctx
=
264 (struct distribute_ctx
*)listnode_head(dist_ctx_list
);
266 /* if interface is present, get name */
267 const char *ifname
= NULL
;
268 if (argv
[argc
- 1]->type
== VARIABLE_TKN
)
269 ifname
= argv
[argc
- 1]->arg
;
271 /* Get interface name corresponding distribute list. */
272 distfn(ctx
, ifname
, type
, argv
[1 + prefix
]->arg
);
277 DEFUN (ipv6_distribute_list
,
278 ipv6_distribute_list_cmd
,
279 "ipv6 distribute-list [prefix] WORD <in|out> [WORD]",
281 "Filter networks in routing updates\n"
284 "Filter incoming routing updates\n"
285 "Filter outgoing routing updates\n"
288 int prefix
= (argv
[2]->type
== WORD_TKN
) ? 1 : 0;
289 /* Check of distribute list type. */
290 enum distribute_type type
= argv
[3 + prefix
]->arg
[0] == 'i'
294 /* Set appropriate function call */
295 void (*distfn
)(struct distribute_ctx
*, const char *,
296 enum distribute_type
, const char *) =
297 prefix
? &distribute_list_prefix_set
: &distribute_list_set
;
298 struct distribute_ctx
*ctx
= listnode_head(dist_ctx_list
);
300 /* if interface is present, get name */
301 const char *ifname
= NULL
;
302 if (argv
[argc
- 1]->type
== VARIABLE_TKN
)
303 ifname
= argv
[argc
- 1]->arg
;
305 /* Get interface name corresponding distribute list. */
306 distfn(ctx
, ifname
, type
, argv
[2 + prefix
]->arg
);
311 DEFUN (no_distribute_list
,
312 no_distribute_list_cmd
,
313 "no distribute-list [prefix] WORD <in|out> [WORD]",
315 "Filter networks in routing updates\n"
318 "Filter incoming routing updates\n"
319 "Filter outgoing routing updates\n"
322 int prefix
= (argv
[2]->type
== WORD_TKN
) ? 1 : 0;
323 int idx_alname
= 2 + prefix
;
324 int idx_disttype
= idx_alname
+ 1;
325 enum distribute_type type
=
326 argv
[idx_disttype
]->arg
[0] == 'i' ?
327 DISTRIBUTE_V4_IN
: DISTRIBUTE_V4_OUT
;
329 /* Set appropriate function call */
330 int (*distfn
)(struct distribute_ctx
*, const char *,
331 enum distribute_type
, const char *) =
332 prefix
? &distribute_list_prefix_unset
: &distribute_list_unset
;
333 struct distribute_ctx
*ctx
= listnode_head(dist_ctx_list
);
335 /* if interface is present, get name */
336 const char *ifname
= NULL
;
337 if (argv
[argc
- 1]->type
== VARIABLE_TKN
)
338 ifname
= argv
[argc
- 1]->arg
;
339 /* Get interface name corresponding distribute list. */
340 int ret
= distfn(ctx
, ifname
, type
, argv
[2 + prefix
]->arg
);
343 vty_out(vty
, "distribute list doesn't exist\n");
344 return CMD_WARNING_CONFIG_FAILED
;
349 DEFUN (no_ipv6_distribute_list
,
350 no_ipv6_distribute_list_cmd
,
351 "no ipv6 distribute-list [prefix] WORD <in|out> [WORD]",
354 "Filter networks in routing updates\n"
357 "Filter incoming routing updates\n"
358 "Filter outgoing routing updates\n"
361 int prefix
= (argv
[3]->type
== WORD_TKN
) ? 1 : 0;
362 int idx_alname
= 3 + prefix
;
363 int idx_disttype
= idx_alname
+ 1;
365 enum distribute_type type
=
366 argv
[idx_disttype
]->arg
[0] == 'i' ?
367 DISTRIBUTE_V6_IN
: DISTRIBUTE_V6_OUT
;
368 struct distribute_ctx
*ctx
= listnode_head(dist_ctx_list
);
370 /* Set appropriate function call */
371 int (*distfn
)(struct distribute_ctx
*, const char *,
372 enum distribute_type
, const char *) =
373 prefix
? &distribute_list_prefix_unset
: &distribute_list_unset
;
375 /* if interface is present, get name */
376 const char *ifname
= NULL
;
378 if (argv
[argc
- 1]->type
== VARIABLE_TKN
)
379 ifname
= argv
[argc
- 1]->arg
;
380 /* Get interface name corresponding distribute list. */
381 int ret
= distfn(ctx
, ifname
, type
, argv
[3 + prefix
]->arg
);
384 vty_out(vty
, "distribute list doesn't exist\n");
385 return CMD_WARNING_CONFIG_FAILED
;
390 static int distribute_print(struct vty
*vty
, char *tab
[], int is_prefix
,
391 enum distribute_type type
, int has_print
)
394 vty_out(vty
, "%s %s%s", has_print
? "," : "",
395 is_prefix
? "(prefix-list) " : "", tab
[type
]);
401 int config_show_distribute(struct vty
*vty
, struct distribute_ctx
*dist_ctxt
)
405 struct hash_bucket
*mp
;
406 struct distribute
*dist
;
408 /* Output filter configuration. */
409 dist
= distribute_lookup(dist_ctxt
, NULL
);
410 vty_out(vty
, " Outgoing update filter list for all interface is");
413 has_print
= distribute_print(vty
, dist
->list
, 0,
414 DISTRIBUTE_V4_OUT
, has_print
);
415 has_print
= distribute_print(vty
, dist
->prefix
, 1,
416 DISTRIBUTE_V4_OUT
, has_print
);
417 has_print
= distribute_print(vty
, dist
->list
, 0,
418 DISTRIBUTE_V6_OUT
, has_print
);
419 has_print
= distribute_print(vty
, dist
->prefix
, 1,
420 DISTRIBUTE_V6_OUT
, has_print
);
425 vty_out(vty
, " not set\n");
427 for (i
= 0; i
< dist_ctxt
->disthash
->size
; i
++)
428 for (mp
= dist_ctxt
->disthash
->index
[i
]; mp
; mp
= mp
->next
) {
431 vty_out(vty
, " %s filtered by",
434 has_print
= distribute_print(vty
, dist
->list
, 0,
437 has_print
= distribute_print(
438 vty
, dist
->prefix
, 1, DISTRIBUTE_V4_OUT
,
440 has_print
= distribute_print(vty
, dist
->list
, 0,
443 has_print
= distribute_print(
444 vty
, dist
->prefix
, 1, DISTRIBUTE_V6_OUT
,
449 vty_out(vty
, " nothing\n");
454 /* Input filter configuration. */
455 dist
= distribute_lookup(dist_ctxt
, NULL
);
456 vty_out(vty
, " Incoming update filter list for all interface is");
459 has_print
= distribute_print(vty
, dist
->list
, 0,
460 DISTRIBUTE_V4_IN
, has_print
);
461 has_print
= distribute_print(vty
, dist
->prefix
, 1,
462 DISTRIBUTE_V4_IN
, has_print
);
463 has_print
= distribute_print(vty
, dist
->list
, 0,
464 DISTRIBUTE_V6_IN
, has_print
);
465 has_print
= distribute_print(vty
, dist
->prefix
, 1,
466 DISTRIBUTE_V6_IN
, has_print
);
471 vty_out(vty
, " not set\n");
473 for (i
= 0; i
< dist_ctxt
->disthash
->size
; i
++)
474 for (mp
= dist_ctxt
->disthash
->index
[i
]; mp
; mp
= mp
->next
) {
477 vty_out(vty
, " %s filtered by",
480 has_print
= distribute_print(vty
, dist
->list
, 0,
483 has_print
= distribute_print(
484 vty
, dist
->prefix
, 1, DISTRIBUTE_V4_IN
,
486 has_print
= distribute_print(vty
, dist
->list
, 0,
489 has_print
= distribute_print(
490 vty
, dist
->prefix
, 1, DISTRIBUTE_V6_IN
,
495 vty_out(vty
, " nothing\n");
501 /* Configuration write function. */
502 int config_write_distribute(struct vty
*vty
,
503 struct distribute_ctx
*dist_ctxt
)
508 struct hash_bucket
*mp
;
511 for (i
= 0; i
< dist_ctxt
->disthash
->size
; i
++)
512 for (mp
= dist_ctxt
->disthash
->index
[i
]; mp
; mp
= mp
->next
) {
513 struct distribute
*dist
;
517 for (j
= 0; j
< DISTRIBUTE_MAX
; j
++)
519 output
= j
== DISTRIBUTE_V4_OUT
520 || j
== DISTRIBUTE_V6_OUT
;
521 v6
= j
== DISTRIBUTE_V6_IN
522 || j
== DISTRIBUTE_V6_OUT
;
524 " %sdistribute-list %s %s %s\n",
527 output
? "out" : "in",
528 dist
->ifname
? dist
->ifname
533 for (j
= 0; j
< DISTRIBUTE_MAX
; j
++)
534 if (dist
->prefix
[j
]) {
535 output
= j
== DISTRIBUTE_V4_OUT
536 || j
== DISTRIBUTE_V6_OUT
;
537 v6
= j
== DISTRIBUTE_V6_IN
538 || j
== DISTRIBUTE_V6_OUT
;
540 " %sdistribute-list prefix %s %s %s\n",
543 output
? "out" : "in",
544 dist
->ifname
? dist
->ifname
552 void distribute_list_delete(struct distribute_ctx
**ctx
)
554 if ((*ctx
)->disthash
) {
555 hash_clean((*ctx
)->disthash
, (void (*)(void *))distribute_free
);
558 dist_ctx_list
= list_new();
559 listnode_delete(dist_ctx_list
, *ctx
);
560 if (list_isempty(dist_ctx_list
))
561 list_delete(&dist_ctx_list
);
562 XFREE(MTYPE_DISTRIBUTE_CTX
, (*ctx
));
565 /* Initialize distribute list container */
566 struct distribute_ctx
*distribute_list_ctx_create(struct vrf
*vrf
)
568 struct distribute_ctx
*ctx
;
570 ctx
= XCALLOC(MTYPE_DISTRIBUTE_CTX
, sizeof(struct distribute_ctx
));
572 ctx
->disthash
= hash_create(
573 distribute_hash_make
,
574 (bool (*)(const void *, const void *))distribute_cmp
, NULL
);
576 dist_ctx_list
= list_new();
577 listnode_add(dist_ctx_list
, ctx
);
581 /* Initialize distribute list vty commands */
582 void distribute_list_init(int node
)
584 /* vtysh command-extraction doesn't grok install_element(node, ) */
585 if (node
== RIP_NODE
) {
586 install_element(RIP_NODE
, &distribute_list_cmd
);
587 install_element(RIP_NODE
, &no_distribute_list_cmd
);
588 } else if (node
== RIPNG_NODE
) {
589 install_element(RIPNG_NODE
, &distribute_list_cmd
);
590 install_element(RIPNG_NODE
, &no_distribute_list_cmd
);
592 install_element(RIPNG_NODE
, &ipv6_distribute_list_cmd
);
593 install_element(RIPNG_NODE
, &no_ipv6_distribute_list_cmd
);
596 /* TODO: install v4 syntax command for v6 only protocols. */
597 /* if (node == RIPNG_NODE) {
598 * install_element (node, &ipv6_as_v4_distribute_list_all_cmd);
599 * install_element (node, &no_ipv6_as_v4_distribute_list_all_cmd);
600 * install_element (node, &ipv6_as_v4_distribute_list_cmd);
601 * install_element (node, &no_ipv6_as_v4_distribute_list_cmd);
602 * install_element (node, &ipv6_as_v4_distribute_list_prefix_all_cmd);
603 * install_element (node,
604 &no_ipv6_as_v4_distribute_list_prefix_all_cmd);
605 * install_element (node, &ipv6_as_v4_distribute_list_prefix_cmd);
606 * install_element (node, &no_ipv6_as_v4_distribute_list_prefix_cmd);