blob: 6899c4d1742958b8c614390d701dd08a43eac0e0 [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
hasso98b718a2004-10-11 12:57:57 +000050strcmp_safe (const char *s1, const char *s2)
paul718e3742002-12-13 20:15:29 +000051{
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 *
hasso98b718a2004-10-11 12:57:57 +000078rip_offset_list_lookup (const char *ifname)
paul718e3742002-12-13 20:15:29 +000079{
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 *
hasso98b718a2004-10-11 12:57:57 +000092rip_offset_list_get (const char *ifname)
paul718e3742002-12-13 20:15:29 +000093{
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
hasso98b718a2004-10-11 12:57:57 +0000109rip_offset_list_set (struct vty *vty, const char *alist, const char *direct_str,
110 const char *metric_str, const char *ifname)
paul718e3742002-12-13 20:15:29 +0000111{
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
hasso98b718a2004-10-11 12:57:57 +0000147rip_offset_list_unset (struct vty *vty, const char *alist,
148 const char *direct_str, const char *metric_str,
149 const char *ifname)
paul718e3742002-12-13 20:15:29 +0000150{
151 int direct;
152 int metric;
153 struct rip_offset_list *offset;
154
155 /* Check direction. */
156 if (strncmp (direct_str, "i", 1) == 0)
157 direct = RIP_OFFSET_LIST_IN;
158 else if (strncmp (direct_str, "o", 1) == 0)
159 direct = RIP_OFFSET_LIST_OUT;
160 else
161 {
162 vty_out (vty, "Invalid direction: %s%s", direct_str, VTY_NEWLINE);
163 return CMD_WARNING;
164 }
165
166 /* Check metric. */
167 metric = atoi (metric_str);
168 if (metric < 0 || metric > 16)
169 {
170 vty_out (vty, "Invalid metric: %s%s", metric_str, VTY_NEWLINE);
171 return CMD_WARNING;
172 }
173
174 /* Get offset-list structure with interface name. */
175 offset = rip_offset_list_lookup (ifname);
176
177 if (offset)
178 {
179 if (offset->direct[direct].alist_name)
180 free (offset->direct[direct].alist_name);
181 offset->direct[direct].alist_name = NULL;
182
183 if (offset->direct[RIP_OFFSET_LIST_IN].alist_name == NULL &&
184 offset->direct[RIP_OFFSET_LIST_OUT].alist_name == NULL)
185 {
186 listnode_delete (rip_offset_list_master, offset);
187 if (offset->ifname)
188 free (offset->ifname);
189 rip_offset_list_free (offset);
190 }
191 }
192 else
193 {
194 vty_out (vty, "Can't find offset-list%s", VTY_NEWLINE);
195 return CMD_WARNING;
196 }
197 return CMD_SUCCESS;
198}
199
200#define OFFSET_LIST_IN_NAME(O) ((O)->direct[RIP_OFFSET_LIST_IN].alist_name)
201#define OFFSET_LIST_IN_METRIC(O) ((O)->direct[RIP_OFFSET_LIST_IN].metric)
202
203#define OFFSET_LIST_OUT_NAME(O) ((O)->direct[RIP_OFFSET_LIST_OUT].alist_name)
204#define OFFSET_LIST_OUT_METRIC(O) ((O)->direct[RIP_OFFSET_LIST_OUT].metric)
205
206/* If metric is modifed return 1. */
207int
208rip_offset_list_apply_in (struct prefix_ipv4 *p, struct interface *ifp,
209 u_int32_t *metric)
210{
211 struct rip_offset_list *offset;
212 struct access_list *alist;
213
214 /* Look up offset-list with interface name. */
215 offset = rip_offset_list_lookup (ifp->name);
216 if (offset && OFFSET_LIST_IN_NAME (offset))
217 {
218 alist = access_list_lookup (AFI_IP, OFFSET_LIST_IN_NAME (offset));
219
220 if (alist
221 && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT)
222 {
223 *metric += OFFSET_LIST_IN_METRIC (offset);
224 return 1;
225 }
226 return 0;
227 }
228 /* Look up offset-list without interface name. */
229 offset = rip_offset_list_lookup (NULL);
230 if (offset && OFFSET_LIST_IN_NAME (offset))
231 {
232 alist = access_list_lookup (AFI_IP, OFFSET_LIST_IN_NAME (offset));
233
234 if (alist
235 && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT)
236 {
237 *metric += OFFSET_LIST_IN_METRIC (offset);
238 return 1;
239 }
240 return 0;
241 }
242 return 0;
243}
244
245/* If metric is modifed return 1. */
246int
247rip_offset_list_apply_out (struct prefix_ipv4 *p, struct interface *ifp,
248 u_int32_t *metric)
249{
250 struct rip_offset_list *offset;
251 struct access_list *alist;
252
253 /* Look up offset-list with interface name. */
254 offset = rip_offset_list_lookup (ifp->name);
255 if (offset && OFFSET_LIST_OUT_NAME (offset))
256 {
257 alist = access_list_lookup (AFI_IP, OFFSET_LIST_OUT_NAME (offset));
258
259 if (alist
260 && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT)
261 {
262 *metric += OFFSET_LIST_OUT_METRIC (offset);
263 return 1;
264 }
265 return 0;
266 }
267
268 /* Look up offset-list without interface name. */
269 offset = rip_offset_list_lookup (NULL);
270 if (offset && OFFSET_LIST_OUT_NAME (offset))
271 {
272 alist = access_list_lookup (AFI_IP, OFFSET_LIST_OUT_NAME (offset));
273
274 if (alist
275 && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT)
276 {
277 *metric += OFFSET_LIST_OUT_METRIC (offset);
278 return 1;
279 }
280 return 0;
281 }
282 return 0;
283}
284
285DEFUN (rip_offset_list,
286 rip_offset_list_cmd,
287 "offset-list WORD (in|out) <0-16>",
288 "Modify RIP metric\n"
289 "Access-list name\n"
290 "For incoming updates\n"
291 "For outgoing updates\n"
292 "Metric value\n")
293{
294 return rip_offset_list_set (vty, argv[0], argv[1], argv[2], NULL);
295}
296
297DEFUN (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 return rip_offset_list_set (vty, argv[0], argv[1], argv[2], argv[3]);
308}
309
310DEFUN (no_rip_offset_list,
311 no_rip_offset_list_cmd,
312 "no offset-list WORD (in|out) <0-16>",
313 NO_STR
314 "Modify RIP metric\n"
315 "Access-list name\n"
316 "For incoming updates\n"
317 "For outgoing updates\n"
318 "Metric value\n")
319{
320 return rip_offset_list_unset (vty, argv[0], argv[1], argv[2], NULL);
321}
322
323DEFUN (no_rip_offset_list_ifname,
324 no_rip_offset_list_ifname_cmd,
325 "no offset-list WORD (in|out) <0-16> IFNAME",
326 NO_STR
327 "Modify RIP metric\n"
328 "Access-list name\n"
329 "For incoming updates\n"
330 "For outgoing updates\n"
331 "Metric value\n"
332 "Interface to match\n")
333{
334 return rip_offset_list_unset (vty, argv[0], argv[1], argv[2], argv[3]);
335}
336
337int
338offset_list_cmp (struct rip_offset_list *o1, struct rip_offset_list *o2)
339{
340 return strcmp_safe (o1->ifname, o2->ifname);
341}
342
343void
344offset_list_del (struct rip_offset_list *offset)
345{
346 if (OFFSET_LIST_IN_NAME (offset))
347 free (OFFSET_LIST_IN_NAME (offset));
348 if (OFFSET_LIST_OUT_NAME (offset))
349 free (OFFSET_LIST_OUT_NAME (offset));
350 if (offset->ifname)
351 free (offset->ifname);
352 rip_offset_list_free (offset);
353}
354
355void
356rip_offset_init ()
357{
358 rip_offset_list_master = list_new ();
359 rip_offset_list_master->cmp = (int (*)(void *, void *)) offset_list_cmp;
360 rip_offset_list_master->del = (void (*)(void *)) offset_list_del;
361
362 install_element (RIP_NODE, &rip_offset_list_cmd);
363 install_element (RIP_NODE, &rip_offset_list_ifname_cmd);
364 install_element (RIP_NODE, &no_rip_offset_list_cmd);
365 install_element (RIP_NODE, &no_rip_offset_list_ifname_cmd);
366}
367
368void
369rip_offset_clean ()
370{
371 list_delete (rip_offset_list_master);
372
373 rip_offset_list_master = list_new ();
374 rip_offset_list_master->cmp = (int (*)(void *, void *)) offset_list_cmp;
375 rip_offset_list_master->del = (void (*)(void *)) offset_list_del;
376}
377
378int
379config_write_rip_offset_list (struct vty *vty)
380{
381 struct listnode *nn;
382 struct rip_offset_list *offset;
383
384 LIST_LOOP (rip_offset_list_master, offset, nn)
385 {
386 if (! offset->ifname)
387 {
388 if (offset->direct[RIP_OFFSET_LIST_IN].alist_name)
389 vty_out (vty, " offset-list %s in %d%s",
390 offset->direct[RIP_OFFSET_LIST_IN].alist_name,
391 offset->direct[RIP_OFFSET_LIST_IN].metric,
392 VTY_NEWLINE);
393 if (offset->direct[RIP_OFFSET_LIST_OUT].alist_name)
394 vty_out (vty, " offset-list %s out %d%s",
395 offset->direct[RIP_OFFSET_LIST_OUT].alist_name,
396 offset->direct[RIP_OFFSET_LIST_OUT].metric,
397 VTY_NEWLINE);
398 }
399 else
400 {
401 if (offset->direct[RIP_OFFSET_LIST_IN].alist_name)
402 vty_out (vty, " offset-list %s in %d %s%s",
403 offset->direct[RIP_OFFSET_LIST_IN].alist_name,
404 offset->direct[RIP_OFFSET_LIST_IN].metric,
405 offset->ifname, VTY_NEWLINE);
406 if (offset->direct[RIP_OFFSET_LIST_OUT].alist_name)
407 vty_out (vty, " offset-list %s out %d %s%s",
408 offset->direct[RIP_OFFSET_LIST_OUT].alist_name,
409 offset->direct[RIP_OFFSET_LIST_OUT].metric,
410 offset->ifname, VTY_NEWLINE);
411 }
412 }
413
414 return 0;
415}