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