github.com/jfrazelle/docker@v1.1.2-0.20210712172922-bf78e25fe508/libnetwork/drivers/overlay/ov_serf.go (about)

     1  // +build linux
     2  
     3  package overlay
     4  
     5  import (
     6  	"fmt"
     7  	"net"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/hashicorp/serf/serf"
    12  	"github.com/sirupsen/logrus"
    13  )
    14  
    15  type ovNotify struct {
    16  	action string
    17  	ep     *endpoint
    18  	nw     *network
    19  }
    20  
    21  type logWriter struct{}
    22  
    23  func (l *logWriter) Write(p []byte) (int, error) {
    24  	str := string(p)
    25  
    26  	switch {
    27  	case strings.Contains(str, "[WARN]"):
    28  		logrus.Warn(str)
    29  	case strings.Contains(str, "[DEBUG]"):
    30  		logrus.Debug(str)
    31  	case strings.Contains(str, "[INFO]"):
    32  		logrus.Info(str)
    33  	case strings.Contains(str, "[ERR]"):
    34  		logrus.Error(str)
    35  	}
    36  
    37  	return len(p), nil
    38  }
    39  
    40  func (d *driver) serfInit() error {
    41  	var err error
    42  
    43  	config := serf.DefaultConfig()
    44  	config.Init()
    45  	config.MemberlistConfig.BindAddr = d.advertiseAddress
    46  
    47  	d.eventCh = make(chan serf.Event, 4)
    48  	config.EventCh = d.eventCh
    49  	config.UserCoalescePeriod = 1 * time.Second
    50  	config.UserQuiescentPeriod = 50 * time.Millisecond
    51  
    52  	config.LogOutput = &logWriter{}
    53  	config.MemberlistConfig.LogOutput = config.LogOutput
    54  
    55  	s, err := serf.Create(config)
    56  	if err != nil {
    57  		return fmt.Errorf("failed to create cluster node: %v", err)
    58  	}
    59  	defer func() {
    60  		if err != nil {
    61  			s.Shutdown()
    62  		}
    63  	}()
    64  
    65  	d.serfInstance = s
    66  
    67  	d.notifyCh = make(chan ovNotify)
    68  	d.exitCh = make(chan chan struct{})
    69  
    70  	go d.startSerfLoop(d.eventCh, d.notifyCh, d.exitCh)
    71  	return nil
    72  }
    73  
    74  func (d *driver) serfJoin(neighIP string) error {
    75  	if neighIP == "" {
    76  		return fmt.Errorf("no neighbor to join")
    77  	}
    78  	if _, err := d.serfInstance.Join([]string{neighIP}, true); err != nil {
    79  		return fmt.Errorf("Failed to join the cluster at neigh IP %s: %v",
    80  			neighIP, err)
    81  	}
    82  	return nil
    83  }
    84  
    85  func (d *driver) notifyEvent(event ovNotify) {
    86  	ep := event.ep
    87  
    88  	ePayload := fmt.Sprintf("%s %s %s %s", event.action, ep.addr.IP.String(),
    89  		net.IP(ep.addr.Mask).String(), ep.mac.String())
    90  	eName := fmt.Sprintf("jl %s %s %s", d.serfInstance.LocalMember().Addr.String(),
    91  		event.nw.id, ep.id)
    92  
    93  	if err := d.serfInstance.UserEvent(eName, []byte(ePayload), true); err != nil {
    94  		logrus.Errorf("Sending user event failed: %v\n", err)
    95  	}
    96  }
    97  
    98  func (d *driver) processEvent(u serf.UserEvent) {
    99  	logrus.Debugf("Received user event name:%s, payload:%s LTime:%d \n", u.Name,
   100  		string(u.Payload), uint64(u.LTime))
   101  
   102  	var dummy, action, vtepStr, nid, eid, ipStr, maskStr, macStr string
   103  	if _, err := fmt.Sscan(u.Name, &dummy, &vtepStr, &nid, &eid); err != nil {
   104  		fmt.Printf("Failed to scan name string: %v\n", err)
   105  	}
   106  
   107  	if _, err := fmt.Sscan(string(u.Payload), &action,
   108  		&ipStr, &maskStr, &macStr); err != nil {
   109  		fmt.Printf("Failed to scan value string: %v\n", err)
   110  	}
   111  
   112  	logrus.Debugf("Parsed data = %s/%s/%s/%s/%s/%s\n", nid, eid, vtepStr, ipStr, maskStr, macStr)
   113  
   114  	mac, err := net.ParseMAC(macStr)
   115  	if err != nil {
   116  		logrus.Errorf("Failed to parse mac: %v\n", err)
   117  	}
   118  
   119  	if d.serfInstance.LocalMember().Addr.String() == vtepStr {
   120  		return
   121  	}
   122  
   123  	switch action {
   124  	case "join":
   125  		d.peerAdd(nid, eid, net.ParseIP(ipStr), net.IPMask(net.ParseIP(maskStr).To4()), mac, net.ParseIP(vtepStr), false, false, false)
   126  	case "leave":
   127  		d.peerDelete(nid, eid, net.ParseIP(ipStr), net.IPMask(net.ParseIP(maskStr).To4()), mac, net.ParseIP(vtepStr), false)
   128  	}
   129  }
   130  
   131  func (d *driver) processQuery(q *serf.Query) {
   132  	logrus.Debugf("Received query name:%s, payload:%s\n", q.Name,
   133  		string(q.Payload))
   134  
   135  	var nid, ipStr string
   136  	if _, err := fmt.Sscan(string(q.Payload), &nid, &ipStr); err != nil {
   137  		fmt.Printf("Failed to scan query payload string: %v\n", err)
   138  	}
   139  
   140  	pKey, pEntry, err := d.peerDbSearch(nid, net.ParseIP(ipStr))
   141  	if err != nil {
   142  		return
   143  	}
   144  
   145  	logrus.Debugf("Sending peer query resp mac %v, mask %s, vtep %s", pKey.peerMac, net.IP(pEntry.peerIPMask).String(), pEntry.vtep)
   146  	q.Respond([]byte(fmt.Sprintf("%s %s %s", pKey.peerMac.String(), net.IP(pEntry.peerIPMask).String(), pEntry.vtep.String())))
   147  }
   148  
   149  func (d *driver) resolvePeer(nid string, peerIP net.IP) (net.HardwareAddr, net.IPMask, net.IP, error) {
   150  	if d.serfInstance == nil {
   151  		return nil, nil, nil, fmt.Errorf("could not resolve peer: serf instance not initialized")
   152  	}
   153  
   154  	qPayload := fmt.Sprintf("%s %s", nid, peerIP.String())
   155  	resp, err := d.serfInstance.Query("peerlookup", []byte(qPayload), nil)
   156  	if err != nil {
   157  		return nil, nil, nil, fmt.Errorf("resolving peer by querying the cluster failed: %v", err)
   158  	}
   159  
   160  	respCh := resp.ResponseCh()
   161  	select {
   162  	case r := <-respCh:
   163  		var macStr, maskStr, vtepStr string
   164  		if _, err := fmt.Sscan(string(r.Payload), &macStr, &maskStr, &vtepStr); err != nil {
   165  			return nil, nil, nil, fmt.Errorf("bad response %q for the resolve query: %v", string(r.Payload), err)
   166  		}
   167  
   168  		mac, err := net.ParseMAC(macStr)
   169  		if err != nil {
   170  			return nil, nil, nil, fmt.Errorf("failed to parse mac: %v", err)
   171  		}
   172  
   173  		logrus.Debugf("Received peer query response, mac %s, vtep %s, mask %s", macStr, vtepStr, maskStr)
   174  		return mac, net.IPMask(net.ParseIP(maskStr).To4()), net.ParseIP(vtepStr), nil
   175  
   176  	case <-time.After(time.Second):
   177  		return nil, nil, nil, fmt.Errorf("timed out resolving peer by querying the cluster")
   178  	}
   179  }
   180  
   181  func (d *driver) startSerfLoop(eventCh chan serf.Event, notifyCh chan ovNotify,
   182  	exitCh chan chan struct{}) {
   183  
   184  	for {
   185  		select {
   186  		case notify, ok := <-notifyCh:
   187  			if !ok {
   188  				break
   189  			}
   190  
   191  			d.notifyEvent(notify)
   192  		case ch, ok := <-exitCh:
   193  			if !ok {
   194  				break
   195  			}
   196  
   197  			if err := d.serfInstance.Leave(); err != nil {
   198  				logrus.Errorf("failed leaving the cluster: %v\n", err)
   199  			}
   200  
   201  			d.serfInstance.Shutdown()
   202  			close(ch)
   203  			return
   204  		case e, ok := <-eventCh:
   205  			if !ok {
   206  				break
   207  			}
   208  
   209  			if e.EventType() == serf.EventQuery {
   210  				d.processQuery(e.(*serf.Query))
   211  				break
   212  			}
   213  
   214  			u, ok := e.(serf.UserEvent)
   215  			if !ok {
   216  				break
   217  			}
   218  			d.processEvent(u)
   219  		}
   220  	}
   221  }
   222  
   223  func (d *driver) isSerfAlive() bool {
   224  	d.Lock()
   225  	serfInstance := d.serfInstance
   226  	d.Unlock()
   227  	if serfInstance == nil || serfInstance.State() != serf.SerfAlive {
   228  		return false
   229  	}
   230  	return true
   231  }