]>
Commit | Line | Data |
---|---|---|
acddc0ed | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
718e3744 | 2 | /* route-map for interface. |
3 | * Copyright (C) 1999 Kunihiro Ishiguro | |
718e3744 | 4 | */ |
5 | ||
6 | #include <zebra.h> | |
7 | ||
8 | #include "hash.h" | |
9 | #include "command.h" | |
10 | #include "memory.h" | |
11 | #include "if.h" | |
0750d21f | 12 | #include "if_rmap.h" |
718e3744 | 13 | |
bf8d3d6a DL |
14 | DEFINE_MTYPE_STATIC(LIB, IF_RMAP_CTX, "Interface route map container"); |
15 | DEFINE_MTYPE_STATIC(LIB, IF_RMAP_CTX_NAME, | |
16 | "Interface route map container name"); | |
17 | DEFINE_MTYPE_STATIC(LIB, IF_RMAP, "Interface route map"); | |
18 | DEFINE_MTYPE_STATIC(LIB, IF_RMAP_NAME, "I.f. route map name"); | |
4a1ab8e4 | 19 | |
c17faa4b | 20 | static struct list *if_rmap_ctx_list; |
6b0655a2 | 21 | |
d62a17ae | 22 | static struct if_rmap *if_rmap_new(void) |
718e3744 | 23 | { |
d62a17ae | 24 | struct if_rmap *new; |
718e3744 | 25 | |
d62a17ae | 26 | new = XCALLOC(MTYPE_IF_RMAP, sizeof(struct if_rmap)); |
718e3744 | 27 | |
d62a17ae | 28 | return new; |
718e3744 | 29 | } |
30 | ||
d62a17ae | 31 | static void if_rmap_free(struct if_rmap *if_rmap) |
718e3744 | 32 | { |
0a22ddfb | 33 | XFREE(MTYPE_IF_RMAP_NAME, if_rmap->ifname); |
718e3744 | 34 | |
0a22ddfb QY |
35 | XFREE(MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_IN]); |
36 | XFREE(MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_OUT]); | |
718e3744 | 37 | |
d62a17ae | 38 | XFREE(MTYPE_IF_RMAP, if_rmap); |
718e3744 | 39 | } |
40 | ||
4b23867c | 41 | struct if_rmap *if_rmap_lookup(struct if_rmap_ctx *ctx, const char *ifname) |
718e3744 | 42 | { |
d62a17ae | 43 | struct if_rmap key; |
44 | struct if_rmap *if_rmap; | |
718e3744 | 45 | |
d62a17ae | 46 | /* temporary copy */ |
47 | key.ifname = (ifname) ? XSTRDUP(MTYPE_IF_RMAP_NAME, ifname) : NULL; | |
718e3744 | 48 | |
4b23867c | 49 | if_rmap = hash_lookup(ctx->ifrmaphash, &key); |
3a7c85d1 | 50 | |
0a22ddfb | 51 | XFREE(MTYPE_IF_RMAP_NAME, key.ifname); |
d62a17ae | 52 | |
53 | return if_rmap; | |
718e3744 | 54 | } |
55 | ||
4b23867c PG |
56 | void if_rmap_hook_add(struct if_rmap_ctx *ctx, |
57 | void (*func)(struct if_rmap_ctx *ctx, | |
58 | struct if_rmap *)) | |
718e3744 | 59 | { |
4b23867c | 60 | ctx->if_rmap_add_hook = func; |
718e3744 | 61 | } |
62 | ||
4b23867c PG |
63 | void if_rmap_hook_delete(struct if_rmap_ctx *ctx, |
64 | void (*func)(struct if_rmap_ctx *ctx, | |
65 | struct if_rmap *)) | |
718e3744 | 66 | { |
4b23867c | 67 | ctx->if_rmap_delete_hook = func; |
718e3744 | 68 | } |
69 | ||
d62a17ae | 70 | static void *if_rmap_hash_alloc(void *arg) |
718e3744 | 71 | { |
d62a17ae | 72 | struct if_rmap *ifarg = (struct if_rmap *)arg; |
73 | struct if_rmap *if_rmap; | |
718e3744 | 74 | |
d62a17ae | 75 | if_rmap = if_rmap_new(); |
76 | if_rmap->ifname = XSTRDUP(MTYPE_IF_RMAP_NAME, ifarg->ifname); | |
718e3744 | 77 | |
d62a17ae | 78 | return if_rmap; |
718e3744 | 79 | } |
80 | ||
4b23867c | 81 | static struct if_rmap *if_rmap_get(struct if_rmap_ctx *ctx, const char *ifname) |
718e3744 | 82 | { |
d62a17ae | 83 | struct if_rmap key; |
84 | struct if_rmap *ret; | |
718e3744 | 85 | |
d62a17ae | 86 | /* temporary copy */ |
87 | key.ifname = (ifname) ? XSTRDUP(MTYPE_IF_RMAP_NAME, ifname) : NULL; | |
718e3744 | 88 | |
4b23867c | 89 | ret = hash_get(ctx->ifrmaphash, &key, if_rmap_hash_alloc); |
3a7c85d1 | 90 | |
0a22ddfb | 91 | XFREE(MTYPE_IF_RMAP_NAME, key.ifname); |
24873f0c | 92 | |
d62a17ae | 93 | return ret; |
718e3744 | 94 | } |
95 | ||
d8b87afe | 96 | static unsigned int if_rmap_hash_make(const void *data) |
718e3744 | 97 | { |
d62a17ae | 98 | const struct if_rmap *if_rmap = data; |
718e3744 | 99 | |
d62a17ae | 100 | return string_hash_make(if_rmap->ifname); |
718e3744 | 101 | } |
102 | ||
74df8d6d | 103 | static bool if_rmap_hash_cmp(const void *arg1, const void *arg2) |
718e3744 | 104 | { |
d62a17ae | 105 | const struct if_rmap *if_rmap1 = arg1; |
106 | const struct if_rmap *if_rmap2 = arg2; | |
ffe11cfb | 107 | |
d62a17ae | 108 | return strcmp(if_rmap1->ifname, if_rmap2->ifname) == 0; |
718e3744 | 109 | } |
6b0655a2 | 110 | |
4b23867c PG |
111 | static struct if_rmap *if_rmap_set(struct if_rmap_ctx *ctx, |
112 | const char *ifname, enum if_rmap_type type, | |
d62a17ae | 113 | const char *routemap_name) |
718e3744 | 114 | { |
d62a17ae | 115 | struct if_rmap *if_rmap; |
116 | ||
4b23867c | 117 | if_rmap = if_rmap_get(ctx, ifname); |
d62a17ae | 118 | |
119 | if (type == IF_RMAP_IN) { | |
0a22ddfb | 120 | XFREE(MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_IN]); |
d62a17ae | 121 | if_rmap->routemap[IF_RMAP_IN] = |
122 | XSTRDUP(MTYPE_IF_RMAP_NAME, routemap_name); | |
123 | } | |
124 | if (type == IF_RMAP_OUT) { | |
0a22ddfb | 125 | XFREE(MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_OUT]); |
d62a17ae | 126 | if_rmap->routemap[IF_RMAP_OUT] = |
127 | XSTRDUP(MTYPE_IF_RMAP_NAME, routemap_name); | |
128 | } | |
129 | ||
4b23867c PG |
130 | if (ctx->if_rmap_add_hook) |
131 | (ctx->if_rmap_add_hook)(ctx, if_rmap); | |
d62a17ae | 132 | |
133 | return if_rmap; | |
718e3744 | 134 | } |
135 | ||
4b23867c PG |
136 | static int if_rmap_unset(struct if_rmap_ctx *ctx, |
137 | const char *ifname, enum if_rmap_type type, | |
d62a17ae | 138 | const char *routemap_name) |
718e3744 | 139 | { |
d62a17ae | 140 | struct if_rmap *if_rmap; |
141 | ||
4b23867c | 142 | if_rmap = if_rmap_lookup(ctx, ifname); |
d62a17ae | 143 | if (!if_rmap) |
144 | return 0; | |
145 | ||
146 | if (type == IF_RMAP_IN) { | |
147 | if (!if_rmap->routemap[IF_RMAP_IN]) | |
148 | return 0; | |
149 | if (strcmp(if_rmap->routemap[IF_RMAP_IN], routemap_name) != 0) | |
150 | return 0; | |
151 | ||
152 | XFREE(MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_IN]); | |
d62a17ae | 153 | } |
154 | ||
155 | if (type == IF_RMAP_OUT) { | |
156 | if (!if_rmap->routemap[IF_RMAP_OUT]) | |
157 | return 0; | |
158 | if (strcmp(if_rmap->routemap[IF_RMAP_OUT], routemap_name) != 0) | |
159 | return 0; | |
160 | ||
161 | XFREE(MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_OUT]); | |
d62a17ae | 162 | } |
163 | ||
4b23867c PG |
164 | if (ctx->if_rmap_delete_hook) |
165 | ctx->if_rmap_delete_hook(ctx, if_rmap); | |
d62a17ae | 166 | |
167 | if (if_rmap->routemap[IF_RMAP_IN] == NULL | |
168 | && if_rmap->routemap[IF_RMAP_OUT] == NULL) { | |
4b23867c | 169 | hash_release(ctx->ifrmaphash, if_rmap); |
d62a17ae | 170 | if_rmap_free(if_rmap); |
171 | } | |
172 | ||
173 | return 1; | |
718e3744 | 174 | } |
175 | ||
0750d21f | 176 | DEFUN (if_rmap, |
177 | if_rmap_cmd, | |
6147e2c6 | 178 | "route-map RMAP_NAME <in|out> IFNAME", |
718e3744 | 179 | "Route map set\n" |
180 | "Route map name\n" | |
181 | "Route map set for input filtering\n" | |
182 | "Route map set for output filtering\n" | |
183 | "Route map interface name\n") | |
184 | { | |
d62a17ae | 185 | int idx_rmap_name = 1; |
186 | int idx_in_out = 2; | |
187 | int idx_ifname = 3; | |
188 | enum if_rmap_type type; | |
4b23867c PG |
189 | struct if_rmap_ctx *ctx = |
190 | (struct if_rmap_ctx *)listnode_head(if_rmap_ctx_list); | |
d62a17ae | 191 | |
192 | if (strncmp(argv[idx_in_out]->text, "in", 1) == 0) | |
193 | type = IF_RMAP_IN; | |
194 | else if (strncmp(argv[idx_in_out]->text, "out", 1) == 0) | |
195 | type = IF_RMAP_OUT; | |
196 | else { | |
197 | vty_out(vty, "route-map direction must be [in|out]\n"); | |
198 | return CMD_WARNING_CONFIG_FAILED; | |
199 | } | |
200 | ||
4b23867c PG |
201 | if_rmap_set(ctx, argv[idx_ifname]->arg, |
202 | type, argv[idx_rmap_name]->arg); | |
d62a17ae | 203 | |
204 | return CMD_SUCCESS; | |
c349116d | 205 | } |
4f849479 | 206 | |
0750d21f | 207 | DEFUN (no_if_rmap, |
208 | no_if_rmap_cmd, | |
6147e2c6 | 209 | "no route-map ROUTEMAP_NAME <in|out> IFNAME", |
718e3744 | 210 | NO_STR |
211 | "Route map unset\n" | |
212 | "Route map name\n" | |
213 | "Route map for input filtering\n" | |
214 | "Route map for output filtering\n" | |
215 | "Route map interface name\n") | |
216 | { | |
d62a17ae | 217 | int idx_routemap_name = 2; |
218 | int idx_in_out = 3; | |
219 | int idx_ifname = 4; | |
220 | int ret; | |
221 | enum if_rmap_type type; | |
4b23867c PG |
222 | struct if_rmap_ctx *ctx = |
223 | (struct if_rmap_ctx *)listnode_head(if_rmap_ctx_list); | |
d62a17ae | 224 | |
225 | if (strncmp(argv[idx_in_out]->arg, "i", 1) == 0) | |
226 | type = IF_RMAP_IN; | |
227 | else if (strncmp(argv[idx_in_out]->arg, "o", 1) == 0) | |
228 | type = IF_RMAP_OUT; | |
229 | else { | |
230 | vty_out(vty, "route-map direction must be [in|out]\n"); | |
231 | return CMD_WARNING_CONFIG_FAILED; | |
232 | } | |
233 | ||
4b23867c | 234 | ret = if_rmap_unset(ctx, argv[idx_ifname]->arg, type, |
d62a17ae | 235 | argv[idx_routemap_name]->arg); |
236 | if (!ret) { | |
237 | vty_out(vty, "route-map doesn't exist\n"); | |
238 | return CMD_WARNING_CONFIG_FAILED; | |
239 | } | |
240 | return CMD_SUCCESS; | |
c349116d | 241 | } |
4f849479 | 242 | |
6b0655a2 | 243 | |
718e3744 | 244 | /* Configuration write function. */ |
4b23867c PG |
245 | int config_write_if_rmap(struct vty *vty, |
246 | struct if_rmap_ctx *ctx) | |
718e3744 | 247 | { |
d62a17ae | 248 | unsigned int i; |
e3b78da8 | 249 | struct hash_bucket *mp; |
d62a17ae | 250 | int write = 0; |
4b23867c | 251 | struct hash *ifrmaphash = ctx->ifrmaphash; |
d62a17ae | 252 | |
253 | for (i = 0; i < ifrmaphash->size; i++) | |
254 | for (mp = ifrmaphash->index[i]; mp; mp = mp->next) { | |
255 | struct if_rmap *if_rmap; | |
256 | ||
257 | if_rmap = mp->data; | |
258 | ||
259 | if (if_rmap->routemap[IF_RMAP_IN]) { | |
260 | vty_out(vty, " route-map %s in %s\n", | |
261 | if_rmap->routemap[IF_RMAP_IN], | |
262 | if_rmap->ifname); | |
263 | write++; | |
264 | } | |
265 | ||
266 | if (if_rmap->routemap[IF_RMAP_OUT]) { | |
267 | vty_out(vty, " route-map %s out %s\n", | |
268 | if_rmap->routemap[IF_RMAP_OUT], | |
269 | if_rmap->ifname); | |
270 | write++; | |
271 | } | |
272 | } | |
273 | return write; | |
718e3744 | 274 | } |
275 | ||
4b23867c PG |
276 | void if_rmap_ctx_delete(struct if_rmap_ctx *ctx) |
277 | { | |
cbcbac45 | 278 | listnode_delete(if_rmap_ctx_list, ctx); |
4b23867c | 279 | hash_clean(ctx->ifrmaphash, (void (*)(void *))if_rmap_free); |
aec0d756 PG |
280 | if (ctx->name) |
281 | XFREE(MTYPE_IF_RMAP_CTX_NAME, ctx); | |
4b23867c PG |
282 | XFREE(MTYPE_IF_RMAP_CTX, ctx); |
283 | } | |
284 | ||
aec0d756 PG |
285 | /* name is optional: either vrf name, or other */ |
286 | struct if_rmap_ctx *if_rmap_ctx_create(const char *name) | |
718e3744 | 287 | { |
4b23867c PG |
288 | struct if_rmap_ctx *ctx; |
289 | ||
290 | ctx = XCALLOC(MTYPE_IF_RMAP_CTX, sizeof(struct if_rmap_ctx)); | |
aec0d756 PG |
291 | |
292 | if (ctx->name) | |
293 | ctx->name = XSTRDUP(MTYPE_IF_RMAP_CTX_NAME, name); | |
4b23867c PG |
294 | ctx->ifrmaphash = hash_create_size(4, if_rmap_hash_make, if_rmap_hash_cmp, |
295 | "Interface Route-Map Hash"); | |
296 | if (!if_rmap_ctx_list) | |
297 | if_rmap_ctx_list = list_new(); | |
298 | listnode_add(if_rmap_ctx_list, ctx); | |
299 | return ctx; | |
718e3744 | 300 | } |
301 | ||
d62a17ae | 302 | void if_rmap_init(int node) |
718e3744 | 303 | { |
d62a17ae | 304 | if (node == RIPNG_NODE) { |
305 | } else if (node == RIP_NODE) { | |
306 | install_element(RIP_NODE, &if_rmap_cmd); | |
307 | install_element(RIP_NODE, &no_if_rmap_cmd); | |
308 | } | |
4b23867c PG |
309 | if_rmap_ctx_list = list_new(); |
310 | } | |
311 | ||
312 | void if_rmap_terminate(void) | |
313 | { | |
314 | if (!if_rmap_ctx_list) | |
315 | return; | |
316 | list_delete(&if_rmap_ctx_list); | |
718e3744 | 317 | } |