]>
Commit | Line | Data |
---|---|---|
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 |
31 | DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE, "Distribute list") |
32 | DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_IFNAME, "Dist-list ifname") | |
33 | DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_NAME, "Dist-list name") | |
34 | ||
718e3744 | 35 | /* Hash of distribute list. */ |
36 | struct hash *disthash; | |
37 | ||
38 | /* Hook functions. */ | |
39 | void (*distribute_add_hook) (struct distribute *); | |
40 | void (*distribute_delete_hook) (struct distribute *); | |
6b0655a2 | 41 | |
8cc4198f | 42 | static struct distribute * |
43 | distribute_new (void) | |
718e3744 | 44 | { |
393deb9b | 45 | return XCALLOC (MTYPE_DISTRIBUTE, sizeof (struct distribute)); |
718e3744 | 46 | } |
47 | ||
48 | /* Free distribute object. */ | |
8cc4198f | 49 | static void |
718e3744 | 50 | distribute_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. */ | |
69 | struct distribute * | |
9035efaa | 70 | distribute_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 | ||
86 | void | |
87 | distribute_list_add_hook (void (*func) (struct distribute *)) | |
88 | { | |
89 | distribute_add_hook = func; | |
90 | } | |
91 | ||
92 | void | |
93 | distribute_list_delete_hook (void (*func) (struct distribute *)) | |
94 | { | |
95 | distribute_delete_hook = func; | |
96 | } | |
97 | ||
8cc4198f | 98 | static void * |
718e3744 | 99 | distribute_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 | 112 | static struct distribute * |
9035efaa | 113 | distribute_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 | 129 | static unsigned int |
6392aa83 | 130 | distribute_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 | 139 | static int |
ffe11cfb | 140 | distribute_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 | 151 | static void |
9035efaa | 152 | distribute_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 | 178 | static int |
9035efaa | 179 | distribute_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 | 227 | static void |
9035efaa | 228 | distribute_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 | 254 | static int |
9035efaa | 255 | distribute_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 | 302 | DEFUN (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 |
332 | DEFUN (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 | 368 | int |
369 | config_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. */ | |
447 | int | |
448 | config_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. */ | |
502 | void | |
503 | distribute_list_reset () | |
504 | { | |
505 | hash_clean (disthash, (void (*) (void *)) distribute_free); | |
506 | } | |
507 | ||
508 | /* Initialize distribute list related hash. */ | |
509 | void | |
510 | distribute_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 | } |