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