From 2c62df234c8fed34795c72b99be626ab85face92 Mon Sep 17 00:00:00 2001 From: matt Date: Tue, 20 Jun 2017 11:33:52 -0700 Subject: [PATCH] Added iface-regex option Allows for more flexibility when selecting the network interface that flannel should be using. Addresses #620 --- Documentation/configuration.md | 1 + main.go | 50 ++++++++++++++++++++++++++++++++-- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/Documentation/configuration.md b/Documentation/configuration.md index 65cf209514642..9131d9c08d59a 100644 --- a/Documentation/configuration.md +++ b/Documentation/configuration.md @@ -54,6 +54,7 @@ The following configuration illustrates the use of most options with `udp` backe --etcd-cafile="": SSL Certificate Authority file used to secure etcd communication. --kube-subnet-mgr: Contact the Kubernetes API for subnet assignment instead of etcd. --iface="": interface to use (IP or name) for inter-host communication. Defaults to the interface for the default route on the machine. +--iface-regex="": regex expression to match the first interface to use (IP or name) for inter-host communication. If unspecified, will default to the interface for the default route on the machine. This option is superseded by the iface option and will not be used if the iface option is also specified. --subnet-file=/run/flannel/subnet.env: filename where env variables (subnet and MTU values) will be written to. --subnet-lease-renew-margin=60: subnet lease renewal margin, in minutes. --ip-masq=false: setup IP masquerade for traffic destined for outside the flannel network. Flannel assumes that the default policy is ACCEPT in the NAT POSTROUTING chain. diff --git a/main.go b/main.go index 7cc2b30f0200e..efb75cc0bd1ca 100644 --- a/main.go +++ b/main.go @@ -23,6 +23,7 @@ import ( "os" "os/signal" "path/filepath" + "regexp" "strconv" "strings" "syscall" @@ -65,6 +66,7 @@ type CmdLineOpts struct { version bool kubeSubnetMgr bool iface string + ifaceRegex string ipMasq bool subnetFile string subnetDir string @@ -89,6 +91,7 @@ func init() { flag.StringVar(&opts.etcdUsername, "etcd-username", "", "Username for BasicAuth to etcd") flag.StringVar(&opts.etcdPassword, "etcd-password", "", "Password for BasicAuth to etcd") flag.StringVar(&opts.iface, "iface", "", "interface to use (IP or name) for inter-host communication") + flag.StringVar(&opts.ifaceRegex, "iface-regex", "", "regex expression to match the first interface to use (IP or name) for inter-host communication. Skipped if the iface option is also specified") flag.StringVar(&opts.subnetFile, "subnet-file", "/run/flannel/subnet.env", "filename where env variables (subnet, MTU, ... ) will be written to") flag.StringVar(&opts.publicIP, "public-ip", "", "IP accessible by other nodes for inter-host communication") flag.IntVar(&opts.subnetLeaseRenewMargin, "subnet-lease-renew-margin", 60, "Subnet lease renewal margin, in minutes.") @@ -140,7 +143,7 @@ func main() { flagutil.SetFlagsFromEnv(flag.CommandLine, "FLANNELD") // Work out which interface to use - extIface, err := LookupExtIface(opts.iface) + extIface, err := LookupExtIface(opts.iface, opts.ifaceRegex) if err != nil { log.Error("Failed to find interface to use: ", err) os.Exit(1) @@ -306,7 +309,7 @@ func MonitorLease(ctx context.Context, sm subnet.Manager, bn backend.Network) er } } -func LookupExtIface(ifname string) (*backend.ExternalInterface, error) { +func LookupExtIface(ifname string, ifregex string) (*backend.ExternalInterface, error) { var iface *net.Interface var ifaceAddr net.IP var err error @@ -324,6 +327,49 @@ func LookupExtIface(ifname string) (*backend.ExternalInterface, error) { return nil, fmt.Errorf("error looking up interface %s: %s", ifname, err) } } + } else if len(ifregex) > 0 { + // Use the regex if specified and the iface option for matching a specific ip or name is not used + ifaces, err := net.Interfaces() + if err != nil { + return nil, fmt.Errorf("error listing all interfaces: %s", err) + } + + // Check IP + for _, ifaceToMatch := range ifaces { + ifaceIP, err := ip.GetIfaceIP4Addr(&ifaceToMatch) + if err != nil { + // Skip if there is no IPv4 address + continue + } + + matched, err := regexp.MatchString(ifregex, ifaceIP.String()) + if err != nil { + return nil, fmt.Errorf("regex error matching pattern %s to %s", ifregex, ifaceIP.String()) + } + + if matched { + ifaceAddr = ifaceIP + iface = &ifaceToMatch + break + } + } + + // Check Name + if iface == nil && ifaceAddr == nil { + for _, ifaceToMatch := range ifaces { + matched, err := regexp.MatchString(ifregex, ifaceToMatch.Name) + if err != nil { + return nil, fmt.Errorf("regex error matching pattern %s to %s", ifregex, ifaceToMatch.Name) + } + + if matched { + iface = &ifaceToMatch + break + } + } + } + + return nil, fmt.Errorf("Could not match pattern %s to any of the available network interfaces", ifregex) } else { log.Info("Determining IP address of default interface") if iface, err = ip.GetDefaultGatewayIface(); err != nil {