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 <r...@openbsd.org> @@ -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;