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