]> git.proxmox.com Git - mirror_frr.git/blame - lib/distribute.c
ospf6d: fix a few vty help strings
[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{
52 if (dist->ifname)
9035efaa 53 XFREE (MTYPE_DISTRIBUTE_IFNAME, dist->ifname);
718e3744 54
55 if (dist->list[DISTRIBUTE_IN])
6e919709 56 XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[DISTRIBUTE_IN]);
718e3744 57 if (dist->list[DISTRIBUTE_OUT])
6e919709 58 XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[DISTRIBUTE_OUT]);
718e3744 59
60 if (dist->prefix[DISTRIBUTE_IN])
6e919709 61 XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[DISTRIBUTE_IN]);
718e3744 62 if (dist->prefix[DISTRIBUTE_OUT])
6e919709 63 XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[DISTRIBUTE_OUT]);
718e3744 64
65 XFREE (MTYPE_DISTRIBUTE, dist);
66}
67
68/* Lookup interface's distribute list. */
69struct distribute *
9035efaa 70distribute_lookup (const char *ifname)
718e3744 71{
72 struct distribute key;
73 struct distribute *dist;
74
9035efaa 75 /* temporary reference */
3a7c85d1 76 key.ifname = (ifname) ? XSTRDUP(MTYPE_DISTRIBUTE_IFNAME, ifname) : NULL;
718e3744 77
78 dist = hash_lookup (disthash, &key);
3a7c85d1
DS
79
80 if (key.ifname)
81 XFREE(MTYPE_DISTRIBUTE_IFNAME, key.ifname);
24873f0c 82
718e3744 83 return dist;
84}
85
86void
87distribute_list_add_hook (void (*func) (struct distribute *))
88{
89 distribute_add_hook = func;
90}
91
92void
93distribute_list_delete_hook (void (*func) (struct distribute *))
94{
95 distribute_delete_hook = func;
96}
97
8cc4198f 98static void *
718e3744 99distribute_hash_alloc (struct distribute *arg)
100{
101 struct distribute *dist;
102
103 dist = distribute_new ();
104 if (arg->ifname)
9035efaa 105 dist->ifname = XSTRDUP (MTYPE_DISTRIBUTE_IFNAME, arg->ifname);
718e3744 106 else
107 dist->ifname = NULL;
108 return dist;
109}
110
111/* Make new distribute list and push into hash. */
8cc4198f 112static struct distribute *
9035efaa 113distribute_get (const char *ifname)
718e3744 114{
115 struct distribute key;
24873f0c 116 struct distribute *ret;
718e3744 117
9035efaa 118 /* temporary reference */
3a7c85d1 119 key.ifname = (ifname) ? XSTRDUP(MTYPE_DISTRIBUTE_IFNAME, ifname) : NULL;
9035efaa 120
24873f0c
DS
121 ret = hash_get (disthash, &key, (void * (*) (void *))distribute_hash_alloc);
122
3a7c85d1
DS
123 if (key.ifname)
124 XFREE(MTYPE_DISTRIBUTE_IFNAME, key.ifname);
125
24873f0c 126 return ret;
718e3744 127}
128
8cc4198f 129static unsigned int
6392aa83 130distribute_hash_make (void *arg)
718e3744 131{
6392aa83 132 const struct distribute *dist = arg;
718e3744 133
6392aa83 134 return dist->ifname ? string_hash_make (dist->ifname) : 0;
718e3744 135}
136
137/* If two distribute-list have same value then return 1 else return
138 0. This function is used by hash package. */
8cc4198f 139static int
ffe11cfb 140distribute_cmp (const struct distribute *dist1, const struct distribute *dist2)
718e3744 141{
142 if (dist1->ifname && dist2->ifname)
143 if (strcmp (dist1->ifname, dist2->ifname) == 0)
144 return 1;
145 if (! dist1->ifname && ! dist2->ifname)
146 return 1;
147 return 0;
148}
6b0655a2 149
718e3744 150/* Set access-list name to the distribute list. */
c0c053fa 151static void
9035efaa 152distribute_list_set (const char *ifname, enum distribute_type type,
153 const char *alist_name)
718e3744 154{
155 struct distribute *dist;
156
157 dist = distribute_get (ifname);
158
159 if (type == DISTRIBUTE_IN)
160 {
161 if (dist->list[DISTRIBUTE_IN])
6e919709
DS
162 XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[DISTRIBUTE_IN]);
163 dist->list[DISTRIBUTE_IN] = XSTRDUP(MTYPE_DISTRIBUTE_NAME, alist_name);
718e3744 164 }
165 if (type == DISTRIBUTE_OUT)
166 {
167 if (dist->list[DISTRIBUTE_OUT])
6e919709
DS
168 XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[DISTRIBUTE_OUT]);
169 dist->list[DISTRIBUTE_OUT] = XSTRDUP(MTYPE_DISTRIBUTE_NAME, alist_name);
718e3744 170 }
171
172 /* Apply this distribute-list to the interface. */
173 (*distribute_add_hook) (dist);
718e3744 174}
175
176/* Unset distribute-list. If matched distribute-list exist then
177 return 1. */
8cc4198f 178static int
9035efaa 179distribute_list_unset (const char *ifname, enum distribute_type type,
180 const char *alist_name)
718e3744 181{
182 struct distribute *dist;
183
184 dist = distribute_lookup (ifname);
185 if (!dist)
186 return 0;
187
188 if (type == DISTRIBUTE_IN)
189 {
190 if (!dist->list[DISTRIBUTE_IN])
191 return 0;
192 if (strcmp (dist->list[DISTRIBUTE_IN], alist_name) != 0)
193 return 0;
194
6e919709 195 XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[DISTRIBUTE_IN]);
718e3744 196 dist->list[DISTRIBUTE_IN] = NULL;
197 }
198
199 if (type == DISTRIBUTE_OUT)
200 {
201 if (!dist->list[DISTRIBUTE_OUT])
202 return 0;
203 if (strcmp (dist->list[DISTRIBUTE_OUT], alist_name) != 0)
204 return 0;
205
6e919709 206 XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[DISTRIBUTE_OUT]);
718e3744 207 dist->list[DISTRIBUTE_OUT] = NULL;
208 }
209
210 /* Apply this distribute-list to the interface. */
211 (*distribute_delete_hook) (dist);
212
213 /* If both out and in is NULL then free distribute list. */
214 if (dist->list[DISTRIBUTE_IN] == NULL &&
215 dist->list[DISTRIBUTE_OUT] == NULL &&
216 dist->prefix[DISTRIBUTE_IN] == NULL &&
217 dist->prefix[DISTRIBUTE_OUT] == NULL)
218 {
219 hash_release (disthash, dist);
220 distribute_free (dist);
221 }
222
223 return 1;
224}
225
226/* Set access-list name to the distribute list. */
c0c053fa 227static void
9035efaa 228distribute_list_prefix_set (const char *ifname, enum distribute_type type,
229 const char *plist_name)
718e3744 230{
231 struct distribute *dist;
232
233 dist = distribute_get (ifname);
234
235 if (type == DISTRIBUTE_IN)
236 {
237 if (dist->prefix[DISTRIBUTE_IN])
6e919709
DS
238 XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[DISTRIBUTE_IN]);
239 dist->prefix[DISTRIBUTE_IN] = XSTRDUP(MTYPE_DISTRIBUTE_NAME, plist_name);
718e3744 240 }
241 if (type == DISTRIBUTE_OUT)
242 {
243 if (dist->prefix[DISTRIBUTE_OUT])
6e919709
DS
244 XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[DISTRIBUTE_OUT]);
245 dist->prefix[DISTRIBUTE_OUT] = XSTRDUP(MTYPE_DISTRIBUTE_NAME, plist_name);
718e3744 246 }
247
248 /* Apply this distribute-list to the interface. */
249 (*distribute_add_hook) (dist);
718e3744 250}
251
252/* Unset distribute-list. If matched distribute-list exist then
253 return 1. */
8cc4198f 254static int
9035efaa 255distribute_list_prefix_unset (const char *ifname, enum distribute_type type,
256 const char *plist_name)
718e3744 257{
258 struct distribute *dist;
259
260 dist = distribute_lookup (ifname);
261 if (!dist)
262 return 0;
263
264 if (type == DISTRIBUTE_IN)
265 {
266 if (!dist->prefix[DISTRIBUTE_IN])
267 return 0;
268 if (strcmp (dist->prefix[DISTRIBUTE_IN], plist_name) != 0)
269 return 0;
270
6e919709
DS
271 XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[DISTRIBUTE_IN]);
272 dist->prefix[DISTRIBUTE_IN] = NULL;
718e3744 273 }
274
275 if (type == DISTRIBUTE_OUT)
276 {
277 if (!dist->prefix[DISTRIBUTE_OUT])
278 return 0;
279 if (strcmp (dist->prefix[DISTRIBUTE_OUT], plist_name) != 0)
280 return 0;
281
6e919709
DS
282 XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[DISTRIBUTE_OUT]);
283 dist->prefix[DISTRIBUTE_OUT] = NULL;
718e3744 284 }
285
286 /* Apply this distribute-list to the interface. */
287 (*distribute_delete_hook) (dist);
288
289 /* If both out and in is NULL then free distribute list. */
290 if (dist->list[DISTRIBUTE_IN] == NULL &&
291 dist->list[DISTRIBUTE_OUT] == NULL &&
292 dist->prefix[DISTRIBUTE_IN] == NULL &&
293 dist->prefix[DISTRIBUTE_OUT] == NULL)
294 {
295 hash_release (disthash, dist);
296 distribute_free (dist);
297 }
298
299 return 1;
300}
301
718e3744 302DEFUN (distribute_list,
303 distribute_list_cmd,
aa1c90a4 304 "distribute-list [prefix] WORD <in|out> [WORD]",
718e3744 305 "Filter networks in routing updates\n"
306 "Access-list name\n"
307 "Filter incoming routing updates\n"
308 "Filter outgoing routing updates\n"
309 "Interface name\n")
310{
aa1c90a4 311 int prefix = (argv[1]->type == WORD_TKN) ? 1 : 0;
718e3744 312
313 /* Check of distribute list type. */
aa1c90a4
QY
314 enum distribute_type type = argv[2 + prefix]->arg[0] == 'i' ?
315 DISTRIBUTE_IN : DISTRIBUTE_OUT;
ba23a691 316
aa1c90a4 317 /* Set appropriate function call */
c0c053fa 318 void (*distfn)(const char *, enum distribute_type, const char *) = prefix ?
aa1c90a4
QY
319 &distribute_list_prefix_set : &distribute_list_set;
320
321 /* if interface is present, get name */
322 const char *ifname = NULL;
323 if (argv[argc - 1]->type == VARIABLE_TKN)
324 ifname = argv[argc - 1]->arg;
718e3744 325
aa1c90a4
QY
326 /* Get interface name corresponding distribute list. */
327 distfn (ifname, type, argv[1 + prefix]->arg);
718e3744 328
718e3744 329 return CMD_SUCCESS;
aa1c90a4 330}
718e3744 331
aa1c90a4
QY
332DEFUN (no_distribute_list,
333 no_distribute_list_cmd,
334 "no distribute-list [prefix] WORD <in|out> [WORD]",
ba23a691 335 NO_STR
336 "Filter networks in routing updates\n"
337 "Access-list name\n"
338 "Filter incoming routing updates\n"
339 "Filter outgoing routing updates\n"
340 "Interface name\n")
718e3744 341{
aa1c90a4 342 int prefix = (argv[2]->type == WORD_TKN) ? 1 : 0;
718e3744 343
344 /* Check of distribute list type. */
aa1c90a4
QY
345 enum distribute_type type = argv[3 + prefix]->arg[0] == 'i' ?
346 DISTRIBUTE_IN : DISTRIBUTE_OUT;
ba23a691 347
aa1c90a4
QY
348 /* Set appropriate function call */
349 int (*distfn)(const char *, enum distribute_type, const char *) = prefix ?
350 &distribute_list_prefix_unset : &distribute_list_unset;
351
352 /* if interface is present, get name */
353 const char *ifname = NULL;
354 if (argv[argc - 1]->type == VARIABLE_TKN)
355 ifname = argv[argc - 1]->arg;
718e3744 356
357 /* Get interface name corresponding distribute list. */
aa1c90a4 358 int ret = distfn (ifname, type, argv[2 + prefix]->arg);
718e3744 359
718e3744 360 if (! ret)
361 {
362 vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE);
363 return CMD_WARNING;
364 }
365 return CMD_SUCCESS;
aa1c90a4 366}
ba23a691 367
718e3744 368int
369config_show_distribute (struct vty *vty)
370{
8c328f11 371 unsigned int i;
718e3744 372 struct hash_backet *mp;
373 struct distribute *dist;
374
375 /* Output filter configuration. */
376 dist = distribute_lookup (NULL);
377 if (dist && (dist->list[DISTRIBUTE_OUT] || dist->prefix[DISTRIBUTE_OUT]))
378 {
379 vty_out (vty, " Outgoing update filter list for all interface is");
380 if (dist->list[DISTRIBUTE_OUT])
381 vty_out (vty, " %s", dist->list[DISTRIBUTE_OUT]);
382 if (dist->prefix[DISTRIBUTE_OUT])
383 vty_out (vty, "%s (prefix-list) %s",
384 dist->list[DISTRIBUTE_OUT] ? "," : "",
385 dist->prefix[DISTRIBUTE_OUT]);
386 vty_out (vty, "%s", VTY_NEWLINE);
387 }
388 else
389 vty_out (vty, " Outgoing update filter list for all interface is not set%s", VTY_NEWLINE);
390
391 for (i = 0; i < disthash->size; i++)
392 for (mp = disthash->index[i]; mp; mp = mp->next)
393 {
394 dist = mp->data;
395 if (dist->ifname)
396 if (dist->list[DISTRIBUTE_OUT] || dist->prefix[DISTRIBUTE_OUT])
397 {
398 vty_out (vty, " %s filtered by", dist->ifname);
399 if (dist->list[DISTRIBUTE_OUT])
400 vty_out (vty, " %s", dist->list[DISTRIBUTE_OUT]);
401 if (dist->prefix[DISTRIBUTE_OUT])
402 vty_out (vty, "%s (prefix-list) %s",
403 dist->list[DISTRIBUTE_OUT] ? "," : "",
404 dist->prefix[DISTRIBUTE_OUT]);
405 vty_out (vty, "%s", VTY_NEWLINE);
406 }
407 }
408
409
410 /* Input filter configuration. */
411 dist = distribute_lookup (NULL);
412 if (dist && (dist->list[DISTRIBUTE_IN] || dist->prefix[DISTRIBUTE_IN]))
413 {
414 vty_out (vty, " Incoming update filter list for all interface is");
415 if (dist->list[DISTRIBUTE_IN])
416 vty_out (vty, " %s", dist->list[DISTRIBUTE_IN]);
417 if (dist->prefix[DISTRIBUTE_IN])
418 vty_out (vty, "%s (prefix-list) %s",
419 dist->list[DISTRIBUTE_IN] ? "," : "",
420 dist->prefix[DISTRIBUTE_IN]);
421 vty_out (vty, "%s", VTY_NEWLINE);
422 }
423 else
424 vty_out (vty, " Incoming update filter list for all interface is not set%s", VTY_NEWLINE);
425
426 for (i = 0; i < disthash->size; i++)
427 for (mp = disthash->index[i]; mp; mp = mp->next)
428 {
429 dist = mp->data;
430 if (dist->ifname)
431 if (dist->list[DISTRIBUTE_IN] || dist->prefix[DISTRIBUTE_IN])
432 {
433 vty_out (vty, " %s filtered by", dist->ifname);
434 if (dist->list[DISTRIBUTE_IN])
435 vty_out (vty, " %s", dist->list[DISTRIBUTE_IN]);
436 if (dist->prefix[DISTRIBUTE_IN])
437 vty_out (vty, "%s (prefix-list) %s",
438 dist->list[DISTRIBUTE_IN] ? "," : "",
439 dist->prefix[DISTRIBUTE_IN]);
440 vty_out (vty, "%s", VTY_NEWLINE);
441 }
442 }
443 return 0;
444}
445
446/* Configuration write function. */
447int
448config_write_distribute (struct vty *vty)
449{
8c328f11 450 unsigned int i;
718e3744 451 struct hash_backet *mp;
452 int write = 0;
453
454 for (i = 0; i < disthash->size; i++)
455 for (mp = disthash->index[i]; mp; mp = mp->next)
456 {
457 struct distribute *dist;
458
459 dist = mp->data;
460
461 if (dist->list[DISTRIBUTE_IN])
462 {
463 vty_out (vty, " distribute-list %s in %s%s",
464 dist->list[DISTRIBUTE_IN],
465 dist->ifname ? dist->ifname : "",
466 VTY_NEWLINE);
467 write++;
468 }
469
470 if (dist->list[DISTRIBUTE_OUT])
471 {
472 vty_out (vty, " distribute-list %s out %s%s",
473
474 dist->list[DISTRIBUTE_OUT],
475 dist->ifname ? dist->ifname : "",
476 VTY_NEWLINE);
477 write++;
478 }
479
480 if (dist->prefix[DISTRIBUTE_IN])
481 {
482 vty_out (vty, " distribute-list prefix %s in %s%s",
483 dist->prefix[DISTRIBUTE_IN],
484 dist->ifname ? dist->ifname : "",
485 VTY_NEWLINE);
486 write++;
487 }
488
489 if (dist->prefix[DISTRIBUTE_OUT])
490 {
491 vty_out (vty, " distribute-list prefix %s out %s%s",
492 dist->prefix[DISTRIBUTE_OUT],
493 dist->ifname ? dist->ifname : "",
494 VTY_NEWLINE);
495 write++;
496 }
497 }
498 return write;
499}
500
501/* Clear all distribute list. */
502void
503distribute_list_reset ()
504{
505 hash_clean (disthash, (void (*) (void *)) distribute_free);
506}
507
508/* Initialize distribute list related hash. */
509void
510distribute_list_init (int node)
511{
6392aa83 512 disthash = hash_create (distribute_hash_make,
ffe11cfb 513 (int (*) (const void *, const void *)) distribute_cmp);
718e3744 514
aa1c90a4
QY
515 install_element (node, &distribute_list_cmd);
516 install_element (node, &no_distribute_list_cmd);
718e3744 517}