Enable IPv6 in runsc

Fixes #1341

PiperOrigin-RevId: 285108973
This commit is contained in:
Bhasker Hariharan
2019-12-11 19:14:26 -08:00
committed by gVisor bot
parent 6fc9f0aefd
commit b9aa62b9f9
3 changed files with 80 additions and 51 deletions
+24 -11
View File
@@ -80,7 +80,8 @@ type CreateLinksAndRoutesArgs struct {
LoopbackLinks []LoopbackLink
FDBasedLinks []FDBasedLink
DefaultGateway DefaultRoute
Defaultv4Gateway DefaultRoute
Defaultv6Gateway DefaultRoute
}
// Empty returns true if route hasn't been set.
@@ -122,10 +123,10 @@ func (n *Network) CreateLinksAndRoutes(args *CreateLinksAndRoutesArgs, _ *struct
nicID++
nicids[link.Name] = nicID
ep := loopback.New()
linkEP := loopback.New()
log.Infof("Enabling loopback interface %q with id %d on addresses %+v", link.Name, nicID, link.Addresses)
if err := n.createNICWithAddrs(nicID, link.Name, ep, link.Addresses, true /* loopback */); err != nil {
if err := n.createNICWithAddrs(nicID, link.Name, linkEP, link.Addresses, true /* loopback */); err != nil {
return err
}
@@ -157,7 +158,7 @@ func (n *Network) CreateLinksAndRoutes(args *CreateLinksAndRoutesArgs, _ *struct
}
mac := tcpip.LinkAddress(link.LinkAddress)
ep, err := fdbased.New(&fdbased.Options{
linkEP, err := fdbased.New(&fdbased.Options{
FDs: FDs,
MTU: uint32(link.MTU),
EthernetHeader: true,
@@ -172,7 +173,7 @@ func (n *Network) CreateLinksAndRoutes(args *CreateLinksAndRoutesArgs, _ *struct
}
log.Infof("Enabling interface %q with id %d on addresses %+v (%v) w/ %d channels", link.Name, nicID, link.Addresses, mac, link.NumChannels)
if err := n.createNICWithAddrs(nicID, link.Name, ep, link.Addresses, false /* loopback */); err != nil {
if err := n.createNICWithAddrs(nicID, link.Name, linkEP, link.Addresses, false /* loopback */); err != nil {
return err
}
@@ -186,12 +187,24 @@ func (n *Network) CreateLinksAndRoutes(args *CreateLinksAndRoutesArgs, _ *struct
}
}
if !args.DefaultGateway.Route.Empty() {
nicID, ok := nicids[args.DefaultGateway.Name]
if !args.Defaultv4Gateway.Route.Empty() {
nicID, ok := nicids[args.Defaultv4Gateway.Name]
if !ok {
return fmt.Errorf("invalid interface name %q for default route", args.DefaultGateway.Name)
return fmt.Errorf("invalid interface name %q for default route", args.Defaultv4Gateway.Name)
}
route, err := args.DefaultGateway.Route.toTcpipRoute(nicID)
route, err := args.Defaultv4Gateway.Route.toTcpipRoute(nicID)
if err != nil {
return err
}
routes = append(routes, route)
}
if !args.Defaultv6Gateway.Route.Empty() {
nicID, ok := nicids[args.Defaultv6Gateway.Name]
if !ok {
return fmt.Errorf("invalid interface name %q for default route", args.Defaultv6Gateway.Name)
}
route, err := args.Defaultv6Gateway.Route.toTcpipRoute(nicID)
if err != nil {
return err
}
@@ -208,11 +221,11 @@ func (n *Network) CreateLinksAndRoutes(args *CreateLinksAndRoutesArgs, _ *struct
func (n *Network) createNICWithAddrs(id tcpip.NICID, name string, ep stack.LinkEndpoint, addrs []net.IP, loopback bool) error {
if loopback {
if err := n.Stack.CreateNamedLoopbackNIC(id, name, sniffer.New(ep)); err != nil {
return fmt.Errorf("CreateNamedLoopbackNIC(%v, %v) failed: %v", id, name, err)
return fmt.Errorf("CreateNamedLoopbackNIC(%v, %v, %v) failed: %v", id, name, ep, err)
}
} else {
if err := n.Stack.CreateNamedNIC(id, name, sniffer.New(ep)); err != nil {
return fmt.Errorf("CreateNamedNIC(%v, %v) failed: %v", id, name, err)
return fmt.Errorf("CreateNamedNIC(%v, %v, %v) failed: %v", id, name, ep, err)
}
}
+1
View File
@@ -19,6 +19,7 @@ go_library(
"//pkg/log",
"//pkg/sentry/control",
"//pkg/sentry/platform",
"//pkg/tcpip/header",
"//pkg/tcpip/stack",
"//pkg/urpc",
"//runsc/boot",
+55 -40
View File
@@ -28,6 +28,7 @@ import (
"github.com/vishvananda/netlink"
"golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/stack"
"gvisor.dev/gvisor/pkg/urpc"
"gvisor.dev/gvisor/runsc/boot"
@@ -183,36 +184,39 @@ func createInterfacesAndRoutesFromNS(conn *urpc.Client, nsPath string, hardwareG
continue
}
// Keep only IPv4 addresses.
var ip4addrs []*net.IPNet
var ipAddrs []*net.IPNet
for _, ifaddr := range allAddrs {
ipNet, ok := ifaddr.(*net.IPNet)
if !ok {
return fmt.Errorf("address is not IPNet: %+v", ifaddr)
}
if ipNet.IP.To4() == nil {
log.Warningf("IPv6 is not supported, skipping: %v", ipNet)
continue
}
ip4addrs = append(ip4addrs, ipNet)
ipAddrs = append(ipAddrs, ipNet)
}
if len(ip4addrs) == 0 {
log.Warningf("No IPv4 address found for interface %q, skipping", iface.Name)
if len(ipAddrs) == 0 {
log.Warningf("No usable IP addresses found for interface %q, skipping", iface.Name)
continue
}
// Scrape the routes before removing the address, since that
// will remove the routes as well.
routes, def, err := routesForIface(iface)
routes, defv4, defv6, err := routesForIface(iface)
if err != nil {
return fmt.Errorf("getting routes for interface %q: %v", iface.Name, err)
}
if def != nil {
if !args.DefaultGateway.Route.Empty() {
return fmt.Errorf("more than one default route found, interface: %v, route: %v, default route: %+v", iface.Name, def, args.DefaultGateway)
if defv4 != nil {
if !args.Defaultv4Gateway.Route.Empty() {
return fmt.Errorf("more than one default route found, interface: %v, route: %v, default route: %+v", iface.Name, defv4, args.Defaultv4Gateway)
}
args.DefaultGateway.Route = *def
args.DefaultGateway.Name = iface.Name
args.Defaultv4Gateway.Route = *defv4
args.Defaultv4Gateway.Name = iface.Name
}
if defv6 != nil {
if !args.Defaultv6Gateway.Route.Empty() {
return fmt.Errorf("more than one default route found, interface: %v, route: %v, default route: %+v", iface.Name, defv6, args.Defaultv6Gateway)
}
args.Defaultv6Gateway.Route = *defv6
args.Defaultv6Gateway.Name = iface.Name
}
link := boot.FDBasedLink{
@@ -247,6 +251,7 @@ func createInterfacesAndRoutesFromNS(conn *urpc.Client, nsPath string, hardwareG
}
args.FilePayload.Files = append(args.FilePayload.Files, socketEntry.deviceFile)
}
if link.GSOMaxSize == 0 && softwareGSO {
// Hardware GSO is disabled. Let's enable software GSO.
link.GSOMaxSize = stack.SoftwareGSOMaxSize
@@ -255,7 +260,7 @@ func createInterfacesAndRoutesFromNS(conn *urpc.Client, nsPath string, hardwareG
// Collect the addresses for the interface, enable forwarding,
// and remove them from the host.
for _, addr := range ip4addrs {
for _, addr := range ipAddrs {
link.Addresses = append(link.Addresses, addr.IP)
// Steal IP address from NIC.
@@ -351,46 +356,56 @@ func loopbackLinks(iface net.Interface, addrs []net.Addr) ([]boot.LoopbackLink,
}
// routesForIface iterates over all routes for the given interface and converts
// them to boot.Routes.
func routesForIface(iface net.Interface) ([]boot.Route, *boot.Route, error) {
// them to boot.Routes. It also returns the a default v4/v6 route if found.
func routesForIface(iface net.Interface) ([]boot.Route, *boot.Route, *boot.Route, error) {
link, err := netlink.LinkByIndex(iface.Index)
if err != nil {
return nil, nil, err
return nil, nil, nil, err
}
rs, err := netlink.RouteList(link, netlink.FAMILY_ALL)
if err != nil {
return nil, nil, fmt.Errorf("getting routes from %q: %v", iface.Name, err)
return nil, nil, nil, fmt.Errorf("getting routes from %q: %v", iface.Name, err)
}
var def *boot.Route
var defv4, defv6 *boot.Route
var routes []boot.Route
for _, r := range rs {
// Is it a default route?
if r.Dst == nil {
if r.Gw == nil {
return nil, nil, fmt.Errorf("default route with no gateway %q: %+v", iface.Name, r)
}
if r.Gw.To4() == nil {
log.Warningf("IPv6 is not supported, skipping default route: %v", r)
continue
}
if def != nil {
return nil, nil, fmt.Errorf("more than one default route found %q, def: %+v, route: %+v", iface.Name, def, r)
return nil, nil, nil, fmt.Errorf("default route with no gateway %q: %+v", iface.Name, r)
}
// Create a catch all route to the gateway.
def = &boot.Route{
Destination: net.IPNet{
IP: net.IPv4zero,
Mask: net.IPMask(net.IPv4zero),
},
Gateway: r.Gw,
switch len(r.Gw) {
case header.IPv4AddressSize:
if defv4 != nil {
return nil, nil, nil, fmt.Errorf("more than one default route found %q, def: %+v, route: %+v", iface.Name, defv4, r)
}
defv4 = &boot.Route{
Destination: net.IPNet{
IP: net.IPv4zero,
Mask: net.IPMask(net.IPv4zero),
},
Gateway: r.Gw,
}
case header.IPv6AddressSize:
if defv6 != nil {
return nil, nil, nil, fmt.Errorf("more than one default route found %q, def: %+v, route: %+v", iface.Name, defv6, r)
}
defv6 = &boot.Route{
Destination: net.IPNet{
IP: net.IPv6zero,
Mask: net.IPMask(net.IPv6zero),
},
Gateway: r.Gw,
}
default:
return nil, nil, nil, fmt.Errorf("unexpected address size for gateway: %+v for route: %+v", r.Gw, r)
}
continue
}
if r.Dst.IP.To4() == nil {
log.Warningf("IPv6 is not supported, skipping route: %v", r)
continue
}
dst := *r.Dst
dst.IP = dst.IP.Mask(dst.Mask)
routes = append(routes, boot.Route{
@@ -398,7 +413,7 @@ func routesForIface(iface net.Interface) ([]boot.Route, *boot.Route, error) {
Gateway: r.Gw,
})
}
return routes, def, nil
return routes, defv4, defv6, nil
}
// removeAddress removes IP address from network device. It's equivalent to: