github.com/jfrazelle/docker@v1.1.2-0.20210712172922-bf78e25fe508/libnetwork/drivers/overlay/joinleave.go (about) 1 // +build linux 2 3 package overlay 4 5 import ( 6 "fmt" 7 "net" 8 "syscall" 9 10 "github.com/docker/docker/libnetwork/driverapi" 11 "github.com/docker/docker/libnetwork/ns" 12 "github.com/docker/docker/libnetwork/types" 13 "github.com/gogo/protobuf/proto" 14 "github.com/sirupsen/logrus" 15 ) 16 17 // Join method is invoked when a Sandbox is attached to an endpoint. 18 func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error { 19 if err := validateID(nid, eid); err != nil { 20 return err 21 } 22 23 n := d.network(nid) 24 if n == nil { 25 return fmt.Errorf("could not find network with id %s", nid) 26 } 27 28 ep := n.endpoint(eid) 29 if ep == nil { 30 return fmt.Errorf("could not find endpoint with id %s", eid) 31 } 32 33 if n.secure && len(d.keys) == 0 { 34 return fmt.Errorf("cannot join secure network: encryption keys not present") 35 } 36 37 nlh := ns.NlHandle() 38 39 if n.secure && !nlh.SupportsNetlinkFamily(syscall.NETLINK_XFRM) { 40 return fmt.Errorf("cannot join secure network: required modules to install IPSEC rules are missing on host") 41 } 42 43 s := n.getSubnetforIP(ep.addr) 44 if s == nil { 45 return fmt.Errorf("could not find subnet for endpoint %s", eid) 46 } 47 48 if err := n.obtainVxlanID(s); err != nil { 49 return fmt.Errorf("couldn't get vxlan id for %q: %v", s.subnetIP.String(), err) 50 } 51 52 if err := n.joinSandbox(s, false, true); err != nil { 53 return fmt.Errorf("network sandbox join failed: %v", err) 54 } 55 56 sbox := n.sandbox() 57 58 overlayIfName, containerIfName, err := createVethPair() 59 if err != nil { 60 return err 61 } 62 63 ep.ifName = containerIfName 64 65 if err = d.writeEndpointToStore(ep); err != nil { 66 return fmt.Errorf("failed to update overlay endpoint %.7s to local data store: %v", ep.id, err) 67 } 68 69 // Set the container interface and its peer MTU to 1450 to allow 70 // for 50 bytes vxlan encap (inner eth header(14) + outer IP(20) + 71 // outer UDP(8) + vxlan header(8)) 72 mtu := n.maxMTU() 73 74 veth, err := nlh.LinkByName(overlayIfName) 75 if err != nil { 76 return fmt.Errorf("cound not find link by name %s: %v", overlayIfName, err) 77 } 78 err = nlh.LinkSetMTU(veth, mtu) 79 if err != nil { 80 return err 81 } 82 83 if err = sbox.AddInterface(overlayIfName, "veth", 84 sbox.InterfaceOptions().Master(s.brName)); err != nil { 85 return fmt.Errorf("could not add veth pair inside the network sandbox: %v", err) 86 } 87 88 veth, err = nlh.LinkByName(containerIfName) 89 if err != nil { 90 return fmt.Errorf("could not find link by name %s: %v", containerIfName, err) 91 } 92 err = nlh.LinkSetMTU(veth, mtu) 93 if err != nil { 94 return err 95 } 96 97 if err = nlh.LinkSetHardwareAddr(veth, ep.mac); err != nil { 98 return fmt.Errorf("could not set mac address (%v) to the container interface: %v", ep.mac, err) 99 } 100 101 for _, sub := range n.subnets { 102 if sub == s { 103 continue 104 } 105 if err = jinfo.AddStaticRoute(sub.subnetIP, types.NEXTHOP, s.gwIP.IP); err != nil { 106 logrus.Errorf("Adding subnet %s static route in network %q failed\n", s.subnetIP, n.id) 107 } 108 } 109 110 if iNames := jinfo.InterfaceName(); iNames != nil { 111 err = iNames.SetNames(containerIfName, "eth") 112 if err != nil { 113 return err 114 } 115 } 116 117 d.peerAdd(nid, eid, ep.addr.IP, ep.addr.Mask, ep.mac, net.ParseIP(d.advertiseAddress), false, false, true) 118 119 if err = d.checkEncryption(nid, nil, n.vxlanID(s), true, true); err != nil { 120 logrus.Warn(err) 121 } 122 123 buf, err := proto.Marshal(&PeerRecord{ 124 EndpointIP: ep.addr.String(), 125 EndpointMAC: ep.mac.String(), 126 TunnelEndpointIP: d.advertiseAddress, 127 }) 128 if err != nil { 129 return err 130 } 131 132 if err := jinfo.AddTableEntry(ovPeerTable, eid, buf); err != nil { 133 logrus.Errorf("overlay: Failed adding table entry to joininfo: %v", err) 134 } 135 136 d.pushLocalEndpointEvent("join", nid, eid) 137 138 return nil 139 } 140 141 func (d *driver) DecodeTableEntry(tablename string, key string, value []byte) (string, map[string]string) { 142 if tablename != ovPeerTable { 143 logrus.Errorf("DecodeTableEntry: unexpected table name %s", tablename) 144 return "", nil 145 } 146 147 var peer PeerRecord 148 if err := proto.Unmarshal(value, &peer); err != nil { 149 logrus.Errorf("DecodeTableEntry: failed to unmarshal peer record for key %s: %v", key, err) 150 return "", nil 151 } 152 153 return key, map[string]string{ 154 "Host IP": peer.TunnelEndpointIP, 155 } 156 } 157 158 func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) { 159 if tableName != ovPeerTable { 160 logrus.Errorf("Unexpected table notification for table %s received", tableName) 161 return 162 } 163 164 eid := key 165 166 var peer PeerRecord 167 if err := proto.Unmarshal(value, &peer); err != nil { 168 logrus.Errorf("Failed to unmarshal peer record: %v", err) 169 return 170 } 171 172 // Ignore local peers. We already know about them and they 173 // should not be added to vxlan fdb. 174 if peer.TunnelEndpointIP == d.advertiseAddress { 175 return 176 } 177 178 addr, err := types.ParseCIDR(peer.EndpointIP) 179 if err != nil { 180 logrus.Errorf("Invalid peer IP %s received in event notify", peer.EndpointIP) 181 return 182 } 183 184 mac, err := net.ParseMAC(peer.EndpointMAC) 185 if err != nil { 186 logrus.Errorf("Invalid mac %s received in event notify", peer.EndpointMAC) 187 return 188 } 189 190 vtep := net.ParseIP(peer.TunnelEndpointIP) 191 if vtep == nil { 192 logrus.Errorf("Invalid VTEP %s received in event notify", peer.TunnelEndpointIP) 193 return 194 } 195 196 if etype == driverapi.Delete { 197 d.peerDelete(nid, eid, addr.IP, addr.Mask, mac, vtep, false) 198 return 199 } 200 201 d.peerAdd(nid, eid, addr.IP, addr.Mask, mac, vtep, false, false, false) 202 } 203 204 // Leave method is invoked when a Sandbox detaches from an endpoint. 205 func (d *driver) Leave(nid, eid string) error { 206 if err := validateID(nid, eid); err != nil { 207 return err 208 } 209 210 n := d.network(nid) 211 if n == nil { 212 return fmt.Errorf("could not find network with id %s", nid) 213 } 214 215 ep := n.endpoint(eid) 216 217 if ep == nil { 218 return types.InternalMaskableErrorf("could not find endpoint with id %s", eid) 219 } 220 221 if d.notifyCh != nil { 222 d.notifyCh <- ovNotify{ 223 action: "leave", 224 nw: n, 225 ep: ep, 226 } 227 } 228 229 d.peerDelete(nid, eid, ep.addr.IP, ep.addr.Mask, ep.mac, net.ParseIP(d.advertiseAddress), true) 230 231 n.leaveSandbox() 232 233 return nil 234 }