]> git.proxmox.com Git - mirror_frr.git/blob - ripngd/ripng_offset.c
release: FRR 3.0-rc1
[mirror_frr.git] / ripngd / ripng_offset.c
1 /* RIPng offset-list
2 * Copyright (C) 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
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
17 * along with GNU Zebra; see the file COPYING. If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
22 /* RIPng support by Vincent Jardin <vincent.jardin@6wind.com>
23 * Copyright (C) 2002 6WIND
24 */
25
26 #include <zebra.h>
27
28 #include "if.h"
29 #include "prefix.h"
30 #include "filter.h"
31 #include "command.h"
32 #include "linklist.h"
33 #include "memory.h"
34
35 #include "ripngd/ripngd.h"
36
37 #define RIPNG_OFFSET_LIST_IN 0
38 #define RIPNG_OFFSET_LIST_OUT 1
39 #define RIPNG_OFFSET_LIST_MAX 2
40
41 struct ripng_offset_list {
42 char *ifname;
43
44 struct {
45 char *alist_name;
46 /* struct access_list *alist; */
47 int metric;
48 } direct[RIPNG_OFFSET_LIST_MAX];
49 };
50
51 static struct list *ripng_offset_list_master;
52
53 static int strcmp_safe(const char *s1, const char *s2)
54 {
55 if (s1 == NULL && s2 == NULL)
56 return 0;
57 if (s1 == NULL)
58 return -1;
59 if (s2 == NULL)
60 return 1;
61 return strcmp(s1, s2);
62 }
63
64 static struct ripng_offset_list *ripng_offset_list_new(void)
65 {
66 struct ripng_offset_list *new;
67
68 new = XCALLOC(MTYPE_RIPNG_OFFSET_LIST,
69 sizeof(struct ripng_offset_list));
70 return new;
71 }
72
73 static void ripng_offset_list_free(struct ripng_offset_list *offset)
74 {
75 XFREE(MTYPE_RIPNG_OFFSET_LIST, offset);
76 }
77
78 static struct ripng_offset_list *ripng_offset_list_lookup(const char *ifname)
79 {
80 struct ripng_offset_list *offset;
81 struct listnode *node, *nnode;
82
83 for (ALL_LIST_ELEMENTS(ripng_offset_list_master, node, nnode, offset)) {
84 if (strcmp_safe(offset->ifname, ifname) == 0)
85 return offset;
86 }
87 return NULL;
88 }
89
90 static struct ripng_offset_list *ripng_offset_list_get(const char *ifname)
91 {
92 struct ripng_offset_list *offset;
93
94 offset = ripng_offset_list_lookup(ifname);
95 if (offset)
96 return offset;
97
98 offset = ripng_offset_list_new();
99 if (ifname)
100 offset->ifname = strdup(ifname);
101 listnode_add_sort(ripng_offset_list_master, offset);
102
103 return offset;
104 }
105
106 static int ripng_offset_list_set(struct vty *vty, const char *alist,
107 const char *direct_str, const char *metric_str,
108 const char *ifname)
109 {
110 int direct;
111 int metric;
112 struct ripng_offset_list *offset;
113
114 /* Check direction. */
115 if (strncmp(direct_str, "i", 1) == 0)
116 direct = RIPNG_OFFSET_LIST_IN;
117 else if (strncmp(direct_str, "o", 1) == 0)
118 direct = RIPNG_OFFSET_LIST_OUT;
119 else {
120 vty_out(vty, "Invalid direction: %s%s", direct_str,
121 VTY_NEWLINE);
122 return CMD_WARNING;
123 }
124
125 /* Check metric. */
126 metric = atoi(metric_str);
127 if (metric < 0 || metric > 16) {
128 vty_out(vty, "Invalid metric: %s%s", metric_str, VTY_NEWLINE);
129 return CMD_WARNING;
130 }
131
132 /* Get offset-list structure with interface name. */
133 offset = ripng_offset_list_get(ifname);
134
135 if (offset->direct[direct].alist_name)
136 free(offset->direct[direct].alist_name);
137 offset->direct[direct].alist_name = strdup(alist);
138 offset->direct[direct].metric = metric;
139
140 return CMD_SUCCESS;
141 }
142
143 static int ripng_offset_list_unset(struct vty *vty, const char *alist,
144 const char *direct_str,
145 const char *metric_str, const char *ifname)
146 {
147 int direct;
148 int metric;
149 struct ripng_offset_list *offset;
150
151 /* Check direction. */
152 if (strncmp(direct_str, "i", 1) == 0)
153 direct = RIPNG_OFFSET_LIST_IN;
154 else if (strncmp(direct_str, "o", 1) == 0)
155 direct = RIPNG_OFFSET_LIST_OUT;
156 else {
157 vty_out(vty, "Invalid direction: %s%s", direct_str,
158 VTY_NEWLINE);
159 return CMD_WARNING;
160 }
161
162 /* Check metric. */
163 metric = atoi(metric_str);
164 if (metric < 0 || metric > 16) {
165 vty_out(vty, "Invalid metric: %s%s", metric_str, VTY_NEWLINE);
166 return CMD_WARNING;
167 }
168
169 /* Get offset-list structure with interface name. */
170 offset = ripng_offset_list_lookup(ifname);
171
172 if (offset) {
173 if (offset->direct[direct].alist_name)
174 free(offset->direct[direct].alist_name);
175 offset->direct[direct].alist_name = NULL;
176
177 if (offset->direct[RIPNG_OFFSET_LIST_IN].alist_name == NULL
178 && offset->direct[RIPNG_OFFSET_LIST_OUT].alist_name
179 == NULL) {
180 listnode_delete(ripng_offset_list_master, offset);
181 if (offset->ifname)
182 free(offset->ifname);
183 ripng_offset_list_free(offset);
184 }
185 } else {
186 vty_out(vty, "Can't find offset-list%s", VTY_NEWLINE);
187 return CMD_WARNING;
188 }
189 return CMD_SUCCESS;
190 }
191
192 #define OFFSET_LIST_IN_NAME(O) ((O)->direct[RIPNG_OFFSET_LIST_IN].alist_name)
193 #define OFFSET_LIST_IN_METRIC(O) ((O)->direct[RIPNG_OFFSET_LIST_IN].metric)
194
195 #define OFFSET_LIST_OUT_NAME(O) ((O)->direct[RIPNG_OFFSET_LIST_OUT].alist_name)
196 #define OFFSET_LIST_OUT_METRIC(O) ((O)->direct[RIPNG_OFFSET_LIST_OUT].metric)
197
198 /* If metric is modifed return 1. */
199 int ripng_offset_list_apply_in(struct prefix_ipv6 *p, struct interface *ifp,
200 u_char *metric)
201 {
202 struct ripng_offset_list *offset;
203 struct access_list *alist;
204
205 /* Look up offset-list with interface name. */
206 offset = ripng_offset_list_lookup(ifp->name);
207 if (offset && OFFSET_LIST_IN_NAME(offset)) {
208 alist = access_list_lookup(AFI_IP6,
209 OFFSET_LIST_IN_NAME(offset));
210
211 if (alist
212 && access_list_apply(alist, (struct prefix *)p)
213 == FILTER_PERMIT) {
214 *metric += OFFSET_LIST_IN_METRIC(offset);
215 return 1;
216 }
217 return 0;
218 }
219 /* Look up offset-list without interface name. */
220 offset = ripng_offset_list_lookup(NULL);
221 if (offset && OFFSET_LIST_IN_NAME(offset)) {
222 alist = access_list_lookup(AFI_IP6,
223 OFFSET_LIST_IN_NAME(offset));
224
225 if (alist
226 && access_list_apply(alist, (struct prefix *)p)
227 == FILTER_PERMIT) {
228 *metric += OFFSET_LIST_IN_METRIC(offset);
229 return 1;
230 }
231 return 0;
232 }
233 return 0;
234 }
235
236 /* If metric is modifed return 1. */
237 int ripng_offset_list_apply_out(struct prefix_ipv6 *p, struct interface *ifp,
238 u_char *metric)
239 {
240 struct ripng_offset_list *offset;
241 struct access_list *alist;
242
243 /* Look up offset-list with interface name. */
244 offset = ripng_offset_list_lookup(ifp->name);
245 if (offset && OFFSET_LIST_OUT_NAME(offset)) {
246 alist = access_list_lookup(AFI_IP6,
247 OFFSET_LIST_OUT_NAME(offset));
248
249 if (alist
250 && access_list_apply(alist, (struct prefix *)p)
251 == FILTER_PERMIT) {
252 *metric += OFFSET_LIST_OUT_METRIC(offset);
253 return 1;
254 }
255 return 0;
256 }
257
258 /* Look up offset-list without interface name. */
259 offset = ripng_offset_list_lookup(NULL);
260 if (offset && OFFSET_LIST_OUT_NAME(offset)) {
261 alist = access_list_lookup(AFI_IP6,
262 OFFSET_LIST_OUT_NAME(offset));
263
264 if (alist
265 && access_list_apply(alist, (struct prefix *)p)
266 == FILTER_PERMIT) {
267 *metric += OFFSET_LIST_OUT_METRIC(offset);
268 return 1;
269 }
270 return 0;
271 }
272 return 0;
273 }
274
275 DEFUN (ripng_offset_list,
276 ripng_offset_list_cmd,
277 "offset-list WORD <in|out> (0-16)",
278 "Modify RIPng metric\n"
279 "Access-list name\n"
280 "For incoming updates\n"
281 "For outgoing updates\n"
282 "Metric value\n")
283 {
284 int idx_word = 1;
285 int idx_in_out = 2;
286 int idx_number = 3;
287 return ripng_offset_list_set(vty, argv[idx_word]->arg,
288 argv[idx_in_out]->arg,
289 argv[idx_number]->arg, NULL);
290 }
291
292 DEFUN (ripng_offset_list_ifname,
293 ripng_offset_list_ifname_cmd,
294 "offset-list WORD <in|out> (0-16) IFNAME",
295 "Modify RIPng metric\n"
296 "Access-list name\n"
297 "For incoming updates\n"
298 "For outgoing updates\n"
299 "Metric value\n"
300 "Interface to match\n")
301 {
302 int idx_word = 1;
303 int idx_in_out = 2;
304 int idx_number = 3;
305 int idx_ifname = 4;
306 return ripng_offset_list_set(
307 vty, argv[idx_word]->arg, argv[idx_in_out]->arg,
308 argv[idx_number]->arg, argv[idx_ifname]->arg);
309 }
310
311 DEFUN (no_ripng_offset_list,
312 no_ripng_offset_list_cmd,
313 "no offset-list WORD <in|out> (0-16)",
314 NO_STR
315 "Modify RIPng metric\n"
316 "Access-list name\n"
317 "For incoming updates\n"
318 "For outgoing updates\n"
319 "Metric value\n")
320 {
321 int idx_word = 2;
322 int idx_in_out = 3;
323 int idx_number = 4;
324 return ripng_offset_list_unset(vty, argv[idx_word]->arg,
325 argv[idx_in_out]->arg,
326 argv[idx_number]->arg, NULL);
327 }
328
329 DEFUN (no_ripng_offset_list_ifname,
330 no_ripng_offset_list_ifname_cmd,
331 "no offset-list WORD <in|out> (0-16) IFNAME",
332 NO_STR
333 "Modify RIPng metric\n"
334 "Access-list name\n"
335 "For incoming updates\n"
336 "For outgoing updates\n"
337 "Metric value\n"
338 "Interface to match\n")
339 {
340 int idx_word = 2;
341 int idx_in_out = 3;
342 int idx_number = 4;
343 int idx_ifname = 5;
344 return ripng_offset_list_unset(
345 vty, argv[idx_word]->arg, argv[idx_in_out]->arg,
346 argv[idx_number]->arg, argv[idx_ifname]->arg);
347 }
348
349 static int offset_list_cmp(struct ripng_offset_list *o1,
350 struct ripng_offset_list *o2)
351 {
352 return strcmp_safe(o1->ifname, o2->ifname);
353 }
354
355 static void offset_list_del(struct ripng_offset_list *offset)
356 {
357 if (OFFSET_LIST_IN_NAME(offset))
358 free(OFFSET_LIST_IN_NAME(offset));
359 if (OFFSET_LIST_OUT_NAME(offset))
360 free(OFFSET_LIST_OUT_NAME(offset));
361 if (offset->ifname)
362 free(offset->ifname);
363 ripng_offset_list_free(offset);
364 }
365
366 void ripng_offset_init(void)
367 {
368 ripng_offset_list_master = list_new();
369 ripng_offset_list_master->cmp =
370 (int (*)(void *, void *))offset_list_cmp;
371 ripng_offset_list_master->del = (void (*)(void *))offset_list_del;
372
373 install_element(RIPNG_NODE, &ripng_offset_list_cmd);
374 install_element(RIPNG_NODE, &ripng_offset_list_ifname_cmd);
375 install_element(RIPNG_NODE, &no_ripng_offset_list_cmd);
376 install_element(RIPNG_NODE, &no_ripng_offset_list_ifname_cmd);
377 }
378
379 void ripng_offset_clean(void)
380 {
381 list_delete(ripng_offset_list_master);
382
383 ripng_offset_list_master = list_new();
384 ripng_offset_list_master->cmp =
385 (int (*)(void *, void *))offset_list_cmp;
386 ripng_offset_list_master->del = (void (*)(void *))offset_list_del;
387 }
388
389 int config_write_ripng_offset_list(struct vty *vty)
390 {
391 struct listnode *node, *nnode;
392 struct ripng_offset_list *offset;
393
394 for (ALL_LIST_ELEMENTS(ripng_offset_list_master, node, nnode, offset)) {
395 if (!offset->ifname) {
396 if (offset->direct[RIPNG_OFFSET_LIST_IN].alist_name)
397 vty_out(vty, " offset-list %s in %d%s",
398 offset->direct[RIPNG_OFFSET_LIST_IN]
399 .alist_name,
400 offset->direct[RIPNG_OFFSET_LIST_IN]
401 .metric,
402 VTY_NEWLINE);
403 if (offset->direct[RIPNG_OFFSET_LIST_OUT].alist_name)
404 vty_out(vty, " offset-list %s out %d%s",
405 offset->direct[RIPNG_OFFSET_LIST_OUT]
406 .alist_name,
407 offset->direct[RIPNG_OFFSET_LIST_OUT]
408 .metric,
409 VTY_NEWLINE);
410 } else {
411 if (offset->direct[RIPNG_OFFSET_LIST_IN].alist_name)
412 vty_out(vty, " offset-list %s in %d %s%s",
413 offset->direct[RIPNG_OFFSET_LIST_IN]
414 .alist_name,
415 offset->direct[RIPNG_OFFSET_LIST_IN]
416 .metric,
417 offset->ifname, VTY_NEWLINE);
418 if (offset->direct[RIPNG_OFFSET_LIST_OUT].alist_name)
419 vty_out(vty, " offset-list %s out %d %s%s",
420 offset->direct[RIPNG_OFFSET_LIST_OUT]
421 .alist_name,
422 offset->direct[RIPNG_OFFSET_LIST_OUT]
423 .metric,
424 offset->ifname, VTY_NEWLINE);
425 }
426 }
427
428 return 0;
429 }