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