On Fri 20/07/2018 07:57, Florian Obser wrote: > On Thu, Jul 19, 2018 at 09:47:06PM +0200, Björn Ketelaars wrote: > > On Wed 18/07/2018 08:54, Florian Obser wrote: > > > During g2k18 I commited rad(8). > > > > > > The latest amd64 and i386 snapshots should contain it with enough > > > features to replace rtadvd(8). If you are using rtadvd(8) I'd > > > appreciate if you could switch to rad(8) and report back if any > > > features are missing. > > > > Florian, > > > > Thank you for rad(8). I like the configuration format, and it seems to > > work for me as replacement for rtadvd(8). For reference purposes: > > > > $ cat /etc/rtadvd.conf > > vlan1003:\ > > :mtu#1480:\ > > :rdnss="2001:470:7ce4:1::1":\ > > :dnssl="guest": > > > > $ cat /etc/rad.conf > > interface vlan1003 { > > dns { > > resolver 2001:470:7ce4:1::1 > > search guest > > } > > } > > > > There is one thing that I'm missing, and that is the MTU option in RA > > messages (RFC 4861 Section 4.6.4). I've baked up a diff which works for > > me. My current rad.conf looks like: > > > > interface vlan1003 { > > dns { > > resolver 2001:470:7ce4:1::1 > > search guest > > } > > > > mtu 1480 > > } > > > > Output "tcpdump -vvvv -ttt -i vlan1003 icmp6 and 'ip6[40] = 134'": > > > > Jul 19 21:26:10.009348 fe80::a562:1f47:a75c:a5fc > ff02::1: icmp6: router > > advertisement(chlim=0, pref=medium, router_ltime=1800, reachable_time=0, > > retrans_time=0)(prefix info: LA valid_ltime=2592000, > > preferred_ltime=604800, prefix=2001:470:7ce4:1::/64)(mtu: mtu=1480)[ndp > > opt] (len 88, hlim 255) > > > > I'm not sure this is an option for rad(8) that is useful for anyone else > > but me. What do you think? Also, what do you think of the diff below? > > I like it, I think we should have it. Out of curiosity, which clients > pay attention to the MTU option? I know that slaacd does not. If you > are sufficiently bored you might want to implement it there, too! ;) > (hint: you will need to add to the wroute pledge in the kernel) > > Diff reads mostly ok but needs a few tweaks, see inline: > > > > > > > diff --git engine.c engine.c > > index 5d186439dd8..4ade634a689 100644 > > --- engine.c > > +++ engine.c > > @@ -355,6 +355,9 @@ engine_dispatch_main(int fd, short event, void *bula) > > SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_prefix_list, > > ra_prefix_conf, entry); > > break; > > + case IMSG_RECONF_RA_MTU: > > + ra_iface_conf->ra_mtu = *((uint32_t *)imsg.data); > > + break; > > no need for the extra IMSG, ra_mtu is not a substructure in > ra_iface_conf, it will be copied with the rest of the ra_iface_conf in > IMSG_RECONF_RA_IFACE > > > case IMSG_RECONF_RA_RDNS_LIFETIME: > > ra_iface_conf->rdns_lifetime = *((uint32_t *)imsg.data); > > break; > > diff --git frontend.c frontend.c > > index b06fa43038c..06c4cc5cb2b 100644 > > --- frontend.c > > +++ frontend.c > > @@ -397,6 +397,9 @@ frontend_dispatch_main(int fd, short event, void *bula) > > SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_prefix_list, > > ra_prefix_conf, entry); > > break; > > + case IMSG_RECONF_RA_MTU: > > + ra_iface_conf->ra_mtu = *((uint32_t *)imsg.data); > > + break; > > same here > > > case IMSG_RECONF_RA_RDNS_LIFETIME: > > ra_iface_conf->rdns_lifetime = *((uint32_t *)imsg.data); > > break; > > @@ -888,6 +891,7 @@ build_packet(struct ra_iface *ra_iface) > > { > > struct nd_router_advert *ra; > > struct nd_opt_prefix_info *ndopt_pi; > > + struct nd_opt_mtu *ndopt_mtu; > > struct ra_iface_conf *ra_iface_conf; > > struct ra_options_conf *ra_options_conf; > > struct ra_prefix_conf *ra_prefix_conf; > > @@ -960,6 +964,15 @@ build_packet(struct ra_iface *ra_iface) > > p += sizeof(*ndopt_pi); > > } > > > > + if (ra_iface_conf->ra_mtu > 0) { > > + ndopt_mtu = (struct nd_opt_mtu *)p; > > + ndopt_mtu->nd_opt_mtu_type = ND_OPT_MTU; > > + ndopt_mtu->nd_opt_mtu_len = 1; > > + ndopt_mtu->nd_opt_mtu_reserved = 0; > > + ndopt_mtu->nd_opt_mtu_mtu = htonl(ra_iface_conf->ra_mtu); > > + p += sizeof(*ndopt_mtu); > > + } > > + > > you need to account for the length of the mtu option, see the beginning > of build_packet(), something like > > if (ra_iface_conf->ra_mtu > 0) > len += sizeof(*ndopt_mtu); > > > if (ra_iface_conf->rdnss_count > 0) { > > ndopt_rdnss = (struct nd_opt_rdnss *)p; > > ndopt_rdnss->nd_opt_rdnss_type = ND_OPT_RDNSS; > > diff --git parse.y parse.y > > index 582d165c7d6..9696ac58213 100644 > > --- parse.y > > +++ parse.y > > @@ -115,7 +115,7 @@ typedef struct { > > %token DEFAULT ROUTER HOP LIMIT MANAGED ADDRESS > > %token CONFIGURATION OTHER LIFETIME REACHABLE TIME RETRANS TIMER > > %token AUTO PREFIX VALID PREFERRED LIFETIME ONLINK AUTONOMOUS > > -%token ADDRESS_CONFIGURATION DNS RESOLVER SEARCH > > +%token ADDRESS_CONFIGURATION DNS RESOLVER SEARCH MTU > > > > %token <v.string> STRING > > %token <v.number> NUMBER > > @@ -265,6 +265,9 @@ ra_ifaceoptsl : NO AUTO PREFIX { > > } ra_prefix_block { > > ra_prefix_conf = NULL; > > } > > + | MTU NUMBER { > > + ra_iface_conf->ra_mtu = $2; > > + } > > | DNS dns_block > > | ra_opt_block > > ; > > @@ -423,6 +426,7 @@ lookup(char *s) > > {"lifetime", LIFETIME}, > > {"limit", LIMIT}, > > {"managed", MANAGED}, > > + {"mtu", MTU}, > > {"no", NO}, > > {"on-link", ONLINK}, > > {"other", OTHER}, > > @@ -958,6 +962,8 @@ conf_get_ra_iface(char *name) > > /* Inherit attributes set in global section. */ > > iface->ra_options = conf->ra_options; > > > > + iface->ra_mtu = DEFAULT_MTU; > > + > > no need, 0 is the default since it's calloc'ed > > > iface->rdns_lifetime = DEFAULT_RDNS_LIFETIME; > > > > SIMPLEQ_INIT(&iface->ra_prefix_list); > > diff --git printconf.c printconf.c > > index 1fc8cd4ca3f..0285bdb75be 100644 > > --- printconf.c > > +++ printconf.c > > @@ -99,6 +99,9 @@ print_config(struct rad_conf *conf) > > printf("\t}\n"); > > } > > > > + if (iface->ra_mtu > 0) > > + printf("\tmtu %u\n", iface->ra_mtu); > > + > > if (!SIMPLEQ_EMPTY(&iface->ra_rdnss_list) || > > !SIMPLEQ_EMPTY(&iface->ra_dnssl_list)) { > > printf("\tdns {\n"); > > diff --git rad.c rad.c > > index 4652e1e0fb7..cdaf529d806 100644 > > --- rad.c > > +++ rad.c > > @@ -622,6 +622,9 @@ main_imsg_send_config(struct rad_conf *xconf) > > ra_prefix_conf, sizeof(*ra_prefix_conf)) == -1) > > return (-1); > > } > > + if (main_sendboth(IMSG_RECONF_RA_MTU, &ra_iface_conf->ra_mtu, > > + sizeof(ra_iface_conf->ra_mtu)) == -1) > > + return (-1); > > no need > > > if (main_sendboth(IMSG_RECONF_RA_RDNS_LIFETIME, > > &ra_iface_conf->rdns_lifetime, > > sizeof(ra_iface_conf->rdns_lifetime)) == -1) > > diff --git rad.conf.5 rad.conf.5 > > index 6ca6b3ef956..6165e74070d 100644 > > --- rad.conf.5 > > +++ rad.conf.5 > > @@ -126,6 +126,14 @@ prefix. > > The default is 2592000. > > .El > > .Pp > > +A maximum transmission unit (MTU) field can be advertised by configuring it > > +in an interface block: > > +.Bl -tag -width Ds > > +.It Ic mtu Ar bytes > > +MTU in bytes. If 0 is specified the option will not be included. > > +The default is 0. > > +.El > > +.Pp > > Recursive resolvers are configured inside an interface block: > > .Bd -unfilled -offset indent > > .Ic dns Brq dns options > > diff --git rad.h rad.h > > index db80d7c772d..8d919303723 100644 > > --- rad.h > > +++ rad.h > > @@ -26,6 +26,7 @@ > > #define OPT_VERBOSE2 0x00000002 > > #define OPT_NOACTION 0x00000004 > > > > +#define DEFAULT_MTU 0 > > no need > > > > > #define MAX_RTR_ADV_INTERVAL 600 > > #define MIN_RTR_ADV_INTERVAL 200 > > @@ -59,6 +60,7 @@ enum imsg_type { > > IMSG_RECONF_RA_IFACE, > > IMSG_RECONF_RA_AUTOPREFIX, > > IMSG_RECONF_RA_PREFIX, > > + IMSG_RECONF_RA_MTU, > > IMSG_RECONF_RA_RDNS_LIFETIME, > > IMSG_RECONF_RA_RDNSS, > > IMSG_RECONF_RA_DNSSL, > > @@ -114,6 +116,7 @@ struct ra_iface_conf { > > struct ra_prefix_conf *autoprefix; > > SIMPLEQ_HEAD(ra_prefix_conf_head, > > ra_prefix_conf) ra_prefix_list; > > + uint32_t ra_mtu; > > uint32_t rdns_lifetime; > > SIMPLEQ_HEAD(, ra_rdnss_conf) ra_rdnss_list; > > int rdnss_count; > > After reading the diff a 2nd time I think I'd prefer to have the mtu > in ra_options, as a potential global setting. After all, if you need > to set the mtu on one interface you probably have to set it on all. > > We then also need a ``no mtu'' in the parser, but that's easy enough.
New diff, which addresses all your comments except the "no mtu" bit in the parser as I do not understand what you mean. diff --git frontend.c frontend.c index b06fa43038c..0509d2b3efe 100644 --- frontend.c +++ frontend.c @@ -887,6 +887,7 @@ void build_packet(struct ra_iface *ra_iface) { struct nd_router_advert *ra; + struct nd_opt_mtu *ndopt_mtu; struct nd_opt_prefix_info *ndopt_pi; struct ra_iface_conf *ra_iface_conf; struct ra_options_conf *ra_options_conf; @@ -904,6 +905,8 @@ build_packet(struct ra_iface *ra_iface) ra_options_conf = &ra_iface_conf->ra_options; len = sizeof(*ra); + if (ra_options_conf->mtu > 0) + len += sizeof(*ndopt_mtu); len += sizeof(*ndopt_pi) * ra_iface->prefix_count; if (ra_iface_conf->rdnss_count > 0) len += sizeof(*ndopt_rdnss) + ra_iface_conf->rdnss_count * @@ -940,6 +943,15 @@ build_packet(struct ra_iface *ra_iface) ra->nd_ra_retransmit = htonl(ra_options_conf->retrans_timer); p += sizeof(*ra); + if (ra_options_conf->mtu > 0) { + ndopt_mtu = (struct nd_opt_mtu *)p; + ndopt_mtu->nd_opt_mtu_type = ND_OPT_MTU; + ndopt_mtu->nd_opt_mtu_len = 1; + ndopt_mtu->nd_opt_mtu_reserved = 0; + ndopt_mtu->nd_opt_mtu_mtu = htonl(ra_options_conf->mtu); + p += sizeof(*ndopt_mtu); + } + SIMPLEQ_FOREACH(ra_prefix_conf, &ra_iface->prefixes, entry) { ndopt_pi = (struct nd_opt_prefix_info *)p; memset(ndopt_pi, 0, sizeof(*ndopt_pi)); diff --git parse.y parse.y index 582d165c7d6..6eb6990f97b 100644 --- parse.y +++ parse.y @@ -115,7 +115,7 @@ typedef struct { %token DEFAULT ROUTER HOP LIMIT MANAGED ADDRESS %token CONFIGURATION OTHER LIFETIME REACHABLE TIME RETRANS TIMER %token AUTO PREFIX VALID PREFERRED LIFETIME ONLINK AUTONOMOUS -%token ADDRESS_CONFIGURATION DNS RESOLVER SEARCH +%token ADDRESS_CONFIGURATION DNS RESOLVER SEARCH MTU %token <v.string> STRING %token <v.number> NUMBER @@ -209,6 +209,9 @@ ra_opt_block : DEFAULT ROUTER yesno { | RETRANS TIMER NUMBER { ra_options->retrans_timer = $3; } + | MTU NUMBER { + ra_options->mtu = $2; + } ; optnl : '\n' optnl /* zero or more newlines */ @@ -423,6 +426,7 @@ lookup(char *s) {"lifetime", LIFETIME}, {"limit", LIMIT}, {"managed", MANAGED}, + {"mtu", MTU}, {"no", NO}, {"on-link", ONLINK}, {"other", OTHER}, diff --git printconf.c printconf.c index 1fc8cd4ca3f..b7864dbae6b 100644 --- printconf.c +++ printconf.c @@ -54,6 +54,7 @@ print_ra_options(const char *indent, const struct ra_options_conf *ra_options) printf("%srouter lifetime %d\n", indent, ra_options->router_lifetime); printf("%sreachable time %u\n", indent, ra_options->reachable_time); printf("%sretrans timer %u\n", indent, ra_options->retrans_timer); + printf("%smtu %u\n", indent, ra_options->mtu); } void diff --git rad.c rad.c index 4652e1e0fb7..9f4be1b2190 100644 --- rad.c +++ rad.c @@ -716,6 +716,7 @@ config_new_empty(void) xconf->ra_options.router_lifetime = 1800; xconf->ra_options.reachable_time = 0; xconf->ra_options.retrans_timer = 0; + xconf->ra_options.mtu = 0; return (xconf); } diff --git rad.conf.5 rad.conf.5 index 6ca6b3ef956..486bec24769 100644 --- rad.conf.5 +++ rad.conf.5 @@ -87,6 +87,11 @@ The default is 1800 seconds. .\" XXX .\" .It Ic retrans timer Ar number .\" XXX +.It Ic mtu Ar bytes +The MTU option is used in Router Advertisement messages to ensure that all +nodes on a link use the same MTU value in those cases where the link MTU +is not well known. +The default is 0, meaning unspecified by this router. .El .Sh INTERFACES A list of interfaces to send advertisments on: diff --git rad.h rad.h index db80d7c772d..f9d26d66c9c 100644 --- rad.h +++ rad.h @@ -76,7 +76,7 @@ enum imsg_type { IMSG_SOCKET_IPC }; -/* RFC 4861 Section 4.2 */ +/* RFC 4861 Sections 4.2 and 4.6.4 */ struct ra_options_conf { int dfr; /* is default router? */ int cur_hl; /* current hop limit */ @@ -85,6 +85,7 @@ struct ra_options_conf { int router_lifetime; /* default router lifetime */ uint32_t reachable_time; uint32_t retrans_timer; + uint32_t mtu; }; /* RFC 4861 Section 4.6.2 */