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 static enum distribute_type
distribute_direction(const char *dir
, bool v4
)
247 return DISTRIBUTE_V4_IN
;
249 return DISTRIBUTE_V6_IN
;
250 } else if (dir
[0] == 'o') {
252 return DISTRIBUTE_V4_OUT
;
254 return DISTRIBUTE_V6_OUT
;
257 assert(!"Expecting in or out only, fix your code");
259 __builtin_unreachable();
262 int distribute_list_parser(bool prefix
, bool v4
, const char *dir
,
263 const char *list
, const char *ifname
)
265 enum distribute_type type
= distribute_direction(dir
, v4
);
266 struct distribute_ctx
*ctx
= listnode_head(dist_ctx_list
);
268 void (*distfn
)(struct distribute_ctx
*, const char *,
269 enum distribute_type
, const char *) =
270 prefix
? &distribute_list_prefix_set
: &distribute_list_set
;
272 distfn(ctx
, ifname
, type
, list
);
277 int distribute_list_no_parser(struct vty
*vty
, bool prefix
, bool v4
,
278 const char *dir
, const char *list
,
281 enum distribute_type type
= distribute_direction(dir
, v4
);
282 struct distribute_ctx
*ctx
= listnode_head(dist_ctx_list
);
285 int (*distfn
)(struct distribute_ctx
*, const char *,
286 enum distribute_type
, const char *) =
287 prefix
? &distribute_list_prefix_unset
: &distribute_list_unset
;
290 ret
= distfn(ctx
, ifname
, type
, list
);
292 vty_out(vty
, "distribute list doesn't exist\n");
293 return CMD_WARNING_CONFIG_FAILED
;
299 static int distribute_print(struct vty
*vty
, char *tab
[], int is_prefix
,
300 enum distribute_type type
, int has_print
)
303 vty_out(vty
, "%s %s%s", has_print
? "," : "",
304 is_prefix
? "(prefix-list) " : "", tab
[type
]);
310 int config_show_distribute(struct vty
*vty
, struct distribute_ctx
*dist_ctxt
)
314 struct hash_bucket
*mp
;
315 struct distribute
*dist
;
317 /* Output filter configuration. */
318 dist
= distribute_lookup(dist_ctxt
, NULL
);
319 vty_out(vty
, " Outgoing update filter list for all interface is");
322 has_print
= distribute_print(vty
, dist
->list
, 0,
323 DISTRIBUTE_V4_OUT
, has_print
);
324 has_print
= distribute_print(vty
, dist
->prefix
, 1,
325 DISTRIBUTE_V4_OUT
, has_print
);
326 has_print
= distribute_print(vty
, dist
->list
, 0,
327 DISTRIBUTE_V6_OUT
, has_print
);
328 has_print
= distribute_print(vty
, dist
->prefix
, 1,
329 DISTRIBUTE_V6_OUT
, has_print
);
334 vty_out(vty
, " not set\n");
336 for (i
= 0; i
< dist_ctxt
->disthash
->size
; i
++)
337 for (mp
= dist_ctxt
->disthash
->index
[i
]; mp
; mp
= mp
->next
) {
340 vty_out(vty
, " %s filtered by",
343 has_print
= distribute_print(vty
, dist
->list
, 0,
346 has_print
= distribute_print(
347 vty
, dist
->prefix
, 1, DISTRIBUTE_V4_OUT
,
349 has_print
= distribute_print(vty
, dist
->list
, 0,
352 has_print
= distribute_print(
353 vty
, dist
->prefix
, 1, DISTRIBUTE_V6_OUT
,
358 vty_out(vty
, " nothing\n");
363 /* Input filter configuration. */
364 dist
= distribute_lookup(dist_ctxt
, NULL
);
365 vty_out(vty
, " Incoming update filter list for all interface is");
368 has_print
= distribute_print(vty
, dist
->list
, 0,
369 DISTRIBUTE_V4_IN
, has_print
);
370 has_print
= distribute_print(vty
, dist
->prefix
, 1,
371 DISTRIBUTE_V4_IN
, has_print
);
372 has_print
= distribute_print(vty
, dist
->list
, 0,
373 DISTRIBUTE_V6_IN
, has_print
);
374 has_print
= distribute_print(vty
, dist
->prefix
, 1,
375 DISTRIBUTE_V6_IN
, has_print
);
380 vty_out(vty
, " not set\n");
382 for (i
= 0; i
< dist_ctxt
->disthash
->size
; i
++)
383 for (mp
= dist_ctxt
->disthash
->index
[i
]; mp
; mp
= mp
->next
) {
386 vty_out(vty
, " %s filtered by",
389 has_print
= distribute_print(vty
, dist
->list
, 0,
392 has_print
= distribute_print(
393 vty
, dist
->prefix
, 1, DISTRIBUTE_V4_IN
,
395 has_print
= distribute_print(vty
, dist
->list
, 0,
398 has_print
= distribute_print(
399 vty
, dist
->prefix
, 1, DISTRIBUTE_V6_IN
,
404 vty_out(vty
, " nothing\n");
410 /* Configuration write function. */
411 int config_write_distribute(struct vty
*vty
,
412 struct distribute_ctx
*dist_ctxt
)
417 struct hash_bucket
*mp
;
420 for (i
= 0; i
< dist_ctxt
->disthash
->size
; i
++)
421 for (mp
= dist_ctxt
->disthash
->index
[i
]; mp
; mp
= mp
->next
) {
422 struct distribute
*dist
;
426 for (j
= 0; j
< DISTRIBUTE_MAX
; j
++)
428 output
= j
== DISTRIBUTE_V4_OUT
429 || j
== DISTRIBUTE_V6_OUT
;
430 v6
= j
== DISTRIBUTE_V6_IN
431 || j
== DISTRIBUTE_V6_OUT
;
433 " %sdistribute-list %s %s %s\n",
436 output
? "out" : "in",
437 dist
->ifname
? dist
->ifname
442 for (j
= 0; j
< DISTRIBUTE_MAX
; j
++)
443 if (dist
->prefix
[j
]) {
444 output
= j
== DISTRIBUTE_V4_OUT
445 || j
== DISTRIBUTE_V6_OUT
;
446 v6
= j
== DISTRIBUTE_V6_IN
447 || j
== DISTRIBUTE_V6_OUT
;
449 " %sdistribute-list prefix %s %s %s\n",
452 output
? "out" : "in",
453 dist
->ifname
? dist
->ifname
461 void distribute_list_delete(struct distribute_ctx
**ctx
)
463 if ((*ctx
)->disthash
) {
464 hash_clean((*ctx
)->disthash
, (void (*)(void *))distribute_free
);
467 dist_ctx_list
= list_new();
468 listnode_delete(dist_ctx_list
, *ctx
);
469 if (list_isempty(dist_ctx_list
))
470 list_delete(&dist_ctx_list
);
471 XFREE(MTYPE_DISTRIBUTE_CTX
, (*ctx
));
474 /* Initialize distribute list container */
475 struct distribute_ctx
*distribute_list_ctx_create(struct vrf
*vrf
)
477 struct distribute_ctx
*ctx
;
479 ctx
= XCALLOC(MTYPE_DISTRIBUTE_CTX
, sizeof(struct distribute_ctx
));
481 ctx
->disthash
= hash_create(
482 distribute_hash_make
,
483 (bool (*)(const void *, const void *))distribute_cmp
, NULL
);
485 dist_ctx_list
= list_new();
486 listnode_add(dist_ctx_list
, ctx
);