Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0-or-later
2 : /* Distribute list functions
3 : * Copyright (C) 1998, 1999 Kunihiro Ishiguro
4 : */
5 :
6 : #include <zebra.h>
7 :
8 : #include "hash.h"
9 : #include "if.h"
10 : #include "filter.h"
11 : #include "command.h"
12 : #include "distribute.h"
13 : #include "memory.h"
14 :
15 12 : DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_CTX, "Distribute ctx");
16 12 : DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE, "Distribute list");
17 12 : DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_IFNAME, "Dist-list ifname");
18 12 : DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_NAME, "Dist-list name");
19 :
20 : static struct list *dist_ctx_list;
21 :
22 0 : static struct distribute *distribute_new(void)
23 : {
24 0 : return XCALLOC(MTYPE_DISTRIBUTE, sizeof(struct distribute));
25 : }
26 :
27 : /* Free distribute object. */
28 0 : static void distribute_free(struct distribute *dist)
29 : {
30 0 : int i = 0;
31 :
32 0 : XFREE(MTYPE_DISTRIBUTE_IFNAME, dist->ifname);
33 :
34 0 : for (i = 0; i < DISTRIBUTE_MAX; i++) {
35 0 : XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[i]);
36 : }
37 :
38 0 : for (i = 0; i < DISTRIBUTE_MAX; i++) {
39 0 : XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[i]);
40 : }
41 :
42 0 : XFREE(MTYPE_DISTRIBUTE, dist);
43 0 : }
44 :
45 0 : static void distribute_free_if_empty(struct distribute_ctx *ctx,
46 : struct distribute *dist)
47 : {
48 0 : int i;
49 :
50 0 : for (i = 0; i < DISTRIBUTE_MAX; i++)
51 0 : if (dist->list[i] != NULL || dist->prefix[i] != NULL)
52 : return;
53 :
54 0 : hash_release(ctx->disthash, dist);
55 0 : distribute_free(dist);
56 : }
57 :
58 : /* Lookup interface's distribute list. */
59 0 : struct distribute *distribute_lookup(struct distribute_ctx *ctx,
60 : const char *ifname)
61 : {
62 0 : struct distribute key;
63 0 : struct distribute *dist;
64 :
65 : /* temporary reference */
66 0 : key.ifname = (ifname) ? XSTRDUP(MTYPE_DISTRIBUTE_IFNAME, ifname) : NULL;
67 :
68 0 : dist = hash_lookup(ctx->disthash, &key);
69 :
70 0 : XFREE(MTYPE_DISTRIBUTE_IFNAME, key.ifname);
71 :
72 0 : return dist;
73 : }
74 :
75 0 : void distribute_list_add_hook(struct distribute_ctx *ctx,
76 : void (*func)(struct distribute_ctx *ctx,
77 : struct distribute *))
78 : {
79 0 : ctx->distribute_add_hook = func;
80 0 : }
81 :
82 0 : void distribute_list_delete_hook(struct distribute_ctx *ctx,
83 : void (*func)(struct distribute_ctx *ctx,
84 : struct distribute *))
85 : {
86 0 : ctx->distribute_delete_hook = func;
87 0 : }
88 :
89 0 : static void *distribute_hash_alloc(struct distribute *arg)
90 : {
91 0 : struct distribute *dist;
92 :
93 0 : dist = distribute_new();
94 0 : if (arg->ifname)
95 0 : dist->ifname = XSTRDUP(MTYPE_DISTRIBUTE_IFNAME, arg->ifname);
96 : else
97 0 : dist->ifname = NULL;
98 0 : return dist;
99 : }
100 :
101 : /* Make new distribute list and push into hash. */
102 0 : static struct distribute *distribute_get(struct distribute_ctx *ctx,
103 : const char *ifname)
104 : {
105 0 : struct distribute key;
106 0 : struct distribute *ret;
107 :
108 : /* temporary reference */
109 0 : key.ifname = (ifname) ? XSTRDUP(MTYPE_DISTRIBUTE_IFNAME, ifname) : NULL;
110 :
111 0 : ret = hash_get(ctx->disthash, &key,
112 : (void *(*)(void *))distribute_hash_alloc);
113 :
114 0 : XFREE(MTYPE_DISTRIBUTE_IFNAME, key.ifname);
115 :
116 0 : return ret;
117 : }
118 :
119 0 : static unsigned int distribute_hash_make(const void *arg)
120 : {
121 0 : const struct distribute *dist = arg;
122 :
123 0 : return dist->ifname ? string_hash_make(dist->ifname) : 0;
124 : }
125 :
126 : /* If two distribute-list have same value then return 1 else return
127 : 0. This function is used by hash package. */
128 0 : static bool distribute_cmp(const struct distribute *dist1,
129 : const struct distribute *dist2)
130 : {
131 0 : if (dist1->ifname && dist2->ifname)
132 0 : if (strcmp(dist1->ifname, dist2->ifname) == 0)
133 : return true;
134 0 : if (!dist1->ifname && !dist2->ifname)
135 0 : return true;
136 : return false;
137 : }
138 :
139 : /* Set access-list name to the distribute list. */
140 0 : static void distribute_list_set(struct distribute_ctx *ctx,
141 : const char *ifname, enum distribute_type type,
142 : const char *alist_name)
143 : {
144 0 : struct distribute *dist;
145 :
146 0 : dist = distribute_get(ctx, ifname);
147 :
148 0 : XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[type]);
149 0 : dist->list[type] = XSTRDUP(MTYPE_DISTRIBUTE_NAME, alist_name);
150 :
151 : /* Apply this distribute-list to the interface. */
152 0 : (ctx->distribute_add_hook)(ctx, dist);
153 0 : }
154 :
155 : /* Unset distribute-list. If matched distribute-list exist then
156 : return 1. */
157 0 : static int distribute_list_unset(struct distribute_ctx *ctx,
158 : const char *ifname,
159 : enum distribute_type type,
160 : const char *alist_name)
161 : {
162 0 : struct distribute *dist;
163 :
164 0 : dist = distribute_lookup(ctx, ifname);
165 0 : if (!dist)
166 : return 0;
167 :
168 0 : if (!dist->list[type])
169 : return 0;
170 0 : if (strcmp(dist->list[type], alist_name) != 0)
171 : return 0;
172 :
173 0 : XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[type]);
174 :
175 : /* Apply this distribute-list to the interface. */
176 0 : (ctx->distribute_delete_hook)(ctx, dist);
177 :
178 : /* If all dist are NULL, then free distribute list. */
179 0 : distribute_free_if_empty(ctx, dist);
180 0 : return 1;
181 : }
182 :
183 : /* Set access-list name to the distribute list. */
184 0 : static void distribute_list_prefix_set(struct distribute_ctx *ctx,
185 : const char *ifname,
186 : enum distribute_type type,
187 : const char *plist_name)
188 : {
189 0 : struct distribute *dist;
190 :
191 0 : dist = distribute_get(ctx, ifname);
192 :
193 0 : XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[type]);
194 0 : dist->prefix[type] = XSTRDUP(MTYPE_DISTRIBUTE_NAME, plist_name);
195 :
196 : /* Apply this distribute-list to the interface. */
197 0 : (ctx->distribute_add_hook)(ctx, dist);
198 0 : }
199 :
200 : /* Unset distribute-list. If matched distribute-list exist then
201 : return 1. */
202 0 : static int distribute_list_prefix_unset(struct distribute_ctx *ctx,
203 : const char *ifname,
204 : enum distribute_type type,
205 : const char *plist_name)
206 : {
207 0 : struct distribute *dist;
208 :
209 0 : dist = distribute_lookup(ctx, ifname);
210 0 : if (!dist)
211 : return 0;
212 :
213 0 : if (!dist->prefix[type])
214 : return 0;
215 0 : if (strcmp(dist->prefix[type], plist_name) != 0)
216 : return 0;
217 :
218 0 : XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[type]);
219 :
220 : /* Apply this distribute-list to the interface. */
221 0 : (ctx->distribute_delete_hook)(ctx, dist);
222 :
223 : /* If all dist are NULL, then free distribute list. */
224 0 : distribute_free_if_empty(ctx, dist);
225 0 : return 1;
226 : }
227 :
228 0 : static enum distribute_type distribute_direction(const char *dir, bool v4)
229 : {
230 0 : if (dir[0] == 'i') {
231 0 : if (v4)
232 : return DISTRIBUTE_V4_IN;
233 : else
234 0 : return DISTRIBUTE_V6_IN;
235 0 : } else if (dir[0] == 'o') {
236 0 : if (v4)
237 : return DISTRIBUTE_V4_OUT;
238 : else
239 0 : return DISTRIBUTE_V6_OUT;
240 : }
241 :
242 0 : assert(!"Expecting in or out only, fix your code");
243 :
244 : __builtin_unreachable();
245 : }
246 :
247 0 : int distribute_list_parser(bool prefix, bool v4, const char *dir,
248 : const char *list, const char *ifname)
249 : {
250 0 : enum distribute_type type = distribute_direction(dir, v4);
251 0 : struct distribute_ctx *ctx = listnode_head(dist_ctx_list);
252 :
253 0 : void (*distfn)(struct distribute_ctx *, const char *,
254 : enum distribute_type, const char *) =
255 0 : prefix ? &distribute_list_prefix_set : &distribute_list_set;
256 :
257 0 : distfn(ctx, ifname, type, list);
258 :
259 0 : return CMD_SUCCESS;
260 : }
261 :
262 0 : int distribute_list_no_parser(struct vty *vty, bool prefix, bool v4,
263 : const char *dir, const char *list,
264 : const char *ifname)
265 : {
266 0 : enum distribute_type type = distribute_direction(dir, v4);
267 0 : struct distribute_ctx *ctx = listnode_head(dist_ctx_list);
268 0 : int ret;
269 :
270 0 : int (*distfn)(struct distribute_ctx *, const char *,
271 : enum distribute_type, const char *) =
272 0 : prefix ? &distribute_list_prefix_unset : &distribute_list_unset;
273 :
274 :
275 0 : ret = distfn(ctx, ifname, type, list);
276 0 : if (!ret) {
277 0 : vty_out(vty, "distribute list doesn't exist\n");
278 0 : return CMD_WARNING_CONFIG_FAILED;
279 : }
280 :
281 : return CMD_SUCCESS;
282 : }
283 :
284 0 : static int distribute_print(struct vty *vty, char *tab[], int is_prefix,
285 : enum distribute_type type, int has_print)
286 : {
287 0 : if (tab[type]) {
288 0 : vty_out(vty, "%s %s%s", has_print ? "," : "",
289 : is_prefix ? "(prefix-list) " : "", tab[type]);
290 0 : return 1;
291 : }
292 : return has_print;
293 : }
294 :
295 0 : int config_show_distribute(struct vty *vty, struct distribute_ctx *dist_ctxt)
296 : {
297 0 : unsigned int i;
298 0 : int has_print = 0;
299 0 : struct hash_bucket *mp;
300 0 : struct distribute *dist;
301 :
302 : /* Output filter configuration. */
303 0 : dist = distribute_lookup(dist_ctxt, NULL);
304 0 : vty_out(vty, " Outgoing update filter list for all interface is");
305 0 : has_print = 0;
306 0 : if (dist) {
307 0 : has_print = distribute_print(vty, dist->list, 0,
308 : DISTRIBUTE_V4_OUT, has_print);
309 0 : has_print = distribute_print(vty, dist->prefix, 1,
310 : DISTRIBUTE_V4_OUT, has_print);
311 0 : has_print = distribute_print(vty, dist->list, 0,
312 : DISTRIBUTE_V6_OUT, has_print);
313 0 : has_print = distribute_print(vty, dist->prefix, 1,
314 : DISTRIBUTE_V6_OUT, has_print);
315 : }
316 0 : if (has_print)
317 0 : vty_out(vty, "\n");
318 : else
319 0 : vty_out(vty, " not set\n");
320 :
321 0 : for (i = 0; i < dist_ctxt->disthash->size; i++)
322 0 : for (mp = dist_ctxt->disthash->index[i]; mp; mp = mp->next) {
323 0 : dist = mp->data;
324 0 : if (dist->ifname) {
325 0 : vty_out(vty, " %s filtered by",
326 : dist->ifname);
327 0 : has_print = 0;
328 0 : has_print = distribute_print(vty, dist->list, 0,
329 : DISTRIBUTE_V4_OUT,
330 : has_print);
331 0 : has_print = distribute_print(
332 0 : vty, dist->prefix, 1, DISTRIBUTE_V4_OUT,
333 : has_print);
334 0 : has_print = distribute_print(vty, dist->list, 0,
335 : DISTRIBUTE_V6_OUT,
336 : has_print);
337 0 : has_print = distribute_print(
338 : vty, dist->prefix, 1, DISTRIBUTE_V6_OUT,
339 : has_print);
340 0 : if (has_print)
341 0 : vty_out(vty, "\n");
342 : else
343 0 : vty_out(vty, " nothing\n");
344 : }
345 : }
346 :
347 :
348 : /* Input filter configuration. */
349 0 : dist = distribute_lookup(dist_ctxt, NULL);
350 0 : vty_out(vty, " Incoming update filter list for all interface is");
351 0 : has_print = 0;
352 0 : if (dist) {
353 0 : has_print = distribute_print(vty, dist->list, 0,
354 : DISTRIBUTE_V4_IN, has_print);
355 0 : has_print = distribute_print(vty, dist->prefix, 1,
356 : DISTRIBUTE_V4_IN, has_print);
357 0 : has_print = distribute_print(vty, dist->list, 0,
358 : DISTRIBUTE_V6_IN, has_print);
359 0 : has_print = distribute_print(vty, dist->prefix, 1,
360 : DISTRIBUTE_V6_IN, has_print);
361 : }
362 0 : if (has_print)
363 0 : vty_out(vty, "\n");
364 : else
365 0 : vty_out(vty, " not set\n");
366 :
367 0 : for (i = 0; i < dist_ctxt->disthash->size; i++)
368 0 : for (mp = dist_ctxt->disthash->index[i]; mp; mp = mp->next) {
369 0 : dist = mp->data;
370 0 : if (dist->ifname) {
371 0 : vty_out(vty, " %s filtered by",
372 : dist->ifname);
373 0 : has_print = 0;
374 0 : has_print = distribute_print(vty, dist->list, 0,
375 : DISTRIBUTE_V4_IN,
376 : has_print);
377 0 : has_print = distribute_print(
378 0 : vty, dist->prefix, 1, DISTRIBUTE_V4_IN,
379 : has_print);
380 0 : has_print = distribute_print(vty, dist->list, 0,
381 : DISTRIBUTE_V6_IN,
382 : has_print);
383 0 : has_print = distribute_print(
384 : vty, dist->prefix, 1, DISTRIBUTE_V6_IN,
385 : has_print);
386 0 : if (has_print)
387 0 : vty_out(vty, "\n");
388 : else
389 0 : vty_out(vty, " nothing\n");
390 : }
391 : }
392 0 : return 0;
393 : }
394 :
395 : /* Configuration write function. */
396 0 : int config_write_distribute(struct vty *vty,
397 : struct distribute_ctx *dist_ctxt)
398 : {
399 0 : unsigned int i;
400 0 : int j;
401 0 : int output, v6;
402 0 : struct hash_bucket *mp;
403 0 : int write = 0;
404 :
405 0 : for (i = 0; i < dist_ctxt->disthash->size; i++)
406 0 : for (mp = dist_ctxt->disthash->index[i]; mp; mp = mp->next) {
407 0 : struct distribute *dist;
408 :
409 0 : dist = mp->data;
410 :
411 0 : for (j = 0; j < DISTRIBUTE_MAX; j++)
412 0 : if (dist->list[j]) {
413 0 : output = j == DISTRIBUTE_V4_OUT
414 0 : || j == DISTRIBUTE_V6_OUT;
415 0 : v6 = j == DISTRIBUTE_V6_IN
416 0 : || j == DISTRIBUTE_V6_OUT;
417 0 : vty_out(vty,
418 : " %sdistribute-list %s %s %s\n",
419 : v6 ? "ipv6 " : "",
420 : dist->list[j],
421 : output ? "out" : "in",
422 0 : dist->ifname ? dist->ifname
423 : : "");
424 0 : write++;
425 : }
426 :
427 0 : for (j = 0; j < DISTRIBUTE_MAX; j++)
428 0 : if (dist->prefix[j]) {
429 0 : output = j == DISTRIBUTE_V4_OUT
430 0 : || j == DISTRIBUTE_V6_OUT;
431 0 : v6 = j == DISTRIBUTE_V6_IN
432 0 : || j == DISTRIBUTE_V6_OUT;
433 0 : vty_out(vty,
434 : " %sdistribute-list prefix %s %s %s\n",
435 : v6 ? "ipv6 " : "",
436 : dist->prefix[j],
437 : output ? "out" : "in",
438 0 : dist->ifname ? dist->ifname
439 : : "");
440 0 : write++;
441 : }
442 : }
443 0 : return write;
444 : }
445 :
446 0 : void distribute_list_delete(struct distribute_ctx **ctx)
447 : {
448 0 : hash_clean_and_free(&(*ctx)->disthash,
449 : (void (*)(void *))distribute_free);
450 :
451 0 : if (dist_ctx_list) {
452 0 : listnode_delete(dist_ctx_list, *ctx);
453 0 : if (list_isempty(dist_ctx_list))
454 0 : list_delete(&dist_ctx_list);
455 : }
456 :
457 0 : XFREE(MTYPE_DISTRIBUTE_CTX, (*ctx));
458 0 : }
459 :
460 : /* Initialize distribute list container */
461 0 : struct distribute_ctx *distribute_list_ctx_create(struct vrf *vrf)
462 : {
463 0 : struct distribute_ctx *ctx;
464 :
465 0 : ctx = XCALLOC(MTYPE_DISTRIBUTE_CTX, sizeof(struct distribute_ctx));
466 0 : ctx->vrf = vrf;
467 0 : ctx->disthash = hash_create(
468 : distribute_hash_make,
469 : (bool (*)(const void *, const void *))distribute_cmp, NULL);
470 0 : if (!dist_ctx_list)
471 0 : dist_ctx_list = list_new();
472 0 : listnode_add(dist_ctx_list, ctx);
473 0 : return ctx;
474 : }
|