On Tue, Aug 7, 2018 at 5:49 AM, Charles Myers <[email protected]> wrote:
> Signed-off-by: Charles Myers <[email protected]> > --- > bsd/porting/networking.cc | 178 ++++++++++++++++++++++++++++++ > +++++++++++++++- > bsd/porting/networking.hh | 8 +++ > bsd/porting/route.cc | 86 ++++++++++++++++++---- > bsd/sys/netinet/in.cc | 10 +++ > bsd/sys/netinet/in.h | 1 + > loader.cc | 76 +++++++++++++++----- > 6 files changed, 327 insertions(+), 32 deletions(-) > > diff --git a/bsd/porting/networking.cc b/bsd/porting/networking.cc > index 016106c..e2767a7 100644 > --- a/bsd/porting/networking.cc > +++ b/bsd/porting/networking.cc > @@ -17,6 +17,15 @@ > #include <bsd/sys/net/route.h> > #include <bsd/sys/netinet/in.h> > #include <bsd/sys/netinet/in_var.h> > +#ifdef INET6 > +#include <bsd/sys/netinet6/in6.h> > +#include <bsd/sys/netinet6/in6_var.h> > +#include <bsd/sys/netinet6/nd6.h> > +#include <bsd/sys/netinet6/ip6_var.h> > + > +// FIXME: inet_pton() is from musl which uses different AF_INET6 > +#define LINUX_AF_INET6 10 > We already have this exact #define in bsd/sys/compat/linux/linux_socket.h, can we include that instead? I think you should remove the "FIXME" - this is the correct behavior of inet_pton and other User-facing functions, which take the Linux versions of the ABI - and unfortunately while in Linux and BSD AF_INET is the same, AF_INET6 is not :-( Instead of a "FIXME" here you can explain at the point you use LINUX_AF_INET6 below, why you use it. > +#endif // INET6 > #include <bsd/sys/sys/socket.h> > #include <bsd/sys/sys/socketvar.h> > > @@ -61,6 +70,18 @@ int if_set_mtu(std::string if_name, u16 mtu) > > int start_if(std::string if_name, std::string ip_addr, std::string > mask_addr) > { > + return if_add_addr(if_name, ip_addr, mask_addr); > +} > + > +int stop_if(std::string if_name, std::string ip_addr) > +{ > + std::string mask_addr; > If you intend to use an empty string, you can (I think) also just use "" below, and don't need to name it (but you can, if you want...). > + > + return if_del_addr(if_name, ip_addr, mask_addr); > +} > + > +int if_add_ipv4_addr(std::string if_name, std::string ip_addr, > std::string mask_addr) > +{ > int error, success; > struct bsd_ifreq oldaddr; > struct in_aliasreq ifra; > @@ -99,7 +120,9 @@ int start_if(std::string if_name, std::string ip_addr, > std::string mask_addr) > error = EINVAL; > goto out; > } > + mask->sin_family = AF_INET; > mask->sin_len = sizeof(struct bsd_sockaddr_in); > + > broadcast->sin_family = AF_INET; > broadcast->sin_len = sizeof(struct bsd_sockaddr_in); > broadcast->sin_addr.s_addr = (addr->sin_addr.s_addr & > @@ -117,7 +140,7 @@ out: > return (error); > } > > -int stop_if(std::string if_name, std::string ip_addr) > +int if_del_ipv4_addr(std::string if_name, std::string ip_addr) > { > int error, success; > struct in_aliasreq ifra; > @@ -155,6 +178,157 @@ out: > return (error); > } > > +#ifdef INET6 > + > +int if_add_ipv6_addr(std::string if_name, std::string ip_addr, > std::string netmask) > +{ > + int error, success; > + struct in6_ifreq oldaddr; > + struct in6_aliasreq ifra; > + struct bsd_sockaddr_in6* addr = &ifra.ifra_addr; > + struct bsd_sockaddr_in6* mask = &ifra.ifra_prefixmask; > + //struct bsd_sockaddr_in6* dst = &ifra.ifra_dstaddr; > + struct ifnet* ifp; > + > + if (if_name.empty() || ip_addr.empty() || netmask.empty()) { > + return (EINVAL); > + } > + > + bzero(&ifra, sizeof(struct in6_aliasreq)); > + ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; > + ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; > + > + /* IF Name */ > + strncpy(ifra.ifra_name, if_name.c_str(), IFNAMSIZ); > + ifp = ifunit_ref(if_name.c_str()); > + if (!ifp) { > + return (ENOENT); > + } > + > + /* IP Address */ > + if ((success = inet_pton(LINUX_AF_INET6, ip_addr.c_str(), > &addr->sin6_addr)) != 1) { > Maybe the comment about the peculiar AF parameter of inet_pton belongs here, not about (but as a comment, not a FIXME) + bsd_log(ERR, "Failed converting IPv6 address %s\n", > ip_addr.c_str()); > + error = EINVAL; > + goto out; > + } > + addr->sin6_family = AF_INET6; > + addr->sin6_len = sizeof(struct bsd_sockaddr_in6); > + > + /* Mask */ > + if (inet_pton(LINUX_AF_INET6, netmask.c_str(), &mask->sin6_addr) != > 1) { > + /* Interpret it as a prefix length */ > + long prefix_len = strtol(netmask.c_str(), NULL, 0); > + if (prefix_len < 0 || prefix_len > 128) { > + error = EINVAL; > + goto out; > + } > + in6_prefixlen2mask(&mask->sin6_addr, prefix_len); > + } > + mask->sin6_family = AF_INET6; > + mask->sin6_len = sizeof(struct bsd_sockaddr_in6); > + > + strncpy(oldaddr.ifr_name, if_name.c_str(), IFNAMSIZ); > + error = in6_control(NULL, SIOCGIFADDR_IN6, (caddr_t)&oldaddr, ifp, > NULL); > + if (!error) { > + in6_control(NULL, SIOCDIFADDR_IN6, (caddr_t)&oldaddr, ifp, NULL); > + } > + error = in6_control(NULL, SIOCAIFADDR_IN6, (caddr_t)&ifra, ifp, NULL); > + > +out: > + if_rele(ifp); > + return (error); > +} > + > +int if_del_ipv6_addr(std::string if_name, std::string ip_addr, > std::string netmask) > +{ > + int error, success; > + struct in6_aliasreq ifra; > + struct bsd_sockaddr_in6* addr = &ifra.ifra_addr; > + struct bsd_sockaddr_in6* mask = &ifra.ifra_prefixmask; > + struct ifnet* ifp; > + > + if (if_name.empty() || ip_addr.empty() || netmask.empty()) > + return (EINVAL); > + > + bzero(&ifra, sizeof(struct in6_aliasreq)); > + > + /* IF Name */ > + strncpy(ifra.ifra_name, if_name.c_str(), IFNAMSIZ); > + ifp = ifunit_ref(if_name.c_str()); > + if (!ifp) { > + return (ENOENT); > + } > + > + /* IP Address */ > + if ((success = inet_pton(LINUX_AF_INET6, ip_addr.c_str(), > &addr->sin6_addr)) != 1) { > + bsd_log(ERR, "Failed converting IPv6 address %s\n", > ip_addr.c_str()); > + error = EINVAL; > + goto out; > + } > + addr->sin6_family = AF_INET6; > + addr->sin6_len = sizeof(struct bsd_sockaddr_in6); > + > + /* Mask */ > + if (inet_pton(LINUX_AF_INET6, netmask.c_str(), &mask->sin6_addr) != > 1) { > + /* Interpret it as a prefix length */ > + long prefix_len = strtol(netmask.c_str(), NULL, 0); > + if (prefix_len < 0 || prefix_len > 128) { > + error = EINVAL; > + goto out; > + } > + in6_prefixlen2mask(&mask->sin6_addr, prefix_len); > + } > + mask->sin6_family = AF_INET6; > + mask->sin6_len = sizeof(struct bsd_sockaddr_in6); > + > + error = in6_control(NULL, SIOCDIFADDR_IN6, (caddr_t)&ifra, ifp, NULL); > + > +out: > + if_rele(ifp); > + return (error); > +} > + > +int set_ipv6_accept_rtadv(bool enable) > +{ > + V_ip6_accept_rtadv = enable ? 1 : 0; > + return 0; > +} > + > +bool get_ipv6_accept_rtadv(void) > +{ > + return (V_ip6_accept_rtadv != 0); > +} > + > +#endif // INET6 > + > +int if_add_addr(std::string if_name, std::string ip_addr, std::string > mask_addr) > +{ > + struct in_addr v4; > + if (inet_pton(AF_INET, ip_addr.c_str(), &v4)) { > This is also supposed to be LINUX_AF_INET, but it's the same :-) + return if_add_ipv4_addr(if_name, ip_addr, mask_addr); > + } > +#ifdef INET6 > + else { > + return if_add_ipv6_addr(if_name, ip_addr, mask_addr); > + } > +#endif > + return EINVAL; > +} > + > +int if_del_addr(std::string if_name, std::string ip_addr, std::string > mask_addr) > +{ > + struct in_addr v4; > + if (inet_pton(AF_INET, ip_addr.c_str(), &v4)) { > + return if_del_ipv4_addr(if_name, ip_addr); > + } > +#ifdef INET6 > + else { > + return if_del_ipv6_addr(if_name, ip_addr, mask_addr); > + } > +#endif > + return EINVAL; > +} > + > int ifup(std::string if_name) > { > int error; > @@ -194,4 +368,6 @@ std::string if_ip(std::string if_name) { > } > return inet_ntoa(((bsd_sockaddr_in*)&(addr.ifr_addr))->sin_addr); > } > + > + > } > diff --git a/bsd/porting/networking.hh b/bsd/porting/networking.hh > index 8d06fe2..e25cb00 100644 > --- a/bsd/porting/networking.hh > +++ b/bsd/porting/networking.hh > @@ -22,6 +22,14 @@ namespace osv { > int stop_if(std::string if_name, std::string ip_addr); > int ifup(std::string if_name); > std::string if_ip(std::string if_name); > + > + int if_add_addr(std::string if_name, std::string ip_addr, std::string > netmask); > + int if_del_addr(std::string if_name, std::string ip_addr, std::string > netmask); > + > +#ifdef INET6 > + int set_ipv6_accept_rtadv(bool enable); > + bool get_ipv6_accept_rtadv(void); > +#endif > } > > #endif /* __NETWORKING_H__ */ > diff --git a/bsd/porting/route.cc b/bsd/porting/route.cc > index b1f9d50..794a0a5 100644 > --- a/bsd/porting/route.cc > +++ b/bsd/porting/route.cc > @@ -41,6 +41,10 @@ > #include <bsd/sys/sys/socket.h> > #include <bsd/sys/sys/socketvar.h> > #include <bsd/sys/sys/sysctl.h> > +#ifdef INET6 > +#include <bsd/sys/netinet6/in6.h> > +#include <bsd/sys/netinet6/in6_var.h> > +#endif > > int sysctl_rtsock(SYSCTL_HANDLER_ARGS) ; > > @@ -172,6 +176,59 @@ static struct mbuf* osv_route_arp_rtmsg(int if_idx, > int cmd, const char* ip, > return (m); > } > > +static int osv_sockaddr_from_string(struct bsd_sockaddr_storage *addr, > const char *str) > +{ > + struct bsd_sockaddr_in *sa4 = (struct bsd_sockaddr_in*)addr; > + if (inet_pton(AF_INET, str, (void*)&sa4->sin_addr)) { > + sa4->sin_len = sizeof(*sa4); > + sa4->sin_family = AF_INET; > + sa4->sin_port = 0; > + return 1; > + } > +#ifdef INET6 > + struct bsd_sockaddr_in6 *sa6 = (struct bsd_sockaddr_in6*)addr; > + if (inet_pton(AF_INET6, str, (void*)&sa6->sin6_addr)) { > + sa6->sin6_len = sizeof(*sa6); > + sa6->sin6_family = AF_INET6; > + sa6->sin6_port = 0; > + sa6->sin6_flowinfo = 0; > + sa6->sin6_scope_id = 0; > + return 1; > + } > +#endif > + return 0; > +} > + > +static int osv_sockaddr_from_prefix_len(int af, struct > bsd_sockaddr_storage *addr, int prefix_len) > +{ > + switch(af){ > + case AF_INET: > + { > + struct bsd_sockaddr_in *sa4 = (struct bsd_sockaddr_in *)addr; > + sa4->sin_len = sizeof(*sa4); > + sa4->sin_family = AF_INET; > + sa4->sin_port = 0; > + in_prefixlen2mask(&sa4->sin_addr, prefix_len); > + } > + return 1; > +#ifdef INET6 > + case AF_INET6: > + { > + struct bsd_sockaddr_in6 *sa6 = (struct bsd_sockaddr_in6 > *)addr; > + sa6->sin6_len = sizeof(*sa6); > + sa6->sin6_family = AF_INET6; > + sa6->sin6_port = 0; > + sa6->sin6_flowinfo = 0; > + sa6->sin6_scope_id = 0; > + in6_prefixlen2mask(&sa6->sin6_addr, prefix_len); > + } > + return 1; > +#endif > + default: > + return 0; > + } > +} > + > /* Compose a routing message to be sent on socket */ > static struct mbuf* osv_route_rtmsg(int cmd, const char* destination, > const char* gateway, const char* netmask, int flags, gw_type type) > @@ -185,10 +242,10 @@ static struct mbuf* osv_route_rtmsg(int cmd, const > char* destination, > struct bsd_ifaddr *ifa; > bool is_link = type == gw_type::link; > > - /* IPv4: Addresses */ > - struct bsd_sockaddr_in dst; > - struct bsd_sockaddr_in gw; > - struct bsd_sockaddr_in mask; > + /* IP: Addresses */ > + struct bsd_sockaddr_storage dst; > + struct bsd_sockaddr_storage gw; > + struct bsd_sockaddr_storage mask; > > /* Link: Address*/ > struct bsd_sockaddr_dl sdl; > @@ -215,9 +272,7 @@ static struct mbuf* osv_route_rtmsg(int cmd, const > char* destination, > bzero(&sdl, sizeof(sdl)); > bzero(&mask, sizeof(mask)); > > - dst.sin_family = AF_INET; > - dst.sin_len = sizeof(struct bsd_sockaddr_in); > - inet_aton(destination, &dst.sin_addr); > + osv_sockaddr_from_string(&dst, destination); > > if (is_link) { > /* Get ifindex from name */ > @@ -234,15 +289,20 @@ static struct mbuf* osv_route_rtmsg(int cmd, const > char* destination, > memcpy(ea, IF_LLADDR(ifp), ETHER_ADDR_LEN); > if_rele(ifp); > } else { > - gw.sin_family = AF_INET; > - gw.sin_len = sizeof(struct bsd_sockaddr_in); > - inet_aton(gateway, &gw.sin_addr); > + osv_sockaddr_from_string(&gw, gateway); > } > > if (netmask) { > - mask.sin_family = AF_INET; > - mask.sin_len = sizeof(struct bsd_sockaddr_in); > - inet_aton(netmask, &mask.sin_addr); > + if (osv_sockaddr_from_string(&mask, netmask) == 0) { > + // Try parsing it as a prefix length > + char *p_end = NULL; > + long prefix_len = strtol(netmask, &p_end, 0); > + if (p_end == netmask) { > + // Bad netmask string. Probably safer to treat it as a > host route. > + prefix_len = (((struct bsd_sockaddr *)&dst)->sa_family > == AF_INET6) ? 128 : 32; > + } > + osv_sockaddr_from_prefix_len(((struct bsd_sockaddr > *)&dst)->sa_family, &mask, prefix_len); > + } > } > > /* > diff --git a/bsd/sys/netinet/in.cc b/bsd/sys/netinet/in.cc > index f7c1934..c0c37cd 100644 > --- a/bsd/sys/netinet/in.cc > +++ b/bsd/sys/netinet/in.cc > @@ -1673,3 +1673,13 @@ in_domifdetach(struct ifnet *ifp, void *aux) > lltable_free(ii->ii_llt); > free(ii); > } > + > +void > +in_prefixlen2mask(struct in_addr *maskp, int plen) > +{ > + if (plen == 0) > + maskp->s_addr = 0; > + else > + maskp->s_addr = htonl(0xffffffff << (32 - plen)); > +} > + > diff --git a/bsd/sys/netinet/in.h b/bsd/sys/netinet/in.h > index 43291b7..672e613 100644 > --- a/bsd/sys/netinet/in.h > +++ b/bsd/sys/netinet/in.h > @@ -470,6 +470,7 @@ const char *inet_ntoa_r(struct in_addr ina, char *buf, > socklen_t); /* in libkern > const char *inet_ntop(int, const void *, char *, socklen_t); /* in > libkern */ > int inet_pton(int af, const char *, void *); /* in libkern */ > void in_ifdetach(struct ifnet *); > +void in_prefixlen2mask(struct in_addr *maskp, int plen); > __END_DECLS > > #define in_hosteq(s, t) ((s).s_addr == (t).s_addr) > diff --git a/loader.cc b/loader.cc > index 3f88ebd..5e04c83 100644 > --- a/loader.cc > +++ b/loader.cc > @@ -5,6 +5,8 @@ > * BSD license as described in the LICENSE file in the top-level > directory. > */ > > +#include <bsd/porting/netport.h> > + > #include "fs/fs.hh" > #include <bsd/init.hh> > #include <bsd/net.hh> > @@ -137,8 +139,8 @@ static bool opt_verbose = false; > static std::string opt_chdir; > static bool opt_bootchart = false; > static std::vector<std::string> opt_ip; > -static std::string opt_defaultgw; > -static std::string opt_nameserver; > +static std::vector<std::string> opt_defaultgw; > +static std::vector<std::string> opt_nameserver; > static std::string opt_redirect; > static std::chrono::nanoseconds boot_delay; > bool opt_assign_net = false; > @@ -177,8 +179,8 @@ void parse_options(int loader_argc, char** loader_argv) > ("cwd", bpo::value<std::vector<std::string>>(), "set current > working directory") > ("bootchart", "perform a test boot measuring a time distribution > of the various operations\n") > ("ip", bpo::value<std::vector<std::string>>(), "set static IP on > NIC") > - ("defaultgw", bpo::value<std::string>(), "set default gateway > address") > - ("nameserver", bpo::value<std::string>(), "set nameserver > address") > + ("defaultgw", bpo::value<std::vector<std::string>>(), "set > default gateway address") > + ("nameserver", bpo::value<std::vector<std::string>>(), "set > nameserver address") > ("delay", bpo::value<float>()->default_value(0), "delay in seconds > before boot") > ("redirect", bpo::value<std::string>(), "redirect stdout and > stderr to file") > ("disable_rofs_cache", "disable ROFS memory cache") > @@ -287,11 +289,11 @@ void parse_options(int loader_argc, char** > loader_argv) > } > > if (vars.count("defaultgw")) { > - opt_defaultgw = vars["defaultgw"].as<std::string>(); > + opt_defaultgw = vars["defaultgw"].as<std::vector<std::string>>(); > } > > if (vars.count("nameserver")) { > - opt_nameserver = vars["nameserver"].as<std::string>(); > + opt_nameserver = vars["nameserver"].as<std:: > vector<std::string>>(); > } > > if (vars.count("redirect")) { > @@ -365,40 +367,77 @@ void* do_main_thread(void *_main_args) > } > } > > +#ifdef INET6 > + // Enable IPv6 StateLess Address AutoConfiguration (SLAAC) > + osv::set_ipv6_accept_rtadv(true); > +#endif > + > bool has_if = false; > osv::for_each_if([&has_if] (std::string if_name) { > if (if_name == "lo0") > return; > > has_if = true; > - // Start DHCP by default and wait for an IP > - if (osv::start_if(if_name, "0.0.0.0", "255.255.255.0") != 0 || > - osv::ifup(if_name) != 0) > + > + if (osv::ifup(if_name) != 0) > debug("Could not initialize network interface.\n"); > + > + if (opt_ip.size() == 0) { > + // Start DHCP by default and wait for an IP > + if (osv::if_add_addr(if_name, "0.0.0.0", "255.255.255.0") != > 0) > + debug("Could not add 0.0.0.0 IP to interface.\n"); > + } > }); > if (has_if) { > if (opt_ip.size() == 0) { > dhcp_start(true); > } else { > + // Add interface IP addresses > for (auto t : opt_ip) { > std::vector<std::string> tmp; > - boost::split(tmp, t, boost::is_any_of(" ,"), > boost::token_compress_on); > + boost::split(tmp, t, boost::is_any_of(" ,/"), > boost::token_compress_on); > if (tmp.size() != 3) > abort("incorrect parameter on --ip"); > > - printf("%s: %s\n",tmp[0].c_str(),tmp[1].c_str()); > + printf("%s: %s %s\n",tmp[0].c_str(),tmp[1].c_str(), > tmp[2].c_str()); > > - if (osv::start_if(tmp[0], tmp[1], tmp[2]) != 0) > - debug("Could not initialize network interface.\n"); > + if (osv::if_add_addr(tmp[0], tmp[1], tmp[2]) != 0) > + debug("Could not add IP address to interface.\n"); > } > + // Add default gateway routes > + // One default route is allowed for IPv4 and one for IPv6 > if (opt_defaultgw.size() != 0) { > - osv_route_add_network("0.0.0.0", > - "0.0.0.0", > - opt_defaultgw.c_str()); > + bool has_defaultgw_v4=false, has_defaultgw_v6=false; > + for (auto t : opt_defaultgw) { > + auto addr = boost::asio::ip::address::from_string(t); > + if (addr.is_v4()) { > + if (!has_defaultgw_v4) { > + osv_route_add_network("0.0.0.0", > + "0.0.0.0", > + t.c_str()); > + has_defaultgw_v4 = true; > + } > + } > + else { > + if (!has_defaultgw_v6) { > + osv_route_add_network("::", > + "::", > + t.c_str()); > + has_defaultgw_v6 = true; > + } > + } > + } > } > + // Add nameserver addresses > if (opt_nameserver.size() != 0) { > - auto addr = boost::asio::ip::address_v4:: > from_string(opt_nameserver); > - osv::set_dns_config({addr}, std::vector<std::string>()); > + std::vector<boost::asio::ip::address> dns_servers; > + for (auto t : opt_nameserver) { > + auto addr = boost::asio::ip::address::from_string(t); > + dns_servers.push_back(addr); > + } > + if (!dns_servers.empty()) { > + osv::set_dns_config(dns_servers, > std::vector<std::string>()); > + } > } > } > } > @@ -465,6 +504,7 @@ void* do_main_thread(void *_main_args) > for (int i = 0; i < count; i++) { > if (!strcmp(".", namelist[i]->d_name) || > !strcmp("..", namelist[i]->d_name)) { > + free(namelist[i]); > Not related to this patch, but looks correct :-) continue; > } > std::string fn("/init/"); > -- > 2.7.4 > > -- > You received this message because you are subscribed to the Google Groups > "OSv Development" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > For more options, visit https://groups.google.com/d/optout. > -- You received this message because you are subscribed to the Google Groups "OSv Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
