Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fetch MTU from the nodeIP interface #10635

Merged
merged 1 commit into from Jun 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 7 additions & 1 deletion daemon/cmd/daemon.go
Expand Up @@ -289,7 +289,13 @@ func NewDaemon(ctx context.Context, dp datapath.Datapath) (*Daemon, *endpointRes
return nil, nil, fmt.Errorf("unable to setup encryption: %s", err)
}

mtuConfig := mtu.NewConfiguration(authKeySize, option.Config.EnableIPSec, option.Config.Tunnel != option.TunnelDisabled, configuredMTU)
var mtuConfig mtu.Configuration
externalIP := node.GetExternalIPv4()
if externalIP == nil {
externalIP = node.GetIPv6()
}
// ExternalIP could be nil but we are covering that case inside NewConfiguration
mtuConfig = mtu.NewConfiguration(authKeySize, option.Config.EnableIPSec, option.Config.Tunnel != option.TunnelDisabled, configuredMTU, externalIP)

nodeMngr, err := nodemanager.NewManager("all", dp.Node(), ipcache.IPIdentityCache, option.Config)
if err != nil {
Expand Down
14 changes: 7 additions & 7 deletions daemon/cmd/status_test.go
Expand Up @@ -82,7 +82,7 @@ func (g *GetNodesSuite) Test_getNodesHandle(c *C) {
{
name: "create a client ID and store it locally",
setupArgs: func() args {
nodeDiscovery := nodediscovery.NewNodeDiscovery(nm, mtu.NewConfiguration(0, false, false, 0), &cnitypes.NetConf{})
nodeDiscovery := nodediscovery.NewNodeDiscovery(nm, mtu.NewConfiguration(0, false, false, 0, nil), &cnitypes.NetConf{})
nodeDiscovery.LocalNode.Name = "foo"
return args{
params: GetClusterNodesParams{
Expand Down Expand Up @@ -114,7 +114,7 @@ func (g *GetNodesSuite) Test_getNodesHandle(c *C) {
{
name: "retrieve nodes diff from a client that was already present",
setupArgs: func() args {
nodeDiscovery := nodediscovery.NewNodeDiscovery(nm, mtu.NewConfiguration(0, false, false, 0), &cnitypes.NetConf{})
nodeDiscovery := nodediscovery.NewNodeDiscovery(nm, mtu.NewConfiguration(0, false, false, 0, nil), &cnitypes.NetConf{})
nodeDiscovery.LocalNode.Name = "foo"
return args{
params: GetClusterNodesParams{
Expand Down Expand Up @@ -168,7 +168,7 @@ func (g *GetNodesSuite) Test_getNodesHandle(c *C) {
{
name: "retrieve nodes from an expired client, it should be ok because the clean up only happens when on insertion",
setupArgs: func() args {
nodeDiscovery := nodediscovery.NewNodeDiscovery(nm, mtu.NewConfiguration(0, false, false, 0), &cnitypes.NetConf{})
nodeDiscovery := nodediscovery.NewNodeDiscovery(nm, mtu.NewConfiguration(0, false, false, 0, nil), &cnitypes.NetConf{})
nodeDiscovery.LocalNode.Name = "foo"
return args{
params: GetClusterNodesParams{
Expand Down Expand Up @@ -223,7 +223,7 @@ func (g *GetNodesSuite) Test_getNodesHandle(c *C) {
{
name: "retrieve nodes for a new client, the expired client should be deleted",
setupArgs: func() args {
nodeDiscovery := nodediscovery.NewNodeDiscovery(nm, mtu.NewConfiguration(0, false, false, 0), &cnitypes.NetConf{})
nodeDiscovery := nodediscovery.NewNodeDiscovery(nm, mtu.NewConfiguration(0, false, false, 0, nil), &cnitypes.NetConf{})
nodeDiscovery.LocalNode.Name = "foo"
return args{
params: GetClusterNodesParams{
Expand Down Expand Up @@ -273,7 +273,7 @@ func (g *GetNodesSuite) Test_getNodesHandle(c *C) {
{
name: "retrieve nodes for a new client, however the randomizer allocated an existing clientID, so we should return a empty clientID",
setupArgs: func() args {
nodeDiscovery := nodediscovery.NewNodeDiscovery(nm, mtu.NewConfiguration(0, false, false, 0), &cnitypes.NetConf{})
nodeDiscovery := nodediscovery.NewNodeDiscovery(nm, mtu.NewConfiguration(0, false, false, 0, nil), &cnitypes.NetConf{})
nodeDiscovery.LocalNode.Name = "foo"
return args{
params: GetClusterNodesParams{
Expand Down Expand Up @@ -323,7 +323,7 @@ func (g *GetNodesSuite) Test_getNodesHandle(c *C) {
{
name: "retrieve nodes for a client that does not want to have diffs, leave all other stored clients alone",
setupArgs: func() args {
nodeDiscovery := nodediscovery.NewNodeDiscovery(nm, mtu.NewConfiguration(0, false, false, 0), &cnitypes.NetConf{})
nodeDiscovery := nodediscovery.NewNodeDiscovery(nm, mtu.NewConfiguration(0, false, false, 0, nil), &cnitypes.NetConf{})
nodeDiscovery.LocalNode.Name = "foo"
return args{
params: GetClusterNodesParams{},
Expand Down Expand Up @@ -433,7 +433,7 @@ func (g *GetNodesSuite) Test_cleanupClients(c *C) {
h := &getNodes{
clients: args.clients,
d: &Daemon{
nodeDiscovery: nodediscovery.NewNodeDiscovery(nm, mtu.NewConfiguration(0, false, false, 0), &cnitypes.NetConf{}),
nodeDiscovery: nodediscovery.NewNodeDiscovery(nm, mtu.NewConfiguration(0, false, false, 0, nil), &cnitypes.NetConf{}),
},
}
h.cleanupClients()
Expand Down
2 changes: 1 addition & 1 deletion pkg/datapath/linux/node_linux_test.go
Expand Up @@ -71,7 +71,7 @@ const (
func (s *linuxPrivilegedBaseTestSuite) SetUpTest(c *check.C, addressing datapath.NodeAddressing, enableIPv6, enableIPv4 bool) {
bpf.ConfigureResourceLimits()
s.nodeAddressing = addressing
s.mtuConfig = mtu.NewConfiguration(0, false, false, 1500)
s.mtuConfig = mtu.NewConfiguration(0, false, false, 1500, nil)
s.enableIPv6 = enableIPv6
s.enableIPv4 = enableIPv4

Expand Down
3 changes: 3 additions & 0 deletions pkg/logging/logfields/logfields.go
Expand Up @@ -168,6 +168,9 @@ const (
// CIDR is a IPv4/IPv4 subnet/CIDR
CIDR = "cidr"

// MTU is the maximum transmission unit of one interface
MTU = "mtu"

// Interface is an interface id/name on the system
Interface = "interface"

Expand Down
6 changes: 6 additions & 0 deletions pkg/mtu/detect_darwin.go
Expand Up @@ -16,6 +16,12 @@

package mtu

import "net"

func autoDetect() (int, error) {
return EthernetMTU, nil
}

func getMTUFromIf(net.IP) (int, error) {
return EthernetMTU, nil
}
45 changes: 45 additions & 0 deletions pkg/mtu/detect_linux.go
Expand Up @@ -20,6 +20,10 @@ import (
"fmt"
"net"

"github.com/cilium/cilium/pkg/logging/logfields"

"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/vishvananda/netlink"
)

Expand Down Expand Up @@ -75,3 +79,44 @@ func autoDetect() (int, error) {

return EthernetMTU, nil
}

// getMTUFromIf finds the interface that holds the ip and returns its mtu
func getMTUFromIf(ip net.IP) (int, error) {
manuelbuil marked this conversation as resolved.
Show resolved Hide resolved
ifaces, err := net.Interfaces()
if err != nil {
return 0, errors.Wrap(err, "Unable to list interfaces")
}

for _, iface := range ifaces {
addrs, err := iface.Addrs()
if err != nil {
log.WithFields(logrus.Fields{
logfields.Device: iface.Name,
}).Warning("Unable to list all addresses")
continue
}

for _, addr := range addrs {
myIP, _, err := net.ParseCIDR(addr.String())

if err != nil {
log.WithFields(logrus.Fields{
logfields.Device: iface.Name,
logfields.IPAddr: addr,
}).Warning("Unable parse the address")
continue
}

if myIP.Equal(ip) == true {
myMTU := iface.MTU
log.WithFields(logrus.Fields{
logfields.Device: iface.Name,
logfields.IPAddr: ip,
logfields.MTU: myMTU,
}).Info("Inheriting MTU from external network interface")
return myMTU, nil
}
}
}
return 0, fmt.Errorf("No interface contains the provided ip: %v", ip)
}
10 changes: 8 additions & 2 deletions pkg/mtu/mtu.go
Expand Up @@ -14,6 +14,8 @@

package mtu

import "net"

const (
// MaxMTU is the highest MTU that can be used for devices and routes
// handled by Cilium. It will typically be used to configure inbound
Expand Down Expand Up @@ -96,13 +98,17 @@ type Configuration struct {
// specified, otherwise it will be automatically detected. if encapEnabled is
// true, the MTU is adjusted to account for encapsulation overhead for all
// routes involved in node to node communication.
func NewConfiguration(authKeySize int, encryptEnabled bool, encapEnabled bool, mtu int) Configuration {
func NewConfiguration(authKeySize int, encryptEnabled bool, encapEnabled bool, mtu int, mtuDetectIP net.IP) Configuration {
encryptOverhead := 0

if mtu == 0 {
var err error

mtu, err = autoDetect()
if mtuDetectIP != nil {
mtu, err = getMTUFromIf(mtuDetectIP)
} else {
mtu, err = autoDetect()
}
if err != nil {
log.WithError(err).Warning("Unable to automatically detect MTU")
mtu = EthernetMTU
Expand Down
36 changes: 26 additions & 10 deletions pkg/mtu/mtu_test.go
Expand Up @@ -17,6 +17,7 @@
package mtu

import (
"net"
"testing"

. "gopkg.in/check.v1"
Expand All @@ -30,48 +31,63 @@ var _ = Suite(&MTUSuite{})

func (m *MTUSuite) TestNewConfiguration(c *C) {
// Add routes with no encryption or tunnel
conf := NewConfiguration(0, false, false, 0)
conf := NewConfiguration(0, false, false, 0, nil)
c.Assert(conf.GetDeviceMTU(), Not(Equals), 0)
c.Assert(conf.GetRouteMTU(), Equals, conf.GetDeviceMTU())

// Add routes with no encryption or tunnel and set MTU
conf = NewConfiguration(0, false, false, 1400)
conf = NewConfiguration(0, false, false, 1400, nil)
c.Assert(conf.GetDeviceMTU(), Equals, 1400)
c.Assert(conf.GetRouteMTU(), Equals, conf.GetDeviceMTU())

// Add routes with tunnel
conf = NewConfiguration(0, false, true, 1400)
conf = NewConfiguration(0, false, true, 1400, nil)
c.Assert(conf.GetDeviceMTU(), Equals, 1400)
c.Assert(conf.GetRouteMTU(), Equals, conf.GetDeviceMTU()-TunnelOverhead)

// Add routes with tunnel and set MTU
conf = NewConfiguration(0, false, true, 1400)
conf = NewConfiguration(0, false, true, 1400, nil)
c.Assert(conf.GetDeviceMTU(), Equals, 1400)
c.Assert(conf.GetRouteMTU(), Equals, conf.GetDeviceMTU()-TunnelOverhead)

// Add routes with encryption and set MTU using standard 128bit, larger 256bit and smaller 96bit ICVlen keys
conf = NewConfiguration(16, true, false, 1400)
conf = NewConfiguration(16, true, false, 1400, nil)
c.Assert(conf.GetDeviceMTU(), Equals, 1400)
c.Assert(conf.GetRouteMTU(), Equals, conf.GetDeviceMTU()-EncryptionIPsecOverhead)

conf = NewConfiguration(32, true, false, 1400)
conf = NewConfiguration(32, true, false, 1400, nil)
c.Assert(conf.GetDeviceMTU(), Equals, 1400)
c.Assert(conf.GetRouteMTU(), Equals, conf.GetDeviceMTU()-(EncryptionIPsecOverhead+16))

conf = NewConfiguration(12, true, false, 1400)
conf = NewConfiguration(12, true, false, 1400, nil)
c.Assert(conf.GetDeviceMTU(), Equals, 1400)
c.Assert(conf.GetRouteMTU(), Equals, conf.GetDeviceMTU()-(EncryptionIPsecOverhead-4))

// Add routes with encryption and tunnels using standard 128bit, larger 256bit and smaller 96bit ICVlen keys
conf = NewConfiguration(16, true, true, 1400)
conf = NewConfiguration(16, true, true, 1400, nil)
c.Assert(conf.GetDeviceMTU(), Equals, 1400)
c.Assert(conf.GetRouteMTU(), Equals, conf.GetDeviceMTU()-(TunnelOverhead+EncryptionIPsecOverhead))

conf = NewConfiguration(32, true, true, 1400)
conf = NewConfiguration(32, true, true, 1400, nil)
c.Assert(conf.GetDeviceMTU(), Equals, 1400)
c.Assert(conf.GetRouteMTU(), Equals, conf.GetDeviceMTU()-(TunnelOverhead+EncryptionIPsecOverhead+16))

conf = NewConfiguration(32, true, true, 1400)
conf = NewConfiguration(32, true, true, 1400, nil)
c.Assert(conf.GetDeviceMTU(), Equals, 1400)
c.Assert(conf.GetRouteMTU(), Equals, conf.GetDeviceMTU()-(TunnelOverhead+EncryptionIPsecOverhead+16))

testIP1 := net.IPv4(0, 0, 0, 0)
testIP2 := net.IPv4(127, 0, 0, 1)
result, _ := getMTUFromIf(testIP1)
c.Assert(result, Equals, 0)

conf = NewConfiguration(0, true, true, 1400, testIP1)
c.Assert(conf.GetDeviceMTU(), Equals, 1400)

conf = NewConfiguration(0, true, true, 0, testIP1)
c.Assert(conf.GetDeviceMTU(), Equals, 1500)

// Assuming loopback interface always exists and has mtu=65536
conf = NewConfiguration(0, true, true, 0, testIP2)
c.Assert(conf.GetDeviceMTU(), Equals, 65536)
}