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