0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-11-10 05:08:42 +00:00
bird/sysdep/unix/krt-set.c
Martin Mares 013a9b91fe When shutting down, remove all routes (except for RTS_INHERIT and RTS_DEVICE
routes) from kernel routing tables unless the "persist" switch is set.
1999-02-13 20:46:03 +00:00

162 lines
3.1 KiB
C

/*
* BIRD -- Unix Routing Table Syncing
*
* (c) 1998--1999 Martin Mares <mj@ucw.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <net/route.h>
#define LOCAL_DEBUG
#include "nest/bird.h"
#include "nest/iface.h"
#include "nest/route.h"
#include "nest/protocol.h"
#include "lib/unix.h"
#include "lib/krt.h"
int
krt_capable(rte *e)
{
rta *a = e->attrs;
return
a->cast == RTC_UNICAST &&
(a->dest == RTD_ROUTER
|| a->dest == RTD_DEVICE
#ifdef RTF_REJECT
|| a->dest == RTD_UNREACHABLE
#endif
) &&
!a->tos;
}
static inline int
krt_capable_op(rte *e)
{
rta *a = e->attrs;
#ifdef CONFIG_AUTO_ROUTES
if (a->dest == RTD_ROUTER && a->source == RTS_DEVICE)
return 0;
#endif
return krt_capable(e);
}
static void
krt_ioctl(int ioc, rte *e, char *name)
{
net *net = e->net;
struct rtentry re;
rta *a = e->attrs;
bzero(&re, sizeof(re));
fill_in_sockaddr((struct sockaddr_in *) &re.rt_dst, net->n.prefix, 0);
fill_in_sockaddr((struct sockaddr_in *) &re.rt_genmask, ipa_mkmask(net->n.pxlen), 0);
re.rt_flags = RTF_UP;
if (net->n.pxlen == 32)
re.rt_flags |= RTF_HOST;
switch (a->dest)
{
case RTD_ROUTER:
fill_in_sockaddr((struct sockaddr_in *) &re.rt_gateway, a->gw, 0);
re.rt_flags |= RTF_GATEWAY;
break;
case RTD_DEVICE:
re.rt_dev = a->iface->name;
break;
#ifdef RTF_REJECT
case RTD_UNREACHABLE:
re.rt_flags |= RTF_REJECT;
break;
#endif
default:
bug("krt set: unknown flags, but not filtered");
}
if (ioctl(if_scan_sock, ioc, &re) < 0)
log(L_ERR "%s(%I/%d): %m", name, net->n.prefix, net->n.pxlen);
}
void
krt_remove_route(rte *old)
{
net *net = old->net;
if (!krt_capable_op(old))
{
DBG("krt_remove_route(ignored %I/%d)\n", net->n.prefix, net->n.pxlen);
return;
}
DBG("krt_remove_route(%I/%d)\n", net->n.prefix, net->n.pxlen);
krt_ioctl(SIOCDELRT, old, "SIOCDELRT");
}
void
krt_add_route(rte *new)
{
net *net = new->net;
if (!krt_capable_op(new))
{
DBG("krt_add_route(ignored %I/%d)\n", net->n.prefix, net->n.pxlen);
return;
}
DBG("krt_add_route(%I/%d)\n", net->n.prefix, net->n.pxlen);
krt_ioctl(SIOCADDRT, new, "SIOCADDRT");
}
void
krt_set_notify(struct proto *x, net *net, rte *new, rte *old)
{
if (old)
krt_remove_route(old);
if (new)
krt_add_route(new);
}
void
krt_set_start(struct krt_proto *x)
{
if (if_scan_sock < 0)
bug("krt set: missing socket");
x->p.rt_notify = krt_set_notify;
}
void
krt_set_preconfig(struct krt_config *c)
{
}
void
krt_set_shutdown(struct krt_proto *x)
{
struct rtable *t = &master_table;
if (((struct krt_config *) x->p.cf)->setopt.persist)
return;
DBG("Flushing kernel routes...\n");
while (t && t->tos)
t = t->sibling;
if (!t)
return;
FIB_WALK(&t->fib, f)
{
net *n = (net *) f;
rte *e = n->routes;
if (e)
{
rta *a = e->attrs;
if (a->source != RTS_DEVICE && a->source != RTS_INHERIT)
krt_remove_route(e);
}
}
FIB_WALK_END;
}