Skip to content

Commit 1478d16

Browse files
committed
feat: add tags and status filter by tags
1 parent 24d9dc1 commit 1478d16

7 files changed

Lines changed: 90 additions & 38 deletions

File tree

cmd/status.go

Lines changed: 48 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,22 @@ import (
1212
"github.com/spf13/cobra"
1313

1414
"github.com/natesales/pathvector/pkg/bird"
15+
"github.com/natesales/pathvector/pkg/templating"
1516
"github.com/natesales/pathvector/pkg/util"
1617
)
1718

1819
var (
19-
userProtocolNames bool
20+
realProtocolNames bool
2021
onlyBGP bool
22+
showTags bool
23+
tagFilter []string
2124
)
2225

2326
func init() {
24-
statusCmd.Flags().BoolVarP(&userProtocolNames, "user-protocol-names", "u", false, "use user-defined protocol names")
27+
statusCmd.Flags().BoolVarP(&realProtocolNames, "real-protocol-names", "r", false, "use real protocol names")
2528
statusCmd.Flags().BoolVarP(&onlyBGP, "bgp", "b", false, "only show BGP protocols")
29+
statusCmd.Flags().BoolVar(&showTags, "tags", false, "show tags column")
30+
statusCmd.Flags().StringArrayVarP(&tagFilter, "filter", "f", []string{}, "tags to filter by")
2631
rootCmd.AddCommand(statusCmd)
2732
}
2833

@@ -42,13 +47,13 @@ var statusCmd = &cobra.Command{
4247
}
4348

4449
// Read protocol names map
45-
var protocolNames map[string]string
46-
if userProtocolNames {
50+
var protocols map[string]*templating.Protocol
51+
if !realProtocolNames {
4752
contents, err := os.ReadFile(path.Join("/etc/bird/", "protocol_names.json"))
4853
if err != nil {
4954
log.Fatalf("Reading protocol names: %v", err)
5055
}
51-
if err := json.Unmarshal(contents, &protocolNames); err != nil {
56+
if err := json.Unmarshal(contents, &protocols); err != nil {
5257
log.Fatalf("Unmarshalling protocol names: %v", err)
5358
}
5459
}
@@ -58,32 +63,43 @@ var statusCmd = &cobra.Command{
5863
log.Fatal(err)
5964
}
6065

61-
util.PrintTable([]string{"Peer", "AS", "Neighbor", "State", "In", "Out", "Since", "Info"}, func() [][]string {
66+
header := []string{"Peer", "AS", "Neighbor", "State", "In", "Out", "Since", "Info"}
67+
if showTags {
68+
header = append(header, "Tags")
69+
}
70+
util.PrintTable(header, func() [][]string {
6271
var table [][]string
6372
for _, protocolState := range protocolStates {
6473
if !onlyBGP || protocolState.BGP != nil {
65-
if protocolState.BGP == nil {
66-
table = append(table, []string{
67-
protocolName(protocolState.Name, protocolNames),
68-
"-",
69-
"-",
70-
colorStatus(protocolState.State),
71-
parseTableInt(protocolState.Routes.Imported),
72-
parseTableInt(protocolState.Routes.Exported),
73-
protocolState.Since,
74-
colorStatus(protocolState.Info),
75-
})
76-
} else { // BGP
77-
table = append(table, []string{
78-
protocolName(protocolState.Name, protocolNames),
79-
parseTableInt(protocolState.BGP.NeighborAS),
80-
protocolState.BGP.NeighborAddress,
74+
neighborAddr, neighborAS := "-", "-"
75+
if protocolState.BGP != nil {
76+
neighborAS = parseTableInt(protocolState.BGP.NeighborAS)
77+
neighborAddr = protocolState.BGP.NeighborAddress
78+
}
79+
80+
// Lookup peer in protocol JSON
81+
protocolName := protocolState.Name
82+
var tags []string
83+
if p, found := protocols[protocolState.Name]; found {
84+
protocolName = p.Name
85+
tags = p.Tags
86+
}
87+
88+
if len(tagFilter) == 0 || containsAny(tagFilter, tags) {
89+
row := []string{
90+
protocolName,
91+
neighborAS,
92+
neighborAddr,
8193
colorStatus(protocolState.State),
8294
parseTableInt(protocolState.Routes.Imported),
8395
parseTableInt(protocolState.Routes.Exported),
8496
protocolState.Since,
8597
colorStatus(protocolState.Info),
86-
})
98+
}
99+
if showTags {
100+
row = append(row, strings.Join(tags, ", "))
101+
}
102+
table = append(table, row)
87103
}
88104
}
89105
}
@@ -92,12 +108,16 @@ var statusCmd = &cobra.Command{
92108
},
93109
}
94110

95-
func protocolName(n string, names map[string]string) string {
96-
if userSuppliedName, found := names[n]; found {
97-
return userSuppliedName
98-
} else {
99-
return n
111+
// containsAny checks if two string slices contain any of the same elements
112+
func containsAny(a []string, b []string) bool {
113+
for _, i := range a {
114+
for _, j := range b {
115+
if i == j {
116+
return true
117+
}
118+
}
100119
}
120+
return false
101121
}
102122

103123
func parseTableInt(i int) string {

docs/docs/configuration.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,14 @@ Peer description
663663
|------|---------|------------|
664664
| string | | |
665665

666+
### `tags`
667+
668+
Peer tags
669+
670+
| Type | Default | Validation |
671+
|------|---------|------------|
672+
| []string | | |
673+
666674
### `disabled`
667675

668676
Should the sessions be disabled?

pkg/config/config.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,9 @@ var defaultBogonASNs = []string{
9393
type Peer struct {
9494
Template *string `yaml:"template" description:"Configuration template" default:"-"`
9595

96-
Description *string `yaml:"description" description:"Peer description" default:"-"`
97-
Disabled *bool `yaml:"disabled" description:"Should the sessions be disabled?" default:"false"`
96+
Description *string `yaml:"description" description:"Peer description" default:"-"`
97+
Tags *[]string `yaml:"tags" description:"Peer tags" default:"-"`
98+
Disabled *bool `yaml:"disabled" description:"Should the sessions be disabled?" default:"false"`
9899

99100
Import *bool `yaml:"import" description:"Import routes from this peer" default:"true"`
100101
Export *bool `yaml:"export" description:"Export routes to this peer" default:"true"`

pkg/embed/templates/peer.tmpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ define AS{{ $peer.ASN }}_{{ $peer.ProtocolName }}_AS_SET_MEMBERS = [
3535
{{ range $i, $neighbor := $peer.NeighborIPs }}
3636
{{ $af := "4" }}{{ if Contains $neighbor ":" }}{{ $af = "6" }}{{ end }}
3737
{{ $neighborNoIface := SplitFirst $neighbor "%" }}
38-
protocol bgp {{ UniqueProtocolName $peer.ProtocolName $peerName $af $peer.ASN }} {
38+
protocol bgp {{ UniqueProtocolName $peer.ProtocolName $peerName $af $peer.ASN $peer.Tags }} {
3939
local{{ if eq $af "4" }}{{ if $peer.Listen4 }} {{ $peer.Listen4 }}{{ end }}{{ else }}{{ if $peer.Listen6 }} {{ $peer.Listen6 }}{{ end }}{{ end }} as {{ if IntDeref $peer.LocalASN }}{{ IntDeref $peer.LocalASN }}{{ else }}ASN{{ end }}{{ if $peer.LocalPort }} port {{ $peer.LocalPort }}{{ end }};
4040
neighbor {{ $neighbor }} as {{ $peer.ASN }}{{ if $peer.NeighborPort }} port {{ $peer.NeighborPort }}{{ end }};
4141
{{ if StrDeref $peer.Description }}description "{{ StrDeref $peer.Description }}";{{ end }}

pkg/templating/templating.go

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import (
1818

1919
var (
2020
protocolNames []string
21-
protocolNameMap = map[string]string{} // bird name:user name
21+
protocolNameMap = map[string]*Protocol{} // bird name:protocol
2222
protocolNameMapLock = sync.Mutex{}
2323
)
2424

@@ -29,8 +29,13 @@ type Wrapper struct {
2929
Config config.Config
3030
}
3131

32+
type Protocol struct {
33+
Name string
34+
Tags []string
35+
}
36+
3237
// ProtocolNames gets a map of protocol names to user defined names
33-
func ProtocolNames() map[string]string {
38+
func ProtocolNames() map[string]*Protocol {
3439
return protocolNameMap
3540
}
3641

@@ -190,14 +195,21 @@ var funcMap = template.FuncMap{
190195
},
191196

192197
// UniqueProtocolName takes a protocol-safe string and address family and returns a unique protocol name
193-
"UniqueProtocolName": func(s, userSuppliedName *string, af string, asn *int) string {
198+
"UniqueProtocolName": func(s, userSuppliedName *string, af string, asn *int, tags *[]string) string {
194199
protoName := fmt.Sprintf("%s_AS%d_v%s", *s, *asn, af)
195200
i := 1
196201
for {
197202
if !util.Contains(protocolNames, protoName) {
198203
protocolNames = append(protocolNames, protoName)
204+
var t []string
205+
if tags != nil {
206+
t = *tags
207+
}
199208
protocolNameMapLock.Lock()
200-
protocolNameMap[protoName] = *userSuppliedName
209+
protocolNameMap[protoName] = &Protocol{
210+
Name: *userSuppliedName,
211+
Tags: t,
212+
}
201213
protocolNameMapLock.Unlock()
202214
return protoName
203215
}

tests/generate-complex.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,3 +118,5 @@ peers:
118118
65510,30: 100
119119
65510,20: 200
120120
65510,20,30: 300
121+
tags:
122+
- ixp

tests/generate-simple.yml

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@ peers:
1616
neighbors:
1717
- 203.0.113.12
1818
- 2001:db8::12
19-
prefixes:
20-
- 192.0.2.0/24
21-
- 2001:db8::/48
19+
tags:
20+
- nwax
21+
- ixp
22+
Example2:
23+
import: false
24+
export: false
25+
asn: 65510
26+
neighbors:
27+
- 203.0.113.12
28+
- 2001:db8::12
29+
tags:
30+
- ixp

0 commit comments

Comments
 (0)