]>
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 | * | |
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 | |
ac4d0be5 | 19 | * 02111-1307, USA. |
a94434b6 | 20 | */ |
21 | ||
ac4d0be5 | 22 | /* RIPng support by Vincent Jardin <vincent.jardin@6wind.com> |
23 | * Copyright (C) 2002 6WIND | |
24 | */ | |
a94434b6 | 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 | ||
6ac29a51 PJ |
35 | #include "ripngd/ripngd.h" |
36 | ||
a94434b6 | 37 | #define RIPNG_OFFSET_LIST_IN 0 |
38 | #define RIPNG_OFFSET_LIST_OUT 1 | |
39 | #define RIPNG_OFFSET_LIST_MAX 2 | |
40 | ||
ac4d0be5 | 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]; | |
a94434b6 | 49 | }; |
50 | ||
51 | static struct list *ripng_offset_list_master; | |
52 | ||
ac4d0be5 | 53 | static int strcmp_safe(const char *s1, const char *s2) |
a94434b6 | 54 | { |
ac4d0be5 | 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); | |
a94434b6 | 62 | } |
63 | ||
ac4d0be5 | 64 | static struct ripng_offset_list *ripng_offset_list_new(void) |
a94434b6 | 65 | { |
ac4d0be5 | 66 | struct ripng_offset_list *new; |
a94434b6 | 67 | |
ac4d0be5 | 68 | new = XCALLOC(MTYPE_RIPNG_OFFSET_LIST, |
69 | sizeof(struct ripng_offset_list)); | |
70 | return new; | |
a94434b6 | 71 | } |
72 | ||
ac4d0be5 | 73 | static void ripng_offset_list_free(struct ripng_offset_list *offset) |
a94434b6 | 74 | { |
ac4d0be5 | 75 | XFREE(MTYPE_RIPNG_OFFSET_LIST, offset); |
a94434b6 | 76 | } |
77 | ||
ac4d0be5 | 78 | static struct ripng_offset_list *ripng_offset_list_lookup(const char *ifname) |
a94434b6 | 79 | { |
ac4d0be5 | 80 | struct ripng_offset_list *offset; |
81 | struct listnode *node, *nnode; | |
a94434b6 | 82 | |
ac4d0be5 | 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; | |
a94434b6 | 88 | } |
89 | ||
ac4d0be5 | 90 | static struct ripng_offset_list *ripng_offset_list_get(const char *ifname) |
a94434b6 | 91 | { |
ac4d0be5 | 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; | |
a94434b6 | 104 | } |
105 | ||
ac4d0be5 | 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) | |
a94434b6 | 109 | { |
ac4d0be5 | 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; | |
a94434b6 | 141 | } |
142 | ||
ac4d0be5 | 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) | |
a94434b6 | 146 | { |
ac4d0be5 | 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; | |
a94434b6 | 188 | } |
ac4d0be5 | 189 | return CMD_SUCCESS; |
a94434b6 | 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. */ | |
ac4d0be5 | 199 | int ripng_offset_list_apply_in(struct prefix_ipv6 *p, struct interface *ifp, |
200 | u_char *metric) | |
a94434b6 | 201 | { |
ac4d0be5 | 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; | |
a94434b6 | 218 | } |
ac4d0be5 | 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; | |
a94434b6 | 232 | } |
ac4d0be5 | 233 | return 0; |
a94434b6 | 234 | } |
235 | ||
236 | /* If metric is modifed return 1. */ | |
ac4d0be5 | 237 | int ripng_offset_list_apply_out(struct prefix_ipv6 *p, struct interface *ifp, |
238 | u_char *metric) | |
a94434b6 | 239 | { |
ac4d0be5 | 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; | |
a94434b6 | 256 | } |
ac4d0be5 | 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; | |
a94434b6 | 271 | } |
ac4d0be5 | 272 | return 0; |
a94434b6 | 273 | } |
274 | ||
275 | DEFUN (ripng_offset_list, | |
276 | ripng_offset_list_cmd, | |
6147e2c6 | 277 | "offset-list WORD <in|out> (0-16)", |
a94434b6 | 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 | { | |
ac4d0be5 | 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); | |
a94434b6 | 290 | } |
291 | ||
292 | DEFUN (ripng_offset_list_ifname, | |
293 | ripng_offset_list_ifname_cmd, | |
6147e2c6 | 294 | "offset-list WORD <in|out> (0-16) IFNAME", |
a94434b6 | 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 | { | |
ac4d0be5 | 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); | |
a94434b6 | 309 | } |
310 | ||
311 | DEFUN (no_ripng_offset_list, | |
312 | no_ripng_offset_list_cmd, | |
6147e2c6 | 313 | "no offset-list WORD <in|out> (0-16)", |
a94434b6 | 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 | { | |
ac4d0be5 | 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); | |
a94434b6 | 327 | } |
328 | ||
329 | DEFUN (no_ripng_offset_list_ifname, | |
330 | no_ripng_offset_list_ifname_cmd, | |
6147e2c6 | 331 | "no offset-list WORD <in|out> (0-16) IFNAME", |
a94434b6 | 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 | { | |
ac4d0be5 | 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); | |
a94434b6 | 347 | } |
348 | ||
ac4d0be5 | 349 | static int offset_list_cmp(struct ripng_offset_list *o1, |
350 | struct ripng_offset_list *o2) | |
a94434b6 | 351 | { |
ac4d0be5 | 352 | return strcmp_safe(o1->ifname, o2->ifname); |
a94434b6 | 353 | } |
354 | ||
ac4d0be5 | 355 | static void offset_list_del(struct ripng_offset_list *offset) |
a94434b6 | 356 | { |
ac4d0be5 | 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); | |
a94434b6 | 364 | } |
365 | ||
ac4d0be5 | 366 | void ripng_offset_init(void) |
a94434b6 | 367 | { |
ac4d0be5 | 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); | |
a94434b6 | 377 | } |
378 | ||
ac4d0be5 | 379 | void ripng_offset_clean(void) |
a94434b6 | 380 | { |
ac4d0be5 | 381 | list_delete(ripng_offset_list_master); |
a94434b6 | 382 | |
ac4d0be5 | 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; | |
a94434b6 | 387 | } |
388 | ||
ac4d0be5 | 389 | int config_write_ripng_offset_list(struct vty *vty) |
a94434b6 | 390 | { |
ac4d0be5 | 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 | } | |
a94434b6 | 426 | } |
a94434b6 | 427 | |
ac4d0be5 | 428 | return 0; |
a94434b6 | 429 | } |