]> git.proxmox.com Git - mirror_frr.git/blob - lib/distribute.c
lib: enforce vrf_name_to_id by returning default_vrf when name is null
[mirror_frr.git] / lib / distribute.c
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 DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE, "Distribute list")
31 DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_IFNAME, "Dist-list ifname")
32 DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_NAME, "Dist-list name")
33
34 /* Hash of distribute list. */
35 struct hash *disthash;
36
37 /* Hook functions. */
38 void (*distribute_add_hook)(struct distribute *);
39 void (*distribute_delete_hook)(struct distribute *);
40
41 static struct distribute *distribute_new(void)
42 {
43 return XCALLOC(MTYPE_DISTRIBUTE, sizeof(struct distribute));
44 }
45
46 /* Free distribute object. */
47 static void distribute_free(struct distribute *dist)
48 {
49 int i = 0;
50
51 if (dist->ifname)
52 XFREE(MTYPE_DISTRIBUTE_IFNAME, dist->ifname);
53
54 for (i = 0; i < DISTRIBUTE_MAX; i++)
55 if (dist->list[i])
56 XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[i]);
57
58 for (i = 0; i < DISTRIBUTE_MAX; i++)
59 if (dist->prefix[i])
60 XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[i]);
61
62 XFREE(MTYPE_DISTRIBUTE, dist);
63 }
64
65 static void distribute_free_if_empty(struct distribute *dist)
66 {
67 int i;
68
69 for (i = 0; i < DISTRIBUTE_MAX; i++)
70 if (dist->list[i] != NULL || dist->prefix[i] != NULL)
71 return;
72
73 hash_release(disthash, dist);
74 distribute_free(dist);
75 }
76
77 /* Lookup interface's distribute list. */
78 struct distribute *distribute_lookup(const char *ifname)
79 {
80 struct distribute key;
81 struct distribute *dist;
82
83 /* temporary reference */
84 key.ifname = (ifname) ? XSTRDUP(MTYPE_DISTRIBUTE_IFNAME, ifname) : NULL;
85
86 dist = hash_lookup(disthash, &key);
87
88 if (key.ifname)
89 XFREE(MTYPE_DISTRIBUTE_IFNAME, key.ifname);
90
91 return dist;
92 }
93
94 void distribute_list_add_hook(void (*func)(struct distribute *))
95 {
96 distribute_add_hook = func;
97 }
98
99 void distribute_list_delete_hook(void (*func)(struct distribute *))
100 {
101 distribute_delete_hook = func;
102 }
103
104 static void *distribute_hash_alloc(struct distribute *arg)
105 {
106 struct distribute *dist;
107
108 dist = distribute_new();
109 if (arg->ifname)
110 dist->ifname = XSTRDUP(MTYPE_DISTRIBUTE_IFNAME, arg->ifname);
111 else
112 dist->ifname = NULL;
113 return dist;
114 }
115
116 /* Make new distribute list and push into hash. */
117 static struct distribute *distribute_get(const char *ifname)
118 {
119 struct distribute key;
120 struct distribute *ret;
121
122 /* temporary reference */
123 key.ifname = (ifname) ? XSTRDUP(MTYPE_DISTRIBUTE_IFNAME, ifname) : NULL;
124
125 ret = hash_get(disthash, &key,
126 (void *(*)(void *))distribute_hash_alloc);
127
128 if (key.ifname)
129 XFREE(MTYPE_DISTRIBUTE_IFNAME, key.ifname);
130
131 return ret;
132 }
133
134 static unsigned int distribute_hash_make(void *arg)
135 {
136 const struct distribute *dist = arg;
137
138 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 static bool distribute_cmp(const struct distribute *dist1,
144 const struct distribute *dist2)
145 {
146 if (dist1->ifname && dist2->ifname)
147 if (strcmp(dist1->ifname, dist2->ifname) == 0)
148 return true;
149 if (!dist1->ifname && !dist2->ifname)
150 return true;
151 return false;
152 }
153
154 /* Set access-list name to the distribute list. */
155 static void distribute_list_set(const char *ifname, enum distribute_type type,
156 const char *alist_name)
157 {
158 struct distribute *dist;
159
160 dist = distribute_get(ifname);
161
162 if (dist->list[type])
163 XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[type]);
164 dist->list[type] = XSTRDUP(MTYPE_DISTRIBUTE_NAME, alist_name);
165
166 /* Apply this distribute-list to the interface. */
167 (*distribute_add_hook)(dist);
168 }
169
170 /* Unset distribute-list. If matched distribute-list exist then
171 return 1. */
172 static int distribute_list_unset(const char *ifname, enum distribute_type type,
173 const char *alist_name)
174 {
175 struct distribute *dist;
176
177 dist = distribute_lookup(ifname);
178 if (!dist)
179 return 0;
180
181 if (!dist->list[type])
182 return 0;
183 if (strcmp(dist->list[type], alist_name) != 0)
184 return 0;
185
186 XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[type]);
187 dist->list[type] = NULL;
188
189 /* Apply this distribute-list to the interface. */
190 (*distribute_delete_hook)(dist);
191
192 /* If all dist are NULL, then free distribute list. */
193 distribute_free_if_empty(dist);
194 return 1;
195 }
196
197 /* Set access-list name to the distribute list. */
198 static void distribute_list_prefix_set(const char *ifname,
199 enum distribute_type type,
200 const char *plist_name)
201 {
202 struct distribute *dist;
203
204 dist = distribute_get(ifname);
205
206 if (dist->prefix[type])
207 XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[type]);
208 dist->prefix[type] = XSTRDUP(MTYPE_DISTRIBUTE_NAME, plist_name);
209
210 /* Apply this distribute-list to the interface. */
211 (*distribute_add_hook)(dist);
212 }
213
214 /* Unset distribute-list. If matched distribute-list exist then
215 return 1. */
216 static int distribute_list_prefix_unset(const char *ifname,
217 enum distribute_type type,
218 const char *plist_name)
219 {
220 struct distribute *dist;
221
222 dist = distribute_lookup(ifname);
223 if (!dist)
224 return 0;
225
226 if (!dist->prefix[type])
227 return 0;
228 if (strcmp(dist->prefix[type], plist_name) != 0)
229 return 0;
230
231 XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[type]);
232 dist->prefix[type] = NULL;
233
234 /* Apply this distribute-list to the interface. */
235 (*distribute_delete_hook)(dist);
236
237 /* If all dist are NULL, then free distribute list. */
238 distribute_free_if_empty(dist);
239 return 1;
240 }
241
242 DEFUN (distribute_list,
243 distribute_list_cmd,
244 "distribute-list [prefix] WORD <in|out> [WORD]",
245 "Filter networks in routing updates\n"
246 "Specify a prefix\n"
247 "Access-list name\n"
248 "Filter incoming routing updates\n"
249 "Filter outgoing routing updates\n"
250 "Interface name\n")
251 {
252 int prefix = (argv[1]->type == WORD_TKN) ? 1 : 0;
253
254 /* Check of distribute list type. */
255 enum distribute_type type = argv[2 + prefix]->arg[0] == 'i'
256 ? DISTRIBUTE_V4_IN
257 : DISTRIBUTE_V4_OUT;
258
259 /* Set appropriate function call */
260 void (*distfn)(const char *, enum distribute_type, const char *) =
261 prefix ? &distribute_list_prefix_set : &distribute_list_set;
262
263 /* if interface is present, get name */
264 const char *ifname = NULL;
265 if (argv[argc - 1]->type == VARIABLE_TKN)
266 ifname = argv[argc - 1]->arg;
267
268 /* Get interface name corresponding distribute list. */
269 distfn(ifname, type, argv[1 + prefix]->arg);
270
271 return CMD_SUCCESS;
272 }
273
274 DEFUN (ipv6_distribute_list,
275 ipv6_distribute_list_cmd,
276 "ipv6 distribute-list [prefix] WORD <in|out> [WORD]",
277 "IPv6\n"
278 "Filter networks in routing updates\n"
279 "Specify a prefix\n"
280 "Access-list name\n"
281 "Filter incoming routing updates\n"
282 "Filter outgoing routing updates\n"
283 "Interface name\n")
284 {
285 int prefix = (argv[2]->type == WORD_TKN) ? 1 : 0;
286
287 /* Check of distribute list type. */
288 enum distribute_type type = argv[3 + prefix]->arg[0] == 'i'
289 ? DISTRIBUTE_V6_IN
290 : DISTRIBUTE_V6_OUT;
291
292 /* Set appropriate function call */
293 void (*distfn)(const char *, enum distribute_type, const char *) =
294 prefix ? &distribute_list_prefix_set : &distribute_list_set;
295
296 /* if interface is present, get name */
297 const char *ifname = NULL;
298 if (argv[argc - 1]->type == VARIABLE_TKN)
299 ifname = argv[argc - 1]->arg;
300
301 /* Get interface name corresponding distribute list. */
302 distfn(ifname, type, argv[2 + prefix]->arg);
303
304 return CMD_SUCCESS;
305 }
306
307 DEFUN (no_distribute_list,
308 no_distribute_list_cmd,
309 "no distribute-list [prefix] WORD <in|out> [WORD]",
310 NO_STR
311 "Filter networks in routing updates\n"
312 "Specify a prefix\n"
313 "Access-list name\n"
314 "Filter incoming routing updates\n"
315 "Filter outgoing routing updates\n"
316 "Interface name\n")
317 {
318 int prefix = (argv[2]->type == WORD_TKN) ? 1 : 0;
319
320 int idx_alname = 2 + prefix;
321 int idx_disttype = idx_alname + 1;
322 enum distribute_type type =
323 argv[idx_disttype]->arg[0] == 'i' ?
324 DISTRIBUTE_V4_IN : DISTRIBUTE_V4_OUT;
325
326 /* Set appropriate function call */
327 int (*distfn)(const char *, enum distribute_type,
328 const char *) =
329 prefix ? &distribute_list_prefix_unset : &distribute_list_unset;
330
331 /* if interface is present, get name */
332 const char *ifname = NULL;
333 if (argv[argc - 1]->type == VARIABLE_TKN)
334 ifname = argv[argc - 1]->arg;
335 /* Get interface name corresponding distribute list. */
336 int ret = distfn(ifname, type, argv[2 + prefix]->arg);
337
338 if (!ret) {
339 vty_out(vty, "distribute list doesn't exist\n");
340 return CMD_WARNING_CONFIG_FAILED;
341 }
342 return CMD_SUCCESS;
343 }
344
345 DEFUN (no_ipv6_distribute_list,
346 no_ipv6_distribute_list_cmd,
347 "no ipv6 distribute-list [prefix] WORD <in|out> [WORD]",
348 NO_STR
349 "IPv6\n"
350 "Filter networks in routing updates\n"
351 "Specify a prefix\n"
352 "Access-list name\n"
353 "Filter incoming routing updates\n"
354 "Filter outgoing routing updates\n"
355 "Interface name\n")
356 {
357 int prefix = (argv[3]->type == WORD_TKN) ? 1 : 0;
358
359 int idx_alname = 3 + prefix;
360 int idx_disttype = idx_alname + 1;
361
362 enum distribute_type type =
363 argv[idx_disttype]->arg[0] == 'i' ?
364 DISTRIBUTE_V6_IN : DISTRIBUTE_V6_OUT;
365
366 /* Set appropriate function call */
367 int (*distfn)(const char *, enum distribute_type, const char *) =
368 prefix ? &distribute_list_prefix_unset : &distribute_list_unset;
369
370 /* if interface is present, get name */
371 const char *ifname = NULL;
372
373 if (argv[argc - 1]->type == VARIABLE_TKN)
374 ifname = argv[argc - 1]->arg;
375 /* Get interface name corresponding distribute list. */
376 int ret = distfn(ifname, type, argv[3 + prefix]->arg);
377
378 if (!ret) {
379 vty_out(vty, "distribute list doesn't exist\n");
380 return CMD_WARNING_CONFIG_FAILED;
381 }
382 return CMD_SUCCESS;
383 }
384
385 static int distribute_print(struct vty *vty, char *tab[], int is_prefix,
386 enum distribute_type type, int has_print)
387 {
388 if (tab[type]) {
389 vty_out(vty, "%s %s%s", has_print ? "," : "",
390 is_prefix ? "(prefix-list) " : "", tab[type]);
391 return 1;
392 }
393 return has_print;
394 }
395
396 int config_show_distribute(struct vty *vty)
397 {
398 unsigned int i;
399 int has_print = 0;
400 struct hash_backet *mp;
401 struct distribute *dist;
402
403 /* Output filter configuration. */
404 dist = distribute_lookup(NULL);
405 vty_out(vty, " Outgoing update filter list for all interface is");
406 has_print = 0;
407 if (dist) {
408 has_print = distribute_print(vty, dist->list, 0,
409 DISTRIBUTE_V4_OUT, has_print);
410 has_print = distribute_print(vty, dist->prefix, 1,
411 DISTRIBUTE_V4_OUT, has_print);
412 has_print = distribute_print(vty, dist->list, 0,
413 DISTRIBUTE_V6_OUT, has_print);
414 has_print = distribute_print(vty, dist->prefix, 1,
415 DISTRIBUTE_V6_OUT, has_print);
416 }
417 if (has_print)
418 vty_out(vty, "\n");
419 else
420 vty_out(vty, " not set\n");
421
422 for (i = 0; i < disthash->size; i++)
423 for (mp = disthash->index[i]; mp; mp = mp->next) {
424 dist = mp->data;
425 if (dist->ifname) {
426 vty_out(vty, " %s filtered by",
427 dist->ifname);
428 has_print = 0;
429 has_print = distribute_print(vty, dist->list, 0,
430 DISTRIBUTE_V4_OUT,
431 has_print);
432 has_print = distribute_print(
433 vty, dist->prefix, 1, DISTRIBUTE_V4_OUT,
434 has_print);
435 has_print = distribute_print(vty, dist->list, 0,
436 DISTRIBUTE_V6_OUT,
437 has_print);
438 has_print = distribute_print(
439 vty, dist->prefix, 1, DISTRIBUTE_V6_OUT,
440 has_print);
441 if (has_print)
442 vty_out(vty, "\n");
443 else
444 vty_out(vty, " nothing\n");
445 }
446 }
447
448
449 /* Input filter configuration. */
450 dist = distribute_lookup(NULL);
451 vty_out(vty, " Incoming update filter list for all interface is");
452 has_print = 0;
453 if (dist) {
454 has_print = distribute_print(vty, dist->list, 0,
455 DISTRIBUTE_V4_IN, has_print);
456 has_print = distribute_print(vty, dist->prefix, 1,
457 DISTRIBUTE_V4_IN, has_print);
458 has_print = distribute_print(vty, dist->list, 0,
459 DISTRIBUTE_V6_IN, has_print);
460 has_print = distribute_print(vty, dist->prefix, 1,
461 DISTRIBUTE_V6_IN, has_print);
462 }
463 if (has_print)
464 vty_out(vty, "\n");
465 else
466 vty_out(vty, " not set\n");
467
468 for (i = 0; i < disthash->size; i++)
469 for (mp = disthash->index[i]; mp; mp = mp->next) {
470 dist = mp->data;
471 if (dist->ifname) {
472 vty_out(vty, " %s filtered by",
473 dist->ifname);
474 has_print = 0;
475 has_print = distribute_print(vty, dist->list, 0,
476 DISTRIBUTE_V4_IN,
477 has_print);
478 has_print = distribute_print(
479 vty, dist->prefix, 1, DISTRIBUTE_V4_IN,
480 has_print);
481 has_print = distribute_print(vty, dist->list, 0,
482 DISTRIBUTE_V6_IN,
483 has_print);
484 has_print = distribute_print(
485 vty, dist->prefix, 1, DISTRIBUTE_V6_IN,
486 has_print);
487 if (has_print)
488 vty_out(vty, "\n");
489 else
490 vty_out(vty, " nothing\n");
491 }
492 }
493 return 0;
494 }
495
496 /* Configuration write function. */
497 int config_write_distribute(struct vty *vty)
498 {
499 unsigned int i;
500 int j;
501 int output, v6;
502 struct hash_backet *mp;
503 int write = 0;
504
505 for (i = 0; i < disthash->size; i++)
506 for (mp = disthash->index[i]; mp; mp = mp->next) {
507 struct distribute *dist;
508
509 dist = mp->data;
510
511 for (j = 0; j < DISTRIBUTE_MAX; j++)
512 if (dist->list[j]) {
513 output = j == DISTRIBUTE_V4_OUT
514 || j == DISTRIBUTE_V6_OUT;
515 v6 = j == DISTRIBUTE_V6_IN
516 || j == DISTRIBUTE_V6_OUT;
517 vty_out(vty,
518 " %sdistribute-list %s %s %s\n",
519 v6 ? "ipv6 " : "",
520 dist->list[j],
521 output ? "out" : "in",
522 dist->ifname ? dist->ifname
523 : "");
524 write++;
525 }
526
527 for (j = 0; j < DISTRIBUTE_MAX; j++)
528 if (dist->prefix[j]) {
529 output = j == DISTRIBUTE_V4_OUT
530 || j == DISTRIBUTE_V6_OUT;
531 v6 = j == DISTRIBUTE_V6_IN
532 || j == DISTRIBUTE_V6_OUT;
533 vty_out(vty,
534 " %sdistribute-list prefix %s %s %s\n",
535 v6 ? "ipv6 " : "",
536 dist->prefix[j],
537 output ? "out" : "in",
538 dist->ifname ? dist->ifname
539 : "");
540 write++;
541 }
542 }
543 return write;
544 }
545
546 /* Clear all distribute list. */
547 void distribute_list_reset()
548 {
549 hash_clean(disthash, (void (*)(void *))distribute_free);
550 }
551
552 /* Initialize distribute list related hash. */
553 void distribute_list_init(int node)
554 {
555 disthash = hash_create(
556 distribute_hash_make,
557 (bool (*)(const void *, const void *))distribute_cmp, NULL);
558
559 /* vtysh command-extraction doesn't grok install_element(node, ) */
560 if (node == RIP_NODE) {
561 install_element(RIP_NODE, &distribute_list_cmd);
562 install_element(RIP_NODE, &no_distribute_list_cmd);
563 } else if (node == RIPNG_NODE) {
564 install_element(RIPNG_NODE, &distribute_list_cmd);
565 install_element(RIPNG_NODE, &no_distribute_list_cmd);
566 }
567
568 /* install v6 */
569 if (node == RIPNG_NODE) {
570 install_element(RIPNG_NODE, &ipv6_distribute_list_cmd);
571 install_element(RIPNG_NODE, &no_ipv6_distribute_list_cmd);
572 }
573
574 /* TODO: install v4 syntax command for v6 only protocols. */
575 /* if (node == RIPNG_NODE) {
576 * install_element (node, &ipv6_as_v4_distribute_list_all_cmd);
577 * install_element (node, &no_ipv6_as_v4_distribute_list_all_cmd);
578 * install_element (node, &ipv6_as_v4_distribute_list_cmd);
579 * install_element (node, &no_ipv6_as_v4_distribute_list_cmd);
580 * install_element (node, &ipv6_as_v4_distribute_list_prefix_all_cmd);
581 * install_element (node,
582 &no_ipv6_as_v4_distribute_list_prefix_all_cmd);
583 * install_element (node, &ipv6_as_v4_distribute_list_prefix_cmd);
584 * install_element (node, &no_ipv6_as_v4_distribute_list_prefix_cmd);
585 }*/
586 }