github.com/jfrazelle/docker@v1.1.2-0.20210712172922-bf78e25fe508/libnetwork/drivers/ipvlan/ipvlan_joinleave.go (about) 1 // +build linux 2 3 package ipvlan 4 5 import ( 6 "fmt" 7 "net" 8 9 "github.com/docker/docker/libnetwork/driverapi" 10 "github.com/docker/docker/libnetwork/netutils" 11 "github.com/docker/docker/libnetwork/ns" 12 "github.com/docker/docker/libnetwork/osl" 13 "github.com/docker/docker/libnetwork/types" 14 "github.com/sirupsen/logrus" 15 ) 16 17 type staticRoute struct { 18 Destination *net.IPNet 19 RouteType int 20 NextHop net.IP 21 } 22 23 const ( 24 defaultV4RouteCidr = "0.0.0.0/0" 25 defaultV6RouteCidr = "::/0" 26 ) 27 28 // Join method is invoked when a Sandbox is attached to an endpoint. 29 func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error { 30 defer osl.InitOSContext()() 31 n, err := d.getNetwork(nid) 32 if err != nil { 33 return err 34 } 35 endpoint := n.endpoint(eid) 36 if endpoint == nil { 37 return fmt.Errorf("could not find endpoint with id %s", eid) 38 } 39 // generate a name for the iface that will be renamed to eth0 in the sbox 40 containerIfName, err := netutils.GenerateIfaceName(ns.NlHandle(), vethPrefix, vethLen) 41 if err != nil { 42 return fmt.Errorf("error generating an interface name: %v", err) 43 } 44 // create the netlink ipvlan interface 45 vethName, err := createIPVlan(containerIfName, n.config.Parent, n.config.IpvlanMode) 46 if err != nil { 47 return err 48 } 49 // bind the generated iface name to the endpoint 50 endpoint.srcName = vethName 51 ep := n.endpoint(eid) 52 if ep == nil { 53 return fmt.Errorf("could not find endpoint with id %s", eid) 54 } 55 if !n.config.Internal { 56 if n.config.IpvlanMode == modeL3 { 57 // disable gateway services to add a default gw using dev eth0 only 58 jinfo.DisableGatewayService() 59 defaultRoute, err := ifaceGateway(defaultV4RouteCidr) 60 if err != nil { 61 return err 62 } 63 if err := jinfo.AddStaticRoute(defaultRoute.Destination, defaultRoute.RouteType, defaultRoute.NextHop); err != nil { 64 return fmt.Errorf("failed to set an ipvlan l3 mode ipv4 default gateway: %v", err) 65 } 66 logrus.Debugf("Ipvlan Endpoint Joined with IPv4_Addr: %s, Ipvlan_Mode: %s, Parent: %s", 67 ep.addr.IP.String(), n.config.IpvlanMode, n.config.Parent) 68 // If the endpoint has a v6 address, set a v6 default route 69 if ep.addrv6 != nil { 70 default6Route, err := ifaceGateway(defaultV6RouteCidr) 71 if err != nil { 72 return err 73 } 74 if err = jinfo.AddStaticRoute(default6Route.Destination, default6Route.RouteType, default6Route.NextHop); err != nil { 75 return fmt.Errorf("failed to set an ipvlan l3 mode ipv6 default gateway: %v", err) 76 } 77 logrus.Debugf("Ipvlan Endpoint Joined with IPv6_Addr: %s, Ipvlan_Mode: %s, Parent: %s", 78 ep.addrv6.IP.String(), n.config.IpvlanMode, n.config.Parent) 79 } 80 } 81 if n.config.IpvlanMode == modeL2 { 82 // parse and correlate the endpoint v4 address with the available v4 subnets 83 if len(n.config.Ipv4Subnets) > 0 { 84 s := n.getSubnetforIPv4(ep.addr) 85 if s == nil { 86 return fmt.Errorf("could not find a valid ipv4 subnet for endpoint %s", eid) 87 } 88 v4gw, _, err := net.ParseCIDR(s.GwIP) 89 if err != nil { 90 return fmt.Errorf("gateway %s is not a valid ipv4 address: %v", s.GwIP, err) 91 } 92 err = jinfo.SetGateway(v4gw) 93 if err != nil { 94 return err 95 } 96 logrus.Debugf("Ipvlan Endpoint Joined with IPv4_Addr: %s, Gateway: %s, Ipvlan_Mode: %s, Parent: %s", 97 ep.addr.IP.String(), v4gw.String(), n.config.IpvlanMode, n.config.Parent) 98 } 99 // parse and correlate the endpoint v6 address with the available v6 subnets 100 if len(n.config.Ipv6Subnets) > 0 { 101 s := n.getSubnetforIPv6(ep.addrv6) 102 if s == nil { 103 return fmt.Errorf("could not find a valid ipv6 subnet for endpoint %s", eid) 104 } 105 v6gw, _, err := net.ParseCIDR(s.GwIP) 106 if err != nil { 107 return fmt.Errorf("gateway %s is not a valid ipv6 address: %v", s.GwIP, err) 108 } 109 err = jinfo.SetGatewayIPv6(v6gw) 110 if err != nil { 111 return err 112 } 113 logrus.Debugf("Ipvlan Endpoint Joined with IPv6_Addr: %s, Gateway: %s, Ipvlan_Mode: %s, Parent: %s", 114 ep.addrv6.IP.String(), v6gw.String(), n.config.IpvlanMode, n.config.Parent) 115 } 116 } 117 } else { 118 if len(n.config.Ipv4Subnets) > 0 { 119 logrus.Debugf("Ipvlan Endpoint Joined with IPv4_Addr: %s, IpVlan_Mode: %s, Parent: %s", 120 ep.addr.IP.String(), n.config.IpvlanMode, n.config.Parent) 121 } 122 if len(n.config.Ipv6Subnets) > 0 { 123 logrus.Debugf("Ipvlan Endpoint Joined with IPv6_Addr: %s IpVlan_Mode: %s, Parent: %s", 124 ep.addrv6.IP.String(), n.config.IpvlanMode, n.config.Parent) 125 } 126 } 127 iNames := jinfo.InterfaceName() 128 err = iNames.SetNames(vethName, containerVethPrefix) 129 if err != nil { 130 return err 131 } 132 if err = d.storeUpdate(ep); err != nil { 133 return fmt.Errorf("failed to save ipvlan endpoint %.7s to store: %v", ep.id, err) 134 } 135 136 return nil 137 } 138 139 // Leave method is invoked when a Sandbox detaches from an endpoint. 140 func (d *driver) Leave(nid, eid string) error { 141 defer osl.InitOSContext()() 142 network, err := d.getNetwork(nid) 143 if err != nil { 144 return err 145 } 146 endpoint, err := network.getEndpoint(eid) 147 if err != nil { 148 return err 149 } 150 if endpoint == nil { 151 return fmt.Errorf("could not find endpoint with id %s", eid) 152 } 153 154 return nil 155 } 156 157 // ifaceGateway returns a static route for either v4/v6 to be set to the container eth0 158 func ifaceGateway(dfNet string) (*staticRoute, error) { 159 nh, dst, err := net.ParseCIDR(dfNet) 160 if err != nil { 161 return nil, fmt.Errorf("unable to parse default route %v", err) 162 } 163 defaultRoute := &staticRoute{ 164 Destination: dst, 165 RouteType: types.CONNECTED, 166 NextHop: nh, 167 } 168 169 return defaultRoute, nil 170 } 171 172 // getSubnetforIPv4 returns the ipv4 subnet to which the given IP belongs 173 func (n *network) getSubnetforIPv4(ip *net.IPNet) *ipv4Subnet { 174 for _, s := range n.config.Ipv4Subnets { 175 _, snet, err := net.ParseCIDR(s.SubnetIP) 176 if err != nil { 177 return nil 178 } 179 // first check if the mask lengths are the same 180 i, _ := snet.Mask.Size() 181 j, _ := ip.Mask.Size() 182 if i != j { 183 continue 184 } 185 if snet.Contains(ip.IP) { 186 return s 187 } 188 } 189 190 return nil 191 } 192 193 // getSubnetforIPv6 returns the ipv6 subnet to which the given IP belongs 194 func (n *network) getSubnetforIPv6(ip *net.IPNet) *ipv6Subnet { 195 for _, s := range n.config.Ipv6Subnets { 196 _, snet, err := net.ParseCIDR(s.SubnetIP) 197 if err != nil { 198 return nil 199 } 200 // first check if the mask lengths are the same 201 i, _ := snet.Mask.Size() 202 j, _ := ip.Mask.Size() 203 if i != j { 204 continue 205 } 206 if snet.Contains(ip.IP) { 207 return s 208 } 209 } 210 211 return nil 212 }