go123: lab.nexedi.com/kirr/go123/xnet/virtnet Index | Files

package virtnet

import "lab.nexedi.com/kirr/go123/xnet/virtnet"

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

Package Files

interfaces.go virtnet.go

Variables

var (
    ErrRegistryDown = errors.New("registry is down")
    ErrNoHost       = errors.New("no such host")
    ErrHostDup      = errors.New("host already registered")
)
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")
)

func NewSubNetwork Uses

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.

type Accept Uses

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 Uses

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 Uses

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

ParseAddr parses addr into virtnet address for named network.

func (*Addr) Network Uses

func (a *Addr) Network() string

Network implements net.Addr .

func (*Addr) String Uses

func (a *Addr) String() string

String implements net.Addr .

type Engine Uses

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 Uses

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 Uses

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 Uses

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 Uses

func (h *Host) Listen(laddr string) (_ net.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 Uses

func (h *Host) Name() string

Name returns host name.

func (*Host) Network Uses

func (h *Host) Network() string

Network returns full network name of underlying network.

type Notifier Uses

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 Uses

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 Uses

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 Uses

func (e *RegistryError) Cause() error

func (*RegistryError) Error Uses

func (e *RegistryError) Error() string

type SubNetwork Uses

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) Close Uses

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 Uses

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 Uses

func (n *SubNetwork) Network() string

Network returns full network name this subnetwork is part of.

func (*SubNetwork) NewHost Uses

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.

Package virtnet imports 11 packages (graph) and is imported by 5 packages. Updated 2019-11-13. Refresh now. Tools for package owners.