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