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