github.com/moby/docker@v26.1.3+incompatible/libnetwork/drivers/ipvlan/ipvlan_joinleave.go (about) 1 //go:build linux 2 3 package ipvlan 4 5 import ( 6 "context" 7 "fmt" 8 "net" 9 10 "github.com/containerd/log" 11 "github.com/docker/docker/libnetwork/driverapi" 12 "github.com/docker/docker/libnetwork/netutils" 13 "github.com/docker/docker/libnetwork/ns" 14 "github.com/docker/docker/libnetwork/types" 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 n, err := d.getNetwork(nid) 31 if err != nil { 32 return err 33 } 34 endpoint := n.endpoint(eid) 35 if endpoint == nil { 36 return fmt.Errorf("could not find endpoint with id %s", eid) 37 } 38 // generate a name for the iface that will be renamed to eth0 in the sbox 39 containerIfName, err := netutils.GenerateIfaceName(ns.NlHandle(), vethPrefix, vethLen) 40 if err != nil { 41 return fmt.Errorf("error generating an interface name: %v", err) 42 } 43 // create the netlink ipvlan interface 44 vethName, err := createIPVlan(containerIfName, n.config.Parent, n.config.IpvlanMode, n.config.IpvlanFlag) 45 if err != nil { 46 return err 47 } 48 // bind the generated iface name to the endpoint 49 endpoint.srcName = vethName 50 ep := n.endpoint(eid) 51 if ep == nil { 52 return fmt.Errorf("could not find endpoint with id %s", eid) 53 } 54 if !n.config.Internal { 55 switch n.config.IpvlanMode { 56 case modeL3, modeL3S: 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/l3s mode ipv4 default gateway: %v", err) 65 } 66 log.G(context.TODO()).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/l3s mode ipv6 default gateway: %v", err) 76 } 77 log.G(context.TODO()).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 case modeL2: 81 // parse and correlate the endpoint v4 address with the available v4 subnets 82 if len(n.config.Ipv4Subnets) > 0 { 83 s := n.getSubnetforIPv4(ep.addr) 84 if s == nil { 85 return fmt.Errorf("could not find a valid ipv4 subnet for endpoint %s", eid) 86 } 87 v4gw, _, err := net.ParseCIDR(s.GwIP) 88 if err != nil { 89 return fmt.Errorf("gateway %s is not a valid ipv4 address: %v", s.GwIP, err) 90 } 91 err = jinfo.SetGateway(v4gw) 92 if err != nil { 93 return err 94 } 95 log.G(context.TODO()).Debugf("Ipvlan Endpoint Joined with IPv4_Addr: %s, Gateway: %s, Ipvlan_Mode: %s, Parent: %s", 96 ep.addr.IP.String(), v4gw.String(), n.config.IpvlanMode, n.config.Parent) 97 } 98 // parse and correlate the endpoint v6 address with the available v6 subnets 99 if len(n.config.Ipv6Subnets) > 0 { 100 s := n.getSubnetforIPv6(ep.addrv6) 101 if s == nil { 102 return fmt.Errorf("could not find a valid ipv6 subnet for endpoint %s", eid) 103 } 104 v6gw, _, err := net.ParseCIDR(s.GwIP) 105 if err != nil { 106 return fmt.Errorf("gateway %s is not a valid ipv6 address: %v", s.GwIP, err) 107 } 108 err = jinfo.SetGatewayIPv6(v6gw) 109 if err != nil { 110 return err 111 } 112 log.G(context.TODO()).Debugf("Ipvlan Endpoint Joined with IPv6_Addr: %s, Gateway: %s, Ipvlan_Mode: %s, Parent: %s", 113 ep.addrv6.IP.String(), v6gw.String(), n.config.IpvlanMode, n.config.Parent) 114 } 115 } 116 } else { 117 if len(n.config.Ipv4Subnets) > 0 { 118 log.G(context.TODO()).Debugf("Ipvlan Endpoint Joined with IPv4_Addr: %s, IpVlan_Mode: %s, Parent: %s", 119 ep.addr.IP.String(), n.config.IpvlanMode, n.config.Parent) 120 } 121 if len(n.config.Ipv6Subnets) > 0 { 122 log.G(context.TODO()).Debugf("Ipvlan Endpoint Joined with IPv6_Addr: %s IpVlan_Mode: %s, Parent: %s", 123 ep.addrv6.IP.String(), n.config.IpvlanMode, n.config.Parent) 124 } 125 // If n.config.Internal was set locally by the driver because there's no parent 126 // interface, libnetwork doesn't know the network is internal. So, stop it from 127 // adding a gateway endpoint. 128 jinfo.DisableGatewayService() 129 } 130 iNames := jinfo.InterfaceName() 131 err = iNames.SetNames(vethName, containerVethPrefix) 132 if err != nil { 133 return err 134 } 135 if err = d.storeUpdate(ep); err != nil { 136 return fmt.Errorf("failed to save ipvlan endpoint %.7s to store: %v", ep.id, err) 137 } 138 139 return nil 140 } 141 142 // Leave method is invoked when a Sandbox detaches from an endpoint. 143 func (d *driver) Leave(nid, eid string) error { 144 network, err := d.getNetwork(nid) 145 if err != nil { 146 return err 147 } 148 endpoint, err := network.getEndpoint(eid) 149 if err != nil { 150 return err 151 } 152 if endpoint == nil { 153 return fmt.Errorf("could not find endpoint with id %s", eid) 154 } 155 156 return nil 157 } 158 159 // ifaceGateway returns a static route for either v4/v6 to be set to the container eth0 160 func ifaceGateway(dfNet string) (*staticRoute, error) { 161 nh, dst, err := net.ParseCIDR(dfNet) 162 if err != nil { 163 return nil, fmt.Errorf("unable to parse default route %v", err) 164 } 165 defaultRoute := &staticRoute{ 166 Destination: dst, 167 RouteType: types.CONNECTED, 168 NextHop: nh, 169 } 170 171 return defaultRoute, nil 172 } 173 174 // getSubnetforIPv4 returns the ipv4 subnet to which the given IP belongs 175 func (n *network) getSubnetforIPv4(ip *net.IPNet) *ipSubnet { 176 return getSubnetForIP(ip, n.config.Ipv4Subnets) 177 } 178 179 // getSubnetforIPv6 returns the ipv6 subnet to which the given IP belongs 180 func (n *network) getSubnetforIPv6(ip *net.IPNet) *ipSubnet { 181 return getSubnetForIP(ip, n.config.Ipv6Subnets) 182 } 183 184 func getSubnetForIP(ip *net.IPNet, subnets []*ipSubnet) *ipSubnet { 185 for _, s := range subnets { 186 _, snet, err := net.ParseCIDR(s.SubnetIP) 187 if err != nil { 188 return nil 189 } 190 // first check if the mask lengths are the same 191 i, _ := snet.Mask.Size() 192 j, _ := ip.Mask.Size() 193 if i != j { 194 continue 195 } 196 if snet.Contains(ip.IP) { 197 return s 198 } 199 } 200 201 return nil 202 }