Skip to content

Commit

Permalink
Get map of interface name to index (#4)
Browse files Browse the repository at this point in the history
Call into "netsh int ipv4 get int" to get interface ID,
map the ID into the IPV4 structs via the interface name
  • Loading branch information
jroggeman authored Oct 23, 2017
1 parent dd3cd37 commit b076c6b
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 5 deletions.
80 changes: 79 additions & 1 deletion netsh/netsh.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/golang/glog"
utilexec "k8s.io/utils/exec"
"errors"
)

// Interface is an injectable interface for running netsh commands. Implementations must be goroutine-safe.
Expand Down Expand Up @@ -46,6 +47,7 @@ type runner struct {

// Ipv4Interface models IPv4 interface output from: netsh interface ipv4 show addresses
type Ipv4Interface struct {
Idx int
Name string
InterfaceMetric int
DhcpEnabled bool
Expand All @@ -68,8 +70,35 @@ func New(exec utilexec.Interface) Interface {
return runner
}

// GetInterfaces uses the show addresses command and returns a formatted structure
func (runner *runner) GetInterfaces() ([]Ipv4Interface, error) {
interfaces, interfaceError := runner.getIpAddressConfigurations()

if interfaceError != nil {
return nil, interfaceError
}

indexMap, indexError := runner.getNetworkInterfaceParameters()

if indexError != nil {
return nil, indexError
}

// zip them up
for _, inter := range interfaces {
name := inter.Name

if val, ok := indexMap[name]; ok {
inter.Idx = val
} else {
return nil, fmt.Errorf("no index found for interface \"%v\"", name)
}
}

return interfaces, nil
}

// GetInterfaces uses the show addresses command and returns a formatted structure
func (runner *runner) getIpAddressConfigurations() ([]Ipv4Interface, error) {
args := []string{
"interface", "ipv4", "show", "addresses",
}
Expand All @@ -85,6 +114,11 @@ func (runner *runner) GetInterfaces() ([]Ipv4Interface, error) {
var currentInterface Ipv4Interface
quotedPattern := regexp.MustCompile("\\\"(.*?)\\\"")
cidrPattern := regexp.MustCompile("\\/(.*?)\\ ")

if err != nil {
return nil, err
}

for _, outputLine := range outputLines {
if strings.Contains(outputLine, "Configuration for interface") {
if currentInterface != (Ipv4Interface{}) {
Expand Down Expand Up @@ -138,6 +172,50 @@ func (runner *runner) GetInterfaces() ([]Ipv4Interface, error) {
return interfaces, nil
}

func (runner *runner) getNetworkInterfaceParameters() (map[string]int, error) {
args := []string{
"interface", "ipv4", "show", "interfaces",
}

output, err := runner.exec.Command(cmdNetsh, args...).CombinedOutput()

if err != nil {
return nil, err
}

// Split output by line
outputString := string(output[:])
outputString = strings.TrimSpace(outputString)
var outputLines = strings.Split(outputString, "\n")

if len(outputLines) < 3 {
return nil, errors.New("unexpected netsh output:\n" + outputString)
}

// Remove first two lines of header text
outputLines = outputLines[2:]

indexMap := make(map[string]int)

reg := regexp.MustCompile("\\s{2,}")

for _, line := range outputLines {

line = strings.TrimSpace(line)

// Split the line by two or more whitespace characters, returning all substrings (n < 0)
splitLine := reg.Split(line, -1)

name := splitLine[4]
if idx, err := strconv.Atoi(splitLine[0]); err == nil {
indexMap[name] = idx
}

}

return indexMap, nil
}

// Enable forwarding on the interface (name or index)
func (runner *runner) EnableForwarding(iface string) error {
args := []string{
Expand Down
45 changes: 41 additions & 4 deletions netsh/netsh_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ Configuration for interface "Loopback Pseudo-Interface 1"
exec: &fakeExec,
}

interfaces, err := runner.GetInterfaces()
interfaces, err := runner.getIpAddressConfigurations()
assert.NoError(t, err)
assert.EqualValues(t, 1, fakeCmd.CombinedOutputCalls)
assert.EqualValues(t, strings.Split("netsh interface ipv4 show addresses", " "), fakeCmd.CombinedOutputLog[0])
Expand Down Expand Up @@ -97,18 +97,55 @@ func TestGetInterfacesFailsGracefully(t *testing.T) {
exec: &fakeExec,
}

interfaces, err := runner.GetInterfaces()
interfaces, err := runner.getIpAddressConfigurations()
assert.Error(t, err)
assert.Nil(t, interfaces)

interfaces, err = runner.GetInterfaces()
interfaces, err = runner.getIpAddressConfigurations()
assert.Error(t, err)
assert.Nil(t, interfaces)

interfaces, err = runner.GetInterfaces()
interfaces, err = runner.getIpAddressConfigurations()
assert.Error(t, err)
assert.Nil(t, interfaces)

assert.EqualValues(t, 3, fakeCmd.CombinedOutputCalls)
assert.EqualValues(t, strings.Split("netsh interface ipv4 show addresses", " "), fakeCmd.CombinedOutputLog[0])
}

func TestGetInterfaceNameToIndexMap(t *testing.T) {
fake := utilexec.FakeCmd{
CombinedOutputScript: []utilexec.FakeCombinedOutputAction{
func() ([]byte, error) { return []byte(`badinput`), nil },
func() ([]byte, error) {
return []byte(`
Idx Met MTU State Name
--- ---------- ---------- ------------ ---------------------------
9 25 1500 connected Ethernet
1 75 4294967295 connected Loopback Pseudo-Interface 1
2 15 1500 connected vEthernet (New Virtual Switch)
14 15 1500 connected vEthernet (HNS Internal NIC)`), nil
},
},
}

fakeExec := getFakeExecTemplate(&fake)

runner := runner{
exec: &fakeExec,
}

// Test bad input
idxMap, err := runner.getNetworkInterfaceParameters()

assert.NotNil(t, err)
assert.Nil(t, idxMap)

// Test good input
idxMap, err = runner.getNetworkInterfaceParameters()

assert.Nil(t, err)
assert.NotNil(t, idxMap)
assert.Equal(t, 9, idxMap["Ethernet"])
assert.Equal(t, 14, idxMap["vEthernet (HNS Internal NIC)"])
}
4 changes: 4 additions & 0 deletions netsh/testing/fake_netsh.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ func (*FakeNetsh) GetInterfaces() ([]netsh.Ipv4Interface, error) {
return nil, nil
}

func (*FakeNetsh) GetInterfaceNameToIndexMap() (map[string]int, error) {
return map[string]int{}, nil
}

func (*FakeNetsh) EnsurePortProxyRule(args []string) (bool, error) {
return true, nil
}
Expand Down

0 comments on commit b076c6b

Please sign in to comment.