It's possible to build that kernel with openvswitch, and vxlan, but
without the vport_vxlan module that glues them together. And at
least one distro has actually done this.
If the local peer's short ID was updated, we broadcastPeerUpdate at
the end (in unlockAndNotify), so there is no need to include the local
peer in the current update.
Also, reading peers.ourself.Version is bad here - we don't take a lock
and it's written by other goroutines. Doesn't actually break anything
though since it's a uint64 and hence atomic.
When we get a forwarded packet, we put its source MAC into the MAC cache,
overriding any existing entry. But we could have a flow which says
to forward packets destined to that MAC based on the old entry. Such
a flow could be prolonged indefinitely by attempts to send to the MAC.
This is obviously bad, so do InvalidateRoutes in such cases.
These are needed to support vxlan encapsulation. In a vxlan packet,
the only place we can straightforwardly hold the source and
destination peer identifiers used by the weave router is in the
24-bit VNI (vxlan network identifier) field. This gives us 12 bits to
indicate a peer. The resulting limit of 4096 peers on a weave network
does not seem like a problem in the near future. But it does mean
that decentralized allocation makes collisions fairly likely even in
weave networks of sizes that are common today. Fortunately, the
problem is much more tractable than IPAM because we can detect when
collisions occur and take action to resolve them.
If a connection gets through all the handshake and subsequent checks -
i.e. it ends up getting added to the LocalPeer's connection list - but
gets terminated within one minute (of the start of the successful
connection attempt), then we apply the existing backoff logic to
schedule a retry, instead of retrying immediately.
In order to do this we retain the 'Target' data structure for such
connections, marking it as 'connected' instead of deleting it (as we
did previously).
Fixes#953.
For fast datapath, the router core will only be invoked upon datapath
misses. And it needs to yield routing decisions in a form that can be
used to configure the in-kernel datapath. So here we make the router
core yield FlowOps, which represent operations which actually do
something with a packet. The router core obtains these in turn from
the Bridge or the Overlay, depending on what it wants to do with
a packet.
For fast datapath, it's critical that the router makes decisions based
only on the required packet header information (as the same header
information will be used when configuring the ODP flow rules). So we
pass only that information into the router core, in the form of
PacketKeys.
The overall effect is to curry the router core: Rather than taking a
packet and doing something with it, it takes packet header information
and returns a function that does something with a packet.
This introduces interfaces to represent the packet forwarding
mechanism, and brings all the scattered UDP-related code together into
a single implementation.
This is not a pure refactoring, although much of the code in sleeve.go
has been copied from pre-existing code, and the UDP protocol remains
the same in spirit. The biggest change is the organization of the
forwarder goroutines (there is now one instead of two, and that
goroutine does a lot of auxiliary work as well as forwarding).
Performance testing between VMs on my laptop suggests that packet
throughput has not gone down, and may even have improved slightly.