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