lab.nexedi.com/kirr/go123@v0.0.0-20240207185015-8299741fa871/xnet/virtnet/interfaces.go (about)

     1  // Copyright (C) 2018-2020  Nexedi SA and Contributors.
     2  //                          Kirill Smelkov <kirr@nexedi.com>
     3  //
     4  // This program is free software: you can Use, Study, Modify and Redistribute
     5  // it under the terms of the GNU General Public License version 3, or (at your
     6  // option) any later version, as published by the Free Software Foundation.
     7  //
     8  // You can also Link and Combine this program with other software covered by
     9  // the terms of any of the Free Software licenses or any of the Open Source
    10  // Initiative approved licenses and Convey the resulting work. Corresponding
    11  // source of such a combination shall include the source code for all other
    12  // software used.
    13  //
    14  // This program is distributed WITHOUT ANY WARRANTY; without even the implied
    15  // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    16  //
    17  // See COPYING file for full licensing terms.
    18  // See https://www.nexedi.com/licensing for rationale and options.
    19  
    20  package virtnet
    21  // interfaces that virtnet uses in its working.
    22  
    23  import (
    24  	"context"
    25  	"errors"
    26  	"fmt"
    27  	"net"
    28  )
    29  
    30  // Engine is the interface for particular virtnet network implementation to be
    31  // used by SubNetwork.
    32  //
    33  // A virtnet network implementation should provide Engine instance to
    34  // SubNetwork when creating it. The subnetwork will use provided engine for its
    35  // operations.
    36  //
    37  // It should be safe to access Engine from multiple goroutines simultaneously.
    38  type Engine interface {
    39  	// VNetNewHost creates resources for host and announces it to registry.
    40  	//
    41  	// VNetNewHost should create resources for new host and announce
    42  	// hostname to provided registry. When announcing it should encode in
    43  	// hostdata a way for VNetDial - potentially run on another subnetwork
    44  	// - to find out where to connect to when dialing to this host.
    45  	//
    46  	// On error the returned error will be wrapped by virtnet with "new
    47  	// host" operation and hostname.
    48  	VNetNewHost(ctx context.Context, hostname string, registry Registry) error
    49  
    50  	// VNetDial creates outbound virtnet connection.
    51  	//
    52  	// VNetDial, given destination virtnet address and destination
    53  	// hostdata, should establish connection to destination. It should let
    54  	// remote side know that its peer virtnet address is src.
    55  	//
    56  	// On success net.Conn that will be handling data exchange via its
    57  	// Read/Write should be returned. This net.Conn will be wrapped by
    58  	// virtnet with overwritten LocalAddr and RemoteAddr to be src and
    59  	// addrAccept correspondingly.
    60  	//
    61  	// On error the returned error will be wrapped by virtnet with
    62  	// corresponding net.OpError{"dial", src, dst}.
    63  	//
    64  	// Virtnet always passes to VNetDial src and dst with the same network
    65  	// name that was used when creating corresponding SubNetwork.
    66  	VNetDial(ctx context.Context, src, dst *Addr, dsthostdata string) (_ net.Conn, addrAccept *Addr, _ error)
    67  
    68  	// Close shuts down subnetwork engine.
    69  	//
    70  	// Close should close engine resources and return corresponding error.
    71  	//
    72  	// There is no need to explicitly interrupt other engine operations -
    73  	// to those virtnet always passes ctx that is canceled before
    74  	// engine.Close is called.
    75  	Close() error
    76  }
    77  
    78  
    79  // Notifier is the interface to be used by particular virtnet network
    80  // implementation for notifying SubNetwork.
    81  //
    82  // A virtnet network implementation receives instance of Notifier together with
    83  // SubNetwork when creating it. The network implementation should use provided
    84  // Notifier to notify the subnetwork to handle incoming events.
    85  //
    86  // It should be safe to access Notifier from multiple goroutines simultaneously.
    87  type Notifier interface {
    88  	// VNetAccept notifies virtnet about incoming connection.
    89  	//
    90  	// VNetAccept, given destination virtnet address, should make decision
    91  	// to either accept or reject provided connection.
    92  	//
    93  	// On success the connection is pre-accepted and corresponding Accept
    94  	// is returned to virtnet network implementation.
    95  	//
    96  	// On error an error is returned without any "accept" prefix, e.g.
    97  	// ErrConnRefused. Such accept prefix should be provided by network
    98  	// implementation that is using VNetAccept.
    99  	VNetAccept(ctx context.Context, src, dst *Addr, netconn net.Conn) (*Accept, error)
   100  
   101  	// VNetDown notifies virtnet that underlying network is down.
   102  	//
   103  	// Provided err describes the cause of why the network is down.
   104  	VNetDown(err error)
   105  }
   106  
   107  // Accept represents successful acceptance decision from Notifier.VNetAccept .
   108  //
   109  // On successful accept decision corresponding virtnet-level Accept() is
   110  // waiting on .Ack to continue and will check the error from there.
   111  //
   112  // On success the connection will be finally accepted and corresponding virtnet
   113  // listener will be notified. Provided netconn will be adjusted by virtnet
   114  // internally with overwritten LocalAddr and RemoteAddr to be correspondingly
   115  // .Addr and src that was originally passed to VNetAccept.
   116  //
   117  // On error the acceptance will be canceled.
   118  type Accept struct {
   119  	Addr *Addr      // accepting with this local address
   120  	Ack  chan error
   121  }
   122  
   123  
   124  // Registry represents access to a virtnet network registry.
   125  //
   126  // A virtnet network implementation should provide Registry instance to
   127  // SubNetwork when creating it. The subnetwork will eventually use it when
   128  // creating hosts via NewHost, and in turn creating outbound connections on
   129  // them via Host.Dial.
   130  //
   131  // The registry holds information about hosts available on the network, and
   132  // for each host additional data about it. Whenever host α needs to establish
   133  // connection to address on host β, it queries the registry for β.
   134  // Correspondingly when a host joins the network, it announces itself to the
   135  // registry so that other hosts could see it.
   136  //
   137  // The registry could be implemented in several ways, for example:
   138  //
   139  //   - dedicated network server,
   140  //   - hosts broadcasting information to each other similar to ARP,
   141  //   - shared memory or file,
   142  //   - ...
   143  //
   144  // It should be safe to access registry from multiple goroutines simultaneously.
   145  type Registry interface {
   146  	// Announce announces host to registry.
   147  	//
   148  	// Returned error, if !nil, is *RegistryError with .Err describing the
   149  	// error cause:
   150  	//
   151  	//	- ErrRegistryDown  if registry cannot be accessed,
   152  	//	- ErrHostDup       if hostname was already announced,
   153  	//	- some other error indicating e.g. IO problem.
   154  	Announce(ctx context.Context, hostname, hostdata string) error
   155  
   156  	// Query queries registry for host.
   157  	//
   158  	// Returned error, if !nil, is *RegistryError with .Err describing the
   159  	// error cause:
   160  	//
   161  	//	- ErrRegistryDown  if registry cannot be accessed,
   162  	//	- ErrNoHost        if hostname was not announced to registry,
   163  	//	- some other error indicating e.g. IO problem.
   164  	Query(ctx context.Context, hostname string) (hostdata string, _ error)
   165  
   166  	// Close closes access to registry.
   167  	//
   168  	// Close should close registry resources and return corresponding error.
   169  	//
   170  	// There is no need to explicitly interrupt other registry operations -
   171  	// to those virtnet always passes ctx that is canceled before
   172  	// registry.Close is called.
   173  	Close() error
   174  }
   175  
   176  var (
   177  	ErrRegistryDown = errors.New("registry is down")
   178  	ErrNoHost       = errors.New("no such host")
   179  	ErrHostDup      = errors.New("host already registered")
   180  )
   181  
   182  // RegistryError represents an error of a registry operation.
   183  type RegistryError struct {
   184  	Registry string      // name of the registry
   185  	Op       string      // operation that failed
   186  	Args     interface{} // operation arguments, if any
   187  	Err      error       // actual error that occurred during the operation
   188  }
   189  
   190  func (e *RegistryError) Error() string {
   191  	s := e.Registry + ": " + e.Op
   192  	if e.Args != nil {
   193  		s += fmt.Sprintf(" %q", e.Args)
   194  	}
   195  	s += ": " + e.Err.Error()
   196  	return s
   197  }
   198  
   199  func (e *RegistryError) Cause() error  { return e.Err }
   200  func (e *RegistryError) Unwrap() error { return e.Err }