Annotation of embedaddon/quagga/zebra/rt_ioctl.c, revision 1.1
1.1 ! misho 1: /*
! 2: * kernel routing table update by ioctl().
! 3: * Copyright (C) 1997, 98 Kunihiro Ishiguro
! 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 "prefix.h"
! 26: #include "log.h"
! 27: #include "if.h"
! 28:
! 29: #include "zebra/zserv.h"
! 30: #include "zebra/rib.h"
! 31: #include "zebra/debug.h"
! 32: #include "zebra/rt.h"
! 33:
! 34: /* Initialize of kernel interface. There is no kernel communication
! 35: support under ioctl(). So this is dummy stub function. */
! 36: void
! 37: kernel_init (void)
! 38: {
! 39: return;
! 40: }
! 41:
! 42: /* Dummy function of routing socket. */
! 43: static void
! 44: kernel_read (int sock)
! 45: {
! 46: return;
! 47: }
! 48:
! 49: #if 0
! 50: /* Initialization prototype of struct sockaddr_in. */
! 51: static struct sockaddr_in sin_proto =
! 52: {
! 53: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
! 54: sizeof (struct sockaddr_in),
! 55: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
! 56: AF_INET, 0, {0}, {0}
! 57: };
! 58: #endif /* 0 */
! 59:
! 60: /* Solaris has ortentry. */
! 61: #ifdef HAVE_OLD_RTENTRY
! 62: #define rtentry ortentry
! 63: #endif /* HAVE_OLD_RTENTRY */
! 64:
! 65: /* Interface to ioctl route message. */
! 66: int
! 67: kernel_add_route (struct prefix_ipv4 *dest, struct in_addr *gate,
! 68: int index, int flags)
! 69: {
! 70: int ret;
! 71: int sock;
! 72: struct rtentry rtentry;
! 73: struct sockaddr_in sin_dest, sin_mask, sin_gate;
! 74:
! 75: memset (&rtentry, 0, sizeof (struct rtentry));
! 76:
! 77: /* Make destination. */
! 78: memset (&sin_dest, 0, sizeof (struct sockaddr_in));
! 79: sin_dest.sin_family = AF_INET;
! 80: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
! 81: sin_dest.sin_len = sizeof (struct sockaddr_in);
! 82: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
! 83: sin_dest.sin_addr = dest->prefix;
! 84:
! 85: /* Make gateway. */
! 86: if (gate)
! 87: {
! 88: memset (&sin_gate, 0, sizeof (struct sockaddr_in));
! 89: sin_gate.sin_family = AF_INET;
! 90: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
! 91: sin_gate.sin_len = sizeof (struct sockaddr_in);
! 92: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
! 93: sin_gate.sin_addr = *gate;
! 94: }
! 95:
! 96: memset (&sin_mask, 0, sizeof (struct sockaddr_in));
! 97: sin_mask.sin_family = AF_INET;
! 98: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
! 99: sin_gate.sin_len = sizeof (struct sockaddr_in);
! 100: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
! 101: masklen2ip (dest->prefixlen, &sin_mask.sin_addr);
! 102:
! 103: /* Set destination address, mask and gateway.*/
! 104: memcpy (&rtentry.rt_dst, &sin_dest, sizeof (struct sockaddr_in));
! 105: if (gate)
! 106: memcpy (&rtentry.rt_gateway, &sin_gate, sizeof (struct sockaddr_in));
! 107: #ifndef SUNOS_5
! 108: memcpy (&rtentry.rt_genmask, &sin_mask, sizeof (struct sockaddr_in));
! 109: #endif /* SUNOS_5 */
! 110:
! 111: /* Routing entry flag set. */
! 112: if (dest->prefixlen == 32)
! 113: rtentry.rt_flags |= RTF_HOST;
! 114:
! 115: if (gate && gate->s_addr != INADDR_ANY)
! 116: rtentry.rt_flags |= RTF_GATEWAY;
! 117:
! 118: rtentry.rt_flags |= RTF_UP;
! 119:
! 120: /* Additional flags */
! 121: rtentry.rt_flags |= flags;
! 122:
! 123:
! 124: /* For tagging route. */
! 125: /* rtentry.rt_flags |= RTF_DYNAMIC; */
! 126:
! 127: /* Open socket for ioctl. */
! 128: sock = socket (AF_INET, SOCK_DGRAM, 0);
! 129: if (sock < 0)
! 130: {
! 131: zlog_warn ("can't make socket\n");
! 132: return -1;
! 133: }
! 134:
! 135: /* Send message by ioctl(). */
! 136: ret = ioctl (sock, SIOCADDRT, &rtentry);
! 137: if (ret < 0)
! 138: {
! 139: switch (errno)
! 140: {
! 141: case EEXIST:
! 142: close (sock);
! 143: return ZEBRA_ERR_RTEXIST;
! 144: break;
! 145: case ENETUNREACH:
! 146: close (sock);
! 147: return ZEBRA_ERR_RTUNREACH;
! 148: break;
! 149: case EPERM:
! 150: close (sock);
! 151: return ZEBRA_ERR_EPERM;
! 152: break;
! 153: }
! 154:
! 155: close (sock);
! 156: zlog_warn ("write : %s (%d)", safe_strerror (errno), errno);
! 157: return 1;
! 158: }
! 159: close (sock);
! 160:
! 161: return ret;
! 162: }
! 163:
! 164: /* Interface to ioctl route message. */
! 165: static int
! 166: kernel_ioctl_ipv4 (u_long cmd, struct prefix *p, struct rib *rib, int family)
! 167: {
! 168: int ret;
! 169: int sock;
! 170: struct rtentry rtentry;
! 171: struct sockaddr_in sin_dest, sin_mask, sin_gate;
! 172: struct nexthop *nexthop;
! 173: int nexthop_num = 0;
! 174: struct interface *ifp;
! 175:
! 176: memset (&rtentry, 0, sizeof (struct rtentry));
! 177:
! 178: /* Make destination. */
! 179: memset (&sin_dest, 0, sizeof (struct sockaddr_in));
! 180: sin_dest.sin_family = AF_INET;
! 181: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
! 182: sin_dest.sin_len = sizeof (struct sockaddr_in);
! 183: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
! 184: sin_dest.sin_addr = p->u.prefix4;
! 185:
! 186: if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE))
! 187: {
! 188: SET_FLAG (rtentry.rt_flags, RTF_REJECT);
! 189:
! 190: if (cmd == SIOCADDRT)
! 191: for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
! 192: SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
! 193:
! 194: goto skip;
! 195: }
! 196:
! 197: memset (&sin_gate, 0, sizeof (struct sockaddr_in));
! 198:
! 199: /* Make gateway. */
! 200: for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
! 201: {
! 202: if ((cmd == SIOCADDRT
! 203: && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
! 204: || (cmd == SIOCDELRT
! 205: && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
! 206: {
! 207: if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
! 208: {
! 209: if (nexthop->rtype == NEXTHOP_TYPE_IPV4 ||
! 210: nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
! 211: {
! 212: sin_gate.sin_family = AF_INET;
! 213: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
! 214: sin_gate.sin_len = sizeof (struct sockaddr_in);
! 215: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
! 216: sin_gate.sin_addr = nexthop->rgate.ipv4;
! 217: rtentry.rt_flags |= RTF_GATEWAY;
! 218: }
! 219: if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
! 220: || nexthop->rtype == NEXTHOP_TYPE_IFNAME)
! 221: {
! 222: ifp = if_lookup_by_index (nexthop->rifindex);
! 223: if (ifp)
! 224: rtentry.rt_dev = ifp->name;
! 225: else
! 226: return -1;
! 227: }
! 228: }
! 229: else
! 230: {
! 231: if (nexthop->type == NEXTHOP_TYPE_IPV4 ||
! 232: nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
! 233: {
! 234: sin_gate.sin_family = AF_INET;
! 235: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
! 236: sin_gate.sin_len = sizeof (struct sockaddr_in);
! 237: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
! 238: sin_gate.sin_addr = nexthop->gate.ipv4;
! 239: rtentry.rt_flags |= RTF_GATEWAY;
! 240: }
! 241: if (nexthop->type == NEXTHOP_TYPE_IFINDEX
! 242: || nexthop->type == NEXTHOP_TYPE_IFNAME)
! 243: {
! 244: ifp = if_lookup_by_index (nexthop->ifindex);
! 245: if (ifp)
! 246: rtentry.rt_dev = ifp->name;
! 247: else
! 248: return -1;
! 249: }
! 250: }
! 251:
! 252: if (cmd == SIOCADDRT)
! 253: SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
! 254:
! 255: nexthop_num++;
! 256: break;
! 257: }
! 258: }
! 259:
! 260: /* If there is no useful nexthop then return. */
! 261: if (nexthop_num == 0)
! 262: {
! 263: if (IS_ZEBRA_DEBUG_KERNEL)
! 264: zlog_debug ("netlink_route_multipath(): No useful nexthop.");
! 265: return 0;
! 266: }
! 267:
! 268: skip:
! 269:
! 270: memset (&sin_mask, 0, sizeof (struct sockaddr_in));
! 271: sin_mask.sin_family = AF_INET;
! 272: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
! 273: sin_mask.sin_len = sizeof (struct sockaddr_in);
! 274: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
! 275: masklen2ip (p->prefixlen, &sin_mask.sin_addr);
! 276:
! 277: /* Set destination address, mask and gateway.*/
! 278: memcpy (&rtentry.rt_dst, &sin_dest, sizeof (struct sockaddr_in));
! 279:
! 280: if (rtentry.rt_flags & RTF_GATEWAY)
! 281: memcpy (&rtentry.rt_gateway, &sin_gate, sizeof (struct sockaddr_in));
! 282:
! 283: #ifndef SUNOS_5
! 284: memcpy (&rtentry.rt_genmask, &sin_mask, sizeof (struct sockaddr_in));
! 285: #endif /* SUNOS_5 */
! 286:
! 287: /* Metric. It seems metric minus one value is installed... */
! 288: rtentry.rt_metric = rib->metric;
! 289:
! 290: /* Routing entry flag set. */
! 291: if (p->prefixlen == 32)
! 292: rtentry.rt_flags |= RTF_HOST;
! 293:
! 294: rtentry.rt_flags |= RTF_UP;
! 295:
! 296: /* Additional flags */
! 297: /* rtentry.rt_flags |= flags; */
! 298:
! 299: /* For tagging route. */
! 300: /* rtentry.rt_flags |= RTF_DYNAMIC; */
! 301:
! 302: /* Open socket for ioctl. */
! 303: sock = socket (AF_INET, SOCK_DGRAM, 0);
! 304: if (sock < 0)
! 305: {
! 306: zlog_warn ("can't make socket\n");
! 307: return -1;
! 308: }
! 309:
! 310: /* Send message by ioctl(). */
! 311: ret = ioctl (sock, cmd, &rtentry);
! 312: if (ret < 0)
! 313: {
! 314: switch (errno)
! 315: {
! 316: case EEXIST:
! 317: close (sock);
! 318: return ZEBRA_ERR_RTEXIST;
! 319: break;
! 320: case ENETUNREACH:
! 321: close (sock);
! 322: return ZEBRA_ERR_RTUNREACH;
! 323: break;
! 324: case EPERM:
! 325: close (sock);
! 326: return ZEBRA_ERR_EPERM;
! 327: break;
! 328: }
! 329:
! 330: close (sock);
! 331: zlog_warn ("write : %s (%d)", safe_strerror (errno), errno);
! 332: return ret;
! 333: }
! 334: close (sock);
! 335:
! 336: return ret;
! 337: }
! 338:
! 339: int
! 340: kernel_add_ipv4 (struct prefix *p, struct rib *rib)
! 341: {
! 342: return kernel_ioctl_ipv4 (SIOCADDRT, p, rib, AF_INET);
! 343: }
! 344:
! 345: int
! 346: kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
! 347: {
! 348: return kernel_ioctl_ipv4 (SIOCDELRT, p, rib, AF_INET);
! 349: }
! 350:
! 351: #ifdef HAVE_IPV6
! 352:
! 353: /* Below is hack for GNU libc definition and Linux 2.1.X header. */
! 354: #undef RTF_DEFAULT
! 355: #undef RTF_ADDRCONF
! 356:
! 357: #include <asm/types.h>
! 358:
! 359: #if defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1
! 360: /* struct in6_rtmsg will be declared in net/route.h. */
! 361: #else
! 362: #include <linux/ipv6_route.h>
! 363: #endif
! 364:
! 365: static int
! 366: kernel_ioctl_ipv6 (u_long type, struct prefix_ipv6 *dest, struct in6_addr *gate,
! 367: int index, int flags)
! 368: {
! 369: int ret;
! 370: int sock;
! 371: struct in6_rtmsg rtm;
! 372:
! 373: memset (&rtm, 0, sizeof (struct in6_rtmsg));
! 374:
! 375: rtm.rtmsg_flags |= RTF_UP;
! 376: rtm.rtmsg_metric = 1;
! 377: memcpy (&rtm.rtmsg_dst, &dest->prefix, sizeof (struct in6_addr));
! 378: rtm.rtmsg_dst_len = dest->prefixlen;
! 379:
! 380: /* We need link local index. But this should be done caller...
! 381: if (IN6_IS_ADDR_LINKLOCAL(&rtm.rtmsg_gateway))
! 382: {
! 383: index = if_index_address (&rtm.rtmsg_gateway);
! 384: rtm.rtmsg_ifindex = index;
! 385: }
! 386: else
! 387: rtm.rtmsg_ifindex = 0;
! 388: */
! 389:
! 390: rtm.rtmsg_flags |= RTF_GATEWAY;
! 391:
! 392: /* For tagging route. */
! 393: /* rtm.rtmsg_flags |= RTF_DYNAMIC; */
! 394:
! 395: memcpy (&rtm.rtmsg_gateway, gate, sizeof (struct in6_addr));
! 396:
! 397: if (index)
! 398: rtm.rtmsg_ifindex = index;
! 399: else
! 400: rtm.rtmsg_ifindex = 0;
! 401:
! 402: rtm.rtmsg_metric = 1;
! 403:
! 404: sock = socket (AF_INET6, SOCK_DGRAM, 0);
! 405: if (sock < 0)
! 406: {
! 407: zlog_warn ("can't make socket\n");
! 408: return -1;
! 409: }
! 410:
! 411: /* Send message via ioctl. */
! 412: ret = ioctl (sock, type, &rtm);
! 413: if (ret < 0)
! 414: {
! 415: zlog_warn ("can't %s ipv6 route: %s\n", type == SIOCADDRT ? "add" : "delete",
! 416: safe_strerror(errno));
! 417: ret = errno;
! 418: close (sock);
! 419: return ret;
! 420: }
! 421: close (sock);
! 422:
! 423: return ret;
! 424: }
! 425:
! 426: static int
! 427: kernel_ioctl_ipv6_multipath (u_long cmd, struct prefix *p, struct rib *rib,
! 428: int family)
! 429: {
! 430: int ret;
! 431: int sock;
! 432: struct in6_rtmsg rtm;
! 433: struct nexthop *nexthop;
! 434: int nexthop_num = 0;
! 435:
! 436: memset (&rtm, 0, sizeof (struct in6_rtmsg));
! 437:
! 438: rtm.rtmsg_flags |= RTF_UP;
! 439: rtm.rtmsg_metric = rib->metric;
! 440: memcpy (&rtm.rtmsg_dst, &p->u.prefix, sizeof (struct in6_addr));
! 441: rtm.rtmsg_dst_len = p->prefixlen;
! 442:
! 443: /* We need link local index. But this should be done caller...
! 444: if (IN6_IS_ADDR_LINKLOCAL(&rtm.rtmsg_gateway))
! 445: {
! 446: index = if_index_address (&rtm.rtmsg_gateway);
! 447: rtm.rtmsg_ifindex = index;
! 448: }
! 449: else
! 450: rtm.rtmsg_ifindex = 0;
! 451: */
! 452:
! 453: rtm.rtmsg_flags |= RTF_GATEWAY;
! 454:
! 455: /* For tagging route. */
! 456: /* rtm.rtmsg_flags |= RTF_DYNAMIC; */
! 457:
! 458: /* Make gateway. */
! 459: for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
! 460: {
! 461: if ((cmd == SIOCADDRT
! 462: && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
! 463: || (cmd == SIOCDELRT
! 464: && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
! 465: {
! 466: if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
! 467: {
! 468: if (nexthop->rtype == NEXTHOP_TYPE_IPV6
! 469: || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
! 470: || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
! 471: {
! 472: memcpy (&rtm.rtmsg_gateway, &nexthop->rgate.ipv6,
! 473: sizeof (struct in6_addr));
! 474: }
! 475: if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
! 476: || nexthop->rtype == NEXTHOP_TYPE_IFNAME
! 477: || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
! 478: || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
! 479: rtm.rtmsg_ifindex = nexthop->rifindex;
! 480: else
! 481: rtm.rtmsg_ifindex = 0;
! 482:
! 483: }
! 484: else
! 485: {
! 486: if (nexthop->type == NEXTHOP_TYPE_IPV6
! 487: || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
! 488: || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
! 489: {
! 490: memcpy (&rtm.rtmsg_gateway, &nexthop->gate.ipv6,
! 491: sizeof (struct in6_addr));
! 492: }
! 493: if (nexthop->type == NEXTHOP_TYPE_IFINDEX
! 494: || nexthop->type == NEXTHOP_TYPE_IFNAME
! 495: || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
! 496: || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
! 497: rtm.rtmsg_ifindex = nexthop->ifindex;
! 498: else
! 499: rtm.rtmsg_ifindex = 0;
! 500: }
! 501:
! 502: if (cmd == SIOCADDRT)
! 503: SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
! 504:
! 505: nexthop_num++;
! 506: break;
! 507: }
! 508: }
! 509:
! 510: /* If there is no useful nexthop then return. */
! 511: if (nexthop_num == 0)
! 512: {
! 513: if (IS_ZEBRA_DEBUG_KERNEL)
! 514: zlog_debug ("netlink_route_multipath(): No useful nexthop.");
! 515: return 0;
! 516: }
! 517:
! 518: sock = socket (AF_INET6, SOCK_DGRAM, 0);
! 519: if (sock < 0)
! 520: {
! 521: zlog_warn ("can't make socket\n");
! 522: return -1;
! 523: }
! 524:
! 525: /* Send message via ioctl. */
! 526: ret = ioctl (sock, cmd, &rtm);
! 527: if (ret < 0)
! 528: {
! 529: zlog_warn ("can't %s ipv6 route: %s\n",
! 530: cmd == SIOCADDRT ? "add" : "delete",
! 531: safe_strerror(errno));
! 532: ret = errno;
! 533: close (sock);
! 534: return ret;
! 535: }
! 536: close (sock);
! 537:
! 538: return ret;
! 539: }
! 540:
! 541: int
! 542: kernel_add_ipv6 (struct prefix *p, struct rib *rib)
! 543: {
! 544: return kernel_ioctl_ipv6_multipath (SIOCADDRT, p, rib, AF_INET6);
! 545: }
! 546:
! 547: int
! 548: kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
! 549: {
! 550: return kernel_ioctl_ipv6_multipath (SIOCDELRT, p, rib, AF_INET6);
! 551: }
! 552:
! 553: /* Delete IPv6 route from the kernel. */
! 554: int
! 555: kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
! 556: unsigned int index, int flags, int table)
! 557: {
! 558: return kernel_ioctl_ipv6 (SIOCDELRT, dest, gate, index, flags);
! 559: }
! 560: #endif /* HAVE_IPV6 */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>