pkg/skoop/model/path.go (172 lines of code) (raw):

package model import ( "fmt" "strings" "github.com/alibaba/kubeskoop/pkg/skoop/utils" "github.com/samber/lo" ) type LinkType string const ( LinkExternal LinkType = "external" LinkInfra LinkType = "infra" LinkVeth LinkType = "veth" LinkIPVlan LinkType = "ipvlan" LinkLocal LinkType = "local" ) type LinkAttribute interface { GetAttrs() map[string]string } type SimpleLinkAttribute struct { Interface string IP string } func (a SimpleLinkAttribute) GetAttrs() map[string]string { return map[string]string{ "if": a.Interface, } } type VEthLinkAttribute struct { SimpleLinkAttribute PeerIndex int } func (v VEthLinkAttribute) GetAttrs() map[string]string { attrs := v.SimpleLinkAttribute.GetAttrs() attrs["peer_id"] = fmt.Sprintf("%d", v.PeerIndex) return attrs } type NullAttribute struct { } func (a NullAttribute) GetAttrs() map[string]string { return map[string]string{} } type Link struct { Type LinkType Source *NetNode Destination *NetNode Packet *Packet SourceAttribute LinkAttribute DestinationAttribute LinkAttribute Level int // for print } func (l Link) GetID() string { return fmt.Sprintf("%s,%s,%s,%s", l.Type, l.Source.GetID(), l.Destination.GetID(), fmt.Sprintf("%s:%d", l.Packet.Dst, l.Packet.Dport)) } type PacketPath struct { origin *NetNode } func NewPacketPath(origin *NetNode) *PacketPath { return &PacketPath{ origin: origin, } } func (p *PacketPath) GetLinkLabel(link *Link, action *Action) string { var buf []string buf = append(buf, fmt.Sprintf("type=%s", link.Type)) buf = append(buf, fmt.Sprintf("level=%d", link.Level)) if action != nil { buf = append(buf, fmt.Sprintf("trans=%s", action.Type)) } srcAttrs := map[string]string{} if link.SourceAttribute != nil { srcAttrs = link.SourceAttribute.GetAttrs() } dstAttrs := map[string]string{} if link.DestinationAttribute != nil { dstAttrs = link.DestinationAttribute.GetAttrs() } if oif, ok := srcAttrs["if"]; ok { buf = append(buf, fmt.Sprintf("oif=%s", oif)) } if iif, ok := dstAttrs["if"]; ok { buf = append(buf, fmt.Sprintf("iif=%s", iif)) } buf = append(buf, fmt.Sprintf("src=%s", link.Packet.Src), fmt.Sprintf("dst=%s", link.Packet.Dst), fmt.Sprintf("dport=%d", link.Packet.Dport)) return strings.Join(buf, ",") } func (p *PacketPath) GetOriginNode() *NetNode { return p.origin } func (p *PacketPath) Links() []*Link { var ( links []*Link ) pendingLinks := utils.NewQueue[*Link]() addLink := func(level int, action *Action) { if action == nil { return } for _, l := range action.Outputs { l.Level = level pendingLinks.Enqueue(l) } } addLink(0, p.origin.ActionOf(nil)) for !pendingLinks.Empty() { link := pendingLinks.Pop() links = append(links, link) addLink(link.Level+1, link.Destination.ActionOf(link)) } return links } func (p *PacketPath) Paths() string { buf := strings.Builder{} links := p.Links() if len(links) == 0 { for _, n := range p.Nodes() { buf.WriteString(fmt.Sprintf("\"%v\"", n.GetID())) } return buf.String() } for _, l := range links { action := l.Destination.ActionOf(l) attr := map[string]string{} if action != nil { label := p.GetLinkLabel(l, action) attr["label"] = label if action.Type == ActionTypeServe { attr["arrowhead"] = "dot" } } attrString := strings.Join( lo.MapToSlice(attr, func(k, v string) string { return fmt.Sprintf("%s=%q", k, v) }), ",") buf.WriteString(fmt.Sprintf("\"%v\" -> \"%v\" [%s]\n", l.Source.GetID(), l.Destination.GetID(), attrString)) } return buf.String() } func (p *PacketPath) Nodes() []*NetNode { var ( nodes []*NetNode ) visited := map[string]struct{}{} pendingLinks := utils.NewQueue[*Link]() addLink := func(level int, action *Action) { if action == nil { return } for _, l := range action.Outputs { l.Level = level pendingLinks.Enqueue(l) } } addLink(0, p.origin.ActionOf(nil)) for !pendingLinks.Empty() { link := pendingLinks.Pop() if _, ok := visited[link.Source.GetID()]; !ok { visited[link.Source.GetID()] = struct{}{} nodes = append(nodes, link.Source) } if _, ok := visited[link.Destination.GetID()]; !ok { visited[link.Destination.GetID()] = struct{}{} nodes = append(nodes, link.Destination) } addLink(link.Level+1, link.Destination.ActionOf(link)) } if len(nodes) == 0 { nodes = append(nodes, p.origin) } return nodes }