github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/libnetwork/drivers/overlay/joinleave.go (about)

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