Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ require (
github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da
github.com/eapache/channels v1.1.0
github.com/fsnotify/fsnotify v1.9.0
github.com/gaissmai/bart v0.26.1
github.com/getsentry/sentry-go v0.34.1
github.com/go-test/deep v1.1.1
github.com/go-viper/mapstructure/v2 v2.4.0
github.com/google/go-cmp v0.7.0
github.com/google/uuid v1.6.0
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
Expand All @@ -20,7 +22,6 @@ require (
github.com/prometheus/client_golang v1.16.0
github.com/prometheus/client_model v0.3.0
github.com/segmentio/fasthash v1.0.3
github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.9.1
github.com/spf13/viper v1.20.1
github.com/stretchr/testify v1.10.0
Expand All @@ -37,7 +38,6 @@ require (
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/eapache/queue v1.1.0 // indirect
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/kr/text v0.2.0 // indirect
Expand Down
7 changes: 2 additions & 5 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/gaissmai/bart v0.26.1 h1:+w4rnLGNlA2GDVn382Tfe3jOsK5vOr5n4KmigJ9lbTo=
github.com/gaissmai/bart v0.26.1/go.mod h1:GREWQfTLRWz/c5FTOsIw+KkscuFkIV5t8Rp7Nd1Td5c=
github.com/getsentry/sentry-go v0.34.1 h1:HSjc1C/OsnZttohEPrrqKH42Iud0HuLCXpv8cU1pWcw=
github.com/getsentry/sentry-go v0.34.1/go.mod h1:C55omcY9ChRQIUcVcGcs+Zdy4ZpQGvNJ7JYHIoSWOtE=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
Expand Down Expand Up @@ -82,8 +84,6 @@ github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsF
github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k=
github.com/segmentio/fasthash v1.0.3 h1:EI9+KE1EwvMLBWwjpRDc+fEM+prwxDYbslddQGtrmhM=
github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs=
Expand All @@ -98,7 +98,6 @@ github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4=
github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
Expand Down Expand Up @@ -128,7 +127,6 @@ go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTV
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
Expand All @@ -146,6 +144,5 @@ google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
12 changes: 12 additions & 0 deletions internal/pkg/table/path.go
Original file line number Diff line number Diff line change
Expand Up @@ -1385,3 +1385,15 @@ func nlriToIPNet(nlri bgp.NLRI) *net.IPNet {
}
return nil
}

func nlriToPrefix(nlri bgp.NLRI) netip.Prefix {
switch T := nlri.(type) {
case *bgp.IPAddrPrefix:
return T.Prefix
case *bgp.LabeledIPAddrPrefix:
return T.Prefix
case *bgp.LabeledVPNIPAddrPrefix:
return T.Prefix
}
return netip.Prefix{}
}
124 changes: 47 additions & 77 deletions internal/pkg/table/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import (
"strings"
"sync"

"github.com/k-sone/critbitgo"
"github.com/gaissmai/bart"
"github.com/osrg/gobgp/v4/api"
"github.com/osrg/gobgp/v4/pkg/config/oc"
"github.com/osrg/gobgp/v4/pkg/packet/bgp"
Expand Down Expand Up @@ -270,7 +270,7 @@ func (l DefinedSetList) Less(i, j int) bool {
}

type Prefix struct {
Prefix *net.IPNet
Prefix netip.Prefix
AddressFamily bgp.Family
MasklengthRangeMax uint8
MasklengthRangeMin uint8
Expand All @@ -282,11 +282,11 @@ func (p *Prefix) Match(path *Path) bool {
return false
}

var pAddr net.IP
var pAddr netip.Addr
var pMasklen uint8
switch rf {
case bgp.RF_IPv4_UC, bgp.RF_IPv6_UC:
pAddr = net.IP(path.GetNlri().(*bgp.IPAddrPrefix).Prefix.Addr().AsSlice())
pAddr = path.GetNlri().(*bgp.IPAddrPrefix).Prefix.Addr()
pMasklen = uint8(path.GetNlri().(*bgp.IPAddrPrefix).Prefix.Bits())
default:
return false
Expand All @@ -306,30 +306,13 @@ func (lhs *Prefix) Equal(rhs *Prefix) bool {
}

func (p *Prefix) PrefixString() string {
isZeros := func(p net.IP) bool {
for i := range p {
if p[i] != 0 {
return false
}
}
return true
}

ip := p.Prefix.IP
if p.AddressFamily == bgp.RF_IPv6_UC && isZeros(ip[:10]) && ip[10] == 0xff && ip[11] == 0xff {
m, _ := p.Prefix.Mask.Size()
return fmt.Sprintf("::FFFF:%s/%d", ip.To16(), m)
}
return p.Prefix.String()
}

var _regexpPrefixRange = regexp.MustCompile(`(\d+)\.\.(\d+)`)

func NewPrefix(c oc.Prefix) (*Prefix, error) {
_, prefix, err := net.ParseCIDR(c.IpPrefix.String())
if err != nil {
return nil, err
}
prefix := c.IpPrefix

rf := bgp.RF_IPv4_UC
if strings.Contains(c.IpPrefix.String(), ":") {
Expand All @@ -342,7 +325,7 @@ func NewPrefix(c oc.Prefix) (*Prefix, error) {
maskRange := c.MasklengthRange

if maskRange == "" {
l, _ := prefix.Mask.Size()
l := prefix.Bits()
maskLength := uint8(l)
p.MasklengthRangeMax = maskLength
p.MasklengthRangeMin = maskLength
Expand All @@ -364,7 +347,7 @@ func NewPrefix(c oc.Prefix) (*Prefix, error) {

type PrefixSet struct {
name string
tree *critbitgo.Net
tree *bart.Table[[]*Prefix]
family bgp.Family
}

Expand All @@ -388,18 +371,15 @@ func (lhs *PrefixSet) Append(arg DefinedSet) error {
} else if lhs.tree.Size() != 0 && rhs.family != lhs.family {
return fmt.Errorf("can't append different family")
}
//nolint:errcheck // tree.Add won't return an error
rhs.tree.Walk(nil, func(r *net.IPNet, v any) bool {
w, ok, _ := lhs.tree.Get(r)
if ok {
rp := v.([]*Prefix)
lp := w.([]*Prefix)
lhs.tree.Add(r, append(lp, rp...))
} else {
lhs.tree.Add(r, v)
}
return true
})

for r, v := range rhs.tree.All() {
lhs.tree.Modify(r, func(val []*Prefix, ok bool) ([]*Prefix, bool) {
if ok {
return append(val, v...), false
}
return v, false
})
}
lhs.family = rhs.family
return nil
}
Expand All @@ -409,14 +389,11 @@ func (lhs *PrefixSet) Remove(arg DefinedSet) error {
if !ok {
return fmt.Errorf("type cast failed")
}
//nolint:errcheck // tree.Delete/tree.Add won't return an error
rhs.tree.Walk(nil, func(r *net.IPNet, v any) bool {
w, ok, _ := lhs.tree.Get(r)
for r, rp := range rhs.tree.All() {
lp, ok := lhs.tree.Get(r)
if !ok {
return true
continue
}
rp := v.([]*Prefix)
lp := w.([]*Prefix)
new := make([]*Prefix, 0, len(lp))
for _, lp := range lp {
delete := slices.ContainsFunc(rp, lp.Equal)
Expand All @@ -427,10 +404,9 @@ func (lhs *PrefixSet) Remove(arg DefinedSet) error {
if len(new) == 0 {
lhs.tree.Delete(r)
} else {
lhs.tree.Add(r, new)
lhs.tree.Insert(r, new)
}
return true
})
}
return nil
}

Expand All @@ -446,25 +422,21 @@ func (lhs *PrefixSet) Replace(arg DefinedSet) error {

func (s *PrefixSet) List() []string {
var list []string
s.tree.Walk(nil, func(_ *net.IPNet, v any) bool {
ps := v.([]*Prefix)
for _, ps := range s.tree.All() {
for _, p := range ps {
list = append(list, fmt.Sprintf("%s %d..%d", p.PrefixString(), p.MasklengthRangeMin, p.MasklengthRangeMax))
}
return true
})
}
return list
}

func (s *PrefixSet) ToConfig() *oc.PrefixSet {
list := make([]oc.Prefix, 0, s.tree.Size())
s.tree.Walk(nil, func(_ *net.IPNet, v any) bool {
ps := v.([]*Prefix)
for _, ps := range s.tree.All() {
for _, p := range ps {
list = append(list, oc.Prefix{IpPrefix: netip.MustParsePrefix(p.PrefixString()), MasklengthRange: fmt.Sprintf("%d..%d", p.MasklengthRangeMin, p.MasklengthRangeMax)})
}
return true
})
}
return &oc.PrefixSet{
PrefixSetName: s.name,
PrefixList: list,
Expand All @@ -483,23 +455,20 @@ func NewPrefixSetFromApiStruct(name string, prefixes []*Prefix) (*PrefixSet, err
if name == "" {
return nil, fmt.Errorf("empty prefix set name")
}
tree := critbitgo.NewNet()
tree := new(bart.Table[[]*Prefix])
var family bgp.Family
for i, x := range prefixes {
if i == 0 {
family = x.AddressFamily
} else if family != x.AddressFamily {
return nil, fmt.Errorf("multiple families")
}
d, ok, _ := tree.Get(x.Prefix)
if ok {
ps := d.([]*Prefix)
if err := tree.Add(x.Prefix, append(ps, x)); err != nil {
return nil, fmt.Errorf("failed to add prefix %s: %w", x.PrefixString(), err)
tree.Modify(x.Prefix, func(val []*Prefix, ok bool) ([]*Prefix, bool) {
if ok {
return append(val, x), false
}
} else if err := tree.Add(x.Prefix, []*Prefix{x}); err != nil {
return nil, fmt.Errorf("failed to add prefix %s: %w", x.PrefixString(), err)
}
return []*Prefix{x}, false
})
}
return &PrefixSet{
name: name,
Expand All @@ -516,7 +485,7 @@ func NewPrefixSet(c oc.PrefixSet) (*PrefixSet, error) {
}
return nil, fmt.Errorf("empty prefix set name")
}
tree := critbitgo.NewNet()
tree := new(bart.Table[[]*Prefix])
var family bgp.Family
for i, x := range c.PrefixList {
y, err := NewPrefix(x)
Expand All @@ -528,14 +497,11 @@ func NewPrefixSet(c oc.PrefixSet) (*PrefixSet, error) {
} else if family != y.AddressFamily {
return nil, fmt.Errorf("multiple families")
}
d, ok, _ := tree.Get(y.Prefix)
ps, ok := tree.Get(y.Prefix)
if ok {
ps := d.([]*Prefix)
if err := tree.Add(y.Prefix, append(ps, y)); err != nil {
return nil, fmt.Errorf("failed to add prefix %s: %w", y.PrefixString(), err)
}
} else if err := tree.Add(y.Prefix, []*Prefix{y}); err != nil {
return nil, fmt.Errorf("failed to add prefix %s: %w", y.PrefixString(), err)
tree.Insert(y.Prefix, append(ps, y))
} else {
tree.Insert(y.Prefix, []*Prefix{y})
}
}
return &PrefixSet{
Expand Down Expand Up @@ -1452,20 +1418,24 @@ func (c *PrefixCondition) Evaluate(path *Path, _ *PolicyOptions) bool {
return false
}

r := nlriToIPNet(path.GetNlri())
if r == nil {
r := nlriToPrefix(path.GetNlri())
if !r.IsValid() {
return false
}
ones, _ := r.Mask.Size()
masklen := uint8(ones)
addr := r.Masked().Addr()
masklen := uint8(r.Bits())
result := false
if _, ps, _ := c.set.tree.Match(r); ps != nil {
for _, p := range ps.([]*Prefix) {
if p.MasklengthRangeMin <= masklen && masklen <= p.MasklengthRangeMax {
// Iterate all prefixes in the set and check supernet containment with mask-length range
for _, ps := range c.set.tree.Supernets(r) {
for _, p := range ps {
if p.MasklengthRangeMin <= masklen && masklen <= p.MasklengthRangeMax && p.Prefix.Contains(addr) {
result = true
break
}
}
if result {
break
}
}

if c.option == MATCH_OPTION_INVERT {
Expand Down
Loading
Loading