Annotation of embedaddon/quagga/ripd/ripd.c, revision 1.1
1.1 ! misho 1: /* RIP version 1 and 2.
! 2: * Copyright (C) 2005 6WIND <alain.ritoux@6wind.com>
! 3: * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro <kunihiro@zebra.org>
! 4: *
! 5: * This file is part of GNU Zebra.
! 6: *
! 7: * GNU Zebra is free software; you can redistribute it and/or modify it
! 8: * under the terms of the GNU General Public License as published by the
! 9: * Free Software Foundation; either version 2, or (at your option) any
! 10: * later version.
! 11: *
! 12: * GNU Zebra is distributed in the hope that it will be useful, but
! 13: * WITHOUT ANY WARRANTY; without even the implied warranty of
! 14: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
! 15: * General Public License for more details.
! 16: *
! 17: * You should have received a copy of the GNU General Public License
! 18: * along with GNU Zebra; see the file COPYING. If not, write to the Free
! 19: * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
! 20: * 02111-1307, USA.
! 21: */
! 22:
! 23: #include <zebra.h>
! 24:
! 25: #include "if.h"
! 26: #include "command.h"
! 27: #include "prefix.h"
! 28: #include "table.h"
! 29: #include "thread.h"
! 30: #include "memory.h"
! 31: #include "log.h"
! 32: #include "stream.h"
! 33: #include "filter.h"
! 34: #include "sockunion.h"
! 35: #include "sockopt.h"
! 36: #include "routemap.h"
! 37: #include "if_rmap.h"
! 38: #include "plist.h"
! 39: #include "distribute.h"
! 40: #include "md5.h"
! 41: #include "keychain.h"
! 42: #include "privs.h"
! 43:
! 44: #include "ripd/ripd.h"
! 45: #include "ripd/rip_debug.h"
! 46:
! 47: /* UDP receive buffer size */
! 48: #define RIP_UDP_RCV_BUF 41600
! 49:
! 50: /* privileges global */
! 51: extern struct zebra_privs_t ripd_privs;
! 52:
! 53: /* RIP Structure. */
! 54: struct rip *rip = NULL;
! 55:
! 56: /* RIP neighbor address table. */
! 57: struct route_table *rip_neighbor_table;
! 58:
! 59: /* RIP route changes. */
! 60: long rip_global_route_changes = 0;
! 61:
! 62: /* RIP queries. */
! 63: long rip_global_queries = 0;
! 64:
! 65: /* Prototypes. */
! 66: static void rip_event (enum rip_event, int);
! 67: static void rip_output_process (struct connected *, struct sockaddr_in *, int, u_char);
! 68: static int rip_triggered_update (struct thread *);
! 69: static int rip_update_jitter (unsigned long);
! 70:
! 71: /* RIP output routes type. */
! 72: enum
! 73: {
! 74: rip_all_route,
! 75: rip_changed_route
! 76: };
! 77:
! 78: /* RIP command strings. */
! 79: static const struct message rip_msg[] =
! 80: {
! 81: {RIP_REQUEST, "REQUEST"},
! 82: {RIP_RESPONSE, "RESPONSE"},
! 83: {RIP_TRACEON, "TRACEON"},
! 84: {RIP_TRACEOFF, "TRACEOFF"},
! 85: {RIP_POLL, "POLL"},
! 86: {RIP_POLL_ENTRY, "POLL ENTRY"},
! 87: {0, NULL},
! 88: };
! 89:
! 90: /* Utility function to set boradcast option to the socket. */
! 91: static int
! 92: sockopt_broadcast (int sock)
! 93: {
! 94: int ret;
! 95: int on = 1;
! 96:
! 97: ret = setsockopt (sock, SOL_SOCKET, SO_BROADCAST, (char *) &on, sizeof on);
! 98: if (ret < 0)
! 99: {
! 100: zlog_warn ("can't set sockopt SO_BROADCAST to socket %d", sock);
! 101: return -1;
! 102: }
! 103: return 0;
! 104: }
! 105:
! 106: static int
! 107: rip_route_rte (struct rip_info *rinfo)
! 108: {
! 109: return (rinfo->type == ZEBRA_ROUTE_RIP && rinfo->sub_type == RIP_ROUTE_RTE);
! 110: }
! 111:
! 112: static struct rip_info *
! 113: rip_info_new (void)
! 114: {
! 115: return XCALLOC (MTYPE_RIP_INFO, sizeof (struct rip_info));
! 116: }
! 117:
! 118: void
! 119: rip_info_free (struct rip_info *rinfo)
! 120: {
! 121: XFREE (MTYPE_RIP_INFO, rinfo);
! 122: }
! 123:
! 124: /* RIP route garbage collect timer. */
! 125: static int
! 126: rip_garbage_collect (struct thread *t)
! 127: {
! 128: struct rip_info *rinfo;
! 129: struct route_node *rp;
! 130:
! 131: rinfo = THREAD_ARG (t);
! 132: rinfo->t_garbage_collect = NULL;
! 133:
! 134: /* Off timeout timer. */
! 135: RIP_TIMER_OFF (rinfo->t_timeout);
! 136:
! 137: /* Get route_node pointer. */
! 138: rp = rinfo->rp;
! 139:
! 140: /* Unlock route_node. */
! 141: rp->info = NULL;
! 142: route_unlock_node (rp);
! 143:
! 144: /* Free RIP routing information. */
! 145: rip_info_free (rinfo);
! 146:
! 147: return 0;
! 148: }
! 149:
! 150: /* Timeout RIP routes. */
! 151: static int
! 152: rip_timeout (struct thread *t)
! 153: {
! 154: struct rip_info *rinfo;
! 155: struct route_node *rn;
! 156:
! 157: rinfo = THREAD_ARG (t);
! 158: rinfo->t_timeout = NULL;
! 159:
! 160: rn = rinfo->rp;
! 161:
! 162: /* - The garbage-collection timer is set for 120 seconds. */
! 163: RIP_TIMER_ON (rinfo->t_garbage_collect, rip_garbage_collect,
! 164: rip->garbage_time);
! 165:
! 166: rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rn->p, &rinfo->nexthop,
! 167: rinfo->metric);
! 168: /* - The metric for the route is set to 16 (infinity). This causes
! 169: the route to be removed from service. */
! 170: rinfo->metric = RIP_METRIC_INFINITY;
! 171: rinfo->flags &= ~RIP_RTF_FIB;
! 172:
! 173: /* - The route change flag is to indicate that this entry has been
! 174: changed. */
! 175: rinfo->flags |= RIP_RTF_CHANGED;
! 176:
! 177: /* - The output process is signalled to trigger a response. */
! 178: rip_event (RIP_TRIGGERED_UPDATE, 0);
! 179:
! 180: return 0;
! 181: }
! 182:
! 183: static void
! 184: rip_timeout_update (struct rip_info *rinfo)
! 185: {
! 186: if (rinfo->metric != RIP_METRIC_INFINITY)
! 187: {
! 188: RIP_TIMER_OFF (rinfo->t_timeout);
! 189: RIP_TIMER_ON (rinfo->t_timeout, rip_timeout, rip->timeout_time);
! 190: }
! 191: }
! 192:
! 193: static int
! 194: rip_incoming_filter (struct prefix_ipv4 *p, struct rip_interface *ri)
! 195: {
! 196: struct distribute *dist;
! 197: struct access_list *alist;
! 198: struct prefix_list *plist;
! 199:
! 200: /* Input distribute-list filtering. */
! 201: if (ri->list[RIP_FILTER_IN])
! 202: {
! 203: if (access_list_apply (ri->list[RIP_FILTER_IN],
! 204: (struct prefix *) p) == FILTER_DENY)
! 205: {
! 206: if (IS_RIP_DEBUG_PACKET)
! 207: zlog_debug ("%s/%d filtered by distribute in",
! 208: inet_ntoa (p->prefix), p->prefixlen);
! 209: return -1;
! 210: }
! 211: }
! 212: if (ri->prefix[RIP_FILTER_IN])
! 213: {
! 214: if (prefix_list_apply (ri->prefix[RIP_FILTER_IN],
! 215: (struct prefix *) p) == PREFIX_DENY)
! 216: {
! 217: if (IS_RIP_DEBUG_PACKET)
! 218: zlog_debug ("%s/%d filtered by prefix-list in",
! 219: inet_ntoa (p->prefix), p->prefixlen);
! 220: return -1;
! 221: }
! 222: }
! 223:
! 224: /* All interface filter check. */
! 225: dist = distribute_lookup (NULL);
! 226: if (dist)
! 227: {
! 228: if (dist->list[DISTRIBUTE_IN])
! 229: {
! 230: alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]);
! 231:
! 232: if (alist)
! 233: {
! 234: if (access_list_apply (alist,
! 235: (struct prefix *) p) == FILTER_DENY)
! 236: {
! 237: if (IS_RIP_DEBUG_PACKET)
! 238: zlog_debug ("%s/%d filtered by distribute in",
! 239: inet_ntoa (p->prefix), p->prefixlen);
! 240: return -1;
! 241: }
! 242: }
! 243: }
! 244: if (dist->prefix[DISTRIBUTE_IN])
! 245: {
! 246: plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]);
! 247:
! 248: if (plist)
! 249: {
! 250: if (prefix_list_apply (plist,
! 251: (struct prefix *) p) == PREFIX_DENY)
! 252: {
! 253: if (IS_RIP_DEBUG_PACKET)
! 254: zlog_debug ("%s/%d filtered by prefix-list in",
! 255: inet_ntoa (p->prefix), p->prefixlen);
! 256: return -1;
! 257: }
! 258: }
! 259: }
! 260: }
! 261: return 0;
! 262: }
! 263:
! 264: static int
! 265: rip_outgoing_filter (struct prefix_ipv4 *p, struct rip_interface *ri)
! 266: {
! 267: struct distribute *dist;
! 268: struct access_list *alist;
! 269: struct prefix_list *plist;
! 270:
! 271: if (ri->list[RIP_FILTER_OUT])
! 272: {
! 273: if (access_list_apply (ri->list[RIP_FILTER_OUT],
! 274: (struct prefix *) p) == FILTER_DENY)
! 275: {
! 276: if (IS_RIP_DEBUG_PACKET)
! 277: zlog_debug ("%s/%d is filtered by distribute out",
! 278: inet_ntoa (p->prefix), p->prefixlen);
! 279: return -1;
! 280: }
! 281: }
! 282: if (ri->prefix[RIP_FILTER_OUT])
! 283: {
! 284: if (prefix_list_apply (ri->prefix[RIP_FILTER_OUT],
! 285: (struct prefix *) p) == PREFIX_DENY)
! 286: {
! 287: if (IS_RIP_DEBUG_PACKET)
! 288: zlog_debug ("%s/%d is filtered by prefix-list out",
! 289: inet_ntoa (p->prefix), p->prefixlen);
! 290: return -1;
! 291: }
! 292: }
! 293:
! 294: /* All interface filter check. */
! 295: dist = distribute_lookup (NULL);
! 296: if (dist)
! 297: {
! 298: if (dist->list[DISTRIBUTE_OUT])
! 299: {
! 300: alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]);
! 301:
! 302: if (alist)
! 303: {
! 304: if (access_list_apply (alist,
! 305: (struct prefix *) p) == FILTER_DENY)
! 306: {
! 307: if (IS_RIP_DEBUG_PACKET)
! 308: zlog_debug ("%s/%d filtered by distribute out",
! 309: inet_ntoa (p->prefix), p->prefixlen);
! 310: return -1;
! 311: }
! 312: }
! 313: }
! 314: if (dist->prefix[DISTRIBUTE_OUT])
! 315: {
! 316: plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]);
! 317:
! 318: if (plist)
! 319: {
! 320: if (prefix_list_apply (plist,
! 321: (struct prefix *) p) == PREFIX_DENY)
! 322: {
! 323: if (IS_RIP_DEBUG_PACKET)
! 324: zlog_debug ("%s/%d filtered by prefix-list out",
! 325: inet_ntoa (p->prefix), p->prefixlen);
! 326: return -1;
! 327: }
! 328: }
! 329: }
! 330: }
! 331: return 0;
! 332: }
! 333:
! 334: /* Check nexthop address validity. */
! 335: static int
! 336: rip_nexthop_check (struct in_addr *addr)
! 337: {
! 338: struct listnode *node;
! 339: struct listnode *cnode;
! 340: struct interface *ifp;
! 341: struct connected *ifc;
! 342: struct prefix *p;
! 343:
! 344: /* If nexthop address matches local configured address then it is
! 345: invalid nexthop. */
! 346: for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
! 347: {
! 348: for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, ifc))
! 349: {
! 350: p = ifc->address;
! 351:
! 352: if (p->family == AF_INET
! 353: && IPV4_ADDR_SAME (&p->u.prefix4, addr))
! 354: return -1;
! 355: }
! 356: }
! 357: return 0;
! 358: }
! 359:
! 360: /* RIP add route to routing table. */
! 361: static void
! 362: rip_rte_process (struct rte *rte, struct sockaddr_in *from,
! 363: struct interface *ifp)
! 364: {
! 365: int ret;
! 366: struct prefix_ipv4 p;
! 367: struct route_node *rp;
! 368: struct rip_info *rinfo, rinfotmp;
! 369: struct rip_interface *ri;
! 370: struct in_addr *nexthop;
! 371: u_char oldmetric;
! 372: int same = 0;
! 373: int route_reuse = 0;
! 374: unsigned char old_dist, new_dist;
! 375:
! 376: /* Make prefix structure. */
! 377: memset (&p, 0, sizeof (struct prefix_ipv4));
! 378: p.family = AF_INET;
! 379: p.prefix = rte->prefix;
! 380: p.prefixlen = ip_masklen (rte->mask);
! 381:
! 382: /* Make sure mask is applied. */
! 383: apply_mask_ipv4 (&p);
! 384:
! 385: /* Apply input filters. */
! 386: ri = ifp->info;
! 387:
! 388: ret = rip_incoming_filter (&p, ri);
! 389: if (ret < 0)
! 390: return;
! 391:
! 392: /* Modify entry according to the interface routemap. */
! 393: if (ri->routemap[RIP_FILTER_IN])
! 394: {
! 395: int ret;
! 396: struct rip_info newinfo;
! 397:
! 398: memset (&newinfo, 0, sizeof (newinfo));
! 399: newinfo.type = ZEBRA_ROUTE_RIP;
! 400: newinfo.sub_type = RIP_ROUTE_RTE;
! 401: newinfo.nexthop = rte->nexthop;
! 402: newinfo.from = from->sin_addr;
! 403: newinfo.ifindex = ifp->ifindex;
! 404: newinfo.metric = rte->metric;
! 405: newinfo.metric_out = rte->metric; /* XXX */
! 406: newinfo.tag = ntohs (rte->tag); /* XXX */
! 407:
! 408: /* The object should be of the type of rip_info */
! 409: ret = route_map_apply (ri->routemap[RIP_FILTER_IN],
! 410: (struct prefix *) &p, RMAP_RIP, &newinfo);
! 411:
! 412: if (ret == RMAP_DENYMATCH)
! 413: {
! 414: if (IS_RIP_DEBUG_PACKET)
! 415: zlog_debug ("RIP %s/%d is filtered by route-map in",
! 416: inet_ntoa (p.prefix), p.prefixlen);
! 417: return;
! 418: }
! 419:
! 420: /* Get back the object */
! 421: rte->nexthop = newinfo.nexthop_out;
! 422: rte->tag = htons (newinfo.tag_out); /* XXX */
! 423: rte->metric = newinfo.metric_out; /* XXX: the routemap uses the metric_out field */
! 424: }
! 425:
! 426: /* Once the entry has been validated, update the metric by
! 427: adding the cost of the network on wich the message
! 428: arrived. If the result is greater than infinity, use infinity
! 429: (RFC2453 Sec. 3.9.2) */
! 430: /* Zebra ripd can handle offset-list in. */
! 431: ret = rip_offset_list_apply_in (&p, ifp, &rte->metric);
! 432:
! 433: /* If offset-list does not modify the metric use interface's
! 434: metric. */
! 435: if (!ret)
! 436: rte->metric += ifp->metric;
! 437:
! 438: if (rte->metric > RIP_METRIC_INFINITY)
! 439: rte->metric = RIP_METRIC_INFINITY;
! 440:
! 441: /* Set nexthop pointer. */
! 442: if (rte->nexthop.s_addr == 0)
! 443: nexthop = &from->sin_addr;
! 444: else
! 445: nexthop = &rte->nexthop;
! 446:
! 447: /* Check if nexthop address is myself, then do nothing. */
! 448: if (rip_nexthop_check (nexthop) < 0)
! 449: {
! 450: if (IS_RIP_DEBUG_PACKET)
! 451: zlog_debug ("Nexthop address %s is myself", inet_ntoa (*nexthop));
! 452: return;
! 453: }
! 454:
! 455: /* Get index for the prefix. */
! 456: rp = route_node_get (rip->table, (struct prefix *) &p);
! 457:
! 458: /* Check to see whether there is already RIP route on the table. */
! 459: rinfo = rp->info;
! 460:
! 461: if (rinfo)
! 462: {
! 463: /* Local static route. */
! 464: if (rinfo->type == ZEBRA_ROUTE_RIP
! 465: && ((rinfo->sub_type == RIP_ROUTE_STATIC) ||
! 466: (rinfo->sub_type == RIP_ROUTE_DEFAULT))
! 467: && rinfo->metric != RIP_METRIC_INFINITY)
! 468: {
! 469: route_unlock_node (rp);
! 470: return;
! 471: }
! 472:
! 473: /* Redistributed route check. */
! 474: if (rinfo->type != ZEBRA_ROUTE_RIP
! 475: && rinfo->metric != RIP_METRIC_INFINITY)
! 476: {
! 477: /* Fill in a minimaly temporary rip_info structure, for a future
! 478: rip_distance_apply() use) */
! 479: memset (&rinfotmp, 0, sizeof (rinfotmp));
! 480: IPV4_ADDR_COPY (&rinfotmp.from, &from->sin_addr);
! 481: rinfotmp.rp = rinfo->rp;
! 482: new_dist = rip_distance_apply (&rinfotmp);
! 483: new_dist = new_dist ? new_dist : ZEBRA_RIP_DISTANCE_DEFAULT;
! 484: old_dist = rinfo->distance;
! 485: /* Only connected routes may have a valid NULL distance */
! 486: if (rinfo->type != ZEBRA_ROUTE_CONNECT)
! 487: old_dist = old_dist ? old_dist : ZEBRA_RIP_DISTANCE_DEFAULT;
! 488: /* If imported route does not have STRICT precedence,
! 489: mark it as a ghost */
! 490: if (new_dist > old_dist
! 491: || rte->metric == RIP_METRIC_INFINITY)
! 492: {
! 493: route_unlock_node (rp);
! 494: return;
! 495: }
! 496: else
! 497: {
! 498: RIP_TIMER_OFF (rinfo->t_timeout);
! 499: RIP_TIMER_OFF (rinfo->t_garbage_collect);
! 500:
! 501: rp->info = NULL;
! 502: if (rip_route_rte (rinfo))
! 503: rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p,
! 504: &rinfo->nexthop, rinfo->metric);
! 505: rip_info_free (rinfo);
! 506: rinfo = NULL;
! 507: route_reuse = 1;
! 508: }
! 509: }
! 510: }
! 511:
! 512: if (!rinfo)
! 513: {
! 514: /* Now, check to see whether there is already an explicit route
! 515: for the destination prefix. If there is no such route, add
! 516: this route to the routing table, unless the metric is
! 517: infinity (there is no point in adding a route which
! 518: unusable). */
! 519: if (rte->metric != RIP_METRIC_INFINITY)
! 520: {
! 521: rinfo = rip_info_new ();
! 522:
! 523: /* - Setting the destination prefix and length to those in
! 524: the RTE. */
! 525: rinfo->rp = rp;
! 526:
! 527: /* - Setting the metric to the newly calculated metric (as
! 528: described above). */
! 529: rinfo->metric = rte->metric;
! 530: rinfo->tag = ntohs (rte->tag);
! 531:
! 532: /* - Set the next hop address to be the address of the router
! 533: from which the datagram came or the next hop address
! 534: specified by a next hop RTE. */
! 535: IPV4_ADDR_COPY (&rinfo->nexthop, nexthop);
! 536: IPV4_ADDR_COPY (&rinfo->from, &from->sin_addr);
! 537: rinfo->ifindex = ifp->ifindex;
! 538:
! 539: /* - Initialize the timeout for the route. If the
! 540: garbage-collection timer is running for this route, stop it
! 541: (see section 2.3 for a discussion of the timers). */
! 542: rip_timeout_update (rinfo);
! 543:
! 544: /* - Set the route change flag. */
! 545: rinfo->flags |= RIP_RTF_CHANGED;
! 546:
! 547: /* - Signal the output process to trigger an update (see section
! 548: 2.5). */
! 549: rip_event (RIP_TRIGGERED_UPDATE, 0);
! 550:
! 551: /* Finally, route goes into the kernel. */
! 552: rinfo->type = ZEBRA_ROUTE_RIP;
! 553: rinfo->sub_type = RIP_ROUTE_RTE;
! 554:
! 555: /* Set distance value. */
! 556: rinfo->distance = rip_distance_apply (rinfo);
! 557:
! 558: rp->info = rinfo;
! 559: rip_zebra_ipv4_add (&p, &rinfo->nexthop, rinfo->metric,
! 560: rinfo->distance);
! 561: rinfo->flags |= RIP_RTF_FIB;
! 562: }
! 563:
! 564: /* Unlock temporary lock, i.e. same behaviour */
! 565: if (route_reuse)
! 566: route_unlock_node (rp);
! 567: }
! 568: else
! 569: {
! 570: /* Route is there but we are not sure the route is RIP or not. */
! 571: rinfo = rp->info;
! 572:
! 573: /* If there is an existing route, compare the next hop address
! 574: to the address of the router from which the datagram came.
! 575: If this datagram is from the same router as the existing
! 576: route, reinitialize the timeout. */
! 577: same = (IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr)
! 578: && (rinfo->ifindex == ifp->ifindex));
! 579:
! 580: if (same)
! 581: rip_timeout_update (rinfo);
! 582:
! 583:
! 584: /* Fill in a minimaly temporary rip_info structure, for a future
! 585: rip_distance_apply() use) */
! 586: memset (&rinfotmp, 0, sizeof (rinfotmp));
! 587: IPV4_ADDR_COPY (&rinfotmp.from, &from->sin_addr);
! 588: rinfotmp.rp = rinfo->rp;
! 589:
! 590:
! 591: /* Next, compare the metrics. If the datagram is from the same
! 592: router as the existing route, and the new metric is different
! 593: than the old one; or, if the new metric is lower than the old
! 594: one, or if the tag has been changed; or if there is a route
! 595: with a lower administrave distance; or an update of the
! 596: distance on the actual route; do the following actions: */
! 597: if ((same && rinfo->metric != rte->metric)
! 598: || (rte->metric < rinfo->metric)
! 599: || ((same)
! 600: && (rinfo->metric == rte->metric)
! 601: && ntohs (rte->tag) != rinfo->tag)
! 602: || (rinfo->distance > rip_distance_apply (&rinfotmp))
! 603: || ((rinfo->distance != rip_distance_apply (rinfo)) && same))
! 604: {
! 605: /* - Adopt the route from the datagram. That is, put the
! 606: new metric in, and adjust the next hop address (if
! 607: necessary). */
! 608: oldmetric = rinfo->metric;
! 609: rinfo->metric = rte->metric;
! 610: rinfo->tag = ntohs (rte->tag);
! 611: IPV4_ADDR_COPY (&rinfo->from, &from->sin_addr);
! 612: rinfo->ifindex = ifp->ifindex;
! 613: rinfo->distance = rip_distance_apply (rinfo);
! 614:
! 615: /* Should a new route to this network be established
! 616: while the garbage-collection timer is running, the
! 617: new route will replace the one that is about to be
! 618: deleted. In this case the garbage-collection timer
! 619: must be cleared. */
! 620:
! 621: if (oldmetric == RIP_METRIC_INFINITY &&
! 622: rinfo->metric < RIP_METRIC_INFINITY)
! 623: {
! 624: rinfo->type = ZEBRA_ROUTE_RIP;
! 625: rinfo->sub_type = RIP_ROUTE_RTE;
! 626:
! 627: RIP_TIMER_OFF (rinfo->t_garbage_collect);
! 628:
! 629: if (!IPV4_ADDR_SAME (&rinfo->nexthop, nexthop))
! 630: IPV4_ADDR_COPY (&rinfo->nexthop, nexthop);
! 631:
! 632: rip_zebra_ipv4_add (&p, nexthop, rinfo->metric,
! 633: rinfo->distance);
! 634: rinfo->flags |= RIP_RTF_FIB;
! 635: }
! 636:
! 637: /* Update nexthop and/or metric value. */
! 638: if (oldmetric != RIP_METRIC_INFINITY)
! 639: {
! 640: rip_zebra_ipv4_delete (&p, &rinfo->nexthop, oldmetric);
! 641: rip_zebra_ipv4_add (&p, nexthop, rinfo->metric,
! 642: rinfo->distance);
! 643: rinfo->flags |= RIP_RTF_FIB;
! 644:
! 645: if (!IPV4_ADDR_SAME (&rinfo->nexthop, nexthop))
! 646: IPV4_ADDR_COPY (&rinfo->nexthop, nexthop);
! 647: }
! 648:
! 649: /* - Set the route change flag and signal the output process
! 650: to trigger an update. */
! 651: rinfo->flags |= RIP_RTF_CHANGED;
! 652: rip_event (RIP_TRIGGERED_UPDATE, 0);
! 653:
! 654: /* - If the new metric is infinity, start the deletion
! 655: process (described above); */
! 656: if (rinfo->metric == RIP_METRIC_INFINITY)
! 657: {
! 658: /* If the new metric is infinity, the deletion process
! 659: begins for the route, which is no longer used for
! 660: routing packets. Note that the deletion process is
! 661: started only when the metric is first set to
! 662: infinity. If the metric was already infinity, then a
! 663: new deletion process is not started. */
! 664: if (oldmetric != RIP_METRIC_INFINITY)
! 665: {
! 666: /* - The garbage-collection timer is set for 120 seconds. */
! 667: RIP_TIMER_ON (rinfo->t_garbage_collect,
! 668: rip_garbage_collect, rip->garbage_time);
! 669: RIP_TIMER_OFF (rinfo->t_timeout);
! 670:
! 671: /* - The metric for the route is set to 16
! 672: (infinity). This causes the route to be removed
! 673: from service. */
! 674: rip_zebra_ipv4_delete (&p, &rinfo->nexthop, oldmetric);
! 675: rinfo->flags &= ~RIP_RTF_FIB;
! 676:
! 677: /* - The route change flag is to indicate that this
! 678: entry has been changed. */
! 679: /* - The output process is signalled to trigger a
! 680: response. */
! 681: ; /* Above processes are already done previously. */
! 682: }
! 683: }
! 684: else
! 685: {
! 686: /* otherwise, re-initialize the timeout. */
! 687: rip_timeout_update (rinfo);
! 688: }
! 689: }
! 690: /* Unlock tempolary lock of the route. */
! 691: route_unlock_node (rp);
! 692: }
! 693: }
! 694:
! 695: /* Dump RIP packet */
! 696: static void
! 697: rip_packet_dump (struct rip_packet *packet, int size, const char *sndrcv)
! 698: {
! 699: caddr_t lim;
! 700: struct rte *rte;
! 701: const char *command_str;
! 702: char pbuf[BUFSIZ], nbuf[BUFSIZ];
! 703: u_char netmask = 0;
! 704: u_char *p;
! 705:
! 706: /* Set command string. */
! 707: if (packet->command > 0 && packet->command < RIP_COMMAND_MAX)
! 708: command_str = lookup (rip_msg, packet->command);
! 709: else
! 710: command_str = "unknown";
! 711:
! 712: /* Dump packet header. */
! 713: zlog_debug ("%s %s version %d packet size %d",
! 714: sndrcv, command_str, packet->version, size);
! 715:
! 716: /* Dump each routing table entry. */
! 717: rte = packet->rte;
! 718:
! 719: for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
! 720: {
! 721: if (packet->version == RIPv2)
! 722: {
! 723: netmask = ip_masklen (rte->mask);
! 724:
! 725: if (rte->family == htons (RIP_FAMILY_AUTH))
! 726: {
! 727: if (rte->tag == htons (RIP_AUTH_SIMPLE_PASSWORD))
! 728: {
! 729: p = (u_char *)&rte->prefix;
! 730:
! 731: zlog_debug (" family 0x%X type %d auth string: %s",
! 732: ntohs (rte->family), ntohs (rte->tag), p);
! 733: }
! 734: else if (rte->tag == htons (RIP_AUTH_MD5))
! 735: {
! 736: struct rip_md5_info *md5;
! 737:
! 738: md5 = (struct rip_md5_info *) &packet->rte;
! 739:
! 740: zlog_debug (" family 0x%X type %d (MD5 authentication)",
! 741: ntohs (md5->family), ntohs (md5->type));
! 742: zlog_debug (" RIP-2 packet len %d Key ID %d"
! 743: " Auth Data len %d",
! 744: ntohs (md5->packet_len), md5->keyid,
! 745: md5->auth_len);
! 746: zlog_debug (" Sequence Number %ld",
! 747: (u_long) ntohl (md5->sequence));
! 748: }
! 749: else if (rte->tag == htons (RIP_AUTH_DATA))
! 750: {
! 751: p = (u_char *)&rte->prefix;
! 752:
! 753: zlog_debug (" family 0x%X type %d (MD5 data)",
! 754: ntohs (rte->family), ntohs (rte->tag));
! 755: zlog_debug (" MD5: %02X%02X%02X%02X%02X%02X%02X%02X"
! 756: "%02X%02X%02X%02X%02X%02X%02X",
! 757: p[0], p[1], p[2], p[3], p[4], p[5], p[6],
! 758: p[7], p[9], p[10], p[11], p[12], p[13],
! 759: p[14], p[15]);
! 760: }
! 761: else
! 762: {
! 763: zlog_debug (" family 0x%X type %d (Unknown auth type)",
! 764: ntohs (rte->family), ntohs (rte->tag));
! 765: }
! 766: }
! 767: else
! 768: zlog_debug (" %s/%d -> %s family %d tag %d metric %ld",
! 769: inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ),
! 770: netmask, inet_ntop (AF_INET, &rte->nexthop, nbuf,
! 771: BUFSIZ), ntohs (rte->family),
! 772: ntohs (rte->tag), (u_long) ntohl (rte->metric));
! 773: }
! 774: else
! 775: {
! 776: zlog_debug (" %s family %d tag %d metric %ld",
! 777: inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ),
! 778: ntohs (rte->family), ntohs (rte->tag),
! 779: (u_long)ntohl (rte->metric));
! 780: }
! 781: }
! 782: }
! 783:
! 784: /* Check if the destination address is valid (unicast; not net 0
! 785: or 127) (RFC2453 Section 3.9.2 - Page 26). But we don't
! 786: check net 0 because we accept default route. */
! 787: static int
! 788: rip_destination_check (struct in_addr addr)
! 789: {
! 790: u_int32_t destination;
! 791:
! 792: /* Convert to host byte order. */
! 793: destination = ntohl (addr.s_addr);
! 794:
! 795: if (IPV4_NET127 (destination))
! 796: return 0;
! 797:
! 798: /* Net 0 may match to the default route. */
! 799: if (IPV4_NET0 (destination) && destination != 0)
! 800: return 0;
! 801:
! 802: /* Unicast address must belong to class A, B, C. */
! 803: if (IN_CLASSA (destination))
! 804: return 1;
! 805: if (IN_CLASSB (destination))
! 806: return 1;
! 807: if (IN_CLASSC (destination))
! 808: return 1;
! 809:
! 810: return 0;
! 811: }
! 812:
! 813: /* RIP version 2 authentication. */
! 814: static int
! 815: rip_auth_simple_password (struct rte *rte, struct sockaddr_in *from,
! 816: struct interface *ifp)
! 817: {
! 818: struct rip_interface *ri;
! 819: char *auth_str;
! 820:
! 821: if (IS_RIP_DEBUG_EVENT)
! 822: zlog_debug ("RIPv2 simple password authentication from %s",
! 823: inet_ntoa (from->sin_addr));
! 824:
! 825: ri = ifp->info;
! 826:
! 827: if (ri->auth_type != RIP_AUTH_SIMPLE_PASSWORD
! 828: || rte->tag != htons(RIP_AUTH_SIMPLE_PASSWORD))
! 829: return 0;
! 830:
! 831: /* Simple password authentication. */
! 832: if (ri->auth_str)
! 833: {
! 834: auth_str = (char *) &rte->prefix;
! 835:
! 836: if (strncmp (auth_str, ri->auth_str, 16) == 0)
! 837: return 1;
! 838: }
! 839: if (ri->key_chain)
! 840: {
! 841: struct keychain *keychain;
! 842: struct key *key;
! 843:
! 844: keychain = keychain_lookup (ri->key_chain);
! 845: if (keychain == NULL)
! 846: return 0;
! 847:
! 848: key = key_match_for_accept (keychain, (char *) &rte->prefix);
! 849: if (key)
! 850: return 1;
! 851: }
! 852: return 0;
! 853: }
! 854:
! 855: /* RIP version 2 authentication with MD5. */
! 856: static int
! 857: rip_auth_md5 (struct rip_packet *packet, struct sockaddr_in *from,
! 858: int length, struct interface *ifp)
! 859: {
! 860: struct rip_interface *ri;
! 861: struct rip_md5_info *md5;
! 862: struct rip_md5_data *md5data;
! 863: struct keychain *keychain;
! 864: struct key *key;
! 865: MD5_CTX ctx;
! 866: u_char digest[RIP_AUTH_MD5_SIZE];
! 867: u_int16_t packet_len;
! 868: char auth_str[RIP_AUTH_MD5_SIZE];
! 869:
! 870: if (IS_RIP_DEBUG_EVENT)
! 871: zlog_debug ("RIPv2 MD5 authentication from %s",
! 872: inet_ntoa (from->sin_addr));
! 873:
! 874: ri = ifp->info;
! 875: md5 = (struct rip_md5_info *) &packet->rte;
! 876:
! 877: /* Check auth type. */
! 878: if (ri->auth_type != RIP_AUTH_MD5 || md5->type != htons(RIP_AUTH_MD5))
! 879: return 0;
! 880:
! 881: /* If the authentication length is less than 16, then it must be wrong for
! 882: * any interpretation of rfc2082. Some implementations also interpret
! 883: * this as RIP_HEADER_SIZE+ RIP_AUTH_MD5_SIZE, aka RIP_AUTH_MD5_COMPAT_SIZE.
! 884: */
! 885: if ( !((md5->auth_len == RIP_AUTH_MD5_SIZE)
! 886: || (md5->auth_len == RIP_AUTH_MD5_COMPAT_SIZE)))
! 887: {
! 888: if (IS_RIP_DEBUG_EVENT)
! 889: zlog_debug ("RIPv2 MD5 authentication, strange authentication "
! 890: "length field %d", md5->auth_len);
! 891: return 0;
! 892: }
! 893:
! 894: /* grab and verify check packet length */
! 895: packet_len = ntohs (md5->packet_len);
! 896:
! 897: if (packet_len > (length - RIP_HEADER_SIZE - RIP_AUTH_MD5_SIZE))
! 898: {
! 899: if (IS_RIP_DEBUG_EVENT)
! 900: zlog_debug ("RIPv2 MD5 authentication, packet length field %d "
! 901: "greater than received length %d!",
! 902: md5->packet_len, length);
! 903: return 0;
! 904: }
! 905:
! 906: /* retrieve authentication data */
! 907: md5data = (struct rip_md5_data *) (((u_char *) packet) + packet_len);
! 908:
! 909: memset (auth_str, 0, RIP_AUTH_MD5_SIZE);
! 910:
! 911: if (ri->key_chain)
! 912: {
! 913: keychain = keychain_lookup (ri->key_chain);
! 914: if (keychain == NULL)
! 915: return 0;
! 916:
! 917: key = key_lookup_for_accept (keychain, md5->keyid);
! 918: if (key == NULL)
! 919: return 0;
! 920:
! 921: strncpy (auth_str, key->string, RIP_AUTH_MD5_SIZE);
! 922: }
! 923: else if (ri->auth_str)
! 924: strncpy (auth_str, ri->auth_str, RIP_AUTH_MD5_SIZE);
! 925:
! 926: if (auth_str[0] == 0)
! 927: return 0;
! 928:
! 929: /* MD5 digest authentication. */
! 930: memset (&ctx, 0, sizeof(ctx));
! 931: MD5Init(&ctx);
! 932: MD5Update(&ctx, packet, packet_len + RIP_HEADER_SIZE);
! 933: MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE);
! 934: MD5Final(digest, &ctx);
! 935:
! 936: if (memcmp (md5data->digest, digest, RIP_AUTH_MD5_SIZE) == 0)
! 937: return packet_len;
! 938: else
! 939: return 0;
! 940: }
! 941:
! 942: /* Pick correct auth string for sends, prepare auth_str buffer for use.
! 943: * (left justified and padded).
! 944: *
! 945: * presumes one of ri or key is valid, and that the auth strings they point
! 946: * to are nul terminated. If neither are present, auth_str will be fully
! 947: * zero padded.
! 948: *
! 949: */
! 950: static void
! 951: rip_auth_prepare_str_send (struct rip_interface *ri, struct key *key,
! 952: char *auth_str, int len)
! 953: {
! 954: assert (ri || key);
! 955:
! 956: memset (auth_str, 0, len);
! 957: if (key && key->string)
! 958: strncpy (auth_str, key->string, len);
! 959: else if (ri->auth_str)
! 960: strncpy (auth_str, ri->auth_str, len);
! 961:
! 962: return;
! 963: }
! 964:
! 965: /* Write RIPv2 simple password authentication information
! 966: *
! 967: * auth_str is presumed to be 2 bytes and correctly prepared
! 968: * (left justified and zero padded).
! 969: */
! 970: static void
! 971: rip_auth_simple_write (struct stream *s, char *auth_str, int len)
! 972: {
! 973: assert (s && len == RIP_AUTH_SIMPLE_SIZE);
! 974:
! 975: stream_putw (s, RIP_FAMILY_AUTH);
! 976: stream_putw (s, RIP_AUTH_SIMPLE_PASSWORD);
! 977: stream_put (s, auth_str, RIP_AUTH_SIMPLE_SIZE);
! 978:
! 979: return;
! 980: }
! 981:
! 982: /* write RIPv2 MD5 "authentication header"
! 983: * (uses the auth key data field)
! 984: *
! 985: * Digest offset field is set to 0.
! 986: *
! 987: * returns: offset of the digest offset field, which must be set when
! 988: * length to the auth-data MD5 digest is known.
! 989: */
! 990: static size_t
! 991: rip_auth_md5_ah_write (struct stream *s, struct rip_interface *ri,
! 992: struct key *key)
! 993: {
! 994: size_t doff = 0;
! 995:
! 996: assert (s && ri && ri->auth_type == RIP_AUTH_MD5);
! 997:
! 998: /* MD5 authentication. */
! 999: stream_putw (s, RIP_FAMILY_AUTH);
! 1000: stream_putw (s, RIP_AUTH_MD5);
! 1001:
! 1002: /* MD5 AH digest offset field.
! 1003: *
! 1004: * Set to placeholder value here, to true value when RIP-2 Packet length
! 1005: * is known. Actual value is set in .....().
! 1006: */
! 1007: doff = stream_get_endp(s);
! 1008: stream_putw (s, 0);
! 1009:
! 1010: /* Key ID. */
! 1011: if (key)
! 1012: stream_putc (s, key->index % 256);
! 1013: else
! 1014: stream_putc (s, 1);
! 1015:
! 1016: /* Auth Data Len. Set 16 for MD5 authentication data. Older ripds
! 1017: * however expect RIP_HEADER_SIZE + RIP_AUTH_MD5_SIZE so we allow for this
! 1018: * to be configurable.
! 1019: */
! 1020: stream_putc (s, ri->md5_auth_len);
! 1021:
! 1022: /* Sequence Number (non-decreasing). */
! 1023: /* RFC2080: The value used in the sequence number is
! 1024: arbitrary, but two suggestions are the time of the
! 1025: message's creation or a simple message counter. */
! 1026: stream_putl (s, time (NULL));
! 1027:
! 1028: /* Reserved field must be zero. */
! 1029: stream_putl (s, 0);
! 1030: stream_putl (s, 0);
! 1031:
! 1032: return doff;
! 1033: }
! 1034:
! 1035: /* If authentication is in used, write the appropriate header
! 1036: * returns stream offset to which length must later be written
! 1037: * or 0 if this is not required
! 1038: */
! 1039: static size_t
! 1040: rip_auth_header_write (struct stream *s, struct rip_interface *ri,
! 1041: struct key *key, char *auth_str, int len)
! 1042: {
! 1043: assert (ri->auth_type != RIP_NO_AUTH);
! 1044:
! 1045: switch (ri->auth_type)
! 1046: {
! 1047: case RIP_AUTH_SIMPLE_PASSWORD:
! 1048: rip_auth_prepare_str_send (ri, key, auth_str, len);
! 1049: rip_auth_simple_write (s, auth_str, len);
! 1050: return 0;
! 1051: case RIP_AUTH_MD5:
! 1052: return rip_auth_md5_ah_write (s, ri, key);
! 1053: }
! 1054: assert (1);
! 1055: return 0;
! 1056: }
! 1057:
! 1058: /* Write RIPv2 MD5 authentication data trailer */
! 1059: static void
! 1060: rip_auth_md5_set (struct stream *s, struct rip_interface *ri, size_t doff,
! 1061: char *auth_str, int authlen)
! 1062: {
! 1063: unsigned long len;
! 1064: MD5_CTX ctx;
! 1065: unsigned char digest[RIP_AUTH_MD5_SIZE];
! 1066:
! 1067: /* Make it sure this interface is configured as MD5
! 1068: authentication. */
! 1069: assert ((ri->auth_type == RIP_AUTH_MD5) && (authlen == RIP_AUTH_MD5_SIZE));
! 1070: assert (doff > 0);
! 1071:
! 1072: /* Get packet length. */
! 1073: len = stream_get_endp(s);
! 1074:
! 1075: /* Check packet length. */
! 1076: if (len < (RIP_HEADER_SIZE + RIP_RTE_SIZE))
! 1077: {
! 1078: zlog_err ("rip_auth_md5_set(): packet length %ld is less than minimum length.", len);
! 1079: return;
! 1080: }
! 1081:
! 1082: /* Set the digest offset length in the header */
! 1083: stream_putw_at (s, doff, len);
! 1084:
! 1085: /* Set authentication data. */
! 1086: stream_putw (s, RIP_FAMILY_AUTH);
! 1087: stream_putw (s, RIP_AUTH_DATA);
! 1088:
! 1089: /* Generate a digest for the RIP packet. */
! 1090: memset(&ctx, 0, sizeof(ctx));
! 1091: MD5Init(&ctx);
! 1092: MD5Update(&ctx, STREAM_DATA (s), stream_get_endp (s));
! 1093: MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE);
! 1094: MD5Final(digest, &ctx);
! 1095:
! 1096: /* Copy the digest to the packet. */
! 1097: stream_write (s, digest, RIP_AUTH_MD5_SIZE);
! 1098: }
! 1099:
! 1100: /* RIP routing information. */
! 1101: static void
! 1102: rip_response_process (struct rip_packet *packet, int size,
! 1103: struct sockaddr_in *from, struct connected *ifc)
! 1104: {
! 1105: caddr_t lim;
! 1106: struct rte *rte;
! 1107: struct prefix_ipv4 ifaddr;
! 1108: struct prefix_ipv4 ifaddrclass;
! 1109: int subnetted;
! 1110:
! 1111: /* We don't know yet. */
! 1112: subnetted = -1;
! 1113:
! 1114: /* The Response must be ignored if it is not from the RIP
! 1115: port. (RFC2453 - Sec. 3.9.2)*/
! 1116: if (from->sin_port != htons(RIP_PORT_DEFAULT))
! 1117: {
! 1118: zlog_info ("response doesn't come from RIP port: %d",
! 1119: from->sin_port);
! 1120: rip_peer_bad_packet (from);
! 1121: return;
! 1122: }
! 1123:
! 1124: /* The datagram's IPv4 source address should be checked to see
! 1125: whether the datagram is from a valid neighbor; the source of the
! 1126: datagram must be on a directly connected network (RFC2453 - Sec. 3.9.2) */
! 1127: if (if_lookup_address(from->sin_addr) == NULL)
! 1128: {
! 1129: zlog_info ("This datagram doesn't came from a valid neighbor: %s",
! 1130: inet_ntoa (from->sin_addr));
! 1131: rip_peer_bad_packet (from);
! 1132: return;
! 1133: }
! 1134:
! 1135: /* It is also worth checking to see whether the response is from one
! 1136: of the router's own addresses. */
! 1137:
! 1138: ; /* Alredy done in rip_read () */
! 1139:
! 1140: /* Update RIP peer. */
! 1141: rip_peer_update (from, packet->version);
! 1142:
! 1143: /* Set RTE pointer. */
! 1144: rte = packet->rte;
! 1145:
! 1146: for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
! 1147: {
! 1148: /* RIPv2 authentication check. */
! 1149: /* If the Address Family Identifier of the first (and only the
! 1150: first) entry in the message is 0xFFFF, then the remainder of
! 1151: the entry contains the authentication. */
! 1152: /* If the packet gets here it means authentication enabled */
! 1153: /* Check is done in rip_read(). So, just skipping it */
! 1154: if (packet->version == RIPv2 &&
! 1155: rte == packet->rte &&
! 1156: rte->family == htons(RIP_FAMILY_AUTH))
! 1157: continue;
! 1158:
! 1159: if (rte->family != htons(AF_INET))
! 1160: {
! 1161: /* Address family check. RIP only supports AF_INET. */
! 1162: zlog_info ("Unsupported family %d from %s.",
! 1163: ntohs (rte->family), inet_ntoa (from->sin_addr));
! 1164: continue;
! 1165: }
! 1166:
! 1167: /* - is the destination address valid (e.g., unicast; not net 0
! 1168: or 127) */
! 1169: if (! rip_destination_check (rte->prefix))
! 1170: {
! 1171: zlog_info ("Network is net 0 or net 127 or it is not unicast network");
! 1172: rip_peer_bad_route (from);
! 1173: continue;
! 1174: }
! 1175:
! 1176: /* Convert metric value to host byte order. */
! 1177: rte->metric = ntohl (rte->metric);
! 1178:
! 1179: /* - is the metric valid (i.e., between 1 and 16, inclusive) */
! 1180: if (! (rte->metric >= 1 && rte->metric <= 16))
! 1181: {
! 1182: zlog_info ("Route's metric is not in the 1-16 range.");
! 1183: rip_peer_bad_route (from);
! 1184: continue;
! 1185: }
! 1186:
! 1187: /* RIPv1 does not have nexthop value. */
! 1188: if (packet->version == RIPv1 && rte->nexthop.s_addr != 0)
! 1189: {
! 1190: zlog_info ("RIPv1 packet with nexthop value %s",
! 1191: inet_ntoa (rte->nexthop));
! 1192: rip_peer_bad_route (from);
! 1193: continue;
! 1194: }
! 1195:
! 1196: /* That is, if the provided information is ignored, a possibly
! 1197: sub-optimal, but absolutely valid, route may be taken. If
! 1198: the received Next Hop is not directly reachable, it should be
! 1199: treated as 0.0.0.0. */
! 1200: if (packet->version == RIPv2 && rte->nexthop.s_addr != 0)
! 1201: {
! 1202: u_int32_t addrval;
! 1203:
! 1204: /* Multicast address check. */
! 1205: addrval = ntohl (rte->nexthop.s_addr);
! 1206: if (IN_CLASSD (addrval))
! 1207: {
! 1208: zlog_info ("Nexthop %s is multicast address, skip this rte",
! 1209: inet_ntoa (rte->nexthop));
! 1210: continue;
! 1211: }
! 1212:
! 1213: if (! if_lookup_address (rte->nexthop))
! 1214: {
! 1215: struct route_node *rn;
! 1216: struct rip_info *rinfo;
! 1217:
! 1218: rn = route_node_match_ipv4 (rip->table, &rte->nexthop);
! 1219:
! 1220: if (rn)
! 1221: {
! 1222: rinfo = rn->info;
! 1223:
! 1224: if (rinfo->type == ZEBRA_ROUTE_RIP
! 1225: && rinfo->sub_type == RIP_ROUTE_RTE)
! 1226: {
! 1227: if (IS_RIP_DEBUG_EVENT)
! 1228: zlog_debug ("Next hop %s is on RIP network. Set nexthop to the packet's originator", inet_ntoa (rte->nexthop));
! 1229: rte->nexthop = rinfo->from;
! 1230: }
! 1231: else
! 1232: {
! 1233: if (IS_RIP_DEBUG_EVENT)
! 1234: zlog_debug ("Next hop %s is not directly reachable. Treat it as 0.0.0.0", inet_ntoa (rte->nexthop));
! 1235: rte->nexthop.s_addr = 0;
! 1236: }
! 1237:
! 1238: route_unlock_node (rn);
! 1239: }
! 1240: else
! 1241: {
! 1242: if (IS_RIP_DEBUG_EVENT)
! 1243: zlog_debug ("Next hop %s is not directly reachable. Treat it as 0.0.0.0", inet_ntoa (rte->nexthop));
! 1244: rte->nexthop.s_addr = 0;
! 1245: }
! 1246:
! 1247: }
! 1248: }
! 1249:
! 1250: /* For RIPv1, there won't be a valid netmask.
! 1251:
! 1252: This is a best guess at the masks. If everyone was using old
! 1253: Ciscos before the 'ip subnet zero' option, it would be almost
! 1254: right too :-)
! 1255:
! 1256: Cisco summarize ripv1 advertisments to the classful boundary
! 1257: (/16 for class B's) except when the RIP packet does to inside
! 1258: the classful network in question. */
! 1259:
! 1260: if ((packet->version == RIPv1 && rte->prefix.s_addr != 0)
! 1261: || (packet->version == RIPv2
! 1262: && (rte->prefix.s_addr != 0 && rte->mask.s_addr == 0)))
! 1263: {
! 1264: u_int32_t destination;
! 1265:
! 1266: if (subnetted == -1)
! 1267: {
! 1268: memcpy (&ifaddr, ifc->address, sizeof (struct prefix_ipv4));
! 1269: memcpy (&ifaddrclass, &ifaddr, sizeof (struct prefix_ipv4));
! 1270: apply_classful_mask_ipv4 (&ifaddrclass);
! 1271: subnetted = 0;
! 1272: if (ifaddr.prefixlen > ifaddrclass.prefixlen)
! 1273: subnetted = 1;
! 1274: }
! 1275:
! 1276: destination = ntohl (rte->prefix.s_addr);
! 1277:
! 1278: if (IN_CLASSA (destination))
! 1279: masklen2ip (8, &rte->mask);
! 1280: else if (IN_CLASSB (destination))
! 1281: masklen2ip (16, &rte->mask);
! 1282: else if (IN_CLASSC (destination))
! 1283: masklen2ip (24, &rte->mask);
! 1284:
! 1285: if (subnetted == 1)
! 1286: masklen2ip (ifaddrclass.prefixlen,
! 1287: (struct in_addr *) &destination);
! 1288: if ((subnetted == 1) && ((rte->prefix.s_addr & destination) ==
! 1289: ifaddrclass.prefix.s_addr))
! 1290: {
! 1291: masklen2ip (ifaddr.prefixlen, &rte->mask);
! 1292: if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr)
! 1293: masklen2ip (32, &rte->mask);
! 1294: if (IS_RIP_DEBUG_EVENT)
! 1295: zlog_debug ("Subnetted route %s", inet_ntoa (rte->prefix));
! 1296: }
! 1297: else
! 1298: {
! 1299: if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr)
! 1300: continue;
! 1301: }
! 1302:
! 1303: if (IS_RIP_DEBUG_EVENT)
! 1304: {
! 1305: zlog_debug ("Resultant route %s", inet_ntoa (rte->prefix));
! 1306: zlog_debug ("Resultant mask %s", inet_ntoa (rte->mask));
! 1307: }
! 1308: }
! 1309:
! 1310: /* In case of RIPv2, if prefix in RTE is not netmask applied one
! 1311: ignore the entry. */
! 1312: if ((packet->version == RIPv2)
! 1313: && (rte->mask.s_addr != 0)
! 1314: && ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr))
! 1315: {
! 1316: zlog_warn ("RIPv2 address %s is not mask /%d applied one",
! 1317: inet_ntoa (rte->prefix), ip_masklen (rte->mask));
! 1318: rip_peer_bad_route (from);
! 1319: continue;
! 1320: }
! 1321:
! 1322: /* Default route's netmask is ignored. */
! 1323: if (packet->version == RIPv2
! 1324: && (rte->prefix.s_addr == 0)
! 1325: && (rte->mask.s_addr != 0))
! 1326: {
! 1327: if (IS_RIP_DEBUG_EVENT)
! 1328: zlog_debug ("Default route with non-zero netmask. Set zero to netmask");
! 1329: rte->mask.s_addr = 0;
! 1330: }
! 1331:
! 1332: /* Routing table updates. */
! 1333: rip_rte_process (rte, from, ifc->ifp);
! 1334: }
! 1335: }
! 1336:
! 1337: /* Make socket for RIP protocol. */
! 1338: static int
! 1339: rip_create_socket (struct sockaddr_in *from)
! 1340: {
! 1341: int ret;
! 1342: int sock;
! 1343: struct sockaddr_in addr;
! 1344:
! 1345: memset (&addr, 0, sizeof (struct sockaddr_in));
! 1346:
! 1347: if (!from)
! 1348: {
! 1349: addr.sin_family = AF_INET;
! 1350: addr.sin_addr.s_addr = INADDR_ANY;
! 1351: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
! 1352: addr.sin_len = sizeof (struct sockaddr_in);
! 1353: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
! 1354: } else {
! 1355: memcpy(&addr, from, sizeof(addr));
! 1356: }
! 1357:
! 1358: /* sending port must always be the RIP port */
! 1359: addr.sin_port = htons (RIP_PORT_DEFAULT);
! 1360:
! 1361: /* Make datagram socket. */
! 1362: sock = socket (AF_INET, SOCK_DGRAM, 0);
! 1363: if (sock < 0)
! 1364: {
! 1365: zlog_err("Cannot create UDP socket: %s", safe_strerror(errno));
! 1366: exit (1);
! 1367: }
! 1368:
! 1369: sockopt_broadcast (sock);
! 1370: sockopt_reuseaddr (sock);
! 1371: sockopt_reuseport (sock);
! 1372: #ifdef RIP_RECVMSG
! 1373: setsockopt_pktinfo (sock);
! 1374: #endif /* RIP_RECVMSG */
! 1375: #ifdef IPTOS_PREC_INTERNETCONTROL
! 1376: setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL);
! 1377: #endif
! 1378:
! 1379: if (ripd_privs.change (ZPRIVS_RAISE))
! 1380: zlog_err ("rip_create_socket: could not raise privs");
! 1381: setsockopt_so_recvbuf (sock, RIP_UDP_RCV_BUF);
! 1382: if ( (ret = bind (sock, (struct sockaddr *) & addr, sizeof (addr))) < 0)
! 1383:
! 1384: {
! 1385: int save_errno = errno;
! 1386: if (ripd_privs.change (ZPRIVS_LOWER))
! 1387: zlog_err ("rip_create_socket: could not lower privs");
! 1388:
! 1389: zlog_err("%s: Can't bind socket %d to %s port %d: %s", __func__,
! 1390: sock, inet_ntoa(addr.sin_addr),
! 1391: (int) ntohs(addr.sin_port),
! 1392: safe_strerror(save_errno));
! 1393:
! 1394: close (sock);
! 1395: return ret;
! 1396: }
! 1397:
! 1398: if (ripd_privs.change (ZPRIVS_LOWER))
! 1399: zlog_err ("rip_create_socket: could not lower privs");
! 1400:
! 1401: return sock;
! 1402: }
! 1403:
! 1404: /* RIP packet send to destination address, on interface denoted by
! 1405: * by connected argument. NULL to argument denotes destination should be
! 1406: * should be RIP multicast group
! 1407: */
! 1408: static int
! 1409: rip_send_packet (u_char * buf, int size, struct sockaddr_in *to,
! 1410: struct connected *ifc)
! 1411: {
! 1412: int ret, send_sock;
! 1413: struct sockaddr_in sin;
! 1414:
! 1415: assert (ifc != NULL);
! 1416:
! 1417: if (IS_RIP_DEBUG_PACKET)
! 1418: {
! 1419: #define ADDRESS_SIZE 20
! 1420: char dst[ADDRESS_SIZE];
! 1421: dst[ADDRESS_SIZE - 1] = '\0';
! 1422:
! 1423: if (to)
! 1424: {
! 1425: strncpy (dst, inet_ntoa(to->sin_addr), ADDRESS_SIZE - 1);
! 1426: }
! 1427: else
! 1428: {
! 1429: sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);
! 1430: strncpy (dst, inet_ntoa(sin.sin_addr), ADDRESS_SIZE - 1);
! 1431: }
! 1432: #undef ADDRESS_SIZE
! 1433: zlog_debug("rip_send_packet %s > %s (%s)",
! 1434: inet_ntoa(ifc->address->u.prefix4),
! 1435: dst, ifc->ifp->name);
! 1436: }
! 1437:
! 1438: if ( CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY) )
! 1439: {
! 1440: /*
! 1441: * ZEBRA_IFA_SECONDARY is set on linux when an interface is configured
! 1442: * with multiple addresses on the same subnet: the first address
! 1443: * on the subnet is configured "primary", and all subsequent addresses
! 1444: * on that subnet are treated as "secondary" addresses.
! 1445: * In order to avoid routing-table bloat on other rip listeners,
! 1446: * we do not send out RIP packets with ZEBRA_IFA_SECONDARY source addrs.
! 1447: * XXX Since Linux is the only system for which the ZEBRA_IFA_SECONDARY
! 1448: * flag is set, we would end up sending a packet for a "secondary"
! 1449: * source address on non-linux systems.
! 1450: */
! 1451: if (IS_RIP_DEBUG_PACKET)
! 1452: zlog_debug("duplicate dropped");
! 1453: return 0;
! 1454: }
! 1455:
! 1456: /* Make destination address. */
! 1457: memset (&sin, 0, sizeof (struct sockaddr_in));
! 1458: sin.sin_family = AF_INET;
! 1459: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
! 1460: sin.sin_len = sizeof (struct sockaddr_in);
! 1461: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
! 1462:
! 1463: /* When destination is specified, use it's port and address. */
! 1464: if (to)
! 1465: {
! 1466: sin.sin_port = to->sin_port;
! 1467: sin.sin_addr = to->sin_addr;
! 1468: send_sock = rip->sock;
! 1469: }
! 1470: else
! 1471: {
! 1472: struct sockaddr_in from;
! 1473:
! 1474: sin.sin_port = htons (RIP_PORT_DEFAULT);
! 1475: sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);
! 1476:
! 1477: /* multicast send should bind to local interface address */
! 1478: from.sin_family = AF_INET;
! 1479: from.sin_port = htons (RIP_PORT_DEFAULT);
! 1480: from.sin_addr = ifc->address->u.prefix4;
! 1481: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
! 1482: from.sin_len = sizeof (struct sockaddr_in);
! 1483: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
! 1484:
! 1485: /*
! 1486: * we have to open a new socket for each packet because this
! 1487: * is the most portable way to bind to a different source
! 1488: * ipv4 address for each packet.
! 1489: */
! 1490: if ( (send_sock = rip_create_socket (&from)) < 0)
! 1491: {
! 1492: zlog_warn("rip_send_packet could not create socket.");
! 1493: return -1;
! 1494: }
! 1495: rip_interface_multicast_set (send_sock, ifc);
! 1496: }
! 1497:
! 1498: ret = sendto (send_sock, buf, size, 0, (struct sockaddr *)&sin,
! 1499: sizeof (struct sockaddr_in));
! 1500:
! 1501: if (IS_RIP_DEBUG_EVENT)
! 1502: zlog_debug ("SEND to %s.%d", inet_ntoa(sin.sin_addr),
! 1503: ntohs (sin.sin_port));
! 1504:
! 1505: if (ret < 0)
! 1506: zlog_warn ("can't send packet : %s", safe_strerror (errno));
! 1507:
! 1508: if (!to)
! 1509: close(send_sock);
! 1510:
! 1511: return ret;
! 1512: }
! 1513:
! 1514: /* Add redistributed route to RIP table. */
! 1515: void
! 1516: rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p,
! 1517: unsigned int ifindex, struct in_addr *nexthop,
! 1518: unsigned int metric, unsigned char distance)
! 1519: {
! 1520: int ret;
! 1521: struct route_node *rp;
! 1522: struct rip_info *rinfo;
! 1523:
! 1524: /* Redistribute route */
! 1525: ret = rip_destination_check (p->prefix);
! 1526: if (! ret)
! 1527: return;
! 1528:
! 1529: rp = route_node_get (rip->table, (struct prefix *) p);
! 1530:
! 1531: rinfo = rp->info;
! 1532:
! 1533: if (rinfo)
! 1534: {
! 1535: if (rinfo->type == ZEBRA_ROUTE_CONNECT
! 1536: && rinfo->sub_type == RIP_ROUTE_INTERFACE
! 1537: && rinfo->metric != RIP_METRIC_INFINITY)
! 1538: {
! 1539: route_unlock_node (rp);
! 1540: return;
! 1541: }
! 1542:
! 1543: /* Manually configured RIP route check. */
! 1544: if (rinfo->type == ZEBRA_ROUTE_RIP
! 1545: && ((rinfo->sub_type == RIP_ROUTE_STATIC) ||
! 1546: (rinfo->sub_type == RIP_ROUTE_DEFAULT)) )
! 1547: {
! 1548: if (type != ZEBRA_ROUTE_RIP || ((sub_type != RIP_ROUTE_STATIC) &&
! 1549: (sub_type != RIP_ROUTE_DEFAULT)))
! 1550: {
! 1551: route_unlock_node (rp);
! 1552: return;
! 1553: }
! 1554: }
! 1555:
! 1556: RIP_TIMER_OFF (rinfo->t_timeout);
! 1557: RIP_TIMER_OFF (rinfo->t_garbage_collect);
! 1558:
! 1559: if (rip_route_rte (rinfo))
! 1560: rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p, &rinfo->nexthop,
! 1561: rinfo->metric);
! 1562: rp->info = NULL;
! 1563: rip_info_free (rinfo);
! 1564:
! 1565: route_unlock_node (rp);
! 1566: }
! 1567:
! 1568: rinfo = rip_info_new ();
! 1569:
! 1570: rinfo->type = type;
! 1571: rinfo->sub_type = sub_type;
! 1572: rinfo->ifindex = ifindex;
! 1573: rinfo->metric = 1;
! 1574: rinfo->external_metric = metric;
! 1575: rinfo->distance = distance;
! 1576: rinfo->rp = rp;
! 1577:
! 1578: if (nexthop)
! 1579: rinfo->nexthop = *nexthop;
! 1580:
! 1581: rinfo->flags |= RIP_RTF_FIB;
! 1582: rp->info = rinfo;
! 1583:
! 1584: rinfo->flags |= RIP_RTF_CHANGED;
! 1585:
! 1586: if (IS_RIP_DEBUG_EVENT) {
! 1587: if (!nexthop)
! 1588: zlog_debug ("Redistribute new prefix %s/%d on the interface %s",
! 1589: inet_ntoa(p->prefix), p->prefixlen,
! 1590: ifindex2ifname(ifindex));
! 1591: else
! 1592: zlog_debug ("Redistribute new prefix %s/%d with nexthop %s on the interface %s",
! 1593: inet_ntoa(p->prefix), p->prefixlen, inet_ntoa(rinfo->nexthop),
! 1594: ifindex2ifname(ifindex));
! 1595: }
! 1596:
! 1597:
! 1598: rip_event (RIP_TRIGGERED_UPDATE, 0);
! 1599: }
! 1600:
! 1601: /* Delete redistributed route from RIP table. */
! 1602: void
! 1603: rip_redistribute_delete (int type, int sub_type, struct prefix_ipv4 *p,
! 1604: unsigned int ifindex)
! 1605: {
! 1606: int ret;
! 1607: struct route_node *rp;
! 1608: struct rip_info *rinfo;
! 1609:
! 1610: ret = rip_destination_check (p->prefix);
! 1611: if (! ret)
! 1612: return;
! 1613:
! 1614: rp = route_node_lookup (rip->table, (struct prefix *) p);
! 1615: if (rp)
! 1616: {
! 1617: rinfo = rp->info;
! 1618:
! 1619: if (rinfo != NULL
! 1620: && rinfo->type == type
! 1621: && rinfo->sub_type == sub_type
! 1622: && rinfo->ifindex == ifindex)
! 1623: {
! 1624: /* Perform poisoned reverse. */
! 1625: rinfo->metric = RIP_METRIC_INFINITY;
! 1626: RIP_TIMER_ON (rinfo->t_garbage_collect,
! 1627: rip_garbage_collect, rip->garbage_time);
! 1628: RIP_TIMER_OFF (rinfo->t_timeout);
! 1629: rinfo->flags |= RIP_RTF_CHANGED;
! 1630:
! 1631: if (IS_RIP_DEBUG_EVENT)
! 1632: zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [delete]",
! 1633: inet_ntoa(p->prefix), p->prefixlen,
! 1634: ifindex2ifname(ifindex));
! 1635:
! 1636: rip_event (RIP_TRIGGERED_UPDATE, 0);
! 1637: }
! 1638: }
! 1639: }
! 1640:
! 1641: /* Response to request called from rip_read ().*/
! 1642: static void
! 1643: rip_request_process (struct rip_packet *packet, int size,
! 1644: struct sockaddr_in *from, struct connected *ifc)
! 1645: {
! 1646: caddr_t lim;
! 1647: struct rte *rte;
! 1648: struct prefix_ipv4 p;
! 1649: struct route_node *rp;
! 1650: struct rip_info *rinfo;
! 1651: struct rip_interface *ri;
! 1652:
! 1653: /* Does not reponse to the requests on the loopback interfaces */
! 1654: if (if_is_loopback (ifc->ifp))
! 1655: return;
! 1656:
! 1657: /* Check RIP process is enabled on this interface. */
! 1658: ri = ifc->ifp->info;
! 1659: if (! ri->running)
! 1660: return;
! 1661:
! 1662: /* When passive interface is specified, suppress responses */
! 1663: if (ri->passive)
! 1664: return;
! 1665:
! 1666: /* RIP peer update. */
! 1667: rip_peer_update (from, packet->version);
! 1668:
! 1669: lim = ((caddr_t) packet) + size;
! 1670: rte = packet->rte;
! 1671:
! 1672: /* The Request is processed entry by entry. If there are no
! 1673: entries, no response is given. */
! 1674: if (lim == (caddr_t) rte)
! 1675: return;
! 1676:
! 1677: /* There is one special case. If there is exactly one entry in the
! 1678: request, and it has an address family identifier of zero and a
! 1679: metric of infinity (i.e., 16), then this is a request to send the
! 1680: entire routing table. */
! 1681: if (lim == ((caddr_t) (rte + 1)) &&
! 1682: ntohs (rte->family) == 0 &&
! 1683: ntohl (rte->metric) == RIP_METRIC_INFINITY)
! 1684: {
! 1685: struct prefix_ipv4 saddr;
! 1686:
! 1687: /* saddr will be used for determining which routes to split-horizon.
! 1688: Since the source address we'll pick will be on the same subnet as the
! 1689: destination, for the purpose of split-horizoning, we'll
! 1690: pretend that "from" is our source address. */
! 1691: saddr.family = AF_INET;
! 1692: saddr.prefixlen = IPV4_MAX_BITLEN;
! 1693: saddr.prefix = from->sin_addr;
! 1694:
! 1695: /* All route with split horizon */
! 1696: rip_output_process (ifc, from, rip_all_route, packet->version);
! 1697: }
! 1698: else
! 1699: {
! 1700: /* Examine the list of RTEs in the Request one by one. For each
! 1701: entry, look up the destination in the router's routing
! 1702: database and, if there is a route, put that route's metric in
! 1703: the metric field of the RTE. If there is no explicit route
! 1704: to the specified destination, put infinity in the metric
! 1705: field. Once all the entries have been filled in, change the
! 1706: command from Request to Response and send the datagram back
! 1707: to the requestor. */
! 1708: p.family = AF_INET;
! 1709:
! 1710: for (; ((caddr_t) rte) < lim; rte++)
! 1711: {
! 1712: p.prefix = rte->prefix;
! 1713: p.prefixlen = ip_masklen (rte->mask);
! 1714: apply_mask_ipv4 (&p);
! 1715:
! 1716: rp = route_node_lookup (rip->table, (struct prefix *) &p);
! 1717: if (rp)
! 1718: {
! 1719: rinfo = rp->info;
! 1720: rte->metric = htonl (rinfo->metric);
! 1721: route_unlock_node (rp);
! 1722: }
! 1723: else
! 1724: rte->metric = htonl (RIP_METRIC_INFINITY);
! 1725: }
! 1726: packet->command = RIP_RESPONSE;
! 1727:
! 1728: rip_send_packet ((u_char *)packet, size, from, ifc);
! 1729: }
! 1730: rip_global_queries++;
! 1731: }
! 1732:
! 1733: #if RIP_RECVMSG
! 1734: /* Set IPv6 packet info to the socket. */
! 1735: static int
! 1736: setsockopt_pktinfo (int sock)
! 1737: {
! 1738: int ret;
! 1739: int val = 1;
! 1740:
! 1741: ret = setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof(val));
! 1742: if (ret < 0)
! 1743: zlog_warn ("Can't setsockopt IP_PKTINFO : %s", safe_strerror (errno));
! 1744: return ret;
! 1745: }
! 1746:
! 1747: /* Read RIP packet by recvmsg function. */
! 1748: int
! 1749: rip_recvmsg (int sock, u_char *buf, int size, struct sockaddr_in *from,
! 1750: int *ifindex)
! 1751: {
! 1752: int ret;
! 1753: struct msghdr msg;
! 1754: struct iovec iov;
! 1755: struct cmsghdr *ptr;
! 1756: char adata[1024];
! 1757:
! 1758: msg.msg_name = (void *) from;
! 1759: msg.msg_namelen = sizeof (struct sockaddr_in);
! 1760: msg.msg_iov = &iov;
! 1761: msg.msg_iovlen = 1;
! 1762: msg.msg_control = (void *) adata;
! 1763: msg.msg_controllen = sizeof adata;
! 1764: iov.iov_base = buf;
! 1765: iov.iov_len = size;
! 1766:
! 1767: ret = recvmsg (sock, &msg, 0);
! 1768: if (ret < 0)
! 1769: return ret;
! 1770:
! 1771: for (ptr = ZCMSG_FIRSTHDR(&msg); ptr != NULL; ptr = CMSG_NXTHDR(&msg, ptr))
! 1772: if (ptr->cmsg_level == IPPROTO_IP && ptr->cmsg_type == IP_PKTINFO)
! 1773: {
! 1774: struct in_pktinfo *pktinfo;
! 1775: int i;
! 1776:
! 1777: pktinfo = (struct in_pktinfo *) CMSG_DATA (ptr);
! 1778: i = pktinfo->ipi_ifindex;
! 1779: }
! 1780: return ret;
! 1781: }
! 1782:
! 1783: /* RIP packet read function. */
! 1784: int
! 1785: rip_read_new (struct thread *t)
! 1786: {
! 1787: int ret;
! 1788: int sock;
! 1789: char buf[RIP_PACKET_MAXSIZ];
! 1790: struct sockaddr_in from;
! 1791: unsigned int ifindex;
! 1792:
! 1793: /* Fetch socket then register myself. */
! 1794: sock = THREAD_FD (t);
! 1795: rip_event (RIP_READ, sock);
! 1796:
! 1797: /* Read RIP packet. */
! 1798: ret = rip_recvmsg (sock, buf, RIP_PACKET_MAXSIZ, &from, (int *)&ifindex);
! 1799: if (ret < 0)
! 1800: {
! 1801: zlog_warn ("Can't read RIP packet: %s", safe_strerror (errno));
! 1802: return ret;
! 1803: }
! 1804:
! 1805: return ret;
! 1806: }
! 1807: #endif /* RIP_RECVMSG */
! 1808:
! 1809: /* First entry point of RIP packet. */
! 1810: static int
! 1811: rip_read (struct thread *t)
! 1812: {
! 1813: int sock;
! 1814: int ret;
! 1815: int rtenum;
! 1816: union rip_buf rip_buf;
! 1817: struct rip_packet *packet;
! 1818: struct sockaddr_in from;
! 1819: int len;
! 1820: int vrecv;
! 1821: socklen_t fromlen;
! 1822: struct interface *ifp;
! 1823: struct connected *ifc;
! 1824: struct rip_interface *ri;
! 1825:
! 1826: /* Fetch socket then register myself. */
! 1827: sock = THREAD_FD (t);
! 1828: rip->t_read = NULL;
! 1829:
! 1830: /* Add myself to tne next event */
! 1831: rip_event (RIP_READ, sock);
! 1832:
! 1833: /* RIPd manages only IPv4. */
! 1834: memset (&from, 0, sizeof (struct sockaddr_in));
! 1835: fromlen = sizeof (struct sockaddr_in);
! 1836:
! 1837: len = recvfrom (sock, (char *)&rip_buf.buf, sizeof (rip_buf.buf), 0,
! 1838: (struct sockaddr *) &from, &fromlen);
! 1839: if (len < 0)
! 1840: {
! 1841: zlog_info ("recvfrom failed: %s", safe_strerror (errno));
! 1842: return len;
! 1843: }
! 1844:
! 1845: /* Check is this packet comming from myself? */
! 1846: if (if_check_address (from.sin_addr))
! 1847: {
! 1848: if (IS_RIP_DEBUG_PACKET)
! 1849: zlog_debug ("ignore packet comes from myself");
! 1850: return -1;
! 1851: }
! 1852:
! 1853: /* Which interface is this packet comes from. */
! 1854: ifp = if_lookup_address (from.sin_addr);
! 1855:
! 1856: /* RIP packet received */
! 1857: if (IS_RIP_DEBUG_EVENT)
! 1858: zlog_debug ("RECV packet from %s port %d on %s",
! 1859: inet_ntoa (from.sin_addr), ntohs (from.sin_port),
! 1860: ifp ? ifp->name : "unknown");
! 1861:
! 1862: /* If this packet come from unknown interface, ignore it. */
! 1863: if (ifp == NULL)
! 1864: {
! 1865: zlog_info ("rip_read: cannot find interface for packet from %s port %d",
! 1866: inet_ntoa(from.sin_addr), ntohs (from.sin_port));
! 1867: return -1;
! 1868: }
! 1869:
! 1870: ifc = connected_lookup_address (ifp, from.sin_addr);
! 1871:
! 1872: if (ifc == NULL)
! 1873: {
! 1874: zlog_info ("rip_read: cannot find connected address for packet from %s "
! 1875: "port %d on interface %s",
! 1876: inet_ntoa(from.sin_addr), ntohs (from.sin_port), ifp->name);
! 1877: return -1;
! 1878: }
! 1879:
! 1880: /* Packet length check. */
! 1881: if (len < RIP_PACKET_MINSIZ)
! 1882: {
! 1883: zlog_warn ("packet size %d is smaller than minimum size %d",
! 1884: len, RIP_PACKET_MINSIZ);
! 1885: rip_peer_bad_packet (&from);
! 1886: return len;
! 1887: }
! 1888: if (len > RIP_PACKET_MAXSIZ)
! 1889: {
! 1890: zlog_warn ("packet size %d is larger than max size %d",
! 1891: len, RIP_PACKET_MAXSIZ);
! 1892: rip_peer_bad_packet (&from);
! 1893: return len;
! 1894: }
! 1895:
! 1896: /* Packet alignment check. */
! 1897: if ((len - RIP_PACKET_MINSIZ) % 20)
! 1898: {
! 1899: zlog_warn ("packet size %d is wrong for RIP packet alignment", len);
! 1900: rip_peer_bad_packet (&from);
! 1901: return len;
! 1902: }
! 1903:
! 1904: /* Set RTE number. */
! 1905: rtenum = ((len - RIP_PACKET_MINSIZ) / 20);
! 1906:
! 1907: /* For easy to handle. */
! 1908: packet = &rip_buf.rip_packet;
! 1909:
! 1910: /* RIP version check. */
! 1911: if (packet->version == 0)
! 1912: {
! 1913: zlog_info ("version 0 with command %d received.", packet->command);
! 1914: rip_peer_bad_packet (&from);
! 1915: return -1;
! 1916: }
! 1917:
! 1918: /* Dump RIP packet. */
! 1919: if (IS_RIP_DEBUG_RECV)
! 1920: rip_packet_dump (packet, len, "RECV");
! 1921:
! 1922: /* RIP version adjust. This code should rethink now. RFC1058 says
! 1923: that "Version 1 implementations are to ignore this extra data and
! 1924: process only the fields specified in this document.". So RIPv3
! 1925: packet should be treated as RIPv1 ignoring must be zero field. */
! 1926: if (packet->version > RIPv2)
! 1927: packet->version = RIPv2;
! 1928:
! 1929: /* Is RIP running or is this RIP neighbor ?*/
! 1930: ri = ifp->info;
! 1931: if (! ri->running && ! rip_neighbor_lookup (&from))
! 1932: {
! 1933: if (IS_RIP_DEBUG_EVENT)
! 1934: zlog_debug ("RIP is not enabled on interface %s.", ifp->name);
! 1935: rip_peer_bad_packet (&from);
! 1936: return -1;
! 1937: }
! 1938:
! 1939: /* RIP Version check. RFC2453, 4.6 and 5.1 */
! 1940: vrecv = ((ri->ri_receive == RI_RIP_UNSPEC) ?
! 1941: rip->version_recv : ri->ri_receive);
! 1942: if ((packet->version == RIPv1) && !(vrecv & RIPv1))
! 1943: {
! 1944: if (IS_RIP_DEBUG_PACKET)
! 1945: zlog_debug (" packet's v%d doesn't fit to if version spec",
! 1946: packet->version);
! 1947: rip_peer_bad_packet (&from);
! 1948: return -1;
! 1949: }
! 1950: if ((packet->version == RIPv2) && !(vrecv & RIPv2))
! 1951: {
! 1952: if (IS_RIP_DEBUG_PACKET)
! 1953: zlog_debug (" packet's v%d doesn't fit to if version spec",
! 1954: packet->version);
! 1955: rip_peer_bad_packet (&from);
! 1956: return -1;
! 1957: }
! 1958:
! 1959: /* RFC2453 5.2 If the router is not configured to authenticate RIP-2
! 1960: messages, then RIP-1 and unauthenticated RIP-2 messages will be
! 1961: accepted; authenticated RIP-2 messages shall be discarded. */
! 1962: if ((ri->auth_type == RIP_NO_AUTH)
! 1963: && rtenum
! 1964: && (packet->version == RIPv2)
! 1965: && (packet->rte->family == htons(RIP_FAMILY_AUTH)))
! 1966: {
! 1967: if (IS_RIP_DEBUG_EVENT)
! 1968: zlog_debug ("packet RIPv%d is dropped because authentication disabled",
! 1969: packet->version);
! 1970: rip_peer_bad_packet (&from);
! 1971: return -1;
! 1972: }
! 1973:
! 1974: /* RFC:
! 1975: If the router is configured to authenticate RIP-2 messages, then
! 1976: RIP-1 messages and RIP-2 messages which pass authentication
! 1977: testing shall be accepted; unauthenticated and failed
! 1978: authentication RIP-2 messages shall be discarded. For maximum
! 1979: security, RIP-1 messages should be ignored when authentication is
! 1980: in use (see section 4.1); otherwise, the routing information from
! 1981: authenticated messages will be propagated by RIP-1 routers in an
! 1982: unauthenticated manner.
! 1983: */
! 1984: /* We make an exception for RIPv1 REQUEST packets, to which we'll
! 1985: * always reply regardless of authentication settings, because:
! 1986: *
! 1987: * - if there other authorised routers on-link, the REQUESTor can
! 1988: * passively obtain the routing updates anyway
! 1989: * - if there are no other authorised routers on-link, RIP can
! 1990: * easily be disabled for the link to prevent giving out information
! 1991: * on state of this routers RIP routing table..
! 1992: *
! 1993: * I.e. if RIPv1 has any place anymore these days, it's as a very
! 1994: * simple way to distribute routing information (e.g. to embedded
! 1995: * hosts / appliances) and the ability to give out RIPv1
! 1996: * routing-information freely, while still requiring RIPv2
! 1997: * authentication for any RESPONSEs might be vaguely useful.
! 1998: */
! 1999: if (ri->auth_type != RIP_NO_AUTH
! 2000: && packet->version == RIPv1)
! 2001: {
! 2002: /* Discard RIPv1 messages other than REQUESTs */
! 2003: if (packet->command != RIP_REQUEST)
! 2004: {
! 2005: if (IS_RIP_DEBUG_PACKET)
! 2006: zlog_debug ("RIPv1" " dropped because authentication enabled");
! 2007: rip_peer_bad_packet (&from);
! 2008: return -1;
! 2009: }
! 2010: }
! 2011: else if (ri->auth_type != RIP_NO_AUTH)
! 2012: {
! 2013: const char *auth_desc;
! 2014:
! 2015: if (rtenum == 0)
! 2016: {
! 2017: /* There definitely is no authentication in the packet. */
! 2018: if (IS_RIP_DEBUG_PACKET)
! 2019: zlog_debug ("RIPv2 authentication failed: no auth RTE in packet");
! 2020: rip_peer_bad_packet (&from);
! 2021: return -1;
! 2022: }
! 2023:
! 2024: /* First RTE must be an Authentication Family RTE */
! 2025: if (packet->rte->family != htons(RIP_FAMILY_AUTH))
! 2026: {
! 2027: if (IS_RIP_DEBUG_PACKET)
! 2028: zlog_debug ("RIPv2" " dropped because authentication enabled");
! 2029: rip_peer_bad_packet (&from);
! 2030: return -1;
! 2031: }
! 2032:
! 2033: /* Check RIPv2 authentication. */
! 2034: switch (ntohs(packet->rte->tag))
! 2035: {
! 2036: case RIP_AUTH_SIMPLE_PASSWORD:
! 2037: auth_desc = "simple";
! 2038: ret = rip_auth_simple_password (packet->rte, &from, ifp);
! 2039: break;
! 2040:
! 2041: case RIP_AUTH_MD5:
! 2042: auth_desc = "MD5";
! 2043: ret = rip_auth_md5 (packet, &from, len, ifp);
! 2044: /* Reset RIP packet length to trim MD5 data. */
! 2045: len = ret;
! 2046: break;
! 2047:
! 2048: default:
! 2049: ret = 0;
! 2050: auth_desc = "unknown type";
! 2051: if (IS_RIP_DEBUG_PACKET)
! 2052: zlog_debug ("RIPv2 Unknown authentication type %d",
! 2053: ntohs (packet->rte->tag));
! 2054: }
! 2055:
! 2056: if (ret)
! 2057: {
! 2058: if (IS_RIP_DEBUG_PACKET)
! 2059: zlog_debug ("RIPv2 %s authentication success", auth_desc);
! 2060: }
! 2061: else
! 2062: {
! 2063: if (IS_RIP_DEBUG_PACKET)
! 2064: zlog_debug ("RIPv2 %s authentication failure", auth_desc);
! 2065: rip_peer_bad_packet (&from);
! 2066: return -1;
! 2067: }
! 2068: }
! 2069:
! 2070: /* Process each command. */
! 2071: switch (packet->command)
! 2072: {
! 2073: case RIP_RESPONSE:
! 2074: rip_response_process (packet, len, &from, ifc);
! 2075: break;
! 2076: case RIP_REQUEST:
! 2077: case RIP_POLL:
! 2078: rip_request_process (packet, len, &from, ifc);
! 2079: break;
! 2080: case RIP_TRACEON:
! 2081: case RIP_TRACEOFF:
! 2082: zlog_info ("Obsolete command %s received, please sent it to routed",
! 2083: lookup (rip_msg, packet->command));
! 2084: rip_peer_bad_packet (&from);
! 2085: break;
! 2086: case RIP_POLL_ENTRY:
! 2087: zlog_info ("Obsolete command %s received",
! 2088: lookup (rip_msg, packet->command));
! 2089: rip_peer_bad_packet (&from);
! 2090: break;
! 2091: default:
! 2092: zlog_info ("Unknown RIP command %d received", packet->command);
! 2093: rip_peer_bad_packet (&from);
! 2094: break;
! 2095: }
! 2096:
! 2097: return len;
! 2098: }
! 2099:
! 2100: /* Write routing table entry to the stream and return next index of
! 2101: the routing table entry in the stream. */
! 2102: static int
! 2103: rip_write_rte (int num, struct stream *s, struct prefix_ipv4 *p,
! 2104: u_char version, struct rip_info *rinfo)
! 2105: {
! 2106: struct in_addr mask;
! 2107:
! 2108: /* Write routing table entry. */
! 2109: if (version == RIPv1)
! 2110: {
! 2111: stream_putw (s, AF_INET);
! 2112: stream_putw (s, 0);
! 2113: stream_put_ipv4 (s, p->prefix.s_addr);
! 2114: stream_put_ipv4 (s, 0);
! 2115: stream_put_ipv4 (s, 0);
! 2116: stream_putl (s, rinfo->metric_out);
! 2117: }
! 2118: else
! 2119: {
! 2120: masklen2ip (p->prefixlen, &mask);
! 2121:
! 2122: stream_putw (s, AF_INET);
! 2123: stream_putw (s, rinfo->tag_out);
! 2124: stream_put_ipv4 (s, p->prefix.s_addr);
! 2125: stream_put_ipv4 (s, mask.s_addr);
! 2126: stream_put_ipv4 (s, rinfo->nexthop_out.s_addr);
! 2127: stream_putl (s, rinfo->metric_out);
! 2128: }
! 2129:
! 2130: return ++num;
! 2131: }
! 2132:
! 2133: /* Send update to the ifp or spcified neighbor. */
! 2134: void
! 2135: rip_output_process (struct connected *ifc, struct sockaddr_in *to,
! 2136: int route_type, u_char version)
! 2137: {
! 2138: int ret;
! 2139: struct stream *s;
! 2140: struct route_node *rp;
! 2141: struct rip_info *rinfo;
! 2142: struct rip_interface *ri;
! 2143: struct prefix_ipv4 *p;
! 2144: struct prefix_ipv4 classfull;
! 2145: struct prefix_ipv4 ifaddrclass;
! 2146: struct key *key = NULL;
! 2147: /* this might need to made dynamic if RIP ever supported auth methods
! 2148: with larger key string sizes */
! 2149: char auth_str[RIP_AUTH_SIMPLE_SIZE];
! 2150: size_t doff = 0; /* offset of digest offset field */
! 2151: int num = 0;
! 2152: int rtemax;
! 2153: int subnetted = 0;
! 2154:
! 2155: /* Logging output event. */
! 2156: if (IS_RIP_DEBUG_EVENT)
! 2157: {
! 2158: if (to)
! 2159: zlog_debug ("update routes to neighbor %s", inet_ntoa (to->sin_addr));
! 2160: else
! 2161: zlog_debug ("update routes on interface %s ifindex %d",
! 2162: ifc->ifp->name, ifc->ifp->ifindex);
! 2163: }
! 2164:
! 2165: /* Set output stream. */
! 2166: s = rip->obuf;
! 2167:
! 2168: /* Reset stream and RTE counter. */
! 2169: stream_reset (s);
! 2170: rtemax = (RIP_PACKET_MAXSIZ - 4) / 20;
! 2171:
! 2172: /* Get RIP interface. */
! 2173: ri = ifc->ifp->info;
! 2174:
! 2175: /* If output interface is in simple password authentication mode, we
! 2176: need space for authentication data. */
! 2177: if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD)
! 2178: rtemax -= 1;
! 2179:
! 2180: /* If output interface is in MD5 authentication mode, we need space
! 2181: for authentication header and data. */
! 2182: if (ri->auth_type == RIP_AUTH_MD5)
! 2183: rtemax -= 2;
! 2184:
! 2185: /* If output interface is in simple password authentication mode
! 2186: and string or keychain is specified we need space for auth. data */
! 2187: if (ri->auth_type != RIP_NO_AUTH)
! 2188: {
! 2189: if (ri->key_chain)
! 2190: {
! 2191: struct keychain *keychain;
! 2192:
! 2193: keychain = keychain_lookup (ri->key_chain);
! 2194: if (keychain)
! 2195: key = key_lookup_for_send (keychain);
! 2196: }
! 2197: /* to be passed to auth functions later */
! 2198: rip_auth_prepare_str_send (ri, key, auth_str, RIP_AUTH_SIMPLE_SIZE);
! 2199: }
! 2200:
! 2201: if (version == RIPv1)
! 2202: {
! 2203: memcpy (&ifaddrclass, ifc->address, sizeof (struct prefix_ipv4));
! 2204: apply_classful_mask_ipv4 (&ifaddrclass);
! 2205: subnetted = 0;
! 2206: if (ifc->address->prefixlen > ifaddrclass.prefixlen)
! 2207: subnetted = 1;
! 2208: }
! 2209:
! 2210: for (rp = route_top (rip->table); rp; rp = route_next (rp))
! 2211: if ((rinfo = rp->info) != NULL)
! 2212: {
! 2213: /* For RIPv1, if we are subnetted, output subnets in our network */
! 2214: /* that have the same mask as the output "interface". For other */
! 2215: /* networks, only the classfull version is output. */
! 2216:
! 2217: if (version == RIPv1)
! 2218: {
! 2219: p = (struct prefix_ipv4 *) &rp->p;
! 2220:
! 2221: if (IS_RIP_DEBUG_PACKET)
! 2222: zlog_debug("RIPv1 mask check, %s/%d considered for output",
! 2223: inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen);
! 2224:
! 2225: if (subnetted &&
! 2226: prefix_match ((struct prefix *) &ifaddrclass, &rp->p))
! 2227: {
! 2228: if ((ifc->address->prefixlen != rp->p.prefixlen) &&
! 2229: (rp->p.prefixlen != 32))
! 2230: continue;
! 2231: }
! 2232: else
! 2233: {
! 2234: memcpy (&classfull, &rp->p, sizeof(struct prefix_ipv4));
! 2235: apply_classful_mask_ipv4(&classfull);
! 2236: if (rp->p.u.prefix4.s_addr != 0 &&
! 2237: classfull.prefixlen != rp->p.prefixlen)
! 2238: continue;
! 2239: }
! 2240: if (IS_RIP_DEBUG_PACKET)
! 2241: zlog_debug("RIPv1 mask check, %s/%d made it through",
! 2242: inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen);
! 2243: }
! 2244: else
! 2245: p = (struct prefix_ipv4 *) &rp->p;
! 2246:
! 2247: /* Apply output filters. */
! 2248: ret = rip_outgoing_filter (p, ri);
! 2249: if (ret < 0)
! 2250: continue;
! 2251:
! 2252: /* Changed route only output. */
! 2253: if (route_type == rip_changed_route &&
! 2254: (! (rinfo->flags & RIP_RTF_CHANGED)))
! 2255: continue;
! 2256:
! 2257: /* Split horizon. */
! 2258: /* if (split_horizon == rip_split_horizon) */
! 2259: if (ri->split_horizon == RIP_SPLIT_HORIZON)
! 2260: {
! 2261: /*
! 2262: * We perform split horizon for RIP and connected route.
! 2263: * For rip routes, we want to suppress the route if we would
! 2264: * end up sending the route back on the interface that we
! 2265: * learned it from, with a higher metric. For connected routes,
! 2266: * we suppress the route if the prefix is a subset of the
! 2267: * source address that we are going to use for the packet
! 2268: * (in order to handle the case when multiple subnets are
! 2269: * configured on the same interface).
! 2270: */
! 2271: if (rinfo->type == ZEBRA_ROUTE_RIP &&
! 2272: rinfo->ifindex == ifc->ifp->ifindex)
! 2273: continue;
! 2274: if (rinfo->type == ZEBRA_ROUTE_CONNECT &&
! 2275: prefix_match((struct prefix *)p, ifc->address))
! 2276: continue;
! 2277: }
! 2278:
! 2279: /* Preparation for route-map. */
! 2280: rinfo->metric_set = 0;
! 2281: rinfo->nexthop_out.s_addr = 0;
! 2282: rinfo->metric_out = rinfo->metric;
! 2283: rinfo->tag_out = rinfo->tag;
! 2284: rinfo->ifindex_out = ifc->ifp->ifindex;
! 2285:
! 2286: /* In order to avoid some local loops,
! 2287: * if the RIP route has a nexthop via this interface, keep the nexthop,
! 2288: * otherwise set it to 0. The nexthop should not be propagated
! 2289: * beyond the local broadcast/multicast area in order
! 2290: * to avoid an IGP multi-level recursive look-up.
! 2291: * see (4.4)
! 2292: */
! 2293: if (rinfo->ifindex == ifc->ifp->ifindex)
! 2294: rinfo->nexthop_out = rinfo->nexthop;
! 2295:
! 2296: /* Interface route-map */
! 2297: if (ri->routemap[RIP_FILTER_OUT])
! 2298: {
! 2299: ret = route_map_apply (ri->routemap[RIP_FILTER_OUT],
! 2300: (struct prefix *) p, RMAP_RIP,
! 2301: rinfo);
! 2302:
! 2303: if (ret == RMAP_DENYMATCH)
! 2304: {
! 2305: if (IS_RIP_DEBUG_PACKET)
! 2306: zlog_debug ("RIP %s/%d is filtered by route-map out",
! 2307: inet_ntoa (p->prefix), p->prefixlen);
! 2308: continue;
! 2309: }
! 2310: }
! 2311:
! 2312: /* Apply redistribute route map - continue, if deny */
! 2313: if (rip->route_map[rinfo->type].name
! 2314: && rinfo->sub_type != RIP_ROUTE_INTERFACE)
! 2315: {
! 2316: ret = route_map_apply (rip->route_map[rinfo->type].map,
! 2317: (struct prefix *)p, RMAP_RIP, rinfo);
! 2318:
! 2319: if (ret == RMAP_DENYMATCH)
! 2320: {
! 2321: if (IS_RIP_DEBUG_PACKET)
! 2322: zlog_debug ("%s/%d is filtered by route-map",
! 2323: inet_ntoa (p->prefix), p->prefixlen);
! 2324: continue;
! 2325: }
! 2326: }
! 2327:
! 2328: /* When route-map does not set metric. */
! 2329: if (! rinfo->metric_set)
! 2330: {
! 2331: /* If redistribute metric is set. */
! 2332: if (rip->route_map[rinfo->type].metric_config
! 2333: && rinfo->metric != RIP_METRIC_INFINITY)
! 2334: {
! 2335: rinfo->metric_out = rip->route_map[rinfo->type].metric;
! 2336: }
! 2337: else
! 2338: {
! 2339: /* If the route is not connected or localy generated
! 2340: one, use default-metric value*/
! 2341: if (rinfo->type != ZEBRA_ROUTE_RIP
! 2342: && rinfo->type != ZEBRA_ROUTE_CONNECT
! 2343: && rinfo->metric != RIP_METRIC_INFINITY)
! 2344: rinfo->metric_out = rip->default_metric;
! 2345: }
! 2346: }
! 2347:
! 2348: /* Apply offset-list */
! 2349: if (rinfo->metric != RIP_METRIC_INFINITY)
! 2350: rip_offset_list_apply_out (p, ifc->ifp, &rinfo->metric_out);
! 2351:
! 2352: if (rinfo->metric_out > RIP_METRIC_INFINITY)
! 2353: rinfo->metric_out = RIP_METRIC_INFINITY;
! 2354:
! 2355: /* Perform split-horizon with poisoned reverse
! 2356: * for RIP and connected routes.
! 2357: **/
! 2358: if (ri->split_horizon == RIP_SPLIT_HORIZON_POISONED_REVERSE) {
! 2359: /*
! 2360: * We perform split horizon for RIP and connected route.
! 2361: * For rip routes, we want to suppress the route if we would
! 2362: * end up sending the route back on the interface that we
! 2363: * learned it from, with a higher metric. For connected routes,
! 2364: * we suppress the route if the prefix is a subset of the
! 2365: * source address that we are going to use for the packet
! 2366: * (in order to handle the case when multiple subnets are
! 2367: * configured on the same interface).
! 2368: */
! 2369: if (rinfo->type == ZEBRA_ROUTE_RIP &&
! 2370: rinfo->ifindex == ifc->ifp->ifindex)
! 2371: rinfo->metric_out = RIP_METRIC_INFINITY;
! 2372: if (rinfo->type == ZEBRA_ROUTE_CONNECT &&
! 2373: prefix_match((struct prefix *)p, ifc->address))
! 2374: rinfo->metric_out = RIP_METRIC_INFINITY;
! 2375: }
! 2376:
! 2377: /* Prepare preamble, auth headers, if needs be */
! 2378: if (num == 0)
! 2379: {
! 2380: stream_putc (s, RIP_RESPONSE);
! 2381: stream_putc (s, version);
! 2382: stream_putw (s, 0);
! 2383:
! 2384: /* auth header for !v1 && !no_auth */
! 2385: if ( (ri->auth_type != RIP_NO_AUTH) && (version != RIPv1) )
! 2386: doff = rip_auth_header_write (s, ri, key, auth_str,
! 2387: RIP_AUTH_SIMPLE_SIZE);
! 2388: }
! 2389:
! 2390: /* Write RTE to the stream. */
! 2391: num = rip_write_rte (num, s, p, version, rinfo);
! 2392: if (num == rtemax)
! 2393: {
! 2394: if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
! 2395: rip_auth_md5_set (s, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE);
! 2396:
! 2397: ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s),
! 2398: to, ifc);
! 2399:
! 2400: if (ret >= 0 && IS_RIP_DEBUG_SEND)
! 2401: rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
! 2402: stream_get_endp(s), "SEND");
! 2403: num = 0;
! 2404: stream_reset (s);
! 2405: }
! 2406: }
! 2407:
! 2408: /* Flush unwritten RTE. */
! 2409: if (num != 0)
! 2410: {
! 2411: if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
! 2412: rip_auth_md5_set (s, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE);
! 2413:
! 2414: ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s), to, ifc);
! 2415:
! 2416: if (ret >= 0 && IS_RIP_DEBUG_SEND)
! 2417: rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
! 2418: stream_get_endp (s), "SEND");
! 2419: num = 0;
! 2420: stream_reset (s);
! 2421: }
! 2422:
! 2423: /* Statistics updates. */
! 2424: ri->sent_updates++;
! 2425: }
! 2426:
! 2427: /* Send RIP packet to the interface. */
! 2428: static void
! 2429: rip_update_interface (struct connected *ifc, u_char version, int route_type)
! 2430: {
! 2431: struct sockaddr_in to;
! 2432:
! 2433: /* When RIP version is 2 and multicast enable interface. */
! 2434: if (version == RIPv2 && if_is_multicast (ifc->ifp))
! 2435: {
! 2436: if (IS_RIP_DEBUG_EVENT)
! 2437: zlog_debug ("multicast announce on %s ", ifc->ifp->name);
! 2438:
! 2439: rip_output_process (ifc, NULL, route_type, version);
! 2440: return;
! 2441: }
! 2442:
! 2443: /* If we can't send multicast packet, send it with unicast. */
! 2444: if (if_is_broadcast (ifc->ifp) || if_is_pointopoint (ifc->ifp))
! 2445: {
! 2446: if (ifc->address->family == AF_INET)
! 2447: {
! 2448: /* Destination address and port setting. */
! 2449: memset (&to, 0, sizeof (struct sockaddr_in));
! 2450: if (ifc->destination)
! 2451: /* use specified broadcast or peer destination addr */
! 2452: to.sin_addr = ifc->destination->u.prefix4;
! 2453: else if (ifc->address->prefixlen < IPV4_MAX_PREFIXLEN)
! 2454: /* calculate the appropriate broadcast address */
! 2455: to.sin_addr.s_addr =
! 2456: ipv4_broadcast_addr(ifc->address->u.prefix4.s_addr,
! 2457: ifc->address->prefixlen);
! 2458: else
! 2459: /* do not know where to send the packet */
! 2460: return;
! 2461: to.sin_port = htons (RIP_PORT_DEFAULT);
! 2462:
! 2463: if (IS_RIP_DEBUG_EVENT)
! 2464: zlog_debug("%s announce to %s on %s",
! 2465: CONNECTED_PEER(ifc) ? "unicast" : "broadcast",
! 2466: inet_ntoa (to.sin_addr), ifc->ifp->name);
! 2467:
! 2468: rip_output_process (ifc, &to, route_type, version);
! 2469: }
! 2470: }
! 2471: }
! 2472:
! 2473: /* Update send to all interface and neighbor. */
! 2474: static void
! 2475: rip_update_process (int route_type)
! 2476: {
! 2477: struct listnode *node;
! 2478: struct listnode *ifnode, *ifnnode;
! 2479: struct connected *connected;
! 2480: struct interface *ifp;
! 2481: struct rip_interface *ri;
! 2482: struct route_node *rp;
! 2483: struct sockaddr_in to;
! 2484: struct prefix_ipv4 *p;
! 2485:
! 2486: /* Send RIP update to each interface. */
! 2487: for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
! 2488: {
! 2489: if (if_is_loopback (ifp))
! 2490: continue;
! 2491:
! 2492: if (! if_is_operative (ifp))
! 2493: continue;
! 2494:
! 2495: /* Fetch RIP interface information. */
! 2496: ri = ifp->info;
! 2497:
! 2498: /* When passive interface is specified, suppress announce to the
! 2499: interface. */
! 2500: if (ri->passive)
! 2501: continue;
! 2502:
! 2503: if (ri->running)
! 2504: {
! 2505: /*
! 2506: * If there is no version configuration in the interface,
! 2507: * use rip's version setting.
! 2508: */
! 2509: int vsend = ((ri->ri_send == RI_RIP_UNSPEC) ?
! 2510: rip->version_send : ri->ri_send);
! 2511:
! 2512: if (IS_RIP_DEBUG_EVENT)
! 2513: zlog_debug("SEND UPDATE to %s ifindex %d",
! 2514: (ifp->name ? ifp->name : "_unknown_"), ifp->ifindex);
! 2515:
! 2516: /* send update on each connected network */
! 2517: for (ALL_LIST_ELEMENTS (ifp->connected, ifnode, ifnnode, connected))
! 2518: {
! 2519: if (connected->address->family == AF_INET)
! 2520: {
! 2521: if (vsend & RIPv1)
! 2522: rip_update_interface (connected, RIPv1, route_type);
! 2523: if ((vsend & RIPv2) && if_is_multicast(ifp))
! 2524: rip_update_interface (connected, RIPv2, route_type);
! 2525: }
! 2526: }
! 2527: }
! 2528: }
! 2529:
! 2530: /* RIP send updates to each neighbor. */
! 2531: for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
! 2532: if (rp->info != NULL)
! 2533: {
! 2534: p = (struct prefix_ipv4 *) &rp->p;
! 2535:
! 2536: ifp = if_lookup_address (p->prefix);
! 2537: if (! ifp)
! 2538: {
! 2539: zlog_warn ("Neighbor %s doesnt have connected interface!",
! 2540: inet_ntoa (p->prefix));
! 2541: continue;
! 2542: }
! 2543:
! 2544: if ( (connected = connected_lookup_address (ifp, p->prefix)) == NULL)
! 2545: {
! 2546: zlog_warn ("Neighbor %s doesnt have connected network",
! 2547: inet_ntoa (p->prefix));
! 2548: continue;
! 2549: }
! 2550:
! 2551: /* Set destination address and port */
! 2552: memset (&to, 0, sizeof (struct sockaddr_in));
! 2553: to.sin_addr = p->prefix;
! 2554: to.sin_port = htons (RIP_PORT_DEFAULT);
! 2555:
! 2556: /* RIP version is rip's configuration. */
! 2557: rip_output_process (connected, &to, route_type, rip->version_send);
! 2558: }
! 2559: }
! 2560:
! 2561: /* RIP's periodical timer. */
! 2562: static int
! 2563: rip_update (struct thread *t)
! 2564: {
! 2565: /* Clear timer pointer. */
! 2566: rip->t_update = NULL;
! 2567:
! 2568: if (IS_RIP_DEBUG_EVENT)
! 2569: zlog_debug ("update timer fire!");
! 2570:
! 2571: /* Process update output. */
! 2572: rip_update_process (rip_all_route);
! 2573:
! 2574: /* Triggered updates may be suppressed if a regular update is due by
! 2575: the time the triggered update would be sent. */
! 2576: if (rip->t_triggered_interval)
! 2577: {
! 2578: thread_cancel (rip->t_triggered_interval);
! 2579: rip->t_triggered_interval = NULL;
! 2580: }
! 2581: rip->trigger = 0;
! 2582:
! 2583: /* Register myself. */
! 2584: rip_event (RIP_UPDATE_EVENT, 0);
! 2585:
! 2586: return 0;
! 2587: }
! 2588:
! 2589: /* Walk down the RIP routing table then clear changed flag. */
! 2590: static void
! 2591: rip_clear_changed_flag (void)
! 2592: {
! 2593: struct route_node *rp;
! 2594: struct rip_info *rinfo;
! 2595:
! 2596: for (rp = route_top (rip->table); rp; rp = route_next (rp))
! 2597: if ((rinfo = rp->info) != NULL)
! 2598: if (rinfo->flags & RIP_RTF_CHANGED)
! 2599: rinfo->flags &= ~RIP_RTF_CHANGED;
! 2600: }
! 2601:
! 2602: /* Triggered update interval timer. */
! 2603: static int
! 2604: rip_triggered_interval (struct thread *t)
! 2605: {
! 2606: int rip_triggered_update (struct thread *);
! 2607:
! 2608: rip->t_triggered_interval = NULL;
! 2609:
! 2610: if (rip->trigger)
! 2611: {
! 2612: rip->trigger = 0;
! 2613: rip_triggered_update (t);
! 2614: }
! 2615: return 0;
! 2616: }
! 2617:
! 2618: /* Execute triggered update. */
! 2619: static int
! 2620: rip_triggered_update (struct thread *t)
! 2621: {
! 2622: int interval;
! 2623:
! 2624: /* Clear thred pointer. */
! 2625: rip->t_triggered_update = NULL;
! 2626:
! 2627: /* Cancel interval timer. */
! 2628: if (rip->t_triggered_interval)
! 2629: {
! 2630: thread_cancel (rip->t_triggered_interval);
! 2631: rip->t_triggered_interval = NULL;
! 2632: }
! 2633: rip->trigger = 0;
! 2634:
! 2635: /* Logging triggered update. */
! 2636: if (IS_RIP_DEBUG_EVENT)
! 2637: zlog_debug ("triggered update!");
! 2638:
! 2639: /* Split Horizon processing is done when generating triggered
! 2640: updates as well as normal updates (see section 2.6). */
! 2641: rip_update_process (rip_changed_route);
! 2642:
! 2643: /* Once all of the triggered updates have been generated, the route
! 2644: change flags should be cleared. */
! 2645: rip_clear_changed_flag ();
! 2646:
! 2647: /* After a triggered update is sent, a timer should be set for a
! 2648: random interval between 1 and 5 seconds. If other changes that
! 2649: would trigger updates occur before the timer expires, a single
! 2650: update is triggered when the timer expires. */
! 2651: interval = (random () % 5) + 1;
! 2652:
! 2653: rip->t_triggered_interval =
! 2654: thread_add_timer (master, rip_triggered_interval, NULL, interval);
! 2655:
! 2656: return 0;
! 2657: }
! 2658:
! 2659: /* Withdraw redistributed route. */
! 2660: void
! 2661: rip_redistribute_withdraw (int type)
! 2662: {
! 2663: struct route_node *rp;
! 2664: struct rip_info *rinfo;
! 2665:
! 2666: if (!rip)
! 2667: return;
! 2668:
! 2669: for (rp = route_top (rip->table); rp; rp = route_next (rp))
! 2670: if ((rinfo = rp->info) != NULL)
! 2671: {
! 2672: if (rinfo->type == type
! 2673: && rinfo->sub_type != RIP_ROUTE_INTERFACE)
! 2674: {
! 2675: /* Perform poisoned reverse. */
! 2676: rinfo->metric = RIP_METRIC_INFINITY;
! 2677: RIP_TIMER_ON (rinfo->t_garbage_collect,
! 2678: rip_garbage_collect, rip->garbage_time);
! 2679: RIP_TIMER_OFF (rinfo->t_timeout);
! 2680: rinfo->flags |= RIP_RTF_CHANGED;
! 2681:
! 2682: if (IS_RIP_DEBUG_EVENT) {
! 2683: struct prefix_ipv4 *p = (struct prefix_ipv4 *) &rp->p;
! 2684:
! 2685: zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [withdraw]",
! 2686: inet_ntoa(p->prefix), p->prefixlen,
! 2687: ifindex2ifname(rinfo->ifindex));
! 2688: }
! 2689:
! 2690: rip_event (RIP_TRIGGERED_UPDATE, 0);
! 2691: }
! 2692: }
! 2693: }
! 2694:
! 2695: /* Create new RIP instance and set it to global variable. */
! 2696: static int
! 2697: rip_create (void)
! 2698: {
! 2699: rip = XCALLOC (MTYPE_RIP, sizeof (struct rip));
! 2700:
! 2701: /* Set initial value. */
! 2702: rip->version_send = RI_RIP_VERSION_2;
! 2703: rip->version_recv = RI_RIP_VERSION_1_AND_2;
! 2704: rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
! 2705: rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
! 2706: rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
! 2707: rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
! 2708:
! 2709: /* Initialize RIP routig table. */
! 2710: rip->table = route_table_init ();
! 2711: rip->route = route_table_init ();
! 2712: rip->neighbor = route_table_init ();
! 2713:
! 2714: /* Make output stream. */
! 2715: rip->obuf = stream_new (1500);
! 2716:
! 2717: /* Make socket. */
! 2718: rip->sock = rip_create_socket (NULL);
! 2719: if (rip->sock < 0)
! 2720: return rip->sock;
! 2721:
! 2722: /* Create read and timer thread. */
! 2723: rip_event (RIP_READ, rip->sock);
! 2724: rip_event (RIP_UPDATE_EVENT, 1);
! 2725:
! 2726: return 0;
! 2727: }
! 2728:
! 2729: /* Sned RIP request to the destination. */
! 2730: int
! 2731: rip_request_send (struct sockaddr_in *to, struct interface *ifp,
! 2732: u_char version, struct connected *connected)
! 2733: {
! 2734: struct rte *rte;
! 2735: struct rip_packet rip_packet;
! 2736: struct listnode *node, *nnode;
! 2737:
! 2738: memset (&rip_packet, 0, sizeof (rip_packet));
! 2739:
! 2740: rip_packet.command = RIP_REQUEST;
! 2741: rip_packet.version = version;
! 2742: rte = rip_packet.rte;
! 2743: rte->metric = htonl (RIP_METRIC_INFINITY);
! 2744:
! 2745: if (connected)
! 2746: {
! 2747: /*
! 2748: * connected is only sent for ripv1 case, or when
! 2749: * interface does not support multicast. Caller loops
! 2750: * over each connected address for this case.
! 2751: */
! 2752: if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
! 2753: to, connected) != sizeof (rip_packet))
! 2754: return -1;
! 2755: else
! 2756: return sizeof (rip_packet);
! 2757: }
! 2758:
! 2759: /* send request on each connected network */
! 2760: for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, connected))
! 2761: {
! 2762: struct prefix_ipv4 *p;
! 2763:
! 2764: p = (struct prefix_ipv4 *) connected->address;
! 2765:
! 2766: if (p->family != AF_INET)
! 2767: continue;
! 2768:
! 2769: if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
! 2770: to, connected) != sizeof (rip_packet))
! 2771: return -1;
! 2772: }
! 2773: return sizeof (rip_packet);
! 2774: }
! 2775:
! 2776: static int
! 2777: rip_update_jitter (unsigned long time)
! 2778: {
! 2779: #define JITTER_BOUND 4
! 2780: /* We want to get the jitter to +/- 1/JITTER_BOUND the interval.
! 2781: Given that, we cannot let time be less than JITTER_BOUND seconds.
! 2782: The RIPv2 RFC says jitter should be small compared to
! 2783: update_time. We consider 1/JITTER_BOUND to be small.
! 2784: */
! 2785:
! 2786: int jitter_input = time;
! 2787: int jitter;
! 2788:
! 2789: if (jitter_input < JITTER_BOUND)
! 2790: jitter_input = JITTER_BOUND;
! 2791:
! 2792: jitter = (((rand () % ((jitter_input * 2) + 1)) - jitter_input));
! 2793:
! 2794: return jitter/JITTER_BOUND;
! 2795: }
! 2796:
! 2797: void
! 2798: rip_event (enum rip_event event, int sock)
! 2799: {
! 2800: int jitter = 0;
! 2801:
! 2802: switch (event)
! 2803: {
! 2804: case RIP_READ:
! 2805: rip->t_read = thread_add_read (master, rip_read, NULL, sock);
! 2806: break;
! 2807: case RIP_UPDATE_EVENT:
! 2808: if (rip->t_update)
! 2809: {
! 2810: thread_cancel (rip->t_update);
! 2811: rip->t_update = NULL;
! 2812: }
! 2813: jitter = rip_update_jitter (rip->update_time);
! 2814: rip->t_update =
! 2815: thread_add_timer (master, rip_update, NULL,
! 2816: sock ? 2 : rip->update_time + jitter);
! 2817: break;
! 2818: case RIP_TRIGGERED_UPDATE:
! 2819: if (rip->t_triggered_interval)
! 2820: rip->trigger = 1;
! 2821: else if (! rip->t_triggered_update)
! 2822: rip->t_triggered_update =
! 2823: thread_add_event (master, rip_triggered_update, NULL, 0);
! 2824: break;
! 2825: default:
! 2826: break;
! 2827: }
! 2828: }
! 2829:
! 2830: DEFUN (router_rip,
! 2831: router_rip_cmd,
! 2832: "router rip",
! 2833: "Enable a routing process\n"
! 2834: "Routing Information Protocol (RIP)\n")
! 2835: {
! 2836: int ret;
! 2837:
! 2838: /* If rip is not enabled before. */
! 2839: if (! rip)
! 2840: {
! 2841: ret = rip_create ();
! 2842: if (ret < 0)
! 2843: {
! 2844: zlog_info ("Can't create RIP");
! 2845: return CMD_WARNING;
! 2846: }
! 2847: }
! 2848: vty->node = RIP_NODE;
! 2849: vty->index = rip;
! 2850:
! 2851: return CMD_SUCCESS;
! 2852: }
! 2853:
! 2854: DEFUN (no_router_rip,
! 2855: no_router_rip_cmd,
! 2856: "no router rip",
! 2857: NO_STR
! 2858: "Enable a routing process\n"
! 2859: "Routing Information Protocol (RIP)\n")
! 2860: {
! 2861: if (rip)
! 2862: rip_clean ();
! 2863: return CMD_SUCCESS;
! 2864: }
! 2865:
! 2866: DEFUN (rip_version,
! 2867: rip_version_cmd,
! 2868: "version <1-2>",
! 2869: "Set routing protocol version\n"
! 2870: "version\n")
! 2871: {
! 2872: int version;
! 2873:
! 2874: version = atoi (argv[0]);
! 2875: if (version != RIPv1 && version != RIPv2)
! 2876: {
! 2877: vty_out (vty, "invalid rip version %d%s", version,
! 2878: VTY_NEWLINE);
! 2879: return CMD_WARNING;
! 2880: }
! 2881: rip->version_send = version;
! 2882: rip->version_recv = version;
! 2883:
! 2884: return CMD_SUCCESS;
! 2885: }
! 2886:
! 2887: DEFUN (no_rip_version,
! 2888: no_rip_version_cmd,
! 2889: "no version",
! 2890: NO_STR
! 2891: "Set routing protocol version\n")
! 2892: {
! 2893: /* Set RIP version to the default. */
! 2894: rip->version_send = RI_RIP_VERSION_2;
! 2895: rip->version_recv = RI_RIP_VERSION_1_AND_2;
! 2896:
! 2897: return CMD_SUCCESS;
! 2898: }
! 2899:
! 2900: ALIAS (no_rip_version,
! 2901: no_rip_version_val_cmd,
! 2902: "no version <1-2>",
! 2903: NO_STR
! 2904: "Set routing protocol version\n"
! 2905: "version\n")
! 2906:
! 2907: DEFUN (rip_route,
! 2908: rip_route_cmd,
! 2909: "route A.B.C.D/M",
! 2910: "RIP static route configuration\n"
! 2911: "IP prefix <network>/<length>\n")
! 2912: {
! 2913: int ret;
! 2914: struct prefix_ipv4 p;
! 2915: struct route_node *node;
! 2916:
! 2917: ret = str2prefix_ipv4 (argv[0], &p);
! 2918: if (ret < 0)
! 2919: {
! 2920: vty_out (vty, "Malformed address%s", VTY_NEWLINE);
! 2921: return CMD_WARNING;
! 2922: }
! 2923: apply_mask_ipv4 (&p);
! 2924:
! 2925: /* For router rip configuration. */
! 2926: node = route_node_get (rip->route, (struct prefix *) &p);
! 2927:
! 2928: if (node->info)
! 2929: {
! 2930: vty_out (vty, "There is already same static route.%s", VTY_NEWLINE);
! 2931: route_unlock_node (node);
! 2932: return CMD_WARNING;
! 2933: }
! 2934:
! 2935: node->info = (char *)"static";
! 2936:
! 2937: rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL, 0, 0);
! 2938:
! 2939: return CMD_SUCCESS;
! 2940: }
! 2941:
! 2942: DEFUN (no_rip_route,
! 2943: no_rip_route_cmd,
! 2944: "no route A.B.C.D/M",
! 2945: NO_STR
! 2946: "RIP static route configuration\n"
! 2947: "IP prefix <network>/<length>\n")
! 2948: {
! 2949: int ret;
! 2950: struct prefix_ipv4 p;
! 2951: struct route_node *node;
! 2952:
! 2953: ret = str2prefix_ipv4 (argv[0], &p);
! 2954: if (ret < 0)
! 2955: {
! 2956: vty_out (vty, "Malformed address%s", VTY_NEWLINE);
! 2957: return CMD_WARNING;
! 2958: }
! 2959: apply_mask_ipv4 (&p);
! 2960:
! 2961: /* For router rip configuration. */
! 2962: node = route_node_lookup (rip->route, (struct prefix *) &p);
! 2963: if (! node)
! 2964: {
! 2965: vty_out (vty, "Can't find route %s.%s", argv[0],
! 2966: VTY_NEWLINE);
! 2967: return CMD_WARNING;
! 2968: }
! 2969:
! 2970: rip_redistribute_delete (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0);
! 2971: route_unlock_node (node);
! 2972:
! 2973: node->info = NULL;
! 2974: route_unlock_node (node);
! 2975:
! 2976: return CMD_SUCCESS;
! 2977: }
! 2978:
! 2979: #if 0
! 2980: static void
! 2981: rip_update_default_metric (void)
! 2982: {
! 2983: struct route_node *np;
! 2984: struct rip_info *rinfo;
! 2985:
! 2986: for (np = route_top (rip->table); np; np = route_next (np))
! 2987: if ((rinfo = np->info) != NULL)
! 2988: if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->type != ZEBRA_ROUTE_CONNECT)
! 2989: rinfo->metric = rip->default_metric;
! 2990: }
! 2991: #endif
! 2992:
! 2993: DEFUN (rip_default_metric,
! 2994: rip_default_metric_cmd,
! 2995: "default-metric <1-16>",
! 2996: "Set a metric of redistribute routes\n"
! 2997: "Default metric\n")
! 2998: {
! 2999: if (rip)
! 3000: {
! 3001: rip->default_metric = atoi (argv[0]);
! 3002: /* rip_update_default_metric (); */
! 3003: }
! 3004: return CMD_SUCCESS;
! 3005: }
! 3006:
! 3007: DEFUN (no_rip_default_metric,
! 3008: no_rip_default_metric_cmd,
! 3009: "no default-metric",
! 3010: NO_STR
! 3011: "Set a metric of redistribute routes\n"
! 3012: "Default metric\n")
! 3013: {
! 3014: if (rip)
! 3015: {
! 3016: rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
! 3017: /* rip_update_default_metric (); */
! 3018: }
! 3019: return CMD_SUCCESS;
! 3020: }
! 3021:
! 3022: ALIAS (no_rip_default_metric,
! 3023: no_rip_default_metric_val_cmd,
! 3024: "no default-metric <1-16>",
! 3025: NO_STR
! 3026: "Set a metric of redistribute routes\n"
! 3027: "Default metric\n")
! 3028:
! 3029: DEFUN (rip_timers,
! 3030: rip_timers_cmd,
! 3031: "timers basic <5-2147483647> <5-2147483647> <5-2147483647>",
! 3032: "Adjust routing timers\n"
! 3033: "Basic routing protocol update timers\n"
! 3034: "Routing table update timer value in second. Default is 30.\n"
! 3035: "Routing information timeout timer. Default is 180.\n"
! 3036: "Garbage collection timer. Default is 120.\n")
! 3037: {
! 3038: unsigned long update;
! 3039: unsigned long timeout;
! 3040: unsigned long garbage;
! 3041: char *endptr = NULL;
! 3042: unsigned long RIP_TIMER_MAX = 2147483647;
! 3043: unsigned long RIP_TIMER_MIN = 5;
! 3044:
! 3045: update = strtoul (argv[0], &endptr, 10);
! 3046: if (update > RIP_TIMER_MAX || update < RIP_TIMER_MIN || *endptr != '\0')
! 3047: {
! 3048: vty_out (vty, "update timer value error%s", VTY_NEWLINE);
! 3049: return CMD_WARNING;
! 3050: }
! 3051:
! 3052: timeout = strtoul (argv[1], &endptr, 10);
! 3053: if (timeout > RIP_TIMER_MAX || timeout < RIP_TIMER_MIN || *endptr != '\0')
! 3054: {
! 3055: vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
! 3056: return CMD_WARNING;
! 3057: }
! 3058:
! 3059: garbage = strtoul (argv[2], &endptr, 10);
! 3060: if (garbage > RIP_TIMER_MAX || garbage < RIP_TIMER_MIN || *endptr != '\0')
! 3061: {
! 3062: vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
! 3063: return CMD_WARNING;
! 3064: }
! 3065:
! 3066: /* Set each timer value. */
! 3067: rip->update_time = update;
! 3068: rip->timeout_time = timeout;
! 3069: rip->garbage_time = garbage;
! 3070:
! 3071: /* Reset update timer thread. */
! 3072: rip_event (RIP_UPDATE_EVENT, 0);
! 3073:
! 3074: return CMD_SUCCESS;
! 3075: }
! 3076:
! 3077: DEFUN (no_rip_timers,
! 3078: no_rip_timers_cmd,
! 3079: "no timers basic",
! 3080: NO_STR
! 3081: "Adjust routing timers\n"
! 3082: "Basic routing protocol update timers\n")
! 3083: {
! 3084: /* Set each timer value to the default. */
! 3085: rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
! 3086: rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
! 3087: rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
! 3088:
! 3089: /* Reset update timer thread. */
! 3090: rip_event (RIP_UPDATE_EVENT, 0);
! 3091:
! 3092: return CMD_SUCCESS;
! 3093: }
! 3094:
! 3095: ALIAS (no_rip_timers,
! 3096: no_rip_timers_val_cmd,
! 3097: "no timers basic <0-65535> <0-65535> <0-65535>",
! 3098: NO_STR
! 3099: "Adjust routing timers\n"
! 3100: "Basic routing protocol update timers\n"
! 3101: "Routing table update timer value in second. Default is 30.\n"
! 3102: "Routing information timeout timer. Default is 180.\n"
! 3103: "Garbage collection timer. Default is 120.\n")
! 3104:
! 3105:
! 3106: struct route_table *rip_distance_table;
! 3107:
! 3108: struct rip_distance
! 3109: {
! 3110: /* Distance value for the IP source prefix. */
! 3111: u_char distance;
! 3112:
! 3113: /* Name of the access-list to be matched. */
! 3114: char *access_list;
! 3115: };
! 3116:
! 3117: static struct rip_distance *
! 3118: rip_distance_new (void)
! 3119: {
! 3120: return XCALLOC (MTYPE_RIP_DISTANCE, sizeof (struct rip_distance));
! 3121: }
! 3122:
! 3123: static void
! 3124: rip_distance_free (struct rip_distance *rdistance)
! 3125: {
! 3126: XFREE (MTYPE_RIP_DISTANCE, rdistance);
! 3127: }
! 3128:
! 3129: static int
! 3130: rip_distance_set (struct vty *vty, const char *distance_str, const char *ip_str,
! 3131: const char *access_list_str)
! 3132: {
! 3133: int ret;
! 3134: struct prefix_ipv4 p;
! 3135: u_char distance;
! 3136: struct route_node *rn;
! 3137: struct rip_distance *rdistance;
! 3138:
! 3139: ret = str2prefix_ipv4 (ip_str, &p);
! 3140: if (ret == 0)
! 3141: {
! 3142: vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
! 3143: return CMD_WARNING;
! 3144: }
! 3145:
! 3146: distance = atoi (distance_str);
! 3147:
! 3148: /* Get RIP distance node. */
! 3149: rn = route_node_get (rip_distance_table, (struct prefix *) &p);
! 3150: if (rn->info)
! 3151: {
! 3152: rdistance = rn->info;
! 3153: route_unlock_node (rn);
! 3154: }
! 3155: else
! 3156: {
! 3157: rdistance = rip_distance_new ();
! 3158: rn->info = rdistance;
! 3159: }
! 3160:
! 3161: /* Set distance value. */
! 3162: rdistance->distance = distance;
! 3163:
! 3164: /* Reset access-list configuration. */
! 3165: if (rdistance->access_list)
! 3166: {
! 3167: free (rdistance->access_list);
! 3168: rdistance->access_list = NULL;
! 3169: }
! 3170: if (access_list_str)
! 3171: rdistance->access_list = strdup (access_list_str);
! 3172:
! 3173: return CMD_SUCCESS;
! 3174: }
! 3175:
! 3176: static int
! 3177: rip_distance_unset (struct vty *vty, const char *distance_str,
! 3178: const char *ip_str, const char *access_list_str)
! 3179: {
! 3180: int ret;
! 3181: struct prefix_ipv4 p;
! 3182: u_char distance;
! 3183: struct route_node *rn;
! 3184: struct rip_distance *rdistance;
! 3185:
! 3186: ret = str2prefix_ipv4 (ip_str, &p);
! 3187: if (ret == 0)
! 3188: {
! 3189: vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
! 3190: return CMD_WARNING;
! 3191: }
! 3192:
! 3193: distance = atoi (distance_str);
! 3194:
! 3195: rn = route_node_lookup (rip_distance_table, (struct prefix *)&p);
! 3196: if (! rn)
! 3197: {
! 3198: vty_out (vty, "Can't find specified prefix%s", VTY_NEWLINE);
! 3199: return CMD_WARNING;
! 3200: }
! 3201:
! 3202: rdistance = rn->info;
! 3203:
! 3204: if (rdistance->access_list)
! 3205: free (rdistance->access_list);
! 3206: rip_distance_free (rdistance);
! 3207:
! 3208: rn->info = NULL;
! 3209: route_unlock_node (rn);
! 3210: route_unlock_node (rn);
! 3211:
! 3212: return CMD_SUCCESS;
! 3213: }
! 3214:
! 3215: static void
! 3216: rip_distance_reset (void)
! 3217: {
! 3218: struct route_node *rn;
! 3219: struct rip_distance *rdistance;
! 3220:
! 3221: for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
! 3222: if ((rdistance = rn->info) != NULL)
! 3223: {
! 3224: if (rdistance->access_list)
! 3225: free (rdistance->access_list);
! 3226: rip_distance_free (rdistance);
! 3227: rn->info = NULL;
! 3228: route_unlock_node (rn);
! 3229: }
! 3230: }
! 3231:
! 3232: /* Apply RIP information to distance method. */
! 3233: u_char
! 3234: rip_distance_apply (struct rip_info *rinfo)
! 3235: {
! 3236: struct route_node *rn;
! 3237: struct prefix_ipv4 p;
! 3238: struct rip_distance *rdistance;
! 3239: struct access_list *alist;
! 3240:
! 3241: if (! rip)
! 3242: return 0;
! 3243:
! 3244: memset (&p, 0, sizeof (struct prefix_ipv4));
! 3245: p.family = AF_INET;
! 3246: p.prefix = rinfo->from;
! 3247: p.prefixlen = IPV4_MAX_BITLEN;
! 3248:
! 3249: /* Check source address. */
! 3250: rn = route_node_match (rip_distance_table, (struct prefix *) &p);
! 3251: if (rn)
! 3252: {
! 3253: rdistance = rn->info;
! 3254: route_unlock_node (rn);
! 3255:
! 3256: if (rdistance->access_list)
! 3257: {
! 3258: alist = access_list_lookup (AFI_IP, rdistance->access_list);
! 3259: if (alist == NULL)
! 3260: return 0;
! 3261: if (access_list_apply (alist, &rinfo->rp->p) == FILTER_DENY)
! 3262: return 0;
! 3263:
! 3264: return rdistance->distance;
! 3265: }
! 3266: else
! 3267: return rdistance->distance;
! 3268: }
! 3269:
! 3270: if (rip->distance)
! 3271: return rip->distance;
! 3272:
! 3273: return 0;
! 3274: }
! 3275:
! 3276: static void
! 3277: rip_distance_show (struct vty *vty)
! 3278: {
! 3279: struct route_node *rn;
! 3280: struct rip_distance *rdistance;
! 3281: int header = 1;
! 3282: char buf[BUFSIZ];
! 3283:
! 3284: vty_out (vty, " Distance: (default is %d)%s",
! 3285: rip->distance ? rip->distance :ZEBRA_RIP_DISTANCE_DEFAULT,
! 3286: VTY_NEWLINE);
! 3287:
! 3288: for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
! 3289: if ((rdistance = rn->info) != NULL)
! 3290: {
! 3291: if (header)
! 3292: {
! 3293: vty_out (vty, " Address Distance List%s",
! 3294: VTY_NEWLINE);
! 3295: header = 0;
! 3296: }
! 3297: sprintf (buf, "%s/%d", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen);
! 3298: vty_out (vty, " %-20s %4d %s%s",
! 3299: buf, rdistance->distance,
! 3300: rdistance->access_list ? rdistance->access_list : "",
! 3301: VTY_NEWLINE);
! 3302: }
! 3303: }
! 3304:
! 3305: DEFUN (rip_distance,
! 3306: rip_distance_cmd,
! 3307: "distance <1-255>",
! 3308: "Administrative distance\n"
! 3309: "Distance value\n")
! 3310: {
! 3311: rip->distance = atoi (argv[0]);
! 3312: return CMD_SUCCESS;
! 3313: }
! 3314:
! 3315: DEFUN (no_rip_distance,
! 3316: no_rip_distance_cmd,
! 3317: "no distance <1-255>",
! 3318: NO_STR
! 3319: "Administrative distance\n"
! 3320: "Distance value\n")
! 3321: {
! 3322: rip->distance = 0;
! 3323: return CMD_SUCCESS;
! 3324: }
! 3325:
! 3326: DEFUN (rip_distance_source,
! 3327: rip_distance_source_cmd,
! 3328: "distance <1-255> A.B.C.D/M",
! 3329: "Administrative distance\n"
! 3330: "Distance value\n"
! 3331: "IP source prefix\n")
! 3332: {
! 3333: rip_distance_set (vty, argv[0], argv[1], NULL);
! 3334: return CMD_SUCCESS;
! 3335: }
! 3336:
! 3337: DEFUN (no_rip_distance_source,
! 3338: no_rip_distance_source_cmd,
! 3339: "no distance <1-255> A.B.C.D/M",
! 3340: NO_STR
! 3341: "Administrative distance\n"
! 3342: "Distance value\n"
! 3343: "IP source prefix\n")
! 3344: {
! 3345: rip_distance_unset (vty, argv[0], argv[1], NULL);
! 3346: return CMD_SUCCESS;
! 3347: }
! 3348:
! 3349: DEFUN (rip_distance_source_access_list,
! 3350: rip_distance_source_access_list_cmd,
! 3351: "distance <1-255> A.B.C.D/M WORD",
! 3352: "Administrative distance\n"
! 3353: "Distance value\n"
! 3354: "IP source prefix\n"
! 3355: "Access list name\n")
! 3356: {
! 3357: rip_distance_set (vty, argv[0], argv[1], argv[2]);
! 3358: return CMD_SUCCESS;
! 3359: }
! 3360:
! 3361: DEFUN (no_rip_distance_source_access_list,
! 3362: no_rip_distance_source_access_list_cmd,
! 3363: "no distance <1-255> A.B.C.D/M WORD",
! 3364: NO_STR
! 3365: "Administrative distance\n"
! 3366: "Distance value\n"
! 3367: "IP source prefix\n"
! 3368: "Access list name\n")
! 3369: {
! 3370: rip_distance_unset (vty, argv[0], argv[1], argv[2]);
! 3371: return CMD_SUCCESS;
! 3372: }
! 3373:
! 3374: /* Print out routes update time. */
! 3375: static void
! 3376: rip_vty_out_uptime (struct vty *vty, struct rip_info *rinfo)
! 3377: {
! 3378: time_t clock;
! 3379: struct tm *tm;
! 3380: #define TIME_BUF 25
! 3381: char timebuf [TIME_BUF];
! 3382: struct thread *thread;
! 3383:
! 3384: if ((thread = rinfo->t_timeout) != NULL)
! 3385: {
! 3386: clock = thread_timer_remain_second (thread);
! 3387: tm = gmtime (&clock);
! 3388: strftime (timebuf, TIME_BUF, "%M:%S", tm);
! 3389: vty_out (vty, "%5s", timebuf);
! 3390: }
! 3391: else if ((thread = rinfo->t_garbage_collect) != NULL)
! 3392: {
! 3393: clock = thread_timer_remain_second (thread);
! 3394: tm = gmtime (&clock);
! 3395: strftime (timebuf, TIME_BUF, "%M:%S", tm);
! 3396: vty_out (vty, "%5s", timebuf);
! 3397: }
! 3398: }
! 3399:
! 3400: static const char *
! 3401: rip_route_type_print (int sub_type)
! 3402: {
! 3403: switch (sub_type)
! 3404: {
! 3405: case RIP_ROUTE_RTE:
! 3406: return "n";
! 3407: case RIP_ROUTE_STATIC:
! 3408: return "s";
! 3409: case RIP_ROUTE_DEFAULT:
! 3410: return "d";
! 3411: case RIP_ROUTE_REDISTRIBUTE:
! 3412: return "r";
! 3413: case RIP_ROUTE_INTERFACE:
! 3414: return "i";
! 3415: default:
! 3416: return "?";
! 3417: }
! 3418: }
! 3419:
! 3420: DEFUN (show_ip_rip,
! 3421: show_ip_rip_cmd,
! 3422: "show ip rip",
! 3423: SHOW_STR
! 3424: IP_STR
! 3425: "Show RIP routes\n")
! 3426: {
! 3427: struct route_node *np;
! 3428: struct rip_info *rinfo;
! 3429:
! 3430: if (! rip)
! 3431: return CMD_SUCCESS;
! 3432:
! 3433: vty_out (vty, "Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP%s"
! 3434: "Sub-codes:%s"
! 3435: " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s"
! 3436: " (i) - interface%s%s"
! 3437: " Network Next Hop Metric From Tag Time%s",
! 3438: VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
! 3439:
! 3440: for (np = route_top (rip->table); np; np = route_next (np))
! 3441: if ((rinfo = np->info) != NULL)
! 3442: {
! 3443: int len;
! 3444:
! 3445: len = vty_out (vty, "%c(%s) %s/%d",
! 3446: /* np->lock, For debugging. */
! 3447: zebra_route_char(rinfo->type),
! 3448: rip_route_type_print (rinfo->sub_type),
! 3449: inet_ntoa (np->p.u.prefix4), np->p.prefixlen);
! 3450:
! 3451: len = 24 - len;
! 3452:
! 3453: if (len > 0)
! 3454: vty_out (vty, "%*s", len, " ");
! 3455:
! 3456: if (rinfo->nexthop.s_addr)
! 3457: vty_out (vty, "%-20s %2d ", inet_ntoa (rinfo->nexthop),
! 3458: rinfo->metric);
! 3459: else
! 3460: vty_out (vty, "0.0.0.0 %2d ", rinfo->metric);
! 3461:
! 3462: /* Route which exist in kernel routing table. */
! 3463: if ((rinfo->type == ZEBRA_ROUTE_RIP) &&
! 3464: (rinfo->sub_type == RIP_ROUTE_RTE))
! 3465: {
! 3466: vty_out (vty, "%-15s ", inet_ntoa (rinfo->from));
! 3467: vty_out (vty, "%3d ", rinfo->tag);
! 3468: rip_vty_out_uptime (vty, rinfo);
! 3469: }
! 3470: else if (rinfo->metric == RIP_METRIC_INFINITY)
! 3471: {
! 3472: vty_out (vty, "self ");
! 3473: vty_out (vty, "%3d ", rinfo->tag);
! 3474: rip_vty_out_uptime (vty, rinfo);
! 3475: }
! 3476: else
! 3477: {
! 3478: if (rinfo->external_metric)
! 3479: {
! 3480: len = vty_out (vty, "self (%s:%d)",
! 3481: zebra_route_string(rinfo->type),
! 3482: rinfo->external_metric);
! 3483: len = 16 - len;
! 3484: if (len > 0)
! 3485: vty_out (vty, "%*s", len, " ");
! 3486: }
! 3487: else
! 3488: vty_out (vty, "self ");
! 3489: vty_out (vty, "%3d", rinfo->tag);
! 3490: }
! 3491:
! 3492: vty_out (vty, "%s", VTY_NEWLINE);
! 3493: }
! 3494: return CMD_SUCCESS;
! 3495: }
! 3496:
! 3497: /* Vincent: formerly, it was show_ip_protocols_rip: "show ip protocols" */
! 3498: DEFUN (show_ip_rip_status,
! 3499: show_ip_rip_status_cmd,
! 3500: "show ip rip status",
! 3501: SHOW_STR
! 3502: IP_STR
! 3503: "Show RIP routes\n"
! 3504: "IP routing protocol process parameters and statistics\n")
! 3505: {
! 3506: struct listnode *node;
! 3507: struct interface *ifp;
! 3508: struct rip_interface *ri;
! 3509: extern const struct message ri_version_msg[];
! 3510: const char *send_version;
! 3511: const char *receive_version;
! 3512:
! 3513: if (! rip)
! 3514: return CMD_SUCCESS;
! 3515:
! 3516: vty_out (vty, "Routing Protocol is \"rip\"%s", VTY_NEWLINE);
! 3517: vty_out (vty, " Sending updates every %ld seconds with +/-50%%,",
! 3518: rip->update_time);
! 3519: vty_out (vty, " next due in %lu seconds%s",
! 3520: thread_timer_remain_second(rip->t_update),
! 3521: VTY_NEWLINE);
! 3522: vty_out (vty, " Timeout after %ld seconds,", rip->timeout_time);
! 3523: vty_out (vty, " garbage collect after %ld seconds%s", rip->garbage_time,
! 3524: VTY_NEWLINE);
! 3525:
! 3526: /* Filtering status show. */
! 3527: config_show_distribute (vty);
! 3528:
! 3529: /* Default metric information. */
! 3530: vty_out (vty, " Default redistribution metric is %d%s",
! 3531: rip->default_metric, VTY_NEWLINE);
! 3532:
! 3533: /* Redistribute information. */
! 3534: vty_out (vty, " Redistributing:");
! 3535: config_write_rip_redistribute (vty, 0);
! 3536: vty_out (vty, "%s", VTY_NEWLINE);
! 3537:
! 3538: vty_out (vty, " Default version control: send version %s,",
! 3539: lookup(ri_version_msg,rip->version_send));
! 3540: if (rip->version_recv == RI_RIP_VERSION_1_AND_2)
! 3541: vty_out (vty, " receive any version %s", VTY_NEWLINE);
! 3542: else
! 3543: vty_out (vty, " receive version %s %s",
! 3544: lookup(ri_version_msg,rip->version_recv), VTY_NEWLINE);
! 3545:
! 3546: vty_out (vty, " Interface Send Recv Key-chain%s", VTY_NEWLINE);
! 3547:
! 3548: for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
! 3549: {
! 3550: ri = ifp->info;
! 3551:
! 3552: if (!ri->running)
! 3553: continue;
! 3554:
! 3555: if (ri->enable_network || ri->enable_interface)
! 3556: {
! 3557: if (ri->ri_send == RI_RIP_UNSPEC)
! 3558: send_version = lookup (ri_version_msg, rip->version_send);
! 3559: else
! 3560: send_version = lookup (ri_version_msg, ri->ri_send);
! 3561:
! 3562: if (ri->ri_receive == RI_RIP_UNSPEC)
! 3563: receive_version = lookup (ri_version_msg, rip->version_recv);
! 3564: else
! 3565: receive_version = lookup (ri_version_msg, ri->ri_receive);
! 3566:
! 3567: vty_out (vty, " %-17s%-3s %-3s %s%s", ifp->name,
! 3568: send_version,
! 3569: receive_version,
! 3570: ri->key_chain ? ri->key_chain : "",
! 3571: VTY_NEWLINE);
! 3572: }
! 3573: }
! 3574:
! 3575: vty_out (vty, " Routing for Networks:%s", VTY_NEWLINE);
! 3576: config_write_rip_network (vty, 0);
! 3577:
! 3578: {
! 3579: int found_passive = 0;
! 3580: for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
! 3581: {
! 3582: ri = ifp->info;
! 3583:
! 3584: if ((ri->enable_network || ri->enable_interface) && ri->passive)
! 3585: {
! 3586: if (!found_passive)
! 3587: {
! 3588: vty_out (vty, " Passive Interface(s):%s", VTY_NEWLINE);
! 3589: found_passive = 1;
! 3590: }
! 3591: vty_out (vty, " %s%s", ifp->name, VTY_NEWLINE);
! 3592: }
! 3593: }
! 3594: }
! 3595:
! 3596: vty_out (vty, " Routing Information Sources:%s", VTY_NEWLINE);
! 3597: vty_out (vty, " Gateway BadPackets BadRoutes Distance Last Update%s", VTY_NEWLINE);
! 3598: rip_peer_display (vty);
! 3599:
! 3600: rip_distance_show (vty);
! 3601:
! 3602: return CMD_SUCCESS;
! 3603: }
! 3604:
! 3605: /* RIP configuration write function. */
! 3606: static int
! 3607: config_write_rip (struct vty *vty)
! 3608: {
! 3609: int write = 0;
! 3610: struct route_node *rn;
! 3611: struct rip_distance *rdistance;
! 3612:
! 3613: if (rip)
! 3614: {
! 3615: /* Router RIP statement. */
! 3616: vty_out (vty, "router rip%s", VTY_NEWLINE);
! 3617: write++;
! 3618:
! 3619: /* RIP version statement. Default is RIP version 2. */
! 3620: if (rip->version_send != RI_RIP_VERSION_2
! 3621: || rip->version_recv != RI_RIP_VERSION_1_AND_2)
! 3622: vty_out (vty, " version %d%s", rip->version_send,
! 3623: VTY_NEWLINE);
! 3624:
! 3625: /* RIP timer configuration. */
! 3626: if (rip->update_time != RIP_UPDATE_TIMER_DEFAULT
! 3627: || rip->timeout_time != RIP_TIMEOUT_TIMER_DEFAULT
! 3628: || rip->garbage_time != RIP_GARBAGE_TIMER_DEFAULT)
! 3629: vty_out (vty, " timers basic %lu %lu %lu%s",
! 3630: rip->update_time,
! 3631: rip->timeout_time,
! 3632: rip->garbage_time,
! 3633: VTY_NEWLINE);
! 3634:
! 3635: /* Default information configuration. */
! 3636: if (rip->default_information)
! 3637: {
! 3638: if (rip->default_information_route_map)
! 3639: vty_out (vty, " default-information originate route-map %s%s",
! 3640: rip->default_information_route_map, VTY_NEWLINE);
! 3641: else
! 3642: vty_out (vty, " default-information originate%s",
! 3643: VTY_NEWLINE);
! 3644: }
! 3645:
! 3646: /* Redistribute configuration. */
! 3647: config_write_rip_redistribute (vty, 1);
! 3648:
! 3649: /* RIP offset-list configuration. */
! 3650: config_write_rip_offset_list (vty);
! 3651:
! 3652: /* RIP enabled network and interface configuration. */
! 3653: config_write_rip_network (vty, 1);
! 3654:
! 3655: /* RIP default metric configuration */
! 3656: if (rip->default_metric != RIP_DEFAULT_METRIC_DEFAULT)
! 3657: vty_out (vty, " default-metric %d%s",
! 3658: rip->default_metric, VTY_NEWLINE);
! 3659:
! 3660: /* Distribute configuration. */
! 3661: write += config_write_distribute (vty);
! 3662:
! 3663: /* Interface routemap configuration */
! 3664: write += config_write_if_rmap (vty);
! 3665:
! 3666: /* Distance configuration. */
! 3667: if (rip->distance)
! 3668: vty_out (vty, " distance %d%s", rip->distance, VTY_NEWLINE);
! 3669:
! 3670: /* RIP source IP prefix distance configuration. */
! 3671: for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
! 3672: if ((rdistance = rn->info) != NULL)
! 3673: vty_out (vty, " distance %d %s/%d %s%s", rdistance->distance,
! 3674: inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen,
! 3675: rdistance->access_list ? rdistance->access_list : "",
! 3676: VTY_NEWLINE);
! 3677:
! 3678: /* RIP static route configuration. */
! 3679: for (rn = route_top (rip->route); rn; rn = route_next (rn))
! 3680: if (rn->info)
! 3681: vty_out (vty, " route %s/%d%s",
! 3682: inet_ntoa (rn->p.u.prefix4),
! 3683: rn->p.prefixlen,
! 3684: VTY_NEWLINE);
! 3685:
! 3686: }
! 3687: return write;
! 3688: }
! 3689:
! 3690: /* RIP node structure. */
! 3691: static struct cmd_node rip_node =
! 3692: {
! 3693: RIP_NODE,
! 3694: "%s(config-router)# ",
! 3695: 1
! 3696: };
! 3697:
! 3698: /* Distribute-list update functions. */
! 3699: static void
! 3700: rip_distribute_update (struct distribute *dist)
! 3701: {
! 3702: struct interface *ifp;
! 3703: struct rip_interface *ri;
! 3704: struct access_list *alist;
! 3705: struct prefix_list *plist;
! 3706:
! 3707: if (! dist->ifname)
! 3708: return;
! 3709:
! 3710: ifp = if_lookup_by_name (dist->ifname);
! 3711: if (ifp == NULL)
! 3712: return;
! 3713:
! 3714: ri = ifp->info;
! 3715:
! 3716: if (dist->list[DISTRIBUTE_IN])
! 3717: {
! 3718: alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]);
! 3719: if (alist)
! 3720: ri->list[RIP_FILTER_IN] = alist;
! 3721: else
! 3722: ri->list[RIP_FILTER_IN] = NULL;
! 3723: }
! 3724: else
! 3725: ri->list[RIP_FILTER_IN] = NULL;
! 3726:
! 3727: if (dist->list[DISTRIBUTE_OUT])
! 3728: {
! 3729: alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]);
! 3730: if (alist)
! 3731: ri->list[RIP_FILTER_OUT] = alist;
! 3732: else
! 3733: ri->list[RIP_FILTER_OUT] = NULL;
! 3734: }
! 3735: else
! 3736: ri->list[RIP_FILTER_OUT] = NULL;
! 3737:
! 3738: if (dist->prefix[DISTRIBUTE_IN])
! 3739: {
! 3740: plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]);
! 3741: if (plist)
! 3742: ri->prefix[RIP_FILTER_IN] = plist;
! 3743: else
! 3744: ri->prefix[RIP_FILTER_IN] = NULL;
! 3745: }
! 3746: else
! 3747: ri->prefix[RIP_FILTER_IN] = NULL;
! 3748:
! 3749: if (dist->prefix[DISTRIBUTE_OUT])
! 3750: {
! 3751: plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]);
! 3752: if (plist)
! 3753: ri->prefix[RIP_FILTER_OUT] = plist;
! 3754: else
! 3755: ri->prefix[RIP_FILTER_OUT] = NULL;
! 3756: }
! 3757: else
! 3758: ri->prefix[RIP_FILTER_OUT] = NULL;
! 3759: }
! 3760:
! 3761: void
! 3762: rip_distribute_update_interface (struct interface *ifp)
! 3763: {
! 3764: struct distribute *dist;
! 3765:
! 3766: dist = distribute_lookup (ifp->name);
! 3767: if (dist)
! 3768: rip_distribute_update (dist);
! 3769: }
! 3770:
! 3771: /* Update all interface's distribute list. */
! 3772: /* ARGSUSED */
! 3773: static void
! 3774: rip_distribute_update_all (struct prefix_list *notused)
! 3775: {
! 3776: struct interface *ifp;
! 3777: struct listnode *node, *nnode;
! 3778:
! 3779: for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
! 3780: rip_distribute_update_interface (ifp);
! 3781: }
! 3782: /* ARGSUSED */
! 3783: static void
! 3784: rip_distribute_update_all_wrapper(struct access_list *notused)
! 3785: {
! 3786: rip_distribute_update_all(NULL);
! 3787: }
! 3788:
! 3789: /* Delete all added rip route. */
! 3790: void
! 3791: rip_clean (void)
! 3792: {
! 3793: int i;
! 3794: struct route_node *rp;
! 3795: struct rip_info *rinfo;
! 3796:
! 3797: if (rip)
! 3798: {
! 3799: /* Clear RIP routes */
! 3800: for (rp = route_top (rip->table); rp; rp = route_next (rp))
! 3801: if ((rinfo = rp->info) != NULL)
! 3802: {
! 3803: if (rinfo->type == ZEBRA_ROUTE_RIP &&
! 3804: rinfo->sub_type == RIP_ROUTE_RTE)
! 3805: rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p,
! 3806: &rinfo->nexthop, rinfo->metric);
! 3807:
! 3808: RIP_TIMER_OFF (rinfo->t_timeout);
! 3809: RIP_TIMER_OFF (rinfo->t_garbage_collect);
! 3810:
! 3811: rp->info = NULL;
! 3812: route_unlock_node (rp);
! 3813:
! 3814: rip_info_free (rinfo);
! 3815: }
! 3816:
! 3817: /* Cancel RIP related timers. */
! 3818: RIP_TIMER_OFF (rip->t_update);
! 3819: RIP_TIMER_OFF (rip->t_triggered_update);
! 3820: RIP_TIMER_OFF (rip->t_triggered_interval);
! 3821:
! 3822: /* Cancel read thread. */
! 3823: if (rip->t_read)
! 3824: {
! 3825: thread_cancel (rip->t_read);
! 3826: rip->t_read = NULL;
! 3827: }
! 3828:
! 3829: /* Close RIP socket. */
! 3830: if (rip->sock >= 0)
! 3831: {
! 3832: close (rip->sock);
! 3833: rip->sock = -1;
! 3834: }
! 3835:
! 3836: /* Static RIP route configuration. */
! 3837: for (rp = route_top (rip->route); rp; rp = route_next (rp))
! 3838: if (rp->info)
! 3839: {
! 3840: rp->info = NULL;
! 3841: route_unlock_node (rp);
! 3842: }
! 3843:
! 3844: /* RIP neighbor configuration. */
! 3845: for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
! 3846: if (rp->info)
! 3847: {
! 3848: rp->info = NULL;
! 3849: route_unlock_node (rp);
! 3850: }
! 3851:
! 3852: /* Redistribute related clear. */
! 3853: if (rip->default_information_route_map)
! 3854: free (rip->default_information_route_map);
! 3855:
! 3856: for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
! 3857: if (rip->route_map[i].name)
! 3858: free (rip->route_map[i].name);
! 3859:
! 3860: XFREE (MTYPE_ROUTE_TABLE, rip->table);
! 3861: XFREE (MTYPE_ROUTE_TABLE, rip->route);
! 3862: XFREE (MTYPE_ROUTE_TABLE, rip->neighbor);
! 3863:
! 3864: XFREE (MTYPE_RIP, rip);
! 3865: rip = NULL;
! 3866: }
! 3867:
! 3868: rip_clean_network ();
! 3869: rip_passive_nondefault_clean ();
! 3870: rip_offset_clean ();
! 3871: rip_interface_clean ();
! 3872: rip_distance_reset ();
! 3873: rip_redistribute_clean ();
! 3874: }
! 3875:
! 3876: /* Reset all values to the default settings. */
! 3877: void
! 3878: rip_reset (void)
! 3879: {
! 3880: /* Reset global counters. */
! 3881: rip_global_route_changes = 0;
! 3882: rip_global_queries = 0;
! 3883:
! 3884: /* Call ripd related reset functions. */
! 3885: rip_debug_reset ();
! 3886: rip_route_map_reset ();
! 3887:
! 3888: /* Call library reset functions. */
! 3889: vty_reset ();
! 3890: access_list_reset ();
! 3891: prefix_list_reset ();
! 3892:
! 3893: distribute_list_reset ();
! 3894:
! 3895: rip_interface_reset ();
! 3896: rip_distance_reset ();
! 3897:
! 3898: rip_zclient_reset ();
! 3899: }
! 3900:
! 3901: static void
! 3902: rip_if_rmap_update (struct if_rmap *if_rmap)
! 3903: {
! 3904: struct interface *ifp;
! 3905: struct rip_interface *ri;
! 3906: struct route_map *rmap;
! 3907:
! 3908: ifp = if_lookup_by_name (if_rmap->ifname);
! 3909: if (ifp == NULL)
! 3910: return;
! 3911:
! 3912: ri = ifp->info;
! 3913:
! 3914: if (if_rmap->routemap[IF_RMAP_IN])
! 3915: {
! 3916: rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]);
! 3917: if (rmap)
! 3918: ri->routemap[IF_RMAP_IN] = rmap;
! 3919: else
! 3920: ri->routemap[IF_RMAP_IN] = NULL;
! 3921: }
! 3922: else
! 3923: ri->routemap[RIP_FILTER_IN] = NULL;
! 3924:
! 3925: if (if_rmap->routemap[IF_RMAP_OUT])
! 3926: {
! 3927: rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]);
! 3928: if (rmap)
! 3929: ri->routemap[IF_RMAP_OUT] = rmap;
! 3930: else
! 3931: ri->routemap[IF_RMAP_OUT] = NULL;
! 3932: }
! 3933: else
! 3934: ri->routemap[RIP_FILTER_OUT] = NULL;
! 3935: }
! 3936:
! 3937: void
! 3938: rip_if_rmap_update_interface (struct interface *ifp)
! 3939: {
! 3940: struct if_rmap *if_rmap;
! 3941:
! 3942: if_rmap = if_rmap_lookup (ifp->name);
! 3943: if (if_rmap)
! 3944: rip_if_rmap_update (if_rmap);
! 3945: }
! 3946:
! 3947: static void
! 3948: rip_routemap_update_redistribute (void)
! 3949: {
! 3950: int i;
! 3951:
! 3952: if (rip)
! 3953: {
! 3954: for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
! 3955: {
! 3956: if (rip->route_map[i].name)
! 3957: rip->route_map[i].map =
! 3958: route_map_lookup_by_name (rip->route_map[i].name);
! 3959: }
! 3960: }
! 3961: }
! 3962:
! 3963: /* ARGSUSED */
! 3964: static void
! 3965: rip_routemap_update (const char *notused)
! 3966: {
! 3967: struct interface *ifp;
! 3968: struct listnode *node, *nnode;
! 3969:
! 3970: for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
! 3971: rip_if_rmap_update_interface (ifp);
! 3972:
! 3973: rip_routemap_update_redistribute ();
! 3974: }
! 3975:
! 3976: /* Allocate new rip structure and set default value. */
! 3977: void
! 3978: rip_init (void)
! 3979: {
! 3980: /* Randomize for triggered update random(). */
! 3981: srand (time (NULL));
! 3982:
! 3983: /* Install top nodes. */
! 3984: install_node (&rip_node, config_write_rip);
! 3985:
! 3986: /* Install rip commands. */
! 3987: install_element (VIEW_NODE, &show_ip_rip_cmd);
! 3988: install_element (VIEW_NODE, &show_ip_rip_status_cmd);
! 3989: install_element (ENABLE_NODE, &show_ip_rip_cmd);
! 3990: install_element (ENABLE_NODE, &show_ip_rip_status_cmd);
! 3991: install_element (CONFIG_NODE, &router_rip_cmd);
! 3992: install_element (CONFIG_NODE, &no_router_rip_cmd);
! 3993:
! 3994: install_default (RIP_NODE);
! 3995: install_element (RIP_NODE, &rip_version_cmd);
! 3996: install_element (RIP_NODE, &no_rip_version_cmd);
! 3997: install_element (RIP_NODE, &no_rip_version_val_cmd);
! 3998: install_element (RIP_NODE, &rip_default_metric_cmd);
! 3999: install_element (RIP_NODE, &no_rip_default_metric_cmd);
! 4000: install_element (RIP_NODE, &no_rip_default_metric_val_cmd);
! 4001: install_element (RIP_NODE, &rip_timers_cmd);
! 4002: install_element (RIP_NODE, &no_rip_timers_cmd);
! 4003: install_element (RIP_NODE, &no_rip_timers_val_cmd);
! 4004: install_element (RIP_NODE, &rip_route_cmd);
! 4005: install_element (RIP_NODE, &no_rip_route_cmd);
! 4006: install_element (RIP_NODE, &rip_distance_cmd);
! 4007: install_element (RIP_NODE, &no_rip_distance_cmd);
! 4008: install_element (RIP_NODE, &rip_distance_source_cmd);
! 4009: install_element (RIP_NODE, &no_rip_distance_source_cmd);
! 4010: install_element (RIP_NODE, &rip_distance_source_access_list_cmd);
! 4011: install_element (RIP_NODE, &no_rip_distance_source_access_list_cmd);
! 4012:
! 4013: /* Debug related init. */
! 4014: rip_debug_init ();
! 4015:
! 4016: /* SNMP init. */
! 4017: #ifdef HAVE_SNMP
! 4018: rip_snmp_init ();
! 4019: #endif /* HAVE_SNMP */
! 4020:
! 4021: /* Access list install. */
! 4022: access_list_init ();
! 4023: access_list_add_hook (rip_distribute_update_all_wrapper);
! 4024: access_list_delete_hook (rip_distribute_update_all_wrapper);
! 4025:
! 4026: /* Prefix list initialize.*/
! 4027: prefix_list_init ();
! 4028: prefix_list_add_hook (rip_distribute_update_all);
! 4029: prefix_list_delete_hook (rip_distribute_update_all);
! 4030:
! 4031: /* Distribute list install. */
! 4032: distribute_list_init (RIP_NODE);
! 4033: distribute_list_add_hook (rip_distribute_update);
! 4034: distribute_list_delete_hook (rip_distribute_update);
! 4035:
! 4036: /* Route-map */
! 4037: rip_route_map_init ();
! 4038: rip_offset_init ();
! 4039:
! 4040: route_map_add_hook (rip_routemap_update);
! 4041: route_map_delete_hook (rip_routemap_update);
! 4042:
! 4043: if_rmap_init (RIP_NODE);
! 4044: if_rmap_hook_add (rip_if_rmap_update);
! 4045: if_rmap_hook_delete (rip_if_rmap_update);
! 4046:
! 4047: /* Distance control. */
! 4048: rip_distance_table = route_table_init ();
! 4049: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>