commit
e5c69801a7
12 files changed
+367
-310
No files matched your search
+5
-5
@@ -146,16 +146,16 @@ var dnsEntriesTemplate = defTemplate("dnsEntries", `\
|
||||
|
||||
type WeaveStatus struct {
|
||||
Version string
|
||||
Router *weave.Status `json:"Router,omitempty"`
|
||||
IPAM *ipam.Status `json:"IPAM,omitempty"`
|
||||
DNS *nameserver.Status `json:"DNS,omitempty"`
|
||||
Router *weave.NetworkRouterStatus `json:"Router,omitempty"`
|
||||
IPAM *ipam.Status `json:"IPAM,omitempty"`
|
||||
DNS *nameserver.Status `json:"DNS,omitempty"`
|
||||
}
|
||||
|
||||
func HandleHTTP(muxRouter *mux.Router, version string, router *weave.Router, allocator *ipam.Allocator, defaultSubnet address.CIDR, ns *nameserver.Nameserver, dnsserver *nameserver.DNSServer) {
|
||||
func HandleHTTP(muxRouter *mux.Router, version string, router *weave.NetworkRouter, allocator *ipam.Allocator, defaultSubnet address.CIDR, ns *nameserver.Nameserver, dnsserver *nameserver.DNSServer) {
|
||||
status := func() WeaveStatus {
|
||||
return WeaveStatus{
|
||||
version,
|
||||
weave.NewStatus(router),
|
||||
weave.NewNetworkRouterStatus(router),
|
||||
ipam.NewStatus(allocator, defaultSubnet),
|
||||
nameserver.NewStatus(ns, dnsserver)}
|
||||
}
|
||||
|
||||
+8
-7
@@ -42,6 +42,7 @@ func main() {
|
||||
addDatapathInterface string
|
||||
|
||||
config weave.Config
|
||||
networkConfig weave.NetworkConfig
|
||||
protocolMinVersion int
|
||||
ifaceName string
|
||||
routerName string
|
||||
@@ -150,7 +151,7 @@ func main() {
|
||||
}
|
||||
config.ProtocolMinVersion = byte(protocolMinVersion)
|
||||
|
||||
var fastDPOverlay weave.Overlay
|
||||
var fastDPOverlay weave.NetworkOverlay
|
||||
if datapathName != "" {
|
||||
// A datapath name implies that "Bridge" and "Overlay"
|
||||
// packet handling use fast datapath, although other
|
||||
@@ -163,7 +164,7 @@ func main() {
|
||||
})
|
||||
|
||||
checkFatal(err)
|
||||
config.Bridge = fastdp.Bridge()
|
||||
networkConfig.Bridge = fastdp.Bridge()
|
||||
fastDPOverlay = fastdp.Overlay()
|
||||
}
|
||||
|
||||
@@ -178,7 +179,7 @@ func main() {
|
||||
checkFatal(err)
|
||||
|
||||
// bufsz flag is in MB
|
||||
config.Bridge, err = weave.NewPcap(iface, bufSzMB*1024*1024)
|
||||
networkConfig.Bridge, err = weave.NewPcap(iface, bufSzMB*1024*1024)
|
||||
checkFatal(err)
|
||||
}
|
||||
|
||||
@@ -229,12 +230,12 @@ func main() {
|
||||
config.PeerDiscovery = !noDiscovery
|
||||
|
||||
if pktdebug {
|
||||
config.PacketLogging = packetLogging{}
|
||||
networkConfig.PacketLogging = packetLogging{}
|
||||
} else {
|
||||
config.PacketLogging = nopPacketLogging{}
|
||||
networkConfig.PacketLogging = nopPacketLogging{}
|
||||
}
|
||||
|
||||
router := weave.NewRouter(config, name, nickName, overlays)
|
||||
router := weave.NewNetworkRouter(config, networkConfig, name, nickName, overlays)
|
||||
Log.Println("Our name is", router.Ourself)
|
||||
|
||||
var dockerCli *docker.Client
|
||||
@@ -258,7 +259,7 @@ func main() {
|
||||
var allocator *ipam.Allocator
|
||||
var defaultSubnet address.CIDR
|
||||
if iprangeCIDR != "" {
|
||||
allocator, defaultSubnet = createAllocator(router, iprangeCIDR, ipsubnetCIDR, determineQuorum(peerCount, peers), isKnownPeer)
|
||||
allocator, defaultSubnet = createAllocator(router.Router, iprangeCIDR, ipsubnetCIDR, determineQuorum(peerCount, peers), isKnownPeer)
|
||||
observeContainers(allocator)
|
||||
} else if peerCount > 0 {
|
||||
Log.Fatal("--init-peer-count flag specified without --ipalloc-range")
|
||||
|
||||
+18
-19
@@ -49,7 +49,7 @@ type LocalConnection struct {
|
||||
uid uint64
|
||||
actionChan chan<- ConnectionAction
|
||||
finished <-chan struct{} // closed to signal that actorLoop has finished
|
||||
forwarder OverlayForwarder
|
||||
OverlayConn OverlayConnection
|
||||
}
|
||||
|
||||
type ConnectionAction func() error
|
||||
@@ -190,7 +190,7 @@ func (conn *LocalConnection) run(actionChan <-chan ConnectionAction, finished ch
|
||||
|
||||
conn.Log("connection ready; using protocol version", conn.version)
|
||||
|
||||
params := ForwarderParams{
|
||||
params := OverlayConnectionParams{
|
||||
RemotePeer: conn.remote,
|
||||
LocalAddr: conn.TCPConn.LocalAddr().(*net.TCPAddr),
|
||||
RemoteAddr: conn.TCPConn.RemoteAddr().(*net.TCPAddr),
|
||||
@@ -200,28 +200,27 @@ func (conn *LocalConnection) run(actionChan <-chan ConnectionAction, finished ch
|
||||
SendControlMessage: conn.sendOverlayControlMessage,
|
||||
Features: intro.Features,
|
||||
}
|
||||
if conn.forwarder, err = conn.Router.Overlay.MakeForwarder(params); err != nil {
|
||||
if conn.OverlayConn, err = conn.Router.Overlay.PrepareConnection(params); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// As soon as we do AddConnection, the new connection becomes
|
||||
// visible to the packet routing logic. So AddConnection must
|
||||
// come after MakeForwarder
|
||||
// come after PrepareConnection
|
||||
if err = conn.Router.Ourself.AddConnection(conn); err != nil {
|
||||
return
|
||||
}
|
||||
conn.Router.ConnectionMaker.ConnectionCreated(conn)
|
||||
|
||||
// Forwarder confirmation comes after AddConnection, because
|
||||
// only after that completes do we know the connection is
|
||||
// valid: in particular that it is not a duplicate connection
|
||||
// to the same peer. Sending heartbeats on a duplicate
|
||||
// connection can trip up crypto at the other end, since the
|
||||
// associated UDP packets may get decoded by the other
|
||||
// connection. It is also generally wasteful to engage in any
|
||||
// interaction with the remote on a connection that turns out
|
||||
// to be invalid.
|
||||
conn.forwarder.Confirm()
|
||||
// OverlayConnection confirmation comes after AddConnection,
|
||||
// because only after that completes do we know the connection is
|
||||
// valid: in particular that it is not a duplicate connection to
|
||||
// the same peer. Overlay communication on a duplicate connection
|
||||
// can cause problems such as tripping up overlay crypto at the
|
||||
// other end due to data being decoded by the other connection. It
|
||||
// is also generally wasteful to engage in any interaction with
|
||||
// the remote on a connection that turns out to be invalid.
|
||||
conn.OverlayConn.Confirm()
|
||||
|
||||
// receiveTCP must follow also AddConnection. In the absence
|
||||
// of any indirect connectivity to the remote peer, the first
|
||||
@@ -337,8 +336,8 @@ func (conn *LocalConnection) registerRemote(remote *Peer, acceptNewPeer bool) er
|
||||
}
|
||||
|
||||
func (conn *LocalConnection) actorLoop(actionChan <-chan ConnectionAction) (err error) {
|
||||
fwdErrorChan := conn.forwarder.ErrorChannel()
|
||||
fwdEstablishedChan := conn.forwarder.EstablishedChannel()
|
||||
fwdErrorChan := conn.OverlayConn.ErrorChannel()
|
||||
fwdEstablishedChan := conn.OverlayConn.EstablishedChannel()
|
||||
|
||||
for err == nil {
|
||||
select {
|
||||
@@ -379,8 +378,8 @@ func (conn *LocalConnection) shutdown(err error) {
|
||||
conn.heartbeatTCP.Stop()
|
||||
}
|
||||
|
||||
if conn.forwarder != nil {
|
||||
conn.forwarder.Stop()
|
||||
if conn.OverlayConn != nil {
|
||||
conn.OverlayConn.Stop()
|
||||
}
|
||||
|
||||
conn.Router.ConnectionMaker.ConnectionTerminated(conn, err)
|
||||
@@ -424,7 +423,7 @@ func (conn *LocalConnection) handleProtocolMsg(tag ProtocolTag, payload []byte)
|
||||
switch tag {
|
||||
case ProtocolHeartbeat:
|
||||
case ProtocolConnectionEstablished, ProtocolFragmentationReceived, ProtocolPMTUVerified, ProtocolOverlayControlMsg:
|
||||
conn.forwarder.ControlMessage(byte(tag), payload)
|
||||
conn.OverlayConn.ControlMessage(byte(tag), payload)
|
||||
case ProtocolGossipUnicast, ProtocolGossipBroadcast, ProtocolGossip:
|
||||
return conn.Router.handleGossip(tag, payload)
|
||||
default:
|
||||
|
||||
+2
-2
@@ -297,7 +297,7 @@ type fastDatapathOverlay struct {
|
||||
*FastDatapath
|
||||
}
|
||||
|
||||
func (fastdp *FastDatapath) Overlay() Overlay {
|
||||
func (fastdp *FastDatapath) Overlay() NetworkOverlay {
|
||||
return fastDatapathOverlay{fastdp}
|
||||
}
|
||||
|
||||
@@ -506,7 +506,7 @@ type fastDatapathForwarder struct {
|
||||
errorChan chan error
|
||||
}
|
||||
|
||||
func (fastdp fastDatapathOverlay) MakeForwarder(params ForwarderParams) (OverlayForwarder, error) {
|
||||
func (fastdp fastDatapathOverlay) PrepareConnection(params OverlayConnectionParams) (OverlayConnection, error) {
|
||||
if params.SessionKey != nil {
|
||||
// No encryption suport in fastdp. The weaver main.go
|
||||
// is responsible for ensuring this doesn't happen.
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package router
|
||||
|
||||
// Interface to overlay network packet handling
|
||||
type NetworkOverlay interface {
|
||||
Overlay
|
||||
|
||||
// The routes have changed, so any cached information should
|
||||
// be discarded.
|
||||
InvalidateRoutes()
|
||||
|
||||
// A mapping of a short id to a peer has changed
|
||||
InvalidateShortIDs()
|
||||
|
||||
// Start consuming forwarded packets.
|
||||
StartConsumingPackets(*Peer, *Peers, OverlayConsumer) error
|
||||
}
|
||||
|
||||
// When a consumer is called, the decoder will already have been used
|
||||
// to decode the frame.
|
||||
type OverlayConsumer func(ForwardPacketKey) FlowOp
|
||||
|
||||
// All of the machinery to forward packets to a particular peer
|
||||
type OverlayForwarder interface {
|
||||
OverlayConnection
|
||||
// Forward a packet across the connection. May be called as soon
|
||||
// as the overlay connection is created, in particular before
|
||||
// Confirm(). The return value nil means the key could not be
|
||||
// handled by this forwarder.
|
||||
Forward(ForwardPacketKey) FlowOp
|
||||
}
|
||||
|
||||
type NullNetworkOverlay struct{ NullOverlay }
|
||||
|
||||
func (NullNetworkOverlay) InvalidateRoutes() {
|
||||
}
|
||||
|
||||
func (NullNetworkOverlay) InvalidateShortIDs() {
|
||||
}
|
||||
|
||||
func (NullNetworkOverlay) StartConsumingPackets(*Peer, *Peers, OverlayConsumer) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (NullNetworkOverlay) Forward(ForwardPacketKey) FlowOp {
|
||||
return DiscardingFlowOp{}
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
MaxUDPPacketSize = 65535
|
||||
FastHeartbeat = 500 * time.Millisecond
|
||||
SlowHeartbeat = 10 * time.Second
|
||||
MaxMissedHeartbeats = 6
|
||||
HeartbeatTimeout = MaxMissedHeartbeats * SlowHeartbeat
|
||||
// should be greater than typical ARP cache expiries, i.e. > 3/2 *
|
||||
// /proc/sys/net/ipv4_neigh/*/base_reachable_time_ms on Linux
|
||||
macMaxAge = 10 * time.Minute
|
||||
)
|
||||
|
||||
type NetworkConfig struct {
|
||||
BufSz int
|
||||
PacketLogging PacketLogging
|
||||
Bridge Bridge
|
||||
}
|
||||
|
||||
type PacketLogging interface {
|
||||
LogPacket(string, PacketKey)
|
||||
LogForwardPacket(string, ForwardPacketKey)
|
||||
}
|
||||
|
||||
type NetworkRouter struct {
|
||||
*Router
|
||||
NetworkConfig
|
||||
Macs *MacCache
|
||||
}
|
||||
|
||||
func NewNetworkRouter(config Config, networkConfig NetworkConfig, name PeerName, nickName string, overlay NetworkOverlay) *NetworkRouter {
|
||||
if overlay == nil {
|
||||
overlay = NullNetworkOverlay{}
|
||||
}
|
||||
if networkConfig.Bridge == nil {
|
||||
networkConfig.Bridge = NullBridge{}
|
||||
}
|
||||
|
||||
router := &NetworkRouter{Router: NewRouter(config, name, nickName, overlay), NetworkConfig: networkConfig}
|
||||
router.Peers.OnInvalidateShortIDs(overlay.InvalidateShortIDs)
|
||||
router.Routes.OnChange(overlay.InvalidateRoutes)
|
||||
router.Macs = NewMacCache(macMaxAge,
|
||||
func(mac net.HardwareAddr, peer *Peer) {
|
||||
log.Println("Expired MAC", mac, "at", peer)
|
||||
})
|
||||
router.Peers.OnGC(func(peer *Peer) { router.Macs.Delete(peer) })
|
||||
return router
|
||||
}
|
||||
|
||||
// Start listening for TCP connections, locally captured packets, and
|
||||
// forwarded packets.
|
||||
func (router *NetworkRouter) Start() {
|
||||
log.Println("Sniffing traffic on", router.Bridge)
|
||||
checkFatal(router.Bridge.StartConsumingPackets(router.handleCapturedPacket))
|
||||
checkFatal(router.Overlay.(NetworkOverlay).StartConsumingPackets(router.Ourself.Peer, router.Peers, router.handleForwardedPacket))
|
||||
router.Router.Start()
|
||||
}
|
||||
|
||||
func (router *NetworkRouter) handleCapturedPacket(key PacketKey) FlowOp {
|
||||
router.PacketLogging.LogPacket("Captured", key)
|
||||
srcMac := net.HardwareAddr(key.SrcMAC[:])
|
||||
|
||||
switch newSrcMac, conflictPeer := router.Macs.Add(srcMac, router.Ourself.Peer); {
|
||||
case newSrcMac:
|
||||
log.Println("Discovered local MAC", srcMac)
|
||||
|
||||
case conflictPeer != nil:
|
||||
// The MAC cache has an entry for the source MAC
|
||||
// associated with another peer. This probably means
|
||||
// we are seeing a frame we injected ourself. That
|
||||
// shouldn't happen, but discard it just in case.
|
||||
log.Error("Captured frame from MAC (", srcMac, ") associated with another peer ", conflictPeer)
|
||||
return DiscardingFlowOp{}
|
||||
}
|
||||
|
||||
// Discard STP broadcasts
|
||||
if key.DstMAC == [...]byte{0x01, 0x80, 0xC2, 0x00, 0x00, 0x00} {
|
||||
return DiscardingFlowOp{}
|
||||
}
|
||||
|
||||
dstMac := net.HardwareAddr(key.DstMAC[:])
|
||||
switch dstPeer := router.Macs.Lookup(dstMac); dstPeer {
|
||||
case router.Ourself.Peer:
|
||||
// The packet is destined for a local MAC. The bridge
|
||||
// won't normally send us such packets, and if it does
|
||||
// it's likely to be broadcasting the packet to all
|
||||
// ports. So if it happens, just drop the packet to
|
||||
// avoid warnings if we try to forward it.
|
||||
return DiscardingFlowOp{}
|
||||
case nil:
|
||||
// If we don't know which peer corresponds to the dest
|
||||
// MAC, broadcast it.
|
||||
router.PacketLogging.LogPacket("Broadcasting", key)
|
||||
return router.relayBroadcast(router.Ourself.Peer, key)
|
||||
default:
|
||||
router.PacketLogging.LogPacket("Forwarding", key)
|
||||
return router.relay(ForwardPacketKey{
|
||||
PacketKey: key,
|
||||
SrcPeer: router.Ourself.Peer,
|
||||
DstPeer: dstPeer})
|
||||
}
|
||||
}
|
||||
|
||||
func (router *NetworkRouter) handleForwardedPacket(key ForwardPacketKey) FlowOp {
|
||||
if key.DstPeer != router.Ourself.Peer {
|
||||
// it's not for us, we're just relaying it
|
||||
router.PacketLogging.LogForwardPacket("Relaying", key)
|
||||
return router.relay(key)
|
||||
}
|
||||
|
||||
// At this point, it's either unicast to us, or a broadcast
|
||||
// (because the DstPeer on a forwarded broadcast packet is
|
||||
// always set to the peer being forwarded to)
|
||||
|
||||
srcMac := net.HardwareAddr(key.SrcMAC[:])
|
||||
dstMac := net.HardwareAddr(key.DstMAC[:])
|
||||
|
||||
switch newSrcMac, conflictPeer := router.Macs.AddForced(srcMac, key.SrcPeer); {
|
||||
case newSrcMac:
|
||||
log.Print("Discovered remote MAC ", srcMac, " at ", key.SrcPeer)
|
||||
|
||||
case conflictPeer != nil:
|
||||
log.Print("Discovered remote MAC ", srcMac, " at ", key.SrcPeer, " (was at ", conflictPeer, ")")
|
||||
|
||||
// We need to clear out any flows destined to the MAC
|
||||
// that forward to the old peer.
|
||||
router.Overlay.(NetworkOverlay).InvalidateRoutes()
|
||||
}
|
||||
|
||||
router.PacketLogging.LogForwardPacket("Injecting", key)
|
||||
injectFop := router.Bridge.InjectPacket(key.PacketKey)
|
||||
dstPeer := router.Macs.Lookup(dstMac)
|
||||
if dstPeer == router.Ourself.Peer {
|
||||
return injectFop
|
||||
}
|
||||
|
||||
router.PacketLogging.LogForwardPacket("Relaying broadcast", key)
|
||||
relayFop := router.relayBroadcast(key.SrcPeer, key.PacketKey)
|
||||
switch {
|
||||
case injectFop == nil:
|
||||
return relayFop
|
||||
|
||||
case relayFop == nil:
|
||||
return injectFop
|
||||
|
||||
default:
|
||||
mfop := NewMultiFlowOp(false)
|
||||
mfop.Add(injectFop)
|
||||
mfop.Add(relayFop)
|
||||
return mfop
|
||||
}
|
||||
}
|
||||
|
||||
// Routing
|
||||
|
||||
func (router *NetworkRouter) relay(key ForwardPacketKey) FlowOp {
|
||||
relayPeerName, found := router.Routes.Unicast(key.DstPeer.Name)
|
||||
if !found {
|
||||
// Not necessarily an error as there could be a race with the
|
||||
// dst disappearing whilst the frame is in flight
|
||||
log.Println("Received packet for unknown destination:", key.DstPeer)
|
||||
return DiscardingFlowOp{}
|
||||
}
|
||||
|
||||
conn, found := router.Ourself.ConnectionTo(relayPeerName)
|
||||
if !found {
|
||||
// Again, could just be a race, not necessarily an error
|
||||
log.Println("Unable to find connection to relay peer", relayPeerName)
|
||||
return DiscardingFlowOp{}
|
||||
}
|
||||
|
||||
return conn.(*LocalConnection).OverlayConn.(OverlayForwarder).Forward(key)
|
||||
}
|
||||
|
||||
func (router *NetworkRouter) relayBroadcast(srcPeer *Peer, key PacketKey) FlowOp {
|
||||
nextHops := router.Routes.Broadcast(srcPeer.Name)
|
||||
if len(nextHops) == 0 {
|
||||
return DiscardingFlowOp{}
|
||||
}
|
||||
|
||||
op := NewMultiFlowOp(true)
|
||||
|
||||
for _, conn := range router.Ourself.ConnectionsTo(nextHops) {
|
||||
op.Add(conn.(*LocalConnection).OverlayConn.(OverlayForwarder).Forward(ForwardPacketKey{
|
||||
PacketKey: key,
|
||||
SrcPeer: srcPeer,
|
||||
DstPeer: conn.Remote()}))
|
||||
}
|
||||
|
||||
return op
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type NetworkRouterStatus struct {
|
||||
*Status
|
||||
Interface string
|
||||
CaptureStats map[string]int
|
||||
MACs []MACStatus
|
||||
}
|
||||
|
||||
type MACStatus struct {
|
||||
Mac string
|
||||
Name string
|
||||
NickName string
|
||||
LastSeen time.Time
|
||||
}
|
||||
|
||||
func NewNetworkRouterStatus(router *NetworkRouter) *NetworkRouterStatus {
|
||||
return &NetworkRouterStatus{
|
||||
NewStatus(router.Router),
|
||||
router.Bridge.String(),
|
||||
router.Bridge.Stats(),
|
||||
NewMACStatusSlice(router.Macs)}
|
||||
}
|
||||
|
||||
func NewMACStatusSlice(cache *MacCache) []MACStatus {
|
||||
cache.RLock()
|
||||
defer cache.RUnlock()
|
||||
|
||||
var slice []MACStatus
|
||||
for key, entry := range cache.table {
|
||||
slice = append(slice, MACStatus{
|
||||
intmac(key).String(),
|
||||
entry.peer.Name.String(),
|
||||
entry.peer.NickName,
|
||||
entry.lastSeen})
|
||||
}
|
||||
|
||||
return slice
|
||||
}
|
||||
+22
-55
@@ -4,34 +4,24 @@ import (
|
||||
"net"
|
||||
)
|
||||
|
||||
// Interface to overlay network packet handling
|
||||
type Overlay interface {
|
||||
// Start consuming forwarded packets.
|
||||
StartConsumingPackets(*Peer, *Peers, OverlayConsumer) error
|
||||
|
||||
// Form a packet-forwarding connection.
|
||||
MakeForwarder(ForwarderParams) (OverlayForwarder, error)
|
||||
|
||||
// The routes have changed, so any cached information should
|
||||
// be discarded.
|
||||
InvalidateRoutes()
|
||||
|
||||
// A mapping of a short id to a peer has changed
|
||||
InvalidateShortIDs()
|
||||
|
||||
// Enhance a features map with overlay-related features
|
||||
AddFeaturesTo(map[string]string)
|
||||
|
||||
// Prepare on overlay connection. The connection should remain
|
||||
// passive until it has been Confirm()ed.
|
||||
PrepareConnection(OverlayConnectionParams) (OverlayConnection, error)
|
||||
|
||||
// Obtain diagnostic information specific to the overlay
|
||||
Diagnostics() interface{}
|
||||
}
|
||||
|
||||
type ForwarderParams struct {
|
||||
type OverlayConnectionParams struct {
|
||||
RemotePeer *Peer
|
||||
|
||||
// The local address of the corresponding TCP connection. Used to
|
||||
// derive the local IP address for sending. May differ for
|
||||
// different forwarders.
|
||||
// different overlay connections.
|
||||
LocalAddr *net.TCPAddr
|
||||
|
||||
// The remote address of the corresponding TCP connection. Used to
|
||||
@@ -50,37 +40,29 @@ type ForwarderParams struct {
|
||||
SessionKey *[32]byte
|
||||
|
||||
// Function to send a control message to the counterpart
|
||||
// forwarder.
|
||||
// overlay connection.
|
||||
SendControlMessage func(tag byte, msg []byte) error
|
||||
|
||||
// Features passed at connection initiation
|
||||
Features map[string]string
|
||||
}
|
||||
|
||||
// When a consumer is called, the decoder will already have been used
|
||||
// to decode the frame.
|
||||
type OverlayConsumer func(ForwardPacketKey) FlowOp
|
||||
|
||||
// All of the machinery to forward packets to a particular peer
|
||||
type OverlayForwarder interface {
|
||||
// Forward a packet across the connection. May be called as
|
||||
// soon as the forwarder is created, in particular before
|
||||
// Confirm(). The return value nil means the key could not be
|
||||
// handled by this forwarder.
|
||||
Forward(ForwardPacketKey) FlowOp
|
||||
|
||||
// All of the machinery to manage overlay connectivity to a particular
|
||||
// peer
|
||||
type OverlayConnection interface {
|
||||
// Confirm that the connection is really wanted, and so the
|
||||
// Overlay should begin heartbeats etc. to verify the
|
||||
// operation of the forwarder.
|
||||
// Overlay should begin heartbeats etc. to verify the operation of
|
||||
// the overlay connection.
|
||||
Confirm()
|
||||
|
||||
// A channel indicating that the forwarder is established,
|
||||
// i.e. its operation has been confirmed.
|
||||
// A channel indicating that the overlay connection is
|
||||
// established, i.e. its operation has been confirmed.
|
||||
EstablishedChannel() <-chan struct{}
|
||||
|
||||
// A channel indicating an error from the forwarder. The
|
||||
// forwarder is not expected to be operational after the first
|
||||
// error, so the channel only needs to buffer a single error.
|
||||
// A channel indicating an error from the overlay connection. The
|
||||
// overlay connection is not expected to be operational after the
|
||||
// first error, so the channel only needs to buffer a single
|
||||
// error.
|
||||
ErrorChannel() <-chan error
|
||||
|
||||
Stop()
|
||||
@@ -96,20 +78,16 @@ type OverlayForwarder interface {
|
||||
|
||||
type NullOverlay struct{}
|
||||
|
||||
func (NullOverlay) StartConsumingPackets(*Peer, *Peers, OverlayConsumer) error {
|
||||
return nil
|
||||
func (NullOverlay) AddFeaturesTo(map[string]string) {
|
||||
}
|
||||
|
||||
func (NullOverlay) MakeForwarder(ForwarderParams) (OverlayForwarder, error) {
|
||||
func (NullOverlay) PrepareConnection(OverlayConnectionParams) (OverlayConnection, error) {
|
||||
return NullOverlay{}, nil
|
||||
}
|
||||
|
||||
func (NullOverlay) InvalidateRoutes() {
|
||||
func (NullOverlay) Diagnostics() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (NullOverlay) InvalidateShortIDs() {
|
||||
}
|
||||
|
||||
func (NullOverlay) Confirm() {
|
||||
}
|
||||
|
||||
@@ -121,13 +99,6 @@ func (NullOverlay) ErrorChannel() <-chan error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (NullOverlay) AddFeaturesTo(map[string]string) {
|
||||
}
|
||||
|
||||
func (NullOverlay) Forward(ForwardPacketKey) FlowOp {
|
||||
return DiscardingFlowOp{}
|
||||
}
|
||||
|
||||
func (NullOverlay) Stop() {
|
||||
}
|
||||
|
||||
@@ -137,7 +108,3 @@ func (NullOverlay) ControlMessage(byte, []byte) {
|
||||
func (NullOverlay) DisplayName() string {
|
||||
return "null"
|
||||
}
|
||||
|
||||
func (NullOverlay) Diagnostics() interface{} {
|
||||
return nil
|
||||
}
|
||||
+12
-11
@@ -13,16 +13,16 @@ import (
|
||||
// uses the best one that seems to be working.
|
||||
|
||||
type OverlaySwitch struct {
|
||||
overlays map[string]Overlay
|
||||
overlays map[string]NetworkOverlay
|
||||
overlayNames []string
|
||||
compatOverlay Overlay
|
||||
compatOverlay NetworkOverlay
|
||||
}
|
||||
|
||||
func NewOverlaySwitch() *OverlaySwitch {
|
||||
return &OverlaySwitch{overlays: make(map[string]Overlay)}
|
||||
return &OverlaySwitch{overlays: make(map[string]NetworkOverlay)}
|
||||
}
|
||||
|
||||
func (osw *OverlaySwitch) Add(name string, overlay Overlay) {
|
||||
func (osw *OverlaySwitch) Add(name string, overlay NetworkOverlay) {
|
||||
// check for repeated names
|
||||
if _, present := osw.overlays[name]; present {
|
||||
log.Fatal("OverlaySwitch: repeated overlay name")
|
||||
@@ -32,7 +32,7 @@ func (osw *OverlaySwitch) Add(name string, overlay Overlay) {
|
||||
osw.overlayNames = append(osw.overlayNames, name)
|
||||
}
|
||||
|
||||
func (osw *OverlaySwitch) SetCompatOverlay(overlay Overlay) {
|
||||
func (osw *OverlaySwitch) SetCompatOverlay(overlay NetworkOverlay) {
|
||||
osw.compatOverlay = overlay
|
||||
}
|
||||
|
||||
@@ -70,19 +70,19 @@ func (osw *OverlaySwitch) StartConsumingPackets(localPeer *Peer, peers *Peers, c
|
||||
}
|
||||
|
||||
type namedOverlay struct {
|
||||
Overlay
|
||||
NetworkOverlay
|
||||
name string
|
||||
}
|
||||
|
||||
// Find the common set of overlays supported by both sides, with the
|
||||
// ordering being the same on both sides too.
|
||||
func (osw *OverlaySwitch) commonOverlays(params ForwarderParams) ([]namedOverlay, error) {
|
||||
func (osw *OverlaySwitch) commonOverlays(params OverlayConnectionParams) ([]namedOverlay, error) {
|
||||
var peerOverlays []string
|
||||
if overlaysFeature, present := params.Features["Overlays"]; present {
|
||||
peerOverlays = strings.Split(overlaysFeature, " ")
|
||||
}
|
||||
|
||||
common := make(map[string]Overlay)
|
||||
common := make(map[string]NetworkOverlay)
|
||||
for _, name := range peerOverlays {
|
||||
if overlay := osw.overlays[name]; overlay != nil {
|
||||
common[name] = overlay
|
||||
@@ -160,9 +160,9 @@ type subForwarderEvent struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (osw *OverlaySwitch) MakeForwarder(params ForwarderParams) (OverlayForwarder, error) {
|
||||
func (osw *OverlaySwitch) PrepareConnection(params OverlayConnectionParams) (OverlayConnection, error) {
|
||||
if _, present := params.Features["Overlays"]; !present && osw.compatOverlay != nil {
|
||||
return osw.compatOverlay.MakeForwarder(params)
|
||||
return osw.compatOverlay.PrepareConnection(params)
|
||||
}
|
||||
|
||||
overlays, err := osw.commonOverlays(params)
|
||||
@@ -200,11 +200,12 @@ func (osw *OverlaySwitch) MakeForwarder(params ForwarderParams) (OverlayForwarde
|
||||
return origSendControlMessage(ProtocolOverlayControlMsg, xmsg)
|
||||
}
|
||||
|
||||
subFwd, err := overlay.MakeForwarder(params)
|
||||
subConn, err := overlay.PrepareConnection(params)
|
||||
if err != nil {
|
||||
fwd.stopFrom(0)
|
||||
return nil, err
|
||||
}
|
||||
subFwd := subConn.(OverlayForwarder)
|
||||
|
||||
subStopChan := make(chan struct{})
|
||||
go monitorForwarder(i, eventsChan, subStopChan, subFwd)
|
||||
|
||||
+12
-178
@@ -11,28 +11,19 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
Port = 6783
|
||||
MaxUDPPacketSize = 65535
|
||||
ChannelSize = 16
|
||||
TCPHeartbeat = 30 * time.Second
|
||||
GossipInterval = 30 * time.Second
|
||||
MaxDuration = time.Duration(math.MaxInt64)
|
||||
FastHeartbeat = 500 * time.Millisecond
|
||||
SlowHeartbeat = 10 * time.Second
|
||||
MaxMissedHeartbeats = 6
|
||||
HeartbeatTimeout = MaxMissedHeartbeats * SlowHeartbeat
|
||||
Port = 6783
|
||||
ChannelSize = 16
|
||||
TCPHeartbeat = 30 * time.Second
|
||||
GossipInterval = 30 * time.Second
|
||||
MaxDuration = time.Duration(math.MaxInt64)
|
||||
|
||||
macMaxAge = 10 * time.Minute // [1]
|
||||
acceptMaxTokens = 100 // [2]
|
||||
acceptTokenDelay = 100 * time.Millisecond // [3]
|
||||
acceptMaxTokens = 100 // [1]
|
||||
acceptTokenDelay = 100 * time.Millisecond // [2]
|
||||
)
|
||||
|
||||
// [1] should be greater than typical ARP cache expiries, i.e. > 3/2 *
|
||||
// /proc/sys/net/ipv4_neigh/*/base_reachable_time_ms on Linux
|
||||
// [1] capacity of token bucket for rate limiting accepts
|
||||
|
||||
// [2] capacity of token bucket for rate limiting accepts
|
||||
|
||||
// [3] control rate at which new tokens are added to the bucket
|
||||
// [2] control rate at which new tokens are added to the bucket
|
||||
|
||||
var (
|
||||
log = common.Log
|
||||
@@ -46,21 +37,12 @@ type Config struct {
|
||||
Password []byte
|
||||
ConnLimit int
|
||||
PeerDiscovery bool
|
||||
BufSz int
|
||||
PacketLogging PacketLogging
|
||||
Bridge Bridge
|
||||
}
|
||||
|
||||
type PacketLogging interface {
|
||||
LogPacket(string, PacketKey)
|
||||
LogForwardPacket(string, ForwardPacketKey)
|
||||
}
|
||||
|
||||
type Router struct {
|
||||
Config
|
||||
Overlay Overlay
|
||||
Ourself *LocalPeer
|
||||
Macs *MacCache
|
||||
Peers *Peers
|
||||
Routes *Routes
|
||||
ConnectionMaker *ConnectionMaker
|
||||
@@ -73,28 +55,17 @@ type Router struct {
|
||||
func NewRouter(config Config, name PeerName, nickName string, overlay Overlay) *Router {
|
||||
router := &Router{Config: config, gossipChannels: make(GossipChannels)}
|
||||
|
||||
if router.Bridge == nil {
|
||||
router.Bridge = NullBridge{}
|
||||
}
|
||||
|
||||
if overlay == nil {
|
||||
overlay = NullOverlay{}
|
||||
}
|
||||
|
||||
router.Overlay = overlay
|
||||
router.Ourself = NewLocalPeer(name, nickName, router)
|
||||
router.Macs = NewMacCache(macMaxAge,
|
||||
func(mac net.HardwareAddr, peer *Peer) {
|
||||
log.Println("Expired MAC", mac, "at", peer)
|
||||
})
|
||||
router.Peers = NewPeers(router.Ourself)
|
||||
router.Peers.OnGC(func(peer *Peer) {
|
||||
router.Macs.Delete(peer)
|
||||
log.Println("Removed unreachable peer", peer)
|
||||
})
|
||||
router.Peers.OnInvalidateShortIDs(overlay.InvalidateShortIDs)
|
||||
router.Routes = NewRoutes(router.Ourself, router.Peers)
|
||||
router.Routes.OnChange(overlay.InvalidateRoutes)
|
||||
router.ConnectionMaker = NewConnectionMaker(router.Ourself, router.Peers, router.Port, router.PeerDiscovery)
|
||||
router.TopologyGossip = router.NewGossip("topology", router)
|
||||
router.acceptLimiter = NewTokenBucket(acceptMaxTokens, acceptTokenDelay)
|
||||
@@ -102,13 +73,10 @@ func NewRouter(config Config, name PeerName, nickName string, overlay Overlay) *
|
||||
return router
|
||||
}
|
||||
|
||||
// Start listening for TCP connections, locally captured packets, and
|
||||
// forwarded packets. This is separate from NewRouter so
|
||||
// that gossipers can register before we start forming connections.
|
||||
// Start listening for TCP connections. This is separate from
|
||||
// NewRouter so that gossipers can register before we start forming
|
||||
// connections.
|
||||
func (router *Router) Start() {
|
||||
log.Println("Sniffing traffic on", router.Bridge)
|
||||
checkFatal(router.Bridge.StartConsumingPackets(router.handleCapturedPacket))
|
||||
checkFatal(router.Overlay.StartConsumingPackets(router.Ourself.Peer, router.Peers, router.handleForwardedPacket))
|
||||
router.listenTCP(router.Port)
|
||||
}
|
||||
|
||||
@@ -121,51 +89,6 @@ func (router *Router) UsingPassword() bool {
|
||||
return router.Password != nil
|
||||
}
|
||||
|
||||
func (router *Router) handleCapturedPacket(key PacketKey) FlowOp {
|
||||
router.PacketLogging.LogPacket("Captured", key)
|
||||
srcMac := net.HardwareAddr(key.SrcMAC[:])
|
||||
|
||||
switch newSrcMac, conflictPeer := router.Macs.Add(srcMac, router.Ourself.Peer); {
|
||||
case newSrcMac:
|
||||
log.Println("Discovered local MAC", srcMac)
|
||||
|
||||
case conflictPeer != nil:
|
||||
// The MAC cache has an entry for the source MAC
|
||||
// associated with another peer. This probably means
|
||||
// we are seeing a frame we injected ourself. That
|
||||
// shouldn't happen, but discard it just in case.
|
||||
log.Error("Captured frame from MAC (", srcMac, ") associated with another peer ", conflictPeer)
|
||||
return DiscardingFlowOp{}
|
||||
}
|
||||
|
||||
// Discard STP broadcasts
|
||||
if key.DstMAC == [...]byte{0x01, 0x80, 0xC2, 0x00, 0x00, 0x00} {
|
||||
return DiscardingFlowOp{}
|
||||
}
|
||||
|
||||
dstMac := net.HardwareAddr(key.DstMAC[:])
|
||||
switch dstPeer := router.Macs.Lookup(dstMac); dstPeer {
|
||||
case router.Ourself.Peer:
|
||||
// The packet is destined for a local MAC. The bridge
|
||||
// won't normally send us such packets, and if it does
|
||||
// it's likely to be broadcasting the packet to all
|
||||
// ports. So if it happens, just drop the packet to
|
||||
// avoid warnings if we try to forward it.
|
||||
return DiscardingFlowOp{}
|
||||
case nil:
|
||||
// If we don't know which peer corresponds to the dest
|
||||
// MAC, broadcast it.
|
||||
router.PacketLogging.LogPacket("Broadcasting", key)
|
||||
return router.relayBroadcast(router.Ourself.Peer, key)
|
||||
default:
|
||||
router.PacketLogging.LogPacket("Forwarding", key)
|
||||
return router.relay(ForwardPacketKey{
|
||||
PacketKey: key,
|
||||
SrcPeer: router.Ourself.Peer,
|
||||
DstPeer: dstPeer})
|
||||
}
|
||||
}
|
||||
|
||||
func (router *Router) listenTCP(localPort int) {
|
||||
localAddr, err := net.ResolveTCPAddr("tcp4", fmt.Sprint(":", localPort))
|
||||
checkFatal(err)
|
||||
@@ -195,95 +118,6 @@ func (router *Router) acceptTCP(tcpConn *net.TCPConn) {
|
||||
StartLocalConnection(connRemote, tcpConn, router, true)
|
||||
}
|
||||
|
||||
func (router *Router) handleForwardedPacket(key ForwardPacketKey) FlowOp {
|
||||
if key.DstPeer != router.Ourself.Peer {
|
||||
// it's not for us, we're just relaying it
|
||||
router.PacketLogging.LogForwardPacket("Relaying", key)
|
||||
return router.relay(key)
|
||||
}
|
||||
|
||||
// At this point, it's either unicast to us, or a broadcast
|
||||
// (because the DstPeer on a forwarded broadcast packet is
|
||||
// always set to the peer being forwarded to)
|
||||
|
||||
srcMac := net.HardwareAddr(key.SrcMAC[:])
|
||||
dstMac := net.HardwareAddr(key.DstMAC[:])
|
||||
|
||||
switch newSrcMac, conflictPeer := router.Macs.AddForced(srcMac, key.SrcPeer); {
|
||||
case newSrcMac:
|
||||
log.Print("Discovered remote MAC ", srcMac, " at ", key.SrcPeer)
|
||||
|
||||
case conflictPeer != nil:
|
||||
log.Print("Discovered remote MAC ", srcMac, " at ", key.SrcPeer, " (was at ", conflictPeer, ")")
|
||||
|
||||
// We need to clear out any flows destined to the MAC
|
||||
// that forward to the old peer.
|
||||
router.Overlay.InvalidateRoutes()
|
||||
}
|
||||
|
||||
router.PacketLogging.LogForwardPacket("Injecting", key)
|
||||
injectFop := router.Bridge.InjectPacket(key.PacketKey)
|
||||
dstPeer := router.Macs.Lookup(dstMac)
|
||||
if dstPeer == router.Ourself.Peer {
|
||||
return injectFop
|
||||
}
|
||||
|
||||
router.PacketLogging.LogForwardPacket("Relaying broadcast", key)
|
||||
relayFop := router.relayBroadcast(key.SrcPeer, key.PacketKey)
|
||||
switch {
|
||||
case injectFop == nil:
|
||||
return relayFop
|
||||
|
||||
case relayFop == nil:
|
||||
return injectFop
|
||||
|
||||
default:
|
||||
mfop := NewMultiFlowOp(false)
|
||||
mfop.Add(injectFop)
|
||||
mfop.Add(relayFop)
|
||||
return mfop
|
||||
}
|
||||
}
|
||||
|
||||
// Routing
|
||||
|
||||
func (router *Router) relay(key ForwardPacketKey) FlowOp {
|
||||
relayPeerName, found := router.Routes.Unicast(key.DstPeer.Name)
|
||||
if !found {
|
||||
// Not necessarily an error as there could be a race with the
|
||||
// dst disappearing whilst the frame is in flight
|
||||
log.Println("Received packet for unknown destination:", key.DstPeer)
|
||||
return DiscardingFlowOp{}
|
||||
}
|
||||
|
||||
conn, found := router.Ourself.ConnectionTo(relayPeerName)
|
||||
if !found {
|
||||
// Again, could just be a race, not necessarily an error
|
||||
log.Println("Unable to find connection to relay peer", relayPeerName)
|
||||
return DiscardingFlowOp{}
|
||||
}
|
||||
|
||||
return conn.(*LocalConnection).forwarder.Forward(key)
|
||||
}
|
||||
|
||||
func (router *Router) relayBroadcast(srcPeer *Peer, key PacketKey) FlowOp {
|
||||
nextHops := router.Routes.Broadcast(srcPeer.Name)
|
||||
if len(nextHops) == 0 {
|
||||
return DiscardingFlowOp{}
|
||||
}
|
||||
|
||||
op := NewMultiFlowOp(true)
|
||||
|
||||
for _, conn := range router.Ourself.ConnectionsTo(nextHops) {
|
||||
op.Add(conn.(*LocalConnection).forwarder.Forward(ForwardPacketKey{
|
||||
PacketKey: key,
|
||||
SrcPeer: srcPeer,
|
||||
DstPeer: conn.Remote()}))
|
||||
}
|
||||
|
||||
return op
|
||||
}
|
||||
|
||||
// Gossiper methods - the Router is the topology Gossiper
|
||||
|
||||
type TopologyGossipData struct {
|
||||
|
||||
+2
-2
@@ -71,7 +71,7 @@ type SleeveOverlay struct {
|
||||
forwarders map[PeerName]*sleeveForwarder
|
||||
}
|
||||
|
||||
func NewSleeveOverlay(localPort int) Overlay {
|
||||
func NewSleeveOverlay(localPort int) NetworkOverlay {
|
||||
return &SleeveOverlay{localPort: localPort}
|
||||
}
|
||||
|
||||
@@ -349,7 +349,7 @@ type controlMessage struct {
|
||||
msg []byte
|
||||
}
|
||||
|
||||
func (sleeve *SleeveOverlay) MakeForwarder(params ForwarderParams) (OverlayForwarder, error) {
|
||||
func (sleeve *SleeveOverlay) PrepareConnection(params OverlayConnectionParams) (OverlayConnection, error) {
|
||||
name := sleeve.localPeer.NameByte
|
||||
var crypto sleeveCrypto
|
||||
if params.SessionKey != nil {
|
||||
|
||||
+1
-31
@@ -2,7 +2,6 @@ package router
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Status struct {
|
||||
@@ -14,9 +13,6 @@ type Status struct {
|
||||
Name string
|
||||
NickName string
|
||||
Port int
|
||||
Interface string
|
||||
CaptureStats map[string]int
|
||||
MACs []MACStatus
|
||||
Peers []PeerStatus
|
||||
UnicastRoutes []UnicastRouteStatus
|
||||
BroadcastRoutes []BroadcastRouteStatus
|
||||
@@ -25,13 +21,6 @@ type Status struct {
|
||||
OverlayDiagnostics interface{}
|
||||
}
|
||||
|
||||
type MACStatus struct {
|
||||
Mac string
|
||||
Name string
|
||||
NickName string
|
||||
LastSeen time.Time
|
||||
}
|
||||
|
||||
type PeerStatus struct {
|
||||
Name string
|
||||
NickName string
|
||||
@@ -75,9 +64,6 @@ func NewStatus(router *Router) *Status {
|
||||
router.Ourself.Name.String(),
|
||||
router.Ourself.NickName,
|
||||
router.Port,
|
||||
router.Bridge.String(),
|
||||
router.Bridge.Stats(),
|
||||
NewMACStatusSlice(router.Macs),
|
||||
NewPeerStatusSlice(router.Peers),
|
||||
NewUnicastRouteStatusSlice(router.Routes),
|
||||
NewBroadcastRouteStatusSlice(router.Routes),
|
||||
@@ -86,22 +72,6 @@ func NewStatus(router *Router) *Status {
|
||||
router.Overlay.Diagnostics()}
|
||||
}
|
||||
|
||||
func NewMACStatusSlice(cache *MacCache) []MACStatus {
|
||||
cache.RLock()
|
||||
defer cache.RUnlock()
|
||||
|
||||
var slice []MACStatus
|
||||
for key, entry := range cache.table {
|
||||
slice = append(slice, MACStatus{
|
||||
intmac(key).String(),
|
||||
entry.peer.Name.String(),
|
||||
entry.peer.NickName,
|
||||
entry.lastSeen})
|
||||
}
|
||||
|
||||
return slice
|
||||
}
|
||||
|
||||
func NewPeerStatusSlice(peers *Peers) []PeerStatus {
|
||||
var slice []PeerStatus
|
||||
|
||||
@@ -176,7 +146,7 @@ func NewLocalConnectionStatusSlice(cm *ConnectionMaker) []LocalConnectionStatus
|
||||
state = "established"
|
||||
}
|
||||
lc, _ := conn.(*LocalConnection)
|
||||
info := fmt.Sprintf("%-6v %v", lc.forwarder.DisplayName(), conn.Remote())
|
||||
info := fmt.Sprintf("%-6v %v", lc.OverlayConn.DisplayName(), conn.Remote())
|
||||
slice = append(slice, LocalConnectionStatus{conn.RemoteTCPAddr(), conn.Outbound(), state, info})
|
||||
}
|
||||
for address, target := range cm.targets {
|
||||
|
||||
Reference in new issue
Block a user