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  }