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