Index: relayctl/relayctl.c =================================================================== RCS file: /cvs/src/usr.sbin/relayctl/relayctl.c,v retrieving revision 1.58 diff -u -p -r1.58 relayctl.c --- relayctl/relayctl.c 29 Nov 2017 15:24:50 -0000 1.58 +++ relayctl/relayctl.c 9 Oct 2020 05:59:37 -0000 @@ -424,8 +424,6 @@ show_summary_msg(struct imsg *imsg, int break; if (rt->rt_conf.rtable) printf("\t%8s\trtable: %d\n", "", rt->rt_conf.rtable); - if (strlen(rt->rt_conf.label)) - printf("\t%8s\trtlabel: %s\n", "", rt->rt_conf.label); break; case IMSG_CTL_NETROUTE: if (type != SHOW_ROUTERS) Index: relayd/parse.y =================================================================== RCS file: /cvs/src/usr.sbin/relayd/parse.y,v retrieving revision 1.243 diff -u -p -r1.243 parse.y --- relayd/parse.y 18 Sep 2019 20:27:53 -0000 1.243 +++ relayd/parse.y 9 Oct 2020 05:59:37 -0000 @@ -180,6 +180,7 @@ typedef struct { %token MATCH PARAMS RANDOM LEASTSTATES SRCHASH KEY CERTIFICATE PASSWORD ECDHE %token EDH TICKETS CONNECTION CONNECTIONS ERRORS STATE CHANGES CHECKS %token WEBSOCKETS +%token NONE LOCAL CONNECTED STATIC OSPF ISIS RIP BGP DEFAULT %token STRING %token NUMBER %type hostname interface table value optstring @@ -188,6 +189,7 @@ typedef struct { %type opttls opttlsclient %type redirect_proto relay_proto match %type action ruleaf key_option +%type rtprio %type port %type host %type address rulesrc ruledst addrprefix @@ -2038,8 +2040,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); @@ -2055,11 +2057,11 @@ router : ROUTER STRING { } ; -routeopts_l : routeopts_l routeoptsl nl - | routeoptsl optnl +routeropts_l : routeropts_l routeroptsl nl + | routeroptsl optnl ; -routeoptsl : ROUTE addrprefix { +routeroptsl : ROUTE addrprefix { struct netroute *nr; if (router->rt_conf.af == AF_UNSPEC) @@ -2080,15 +2082,15 @@ routeoptsl : ROUTE addrprefix { YYERROR; } nr->nr_conf.prefixlen = $2.prefixlen; + 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; @@ -2116,18 +2118,74 @@ routeoptsl : ROUTE addrprefix { } 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: %lld\n", $1); + YYERROR; + } + $$ = $1; } - | DISABLE { rlay->rl_conf.flags |= F_DISABLE; } - | include ; dstaf : /* empty */ { @@ -2205,17 +2263,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: %lld\n", $2); - YYERROR; - } - hst->conf.priority = $2; - } | IP TTL NUMBER { if (hst->conf.ttl) { yyerror("ttl value already set"); @@ -2345,6 +2392,7 @@ lookup(char *s) { "append", APPEND }, { "backlog", BACKLOG }, { "backup", BACKUP }, + { "bgp", BGP }, { "binary", BINARY }, { "block", BLOCK }, { "buffer", BUFFER }, @@ -2356,8 +2404,10 @@ lookup(char *s) { "checks", CHECKS }, { "ciphers", CIPHERS }, { "code", CODE }, + { "connected", CONNECTED }, { "connection", CONNECTION }, { "cookie", COOKIE }, + { "default", DEFAULT }, { "demote", DEMOTE }, { "destination", DESTINATION }, { "digest", DIGEST }, @@ -2383,12 +2433,14 @@ lookup(char *s) { "interface", INTERFACE }, { "interval", INTERVAL }, { "ip", IP }, + { "isis", ISIS }, { "key", KEY }, { "keypair", KEYPAIR }, { "label", LABEL }, { "least-states", LEASTSTATES }, { "listen", LISTEN }, { "loadbalance", LOADBALANCE }, + { "local", LOCAL }, { "log", LOG }, { "lookup", LOOKUP }, { "match", MATCH }, @@ -2397,8 +2449,10 @@ lookup(char *s) { "nat", NAT }, { "no", NO }, { "nodelay", NODELAY }, + { "none", NONE }, { "nothing", NOTHING }, { "on", ON }, + { "ospf", OSPF }, { "params", PARAMS }, { "parent", PARENT }, { "pass", PASS }, @@ -2420,6 +2474,7 @@ lookup(char *s) { "response", RESPONSE }, { "retry", RETRY }, { "return", RETURN }, + { "rip", RIP }, { "roundrobin", ROUNDROBIN }, { "route", ROUTE }, { "router", ROUTER }, @@ -2436,6 +2491,7 @@ lookup(char *s) { "splice", SPLICE }, { "ssl", SSL }, { "state", STATE }, + { "static", STATIC }, { "sticky-address", STICKYADDR }, { "style", STYLE }, { "table", TABLE }, Index: relayd/pfe_route.c =================================================================== RCS file: /cvs/src/usr.sbin/relayd/pfe_route.c,v retrieving revision 1.12 diff -u -p -r1.12 pfe_route.c --- relayd/pfe_route.c 28 May 2017 10:39:15 -0000 1.12 +++ relayd/pfe_route.c 9 Oct 2020 05:59:37 -0000 @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -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,8 +105,12 @@ 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; @@ -119,31 +122,19 @@ pfe_route(struct relayd *env, struct ctl gwname = crt->host.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_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 +147,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 +155,10 @@ 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,63 @@ 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("%s: invalid address family", __func__); + } + + 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/relayd.h =================================================================== RCS file: /cvs/src/usr.sbin/relayd/relayd.h,v retrieving revision 1.260 diff -u -p -r1.260 relayd.h --- relayd/relayd.h 15 Sep 2019 19:23:29 -0000 1.260 +++ relayd/relayd.h 9 Oct 2020 05:59:37 -0000 @@ -423,7 +423,6 @@ struct host_config { char name[HOST_NAME_MAX+1]; struct sockaddr_storage ss; int ttl; - int priority; }; struct host { @@ -856,6 +855,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; }; @@ -873,8 +875,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: relayd/snmp.c =================================================================== RCS file: /cvs/src/usr.sbin/relayd/Attic/snmp.c,v retrieving revision 1.30 diff -u -p -r1.30 snmp.c --- relayd/snmp.c 3 Oct 2019 12:03:49 -0000 1.30 +++ relayd/snmp.c 9 Oct 2020 05:59:37 -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 */