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(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
]);
189 dist
->list
[type
] = NULL
;
191 /* Apply this distribute-list to the interface. */
192 (ctx
->distribute_delete_hook
)(ctx
, dist
);
194 /* If all dist are NULL, then free distribute list. */
195 distribute_free_if_empty(ctx
, dist
);
199 /* Set access-list name to the distribute list. */
200 static void distribute_list_prefix_set(struct distribute_ctx
*ctx
,
202 enum distribute_type type
,
203 const char *plist_name
)
205 struct distribute
*dist
;
207 dist
= distribute_get(ctx
, ifname
);
209 XFREE(MTYPE_DISTRIBUTE_NAME
, dist
->prefix
[type
]);
210 dist
->prefix
[type
] = XSTRDUP(MTYPE_DISTRIBUTE_NAME
, plist_name
);
212 /* Apply this distribute-list to the interface. */
213 (ctx
->distribute_add_hook
)(ctx
, dist
);
216 /* Unset distribute-list. If matched distribute-list exist then
218 static int distribute_list_prefix_unset(struct distribute_ctx
*ctx
,
220 enum distribute_type type
,
221 const char *plist_name
)
223 struct distribute
*dist
;
225 dist
= distribute_lookup(ctx
, ifname
);
229 if (!dist
->prefix
[type
])
231 if (strcmp(dist
->prefix
[type
], plist_name
) != 0)
234 XFREE(MTYPE_DISTRIBUTE_NAME
, dist
->prefix
[type
]);
235 dist
->prefix
[type
] = NULL
;
237 /* Apply this distribute-list to the interface. */
238 (ctx
->distribute_delete_hook
)(ctx
, dist
);
240 /* If all dist are NULL, then free distribute list. */
241 distribute_free_if_empty(ctx
, dist
);
245 DEFUN (distribute_list
,
247 "distribute-list [prefix] WORD <in|out> [WORD]",
248 "Filter networks in routing updates\n"
251 "Filter incoming routing updates\n"
252 "Filter outgoing routing updates\n"
255 int prefix
= (argv
[1]->type
== WORD_TKN
) ? 1 : 0;
256 /* Check of distribute list type. */
257 enum distribute_type type
= argv
[2 + prefix
]->arg
[0] == 'i'
261 /* Set appropriate function call */
262 void (*distfn
)(struct distribute_ctx
*, const char *,
263 enum distribute_type
, const char *) =
264 prefix
? &distribute_list_prefix_set
: &distribute_list_set
;
265 struct distribute_ctx
*ctx
=
266 (struct distribute_ctx
*)listnode_head(dist_ctx_list
);
268 /* if interface is present, get name */
269 const char *ifname
= NULL
;
270 if (argv
[argc
- 1]->type
== VARIABLE_TKN
)
271 ifname
= argv
[argc
- 1]->arg
;
273 /* Get interface name corresponding distribute list. */
274 distfn(ctx
, ifname
, type
, argv
[1 + prefix
]->arg
);
279 DEFUN (ipv6_distribute_list
,
280 ipv6_distribute_list_cmd
,
281 "ipv6 distribute-list [prefix] WORD <in|out> [WORD]",
283 "Filter networks in routing updates\n"
286 "Filter incoming routing updates\n"
287 "Filter outgoing routing updates\n"
290 int prefix
= (argv
[2]->type
== WORD_TKN
) ? 1 : 0;
291 /* Check of distribute list type. */
292 enum distribute_type type
= argv
[3 + prefix
]->arg
[0] == 'i'
296 /* Set appropriate function call */
297 void (*distfn
)(struct distribute_ctx
*, const char *,
298 enum distribute_type
, const char *) =
299 prefix
? &distribute_list_prefix_set
: &distribute_list_set
;
300 struct distribute_ctx
*ctx
= listnode_head(dist_ctx_list
);
302 /* if interface is present, get name */
303 const char *ifname
= NULL
;
304 if (argv
[argc
- 1]->type
== VARIABLE_TKN
)
305 ifname
= argv
[argc
- 1]->arg
;
307 /* Get interface name corresponding distribute list. */
308 distfn(ctx
, ifname
, type
, argv
[2 + prefix
]->arg
);
313 DEFUN (no_distribute_list
,
314 no_distribute_list_cmd
,
315 "no distribute-list [prefix] WORD <in|out> [WORD]",
317 "Filter networks in routing updates\n"
320 "Filter incoming routing updates\n"
321 "Filter outgoing routing updates\n"
324 int prefix
= (argv
[2]->type
== WORD_TKN
) ? 1 : 0;
325 int idx_alname
= 2 + prefix
;
326 int idx_disttype
= idx_alname
+ 1;
327 enum distribute_type type
=
328 argv
[idx_disttype
]->arg
[0] == 'i' ?
329 DISTRIBUTE_V4_IN
: DISTRIBUTE_V4_OUT
;
331 /* Set appropriate function call */
332 int (*distfn
)(struct distribute_ctx
*, const char *,
333 enum distribute_type
, const char *) =
334 prefix
? &distribute_list_prefix_unset
: &distribute_list_unset
;
335 struct distribute_ctx
*ctx
= listnode_head(dist_ctx_list
);
337 /* if interface is present, get name */
338 const char *ifname
= NULL
;
339 if (argv
[argc
- 1]->type
== VARIABLE_TKN
)
340 ifname
= argv
[argc
- 1]->arg
;
341 /* Get interface name corresponding distribute list. */
342 int ret
= distfn(ctx
, ifname
, type
, argv
[2 + prefix
]->arg
);
345 vty_out(vty
, "distribute list doesn't exist\n");
346 return CMD_WARNING_CONFIG_FAILED
;
351 DEFUN (no_ipv6_distribute_list
,
352 no_ipv6_distribute_list_cmd
,
353 "no ipv6 distribute-list [prefix] WORD <in|out> [WORD]",
356 "Filter networks in routing updates\n"
359 "Filter incoming routing updates\n"
360 "Filter outgoing routing updates\n"
363 int prefix
= (argv
[3]->type
== WORD_TKN
) ? 1 : 0;
364 int idx_alname
= 3 + prefix
;
365 int idx_disttype
= idx_alname
+ 1;
367 enum distribute_type type
=
368 argv
[idx_disttype
]->arg
[0] == 'i' ?
369 DISTRIBUTE_V6_IN
: DISTRIBUTE_V6_OUT
;
370 struct distribute_ctx
*ctx
= listnode_head(dist_ctx_list
);
372 /* Set appropriate function call */
373 int (*distfn
)(struct distribute_ctx
*, const char *,
374 enum distribute_type
, const char *) =
375 prefix
? &distribute_list_prefix_unset
: &distribute_list_unset
;
377 /* if interface is present, get name */
378 const char *ifname
= NULL
;
380 if (argv
[argc
- 1]->type
== VARIABLE_TKN
)
381 ifname
= argv
[argc
- 1]->arg
;
382 /* Get interface name corresponding distribute list. */
383 int ret
= distfn(ctx
, ifname
, type
, argv
[3 + prefix
]->arg
);
386 vty_out(vty
, "distribute list doesn't exist\n");
387 return CMD_WARNING_CONFIG_FAILED
;
392 static int distribute_print(struct vty
*vty
, char *tab
[], int is_prefix
,
393 enum distribute_type type
, int has_print
)
396 vty_out(vty
, "%s %s%s", has_print
? "," : "",
397 is_prefix
? "(prefix-list) " : "", tab
[type
]);
403 int config_show_distribute(struct vty
*vty
, struct distribute_ctx
*dist_ctxt
)
407 struct hash_bucket
*mp
;
408 struct distribute
*dist
;
410 /* Output filter configuration. */
411 dist
= distribute_lookup(dist_ctxt
, NULL
);
412 vty_out(vty
, " Outgoing update filter list for all interface is");
415 has_print
= distribute_print(vty
, dist
->list
, 0,
416 DISTRIBUTE_V4_OUT
, has_print
);
417 has_print
= distribute_print(vty
, dist
->prefix
, 1,
418 DISTRIBUTE_V4_OUT
, has_print
);
419 has_print
= distribute_print(vty
, dist
->list
, 0,
420 DISTRIBUTE_V6_OUT
, has_print
);
421 has_print
= distribute_print(vty
, dist
->prefix
, 1,
422 DISTRIBUTE_V6_OUT
, has_print
);
427 vty_out(vty
, " not set\n");
429 for (i
= 0; i
< dist_ctxt
->disthash
->size
; i
++)
430 for (mp
= dist_ctxt
->disthash
->index
[i
]; mp
; mp
= mp
->next
) {
433 vty_out(vty
, " %s filtered by",
436 has_print
= distribute_print(vty
, dist
->list
, 0,
439 has_print
= distribute_print(
440 vty
, dist
->prefix
, 1, DISTRIBUTE_V4_OUT
,
442 has_print
= distribute_print(vty
, dist
->list
, 0,
445 has_print
= distribute_print(
446 vty
, dist
->prefix
, 1, DISTRIBUTE_V6_OUT
,
451 vty_out(vty
, " nothing\n");
456 /* Input filter configuration. */
457 dist
= distribute_lookup(dist_ctxt
, NULL
);
458 vty_out(vty
, " Incoming update filter list for all interface is");
461 has_print
= distribute_print(vty
, dist
->list
, 0,
462 DISTRIBUTE_V4_IN
, has_print
);
463 has_print
= distribute_print(vty
, dist
->prefix
, 1,
464 DISTRIBUTE_V4_IN
, has_print
);
465 has_print
= distribute_print(vty
, dist
->list
, 0,
466 DISTRIBUTE_V6_IN
, has_print
);
467 has_print
= distribute_print(vty
, dist
->prefix
, 1,
468 DISTRIBUTE_V6_IN
, has_print
);
473 vty_out(vty
, " not set\n");
475 for (i
= 0; i
< dist_ctxt
->disthash
->size
; i
++)
476 for (mp
= dist_ctxt
->disthash
->index
[i
]; mp
; mp
= mp
->next
) {
479 vty_out(vty
, " %s filtered by",
482 has_print
= distribute_print(vty
, dist
->list
, 0,
485 has_print
= distribute_print(
486 vty
, dist
->prefix
, 1, DISTRIBUTE_V4_IN
,
488 has_print
= distribute_print(vty
, dist
->list
, 0,
491 has_print
= distribute_print(
492 vty
, dist
->prefix
, 1, DISTRIBUTE_V6_IN
,
497 vty_out(vty
, " nothing\n");
503 /* Configuration write function. */
504 int config_write_distribute(struct vty
*vty
,
505 struct distribute_ctx
*dist_ctxt
)
510 struct hash_bucket
*mp
;
513 for (i
= 0; i
< dist_ctxt
->disthash
->size
; i
++)
514 for (mp
= dist_ctxt
->disthash
->index
[i
]; mp
; mp
= mp
->next
) {
515 struct distribute
*dist
;
519 for (j
= 0; j
< DISTRIBUTE_MAX
; j
++)
521 output
= j
== DISTRIBUTE_V4_OUT
522 || j
== DISTRIBUTE_V6_OUT
;
523 v6
= j
== DISTRIBUTE_V6_IN
524 || j
== DISTRIBUTE_V6_OUT
;
526 " %sdistribute-list %s %s %s\n",
529 output
? "out" : "in",
530 dist
->ifname
? dist
->ifname
535 for (j
= 0; j
< DISTRIBUTE_MAX
; j
++)
536 if (dist
->prefix
[j
]) {
537 output
= j
== DISTRIBUTE_V4_OUT
538 || j
== DISTRIBUTE_V6_OUT
;
539 v6
= j
== DISTRIBUTE_V6_IN
540 || j
== DISTRIBUTE_V6_OUT
;
542 " %sdistribute-list prefix %s %s %s\n",
545 output
? "out" : "in",
546 dist
->ifname
? dist
->ifname
554 void distribute_list_delete(struct distribute_ctx
**ctx
)
556 if ((*ctx
)->disthash
) {
557 hash_clean((*ctx
)->disthash
, (void (*)(void *))distribute_free
);
560 dist_ctx_list
= list_new();
561 listnode_delete(dist_ctx_list
, *ctx
);
562 if (list_isempty(dist_ctx_list
))
563 list_delete(&dist_ctx_list
);
564 XFREE(MTYPE_DISTRIBUTE_CTX
, (*ctx
));
567 /* Initialize distribute list container */
568 struct distribute_ctx
*distribute_list_ctx_create(struct vrf
*vrf
)
570 struct distribute_ctx
*ctx
;
572 ctx
= XCALLOC(MTYPE_DISTRIBUTE_CTX
, sizeof(struct distribute_ctx
));
574 ctx
->disthash
= hash_create(
575 distribute_hash_make
,
576 (bool (*)(const void *, const void *))distribute_cmp
, NULL
);
578 dist_ctx_list
= list_new();
579 listnode_add(dist_ctx_list
, ctx
);
583 /* Initialize distribute list vty commands */
584 void distribute_list_init(int node
)
586 /* vtysh command-extraction doesn't grok install_element(node, ) */
587 if (node
== RIP_NODE
) {
588 install_element(RIP_NODE
, &distribute_list_cmd
);
589 install_element(RIP_NODE
, &no_distribute_list_cmd
);
590 } else if (node
== RIPNG_NODE
) {
591 install_element(RIPNG_NODE
, &distribute_list_cmd
);
592 install_element(RIPNG_NODE
, &no_distribute_list_cmd
);
594 install_element(RIPNG_NODE
, &ipv6_distribute_list_cmd
);
595 install_element(RIPNG_NODE
, &no_ipv6_distribute_list_cmd
);
598 /* TODO: install v4 syntax command for v6 only protocols. */
599 /* if (node == RIPNG_NODE) {
600 * install_element (node, &ipv6_as_v4_distribute_list_all_cmd);
601 * install_element (node, &no_ipv6_as_v4_distribute_list_all_cmd);
602 * install_element (node, &ipv6_as_v4_distribute_list_cmd);
603 * install_element (node, &no_ipv6_as_v4_distribute_list_cmd);
604 * install_element (node, &ipv6_as_v4_distribute_list_prefix_all_cmd);
605 * install_element (node,
606 &no_ipv6_as_v4_distribute_list_prefix_all_cmd);
607 * install_element (node, &ipv6_as_v4_distribute_list_prefix_cmd);
608 * install_element (node, &no_ipv6_as_v4_distribute_list_prefix_cmd);