1package macvlan 2 3import ( 4 "fmt" 5 "net" 6 7 "github.com/docker/libnetwork/driverapi" 8 "github.com/docker/libnetwork/netutils" 9 "github.com/docker/libnetwork/ns" 10 "github.com/docker/libnetwork/osl" 11 "github.com/sirupsen/logrus" 12) 13 14// Join method is invoked when a Sandbox is attached to an endpoint. 15func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error { 16 defer osl.InitOSContext()() 17 n, err := d.getNetwork(nid) 18 if err != nil { 19 return err 20 } 21 endpoint := n.endpoint(eid) 22 if endpoint == nil { 23 return fmt.Errorf("could not find endpoint with id %s", eid) 24 } 25 // generate a name for the iface that will be renamed to eth0 in the sbox 26 containerIfName, err := netutils.GenerateIfaceName(ns.NlHandle(), vethPrefix, vethLen) 27 if err != nil { 28 return fmt.Errorf("error generating an interface name: %s", err) 29 } 30 // create the netlink macvlan interface 31 vethName, err := createMacVlan(containerIfName, n.config.Parent, n.config.MacvlanMode) 32 if err != nil { 33 return err 34 } 35 // bind the generated iface name to the endpoint 36 endpoint.srcName = vethName 37 ep := n.endpoint(eid) 38 if ep == nil { 39 return fmt.Errorf("could not find endpoint with id %s", eid) 40 } 41 // parse and match the endpoint address with the available v4 subnets 42 if len(n.config.Ipv4Subnets) > 0 { 43 s := n.getSubnetforIPv4(ep.addr) 44 if s == nil { 45 return fmt.Errorf("could not find a valid ipv4 subnet for endpoint %s", eid) 46 } 47 v4gw, _, err := net.ParseCIDR(s.GwIP) 48 if err != nil { 49 return fmt.Errorf("gateway %s is not a valid ipv4 address: %v", s.GwIP, err) 50 } 51 err = jinfo.SetGateway(v4gw) 52 if err != nil { 53 return err 54 } 55 logrus.Debugf("Macvlan Endpoint Joined with IPv4_Addr: %s, Gateway: %s, MacVlan_Mode: %s, Parent: %s", 56 ep.addr.IP.String(), v4gw.String(), n.config.MacvlanMode, n.config.Parent) 57 } 58 // parse and match the endpoint address with the available v6 subnets 59 if len(n.config.Ipv6Subnets) > 0 { 60 s := n.getSubnetforIPv6(ep.addrv6) 61 if s == nil { 62 return fmt.Errorf("could not find a valid ipv6 subnet for endpoint %s", eid) 63 } 64 v6gw, _, err := net.ParseCIDR(s.GwIP) 65 if err != nil { 66 return fmt.Errorf("gateway %s is not a valid ipv6 address: %v", s.GwIP, err) 67 } 68 err = jinfo.SetGatewayIPv6(v6gw) 69 if err != nil { 70 return err 71 } 72 logrus.Debugf("Macvlan Endpoint Joined with IPv6_Addr: %s Gateway: %s MacVlan_Mode: %s, Parent: %s", 73 ep.addrv6.IP.String(), v6gw.String(), n.config.MacvlanMode, n.config.Parent) 74 } 75 iNames := jinfo.InterfaceName() 76 err = iNames.SetNames(vethName, containerVethPrefix) 77 if err != nil { 78 return err 79 } 80 if err := d.storeUpdate(ep); err != nil { 81 return fmt.Errorf("failed to save macvlan endpoint %.7s to store: %v", ep.id, err) 82 } 83 return nil 84} 85 86// Leave method is invoked when a Sandbox detaches from an endpoint. 87func (d *driver) Leave(nid, eid string) error { 88 defer osl.InitOSContext()() 89 network, err := d.getNetwork(nid) 90 if err != nil { 91 return err 92 } 93 endpoint, err := network.getEndpoint(eid) 94 if err != nil { 95 return err 96 } 97 if endpoint == nil { 98 return fmt.Errorf("could not find endpoint with id %s", eid) 99 } 100 101 return nil 102} 103 104// getSubnetforIP returns the ipv4 subnet to which the given IP belongs 105func (n *network) getSubnetforIPv4(ip *net.IPNet) *ipv4Subnet { 106 for _, s := range n.config.Ipv4Subnets { 107 _, snet, err := net.ParseCIDR(s.SubnetIP) 108 if err != nil { 109 return nil 110 } 111 // first check if the mask lengths are the same 112 i, _ := snet.Mask.Size() 113 j, _ := ip.Mask.Size() 114 if i != j { 115 continue 116 } 117 if snet.Contains(ip.IP) { 118 return s 119 } 120 } 121 122 return nil 123} 124 125// getSubnetforIPv6 returns the ipv6 subnet to which the given IP belongs 126func (n *network) getSubnetforIPv6(ip *net.IPNet) *ipv6Subnet { 127 for _, s := range n.config.Ipv6Subnets { 128 _, snet, err := net.ParseCIDR(s.SubnetIP) 129 if err != nil { 130 return nil 131 } 132 // first check if the mask lengths are the same 133 i, _ := snet.Mask.Size() 134 j, _ := ip.Mask.Size() 135 if i != j { 136 continue 137 } 138 if snet.Contains(ip.IP) { 139 return s 140 } 141 } 142 143 return nil 144} 145