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