if you have two carped routers and you also want to redistribute
routes that relayd inserts into the kernel via ospf or bgp, but
only on the router that has the master carp interface, then this
diff should allow you to do so.
in relayd you can have a config like:
table <routers> { $gw1 ip ttl 1 }
router "somenet" {
route 192.168.1.0/24
interface carp0
rtlabel "somenet"
forward to <routers> check icmp
}
and in ospfd:
redistribute rtlabel "somenet"
this will cause the firewall to advertise a route to the 192.168.1.0
only if it can ping $gw1 AND only if the carp0 interface is up (ie,
it is the master).
my intended use is to build very redundant anycast setups for
services checked with relayd.
ok?
Index: parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/parse.y,v
retrieving revision 1.149
diff -u -p -r1.149 parse.y
--- parse.y 26 Oct 2010 15:04:37 -0000 1.149
+++ parse.y 5 Nov 2010 08:30:19 -0000
@@ -1501,6 +1501,18 @@ routeoptsl : ROUTE address '/' NUMBER {
router->rt_conf.gwtable = $3->conf.id;
router->rt_conf.gwport = $3->conf.port;
}
+ | INTERFACE STRING {
+ size_t rv;
+
+ rv = strlcpy(router->rt_conf.ifname, $2,
+ sizeof(router->rt_conf.ifname));
+ free($2);
+
+ if (rv >= sizeof(router->rt_conf.ifname)) {
+ yyerror("router interface name truncated");
+ YYERROR;
+ }
+ }
| RTABLE NUMBER {
if (router->rt_conf.rtable) {
yyerror("router %s rtable already specified",
Index: pfe_route.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/pfe_route.c,v
retrieving revision 1.1
diff -u -p -r1.1 pfe_route.c
--- pfe_route.c 13 Aug 2009 13:51:21 -0000 1.1
+++ pfe_route.c 5 Nov 2010 08:30:19 -0000
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfe_route.c,v 1.1 2009/08/13 13:51:21 reyk Exp $ */
+/* $OpenBSD$ */
/*
* Copyright (c) 2009 Reyk Floeter <[email protected]>
@@ -19,8 +19,10 @@
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/socket.h>
+#include <sys/uio.h>
#include <net/if.h>
+#include <net/if_dl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/route.h>
@@ -38,23 +40,7 @@
extern struct imsgev *iev_main;
-struct relay_rtmsg {
- struct rt_msghdr rm_hdr;
- union {
- struct {
- struct sockaddr_in rm_dst;
- struct sockaddr_in rm_gateway;
- struct sockaddr_in rm_netmask;
- struct sockaddr_rtlabel rm_label;
- } u4;
- struct {
- struct sockaddr_in6 rm_dst;
- struct sockaddr_in6 rm_gateway;
- struct sockaddr_in6 rm_netmask;
- struct sockaddr_rtlabel rm_label;
- } u6;
- } rm_u;
-};
+void iov_add(struct iovec *, int *, void *, size_t);
void
init_routes(struct relayd *env)
@@ -106,19 +92,52 @@ sync_routes(struct relayd *env, struct r
}
}
+#define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) :
sizeof(long))
+
+void
+iov_add(struct iovec *iov, int *iovcount, void *base, size_t len)
+{
+ static char pad[sizeof(long)];
+
+ iov[*iovcount].iov_base = base;
+ iov[*iovcount].iov_len = len;
+ (*iovcount)++;
+
+ if (ROUNDUP(len) > len) {
+ iov[*iovcount].iov_base = pad;
+ iov[*iovcount].iov_len = ROUNDUP(len) - len;
+ (*iovcount)++;
+ }
+}
+
int
pfe_route(struct relayd *env, struct ctl_netroute *crt)
{
- struct relay_rtmsg rm;
- struct sockaddr_rtlabel sr;
+ struct rt_msghdr rm_hdr;
+ union {
+ struct {
+ struct sockaddr_in rm_dst;
+ struct sockaddr_in rm_gateway;
+ struct sockaddr_in rm_netmask;
+ } u4;
+ struct {
+ struct sockaddr_in6 rm_dst;
+ struct sockaddr_in6 rm_gateway;
+ struct sockaddr_in6 rm_netmask;
+ } u6;
+ } rm_u;
+ struct sockaddr_rtlabel rm_label;
+ struct sockaddr_dl rm_ifp;
+
struct sockaddr_storage *gw;
struct sockaddr_in *s4;
struct sockaddr_in6 *s6;
- size_t len = 0;
- struct netroute *nr;
+ struct netroute *nr;
struct host *host;
char *gwname;
int i = 0;
+ struct iovec iov[8];
+ int iovcount = 1;
if ((nr = route_find(env, crt->id)) == NULL ||
(host = host_find(env, crt->hostid)) == NULL) {
@@ -129,71 +148,59 @@ pfe_route(struct relayd *env, struct ctl
gw = &host->conf.ss;
gwname = host->conf.name;
- bzero(&rm, sizeof(rm));
- bzero(&sr, sizeof(sr));
-
- rm.rm_hdr.rtm_msglen = len;
- rm.rm_hdr.rtm_version = RTM_VERSION;
- rm.rm_hdr.rtm_type = HOST_ISUP(crt->up) ? RTM_ADD : RTM_DELETE;
- rm.rm_hdr.rtm_flags = RTF_STATIC | RTF_GATEWAY | RTF_MPATH;
- rm.rm_hdr.rtm_seq = env->sc_rtseq++;
- rm.rm_hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
- rm.rm_hdr.rtm_tableid = nr->nr_router->rt_conf.rtable;
+ bzero(iov, sizeof(iov));
+ bzero(&rm_hdr, sizeof(rm_hdr));
+ bzero(&rm_u, sizeof(rm_u));
+
+ rm_hdr.rtm_msglen = sizeof(rm_hdr);
+ rm_hdr.rtm_version = RTM_VERSION;
+ rm_hdr.rtm_type = HOST_ISUP(crt->up) ? RTM_ADD : RTM_DELETE;
+ rm_hdr.rtm_flags = RTF_STATIC | RTF_GATEWAY | RTF_MPATH;
+ rm_hdr.rtm_seq = env->sc_rtseq++;
+ rm_hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
+ rm_hdr.rtm_tableid = nr->nr_router->rt_conf.rtable;
- if (strlen(nr->nr_router->rt_conf.label)) {
- rm.rm_hdr.rtm_addrs |= RTA_LABEL;
- sr.sr_len = sizeof(sr);
- if (snprintf(sr.sr_label, sizeof(sr.sr_label),
- "%s", nr->nr_router->rt_conf.label) == -1)
- goto bad;
- }
+ iov[0].iov_base = &rm_hdr;
+ iov[0].iov_len = sizeof(rm_hdr);
if (nr->nr_conf.ss.ss_family == AF_INET) {
- rm.rm_hdr.rtm_msglen = len =
- sizeof(rm.rm_hdr) + sizeof(rm.rm_u.u4);
-
- bcopy(&sr, &rm.rm_u.u4.rm_label, sizeof(sr));
-
- s4 = &rm.rm_u.u4.rm_dst;
+ s4 = &rm_u.u4.rm_dst;
s4->sin_family = AF_INET;
- s4->sin_len = sizeof(rm.rm_u.u4.rm_dst);
+ s4->sin_len = sizeof(rm_u.u4.rm_dst);
s4->sin_addr.s_addr =
((struct sockaddr_in *)&nr->nr_conf.ss)->sin_addr.s_addr;
- s4 = &rm.rm_u.u4.rm_gateway;
+ s4 = &rm_u.u4.rm_gateway;
s4->sin_family = AF_INET;
- s4->sin_len = sizeof(rm.rm_u.u4.rm_gateway);
+ s4->sin_len = sizeof(rm_u.u4.rm_gateway);
s4->sin_addr.s_addr =
((struct sockaddr_in *)gw)->sin_addr.s_addr;
- rm.rm_hdr.rtm_addrs |= RTA_NETMASK;
- s4 = &rm.rm_u.u4.rm_netmask;
+ s4 = &rm_u.u4.rm_netmask;
s4->sin_family = AF_INET;
- s4->sin_len = sizeof(rm.rm_u.u4.rm_netmask);
+ s4->sin_len = sizeof(rm_u.u4.rm_netmask);
if (nr->nr_conf.prefixlen)
s4->sin_addr.s_addr =
htonl(0xffffffff << (32 - nr->nr_conf.prefixlen));
else if (nr->nr_conf.prefixlen < 0)
- rm.rm_hdr.rtm_flags |= RTF_HOST;
- } else if (nr->nr_conf.ss.ss_family == AF_INET6) {
- rm.rm_hdr.rtm_msglen = len =
- sizeof(rm.rm_hdr) + sizeof(rm.rm_u.u6);
+ rm_hdr.rtm_flags |= RTF_HOST;
- bcopy(&sr, &rm.rm_u.u6.rm_label, sizeof(sr));
+ iov_add(iov, &iovcount, &rm_u.u4, sizeof(rm_u.u4));
- s6 = &rm.rm_u.u6.rm_dst;
+ rm_hdr.rtm_msglen += ROUNDUP(sizeof(rm_u.u4));
+ } else if (nr->nr_conf.ss.ss_family == AF_INET6) {
+ s6 = &rm_u.u6.rm_dst;
bcopy(((struct sockaddr_in6 *)&nr->nr_conf.ss),
s6, sizeof(*s6));
s6->sin6_family = AF_INET6;
s6->sin6_len = sizeof(*s6);
- s6 = &rm.rm_u.u6.rm_gateway;
+ s6 = &rm_u.u6.rm_gateway;
bcopy(((struct sockaddr_in6 *)gw), s6, sizeof(*s6));
s6->sin6_family = AF_INET6;
s6->sin6_len = sizeof(*s6);
- rm.rm_hdr.rtm_addrs |= RTA_NETMASK;
- s6 = &rm.rm_u.u6.rm_netmask;
+ s6 = &rm_u.u6.rm_netmask;
s6->sin6_family = AF_INET6;
s6->sin6_len = sizeof(*s6);
if (nr->nr_conf.prefixlen) {
@@ -204,19 +211,50 @@ pfe_route(struct relayd *env, struct ctl
s6->sin6_addr.s6_addr[nr->nr_conf.prefixlen
/ 8] = 0xff00 >> i;
} else if (nr->nr_conf.prefixlen < 0)
- rm.rm_hdr.rtm_flags |= RTF_HOST;
+ rm_hdr.rtm_flags |= RTF_HOST;
+
+ iov_add(iov, &iovcount, &rm_u.u6, sizeof(rm_u.u6));
+
+ rm_hdr.rtm_msglen += ROUNDUP(sizeof(rm_u.u6));
} else
fatal("pfe_route: invalid address family");
+ if (strlen(nr->nr_router->rt_conf.ifname)) {
+ bzero(&rm_ifp, sizeof(rm_ifp));
+
+ rm_ifp.sdl_len = sizeof(rm_ifp);
+ rm_ifp.sdl_family = AF_LINK;
+ link_addr(nr->nr_router->rt_conf.ifname, &rm_ifp);
+
+ iov_add(iov, &iovcount, &rm_ifp, sizeof(rm_ifp));
+
+ rm_hdr.rtm_msglen += ROUNDUP(sizeof(rm_ifp));
+ rm_hdr.rtm_addrs |= RTA_IFP;
+ }
+
+ if (strlen(nr->nr_router->rt_conf.label)) {
+ bzero(&rm_label, sizeof(rm_label));
+
+ rm_label.sr_len = sizeof(rm_label);
+ if (snprintf(rm_label.sr_label, sizeof(rm_label.sr_label),
+ "%s", nr->nr_router->rt_conf.label) == -1)
+ goto bad;
+
+ iov_add(iov, &iovcount, &rm_label, sizeof(rm_label));
+
+ rm_hdr.rtm_msglen += ROUNDUP(sizeof(rm_label));
+ rm_hdr.rtm_addrs |= RTA_LABEL;
+ }
+
retry:
- if (write(env->sc_rtsock, &rm, len) == -1) {
+ if (writev(env->sc_rtsock, iov, iovcount) == -1) {
switch (errno) {
case EEXIST:
case ESRCH:
- if (rm.rm_hdr.rtm_type == RTM_ADD) {
- rm.rm_hdr.rtm_type = RTM_CHANGE;
+ if (rm_hdr.rtm_type == RTM_ADD) {
+ rm_hdr.rtm_type = RTM_CHANGE;
goto retry;
- } else if (rm.rm_hdr.rtm_type == RTM_DELETE) {
+ } else if (rm_hdr.rtm_type == RTM_DELETE) {
/* Ignore */
break;
}
Index: relayd.conf.5
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relayd.conf.5,v
retrieving revision 1.116
diff -u -p -r1.116 relayd.conf.5
--- relayd.conf.5 26 Oct 2010 15:26:58 -0000 1.116
+++ relayd.conf.5 5 Nov 2010 08:30:19 -0000
@@ -1100,6 +1100,10 @@ Specify the table of target gateways to
.Sx TABLES
section above for information about table options.
This entry is mandatory and must be specified once.
+.It Ic interface Ar name
+Add the routes using the interface specified by the
+.Ar name
+argument to the kernel routing table.
.It Xo
.Ic route
.Ar address Ns Li / Ns Ar prefix
Index: relayd.h
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relayd.h,v
retrieving revision 1.138
diff -u -p -r1.138 relayd.h
--- relayd.h 26 Oct 2010 15:04:37 -0000 1.138
+++ relayd.h 5 Nov 2010 08:30:19 -0000
@@ -609,6 +609,7 @@ struct router_config {
u_int32_t flags;
char name[MAXHOSTNAMELEN];
char label[RT_LABEL_SIZE];
+ char ifname[IFNAMSIZ];
int nroutes;
objid_t gwtable;
in_port_t gwport;