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 41struct 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 53static struct list *ripng_offset_list_master; 54 55static int 56strcmp_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 67static struct ripng_offset_list * 68ripng_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 76static void 77ripng_offset_list_free (struct ripng_offset_list *offset) 78{ 79 XFREE (MTYPE_RIPNG_OFFSET_LIST, offset); 80} 81 82static struct ripng_offset_list * 83ripng_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 96static struct ripng_offset_list * 97ripng_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 113static int 114ripng_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 152static int 153ripng_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. */ 213int 214ripng_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. */ 252int 253ripng_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 291DEFUN (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 303DEFUN (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 316DEFUN (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 329DEFUN (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 343static int 344offset_list_cmp (struct ripng_offset_list *o1, struct ripng_offset_list *o2) 345{ 346 return strcmp_safe (o1->ifname, o2->ifname); 347} 348 349static void 350offset_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 361void 362ripng_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 374void 375ripng_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 384int 385config_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} 422