mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-05-04 03:41:20 +00:00
zebra: remove rt_ioctl kernel interface
None of the BSDs uses ioctls to set routes anymore. Signed-off-by: David Lamparter <equinox@opensourcerouting.org> Acked-by: Greg Troxel <gdt@ir.bbn.com> Acked-by: Feng Lu <lu.feng@6wind.com> Acked-by: Paul Jakma <paul@jakma.org>
This commit is contained in:
parent
f9a3a26046
commit
8df1db88df
420
zebra/rt_ioctl.c
420
zebra/rt_ioctl.c
@ -1,420 +0,0 @@
|
|||||||
/*
|
|
||||||
* kernel routing table update by ioctl().
|
|
||||||
* Copyright (C) 1997, 98 Kunihiro Ishiguro
|
|
||||||
*
|
|
||||||
* This file is part of GNU Zebra.
|
|
||||||
*
|
|
||||||
* GNU Zebra is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License as published by the
|
|
||||||
* Free Software Foundation; either version 2, or (at your option) any
|
|
||||||
* later version.
|
|
||||||
*
|
|
||||||
* GNU Zebra is distributed in the hope that it will be useful, but
|
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with GNU Zebra; see the file COPYING. If not, write to the Free
|
|
||||||
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|
||||||
* 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <zebra.h>
|
|
||||||
|
|
||||||
#include "prefix.h"
|
|
||||||
#include "log.h"
|
|
||||||
#include "if.h"
|
|
||||||
|
|
||||||
#include "zebra/zserv.h"
|
|
||||||
#include "zebra/rib.h"
|
|
||||||
#include "zebra/debug.h"
|
|
||||||
#include "zebra/rt.h"
|
|
||||||
|
|
||||||
/* Initialize of kernel interface. There is no kernel communication
|
|
||||||
support under ioctl(). So this is dummy stub function. */
|
|
||||||
void
|
|
||||||
kernel_init (void)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Dummy function of routing socket. */
|
|
||||||
static void
|
|
||||||
kernel_read (int sock)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Solaris has ortentry. */
|
|
||||||
#ifdef HAVE_OLD_RTENTRY
|
|
||||||
#define rtentry ortentry
|
|
||||||
#endif /* HAVE_OLD_RTENTRY */
|
|
||||||
|
|
||||||
/* Interface to ioctl route message. */
|
|
||||||
static int
|
|
||||||
kernel_ioctl_ipv4 (u_long cmd, struct prefix *p, struct rib *rib, int family)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
int sock;
|
|
||||||
struct rtentry rtentry;
|
|
||||||
struct sockaddr_in sin_dest, sin_mask, sin_gate;
|
|
||||||
struct nexthop *nexthop, *tnexthop;
|
|
||||||
int recursing;
|
|
||||||
int nexthop_num = 0;
|
|
||||||
struct interface *ifp;
|
|
||||||
|
|
||||||
memset (&rtentry, 0, sizeof (struct rtentry));
|
|
||||||
|
|
||||||
/* Make destination. */
|
|
||||||
memset (&sin_dest, 0, sizeof (struct sockaddr_in));
|
|
||||||
sin_dest.sin_family = AF_INET;
|
|
||||||
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
|
|
||||||
sin_dest.sin_len = sizeof (struct sockaddr_in);
|
|
||||||
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
|
|
||||||
sin_dest.sin_addr = p->u.prefix4;
|
|
||||||
|
|
||||||
if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE))
|
|
||||||
{
|
|
||||||
SET_FLAG (rtentry.rt_flags, RTF_REJECT);
|
|
||||||
|
|
||||||
if (cmd == SIOCADDRT)
|
|
||||||
for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
|
|
||||||
{
|
|
||||||
/* We shouldn't encounter recursive nexthops on discard routes,
|
|
||||||
* but it is probably better to handle that case correctly anyway.
|
|
||||||
*/
|
|
||||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
|
||||||
continue;
|
|
||||||
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
|
|
||||||
}
|
|
||||||
goto skip;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset (&sin_gate, 0, sizeof (struct sockaddr_in));
|
|
||||||
|
|
||||||
/* Make gateway. */
|
|
||||||
for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
|
|
||||||
{
|
|
||||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if ((cmd == SIOCADDRT
|
|
||||||
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
|
|
||||||
|| (cmd == SIOCDELRT
|
|
||||||
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
|
|
||||||
{
|
|
||||||
if (nexthop->type == NEXTHOP_TYPE_IPV4 ||
|
|
||||||
nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
|
|
||||||
{
|
|
||||||
sin_gate.sin_family = AF_INET;
|
|
||||||
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
|
|
||||||
sin_gate.sin_len = sizeof (struct sockaddr_in);
|
|
||||||
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
|
|
||||||
sin_gate.sin_addr = nexthop->gate.ipv4;
|
|
||||||
rtentry.rt_flags |= RTF_GATEWAY;
|
|
||||||
}
|
|
||||||
if (nexthop->type == NEXTHOP_TYPE_IFINDEX)
|
|
||||||
{
|
|
||||||
ifp = if_lookup_by_index (nexthop->ifindex);
|
|
||||||
if (ifp)
|
|
||||||
rtentry.rt_dev = ifp->name;
|
|
||||||
else
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cmd == SIOCADDRT)
|
|
||||||
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
|
|
||||||
|
|
||||||
nexthop_num++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If there is no useful nexthop then return. */
|
|
||||||
if (nexthop_num == 0)
|
|
||||||
{
|
|
||||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
|
||||||
zlog_debug ("netlink_route_multipath(): No useful nexthop.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
skip:
|
|
||||||
|
|
||||||
memset (&sin_mask, 0, sizeof (struct sockaddr_in));
|
|
||||||
sin_mask.sin_family = AF_INET;
|
|
||||||
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
|
|
||||||
sin_mask.sin_len = sizeof (struct sockaddr_in);
|
|
||||||
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
|
|
||||||
masklen2ip (p->prefixlen, &sin_mask.sin_addr);
|
|
||||||
|
|
||||||
/* Set destination address, mask and gateway.*/
|
|
||||||
memcpy (&rtentry.rt_dst, &sin_dest, sizeof (struct sockaddr_in));
|
|
||||||
|
|
||||||
if (rtentry.rt_flags & RTF_GATEWAY)
|
|
||||||
memcpy (&rtentry.rt_gateway, &sin_gate, sizeof (struct sockaddr_in));
|
|
||||||
|
|
||||||
#ifndef SUNOS_5
|
|
||||||
memcpy (&rtentry.rt_genmask, &sin_mask, sizeof (struct sockaddr_in));
|
|
||||||
#endif /* SUNOS_5 */
|
|
||||||
|
|
||||||
/* Metric. It seems metric minus one value is installed... */
|
|
||||||
rtentry.rt_metric = rib->metric;
|
|
||||||
|
|
||||||
/* Routing entry flag set. */
|
|
||||||
if (p->prefixlen == 32)
|
|
||||||
rtentry.rt_flags |= RTF_HOST;
|
|
||||||
|
|
||||||
rtentry.rt_flags |= RTF_UP;
|
|
||||||
|
|
||||||
/* Additional flags */
|
|
||||||
/* rtentry.rt_flags |= flags; */
|
|
||||||
|
|
||||||
/* For tagging route. */
|
|
||||||
/* rtentry.rt_flags |= RTF_DYNAMIC; */
|
|
||||||
|
|
||||||
/* Open socket for ioctl. */
|
|
||||||
sock = socket (AF_INET, SOCK_DGRAM, 0);
|
|
||||||
if (sock < 0)
|
|
||||||
{
|
|
||||||
zlog_warn ("can't make socket\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Send message by ioctl(). */
|
|
||||||
ret = ioctl (sock, cmd, &rtentry);
|
|
||||||
if (ret < 0)
|
|
||||||
{
|
|
||||||
switch (errno)
|
|
||||||
{
|
|
||||||
case EEXIST:
|
|
||||||
close (sock);
|
|
||||||
return ZEBRA_ERR_RTEXIST;
|
|
||||||
break;
|
|
||||||
case ENETUNREACH:
|
|
||||||
close (sock);
|
|
||||||
return ZEBRA_ERR_RTUNREACH;
|
|
||||||
break;
|
|
||||||
case EPERM:
|
|
||||||
close (sock);
|
|
||||||
return ZEBRA_ERR_EPERM;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
close (sock);
|
|
||||||
zlog_warn ("write : %s (%d)", safe_strerror (errno), errno);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
close (sock);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
kernel_add_ipv4 (struct prefix *p, struct rib *rib)
|
|
||||||
{
|
|
||||||
return kernel_ioctl_ipv4 (SIOCADDRT, p, rib, AF_INET);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
kernel_update_ipv4 (struct prefix *p, struct rib *rib)
|
|
||||||
{
|
|
||||||
kernel_ioctl_ipv4 (SIOCDELRT, p, rib, AF_INET);
|
|
||||||
return kernel_ioctl_ipv4 (SIOCADDRT, p, rib, AF_INET);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
|
|
||||||
{
|
|
||||||
return kernel_ioctl_ipv4 (SIOCDELRT, p, rib, AF_INET);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
|
|
||||||
/* Below is hack for GNU libc definition and Linux 2.1.X header. */
|
|
||||||
#undef RTF_DEFAULT
|
|
||||||
#undef RTF_ADDRCONF
|
|
||||||
|
|
||||||
#include <asm/types.h>
|
|
||||||
|
|
||||||
#if defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1
|
|
||||||
/* struct in6_rtmsg will be declared in net/route.h. */
|
|
||||||
#else
|
|
||||||
#include <linux/ipv6_route.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int
|
|
||||||
kernel_ioctl_ipv6 (u_long type, struct prefix_ipv6 *dest, struct in6_addr *gate,
|
|
||||||
int index, int flags)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
int sock;
|
|
||||||
struct in6_rtmsg rtm;
|
|
||||||
|
|
||||||
memset (&rtm, 0, sizeof (struct in6_rtmsg));
|
|
||||||
|
|
||||||
rtm.rtmsg_flags |= RTF_UP;
|
|
||||||
rtm.rtmsg_metric = 1;
|
|
||||||
memcpy (&rtm.rtmsg_dst, &dest->prefix, sizeof (struct in6_addr));
|
|
||||||
rtm.rtmsg_dst_len = dest->prefixlen;
|
|
||||||
|
|
||||||
/* We need link local index. But this should be done caller...
|
|
||||||
if (IN6_IS_ADDR_LINKLOCAL(&rtm.rtmsg_gateway))
|
|
||||||
{
|
|
||||||
index = if_index_address (&rtm.rtmsg_gateway);
|
|
||||||
rtm.rtmsg_ifindex = index;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
rtm.rtmsg_ifindex = 0;
|
|
||||||
*/
|
|
||||||
|
|
||||||
rtm.rtmsg_flags |= RTF_GATEWAY;
|
|
||||||
|
|
||||||
/* For tagging route. */
|
|
||||||
/* rtm.rtmsg_flags |= RTF_DYNAMIC; */
|
|
||||||
|
|
||||||
memcpy (&rtm.rtmsg_gateway, gate, sizeof (struct in6_addr));
|
|
||||||
|
|
||||||
if (index)
|
|
||||||
rtm.rtmsg_ifindex = index;
|
|
||||||
else
|
|
||||||
rtm.rtmsg_ifindex = 0;
|
|
||||||
|
|
||||||
rtm.rtmsg_metric = 1;
|
|
||||||
|
|
||||||
sock = socket (AF_INET6, SOCK_DGRAM, 0);
|
|
||||||
if (sock < 0)
|
|
||||||
{
|
|
||||||
zlog_warn ("can't make socket\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Send message via ioctl. */
|
|
||||||
ret = ioctl (sock, type, &rtm);
|
|
||||||
if (ret < 0)
|
|
||||||
{
|
|
||||||
zlog_warn ("can't %s ipv6 route: %s\n", type == SIOCADDRT ? "add" : "delete",
|
|
||||||
safe_strerror(errno));
|
|
||||||
ret = errno;
|
|
||||||
close (sock);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
close (sock);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
kernel_ioctl_ipv6_multipath (u_long cmd, struct prefix *p, struct rib *rib,
|
|
||||||
int family)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
int sock;
|
|
||||||
struct in6_rtmsg rtm;
|
|
||||||
struct nexthop *nexthop, *tnexthop;
|
|
||||||
int recursing;
|
|
||||||
int nexthop_num = 0;
|
|
||||||
|
|
||||||
memset (&rtm, 0, sizeof (struct in6_rtmsg));
|
|
||||||
|
|
||||||
rtm.rtmsg_flags |= RTF_UP;
|
|
||||||
rtm.rtmsg_metric = rib->metric;
|
|
||||||
memcpy (&rtm.rtmsg_dst, &p->u.prefix, sizeof (struct in6_addr));
|
|
||||||
rtm.rtmsg_dst_len = p->prefixlen;
|
|
||||||
|
|
||||||
/* We need link local index. But this should be done caller...
|
|
||||||
if (IN6_IS_ADDR_LINKLOCAL(&rtm.rtmsg_gateway))
|
|
||||||
{
|
|
||||||
index = if_index_address (&rtm.rtmsg_gateway);
|
|
||||||
rtm.rtmsg_ifindex = index;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
rtm.rtmsg_ifindex = 0;
|
|
||||||
*/
|
|
||||||
|
|
||||||
rtm.rtmsg_flags |= RTF_GATEWAY;
|
|
||||||
|
|
||||||
/* For tagging route. */
|
|
||||||
/* rtm.rtmsg_flags |= RTF_DYNAMIC; */
|
|
||||||
|
|
||||||
/* Make gateway. */
|
|
||||||
for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
|
|
||||||
{
|
|
||||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if ((cmd == SIOCADDRT
|
|
||||||
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
|
|
||||||
|| (cmd == SIOCDELRT
|
|
||||||
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
|
|
||||||
{
|
|
||||||
if (nexthop->type == NEXTHOP_TYPE_IPV6
|
|
||||||
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
|
|
||||||
{
|
|
||||||
memcpy (&rtm.rtmsg_gateway, &nexthop->gate.ipv6,
|
|
||||||
sizeof (struct in6_addr));
|
|
||||||
}
|
|
||||||
if (nexthop->type == NEXTHOP_TYPE_IFINDEX
|
|
||||||
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
|
|
||||||
rtm.rtmsg_ifindex = nexthop->ifindex;
|
|
||||||
else
|
|
||||||
rtm.rtmsg_ifindex = 0;
|
|
||||||
|
|
||||||
if (cmd == SIOCADDRT)
|
|
||||||
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
|
|
||||||
|
|
||||||
nexthop_num++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If there is no useful nexthop then return. */
|
|
||||||
if (nexthop_num == 0)
|
|
||||||
{
|
|
||||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
|
||||||
zlog_debug ("netlink_route_multipath(): No useful nexthop.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
sock = socket (AF_INET6, SOCK_DGRAM, 0);
|
|
||||||
if (sock < 0)
|
|
||||||
{
|
|
||||||
zlog_warn ("can't make socket\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Send message via ioctl. */
|
|
||||||
ret = ioctl (sock, cmd, &rtm);
|
|
||||||
if (ret < 0)
|
|
||||||
{
|
|
||||||
zlog_warn ("can't %s ipv6 route: %s\n",
|
|
||||||
cmd == SIOCADDRT ? "add" : "delete",
|
|
||||||
safe_strerror(errno));
|
|
||||||
ret = errno;
|
|
||||||
close (sock);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
close (sock);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
kernel_add_ipv6 (struct prefix *p, struct rib *rib)
|
|
||||||
{
|
|
||||||
return kernel_ioctl_ipv6_multipath (SIOCADDRT, p, rib, AF_INET6);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
kernel_update_ipv6 (struct prefix *p, struct rib *rib)
|
|
||||||
{
|
|
||||||
kernel_ioctl_ipv6_multipath (SIOCDELRT, p, rib, AF_INET6);
|
|
||||||
return kernel_ioctl_ipv6_multipath(SIOCADDRT, p, rib, AF_INET6);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
|
|
||||||
{
|
|
||||||
return kernel_ioctl_ipv6_multipath (SIOCDELRT, p, rib, AF_INET6);
|
|
||||||
}
|
|
||||||
#endif /* HAVE_IPV6 */
|
|
Loading…
Reference in New Issue
Block a user