Merge branch '1.8'

This commit is contained in:
Bryan Boreham committed 2016-12-08 12:27:40 +00:00
commit bb1cca713d
6 files changed
+117 -8

No files matched your search

+35
View File
@@ -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
}
+6
View File
@@ -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
View File
@@ -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
+7 -3
View File
@@ -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)
+12
View File
@@ -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