Skip to content

Commit

Permalink
agent: Add more route information
Browse files Browse the repository at this point in the history
  • Loading branch information
ish-hcc committed Sep 20, 2024
1 parent 44e24e0 commit 36720ce
Show file tree
Hide file tree
Showing 12 changed files with 259 additions and 106 deletions.
2 changes: 1 addition & 1 deletion agent/driver/network/nic_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func GetNICs() ([]network2.NIC, error) {

var defaultRoutes []routes.RouteStruct

defaultRoutes, err = routes.GetLinuxRoutes(true)
defaultRoutes, err = routes.GetRoutes(true)
if err != nil {
return nics, err
}
Expand Down
2 changes: 1 addition & 1 deletion agent/driver/network/nic_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func GetNICs() ([]network2.NIC, error) {

var defaultRoutes []routes.RouteStruct

defaultRoutes, err = routes.GetWindowsRoutes(true)
defaultRoutes, err = routes.GetRoutes(true)
if err != nil {
return networkInterfaces, err
}
Expand Down
92 changes: 92 additions & 0 deletions agent/driver/network/routes_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
//go:build linux

package network

import (
"github.com/cloud-barista/cm-honeybee/agent/lib/routes"
"github.com/cloud-barista/cm-honeybee/agent/pkg/api/rest/model/onprem/network"
"github.com/vishvananda/netlink"
)

func GetRoutes() ([]network.Route, error) {
var rs []network.Route
var osRoutes []routes.RouteStruct
var err error

osRoutes, err = routes.GetRoutes(false)
if err != nil {
return rs, err
}

type routeExt struct {
Source string
Scope string
Proto string
Link string
}
var routeExts = make(map[string]routeExt)

rts, err := netlink.RouteList(nil, netlink.FAMILY_ALL)
if err != nil {
return rs, err
}
for _, rt := range rts {
iface := "N/A"
linkState := ""

if rt.LinkIndex != 0 {
link, err := netlink.LinkByIndex(rt.LinkIndex)
if err == nil {
iface = link.Attrs().Name
if iface == "N/A" {
continue
}

if link.Attrs().OperState == netlink.OperUp {
linkState = "up"
} else {
linkState = "down"
}
}
}

source := ""
if rt.Src != nil {
source = rt.Src.String()
}
scope := rt.Scope.String()
protocol := rt.Protocol.String()

routeExts[iface] = routeExt{
Source: source,
Scope: scope,
Proto: protocol,
Link: linkState,
}
}

for _, r := range osRoutes {
if r.NextHop == "on-link" {
r.NextHop = r.Interface
}

rt := network.Route{
Destination: r.Destination,
Netmask: r.Netmask,
NextHop: r.NextHop,
Metric: r.Metric,
}

ext, ok := routeExts[r.Interface]
if ok {
rt.Source = ext.Source
rt.Scope = ext.Scope
rt.Proto = ext.Proto
rt.Link = ext.Link
}

rs = append(rs, rt)
}

return rs, nil
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,18 @@
//go:build windows

package network

import (
"errors"
"github.com/cloud-barista/cm-honeybee/agent/lib/routes"
"github.com/cloud-barista/cm-honeybee/agent/pkg/api/rest/model/onprem/network"
"runtime"
)

func GetRoutes() ([]network.Route, error) {
var rs []network.Route
var osRoutes []routes.RouteStruct
var err error

if runtime.GOOS == "linux" {
osRoutes, err = routes.GetLinuxRoutes(false)
} else if runtime.GOOS == "windows" {
osRoutes, err = routes.GetWindowsRoutes(false)
} else {
return rs, errors.New("unsupported OS")
}

osRoutes, err = routes.GetRoutes(false)
if err != nil {
return rs, err
}
Expand All @@ -32,8 +25,12 @@ func GetRoutes() ([]network.Route, error) {
rs = append(rs, network.Route{
Destination: r.Destination,
Netmask: r.Netmask,
Source: "N/A",
NextHop: r.NextHop,
Metric: r.Metric,
Scope: "N/A",
Proto: "N/A",
Link: "N/A",
})
}

Expand Down
2 changes: 2 additions & 0 deletions agent/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ require (
github.com/swaggo/swag v1.16.3
github.com/taigrr/systemctl v1.0.7
github.com/ulikunitz/xz v0.5.12
github.com/vishvananda/netlink v1.3.0
k8s.io/apimachinery v0.31.1
k8s.io/client-go v0.31.1
)
Expand Down Expand Up @@ -92,6 +93,7 @@ require (
github.com/tklauser/numcpus v0.8.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
github.com/vishvananda/netns v0.0.4 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 // indirect
Expand Down
6 changes: 6 additions & 0 deletions agent/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,10 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/vishvananda/netlink v1.3.0 h1:X7l42GfcV4S6E4vHTsw48qbrV+9PVojNfIhZcwQdrZk=
github.com/vishvananda/netlink v1.3.0/go.mod h1:i6NetklAujEcC6fK0JPjT8qSwWyO0HLn4UKG+hGqeJs=
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
Expand Down Expand Up @@ -259,7 +263,9 @@ golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//go:build linux

package routes

import (
Expand All @@ -6,12 +8,10 @@ import (
"encoding/binary"
"errors"
"fmt"
"github.com/jollaman999/utils/cmd"
"github.com/jollaman999/utils/logger"
"io"
"net"
"os"
"regexp"
"strconv"
"strings"
)
Expand All @@ -24,97 +24,6 @@ type RouteStruct struct {
Metric int
}

// Windows route output format is always like this:
// ===========================================================================
// Interface List
// 8 ...00 12 3f a7 17 ba ...... Intel(R) PRO/100 VE Network Connection
// 1 ........................... Software Loopback Interface 1
// ===========================================================================
// IPv4 Route Table
// ===========================================================================
// Active Routes:
// Network Destination Netmask Gateway Interface Metric
//
// 0.0.0.0 0.0.0.0 192.168.1.1 192.168.1.100 20
//
// ===========================================================================
//
// Windows commands are localized, so we can't just look for "Active Routes:" string
// I'm trying to pick the active route,
// then jump 2 lines and get the row
// Not using regex because output is quite standard from Windows XP to 8 (NEEDS TESTING)
//
// If multiple default gateways are present, then the one with the lowest metric is returned.
func GetWindowsRoutes(getOnlyDefaults bool) ([]RouteStruct, error) {
output, err := cmd.RunCMD("route print")
if err != nil {
errMsg := err.Error()
logger.Println(logger.ERROR, true, "ROUTES: "+errMsg)
return nil, errors.New(errMsg)
}

const (
destinationField = 0 // field containing string dotted destination IP address
netmaskField = 1 // field containing string dotted netmask
gatewayField = 2 // field containing string dotted gateway IP address
interfaceField = 3 // field containing string dotted interface IP address
metricField = 4 // field containing string metric
)

ipRegex := regexp.MustCompile(`^(((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4})`)
var routes []RouteStruct
lines := strings.Split(output, "\n")
sep := 0
for idx, line := range lines {
if sep == 3 {
// We just entered the 2nd section containing "Active Routes:"
if len(lines) <= idx+2 {
return []RouteStruct{}, nil
}

inputLine := lines[idx+2]
if strings.HasPrefix(inputLine, "=======") {
// End of routes
break
}
fields := strings.Fields(inputLine)
if len(fields) < 5 || !ipRegex.MatchString(fields[0]) {
errMsg := "invalid filed found"
logger.Println(logger.ERROR, true, "ROUTES: "+errMsg)
return nil, errors.New(errMsg)
}

// found default route
if getOnlyDefaults && (fields[destinationField] != "0.0.0.0" || fields[netmaskField] != "0.0.0.0") {
continue
}

metric, _ := strconv.Atoi(fields[metricField])

routes = append(routes, RouteStruct{
Interface: fields[interfaceField],
Destination: fields[destinationField],
Netmask: fields[netmaskField],
NextHop: strings.ToLower(fields[gatewayField]),
Metric: metric,
})
}
if strings.HasPrefix(line, "=======") {
sep++
continue
}
}

if sep == 0 {
// We saw no separator lines, so input must have been garbage.
errMsg := "got invalid result from route command"
logger.Println(logger.ERROR, true, "ROUTES: "+errMsg)
return nil, errors.New(errMsg)
}

return routes, nil
}

func linuxLittleEndianHexToNetIP(hex string) (net.IP, error) {
netIP := make(net.IP, 4)

Expand All @@ -141,7 +50,7 @@ func linuxLittleEndianHexToNetIP(hex string) (net.IP, error) {
// Iface Destination Gateway Flags RefCnt Use Metric Mask
// eno1 00000000 C900A8C0 0003 0 0 100 00000000 0 00
// eno1 0000A8C0 00000000 0001 0 0 100 00FFFFFF 0 00
func GetLinuxRoutes(getOnlyDefaults bool) ([]RouteStruct, error) {
func GetRoutes(getOnlyDefaults bool) ([]RouteStruct, error) {
var file = "/proc/net/route"

f, err := os.Open(file)
Expand Down
Loading

0 comments on commit 36720ce

Please sign in to comment.