Skip to content

Commit

Permalink
Enabled hairpin mode for bridged external interface
Browse files Browse the repository at this point in the history
  • Loading branch information
ofiliz committed Mar 31, 2017
1 parent 87642a3 commit 3755884
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 0 deletions.
65 changes: 65 additions & 0 deletions netlink/link.go
Original file line number Diff line number Diff line change
Expand Up @@ -314,3 +314,68 @@ func SetLinkAddress(ifName string, hwAddress net.HardwareAddr) error {

return s.sendAndWaitForAck(req)
}

// SetLinkPromisc sets the promiscuous mode of a network interface.
func SetLinkPromisc(ifName string, on bool) error {
s, err := getSocket()
if err != nil {
return err
}

iface, err := net.InterfaceByName(ifName)
if err != nil {
return err
}

req := newRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)

ifInfo := newIfInfoMsg()
ifInfo.Type = unix.RTM_SETLINK
ifInfo.Index = int32(iface.Index)

if on {
ifInfo.Flags = unix.IFF_PROMISC
ifInfo.Change = unix.IFF_PROMISC
} else {
ifInfo.Flags = 0 & ^unix.IFF_PROMISC
ifInfo.Change = unix.IFF_PROMISC
}

req.addPayload(ifInfo)

return s.sendAndWaitForAck(req)
}

// SetLinkHairpin sets the hairpin (reflective relay) mode of a bridged interface.
func SetLinkHairpin(bridgeName string, on bool) error {
s, err := getSocket()
if err != nil {
return err
}

iface, err := net.InterfaceByName(bridgeName)
if err != nil {
return err
}

req := newRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)

ifInfo := newIfInfoMsg()
ifInfo.Family = unix.AF_BRIDGE
ifInfo.Type = unix.RTM_SETLINK
ifInfo.Index = int32(iface.Index)
ifInfo.Flags = unix.NLM_F_REQUEST
ifInfo.Change = DEFAULT_CHANGE
req.addPayload(ifInfo)

hairpin := []byte{0}
if on {
hairpin[0] = byte(1)
}

attrProtInfo := newAttribute(unix.IFLA_PROTINFO|unix.NLA_F_NESTED, nil)
attrProtInfo.addNested(newAttribute(IFLA_BRPORT_MODE, hairpin))
req.addPayload(attrProtInfo)

return s.sendAndWaitForAck(req)
}
68 changes: 68 additions & 0 deletions netlink/netlink_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,3 +164,71 @@ func TestSetLinkState(t *testing.T) {
t.Errorf("DeleteLink failed: %+v", err)
}
}

// TestSetLinkPromisc tests setting the promiscuous mode of a network interface.
func TestSetLinkPromisc(t *testing.T) {
_, err := addDummyInterface(ifName)
if err != nil {
t.Errorf("addDummyInterface failed: %v", err)
}

err = SetLinkPromisc(ifName, true)
if err != nil {
t.Errorf("SetLinkPromisc on failed: %+v", err)
}

err = SetLinkPromisc(ifName, false)
if err != nil {
t.Errorf("SetLinkPromisc off failed: %+v", err)
}

err = DeleteLink(ifName)
if err != nil {
t.Errorf("DeleteLink failed: %+v", err)
}
}

// TestSetHairpinMode tests setting the hairpin mode of a bridged interface.
func TestSetLinkHairpin(t *testing.T) {
link := BridgeLink{
LinkInfo: LinkInfo{
Type: LINK_TYPE_BRIDGE,
Name: ifName,
},
}

err := AddLink(&link)
if err != nil {
t.Errorf("AddLink failed: %+v", err)
}

_, err = addDummyInterface(ifName2)
if err != nil {
t.Errorf("addDummyInterface failed: %v", err)
}

err = SetLinkMaster(ifName2, ifName)
if err != nil {
t.Errorf("SetLinkMaster failed: %+v", err)
}

err = SetLinkHairpin(ifName2, true)
if err != nil {
t.Errorf("SetLinkHairpin on failed: %+v", err)
}

err = SetLinkHairpin(ifName2, false)
if err != nil {
t.Errorf("SetLinkHairpin off failed: %+v", err)
}

err = DeleteLink(ifName2)
if err != nil {
t.Errorf("DeleteLink failed: %+v", err)
}

err = DeleteLink(ifName)
if err != nil {
t.Errorf("DeleteLink failed: %+v", err)
}
}
1 change: 1 addition & 0 deletions netlink/protocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const (
IFLA_INFO_DATA = 2
IFLA_NET_NS_FD = 28
IFLA_IPVLAN_MODE = 1
IFLA_BRPORT_MODE = 4
VETH_INFO_PEER = 1
DEFAULT_CHANGE = 0xFFFFFFFF
)
Expand Down
7 changes: 7 additions & 0 deletions network/network_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,13 @@ func (nm *networkManager) connectExternalInterface(extIf *externalInterface, nwI
goto cleanup
}

// External interface hairpin on.
log.Printf("[net] Setting link %v hairpin on.", hostIf.Name)
err = netlink.SetLinkHairpin(hostIf.Name, true)
if err != nil {
goto cleanup
}

// Bridge up.
log.Printf("[net] Setting link %v state up.", bridgeName)
err = netlink.SetLinkState(bridgeName, true)
Expand Down

0 comments on commit 3755884

Please sign in to comment.