github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/libnetwork/drivers/ipvlan/ipvlan_joinleave.go (about) 1 //go:build linux 2 // +build linux 3 4 package ipvlan 5 6 import ( 7 "fmt" 8 "net" 9 10 "github.com/docker/docker/libnetwork/driverapi" 11 "github.com/docker/docker/libnetwork/netutils" 12 "github.com/docker/docker/libnetwork/ns" 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 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 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/l3s 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 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 logrus.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 logrus.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 logrus.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 logrus.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 } 126 iNames := jinfo.InterfaceName() 127 err = iNames.SetNames(vethName, containerVethPrefix) 128 if err != nil { 129 return err 130 } 131 if err = d.storeUpdate(ep); err != nil { 132 return fmt.Errorf("failed to save ipvlan endpoint %.7s to store: %v", ep.id, err) 133 } 134 135 return nil 136 } 137 138 // Leave method is invoked when a Sandbox detaches from an endpoint. 139 func (d *driver) Leave(nid, eid string) error { 140 network, err := d.getNetwork(nid) 141 if err != nil { 142 return err 143 } 144 endpoint, err := network.getEndpoint(eid) 145 if err != nil { 146 return err 147 } 148 if endpoint == nil { 149 return fmt.Errorf("could not find endpoint with id %s", eid) 150 } 151 152 return nil 153 } 154 155 // ifaceGateway returns a static route for either v4/v6 to be set to the container eth0 156 func ifaceGateway(dfNet string) (*staticRoute, error) { 157 nh, dst, err := net.ParseCIDR(dfNet) 158 if err != nil { 159 return nil, fmt.Errorf("unable to parse default route %v", err) 160 } 161 defaultRoute := &staticRoute{ 162 Destination: dst, 163 RouteType: types.CONNECTED, 164 NextHop: nh, 165 } 166 167 return defaultRoute, nil 168 } 169 170 // getSubnetforIPv4 returns the ipv4 subnet to which the given IP belongs 171 func (n *network) getSubnetforIPv4(ip *net.IPNet) *ipSubnet { 172 return getSubnetForIP(ip, n.config.Ipv4Subnets) 173 } 174 175 // getSubnetforIPv6 returns the ipv6 subnet to which the given IP belongs 176 func (n *network) getSubnetforIPv6(ip *net.IPNet) *ipSubnet { 177 return getSubnetForIP(ip, n.config.Ipv6Subnets) 178 } 179 180 func getSubnetForIP(ip *net.IPNet, subnets []*ipSubnet) *ipSubnet { 181 for _, s := range subnets { 182 _, snet, err := net.ParseCIDR(s.SubnetIP) 183 if err != nil { 184 return nil 185 } 186 // first check if the mask lengths are the same 187 i, _ := snet.Mask.Size() 188 j, _ := ip.Mask.Size() 189 if i != j { 190 continue 191 } 192 if snet.Contains(ip.IP) { 193 return s 194 } 195 } 196 197 return nil 198 }