i want relayd to check teh availability of some services and inject
routes when the service is available. if it is available, i want
to advertise the routes using ospfd, but i also want the local
machine to be able to contact the service even if it isnt the carp
master.

to do that i need to inject the routes twice, once on my real
interface and again on my carp interfaces. the route on the real
interface needs to be a higher priority than the carp route.

this shuffles relayd to accomodate this.

it mostly adds stuff to the route statements in routers, but i also
take priorities away from hosts in tables so i can specify them on
routes.

this is an example config:

        rns_nogal=130.102.71.227
        rns_neem=130.102.71.229

        table <rns> { $rns_nogal ip ttl 1, $rns_neem ip ttl 1 } 

        router "rns" { 
                route 130.102.71.160/31 interface vlan888 priority 8
                route 130.102.71.160/31 interface carp40888 priority 16
                forward to <rns> check icmp 
        }

        redirect "dns" {
                listen on 130.102.71.160 tcp port 53
                listen on 130.102.71.160 udp port 53
                listen on 130.102.71.161 tcp port 53
                listen on 130.102.71.161 udp port 53

                match pftag rns
                forward to <rns> port 53 check icmp
        }

i wish redirects took a prefix. maybe thats a diff for another day.

anyway, here's the diff.

thoughts? tweaks? ok?

Index: parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/parse.y,v
retrieving revision 1.204
diff -u -p -r1.204 parse.y
--- parse.y     2 May 2015 13:15:24 -0000       1.204
+++ parse.y     14 May 2015 11:30:28 -0000
@@ -173,6 +173,7 @@ typedef struct {
 %token ROUTER RTLABEL TRANSPARENT TRAP UPDATES URL VIRTUAL WITH TTL RTABLE
 %token MATCH PARAMS RANDOM LEASTSTATES SRCHASH KEY CERTIFICATE PASSWORD ECDH
 %token EDH CURVE
+%token NONE LOCAL CONNECTED STATIC OSPF ISIS RIP BGP DEFAULT
 %token <v.string>      STRING
 %token  <v.number>     NUMBER
 %type  <v.string>      hostname interface table value optstring
@@ -182,6 +183,7 @@ typedef struct {
 %type  <v.number>      redirect_proto relay_proto match
 %type  <v.number>      action ruleaf key_option
 %type  <v.number>      tlsdhparams tlsecdhcurve
+%type  <v.number>      rtprio
 %type  <v.port>        port
 %type  <v.host>        host
 %type  <v.addr>        address
@@ -1864,8 +1866,8 @@ router            : ROUTER STRING         {
                        router = rt;
 
                        tableport = -1;
-               } '{' optnl routeopts_l '}'     {
-                       if (!router->rt_conf.nroutes) {
+               } '{' optnl routeropts_l '}'    {
+                       if (TAILQ_EMPTY(&router->rt_netroutes)) {
                                yyerror("router %s without routes",
                                    router->rt_conf.name);
                                free(router);
@@ -1881,11 +1883,11 @@ router          : ROUTER STRING         {
                }
                ;
 
-routeopts_l    : routeopts_l routeoptsl nl
-               | routeoptsl optnl
+routeropts_l   : routeropts_l routeroptsl nl
+               | routeroptsl optnl
                ;
 
-routeoptsl     : ROUTE address '/' NUMBER {
+routeroptsl    : ROUTE address '/' NUMBER {
                        struct netroute *nr;
 
                        if (router->rt_conf.af == AF_UNSPEC)
@@ -1914,15 +1916,15 @@ routeoptsl      : ROUTE address '/' NUMBER {
                                YYERROR;
                        }
                        nr->nr_conf.prefixlen = $4;
+                       nr->nr_conf.priority = RTP_DEFAULT;
                        nr->nr_conf.routerid = router->rt_conf.id;
                        nr->nr_router = router;
                        bcopy(&$2.ss, &nr->nr_conf.ss, sizeof($2.ss));
 
-                       router->rt_conf.nroutes++;
-                       conf->sc_routecount++;
                        TAILQ_INSERT_TAIL(&router->rt_netroutes, nr, nr_entry);
+                       conf->sc_routecount++;
                        TAILQ_INSERT_TAIL(conf->sc_routes, nr, nr_route);
-               }
+               } routeopts_l
                | FORWARD TO tablespec {
                        free(hashkey);
                        hashkey = NULL;
@@ -1950,18 +1952,74 @@ routeoptsl      : ROUTE address '/' NUMBER {
                        }
                        router->rt_conf.rtable = $2;
                }
-               | RTLABEL STRING {
-                       if (strlcpy(router->rt_conf.label, $2,
-                           sizeof(router->rt_conf.label)) >=
-                           sizeof(router->rt_conf.label)) {
-                               yyerror("route label truncated");
+               | DISABLE               { rlay->rl_conf.flags |= F_DISABLE; }
+               | include
+               ;
+
+routeopts_l    : routeopts_l routeoptsl
+               | routeoptsl
+               | /* empty */
+               ;
+
+routeoptsl     : INTERFACE STRING {
+                       struct netroute *nr = 
+                           TAILQ_LAST(&router->rt_netroutes, netroutelist);
+                       struct netroute_config *c = &nr->nr_conf;
+                       size_t len;
+
+                       if (strlen(c->ifname)) {
+                               yyerror("interface name already defined");
                                free($2);
                                YYERROR;
                        }
+
+                       len = strlcpy(c->ifname, $2, sizeof(c->ifname));
                        free($2);
+
+                       if (len >= sizeof(c->ifname)) {
+                               yyerror("interface name truncated");
+                               YYERROR;
+                       }
+               }
+               | PRIORITY rtprio {
+                       struct netroute *nr = 
+                           TAILQ_LAST(&router->rt_netroutes, netroutelist);
+                       struct netroute_config *c = &nr->nr_conf;
+
+                       c->priority = $2;
+               }
+               | RTLABEL STRING {
+                       struct netroute *nr = 
+                           TAILQ_LAST(&router->rt_netroutes, netroutelist);
+                       struct netroute_config *c = &nr->nr_conf;
+                       size_t len;
+
+                       len = strlcpy(c->label, $2, sizeof(c->label));
+                       free($2);
+
+                       if (len >= sizeof(c->label)) {
+                               yyerror("route label truncated");
+                               YYERROR;
+                       }
+               }
+               ;
+
+rtprio         : NONE                  { $$ = RTP_NONE; }
+               | LOCAL                 { $$ = RTP_LOCAL; }
+               | CONNECTED             { $$ = RTP_CONNECTED; }
+               | STATIC                { $$ = RTP_STATIC; }
+               | OSPF                  { $$ = RTP_OSPF; }
+               | ISIS                  { $$ = RTP_ISIS; }
+               | RIP                   { $$ = RTP_RIP; }
+               | BGP                   { $$ = RTP_BGP; }
+               | DEFAULT               { $$ = RTP_DEFAULT; }
+               | NUMBER {
+                       if ($1 < 0 || $1 > RTP_MAX) {
+                               yyerror("invalid priority value: %d\n", $1);
+                               YYERROR;
+                       }
+                       $$ = $1;
                }
-               | DISABLE               { rlay->rl_conf.flags |= F_DISABLE; }
-               | include
                ;
 
 dstaf          : /* empty */           {
@@ -2039,17 +2097,6 @@ hostflags        : RETRY NUMBER          {
                        }
                        hst->conf.parentid = $2;
                }
-               | PRIORITY NUMBER               {
-                       if (hst->conf.priority) {
-                               yyerror("priority already set");
-                               YYERROR;
-                       }
-                       if ($2 < 0 || $2 > RTP_MAX) {
-                               yyerror("invalid priority value: %d\n", $2);
-                               YYERROR;
-                       }
-                       hst->conf.priority = $2;
-               }
                | IP TTL NUMBER         {
                        if (hst->conf.ttl) {
                                yyerror("ttl value already set");
@@ -2160,6 +2207,7 @@ lookup(char *s)
                { "append",             APPEND },
                { "backlog",            BACKLOG },
                { "backup",             BACKUP },
+               { "bgp",                BGP },
                { "block",              BLOCK },
                { "buffer",             BUFFER },
                { "ca",                 CA },
@@ -2168,8 +2216,10 @@ lookup(char *s)
                { "check",              CHECK },
                { "ciphers",            CIPHERS },
                { "code",               CODE },
+               { "connected",          CONNECTED },
                { "cookie",             COOKIE },
                { "curve",              CURVE },
+               { "default",            DEFAULT },
                { "demote",             DEMOTE },
                { "destination",        DESTINATION },
                { "digest",             DIGEST },
@@ -2192,11 +2242,13 @@ lookup(char *s)
                { "interface",          INTERFACE },
                { "interval",           INTERVAL },
                { "ip",                 IP },
+               { "isis",               ISIS },
                { "key",                KEY },
                { "label",              LABEL },
                { "least-states",       LEASTSTATES },
                { "listen",             LISTEN },
                { "loadbalance",        LOADBALANCE },
+               { "local",              LOCAL },
                { "log",                LOG },
                { "lookup",             LOOKUP },
                { "match",              MATCH },
@@ -2205,8 +2257,10 @@ lookup(char *s)
                { "nat",                NAT },
                { "no",                 NO },
                { "nodelay",            NODELAY },
+               { "none",               NONE },
                { "nothing",            NOTHING },
                { "on",                 ON },
+               { "ospf",               OSPF },
                { "params",             PARAMS },
                { "parent",             PARENT },
                { "pass",               PASS },
@@ -2228,6 +2282,7 @@ lookup(char *s)
                { "response",           RESPONSE },
                { "retry",              RETRY },
                { "return",             RETURN },
+               { "rip",                RIP },
                { "roundrobin",         ROUNDROBIN },
                { "route",              ROUTE },
                { "router",             ROUTER },
@@ -2243,6 +2298,7 @@ lookup(char *s)
                { "source-hash",        SRCHASH },
                { "splice",             SPLICE },
                { "ssl",                SSL },
+               { "static",             STATIC },
                { "sticky-address",     STICKYADDR },
                { "style",              STYLE },
                { "table",              TABLE },
Index: pfe_route.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/pfe_route.c,v
retrieving revision 1.9
diff -u -p -r1.9 pfe_route.c
--- pfe_route.c 22 Jan 2015 17:42:09 -0000      1.9
+++ pfe_route.c 14 May 2015 11:30:28 -0000
@@ -21,6 +21,7 @@
 #include <sys/socket.h>
 
 #include <netinet/in.h>
+#include <net/if_dl.h>
 #include <net/route.h>
 #include <arpa/inet.h>
 
@@ -39,13 +40,11 @@ struct relay_rtmsg {
                        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;
 };
@@ -90,7 +89,7 @@ sync_routes(struct relayd *env, struct r
                            rt->rt_conf.name, buf, nr->nr_conf.prefixlen,
                            host->conf.name,
                            HOST_ISUP(host->up) ? "up" : "down",
-                           host->conf.priority);
+                           nr->nr_conf.priority);
 
                        crt.up = host->up;
                        memcpy(&crt.nr, &nr->nr_conf, sizeof(nr->nr_conf));
@@ -106,44 +105,35 @@ sync_routes(struct relayd *env, struct r
 int
 pfe_route(struct relayd *env, struct ctl_netroute *crt)
 {
+       struct iovec                     iov[3];
+       int                              iovcnt = 0;
+
        struct relay_rtmsg               rm;
        struct sockaddr_rtlabel          sr;
+       struct sockaddr_dl               sdl;
        struct sockaddr_storage         *gw;
        struct sockaddr_in              *s4;
        struct sockaddr_in6             *s6;
-       size_t                           len = 0;
+       size_t                           len;
        char                            *gwname;
        int                              i = 0;
 
        gw = &crt->host.ss;
        gwname = crt->host.name;
 
-       bzero(&rm, sizeof(rm));
-       bzero(&sr, sizeof(sr));
+       memset(&rm, 0, sizeof(rm));
 
-       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_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
        rm.rm_hdr.rtm_tableid = crt->rt.rtable;
-       rm.rm_hdr.rtm_priority = crt->host.priority;
-
-       if (strlen(crt->rt.label)) {
-               rm.rm_hdr.rtm_addrs |= RTA_LABEL;
-               sr.sr_len = sizeof(sr);
-               if (snprintf(sr.sr_label, sizeof(sr.sr_label),
-                   "%s", crt->rt.label) == -1)
-                       goto bad;
-       }
-
-       if (crt->nr.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));
+       rm.rm_hdr.rtm_priority = crt->nr.priority;
+       len = sizeof(rm.rm_hdr);
 
+       switch (crt->nr.ss.ss_family) {
+       case AF_INET:
                s4 = &rm.rm_u.u4.rm_dst;
                s4->sin_family = AF_INET;
                s4->sin_len = sizeof(rm.rm_u.u4.rm_dst);
@@ -156,7 +146,6 @@ pfe_route(struct relayd *env, struct ctl
                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->sin_family = AF_INET;
                s4->sin_len = sizeof(rm.rm_u.u4.rm_netmask);
@@ -165,12 +154,11 @@ pfe_route(struct relayd *env, struct ctl
                            htonl(0xffffffff << (32 - crt->nr.prefixlen));
                else if (crt->nr.prefixlen < 0)
                        rm.rm_hdr.rtm_flags |= RTF_HOST;
-       } else if (crt->nr.ss.ss_family == AF_INET6) {
-               rm.rm_hdr.rtm_msglen = len =
-                   sizeof(rm.rm_hdr) + sizeof(rm.rm_u.u6);
 
-               bcopy(&sr, &rm.rm_u.u6.rm_label, sizeof(sr));
+               len += sizeof(rm.rm_u.u4);
+               break;
 
+       case AF_INET6:
                s6 = &rm.rm_u.u6.rm_dst;
                bcopy(((struct sockaddr_in6 *)&crt->nr.ss),
                    s6, sizeof(*s6));
@@ -182,7 +170,6 @@ pfe_route(struct relayd *env, struct ctl
                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->sin6_family = AF_INET6;
                s6->sin6_len = sizeof(*s6);
@@ -195,11 +182,64 @@ pfe_route(struct relayd *env, struct ctl
                                    / 8] = 0xff00 >> i;
                } else if (crt->nr.prefixlen < 0)
                        rm.rm_hdr.rtm_flags |= RTF_HOST;
-       } else
+
+               len += sizeof(rm.rm_u.u6);
+               break;
+
+       default:
                fatal("pfe_route: invalid address family");
+       }
+
+       iov[iovcnt].iov_base = &rm;
+       iov[iovcnt].iov_len = len;
+       iovcnt++;
+
+       if (strlen(crt->nr.ifname)) {
+               i = if_nametoindex(crt->nr.ifname);
+               if (i == 0) {
+                       log_debug("%s: gateway %s: interface %s does not exist",
+                           __func__, gwname, crt->nr.ifname);
+                       return (-1);
+               }
+
+               memset(&sdl, 0, sizeof(sdl));
+
+               sdl.sdl_family = AF_LINK;
+               sdl.sdl_len = sizeof(sdl);
+               sdl.sdl_index = i;
+
+               rm.rm_hdr.rtm_addrs |= RTA_IFP;
+               iov[iovcnt].iov_base = &sdl;
+               iov[iovcnt].iov_len = sizeof(sdl);
+               iovcnt++;
+
+               len += sizeof(sdl);
+       }
+
+       if (strlen(crt->nr.label)) {
+               memset(&sr, 0, sizeof(sr));
+
+               sr.sr_family = AF_UNSPEC;
+               sr.sr_len = sizeof(sr);
+               if (strlcpy(sr.sr_label, crt->nr.label,
+                   sizeof(sr.sr_label)) >= sizeof(sr.sr_label)) {
+                       log_debug("%s: gateway %s: label is too long",
+                           __func__, gwname);
+                       return (-1);
+               }
+
+               rm.rm_hdr.rtm_addrs |= RTA_LABEL;
+               iov[iovcnt].iov_base = &sr;
+               iov[iovcnt].iov_len = sizeof(sr);
+               iovcnt++;
+
+               len += sizeof(sr);
+       }
+
+       rm.rm_hdr.rtm_msglen = len;
 
  retry:
-       if (write(env->sc_rtsock, &rm, len) == -1) {
+       if (writev(env->sc_rtsock, iov, iovcnt) == -1) {
                switch (errno) {
                case EEXIST:
                case ESRCH:
Index: relayd.conf.5
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relayd.conf.5,v
retrieving revision 1.161
diff -u -p -r1.161 relayd.conf.5
--- relayd.conf.5       9 Mar 2015 17:20:38 -0000       1.161
+++ relayd.conf.5       14 May 2015 11:30:28 -0000
@@ -204,12 +204,6 @@ starting with 1; it can be shown with th
 .Xr relayctl 8
 .Ic show summary
 commands.
-.It Ic priority Ar number
-Change the route priority used when adding a route.
-If not specified, the kernel will set a priority of 8 (RTP_STATIC).
-In ordinary use, a fallback route should be added statically with a very
-high (e.g. 52) priority.
-Unused in all other modes.
 .It Ic retry Ar number
 The optional retry option adds a tolerance for failed host checks;
 the check will be retried for
@@ -1384,10 +1378,16 @@ This entry is mandatory and must be spec
 .It Xo
 .Ic route
 .Ar address Ns Li / Ns Ar prefix
+.Op Ic interface Ar name
+.Op Ic priority Ar number
+.Op Ic rtlabel Ar label
 .Xc
 Specify the network address and prefix length of a route destination
 that is reachable via the active gateways.
-This entry must be specified at least once in a router directive.
+An interface, a priority, and a route label can optionally be specified
+for the route.
+.Pp
+At least one route must be specified in a router directive.
 .It Ic rtable Ar id
 Add the routes to the kernel routing table with the specified
 .Ar id .
Index: relayd.h
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relayd.h,v
retrieving revision 1.209
diff -u -p -r1.209 relayd.h
--- relayd.h    2 May 2015 13:15:24 -0000       1.209
+++ relayd.h    14 May 2015 11:30:28 -0000
@@ -398,7 +399,6 @@ struct host_config {
        char                     name[HOST_NAME_MAX+1];
        struct sockaddr_storage  ss;
        int                      ttl;
-       int                      priority;
 };
 
 struct host {
@@ -803,6 +803,9 @@ struct netroute_config {
        objid_t                  id;
        struct sockaddr_storage  ss;
        int                      prefixlen;
+       char                     ifname[IFNAMSIZ];
+       char                     label[RT_LABEL_SIZE];
+       int                      priority;
        objid_t                  routerid;
 };
 
@@ -820,8 +823,6 @@ struct router_config {
        objid_t                  id;
        u_int32_t                flags;
        char                     name[HOST_NAME_MAX+1];
-       char                     label[RT_LABEL_SIZE];
-       int                      nroutes;
        objid_t                  gwtable;
        in_port_t                gwport;
        int                      rtable;
Index: snmp.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/snmp.c,v
retrieving revision 1.23
diff -u -p -r1.23 snmp.c
--- snmp.c      22 Jan 2015 17:42:09 -0000      1.23
+++ snmp.c      14 May 2015 11:30:28 -0000
@@ -1380,8 +1380,7 @@ snmp_router(struct relayd *env, struct s
                break;
        case 5:         /* pf label */
                if (snmp_agentx_varbind(resp, oid,
-                   AGENTX_OCTET_STRING, router->rt_conf.label,
-                   strlen(router->rt_conf.label)) == -1)
+                   AGENTX_OCTET_STRING, "", 0) == -1)
                        return (-1);
                break;
        case 6:         /* rtable */

Reply via email to