blob: d5893a5bf052971d40bdf65de740d6a0dd6f47be [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* 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/* Hash of distribute list. */
32struct hash *disthash;
33
34/* Hook functions. */
35void (*distribute_add_hook) (struct distribute *);
36void (*distribute_delete_hook) (struct distribute *);
37
38struct distribute *
39distribute_new ()
40{
41 struct distribute *new;
42
43 new = XMALLOC (MTYPE_DISTRIBUTE, sizeof (struct distribute));
44 memset (new, 0, sizeof (struct distribute));
45
46 return new;
47}
48
49/* Free distribute object. */
50void
51distribute_free (struct distribute *dist)
52{
53 if (dist->ifname)
54 free (dist->ifname);
55
56 if (dist->list[DISTRIBUTE_IN])
57 free (dist->list[DISTRIBUTE_IN]);
58 if (dist->list[DISTRIBUTE_OUT])
59 free (dist->list[DISTRIBUTE_OUT]);
60
61 if (dist->prefix[DISTRIBUTE_IN])
62 free (dist->prefix[DISTRIBUTE_IN]);
63 if (dist->prefix[DISTRIBUTE_OUT])
64 free (dist->prefix[DISTRIBUTE_OUT]);
65
66 XFREE (MTYPE_DISTRIBUTE, dist);
67}
68
69/* Lookup interface's distribute list. */
70struct distribute *
71distribute_lookup (char *ifname)
72{
73 struct distribute key;
74 struct distribute *dist;
75
76 key.ifname = ifname;
77
78 dist = hash_lookup (disthash, &key);
79
80 return dist;
81}
82
83void
84distribute_list_add_hook (void (*func) (struct distribute *))
85{
86 distribute_add_hook = func;
87}
88
89void
90distribute_list_delete_hook (void (*func) (struct distribute *))
91{
92 distribute_delete_hook = func;
93}
94
95void *
96distribute_hash_alloc (struct distribute *arg)
97{
98 struct distribute *dist;
99
100 dist = distribute_new ();
101 if (arg->ifname)
102 dist->ifname = strdup (arg->ifname);
103 else
104 dist->ifname = NULL;
105 return dist;
106}
107
108/* Make new distribute list and push into hash. */
109struct distribute *
110distribute_get (char *ifname)
111{
112 struct distribute key;
113
114 key.ifname = ifname;
115
116 return hash_get (disthash, &key, distribute_hash_alloc);
117}
118
119unsigned int
120distribute_hash_make (struct distribute *dist)
121{
122 unsigned int key;
123 int i;
124
125 key = 0;
126 if (dist->ifname)
127 for (i = 0; i < strlen (dist->ifname); i++)
128 key += dist->ifname[i];
129
130 return key;
131}
132
133/* If two distribute-list have same value then return 1 else return
134 0. This function is used by hash package. */
135int
136distribute_cmp (struct distribute *dist1, struct distribute *dist2)
137{
138 if (dist1->ifname && dist2->ifname)
139 if (strcmp (dist1->ifname, dist2->ifname) == 0)
140 return 1;
141 if (! dist1->ifname && ! dist2->ifname)
142 return 1;
143 return 0;
144}
145
146/* Set access-list name to the distribute list. */
147struct distribute *
148distribute_list_set (char *ifname, enum distribute_type type, char *alist_name)
149{
150 struct distribute *dist;
151
152 dist = distribute_get (ifname);
153
154 if (type == DISTRIBUTE_IN)
155 {
156 if (dist->list[DISTRIBUTE_IN])
157 free (dist->list[DISTRIBUTE_IN]);
158 dist->list[DISTRIBUTE_IN] = strdup (alist_name);
159 }
160 if (type == DISTRIBUTE_OUT)
161 {
162 if (dist->list[DISTRIBUTE_OUT])
163 free (dist->list[DISTRIBUTE_OUT]);
164 dist->list[DISTRIBUTE_OUT] = strdup (alist_name);
165 }
166
167 /* Apply this distribute-list to the interface. */
168 (*distribute_add_hook) (dist);
169
170 return dist;
171}
172
173/* Unset distribute-list. If matched distribute-list exist then
174 return 1. */
175int
176distribute_list_unset (char *ifname, enum distribute_type type,
177 char *alist_name)
178{
179 struct distribute *dist;
180
181 dist = distribute_lookup (ifname);
182 if (!dist)
183 return 0;
184
185 if (type == DISTRIBUTE_IN)
186 {
187 if (!dist->list[DISTRIBUTE_IN])
188 return 0;
189 if (strcmp (dist->list[DISTRIBUTE_IN], alist_name) != 0)
190 return 0;
191
192 free (dist->list[DISTRIBUTE_IN]);
193 dist->list[DISTRIBUTE_IN] = NULL;
194 }
195
196 if (type == DISTRIBUTE_OUT)
197 {
198 if (!dist->list[DISTRIBUTE_OUT])
199 return 0;
200 if (strcmp (dist->list[DISTRIBUTE_OUT], alist_name) != 0)
201 return 0;
202
203 free (dist->list[DISTRIBUTE_OUT]);
204 dist->list[DISTRIBUTE_OUT] = NULL;
205 }
206
207 /* Apply this distribute-list to the interface. */
208 (*distribute_delete_hook) (dist);
209
210 /* If both out and in is NULL then free distribute list. */
211 if (dist->list[DISTRIBUTE_IN] == NULL &&
212 dist->list[DISTRIBUTE_OUT] == NULL &&
213 dist->prefix[DISTRIBUTE_IN] == NULL &&
214 dist->prefix[DISTRIBUTE_OUT] == NULL)
215 {
216 hash_release (disthash, dist);
217 distribute_free (dist);
218 }
219
220 return 1;
221}
222
223/* Set access-list name to the distribute list. */
224struct distribute *
225distribute_list_prefix_set (char *ifname, enum distribute_type type,
226 char *plist_name)
227{
228 struct distribute *dist;
229
230 dist = distribute_get (ifname);
231
232 if (type == DISTRIBUTE_IN)
233 {
234 if (dist->prefix[DISTRIBUTE_IN])
235 free (dist->prefix[DISTRIBUTE_IN]);
236 dist->prefix[DISTRIBUTE_IN] = strdup (plist_name);
237 }
238 if (type == DISTRIBUTE_OUT)
239 {
240 if (dist->prefix[DISTRIBUTE_OUT])
241 free (dist->prefix[DISTRIBUTE_OUT]);
242 dist->prefix[DISTRIBUTE_OUT] = strdup (plist_name);
243 }
244
245 /* Apply this distribute-list to the interface. */
246 (*distribute_add_hook) (dist);
247
248 return dist;
249}
250
251/* Unset distribute-list. If matched distribute-list exist then
252 return 1. */
253int
254distribute_list_prefix_unset (char *ifname, enum distribute_type type,
255 char *plist_name)
256{
257 struct distribute *dist;
258
259 dist = distribute_lookup (ifname);
260 if (!dist)
261 return 0;
262
263 if (type == DISTRIBUTE_IN)
264 {
265 if (!dist->prefix[DISTRIBUTE_IN])
266 return 0;
267 if (strcmp (dist->prefix[DISTRIBUTE_IN], plist_name) != 0)
268 return 0;
269
270 free (dist->prefix[DISTRIBUTE_IN]);
271 dist->prefix[DISTRIBUTE_IN] = NULL;
272 }
273
274 if (type == DISTRIBUTE_OUT)
275 {
276 if (!dist->prefix[DISTRIBUTE_OUT])
277 return 0;
278 if (strcmp (dist->prefix[DISTRIBUTE_OUT], plist_name) != 0)
279 return 0;
280
281 free (dist->prefix[DISTRIBUTE_OUT]);
282 dist->prefix[DISTRIBUTE_OUT] = NULL;
283 }
284
285 /* Apply this distribute-list to the interface. */
286 (*distribute_delete_hook) (dist);
287
288 /* If both out and in is NULL then free distribute list. */
289 if (dist->list[DISTRIBUTE_IN] == NULL &&
290 dist->list[DISTRIBUTE_OUT] == NULL &&
291 dist->prefix[DISTRIBUTE_IN] == NULL &&
292 dist->prefix[DISTRIBUTE_OUT] == NULL)
293 {
294 hash_release (disthash, dist);
295 distribute_free (dist);
296 }
297
298 return 1;
299}
300
301DEFUN (distribute_list_all,
302 distribute_list_all_cmd,
303 "distribute-list WORD (in|out)",
304 "Filter networks in routing updates\n"
305 "Access-list name\n"
306 "Filter incoming routing updates\n"
307 "Filter outgoing routing updates\n")
308{
309 enum distribute_type type;
310 struct distribute *dist;
311
312 /* Check of distribute list type. */
313 if (strncmp (argv[1], "i", 1) == 0)
314 type = DISTRIBUTE_IN;
315 else if (strncmp (argv[1], "o", 1) == 0)
316 type = DISTRIBUTE_OUT;
317 else
318 {
319 vty_out (vty, "distribute list direction must be [in|out]%s",
320 VTY_NEWLINE);
321 return CMD_WARNING;
322 }
323
324 /* Get interface name corresponding distribute list. */
325 dist = distribute_list_set (NULL, type, argv[0]);
326
327 return CMD_SUCCESS;
328}
329
330DEFUN (no_distribute_list_all,
331 no_distribute_list_all_cmd,
332 "no distribute-list WORD (in|out)",
333 NO_STR
334 "Filter networks in routing updates\n"
335 "Access-list name\n"
336 "Filter incoming routing updates\n"
337 "Filter outgoing routing updates\n")
338{
339 int ret;
340 enum distribute_type type;
341
342 /* Check of distribute list type. */
343 if (strncmp (argv[1], "i", 1) == 0)
344 type = DISTRIBUTE_IN;
345 else if (strncmp (argv[1], "o", 1) == 0)
346 type = DISTRIBUTE_OUT;
347 else
348 {
349 vty_out (vty, "distribute list direction must be [in|out]%s",
350 VTY_NEWLINE);
351 return CMD_WARNING;
352 }
353
354 ret = distribute_list_unset (NULL, type, argv[0]);
355 if (! ret)
356 {
357 vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE);
358 return CMD_WARNING;
359 }
360 return CMD_SUCCESS;
361}
362
363DEFUN (distribute_list,
364 distribute_list_cmd,
365 "distribute-list WORD (in|out) WORD",
366 "Filter networks in routing updates\n"
367 "Access-list name\n"
368 "Filter incoming routing updates\n"
369 "Filter outgoing routing updates\n"
370 "Interface name\n")
371{
372 enum distribute_type type;
373 struct distribute *dist;
374
375 /* Check of distribute list type. */
376 if (strncmp (argv[1], "i", 1) == 0)
377 type = DISTRIBUTE_IN;
378 else if (strncmp (argv[1], "o", 1) == 0)
379 type = DISTRIBUTE_OUT;
380 else
381 {
382 vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE);
383 return CMD_WARNING;
384 }
385
386 /* Get interface name corresponding distribute list. */
387 dist = distribute_list_set (argv[2], type, argv[0]);
388
389 return CMD_SUCCESS;
390}
391
392DEFUN (no_districute_list, no_distribute_list_cmd,
393 "no distribute-list WORD (in|out) WORD",
394 NO_STR
395 "Filter networks in routing updates\n"
396 "Access-list name\n"
397 "Filter incoming routing updates\n"
398 "Filter outgoing routing updates\n"
399 "Interface name\n")
400{
401 int ret;
402 enum distribute_type type;
403
404 /* Check of distribute list type. */
405 if (strncmp (argv[1], "i", 1) == 0)
406 type = DISTRIBUTE_IN;
407 else if (strncmp (argv[1], "o", 1) == 0)
408 type = DISTRIBUTE_OUT;
409 else
410 {
411 vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE);
412 return CMD_WARNING;
413 }
414
415 ret = distribute_list_unset (argv[2], type, argv[0]);
416 if (! ret)
417 {
418 vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE);
419 return CMD_WARNING;
420 }
421 return CMD_SUCCESS;
422}
423
424DEFUN (districute_list_prefix_all,
425 distribute_list_prefix_all_cmd,
426 "distribute-list prefix WORD (in|out)",
427 "Filter networks in routing updates\n"
428 "Filter prefixes in routing updates\n"
429 "Name of an IP prefix-list\n"
430 "Filter incoming routing updates\n"
431 "Filter outgoing routing updates\n")
432{
433 enum distribute_type type;
434 struct distribute *dist;
435
436 /* Check of distribute list type. */
437 if (strncmp (argv[1], "i", 1) == 0)
438 type = DISTRIBUTE_IN;
439 else if (strncmp (argv[1], "o", 1) == 0)
440 type = DISTRIBUTE_OUT;
441 else
442 {
443 vty_out (vty, "distribute list direction must be [in|out]%s",
444 VTY_NEWLINE);
445 return CMD_WARNING;
446 }
447
448 /* Get interface name corresponding distribute list. */
449 dist = distribute_list_prefix_set (NULL, type, argv[0]);
450
451 return CMD_SUCCESS;
452}
453
454DEFUN (no_districute_list_prefix_all,
455 no_distribute_list_prefix_all_cmd,
456 "no distribute-list prefix WORD (in|out)",
457 NO_STR
458 "Filter networks in routing updates\n"
459 "Filter prefixes in routing updates\n"
460 "Name of an IP prefix-list\n"
461 "Filter incoming routing updates\n"
462 "Filter outgoing routing updates\n")
463{
464 int ret;
465 enum distribute_type type;
466
467 /* Check of distribute list type. */
468 if (strncmp (argv[1], "i", 1) == 0)
469 type = DISTRIBUTE_IN;
470 else if (strncmp (argv[1], "o", 1) == 0)
471 type = DISTRIBUTE_OUT;
472 else
473 {
474 vty_out (vty, "distribute list direction must be [in|out]%s",
475 VTY_NEWLINE);
476 return CMD_WARNING;
477 }
478
479 ret = distribute_list_prefix_unset (NULL, type, argv[0]);
480 if (! ret)
481 {
482 vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE);
483 return CMD_WARNING;
484 }
485 return CMD_SUCCESS;
486}
487
488DEFUN (districute_list_prefix, distribute_list_prefix_cmd,
489 "distribute-list prefix WORD (in|out) WORD",
490 "Filter networks in routing updates\n"
491 "Filter prefixes in routing updates\n"
492 "Name of an IP prefix-list\n"
493 "Filter incoming routing updates\n"
494 "Filter outgoing routing updates\n"
495 "Interface name\n")
496{
497 enum distribute_type type;
498 struct distribute *dist;
499
500 /* Check of distribute list type. */
501 if (strncmp (argv[1], "i", 1) == 0)
502 type = DISTRIBUTE_IN;
503 else if (strncmp (argv[1], "o", 1) == 0)
504 type = DISTRIBUTE_OUT;
505 else
506 {
507 vty_out (vty, "distribute list direction must be [in|out]%s",
508 VTY_NEWLINE);
509 return CMD_WARNING;
510 }
511
512 /* Get interface name corresponding distribute list. */
513 dist = distribute_list_prefix_set (argv[2], type, argv[0]);
514
515 return CMD_SUCCESS;
516}
517
518DEFUN (no_districute_list_prefix, no_distribute_list_prefix_cmd,
519 "no distribute-list prefix WORD (in|out) WORD",
520 NO_STR
521 "Filter networks in routing updates\n"
522 "Filter prefixes in routing updates\n"
523 "Name of an IP prefix-list\n"
524 "Filter incoming routing updates\n"
525 "Filter outgoing routing updates\n"
526 "Interface name\n")
527{
528 int ret;
529 enum distribute_type type;
530
531 /* Check of distribute list type. */
532 if (strncmp (argv[1], "i", 1) == 0)
533 type = DISTRIBUTE_IN;
534 else if (strncmp (argv[1], "o", 1) == 0)
535 type = DISTRIBUTE_OUT;
536 else
537 {
538 vty_out (vty, "distribute list direction must be [in|out]%s",
539 VTY_NEWLINE);
540 return CMD_WARNING;
541 }
542
543 ret = distribute_list_prefix_unset (argv[2], type, argv[0]);
544 if (! ret)
545 {
546 vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE);
547 return CMD_WARNING;
548 }
549 return CMD_SUCCESS;
550}
551
552int
553config_show_distribute (struct vty *vty)
554{
555 int i;
556 struct hash_backet *mp;
557 struct distribute *dist;
558
559 /* Output filter configuration. */
560 dist = distribute_lookup (NULL);
561 if (dist && (dist->list[DISTRIBUTE_OUT] || dist->prefix[DISTRIBUTE_OUT]))
562 {
563 vty_out (vty, " Outgoing update filter list for all interface is");
564 if (dist->list[DISTRIBUTE_OUT])
565 vty_out (vty, " %s", dist->list[DISTRIBUTE_OUT]);
566 if (dist->prefix[DISTRIBUTE_OUT])
567 vty_out (vty, "%s (prefix-list) %s",
568 dist->list[DISTRIBUTE_OUT] ? "," : "",
569 dist->prefix[DISTRIBUTE_OUT]);
570 vty_out (vty, "%s", VTY_NEWLINE);
571 }
572 else
573 vty_out (vty, " Outgoing update filter list for all interface is not set%s", VTY_NEWLINE);
574
575 for (i = 0; i < disthash->size; i++)
576 for (mp = disthash->index[i]; mp; mp = mp->next)
577 {
578 dist = mp->data;
579 if (dist->ifname)
580 if (dist->list[DISTRIBUTE_OUT] || dist->prefix[DISTRIBUTE_OUT])
581 {
582 vty_out (vty, " %s filtered by", dist->ifname);
583 if (dist->list[DISTRIBUTE_OUT])
584 vty_out (vty, " %s", dist->list[DISTRIBUTE_OUT]);
585 if (dist->prefix[DISTRIBUTE_OUT])
586 vty_out (vty, "%s (prefix-list) %s",
587 dist->list[DISTRIBUTE_OUT] ? "," : "",
588 dist->prefix[DISTRIBUTE_OUT]);
589 vty_out (vty, "%s", VTY_NEWLINE);
590 }
591 }
592
593
594 /* Input filter configuration. */
595 dist = distribute_lookup (NULL);
596 if (dist && (dist->list[DISTRIBUTE_IN] || dist->prefix[DISTRIBUTE_IN]))
597 {
598 vty_out (vty, " Incoming update filter list for all interface is");
599 if (dist->list[DISTRIBUTE_IN])
600 vty_out (vty, " %s", dist->list[DISTRIBUTE_IN]);
601 if (dist->prefix[DISTRIBUTE_IN])
602 vty_out (vty, "%s (prefix-list) %s",
603 dist->list[DISTRIBUTE_IN] ? "," : "",
604 dist->prefix[DISTRIBUTE_IN]);
605 vty_out (vty, "%s", VTY_NEWLINE);
606 }
607 else
608 vty_out (vty, " Incoming update filter list for all interface is not set%s", VTY_NEWLINE);
609
610 for (i = 0; i < disthash->size; i++)
611 for (mp = disthash->index[i]; mp; mp = mp->next)
612 {
613 dist = mp->data;
614 if (dist->ifname)
615 if (dist->list[DISTRIBUTE_IN] || dist->prefix[DISTRIBUTE_IN])
616 {
617 vty_out (vty, " %s filtered by", dist->ifname);
618 if (dist->list[DISTRIBUTE_IN])
619 vty_out (vty, " %s", dist->list[DISTRIBUTE_IN]);
620 if (dist->prefix[DISTRIBUTE_IN])
621 vty_out (vty, "%s (prefix-list) %s",
622 dist->list[DISTRIBUTE_IN] ? "," : "",
623 dist->prefix[DISTRIBUTE_IN]);
624 vty_out (vty, "%s", VTY_NEWLINE);
625 }
626 }
627 return 0;
628}
629
630/* Configuration write function. */
631int
632config_write_distribute (struct vty *vty)
633{
634 int i;
635 struct hash_backet *mp;
636 int write = 0;
637
638 for (i = 0; i < disthash->size; i++)
639 for (mp = disthash->index[i]; mp; mp = mp->next)
640 {
641 struct distribute *dist;
642
643 dist = mp->data;
644
645 if (dist->list[DISTRIBUTE_IN])
646 {
647 vty_out (vty, " distribute-list %s in %s%s",
648 dist->list[DISTRIBUTE_IN],
649 dist->ifname ? dist->ifname : "",
650 VTY_NEWLINE);
651 write++;
652 }
653
654 if (dist->list[DISTRIBUTE_OUT])
655 {
656 vty_out (vty, " distribute-list %s out %s%s",
657
658 dist->list[DISTRIBUTE_OUT],
659 dist->ifname ? dist->ifname : "",
660 VTY_NEWLINE);
661 write++;
662 }
663
664 if (dist->prefix[DISTRIBUTE_IN])
665 {
666 vty_out (vty, " distribute-list prefix %s in %s%s",
667 dist->prefix[DISTRIBUTE_IN],
668 dist->ifname ? dist->ifname : "",
669 VTY_NEWLINE);
670 write++;
671 }
672
673 if (dist->prefix[DISTRIBUTE_OUT])
674 {
675 vty_out (vty, " distribute-list prefix %s out %s%s",
676 dist->prefix[DISTRIBUTE_OUT],
677 dist->ifname ? dist->ifname : "",
678 VTY_NEWLINE);
679 write++;
680 }
681 }
682 return write;
683}
684
685/* Clear all distribute list. */
686void
687distribute_list_reset ()
688{
689 hash_clean (disthash, (void (*) (void *)) distribute_free);
690}
691
692/* Initialize distribute list related hash. */
693void
694distribute_list_init (int node)
695{
696 disthash = hash_create (distribute_hash_make, distribute_cmp);
697
698 install_element (node, &distribute_list_all_cmd);
699 install_element (node, &no_distribute_list_all_cmd);
700
701 install_element (node, &distribute_list_cmd);
702 install_element (node, &no_distribute_list_cmd);
703
704 install_element (node, &distribute_list_prefix_all_cmd);
705 install_element (node, &no_distribute_list_prefix_all_cmd);
706
707 install_element (node, &distribute_list_prefix_cmd);
708 install_element (node, &no_distribute_list_prefix_cmd);
709}