]>
Commit | Line | Data |
---|---|---|
a94434b6 | 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 | * | |
896014f4 DL |
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 | |
a94434b6 | 19 | */ |
20 | ||
d62a17ae | 21 | /* RIPng support by Vincent Jardin <vincent.jardin@6wind.com> |
22 | * Copyright (C) 2002 6WIND | |
23 | */ | |
a94434b6 | 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 | ||
6ac29a51 PJ |
34 | #include "ripngd/ripngd.h" |
35 | ||
a94434b6 | 36 | #define RIPNG_OFFSET_LIST_IN 0 |
37 | #define RIPNG_OFFSET_LIST_OUT 1 | |
38 | #define RIPNG_OFFSET_LIST_MAX 2 | |
39 | ||
d62a17ae | 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]; | |
a94434b6 | 48 | }; |
49 | ||
50 | static struct list *ripng_offset_list_master; | |
51 | ||
d62a17ae | 52 | static int strcmp_safe(const char *s1, const char *s2) |
a94434b6 | 53 | { |
d62a17ae | 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); | |
a94434b6 | 61 | } |
62 | ||
d62a17ae | 63 | static struct ripng_offset_list *ripng_offset_list_new(void) |
a94434b6 | 64 | { |
d62a17ae | 65 | struct ripng_offset_list *new; |
a94434b6 | 66 | |
d62a17ae | 67 | new = XCALLOC(MTYPE_RIPNG_OFFSET_LIST, |
68 | sizeof(struct ripng_offset_list)); | |
69 | return new; | |
a94434b6 | 70 | } |
71 | ||
d62a17ae | 72 | static void ripng_offset_list_free(struct ripng_offset_list *offset) |
a94434b6 | 73 | { |
d62a17ae | 74 | XFREE(MTYPE_RIPNG_OFFSET_LIST, offset); |
a94434b6 | 75 | } |
76 | ||
d62a17ae | 77 | static struct ripng_offset_list *ripng_offset_list_lookup(const char *ifname) |
a94434b6 | 78 | { |
d62a17ae | 79 | struct ripng_offset_list *offset; |
80 | struct listnode *node, *nnode; | |
a94434b6 | 81 | |
d62a17ae | 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; | |
a94434b6 | 87 | } |
88 | ||
d62a17ae | 89 | static struct ripng_offset_list *ripng_offset_list_get(const char *ifname) |
a94434b6 | 90 | { |
d62a17ae | 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; | |
a94434b6 | 103 | } |
104 | ||
d62a17ae | 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) | |
a94434b6 | 108 | { |
d62a17ae | 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; | |
a94434b6 | 139 | } |
140 | ||
d62a17ae | 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) | |
a94434b6 | 144 | { |
d62a17ae | 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; | |
a94434b6 | 185 | } |
d62a17ae | 186 | return CMD_SUCCESS; |
a94434b6 | 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. */ | |
d62a17ae | 196 | int ripng_offset_list_apply_in(struct prefix_ipv6 *p, struct interface *ifp, |
d7c0a89a | 197 | uint8_t *metric) |
a94434b6 | 198 | { |
d62a17ae | 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; | |
a94434b6 | 215 | } |
d62a17ae | 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; | |
a94434b6 | 229 | } |
d62a17ae | 230 | return 0; |
a94434b6 | 231 | } |
232 | ||
233 | /* If metric is modifed return 1. */ | |
d62a17ae | 234 | int ripng_offset_list_apply_out(struct prefix_ipv6 *p, struct interface *ifp, |
d7c0a89a | 235 | uint8_t *metric) |
a94434b6 | 236 | { |
d62a17ae | 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; | |
a94434b6 | 253 | } |
d62a17ae | 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; | |
a94434b6 | 268 | } |
d62a17ae | 269 | return 0; |
a94434b6 | 270 | } |
271 | ||
272 | DEFUN (ripng_offset_list, | |
273 | ripng_offset_list_cmd, | |
6147e2c6 | 274 | "offset-list WORD <in|out> (0-16)", |
a94434b6 | 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 | { | |
d62a17ae | 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); | |
a94434b6 | 287 | } |
288 | ||
289 | DEFUN (ripng_offset_list_ifname, | |
290 | ripng_offset_list_ifname_cmd, | |
6147e2c6 | 291 | "offset-list WORD <in|out> (0-16) IFNAME", |
a94434b6 | 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 | { | |
d62a17ae | 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); | |
a94434b6 | 306 | } |
307 | ||
308 | DEFUN (no_ripng_offset_list, | |
309 | no_ripng_offset_list_cmd, | |
6147e2c6 | 310 | "no offset-list WORD <in|out> (0-16)", |
a94434b6 | 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 | { | |
d62a17ae | 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); | |
a94434b6 | 324 | } |
325 | ||
326 | DEFUN (no_ripng_offset_list_ifname, | |
327 | no_ripng_offset_list_ifname_cmd, | |
6147e2c6 | 328 | "no offset-list WORD <in|out> (0-16) IFNAME", |
a94434b6 | 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 | { | |
d62a17ae | 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); | |
a94434b6 | 344 | } |
345 | ||
d62a17ae | 346 | static int offset_list_cmp(struct ripng_offset_list *o1, |
347 | struct ripng_offset_list *o2) | |
a94434b6 | 348 | { |
d62a17ae | 349 | return strcmp_safe(o1->ifname, o2->ifname); |
a94434b6 | 350 | } |
351 | ||
d62a17ae | 352 | static void offset_list_del(struct ripng_offset_list *offset) |
a94434b6 | 353 | { |
d62a17ae | 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); | |
a94434b6 | 361 | } |
362 | ||
d62a17ae | 363 | void ripng_offset_init(void) |
a94434b6 | 364 | { |
d62a17ae | 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); | |
a94434b6 | 374 | } |
375 | ||
d62a17ae | 376 | void ripng_offset_clean(void) |
a94434b6 | 377 | { |
6a154c88 | 378 | list_delete(&ripng_offset_list_master); |
a94434b6 | 379 | |
d62a17ae | 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; | |
a94434b6 | 384 | } |
385 | ||
d62a17ae | 386 | int config_write_ripng_offset_list(struct vty *vty) |
a94434b6 | 387 | { |
d62a17ae | 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 | } | |
a94434b6 | 421 | } |
a94434b6 | 422 | |
d62a17ae | 423 | return 0; |
a94434b6 | 424 | } |