Skip to content

Commit

Permalink
show route for veths
Browse files Browse the repository at this point in the history
Signed-off-by: tianyang ni <tianzong48@gmail.com>
  • Loading branch information
t1anz0ng committed Aug 24, 2022
1 parent abbc193 commit 60b872c
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 90 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ Example:
### text

```shell
sudo go run cmd/iftree/main.go
sudo iftree
```

### graph
Expand All @@ -73,13 +73,13 @@ Or create an ouput image with any [graphviz](https://www.graphviz.org/) compatib
e.g: online editor: https://dreampuf.github.io/GraphvizOnline

```shell
sudo go run cmd/iftree/main.go --graph -Tdot
sudo iftree --graph -Tdot
```

generate image using `dot`(http://www.graphviz.org/download/#executable-packages)

```shell
sudo go run cmd/iftree/main.go --graph -Tdot | dot -Tpng > output.png
sudo iftree --graph -Tdot | dot -Tpng > output.png
```

### table
Expand Down
75 changes: 35 additions & 40 deletions cmd/iftree/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"syscall"

"github.com/containerd/nerdctl/pkg/rootlessutil"
graphviz "github.com/goccy/go-graphviz"
log "github.com/sirupsen/logrus"
"github.com/spf13/pflag"
"github.com/vishvananda/netlink"
Expand All @@ -35,6 +34,8 @@ var (
help = pflag.BoolP("help", "h", false, "")

version = "unknown"

defaultOutput = os.Stdout
)

func init() {
Expand Down Expand Up @@ -139,13 +140,22 @@ func main() {
}
veth.PeerName = p.Attrs().Name
}
unBridgedVpairs = append(unBridgedVpairs,
pkg.Node{
Type: pkg.VethType,
Veth: veth.Name,
Peer: veth.PeerName,
PeerId: peerIdx,
NetNsID: veth.NetNsID})
routes, err := netlink.RouteList(link, 4)
if err != nil {
log.Fatal(err)
}
node := pkg.Node{
Type: pkg.VethType,
Veth: veth.Name,
Peer: veth.PeerName,
PeerId: peerIdx,
NetNsID: veth.NetNsID,
}
if len(routes) > 0 {
// TODO: more than one IP?
node.Route = routes[0].Dst.IP
}
unBridgedVpairs = append(unBridgedVpairs, node)
continue
}

Expand All @@ -156,7 +166,8 @@ func main() {

// if master is not bridge
if _, ok := master.(*netlink.Bridge); !ok {
log.Debug("todo: not bridge")
// TODO: what if master is not bridge?
continue
}
bridge := master.Attrs().Name
v, ok := bridgeVethM[bridge]
Expand Down Expand Up @@ -205,9 +216,10 @@ func main() {
}
log.Debugf("bridgeVethMap: %+v", bridgeVethM)

if *oGraph {
switch {
case *oGraph:
buf := bytes.Buffer{}
output, err := formatter.Graph(bridgeVethM, unBridgedVpairs, loS, bridgeIps)
output, err := formatter.GraphInDOT(bridgeVethM, unBridgedVpairs, loS, bridgeIps)
if err != nil {
log.Fatal(err)
}
Expand All @@ -216,48 +228,31 @@ func main() {

switch gType {
case "dot":
_, err = io.Copy(os.Stdout, &buf)
_, err = io.Copy(defaultOutput, &buf)
case "jpg", "png", "svg":
if !pflag.CommandLine.Changed("output") && !pflag.CommandLine.Changed("gtype") {
log.Warn(`default output dst file: "output.png"`)
}
graph, errG := graphviz.ParseBytes(buf.Bytes())
if errG != nil {
log.Fatal(errG)
}
g := graphviz.New()
fn := fmt.Sprintf("%s.%s", *oGraphName, gType)
f, errF := os.Create(fn)
if errF != nil {
log.Fatal(errF)
}
defer f.Close()
switch gType {
case "jpg":
err = g.Render(graph, graphviz.JPG, f)
case "png":
err = g.Render(graph, graphviz.PNG, f)
case "svg":
err = g.Render(graph, graphviz.SVG, f)
}
err = formatter.GenImage(buf.Bytes(), oGraphName, gType)
default:
log.Fatal("invalid graph type")
}
if err != nil {
log.Fatal(err)
}
return
}
if *oTable {
err := formatter.Table(os.Stdout, bridgeVethM)
if err != nil {
log.Fatal(err)
case *oTable:
if len(bridgeVethM) > 0 {
err := formatter.Table(defaultOutput, bridgeVethM)
if err != nil {
log.Fatal(err)
}
}
if *oNotBridgedVeths {
formatter.TableParis(os.Stdout, unBridgedVpairs)
if *oNotBridgedVeths && len(unBridgedVpairs) > 0 {
formatter.TableParis(defaultOutput, unBridgedVpairs)
}
return
default:
formatter.Print(defaultOutput, bridgeVethM, netNsMap, unBridgedVpairs, *oNotBridgedVeths)
}

formatter.Print(os.Stdout, bridgeVethM, netNsMap, unBridgedVpairs, *oNotBridgedVeths)
}
28 changes: 27 additions & 1 deletion pkg/formatter/graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ package formatter
import (
"fmt"
"net"
"os"
"strings"

"github.com/awalterschulze/gographviz"
graphviz "github.com/goccy/go-graphviz"
log "github.com/sirupsen/logrus"

"github.com/t1anz0ng/iftree/pkg"
)

func Graph(m map[string][]pkg.Node, vpairs, los []pkg.Node, bm map[string]*net.IP) (string, error) {
func GraphInDOT(m map[string][]pkg.Node, vpairs, los []pkg.Node, bm map[string]*net.IP) (string, error) {

root := gographviz.NewEscape()
if err := root.SetName("G"); err != nil {
Expand Down Expand Up @@ -145,3 +148,26 @@ func Graph(m map[string][]pkg.Node, vpairs, los []pkg.Node, bm map[string]*net.I

return root.String(), nil
}

func GenImage(data []byte, oGraphName *string, gType string) (err error) {
graph, errG := graphviz.ParseBytes(data)
if errG != nil {
log.Fatal(errG)
}
g := graphviz.New()
fn := fmt.Sprintf("%s.%s", *oGraphName, gType)
f, errF := os.Create(fn)
if errF != nil {
log.Fatal(errF)
}
defer f.Close()
switch gType {
case "jpg":
err = g.Render(graph, graphviz.JPG, f)
case "png":
err = g.Render(graph, graphviz.PNG, f)
case "svg":
err = g.Render(graph, graphviz.SVG, f)
}
return
}
16 changes: 11 additions & 5 deletions pkg/formatter/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,18 @@ func Table(w io.Writer, m map[string][]pkg.Node) error {
return nil
}

func TableParis(w io.WriteCloser, vpairs []pkg.Node) {
func TableParis(w io.Writer, vpairs []pkg.Node) {

if len(vpairs) == 0 {
return
}
tbStr := strings.Builder{}
t := table.NewWriter()
t.SetOutputMirror(&tbStr)

// (experimental)
t.SetTitle("unused veth pairs")
t.AppendHeader(table.Row{"veth", "pair"})
// (experimental)
t.SetTitle("not bridged veth pairs")
t.AppendHeader(table.Row{"veth", "route", "pair(In NetNS)"})
visited := make(map[string]struct{})
for _, v := range vpairs {
h := hashVethpair(v.Veth, v.Peer)
Expand All @@ -70,7 +74,9 @@ func TableParis(w io.WriteCloser, vpairs []pkg.Node) {
}
t.AppendRow(table.Row{
basicTextStyle.SetString(v.Veth),
basicTextStyle.SetString(v.Peer)})
basicTextStyle.SetString(v.Route.String()),
basicTextStyle.SetString(v.Peer),
})
t.AppendSeparator()
visited[h] = struct{}{}
}
Expand Down
88 changes: 47 additions & 41 deletions pkg/formatter/text.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,73 +15,79 @@ import (

func Print(w io.Writer, vm map[string][]pkg.Node, netNsMap map[int]string, vpairs []pkg.Node, all bool) {

var content strings.Builder
var contents []string

lw := list.NewWriter()
lw.SetOutputMirror(&content)
fmt.Fprintln(&content, titleHighlight.SetString("Bridge <----> veth pair"))
for k, v := range vm {
master, err := netlink.LinkByName(k)
if err != nil {
log.Fatal(err)
}
lw.AppendItem(
bridgeStyle.SetString(
fmt.Sprintf("%s\t%s", k, master.Attrs().OperState)).String())
lw.Indent()
for _, nsName := range netNsMap {
f := false
for _, p := range v {
if nsName == p.NetNsName {
if !f {
lw.AppendItem(netNsStyle.SetString(nsName).String())
f = true
lw.Indent()
}
if len(vm) > 0 {
var content strings.Builder

lw.AppendItem(
vethStyle.SetString(
fmt.Sprintf("%s\t%s",
basicTextStyle.SetString(p.Veth),
basicTextStyle.SetString(p.PeerNameInNetns))).String())
}
lw := list.NewWriter()
lw.SetOutputMirror(&content)
fmt.Fprintln(&content, titleHighlight.SetString("Bridge <----> veth pair"))
for k, v := range vm {
master, err := netlink.LinkByName(k)
if err != nil {
log.Fatal(err)
}
if f {
lw.UnIndent()
lw.AppendItem(
bridgeStyle.SetString(
fmt.Sprintf("%s\t%s", k, master.Attrs().OperState)))
lw.Indent()
for _, nsName := range netNsMap {
f := false
for _, p := range v {
if nsName == p.NetNsName {
if !f {
lw.AppendItem(netNsStyle.SetString(nsName))
f = true
lw.Indent()
}

lw.AppendItem(
vethStyle.SetString(
fmt.Sprintf("%s\t%s",
basicTextStyle.SetString(p.Veth),
basicTextStyle.SetString(p.PeerNameInNetns))))
}
}
if f {
lw.UnIndent()
}
}
lw.UnIndent()
}
lw.UnIndent()
}

lw.SetStyle(list.StyleConnectedRounded)
lw.Render()
lw.SetStyle(list.StyleConnectedRounded)
lw.Render()

contents = append(contents, mainStype.Render(content.String()))
contents = append(contents, mainStype.Render(content.String()))
}

if all {
if all && len(vpairs) > 0 {
var vpair strings.Builder
visited := make(map[string]struct{})

fmt.Fprintln(&vpair, titleHighlight.SetString("not bridged veth pairs"))

visited := make(map[string]struct{})

for _, veth := range vpairs {
h := hashVethpair(veth.Veth, veth.Peer)
if _, ok := visited[h]; ok {
continue
}

fmt.Fprintf(&vpair, "%s%s%s\t%s\n",
fmt.Fprintf(&vpair, "%s%s%s\t%s\t%s\n",
basicTextStyle.SetString(veth.Veth),
textHighlight.SetString("<----->"),
textHighlight.SetString("<-->"),
basicTextStyle.SetString(veth.Peer),
basicTextStyle.SetString(veth.Route.String()),
netNsStyle.SetString(netNsMap[veth.NetNsID]),
)
visited[h] = struct{}{}
}

contents = append(contents, vethPairStyle.Render(vpair.String()))
}
fmt.Fprintln(w, lipgloss.JoinVertical(lipgloss.Top, contents...))

if len(contents) > 0 {
fmt.Fprintln(w, lipgloss.JoinVertical(lipgloss.Top, contents...))
}
}
1 change: 1 addition & 0 deletions pkg/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type Node struct {
NetNsID int
NetNsName string
Master *Bridge
Route net.IP

// general
Name string
Expand Down

0 comments on commit 60b872c

Please sign in to comment.