2016-02-16 22:15:18 -05:00
|
|
|
package macvlan
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
|
|
|
|
"github.com/docker/libnetwork/driverapi"
|
|
|
|
"github.com/docker/libnetwork/netutils"
|
2016-05-16 14:51:40 -04:00
|
|
|
"github.com/docker/libnetwork/ns"
|
2016-02-16 22:15:18 -05:00
|
|
|
"github.com/docker/libnetwork/osl"
|
2017-07-26 17:18:31 -04:00
|
|
|
"github.com/sirupsen/logrus"
|
2016-02-16 22:15:18 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
// Join method is invoked when a Sandbox is attached to an endpoint.
|
|
|
|
func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
|
|
|
defer osl.InitOSContext()()
|
|
|
|
n, err := d.getNetwork(nid)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
endpoint := n.endpoint(eid)
|
|
|
|
if endpoint == nil {
|
|
|
|
return fmt.Errorf("could not find endpoint with id %s", eid)
|
|
|
|
}
|
|
|
|
// generate a name for the iface that will be renamed to eth0 in the sbox
|
2016-05-16 14:51:40 -04:00
|
|
|
containerIfName, err := netutils.GenerateIfaceName(ns.NlHandle(), vethPrefix, vethLen)
|
2016-02-16 22:15:18 -05:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("error generating an interface name: %s", err)
|
|
|
|
}
|
|
|
|
// create the netlink macvlan interface
|
2016-03-02 20:13:15 -05:00
|
|
|
vethName, err := createMacVlan(containerIfName, n.config.Parent, n.config.MacvlanMode)
|
2016-02-16 22:15:18 -05:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
// bind the generated iface name to the endpoint
|
|
|
|
endpoint.srcName = vethName
|
|
|
|
ep := n.endpoint(eid)
|
|
|
|
if ep == nil {
|
|
|
|
return fmt.Errorf("could not find endpoint with id %s", eid)
|
|
|
|
}
|
|
|
|
// parse and match the endpoint address with the available v4 subnets
|
|
|
|
if len(n.config.Ipv4Subnets) > 0 {
|
|
|
|
s := n.getSubnetforIPv4(ep.addr)
|
|
|
|
if s == nil {
|
|
|
|
return fmt.Errorf("could not find a valid ipv4 subnet for endpoint %s", eid)
|
|
|
|
}
|
|
|
|
v4gw, _, err := net.ParseCIDR(s.GwIP)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("gatway %s is not a valid ipv4 address: %v", s.GwIP, err)
|
|
|
|
}
|
|
|
|
err = jinfo.SetGateway(v4gw)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-03-02 20:13:15 -05:00
|
|
|
logrus.Debugf("Macvlan Endpoint Joined with IPv4_Addr: %s, Gateway: %s, MacVlan_Mode: %s, Parent: %s",
|
|
|
|
ep.addr.IP.String(), v4gw.String(), n.config.MacvlanMode, n.config.Parent)
|
2016-02-16 22:15:18 -05:00
|
|
|
}
|
|
|
|
// parse and match the endpoint address with the available v6 subnets
|
|
|
|
if len(n.config.Ipv6Subnets) > 0 {
|
|
|
|
s := n.getSubnetforIPv6(ep.addrv6)
|
|
|
|
if s == nil {
|
|
|
|
return fmt.Errorf("could not find a valid ipv6 subnet for endpoint %s", eid)
|
|
|
|
}
|
|
|
|
v6gw, _, err := net.ParseCIDR(s.GwIP)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("gatway %s is not a valid ipv6 address: %v", s.GwIP, err)
|
|
|
|
}
|
|
|
|
err = jinfo.SetGatewayIPv6(v6gw)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-03-02 20:13:15 -05:00
|
|
|
logrus.Debugf("Macvlan Endpoint Joined with IPv6_Addr: %s Gateway: %s MacVlan_Mode: %s, Parent: %s",
|
|
|
|
ep.addrv6.IP.String(), v6gw.String(), n.config.MacvlanMode, n.config.Parent)
|
2016-02-16 22:15:18 -05:00
|
|
|
}
|
|
|
|
iNames := jinfo.InterfaceName()
|
|
|
|
err = iNames.SetNames(vethName, containerVethPrefix)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-06-10 22:54:00 -04:00
|
|
|
if err := d.storeUpdate(ep); err != nil {
|
|
|
|
return fmt.Errorf("failed to save macvlan endpoint %s to store: %v", ep.id[0:7], err)
|
|
|
|
}
|
2016-02-16 22:15:18 -05:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Leave method is invoked when a Sandbox detaches from an endpoint.
|
|
|
|
func (d *driver) Leave(nid, eid string) error {
|
2016-03-10 16:23:04 -05:00
|
|
|
defer osl.InitOSContext()()
|
2016-02-16 22:15:18 -05:00
|
|
|
network, err := d.getNetwork(nid)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
endpoint, err := network.getEndpoint(eid)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if endpoint == nil {
|
|
|
|
return fmt.Errorf("could not find endpoint with id %s", eid)
|
|
|
|
}
|
2016-03-02 20:13:15 -05:00
|
|
|
|
2016-02-16 22:15:18 -05:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// getSubnetforIP returns the ipv4 subnet to which the given IP belongs
|
|
|
|
func (n *network) getSubnetforIPv4(ip *net.IPNet) *ipv4Subnet {
|
|
|
|
for _, s := range n.config.Ipv4Subnets {
|
|
|
|
_, snet, err := net.ParseCIDR(s.SubnetIP)
|
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
// first check if the mask lengths are the same
|
|
|
|
i, _ := snet.Mask.Size()
|
|
|
|
j, _ := ip.Mask.Size()
|
|
|
|
if i != j {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if snet.Contains(ip.IP) {
|
|
|
|
return s
|
|
|
|
}
|
|
|
|
}
|
2016-03-02 20:13:15 -05:00
|
|
|
|
2016-02-16 22:15:18 -05:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// getSubnetforIPv6 returns the ipv6 subnet to which the given IP belongs
|
|
|
|
func (n *network) getSubnetforIPv6(ip *net.IPNet) *ipv6Subnet {
|
|
|
|
for _, s := range n.config.Ipv6Subnets {
|
|
|
|
_, snet, err := net.ParseCIDR(s.SubnetIP)
|
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
// first check if the mask lengths are the same
|
|
|
|
i, _ := snet.Mask.Size()
|
|
|
|
j, _ := ip.Mask.Size()
|
|
|
|
if i != j {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if snet.Contains(ip.IP) {
|
|
|
|
return s
|
|
|
|
}
|
|
|
|
}
|
2016-03-02 20:13:15 -05:00
|
|
|
|
2016-02-16 22:15:18 -05:00
|
|
|
return nil
|
|
|
|
}
|