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
+#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;
+
+ 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) {
+ 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)) {
+ 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]);
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.