]> git.proxmox.com Git - mirror_frr.git/blame - lib/distribute.c
staticd: Do not ready prefix for printing till it's decoded
[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
d62a17ae 30DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE, "Distribute list")
4a1ab8e4 31DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_IFNAME, "Dist-list ifname")
d62a17ae 32DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_NAME, "Dist-list name")
4a1ab8e4 33
718e3744 34/* Hash of distribute list. */
35struct hash *disthash;
36
37/* Hook functions. */
d62a17ae 38void (*distribute_add_hook)(struct distribute *);
39void (*distribute_delete_hook)(struct distribute *);
6b0655a2 40
d62a17ae 41static struct distribute *distribute_new(void)
718e3744 42{
d62a17ae 43 return XCALLOC(MTYPE_DISTRIBUTE, sizeof(struct distribute));
718e3744 44}
45
46/* Free distribute object. */
d62a17ae 47static void distribute_free(struct distribute *dist)
718e3744 48{
d62a17ae 49 int i = 0;
ee5bb561 50
d62a17ae 51 if (dist->ifname)
52 XFREE(MTYPE_DISTRIBUTE_IFNAME, dist->ifname);
718e3744 53
d62a17ae 54 for (i = 0; i < DISTRIBUTE_MAX; i++)
55 if (dist->list[i])
56 XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[i]);
718e3744 57
d62a17ae 58 for (i = 0; i < DISTRIBUTE_MAX; i++)
59 if (dist->prefix[i])
60 XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[i]);
718e3744 61
d62a17ae 62 XFREE(MTYPE_DISTRIBUTE, dist);
718e3744 63}
64
d62a17ae 65static void distribute_free_if_empty(struct distribute *dist)
ee5bb561 66{
d62a17ae 67 int i;
ee5bb561 68
d62a17ae 69 for (i = 0; i < DISTRIBUTE_MAX; i++)
70 if (dist->list[i] != NULL || dist->prefix[i] != NULL)
71 return;
ee5bb561 72
d62a17ae 73 hash_release(disthash, dist);
74 distribute_free(dist);
ee5bb561
MB
75}
76
718e3744 77/* Lookup interface's distribute list. */
d62a17ae 78struct distribute *distribute_lookup(const char *ifname)
718e3744 79{
d62a17ae 80 struct distribute key;
81 struct distribute *dist;
718e3744 82
d62a17ae 83 /* temporary reference */
84 key.ifname = (ifname) ? XSTRDUP(MTYPE_DISTRIBUTE_IFNAME, ifname) : NULL;
718e3744 85
d62a17ae 86 dist = hash_lookup(disthash, &key);
3a7c85d1 87
d62a17ae 88 if (key.ifname)
89 XFREE(MTYPE_DISTRIBUTE_IFNAME, key.ifname);
24873f0c 90
d62a17ae 91 return dist;
718e3744 92}
93
d62a17ae 94void distribute_list_add_hook(void (*func)(struct distribute *))
718e3744 95{
d62a17ae 96 distribute_add_hook = func;
718e3744 97}
98
d62a17ae 99void distribute_list_delete_hook(void (*func)(struct distribute *))
718e3744 100{
d62a17ae 101 distribute_delete_hook = func;
718e3744 102}
103
d62a17ae 104static void *distribute_hash_alloc(struct distribute *arg)
718e3744 105{
d62a17ae 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;
718e3744 114}
115
116/* Make new distribute list and push into hash. */
d62a17ae 117static struct distribute *distribute_get(const char *ifname)
718e3744 118{
d62a17ae 119 struct distribute key;
120 struct distribute *ret;
121
122 /* temporary reference */
123 key.ifname = (ifname) ? XSTRDUP(MTYPE_DISTRIBUTE_IFNAME, ifname) : NULL;
718e3744 124
d62a17ae 125 ret = hash_get(disthash, &key,
126 (void *(*)(void *))distribute_hash_alloc);
24873f0c 127
d62a17ae 128 if (key.ifname)
129 XFREE(MTYPE_DISTRIBUTE_IFNAME, key.ifname);
3a7c85d1 130
d62a17ae 131 return ret;
718e3744 132}
133
d62a17ae 134static unsigned int distribute_hash_make(void *arg)
718e3744 135{
d62a17ae 136 const struct distribute *dist = arg;
718e3744 137
d62a17ae 138 return dist->ifname ? string_hash_make(dist->ifname) : 0;
718e3744 139}
140
141/* If two distribute-list have same value then return 1 else return
142 0. This function is used by hash package. */
74df8d6d 143static bool distribute_cmp(const struct distribute *dist1,
d62a17ae 144 const struct distribute *dist2)
718e3744 145{
d62a17ae 146 if (dist1->ifname && dist2->ifname)
147 if (strcmp(dist1->ifname, dist2->ifname) == 0)
74df8d6d 148 return true;
d62a17ae 149 if (!dist1->ifname && !dist2->ifname)
74df8d6d
DS
150 return true;
151 return false;
718e3744 152}
6b0655a2 153
718e3744 154/* Set access-list name to the distribute list. */
d62a17ae 155static void distribute_list_set(const char *ifname, enum distribute_type type,
156 const char *alist_name)
718e3744 157{
d62a17ae 158 struct distribute *dist;
718e3744 159
d62a17ae 160 dist = distribute_get(ifname);
718e3744 161
d62a17ae 162 if (dist->list[type])
163 XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[type]);
164 dist->list[type] = XSTRDUP(MTYPE_DISTRIBUTE_NAME, alist_name);
718e3744 165
d62a17ae 166 /* Apply this distribute-list to the interface. */
167 (*distribute_add_hook)(dist);
718e3744 168}
169
170/* Unset distribute-list. If matched distribute-list exist then
171 return 1. */
d62a17ae 172static int distribute_list_unset(const char *ifname, enum distribute_type type,
173 const char *alist_name)
718e3744 174{
d62a17ae 175 struct distribute *dist;
718e3744 176
d62a17ae 177 dist = distribute_lookup(ifname);
178 if (!dist)
179 return 0;
718e3744 180
d62a17ae 181 if (!dist->list[type])
182 return 0;
183 if (strcmp(dist->list[type], alist_name) != 0)
184 return 0;
718e3744 185
d62a17ae 186 XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[type]);
187 dist->list[type] = NULL;
718e3744 188
d62a17ae 189 /* Apply this distribute-list to the interface. */
190 (*distribute_delete_hook)(dist);
718e3744 191
d62a17ae 192 /* If all dist are NULL, then free distribute list. */
193 distribute_free_if_empty(dist);
194 return 1;
718e3744 195}
196
197/* Set access-list name to the distribute list. */
d62a17ae 198static void distribute_list_prefix_set(const char *ifname,
199 enum distribute_type type,
200 const char *plist_name)
718e3744 201{
d62a17ae 202 struct distribute *dist;
718e3744 203
d62a17ae 204 dist = distribute_get(ifname);
718e3744 205
d62a17ae 206 if (dist->prefix[type])
207 XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[type]);
208 dist->prefix[type] = XSTRDUP(MTYPE_DISTRIBUTE_NAME, plist_name);
718e3744 209
d62a17ae 210 /* Apply this distribute-list to the interface. */
211 (*distribute_add_hook)(dist);
718e3744 212}
213
214/* Unset distribute-list. If matched distribute-list exist then
215 return 1. */
d62a17ae 216static int distribute_list_prefix_unset(const char *ifname,
217 enum distribute_type type,
218 const char *plist_name)
718e3744 219{
d62a17ae 220 struct distribute *dist;
718e3744 221
d62a17ae 222 dist = distribute_lookup(ifname);
223 if (!dist)
224 return 0;
718e3744 225
d62a17ae 226 if (!dist->prefix[type])
227 return 0;
228 if (strcmp(dist->prefix[type], plist_name) != 0)
229 return 0;
718e3744 230
d62a17ae 231 XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[type]);
232 dist->prefix[type] = NULL;
718e3744 233
d62a17ae 234 /* Apply this distribute-list to the interface. */
235 (*distribute_delete_hook)(dist);
718e3744 236
d62a17ae 237 /* If all dist are NULL, then free distribute list. */
238 distribute_free_if_empty(dist);
239 return 1;
718e3744 240}
241
718e3744 242DEFUN (distribute_list,
243 distribute_list_cmd,
aa1c90a4 244 "distribute-list [prefix] WORD <in|out> [WORD]",
718e3744 245 "Filter networks in routing updates\n"
856377cc 246 "Specify a prefix\n"
718e3744 247 "Access-list name\n"
248 "Filter incoming routing updates\n"
249 "Filter outgoing routing updates\n"
250 "Interface name\n")
251{
d62a17ae 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;
718e3744 258
d62a17ae 259 /* Set appropriate function call */
260 void (*distfn)(const char *, enum distribute_type, const char *) =
261 prefix ? &distribute_list_prefix_set : &distribute_list_set;
ba23a691 262
d62a17ae 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;
718e3744 267
d62a17ae 268 /* Get interface name corresponding distribute list. */
269 distfn(ifname, type, argv[1 + prefix]->arg);
718e3744 270
d62a17ae 271 return CMD_SUCCESS;
aa1c90a4 272}
718e3744 273
fb23cf4a 274DEFUN (ipv6_distribute_list,
ba23a691 275 ipv6_distribute_list_cmd,
e52702f2
QY
276 "ipv6 distribute-list [prefix] WORD <in|out> [WORD]",
277 "IPv6\n"
fb23cf4a 278 "Filter networks in routing updates\n"
4e93448f 279 "Specify a prefix\n"
fb23cf4a
MB
280 "Access-list name\n"
281 "Filter incoming routing updates\n"
282 "Filter outgoing routing updates\n"
283 "Interface name\n")
284{
d62a17ae 285 int prefix = (argv[2]->type == WORD_TKN) ? 1 : 0;
fb23cf4a 286
d62a17ae 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;
e52702f2 291
d62a17ae 292 /* Set appropriate function call */
293 void (*distfn)(const char *, enum distribute_type, const char *) =
294 prefix ? &distribute_list_prefix_set : &distribute_list_set;
fb23cf4a 295
d62a17ae 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;
fb23cf4a 300
d62a17ae 301 /* Get interface name corresponding distribute list. */
96f05398 302 distfn(ifname, type, argv[2 + prefix]->arg);
d62a17ae 303
304 return CMD_SUCCESS;
fb23cf4a 305}
d62a17ae 306
aa1c90a4
QY
307DEFUN (no_distribute_list,
308 no_distribute_list_cmd,
96f05398 309 "no distribute-list [prefix] WORD <in|out> [WORD]",
ba23a691 310 NO_STR
311 "Filter networks in routing updates\n"
856377cc 312 "Specify a prefix\n"
ba23a691 313 "Access-list name\n"
314 "Filter incoming routing updates\n"
315 "Filter outgoing routing updates\n"
316 "Interface name\n")
718e3744 317{
96f05398 318 int prefix = (argv[2]->type == WORD_TKN) ? 1 : 0;
d62a17ae 319
96f05398 320 int idx_alname = 2 + prefix;
d62a17ae 321 int idx_disttype = idx_alname + 1;
96f05398
PG
322 enum distribute_type type =
323 argv[idx_disttype]->arg[0] == 'i' ?
324 DISTRIBUTE_V4_IN : DISTRIBUTE_V4_OUT;
d62a17ae 325
96f05398
PG
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
345DEFUN (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;
d62a17ae 361
362 enum distribute_type type =
96f05398
PG
363 argv[idx_disttype]->arg[0] == 'i' ?
364 DISTRIBUTE_V6_IN : DISTRIBUTE_V6_OUT;
d62a17ae 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;
96f05398 372
d62a17ae 373 if (argv[argc - 1]->type == VARIABLE_TKN)
374 ifname = argv[argc - 1]->arg;
375 /* Get interface name corresponding distribute list. */
96f05398 376 int ret = distfn(ifname, type, argv[3 + prefix]->arg);
d62a17ae 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;
aa1c90a4 383}
ba23a691 384
d62a17ae 385static int distribute_print(struct vty *vty, char *tab[], int is_prefix,
386 enum distribute_type type, int has_print)
ee5bb561 387{
d62a17ae 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;
ee5bb561
MB
394}
395
d62a17ae 396int config_show_distribute(struct vty *vty)
718e3744 397{
d62a17ae 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;
718e3744 494}
495
496/* Configuration write function. */
d62a17ae 497int config_write_distribute(struct vty *vty)
718e3744 498{
d62a17ae 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;
718e3744 544}
545
546/* Clear all distribute list. */
d62a17ae 547void distribute_list_reset()
718e3744 548{
d62a17ae 549 hash_clean(disthash, (void (*)(void *))distribute_free);
718e3744 550}
551
552/* Initialize distribute list related hash. */
d62a17ae 553void distribute_list_init(int node)
718e3744 554{
d62a17ae 555 disthash = hash_create(
556 distribute_hash_make,
74df8d6d 557 (bool (*)(const void *, const void *))distribute_cmp, NULL);
d62a17ae 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);
96f05398 571 install_element(RIPNG_NODE, &no_ipv6_distribute_list_cmd);
d62a17ae 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 }*/
718e3744 586}