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