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;

Reply via email to