github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/libnetwork/drivers/overlay/joinleave.go (about)

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