Line data Source code
1 : /* Distribute list functions
2 : * Copyright (C) 1998, 1999 Kunihiro Ishiguro
3 : *
4 : * This file is part of GNU Zebra.
5 : *
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.
10 : *
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.
15 : *
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
19 : */
20 :
21 : #include <zebra.h>
22 :
23 : #include "hash.h"
24 : #include "if.h"
25 : #include "filter.h"
26 : #include "command.h"
27 : #include "distribute.h"
28 : #include "memory.h"
29 :
30 18 : DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_CTX, "Distribute ctx");
31 18 : DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE, "Distribute list");
32 18 : DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_IFNAME, "Dist-list ifname");
33 18 : DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_NAME, "Dist-list name");
34 :
35 : static struct list *dist_ctx_list;
36 :
37 0 : static struct distribute *distribute_new(void)
38 : {
39 0 : return XCALLOC(MTYPE_DISTRIBUTE, sizeof(struct distribute));
40 : }
41 :
42 : /* Free distribute object. */
43 0 : static void distribute_free(struct distribute *dist)
44 : {
45 0 : int i = 0;
46 :
47 0 : XFREE(MTYPE_DISTRIBUTE_IFNAME, dist->ifname);
48 :
49 0 : for (i = 0; i < DISTRIBUTE_MAX; i++) {
50 0 : XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[i]);
51 : }
52 :
53 0 : for (i = 0; i < DISTRIBUTE_MAX; i++) {
54 0 : XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[i]);
55 : }
56 :
57 0 : XFREE(MTYPE_DISTRIBUTE, dist);
58 0 : }
59 :
60 0 : static void distribute_free_if_empty(struct distribute_ctx *ctx,
61 : struct distribute *dist)
62 : {
63 0 : int i;
64 :
65 0 : for (i = 0; i < DISTRIBUTE_MAX; i++)
66 0 : if (dist->list[i] != NULL || dist->prefix[i] != NULL)
67 : return;
68 :
69 0 : hash_release(ctx->disthash, dist);
70 0 : distribute_free(dist);
71 : }
72 :
73 : /* Lookup interface's distribute list. */
74 0 : struct distribute *distribute_lookup(struct distribute_ctx *ctx,
75 : const char *ifname)
76 : {
77 0 : struct distribute key;
78 0 : struct distribute *dist;
79 :
80 : /* temporary reference */
81 0 : key.ifname = (ifname) ? XSTRDUP(MTYPE_DISTRIBUTE_IFNAME, ifname) : NULL;
82 :
83 0 : dist = hash_lookup(ctx->disthash, &key);
84 :
85 0 : XFREE(MTYPE_DISTRIBUTE_IFNAME, key.ifname);
86 :
87 0 : return dist;
88 : }
89 :
90 0 : void distribute_list_add_hook(struct distribute_ctx *ctx,
91 : void (*func)(struct distribute_ctx *ctx,
92 : struct distribute *))
93 : {
94 0 : ctx->distribute_add_hook = func;
95 0 : }
96 :
97 0 : void distribute_list_delete_hook(struct distribute_ctx *ctx,
98 : void (*func)(struct distribute_ctx *ctx,
99 : struct distribute *))
100 : {
101 0 : ctx->distribute_delete_hook = func;
102 0 : }
103 :
104 0 : static void *distribute_hash_alloc(struct distribute *arg)
105 : {
106 0 : struct distribute *dist;
107 :
108 0 : dist = distribute_new();
109 0 : if (arg->ifname)
110 0 : dist->ifname = XSTRDUP(MTYPE_DISTRIBUTE_IFNAME, arg->ifname);
111 : else
112 0 : dist->ifname = NULL;
113 0 : return dist;
114 : }
115 :
116 : /* Make new distribute list and push into hash. */
117 0 : static struct distribute *distribute_get(struct distribute_ctx *ctx,
118 : const char *ifname)
119 : {
120 0 : struct distribute key;
121 0 : struct distribute *ret;
122 :
123 : /* temporary reference */
124 0 : key.ifname = (ifname) ? XSTRDUP(MTYPE_DISTRIBUTE_IFNAME, ifname) : NULL;
125 :
126 0 : ret = hash_get(ctx->disthash, &key,
127 : (void *(*)(void *))distribute_hash_alloc);
128 :
129 0 : XFREE(MTYPE_DISTRIBUTE_IFNAME, key.ifname);
130 :
131 0 : return ret;
132 : }
133 :
134 0 : static unsigned int distribute_hash_make(const void *arg)
135 : {
136 0 : const struct distribute *dist = arg;
137 :
138 0 : return dist->ifname ? string_hash_make(dist->ifname) : 0;
139 : }
140 :
141 : /* If two distribute-list have same value then return 1 else return
142 : 0. This function is used by hash package. */
143 0 : static bool distribute_cmp(const struct distribute *dist1,
144 : const struct distribute *dist2)
145 : {
146 0 : if (dist1->ifname && dist2->ifname)
147 0 : if (strcmp(dist1->ifname, dist2->ifname) == 0)
148 : return true;
149 0 : if (!dist1->ifname && !dist2->ifname)
150 0 : return true;
151 : return false;
152 : }
153 :
154 : /* Set access-list name to the distribute list. */
155 0 : static void distribute_list_set(struct distribute_ctx *ctx,
156 : const char *ifname, enum distribute_type type,
157 : const char *alist_name)
158 : {
159 0 : struct distribute *dist;
160 :
161 0 : dist = distribute_get(ctx, ifname);
162 :
163 0 : XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[type]);
164 0 : dist->list[type] = XSTRDUP(MTYPE_DISTRIBUTE_NAME, alist_name);
165 :
166 : /* Apply this distribute-list to the interface. */
167 0 : (ctx->distribute_add_hook)(ctx, dist);
168 0 : }
169 :
170 : /* Unset distribute-list. If matched distribute-list exist then
171 : return 1. */
172 0 : static int distribute_list_unset(struct distribute_ctx *ctx,
173 : const char *ifname,
174 : enum distribute_type type,
175 : const char *alist_name)
176 : {
177 0 : struct distribute *dist;
178 :
179 0 : dist = distribute_lookup(ctx, ifname);
180 0 : if (!dist)
181 : return 0;
182 :
183 0 : if (!dist->list[type])
184 : return 0;
185 0 : if (strcmp(dist->list[type], alist_name) != 0)
186 : return 0;
187 :
188 0 : XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[type]);
189 :
190 : /* Apply this distribute-list to the interface. */
191 0 : (ctx->distribute_delete_hook)(ctx, dist);
192 :
193 : /* If all dist are NULL, then free distribute list. */
194 0 : distribute_free_if_empty(ctx, dist);
195 0 : return 1;
196 : }
197 :
198 : /* Set access-list name to the distribute list. */
199 0 : static void distribute_list_prefix_set(struct distribute_ctx *ctx,
200 : const char *ifname,
201 : enum distribute_type type,
202 : const char *plist_name)
203 : {
204 0 : struct distribute *dist;
205 :
206 0 : dist = distribute_get(ctx, ifname);
207 :
208 0 : XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[type]);
209 0 : dist->prefix[type] = XSTRDUP(MTYPE_DISTRIBUTE_NAME, plist_name);
210 :
211 : /* Apply this distribute-list to the interface. */
212 0 : (ctx->distribute_add_hook)(ctx, dist);
213 0 : }
214 :
215 : /* Unset distribute-list. If matched distribute-list exist then
216 : return 1. */
217 0 : static int distribute_list_prefix_unset(struct distribute_ctx *ctx,
218 : const char *ifname,
219 : enum distribute_type type,
220 : const char *plist_name)
221 : {
222 0 : struct distribute *dist;
223 :
224 0 : dist = distribute_lookup(ctx, ifname);
225 0 : if (!dist)
226 : return 0;
227 :
228 0 : if (!dist->prefix[type])
229 : return 0;
230 0 : if (strcmp(dist->prefix[type], plist_name) != 0)
231 : return 0;
232 :
233 0 : XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[type]);
234 :
235 : /* Apply this distribute-list to the interface. */
236 0 : (ctx->distribute_delete_hook)(ctx, dist);
237 :
238 : /* If all dist are NULL, then free distribute list. */
239 0 : distribute_free_if_empty(ctx, dist);
240 0 : return 1;
241 : }
242 :
243 0 : static enum distribute_type distribute_direction(const char *dir, bool v4)
244 : {
245 0 : if (dir[0] == 'i') {
246 0 : if (v4)
247 : return DISTRIBUTE_V4_IN;
248 : else
249 0 : return DISTRIBUTE_V6_IN;
250 0 : } else if (dir[0] == 'o') {
251 0 : if (v4)
252 : return DISTRIBUTE_V4_OUT;
253 : else
254 0 : return DISTRIBUTE_V6_OUT;
255 : }
256 :
257 0 : assert(!"Expecting in or out only, fix your code");
258 :
259 : __builtin_unreachable();
260 : }
261 :
262 0 : int distribute_list_parser(bool prefix, bool v4, const char *dir,
263 : const char *list, const char *ifname)
264 : {
265 0 : enum distribute_type type = distribute_direction(dir, v4);
266 0 : struct distribute_ctx *ctx = listnode_head(dist_ctx_list);
267 :
268 0 : void (*distfn)(struct distribute_ctx *, const char *,
269 : enum distribute_type, const char *) =
270 0 : prefix ? &distribute_list_prefix_set : &distribute_list_set;
271 :
272 0 : distfn(ctx, ifname, type, list);
273 :
274 0 : return CMD_SUCCESS;
275 : }
276 :
277 0 : int distribute_list_no_parser(struct vty *vty, bool prefix, bool v4,
278 : const char *dir, const char *list,
279 : const char *ifname)
280 : {
281 0 : enum distribute_type type = distribute_direction(dir, v4);
282 0 : struct distribute_ctx *ctx = listnode_head(dist_ctx_list);
283 0 : int ret;
284 :
285 0 : int (*distfn)(struct distribute_ctx *, const char *,
286 : enum distribute_type, const char *) =
287 0 : prefix ? &distribute_list_prefix_unset : &distribute_list_unset;
288 :
289 :
290 0 : ret = distfn(ctx, ifname, type, list);
291 0 : if (!ret) {
292 0 : vty_out(vty, "distribute list doesn't exist\n");
293 0 : return CMD_WARNING_CONFIG_FAILED;
294 : }
295 :
296 : return CMD_SUCCESS;
297 : }
298 :
299 0 : static int distribute_print(struct vty *vty, char *tab[], int is_prefix,
300 : enum distribute_type type, int has_print)
301 : {
302 0 : if (tab[type]) {
303 0 : vty_out(vty, "%s %s%s", has_print ? "," : "",
304 : is_prefix ? "(prefix-list) " : "", tab[type]);
305 0 : return 1;
306 : }
307 : return has_print;
308 : }
309 :
310 0 : int config_show_distribute(struct vty *vty, struct distribute_ctx *dist_ctxt)
311 : {
312 0 : unsigned int i;
313 0 : int has_print = 0;
314 0 : struct hash_bucket *mp;
315 0 : struct distribute *dist;
316 :
317 : /* Output filter configuration. */
318 0 : dist = distribute_lookup(dist_ctxt, NULL);
319 0 : vty_out(vty, " Outgoing update filter list for all interface is");
320 0 : has_print = 0;
321 0 : if (dist) {
322 0 : has_print = distribute_print(vty, dist->list, 0,
323 : DISTRIBUTE_V4_OUT, has_print);
324 0 : has_print = distribute_print(vty, dist->prefix, 1,
325 : DISTRIBUTE_V4_OUT, has_print);
326 0 : has_print = distribute_print(vty, dist->list, 0,
327 : DISTRIBUTE_V6_OUT, has_print);
328 0 : has_print = distribute_print(vty, dist->prefix, 1,
329 : DISTRIBUTE_V6_OUT, has_print);
330 : }
331 0 : if (has_print)
332 0 : vty_out(vty, "\n");
333 : else
334 0 : vty_out(vty, " not set\n");
335 :
336 0 : for (i = 0; i < dist_ctxt->disthash->size; i++)
337 0 : for (mp = dist_ctxt->disthash->index[i]; mp; mp = mp->next) {
338 0 : dist = mp->data;
339 0 : if (dist->ifname) {
340 0 : vty_out(vty, " %s filtered by",
341 : dist->ifname);
342 0 : has_print = 0;
343 0 : has_print = distribute_print(vty, dist->list, 0,
344 : DISTRIBUTE_V4_OUT,
345 : has_print);
346 0 : has_print = distribute_print(
347 0 : vty, dist->prefix, 1, DISTRIBUTE_V4_OUT,
348 : has_print);
349 0 : has_print = distribute_print(vty, dist->list, 0,
350 : DISTRIBUTE_V6_OUT,
351 : has_print);
352 0 : has_print = distribute_print(
353 : vty, dist->prefix, 1, DISTRIBUTE_V6_OUT,
354 : has_print);
355 0 : if (has_print)
356 0 : vty_out(vty, "\n");
357 : else
358 0 : vty_out(vty, " nothing\n");
359 : }
360 : }
361 :
362 :
363 : /* Input filter configuration. */
364 0 : dist = distribute_lookup(dist_ctxt, NULL);
365 0 : vty_out(vty, " Incoming update filter list for all interface is");
366 0 : has_print = 0;
367 0 : if (dist) {
368 0 : has_print = distribute_print(vty, dist->list, 0,
369 : DISTRIBUTE_V4_IN, has_print);
370 0 : has_print = distribute_print(vty, dist->prefix, 1,
371 : DISTRIBUTE_V4_IN, has_print);
372 0 : has_print = distribute_print(vty, dist->list, 0,
373 : DISTRIBUTE_V6_IN, has_print);
374 0 : has_print = distribute_print(vty, dist->prefix, 1,
375 : DISTRIBUTE_V6_IN, has_print);
376 : }
377 0 : if (has_print)
378 0 : vty_out(vty, "\n");
379 : else
380 0 : vty_out(vty, " not set\n");
381 :
382 0 : for (i = 0; i < dist_ctxt->disthash->size; i++)
383 0 : for (mp = dist_ctxt->disthash->index[i]; mp; mp = mp->next) {
384 0 : dist = mp->data;
385 0 : if (dist->ifname) {
386 0 : vty_out(vty, " %s filtered by",
387 : dist->ifname);
388 0 : has_print = 0;
389 0 : has_print = distribute_print(vty, dist->list, 0,
390 : DISTRIBUTE_V4_IN,
391 : has_print);
392 0 : has_print = distribute_print(
393 0 : vty, dist->prefix, 1, DISTRIBUTE_V4_IN,
394 : has_print);
395 0 : has_print = distribute_print(vty, dist->list, 0,
396 : DISTRIBUTE_V6_IN,
397 : has_print);
398 0 : has_print = distribute_print(
399 : vty, dist->prefix, 1, DISTRIBUTE_V6_IN,
400 : has_print);
401 0 : if (has_print)
402 0 : vty_out(vty, "\n");
403 : else
404 0 : vty_out(vty, " nothing\n");
405 : }
406 : }
407 0 : return 0;
408 : }
409 :
410 : /* Configuration write function. */
411 0 : int config_write_distribute(struct vty *vty,
412 : struct distribute_ctx *dist_ctxt)
413 : {
414 0 : unsigned int i;
415 0 : int j;
416 0 : int output, v6;
417 0 : struct hash_bucket *mp;
418 0 : int write = 0;
419 :
420 0 : for (i = 0; i < dist_ctxt->disthash->size; i++)
421 0 : for (mp = dist_ctxt->disthash->index[i]; mp; mp = mp->next) {
422 0 : struct distribute *dist;
423 :
424 0 : dist = mp->data;
425 :
426 0 : for (j = 0; j < DISTRIBUTE_MAX; j++)
427 0 : if (dist->list[j]) {
428 0 : output = j == DISTRIBUTE_V4_OUT
429 0 : || j == DISTRIBUTE_V6_OUT;
430 0 : v6 = j == DISTRIBUTE_V6_IN
431 0 : || j == DISTRIBUTE_V6_OUT;
432 0 : vty_out(vty,
433 : " %sdistribute-list %s %s %s\n",
434 : v6 ? "ipv6 " : "",
435 : dist->list[j],
436 : output ? "out" : "in",
437 0 : dist->ifname ? dist->ifname
438 : : "");
439 0 : write++;
440 : }
441 :
442 0 : for (j = 0; j < DISTRIBUTE_MAX; j++)
443 0 : if (dist->prefix[j]) {
444 0 : output = j == DISTRIBUTE_V4_OUT
445 0 : || j == DISTRIBUTE_V6_OUT;
446 0 : v6 = j == DISTRIBUTE_V6_IN
447 0 : || j == DISTRIBUTE_V6_OUT;
448 0 : vty_out(vty,
449 : " %sdistribute-list prefix %s %s %s\n",
450 : v6 ? "ipv6 " : "",
451 : dist->prefix[j],
452 : output ? "out" : "in",
453 0 : dist->ifname ? dist->ifname
454 : : "");
455 0 : write++;
456 : }
457 : }
458 0 : return write;
459 : }
460 :
461 0 : void distribute_list_delete(struct distribute_ctx **ctx)
462 : {
463 0 : if ((*ctx)->disthash) {
464 0 : hash_clean((*ctx)->disthash, (void (*)(void *))distribute_free);
465 : }
466 0 : if (!dist_ctx_list)
467 0 : dist_ctx_list = list_new();
468 0 : listnode_delete(dist_ctx_list, *ctx);
469 0 : if (list_isempty(dist_ctx_list))
470 0 : list_delete(&dist_ctx_list);
471 0 : XFREE(MTYPE_DISTRIBUTE_CTX, (*ctx));
472 0 : }
473 :
474 : /* Initialize distribute list container */
475 0 : struct distribute_ctx *distribute_list_ctx_create(struct vrf *vrf)
476 : {
477 0 : struct distribute_ctx *ctx;
478 :
479 0 : ctx = XCALLOC(MTYPE_DISTRIBUTE_CTX, sizeof(struct distribute_ctx));
480 0 : ctx->vrf = vrf;
481 0 : ctx->disthash = hash_create(
482 : distribute_hash_make,
483 : (bool (*)(const void *, const void *))distribute_cmp, NULL);
484 0 : if (!dist_ctx_list)
485 0 : dist_ctx_list = list_new();
486 0 : listnode_add(dist_ctx_list, ctx);
487 0 : return ctx;
488 : }
|