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 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
)
48 XFREE(MTYPE_DISTRIBUTE_IFNAME
, dist
->ifname
);
50 for (i
= 0; i
< DISTRIBUTE_MAX
; i
++)
52 XFREE(MTYPE_DISTRIBUTE_NAME
, dist
->list
[i
]);
54 for (i
= 0; i
< DISTRIBUTE_MAX
; i
++)
56 XFREE(MTYPE_DISTRIBUTE_NAME
, dist
->prefix
[i
]);
58 XFREE(MTYPE_DISTRIBUTE
, dist
);
61 static void distribute_free_if_empty(struct distribute_ctx
*ctx
,
62 struct distribute
*dist
)
66 for (i
= 0; i
< DISTRIBUTE_MAX
; i
++)
67 if (dist
->list
[i
] != NULL
|| dist
->prefix
[i
] != NULL
)
70 hash_release(ctx
->disthash
, dist
);
71 distribute_free(dist
);
74 /* Lookup interface's distribute list. */
75 struct distribute
*distribute_lookup(struct distribute_ctx
*ctx
,
78 struct distribute key
;
79 struct distribute
*dist
;
81 /* temporary reference */
82 key
.ifname
= (ifname
) ? XSTRDUP(MTYPE_DISTRIBUTE_IFNAME
, ifname
) : NULL
;
84 dist
= hash_lookup(ctx
->disthash
, &key
);
87 XFREE(MTYPE_DISTRIBUTE_IFNAME
, key
.ifname
);
92 void distribute_list_add_hook(struct distribute_ctx
*ctx
,
93 void (*func
)(struct distribute_ctx
*ctx
,
96 ctx
->distribute_add_hook
= func
;
99 void distribute_list_delete_hook(struct distribute_ctx
*ctx
,
100 void (*func
)(struct distribute_ctx
*ctx
,
101 struct distribute
*))
103 ctx
->distribute_delete_hook
= func
;
106 static void *distribute_hash_alloc(struct distribute
*arg
)
108 struct distribute
*dist
;
110 dist
= distribute_new();
112 dist
->ifname
= XSTRDUP(MTYPE_DISTRIBUTE_IFNAME
, arg
->ifname
);
118 /* Make new distribute list and push into hash. */
119 static struct distribute
*distribute_get(struct distribute_ctx
*ctx
,
122 struct distribute key
;
123 struct distribute
*ret
;
125 /* temporary reference */
126 key
.ifname
= (ifname
) ? XSTRDUP(MTYPE_DISTRIBUTE_IFNAME
, ifname
) : NULL
;
128 ret
= hash_get(ctx
->disthash
, &key
,
129 (void *(*)(void *))distribute_hash_alloc
);
132 XFREE(MTYPE_DISTRIBUTE_IFNAME
, key
.ifname
);
137 static unsigned int distribute_hash_make(void *arg
)
139 const struct distribute
*dist
= arg
;
141 return dist
->ifname
? string_hash_make(dist
->ifname
) : 0;
144 /* If two distribute-list have same value then return 1 else return
145 0. This function is used by hash package. */
146 static bool distribute_cmp(const struct distribute
*dist1
,
147 const struct distribute
*dist2
)
149 if (dist1
->ifname
&& dist2
->ifname
)
150 if (strcmp(dist1
->ifname
, dist2
->ifname
) == 0)
152 if (!dist1
->ifname
&& !dist2
->ifname
)
157 /* Set access-list name to the distribute list. */
158 static void distribute_list_set(struct distribute_ctx
*ctx
,
159 const char *ifname
, enum distribute_type type
,
160 const char *alist_name
)
162 struct distribute
*dist
;
164 dist
= distribute_get(ctx
, ifname
);
166 if (dist
->list
[type
])
167 XFREE(MTYPE_DISTRIBUTE_NAME
, dist
->list
[type
]);
168 dist
->list
[type
] = XSTRDUP(MTYPE_DISTRIBUTE_NAME
, alist_name
);
170 /* Apply this distribute-list to the interface. */
171 (ctx
->distribute_add_hook
)(ctx
, dist
);
174 /* Unset distribute-list. If matched distribute-list exist then
176 static int distribute_list_unset(struct distribute_ctx
*ctx
,
178 enum distribute_type type
,
179 const char *alist_name
)
181 struct distribute
*dist
;
183 dist
= distribute_lookup(ctx
, ifname
);
187 if (!dist
->list
[type
])
189 if (strcmp(dist
->list
[type
], alist_name
) != 0)
192 XFREE(MTYPE_DISTRIBUTE_NAME
, dist
->list
[type
]);
193 dist
->list
[type
] = NULL
;
195 /* Apply this distribute-list to the interface. */
196 (ctx
->distribute_delete_hook
)(ctx
, dist
);
198 /* If all dist are NULL, then free distribute list. */
199 distribute_free_if_empty(ctx
, dist
);
203 /* Set access-list name to the distribute list. */
204 static void distribute_list_prefix_set(struct distribute_ctx
*ctx
,
206 enum distribute_type type
,
207 const char *plist_name
)
209 struct distribute
*dist
;
211 dist
= distribute_get(ctx
, ifname
);
213 if (dist
->prefix
[type
])
214 XFREE(MTYPE_DISTRIBUTE_NAME
, dist
->prefix
[type
]);
215 dist
->prefix
[type
] = XSTRDUP(MTYPE_DISTRIBUTE_NAME
, plist_name
);
217 /* Apply this distribute-list to the interface. */
218 (ctx
->distribute_add_hook
)(ctx
, dist
);
221 /* Unset distribute-list. If matched distribute-list exist then
223 static int distribute_list_prefix_unset(struct distribute_ctx
*ctx
,
225 enum distribute_type type
,
226 const char *plist_name
)
228 struct distribute
*dist
;
230 dist
= distribute_lookup(ctx
, ifname
);
234 if (!dist
->prefix
[type
])
236 if (strcmp(dist
->prefix
[type
], plist_name
) != 0)
239 XFREE(MTYPE_DISTRIBUTE_NAME
, dist
->prefix
[type
]);
240 dist
->prefix
[type
] = NULL
;
242 /* Apply this distribute-list to the interface. */
243 (ctx
->distribute_delete_hook
)(ctx
, dist
);
245 /* If all dist are NULL, then free distribute list. */
246 distribute_free_if_empty(ctx
, dist
);
250 DEFUN (distribute_list
,
252 "distribute-list [prefix] WORD <in|out> [WORD]",
253 "Filter networks in routing updates\n"
256 "Filter incoming routing updates\n"
257 "Filter outgoing routing updates\n"
260 int prefix
= (argv
[1]->type
== WORD_TKN
) ? 1 : 0;
261 /* Check of distribute list type. */
262 enum distribute_type type
= argv
[2 + prefix
]->arg
[0] == 'i'
266 /* Set appropriate function call */
267 void (*distfn
)(struct distribute_ctx
*, const char *,
268 enum distribute_type
, const char *) =
269 prefix
? &distribute_list_prefix_set
: &distribute_list_set
;
270 struct distribute_ctx
*ctx
=
271 (struct distribute_ctx
*)listnode_head(dist_ctx_list
);
273 /* if interface is present, get name */
274 const char *ifname
= NULL
;
275 if (argv
[argc
- 1]->type
== VARIABLE_TKN
)
276 ifname
= argv
[argc
- 1]->arg
;
278 /* Get interface name corresponding distribute list. */
279 distfn(ctx
, ifname
, type
, argv
[1 + prefix
]->arg
);
284 DEFUN (ipv6_distribute_list
,
285 ipv6_distribute_list_cmd
,
286 "ipv6 distribute-list [prefix] WORD <in|out> [WORD]",
288 "Filter networks in routing updates\n"
291 "Filter incoming routing updates\n"
292 "Filter outgoing routing updates\n"
295 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'
301 /* Set appropriate function call */
302 void (*distfn
)(struct distribute_ctx
*, const char *,
303 enum distribute_type
, const char *) =
304 prefix
? &distribute_list_prefix_set
: &distribute_list_set
;
305 struct distribute_ctx
*ctx
= listnode_head(dist_ctx_list
);
307 /* if interface is present, get name */
308 const char *ifname
= NULL
;
309 if (argv
[argc
- 1]->type
== VARIABLE_TKN
)
310 ifname
= argv
[argc
- 1]->arg
;
312 /* Get interface name corresponding distribute list. */
313 distfn(ctx
, ifname
, type
, argv
[2 + prefix
]->arg
);
318 DEFUN (no_distribute_list
,
319 no_distribute_list_cmd
,
320 "no distribute-list [prefix] WORD <in|out> [WORD]",
322 "Filter networks in routing updates\n"
325 "Filter incoming routing updates\n"
326 "Filter outgoing routing updates\n"
329 int prefix
= (argv
[2]->type
== WORD_TKN
) ? 1 : 0;
330 int idx_alname
= 2 + prefix
;
331 int idx_disttype
= idx_alname
+ 1;
332 enum distribute_type type
=
333 argv
[idx_disttype
]->arg
[0] == 'i' ?
334 DISTRIBUTE_V4_IN
: DISTRIBUTE_V4_OUT
;
336 /* Set appropriate function call */
337 int (*distfn
)(struct distribute_ctx
*, const char *,
338 enum distribute_type
, const char *) =
339 prefix
? &distribute_list_prefix_unset
: &distribute_list_unset
;
340 struct distribute_ctx
*ctx
= listnode_head(dist_ctx_list
);
342 /* if interface is present, get name */
343 const char *ifname
= NULL
;
344 if (argv
[argc
- 1]->type
== VARIABLE_TKN
)
345 ifname
= argv
[argc
- 1]->arg
;
346 /* Get interface name corresponding distribute list. */
347 int ret
= distfn(ctx
, ifname
, type
, argv
[2 + prefix
]->arg
);
350 vty_out(vty
, "distribute list doesn't exist\n");
351 return CMD_WARNING_CONFIG_FAILED
;
356 DEFUN (no_ipv6_distribute_list
,
357 no_ipv6_distribute_list_cmd
,
358 "no ipv6 distribute-list [prefix] WORD <in|out> [WORD]",
361 "Filter networks in routing updates\n"
364 "Filter incoming routing updates\n"
365 "Filter outgoing routing updates\n"
368 int prefix
= (argv
[3]->type
== WORD_TKN
) ? 1 : 0;
369 int idx_alname
= 3 + prefix
;
370 int idx_disttype
= idx_alname
+ 1;
372 enum distribute_type type
=
373 argv
[idx_disttype
]->arg
[0] == 'i' ?
374 DISTRIBUTE_V6_IN
: DISTRIBUTE_V6_OUT
;
375 struct distribute_ctx
*ctx
= listnode_head(dist_ctx_list
);
377 /* Set appropriate function call */
378 int (*distfn
)(struct distribute_ctx
*, const char *,
379 enum distribute_type
, const char *) =
380 prefix
? &distribute_list_prefix_unset
: &distribute_list_unset
;
382 /* if interface is present, get name */
383 const char *ifname
= NULL
;
385 if (argv
[argc
- 1]->type
== VARIABLE_TKN
)
386 ifname
= argv
[argc
- 1]->arg
;
387 /* Get interface name corresponding distribute list. */
388 int ret
= distfn(ctx
, ifname
, type
, argv
[3 + prefix
]->arg
);
391 vty_out(vty
, "distribute list doesn't exist\n");
392 return CMD_WARNING_CONFIG_FAILED
;
397 static int distribute_print(struct vty
*vty
, char *tab
[], int is_prefix
,
398 enum distribute_type type
, int has_print
)
401 vty_out(vty
, "%s %s%s", has_print
? "," : "",
402 is_prefix
? "(prefix-list) " : "", tab
[type
]);
408 int config_show_distribute(struct vty
*vty
, struct distribute_ctx
*dist_ctxt
)
412 struct hash_backet
*mp
;
413 struct distribute
*dist
;
415 /* Output filter configuration. */
416 dist
= distribute_lookup(dist_ctxt
, NULL
);
417 vty_out(vty
, " Outgoing update filter list for all interface is");
420 has_print
= distribute_print(vty
, dist
->list
, 0,
421 DISTRIBUTE_V4_OUT
, has_print
);
422 has_print
= distribute_print(vty
, dist
->prefix
, 1,
423 DISTRIBUTE_V4_OUT
, has_print
);
424 has_print
= distribute_print(vty
, dist
->list
, 0,
425 DISTRIBUTE_V6_OUT
, has_print
);
426 has_print
= distribute_print(vty
, dist
->prefix
, 1,
427 DISTRIBUTE_V6_OUT
, has_print
);
432 vty_out(vty
, " not set\n");
434 for (i
= 0; i
< dist_ctxt
->disthash
->size
; i
++)
435 for (mp
= dist_ctxt
->disthash
->index
[i
]; mp
; mp
= mp
->next
) {
438 vty_out(vty
, " %s filtered by",
441 has_print
= distribute_print(vty
, dist
->list
, 0,
444 has_print
= distribute_print(
445 vty
, dist
->prefix
, 1, DISTRIBUTE_V4_OUT
,
447 has_print
= distribute_print(vty
, dist
->list
, 0,
450 has_print
= distribute_print(
451 vty
, dist
->prefix
, 1, DISTRIBUTE_V6_OUT
,
456 vty_out(vty
, " nothing\n");
461 /* Input filter configuration. */
462 dist
= distribute_lookup(dist_ctxt
, NULL
);
463 vty_out(vty
, " Incoming update filter list for all interface is");
466 has_print
= distribute_print(vty
, dist
->list
, 0,
467 DISTRIBUTE_V4_IN
, has_print
);
468 has_print
= distribute_print(vty
, dist
->prefix
, 1,
469 DISTRIBUTE_V4_IN
, has_print
);
470 has_print
= distribute_print(vty
, dist
->list
, 0,
471 DISTRIBUTE_V6_IN
, has_print
);
472 has_print
= distribute_print(vty
, dist
->prefix
, 1,
473 DISTRIBUTE_V6_IN
, has_print
);
478 vty_out(vty
, " not set\n");
480 for (i
= 0; i
< dist_ctxt
->disthash
->size
; i
++)
481 for (mp
= dist_ctxt
->disthash
->index
[i
]; mp
; mp
= mp
->next
) {
484 vty_out(vty
, " %s filtered by",
487 has_print
= distribute_print(vty
, dist
->list
, 0,
490 has_print
= distribute_print(
491 vty
, dist
->prefix
, 1, DISTRIBUTE_V4_IN
,
493 has_print
= distribute_print(vty
, dist
->list
, 0,
496 has_print
= distribute_print(
497 vty
, dist
->prefix
, 1, DISTRIBUTE_V6_IN
,
502 vty_out(vty
, " nothing\n");
508 /* Configuration write function. */
509 int config_write_distribute(struct vty
*vty
,
510 struct distribute_ctx
*dist_ctxt
)
515 struct hash_backet
*mp
;
518 for (i
= 0; i
< dist_ctxt
->disthash
->size
; i
++)
519 for (mp
= dist_ctxt
->disthash
->index
[i
]; mp
; mp
= mp
->next
) {
520 struct distribute
*dist
;
524 for (j
= 0; j
< DISTRIBUTE_MAX
; j
++)
526 output
= j
== DISTRIBUTE_V4_OUT
527 || j
== DISTRIBUTE_V6_OUT
;
528 v6
= j
== DISTRIBUTE_V6_IN
529 || j
== DISTRIBUTE_V6_OUT
;
531 " %sdistribute-list %s %s %s\n",
534 output
? "out" : "in",
535 dist
->ifname
? dist
->ifname
540 for (j
= 0; j
< DISTRIBUTE_MAX
; j
++)
541 if (dist
->prefix
[j
]) {
542 output
= j
== DISTRIBUTE_V4_OUT
543 || j
== DISTRIBUTE_V6_OUT
;
544 v6
= j
== DISTRIBUTE_V6_IN
545 || j
== DISTRIBUTE_V6_OUT
;
547 " %sdistribute-list prefix %s %s %s\n",
550 output
? "out" : "in",
551 dist
->ifname
? dist
->ifname
559 void distribute_list_delete(struct distribute_ctx
**ctx
)
561 if ((*ctx
)->disthash
) {
562 hash_clean((*ctx
)->disthash
, (void (*)(void *))distribute_free
);
565 dist_ctx_list
= list_new();
566 listnode_delete(dist_ctx_list
, *ctx
);
567 if (list_isempty(dist_ctx_list
))
568 list_delete(&dist_ctx_list
);
569 XFREE(MTYPE_DISTRIBUTE_CTX
, (*ctx
));
572 /* Initialize distribute list container */
573 struct distribute_ctx
*distribute_list_ctx_create(struct vrf
*vrf
)
575 struct distribute_ctx
*ctx
;
577 ctx
= XCALLOC(MTYPE_DISTRIBUTE_CTX
, sizeof(struct distribute_ctx
));
579 ctx
->disthash
= hash_create(
580 distribute_hash_make
,
581 (bool (*)(const void *, const void *))distribute_cmp
, NULL
);
583 dist_ctx_list
= list_new();
584 listnode_add(dist_ctx_list
, ctx
);
588 /* Initialize distribute list vty commands */
589 void distribute_list_init(int node
)
591 /* vtysh command-extraction doesn't grok install_element(node, ) */
592 if (node
== RIP_NODE
) {
593 install_element(RIP_NODE
, &distribute_list_cmd
);
594 install_element(RIP_NODE
, &no_distribute_list_cmd
);
595 } else if (node
== RIPNG_NODE
) {
596 install_element(RIPNG_NODE
, &distribute_list_cmd
);
597 install_element(RIPNG_NODE
, &no_distribute_list_cmd
);
599 install_element(RIPNG_NODE
, &ipv6_distribute_list_cmd
);
600 install_element(RIPNG_NODE
, &no_ipv6_distribute_list_cmd
);
603 /* TODO: install v4 syntax command for v6 only protocols. */
604 /* if (node == RIPNG_NODE) {
605 * install_element (node, &ipv6_as_v4_distribute_list_all_cmd);
606 * install_element (node, &no_ipv6_as_v4_distribute_list_all_cmd);
607 * install_element (node, &ipv6_as_v4_distribute_list_cmd);
608 * install_element (node, &no_ipv6_as_v4_distribute_list_cmd);
609 * install_element (node, &ipv6_as_v4_distribute_list_prefix_all_cmd);
610 * install_element (node,
611 &no_ipv6_as_v4_distribute_list_prefix_all_cmd);
612 * install_element (node, &ipv6_as_v4_distribute_list_prefix_cmd);
613 * install_element (node, &no_ipv6_as_v4_distribute_list_prefix_cmd);