virtnet

package
v0.0.0-...-8299741 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 7, 2024 License: GPL-3.0 Imports: 11 Imported by: 0

Documentation

Overview

Package virtnet provides infrastructure for TCP-like virtual networks.

For testing distributed systems it is sometimes handy to imitate network of several TCP hosts. It is also handy that ports allocated on Dial/Listen/Accept on that hosts be predictable - that would help tests to verify network events against expected sequence.

Package virtnet provides infrastructure for using and implementing such TCP-like virtual networks.

Using virtnet networks

Addresses on a virtnet network are host:port pairs represented by Addr. A network conceptually consists of several SubNetworks each being home for multiple Hosts. Host is xnet.Networker and so can be worked with similarly to regular TCP network access-point with Dial/Listen/Accept. Host's ports allocation is predictable: ports of a host are contiguous integer sequence starting from 1 that are all initially free, and whenever autobind is requested the first free port of the host will be used. Virtnet ensures that host names are unique throughout whole network.

To work with a virtnet network, one uses corresponding package for particular virtnet network implementation. Such packages provide a way to join particular network and after joining give back SubNetwork to user. Starting from SubNetwork one can create Hosts and from those exchange data throughout whole network.

Please see packages lab.nexedi.com/kirr/go123/xnet/lonet and lab.nexedi.com/kirr/go123/xnet/pipenet for particular well-known virtnet-based networks.

Implementing virtnet networks

To implement a virtnet-based network one need to implement Engine and Registry.

A virtnet network implementation should provide Engine and Registry instances to SubNetwork when creating it. The subnetwork will use provided engine and registry for its operations. A virtnet network implementation receives instance of Notifier together with SubNetwork when creating it. The network implementation should use provided Notifier to notify the subnetwork to handle incoming events.

Please see Engine, Registry and Notifier documentation for details.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrRegistryDown = errors.New("registry is down")
	ErrNoHost       = errors.New("no such host")
	ErrHostDup      = errors.New("host already registered")
)
View Source
var (
	ErrNetDown         = errors.New("network is down")
	ErrHostDown        = errors.New("host is down")
	ErrSockDown        = errors.New("socket is down")
	ErrAddrAlreadyUsed = errors.New("address already in use")
	ErrAddrNoListen    = errors.New("cannot listen on requested address")
	ErrConnRefused     = errors.New("connection refused")
)

Functions

func NewSubNetwork

func NewSubNetwork(network string, engine Engine, registry Registry) (*SubNetwork, Notifier)

NewSubNetwork creates new SubNetwork with given name.

It should be used by virtnet network implementations who should provide it with Engine and Registry instances.

Together with returned SubNetwork an instance of Notifier is provided that should be used by virtnet network implementation to notify created subnetwork to handle incoming events.

Types

type Accept

type Accept struct {
	Addr *Addr // accepting with this local address
	Ack  chan error
}

Accept represents successful acceptance decision from Notifier.VNetAccept .

On successful accept decision corresponding virtnet-level Accept() is waiting on .Ack to continue and will check the error from there.

On success the connection will be finally accepted and corresponding virtnet listener will be notified. Provided netconn will be adjusted by virtnet internally with overwritten LocalAddr and RemoteAddr to be correspondingly .Addr and src that was originally passed to VNetAccept.

On error the acceptance will be canceled.

type Addr

type Addr struct {
	Net  string // full network name, e.g. "pipeα" or "lonetβ"
	Host string // name of host access point on the network
	Port int    // port on host
}

Addr represents address of a virtnet endpoint.

func ParseAddr

func ParseAddr(network, addr string) (*Addr, error)

ParseAddr parses addr into virtnet address for named network.

func (*Addr) Network

func (a *Addr) Network() string

Network implements net.Addr .

func (*Addr) String

func (a *Addr) String() string

String implements net.Addr .

type Engine

type Engine interface {
	// VNetNewHost creates resources for host and announces it to registry.
	//
	// VNetNewHost should create resources for new host and announce
	// hostname to provided registry. When announcing it should encode in
	// hostdata a way for VNetDial - potentially run on another subnetwork
	// - to find out where to connect to when dialing to this host.
	//
	// On error the returned error will be wrapped by virtnet with "new
	// host" operation and hostname.
	VNetNewHost(ctx context.Context, hostname string, registry Registry) error

	// VNetDial creates outbound virtnet connection.
	//
	// VNetDial, given destination virtnet address and destination
	// hostdata, should establish connection to destination. It should let
	// remote side know that its peer virtnet address is src.
	//
	// On success net.Conn that will be handling data exchange via its
	// Read/Write should be returned. This net.Conn will be wrapped by
	// virtnet with overwritten LocalAddr and RemoteAddr to be src and
	// addrAccept correspondingly.
	//
	// On error the returned error will be wrapped by virtnet with
	// corresponding net.OpError{"dial", src, dst}.
	//
	// Virtnet always passes to VNetDial src and dst with the same network
	// name that was used when creating corresponding SubNetwork.
	VNetDial(ctx context.Context, src, dst *Addr, dsthostdata string) (_ net.Conn, addrAccept *Addr, _ error)

	// Close shuts down subnetwork engine.
	//
	// Close should close engine resources and return corresponding error.
	//
	// There is no need to explicitly interrupt other engine operations -
	// to those virtnet always passes ctx that is canceled before
	// engine.Close is called.
	Close() error
}

Engine is the interface for particular virtnet network implementation to be used by SubNetwork.

A virtnet network implementation should provide Engine instance to SubNetwork when creating it. The subnetwork will use provided engine for its operations.

It should be safe to access Engine from multiple goroutines simultaneously.

type Host

type Host struct {
	// contains filtered or unexported fields
}

Host represents named access point on a virtnet network.

A Host belongs to a SubNetwork. It has name and array of sockets indexed by port. It implements xnet.Networker.

It is safe to use Host from multiple goroutines simultaneously.

func (*Host) Close

func (h *Host) Close() (err error)

Close shutdowns host.

After host is shutdown connections to it cannot be established and all currently-established connections are shut down.

Close interrupts all currently in-flight blocked I/O operations on Host or objects created from it: connections and listeners.

func (*Host) Dial

func (h *Host) Dial(ctx context.Context, addr string) (_ net.Conn, err error)

Dial dials address on the network.

It tries to connect to Accept called on listener corresponding to addr.

func (*Host) Listen

func (h *Host) Listen(ctx context.Context, laddr string) (_ xnet.Listener, err error)

Listen starts new listener on the host.

It either allocates free port if laddr is "" or with 0 port, or binds to laddr. Once listener is started, Dials could connect to listening address. Connection requests created by Dials could be accepted via Accept.

func (*Host) Name

func (h *Host) Name() string

Name returns host name.

func (*Host) Network

func (h *Host) Network() string

Network returns full network name of underlying network.

type Notifier

type Notifier interface {
	// VNetAccept notifies virtnet about incoming connection.
	//
	// VNetAccept, given destination virtnet address, should make decision
	// to either accept or reject provided connection.
	//
	// On success the connection is pre-accepted and corresponding Accept
	// is returned to virtnet network implementation.
	//
	// On error an error is returned without any "accept" prefix, e.g.
	// ErrConnRefused. Such accept prefix should be provided by network
	// implementation that is using VNetAccept.
	VNetAccept(ctx context.Context, src, dst *Addr, netconn net.Conn) (*Accept, error)

	// VNetDown notifies virtnet that underlying network is down.
	//
	// Provided err describes the cause of why the network is down.
	VNetDown(err error)
}

Notifier is the interface to be used by particular virtnet network implementation for notifying SubNetwork.

A virtnet network implementation receives instance of Notifier together with SubNetwork when creating it. The network implementation should use provided Notifier to notify the subnetwork to handle incoming events.

It should be safe to access Notifier from multiple goroutines simultaneously.

type Registry

type Registry interface {
	// Announce announces host to registry.
	//
	// Returned error, if !nil, is *RegistryError with .Err describing the
	// error cause:
	//
	//	- ErrRegistryDown  if registry cannot be accessed,
	//	- ErrHostDup       if hostname was already announced,
	//	- some other error indicating e.g. IO problem.
	Announce(ctx context.Context, hostname, hostdata string) error

	// Query queries registry for host.
	//
	// Returned error, if !nil, is *RegistryError with .Err describing the
	// error cause:
	//
	//	- ErrRegistryDown  if registry cannot be accessed,
	//	- ErrNoHost        if hostname was not announced to registry,
	//	- some other error indicating e.g. IO problem.
	Query(ctx context.Context, hostname string) (hostdata string, _ error)

	// Close closes access to registry.
	//
	// Close should close registry resources and return corresponding error.
	//
	// There is no need to explicitly interrupt other registry operations -
	// to those virtnet always passes ctx that is canceled before
	// registry.Close is called.
	Close() error
}

Registry represents access to a virtnet network registry.

A virtnet network implementation should provide Registry instance to SubNetwork when creating it. The subnetwork will eventually use it when creating hosts via NewHost, and in turn creating outbound connections on them via Host.Dial.

The registry holds information about hosts available on the network, and for each host additional data about it. Whenever host α needs to establish connection to address on host β, it queries the registry for β. Correspondingly when a host joins the network, it announces itself to the registry so that other hosts could see it.

The registry could be implemented in several ways, for example:

  • dedicated network server,
  • hosts broadcasting information to each other similar to ARP,
  • shared memory or file,
  • ...

It should be safe to access registry from multiple goroutines simultaneously.

type RegistryError

type RegistryError struct {
	Registry string      // name of the registry
	Op       string      // operation that failed
	Args     interface{} // operation arguments, if any
	Err      error       // actual error that occurred during the operation
}

RegistryError represents an error of a registry operation.

func (*RegistryError) Cause

func (e *RegistryError) Cause() error

func (*RegistryError) Error

func (e *RegistryError) Error() string

func (*RegistryError) Unwrap

func (e *RegistryError) Unwrap() error

type SubNetwork

type SubNetwork struct {
	// contains filtered or unexported fields
}

SubNetwork represents one subnetwork of a virtnet network.

Multiple Hosts could be created on one subnetwork. Multiple subnetworks could be part of a single virtnet network.

Host names are unique through whole virtnet network.

SubNetwork should be created by a particular virtnet network implementation via NewSubNetwork.

func (*SubNetwork) AutoClose

func (n *SubNetwork) AutoClose()

AutoClose schedules Close to be called after last host on this subnetwork is closed.

It is an error to call AutoClose with no opened hosts - this will panic.

func (*SubNetwork) Close

func (n *SubNetwork) Close() (err error)

Close shutdowns subnetwork.

It recursively interrupts all blocking operations on the subnetwork and shutdowns all subnetwork's hosts and connections.

func (*SubNetwork) Host

func (n *SubNetwork) Host(name string) *Host

Host returns host on the subnetwork by name.

If there is no such host - nil is returned.

func (*SubNetwork) Network

func (n *SubNetwork) Network() string

Network returns full network name this subnetwork is part of.

func (*SubNetwork) NewHost

func (n *SubNetwork) NewHost(ctx context.Context, name string) (_ *Host, err error)

NewHost creates new Host with given name.

The host will be associated with SubNetwork via which it was created.

Host names should be unique through whole virtnet network. If not - an error with ErrHostDup cause will be returned.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL