rt_ioctl.c
上传用户:xiaozhuqw
上传日期:2009-11-15
资源大小:1338k
文件大小:13k
源码类别:

网络

开发平台:

Unix_Linux

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