diff --git a/pkg/controllers/routing/network_routes_controller.go b/pkg/controllers/routing/network_routes_controller.go index c137de3a94..c639a40182 100644 --- a/pkg/controllers/routing/network_routes_controller.go +++ b/pkg/controllers/routing/network_routes_controller.go @@ -2,6 +2,7 @@ package routing import ( "context" + "encoding/json" "errors" "fmt" "io/ioutil" @@ -341,6 +342,46 @@ func (nrc *NetworkRoutingController) updateCNIConfig() { glog.Fatalf("Failed to insert `subnet`(pod CIDR) into CNI conf file: %s", err.Error()) } } + + err = nrc.autoConfigureMTU() + if err != nil { + glog.Fatalf("Failed to auto-configure MTU: %s", err.Error()) + } +} + +func (nrc *NetworkRoutingController) autoConfigureMTU() error { + mtu, err := getMTUFromNodeIP(nrc.nodeIP) + file, err := ioutil.ReadFile(nrc.cniConfFile) + if err != nil { + return fmt.Errorf("Failed to load CNI conf file: %s", err.Error()) + } + var config interface{} + err = json.Unmarshal(file, &config) + if err != nil { + return fmt.Errorf("Failed to parse JSON from CNI conf file: %s", err.Error()) + } + if strings.HasSuffix(nrc.cniConfFile, ".conflist") { + configMap := config.(map[string]interface{}) + for key := range configMap { + if key != "plugins" { + continue + } + pluginConfigs := configMap["plugins"].([]interface{}) + for _, pluginConfig := range pluginConfigs { + pluginConfigMap := pluginConfig.(map[string]interface{}) + pluginConfigMap["mtu"] = mtu + } + } + } else { + pluginConfig := config.(map[string]interface{}) + pluginConfig["mtu"] = mtu + } + configJSON, _ := json.Marshal(config) + err = ioutil.WriteFile(nrc.cniConfFile, configJSON, 0644) + if err != nil { + return fmt.Errorf("Failed to insert `mtu` into CNI conf file: %s", err.Error()) + } + return nil } func (nrc *NetworkRoutingController) watchBgpUpdates() { diff --git a/pkg/controllers/routing/utils.go b/pkg/controllers/routing/utils.go index fd21bdbda2..3b72913392 100644 --- a/pkg/controllers/routing/utils.go +++ b/pkg/controllers/routing/utils.go @@ -120,6 +120,26 @@ func getNodeSubnet(nodeIP net.IP) (net.IPNet, string, error) { return net.IPNet{}, "", errors.New("Failed to find interface with specified node ip") } +func getMTUFromNodeIP(nodeIP net.IP) (int, error) { + links, err := netlink.LinkList() + if err != nil { + return 0, errors.New("Failed to get list of links") + } + for _, link := range links { + addresses, err := netlink.AddrList(link, netlink.FAMILY_ALL) + if err != nil { + return 0, errors.New("Failed to get list of addr") + } + for _, addr := range addresses { + if addr.IPNet.IP.Equal(nodeIP) { + lintMTU := link.Attrs().MTU + return lintMTU - 20, nil // -20 to accommodate IPIP header + } + } + } + return 0, errors.New("Failed to find interface with specified node ip") +} + // generateTunnelName will generate a name for a tunnel interface given a node IP // for example, if the node IP is 10.0.0.1 the tunnel interface will be named tun-10001 // Since linux restricts interface names to 15 characters, if length of a node IP