// NewProxier returns a new Proxier given an iptables Interface instance. // Because of the iptables logic, it is assumed that there is only a single Proxier active on a machine. // An error will be returned if iptables fails to update or acquire the initial lock. // Once a proxier is created, it will keep iptables up to date in the background and // will not terminate if a particular iptables call fails. func NewProxier(ipt utiliptables.Interface, exec utilexec.Interface, syncPeriod time.Duration) (*Proxier, error) { // Set the route_localnet sysctl we need for if err := setSysctl(sysctlRouteLocalnet, 1); err != nil { return nil, fmt.Errorf("can't set sysctl %s: %v", sysctlRouteLocalnet, err) } // Load the module. It's OK if this fails (e.g. the module is not present) // because we'll catch the error on the sysctl, which is what we actually // care about. exec.Command("modprobe", "br-netfilter").CombinedOutput() if err := setSysctl(sysctlBridgeCallIptables, 1); err != nil { return nil, fmt.Errorf("can't set sysctl %s: %v", sysctlBridgeCallIptables, err) } // No turning back. Remove artifacts that might still exist from the userspace Proxier. glog.V(2).Info("Tearing down userspace rules. Errors here are acceptable.") tearDownUserspaceIptables(ipt) return &Proxier{ serviceMap: make(map[proxy.ServicePortName]*serviceInfo), syncPeriod: syncPeriod, iptables: ipt, }, nil }
func findPairInterfaceOfContainerInterface(e exec.Interface, containerInterfaceName, containerDesc string, nsenterArgs []string) (string, error) { nsenterPath, err := e.LookPath("nsenter") if err != nil { return "", err } ethtoolPath, err := e.LookPath("ethtool") if err != nil { return "", err } nsenterArgs = append(nsenterArgs, "-F", "--", ethtoolPath, "--statistics", containerInterfaceName) output, err := e.Command(nsenterPath, nsenterArgs...).CombinedOutput() if err != nil { return "", fmt.Errorf("Unable to query interface %s of container %s: %v: %s", containerInterfaceName, containerDesc, err, string(output)) } // look for peer_ifindex match := ethtoolOutputRegex.FindSubmatch(output) if match == nil { return "", fmt.Errorf("No peer_ifindex in interface statistics for %s of container %s", containerInterfaceName, containerDesc) } peerIfIndex, err := strconv.Atoi(string(match[1])) if err != nil { // seems impossible (\d+ not numeric) return "", fmt.Errorf("peer_ifindex wasn't numeric: %s: %v", match[1], err) } iface, err := net.InterfaceByIndex(peerIfIndex) if err != nil { return "", err } return iface.Name, nil }
// NewProxier returns a new Proxier given an iptables Interface instance. // Because of the iptables logic, it is assumed that there is only a single Proxier active on a machine. // An error will be returned if iptables fails to update or acquire the initial lock. // Once a proxier is created, it will keep iptables up to date in the background and // will not terminate if a particular iptables call fails. func NewProxier(ipt utiliptables.Interface, exec utilexec.Interface, syncPeriod time.Duration, masqueradeAll bool, masqueradeBit int) (*Proxier, error) { // Set the route_localnet sysctl we need for if err := utilsysctl.SetSysctl(sysctlRouteLocalnet, 1); err != nil { return nil, fmt.Errorf("can't set sysctl %s: %v", sysctlRouteLocalnet, err) } // Load the module. It's OK if this fails (e.g. the module is not present) // because we'll catch the error on the sysctl, which is what we actually // care about. exec.Command("modprobe", "br-netfilter").CombinedOutput() if err := utilsysctl.SetSysctl(sysctlBridgeCallIptables, 1); err != nil { glog.Warningf("can't set sysctl %s: %v", sysctlBridgeCallIptables, err) } // Generate the masquerade mark to use for SNAT rules. if masqueradeBit < 0 || masqueradeBit > 31 { return nil, fmt.Errorf("invalid iptables-masquerade-bit %v not in [0, 31]", masqueradeBit) } masqueradeValue := 1 << uint(masqueradeBit) masqueradeMark := fmt.Sprintf("%#08x/%#08x", masqueradeValue, masqueradeValue) return &Proxier{ serviceMap: make(map[proxy.ServicePortName]*serviceInfo), endpointsMap: make(map[proxy.ServicePortName][]string), portsMap: make(map[localPort]closeable), syncPeriod: syncPeriod, iptables: ipt, masqueradeAll: masqueradeAll, masqueradeMark: masqueradeMark, }, nil }
// Runs "iptables --version" to get the version string func getIptablesVersionString(exec utilexec.Interface) (string, error) { // this doesn't access mutable state so we don't need to use the interface / runner bytes, err := exec.Command(cmdIptables, "--version").CombinedOutput() if err != nil { return "", err } return string(bytes), nil }
// Runs "iptables --version" to get the version string func getIptablesVersionString(exec utilexec.Interface) (string, error) { bytes, err := exec.Command("iptables", "--version").CombinedOutput() if err != nil { return "", err } return string(bytes), nil }
// given a LUN find the VHD device path like /dev/sdb // VHD disks under sysfs are like /sys/bus/scsi/devices/3:0:1:0 // return empty string if no disk is found func findDiskByLun(lun int, io ioHandler, exe exec.Interface) (string, error) { var err error sys_path := "/sys/bus/scsi/devices" if dirs, err := io.ReadDir(sys_path); err == nil { for _, f := range dirs { name := f.Name() // look for path like /sys/bus/scsi/devices/3:0:1:0 arr := strings.Split(name, ":") if len(arr) < 4 { continue } target, err := strconv.Atoi(arr[0]) if err != nil { glog.Errorf("failed to parse target from %v (%v), err %v", arr[0], name, err) continue } // as observed, targets 0-3 are used by OS disks. Skip them if target > 3 { l, err := strconv.Atoi(arr[3]) if err != nil { // unknown path format, continue to read the next one glog.Errorf("failed to parse lun from %v (%v), err %v", arr[3], name, err) continue } if lun == l { // find the matching LUN // read vendor and model to ensure it is a VHD disk vendor := path.Join(sys_path, name, "vendor") model := path.Join(sys_path, name, "model") out, err := exe.Command("cat", vendor, model).CombinedOutput() if err != nil { glog.Errorf("failed to cat device vendor and model, err: %v", err) continue } matched, err := regexp.MatchString("^MSFT[ ]{0,}\nVIRTUAL DISK[ ]{0,}\n$", strings.ToUpper(string(out))) if err != nil || !matched { glog.V(4).Infof("doesn't match VHD, output %v, error %v", string(out), err) continue } // find it! dir := path.Join(sys_path, name, "block") dev, err := io.ReadDir(dir) if err != nil { glog.Errorf("failed to read %s", dir) } else { return "/dev/" + dev[0].Name(), nil } } } } } return "", err }
// getIptablesVersionString runs "iptables --version" to get the version string // in the form "X.X.X" func getIptablesVersionString(exec utilexec.Interface) (string, error) { // this doesn't access mutable state so we don't need to use the interface / runner bytes, err := exec.Command(cmdIptables, "--version").CombinedOutput() if err != nil { return "", err } versionMatcher := regexp.MustCompile("v([0-9]+\\.[0-9]+\\.[0-9]+)") match := versionMatcher.FindStringSubmatch(string(bytes)) if match == nil { return "", fmt.Errorf("no iptables version found in string: %s", bytes) } return match[1], nil }
// NewProxier returns a new Proxier given an iptables Interface instance. // Because of the iptables logic, it is assumed that there is only a single Proxier active on a machine. // An error will be returned if iptables fails to update or acquire the initial lock. // Once a proxier is created, it will keep iptables up to date in the background and // will not terminate if a particular iptables call fails. func NewProxier(ipt utiliptables.Interface, exec utilexec.Interface, syncPeriod time.Duration, masqueradeAll bool) (*Proxier, error) { // Set the route_localnet sysctl we need for if err := setSysctl(sysctlRouteLocalnet, 1); err != nil { return nil, fmt.Errorf("can't set sysctl %s: %v", sysctlRouteLocalnet, err) } // Load the module. It's OK if this fails (e.g. the module is not present) // because we'll catch the error on the sysctl, which is what we actually // care about. exec.Command("modprobe", "br-netfilter").CombinedOutput() if err := setSysctl(sysctlBridgeCallIptables, 1); err != nil { return nil, fmt.Errorf("can't set sysctl %s: %v", sysctlBridgeCallIptables, err) } return &Proxier{ serviceMap: make(map[proxy.ServicePortName]*serviceInfo), portsMap: make(map[localPort]closeable), syncPeriod: syncPeriod, iptables: ipt, masqueradeAll: masqueradeAll, }, nil }
func getOnePodIP(execer utilexec.Interface, nsenterPath, netnsPath, interfaceName, addrType string) (net.IP, error) { // Try to retrieve ip inside container network namespace output, err := execer.Command(nsenterPath, fmt.Sprintf("--net=%s", netnsPath), "-F", "--", "ip", "-o", addrType, "addr", "show", "dev", interfaceName, "scope", "global").CombinedOutput() if err != nil { return nil, fmt.Errorf("Unexpected command output %s with error: %v", output, err) } lines := strings.Split(string(output), "\n") if len(lines) < 1 { return nil, fmt.Errorf("Unexpected command output %s", output) } fields := strings.Fields(lines[0]) if len(fields) < 4 { return nil, fmt.Errorf("Unexpected address output %s ", lines[0]) } ip, _, err := net.ParseCIDR(fields[3]) if err != nil { return nil, fmt.Errorf("CNI failed to parse ip from output %s due to %v", output, err) } return ip, nil }