Merge branch '1.8'
This commit is contained in:
commit
bb1cca713d
6 files changed
+117
-8
No files matched your search
@@ -1,6 +1,9 @@
|
||||
package net
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
@@ -51,3 +54,35 @@ func isDatapath(link netlink.Link) bool {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func DetectHairpin(portIfName string, log *logrus.Logger) error {
|
||||
link, err := netlink.LinkByName(portIfName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to find link %q: %s", portIfName, err)
|
||||
}
|
||||
|
||||
ch := make(chan netlink.LinkUpdate)
|
||||
// See EnsureInterface for why done channel is not passed
|
||||
if err := netlink.LinkSubscribe(ch, nil); err != nil {
|
||||
return fmt.Errorf("Unable to subscribe to netlink updates: %s", err)
|
||||
}
|
||||
|
||||
pi, err := netlink.LinkGetProtinfo(link)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to get link protinfo %q: %s", portIfName, err)
|
||||
}
|
||||
if pi.Hairpin {
|
||||
return fmt.Errorf("Hairpin mode enabled on %q", portIfName)
|
||||
}
|
||||
|
||||
go func() {
|
||||
for up := range ch {
|
||||
if up.Attrs().Name == portIfName && up.Attrs().Protinfo != nil &&
|
||||
up.Attrs().Protinfo.Hairpin {
|
||||
log.Errorf("Hairpin mode enabled on %q", portIfName)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -226,6 +226,12 @@ func main() {
|
||||
overlay, bridge := createOverlay(datapathName, ifaceName, isAWSVPC, config.Host, config.Port, bufSzMB)
|
||||
networkConfig.Bridge = bridge
|
||||
|
||||
if bridge != nil {
|
||||
if err := weavenet.DetectHairpin("vethwe-bridge", Log); err != nil {
|
||||
Log.Errorf("DetectHairpin failed: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
name := peerName(routerName, bridge.Interface())
|
||||
|
||||
if nickName == "" {
|
||||
|
||||
+56
-4
@@ -50,7 +50,8 @@ type FastDatapath struct {
|
||||
seenMACs map[MAC]struct{}
|
||||
|
||||
// vxlan vports associated with the given UDP ports
|
||||
vxlanVportIDs map[int]odp.VportID
|
||||
vxlanUDPPorts map[int]odp.VportID
|
||||
vxlanVportIDs map[odp.VportID]struct{}
|
||||
mainVxlanVportID odp.VportID
|
||||
|
||||
// A singleton pool for the occasions when we need to decode
|
||||
@@ -87,7 +88,8 @@ func NewFastDatapath(iface *net.Interface, port int) (*FastDatapath, error) {
|
||||
sendToPort: nil,
|
||||
sendToMAC: make(map[MAC]bridgeSender),
|
||||
seenMACs: make(map[MAC]struct{}),
|
||||
vxlanVportIDs: make(map[int]odp.VportID),
|
||||
vxlanUDPPorts: make(map[int]odp.VportID),
|
||||
vxlanVportIDs: make(map[odp.VportID]struct{}),
|
||||
forwarders: make(map[mesh.PeerName]*fastDatapathForwarder),
|
||||
}
|
||||
|
||||
@@ -433,7 +435,7 @@ func (fastdp *FastDatapath) getVxlanVportID(udpPort int) (odp.VportID, error) {
|
||||
fastdp.lock.Lock()
|
||||
defer fastdp.lock.Unlock()
|
||||
|
||||
if vxlanVportID, present := fastdp.vxlanVportIDs[udpPort]; present {
|
||||
if vxlanVportID, present := fastdp.vxlanUDPPorts[udpPort]; present {
|
||||
return vxlanVportID, nil
|
||||
}
|
||||
|
||||
@@ -459,7 +461,8 @@ func (fastdp *FastDatapath) getVxlanVportID(udpPort int) (odp.VportID, error) {
|
||||
}
|
||||
}
|
||||
|
||||
fastdp.vxlanVportIDs[udpPort] = vxlanVportID
|
||||
fastdp.vxlanUDPPorts[udpPort] = vxlanVportID
|
||||
fastdp.vxlanVportIDs[vxlanVportID] = struct{}{}
|
||||
fastdp.missHandlers[vxlanVportID] = func(fks odp.FlowKeys, lock *fastDatapathLock) FlowOp {
|
||||
log.Debug("ODP miss: ", fks, " on port ", vxlanVportID)
|
||||
tunnel := fks[odp.OVS_KEY_ATTR_TUNNEL].(odp.TunnelFlowKey)
|
||||
@@ -1134,6 +1137,11 @@ func (fastdp *FastDatapath) send(fops FlowOp, frame []byte, lock *fastDatapathLo
|
||||
}
|
||||
}
|
||||
|
||||
if fastdp.isHairpinFlow(&flow) {
|
||||
log.Error("Vetoed installation of hairpin flow ", flow)
|
||||
return
|
||||
}
|
||||
|
||||
if dec != nil {
|
||||
// put the decoder back
|
||||
lock.relock()
|
||||
@@ -1171,6 +1179,50 @@ func (fastdp *FastDatapath) takeDecoder(lock *fastDatapathLock) *EthernetDecoder
|
||||
return dec
|
||||
}
|
||||
|
||||
// A isHairpinFlow checks whether the flow is created due to enabled hairpin
|
||||
// mode on the weave bridge port which attaches the datapath. Such flow is
|
||||
// identified by either:
|
||||
//
|
||||
// * in_port == out_port, where in_port is non-vxlan vport;
|
||||
// * a packet is sent back to a vxlan tunnel it has been received from and
|
||||
// the tunnel id is either the same or dstPeer and srcPeer are reversed.
|
||||
func (fastdp *FastDatapath) isHairpinFlow(flow *odp.FlowSpec) bool {
|
||||
var (
|
||||
vxlanKey odp.TunnelAttrs
|
||||
inVport odp.VportID
|
||||
inVxlan bool
|
||||
)
|
||||
|
||||
for _, key := range flow.FlowKeys {
|
||||
switch k := key.(type) {
|
||||
case odp.InPortFlowKey:
|
||||
inVport = k.VportID()
|
||||
case odp.TunnelFlowKey:
|
||||
inVxlan = true
|
||||
vxlanKey = k.Key()
|
||||
}
|
||||
}
|
||||
|
||||
for _, action := range flow.Actions {
|
||||
switch a := action.(type) {
|
||||
case odp.SetTunnelAction:
|
||||
if inVxlan && a.TunnelAttrs.TunnelId == vxlanKey.TunnelId &&
|
||||
a.TunnelAttrs.Ipv4Src == vxlanKey.Ipv4Dst &&
|
||||
a.TunnelAttrs.Ipv4Dst == vxlanKey.Ipv4Src {
|
||||
return true
|
||||
}
|
||||
case odp.OutputAction:
|
||||
if a.VportID() == inVport {
|
||||
if _, ok := fastdp.vxlanVportIDs[a.VportID()]; !ok {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
type odpActionsFlowOp struct {
|
||||
NonDiscardingFlowOp
|
||||
fastdp *FastDatapath
|
||||
|
||||
@@ -124,6 +124,13 @@ func (router *NetworkRouter) handleCapturedPacket(key PacketKey) FlowOp {
|
||||
}
|
||||
|
||||
func (router *NetworkRouter) handleForwardedPacket(key ForwardPacketKey) FlowOp {
|
||||
srcMac := net.HardwareAddr(key.SrcMAC[:])
|
||||
dstMac := net.HardwareAddr(key.DstMAC[:])
|
||||
|
||||
if key.SrcPeer == router.Ourself.Peer {
|
||||
log.Warn("Received own packet to peer ", key.DstPeer, " from MAC (", srcMac, ") to (", dstMac, ")")
|
||||
}
|
||||
|
||||
if key.DstPeer != router.Ourself.Peer {
|
||||
// it's not for us, we're just relaying it
|
||||
router.PacketLogging.LogForwardPacket("Relaying", key)
|
||||
@@ -134,9 +141,6 @@ func (router *NetworkRouter) handleForwardedPacket(key ForwardPacketKey) FlowOp
|
||||
// (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)
|
||||
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
#! /bin/bash
|
||||
|
||||
. ./config.sh
|
||||
|
||||
start_suite "Detect hairpin mode"
|
||||
|
||||
weave_on $HOST1 launch
|
||||
|
||||
assert_raises "run_on $HOST1 sudo ip link set vethwe-bridge type bridge_slave hairpin on"
|
||||
assert_raises "docker_on $HOST1 logs weave 2>&1 | grep -q 'Hairpin mode enabled on \"vethwe-bridge\"'"
|
||||
|
||||
end_suite
|
||||
+1
-1
Submodule vendor/github.com/vishvananda/netlink updated: a632d6dc28...266f02d3a8.
Reference in new issue
Block a user