diff --git a/examples/netlink/main.go b/examples/fib/main.go similarity index 89% rename from examples/netlink/main.go rename to examples/fib/main.go index aa4e493acb4e37c1f2745f5593e39811870ecacc..677ab11574f6b4e2afd037bc2d33b5f8f8b8f73b 100644 --- a/examples/netlink/main.go +++ b/examples/fib/main.go @@ -7,7 +7,7 @@ import ( "github.com/bio-routing/bio-rd/config" "github.com/bio-routing/bio-rd/protocols/bgp/server" - "github.com/bio-routing/bio-rd/protocols/netlink" + "github.com/bio-routing/bio-rd/protocols/fib" "github.com/bio-routing/bio-rd/routingtable/locRIB" log "github.com/sirupsen/logrus" @@ -43,8 +43,8 @@ func main() { b := server.NewBgpServer() startBGPServer(b, rib, cfg) - // Netlink communication - n := protocolnetlink.NewNetlink(&config.Netlink{ + // FIB communication + n := fib.NewFIB(&config.Netlink{ HoldTime: time.Second * 15, UpdateInterval: time.Second * 15, RoutingTable: config.RtMain, diff --git a/examples/netlink/main_ipv4.go b/examples/fib/main_ipv4.go similarity index 100% rename from examples/netlink/main_ipv4.go rename to examples/fib/main_ipv4.go diff --git a/examples/netlink/main_ipv6.go b/examples/fib/main_ipv6.go similarity index 100% rename from examples/netlink/main_ipv6.go rename to examples/fib/main_ipv6.go diff --git a/go.mod b/go.mod index ef129af356ca82c3dc7489c13b381b63d2e13bbf..4a127d313e57dbab42d096521192f261a995393a 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/vishvananda/netlink v1.0.0 github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc // indirect golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9 // indirect - golang.org/x/net v0.0.0-20181220203305-927f97764cc3 // indirect + golang.org/x/net v0.0.0-20181220203305-927f97764cc3 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 // indirect golang.org/x/sys v0.0.0-20181228120256-c6cbdbf9e68a // indirect google.golang.org/genproto v0.0.0-20181221175505-bd9b4fb69e2f // indirect diff --git a/protocols/device/server_darwin.go b/protocols/device/server_darwin.go index 803b9a1a7420f87f09ef33443f3e57af49242ed3..776fcd734b1f0159a4bba88c3e2e6852a0a3d2a6 100644 --- a/protocols/device/server_darwin.go +++ b/protocols/device/server_darwin.go @@ -7,9 +7,9 @@ import ( ) func (ds *Server) loadAdapter() error { - a, err := newOSAdapterLinux(ds) + a, err := newOSAdapterDarwin(ds) if err != nil { - return errors.Wrap(err, "Unable to create linux adapter") + return errors.Wrap(err, "Unable to create OS X adapter") } ds.osAdapter = a @@ -19,7 +19,7 @@ func (ds *Server) loadAdapter() error { type osAdapterDarwin struct { } -func newOSAdapterLinux(srv *Server) (*osAdapterDarwin, error) { +func newOSAdapterDarwin(srv *Server) (*osAdapterDarwin, error) { return nil, fmt.Errorf("Not implemented") } diff --git a/protocols/fib/fib.go b/protocols/fib/fib.go new file mode 100644 index 0000000000000000000000000000000000000000..a1b64fe25ad082928fd4156937476f303336dd80 --- /dev/null +++ b/protocols/fib/fib.go @@ -0,0 +1,44 @@ +package fib + +import ( + "github.com/bio-routing/bio-rd/config" + "github.com/bio-routing/bio-rd/routingtable/locRIB" +) + +// FIB is forwarding information base +type FIB struct { + locRib *locRIB.LocRIB + + //writer *NetlinkWriter + //reader *NetlinkReader +} + +// NewFIB creates a new Netlink object and returns the pointer to it +func NewFIB(options *config.Netlink, locRib *locRIB.LocRIB) *FIB { + + n := &FIB{ + locRib: locRib, + //writer: NewNetlinkWriter(options), + //reader: NewNetlinkReader(options), + } + return n +} + +// Start the Netlink module +func (f *FIB) Start() { + // connect all RIBs + /*options := routingtable.ClientOptions{ + BestOnly: false, + EcmpOnly: false, + MaxPaths: ^uint(0), // max int + }*/ + + // 1. from locRib to Kernel + //f.locRib.RegisterWithOptions(n.writer, options) + + // 2. from Kernel to locRib + //f.reader.clientManager.RegisterWithOptions(n.locRib, options) + + // Listen for new routes from kernel + //go n.reader.Read() +} diff --git a/protocols/fib/fib_linux.go b/protocols/fib/fib_linux.go new file mode 100644 index 0000000000000000000000000000000000000000..85c98f69c2ac9f19feae0c2a3389555e82f2cca4 --- /dev/null +++ b/protocols/fib/fib_linux.go @@ -0,0 +1,138 @@ +package fib + +import ( + "fmt" + + bnet "github.com/bio-routing/bio-rd/net" + "github.com/bio-routing/bio-rd/route" + "github.com/vishvananda/netlink" +) + +const ( + ProtoUnspec = 0 // unspec (from /etc/iproute2/rt_protos) + ProtoRedirect = 1 // redirect (from /etc/iproute2/rt_protos) + ProtoKernel = 2 // kernel (from /etc/iproute2/rt_protos) + ProtoBoot = 3 // boot (from /etc/iproute2/rt_protos) + ProtoStatic = 4 // static (from /etc/iproute2/rt_protos) + ProtoZebra = 11 // zebra (from /etc/iproute2/rt_protos) + ProtoBird = 12 // bird (from /etc/iproute2/rt_protos) + ProtoDHCP = 16 // dhcp (from /etc/iproute2/rt_protos) + ProtoBio = 45 // bio +) + +// NetlinkRouteDiff gets the list of elements contained by a but not b +func NetlinkRouteDiff(a, b []netlink.Route) []netlink.Route { + ret := make([]netlink.Route, 0) + + for _, pa := range a { + if !netlinkRoutesContains(pa, b) { + ret = append(ret, pa) + } + } + + return ret +} + +func netlinkRoutesContains(needle netlink.Route, haystack []netlink.Route) bool { + for i := range haystack { + if netlinkRouteEquals(&needle, &haystack[i]) { + return true + } + } + + return false +} + +func netlinkRouteEquals(a, b *netlink.Route) bool { + aMaskSize, aMaskBits := a.Dst.Mask.Size() + bMaskSize, bMaskBits := b.Dst.Mask.Size() + + return a.LinkIndex == b.LinkIndex && + a.ILinkIndex == b.ILinkIndex && + a.Scope == b.Scope && + + a.Dst.IP.Equal(b.Dst.IP) && + aMaskSize == bMaskSize && + aMaskBits == bMaskBits && + + a.Src.Equal(b.Src) && + a.Gw.Equal(b.Gw) && + + a.Protocol == b.Protocol && + a.Priority == b.Priority && + a.Table == b.Table && + a.Type == b.Type && + a.Tos == b.Tos && + a.Flags == b.Flags && + a.MTU == b.MTU && + a.AdvMSS == b.AdvMSS +} + +// NewNlPathFromRoute creates a new route.FIBPath object from a netlink.Route object +func NewPathsFromNlRoute(r netlink.Route, kernel bool) (bnet.Prefix, []*route.Path, error) { + var src bnet.IP + var dst bnet.Prefix + + if r.Src == nil && r.Dst == nil { + return bnet.Prefix{}, nil, fmt.Errorf("Cannot create NlPath, since source and destination are both nil") + } + + if r.Src == nil && r.Dst != nil { + dst = bnet.NewPfxFromIPNet(r.Dst) + if dst.Addr().IsIPv4() { + src = bnet.IPv4(0) + } else { + src = bnet.IPv6(0, 0) + } + } + + if r.Src != nil && r.Dst == nil { + src, _ = bnet.IPFromBytes(r.Src) + if src.IsIPv4() { + dst = bnet.NewPfx(bnet.IPv4(0), 0) + } else { + dst = bnet.NewPfx(bnet.IPv6(0, 0), 0) + } + } + + if r.Src != nil && r.Dst != nil { + src, _ = bnet.IPFromBytes(r.Src) + dst = bnet.NewPfxFromIPNet(r.Dst) + } + + paths := make([]*route.Path, 0) + + if len(r.MultiPath) > 0 { + for _, multiPath := range r.MultiPath { + nextHop, _ := bnet.IPFromBytes(multiPath.Gw) + paths = append(paths, &route.Path{ + Type: route.FIBPathType, + FIBPath: &route.FIBPath{ + Src: src, + NextHop: nextHop, + Priority: r.Priority, + Protocol: r.Protocol, + Type: r.Type, + Table: r.Table, + Kernel: kernel, + }, + }) + } + } else { + nextHop, _ := bnet.IPFromBytes(r.Gw) + paths = append(paths, &route.Path{ + Type: route.FIBPathType, + FIBPath: &route.FIBPath{ + Src: src, + NextHop: nextHop, + Priority: r.Priority, + Protocol: r.Protocol, + Type: r.Type, + Table: r.Table, + Kernel: kernel, + }, + }) + } + + return dst, paths, nil +} diff --git a/protocols/fib/fib_linux_test.go b/protocols/fib/fib_linux_test.go new file mode 100644 index 0000000000000000000000000000000000000000..64b4ad237848c64cdb7e5d154316d0adec676d15 --- /dev/null +++ b/protocols/fib/fib_linux_test.go @@ -0,0 +1,393 @@ +package fib + +import ( + "net" + "testing" + + bnet "github.com/bio-routing/bio-rd/net" + "github.com/bio-routing/bio-rd/route" + "github.com/stretchr/testify/assert" + "github.com/vishvananda/netlink" +) + +func TestNetlinkRouteDiff(t *testing.T) { + tests := []struct { + name string + left []netlink.Route + right []netlink.Route + expected []netlink.Route + }{ + { + name: "Equal", + left: []netlink.Route{ + { + Dst: &net.IPNet{ + IP: net.IPv4(10, 0, 0, 1), + Mask: net.IPv4Mask(255, 0, 0, 0), + }, + Table: 1, + }, + { + Dst: &net.IPNet{ + IP: net.IPv4(20, 0, 0, 1), + Mask: net.IPv4Mask(255, 0, 0, 0), + }, + Table: 2, + }, + }, + right: []netlink.Route{ + { + Dst: &net.IPNet{ + IP: net.IPv4(10, 0, 0, 1), + Mask: net.IPv4Mask(255, 0, 0, 0), + }, + Table: 1, + }, + { + Dst: &net.IPNet{ + IP: net.IPv4(20, 0, 0, 1), + Mask: net.IPv4Mask(255, 0, 0, 0), + }, + Table: 2, + }, + }, + expected: []netlink.Route{}, + }, { + name: "Left empty", + left: []netlink.Route{}, + right: []netlink.Route{ + { + Dst: &net.IPNet{ + IP: net.IPv4(10, 0, 0, 1), + Mask: net.IPv4Mask(255, 0, 0, 0), + }, + Table: 1, + }, + { + Dst: &net.IPNet{ + IP: net.IPv4(20, 0, 0, 1), + Mask: net.IPv4Mask(255, 0, 0, 0), + }, + Table: 2, + }, + }, + expected: []netlink.Route{}, + }, { + name: "Right empty", + left: []netlink.Route{ + { + Dst: &net.IPNet{ + IP: net.IPv4(10, 0, 0, 1), + Mask: net.IPv4Mask(255, 0, 0, 0), + }, + Table: 1, + }, + { + Dst: &net.IPNet{ + IP: net.IPv4(20, 0, 0, 1), + Mask: net.IPv4Mask(255, 0, 0, 0), + }, + Table: 2, + }, + }, + right: []netlink.Route{}, + expected: []netlink.Route{ + { + Dst: &net.IPNet{ + IP: net.IPv4(10, 0, 0, 1), + Mask: net.IPv4Mask(255, 0, 0, 0), + }, + Table: 1, + }, + { + Dst: &net.IPNet{ + IP: net.IPv4(20, 0, 0, 1), + Mask: net.IPv4Mask(255, 0, 0, 0), + }, + Table: 2, + }, + }, + }, { + name: "Diff", + left: []netlink.Route{ + { + Dst: &net.IPNet{ + IP: net.IPv4(10, 0, 0, 1), + Mask: net.IPv4Mask(255, 0, 0, 0), + }, + Table: 1, + }, + { + Dst: &net.IPNet{ + IP: net.IPv4(20, 0, 0, 1), + Mask: net.IPv4Mask(255, 0, 0, 0), + }, + Table: 2, + }, + }, + right: []netlink.Route{ + { + Dst: &net.IPNet{ + IP: net.IPv4(10, 0, 0, 1), + Mask: net.IPv4Mask(255, 0, 0, 0), + }, + Table: 1, + }, + }, + expected: []netlink.Route{ + { + Dst: &net.IPNet{ + IP: net.IPv4(20, 0, 0, 1), + Mask: net.IPv4Mask(255, 0, 0, 0), + }, + Table: 2, + }, + }, + }, + } + + for _, test := range tests { + res := NetlinkRouteDiff(test.left, test.right) + assert.Equal(t, test.expected, res) + } + +} + +func TestNewPathsFromNetlinkRoute(t *testing.T) { + tests := []struct { + name string + source netlink.Route + expectedPfx bnet.Prefix + expectedPaths []*route.Path + expectError bool + }{ + { + name: "Simple", + source: netlink.Route{ + Dst: bnet.NewPfx(bnet.IPv4FromOctets(10, 0, 0, 0), 8).GetIPNet(), + Src: bnet.IPv4(456).Bytes(), + Gw: bnet.IPv4(789).Bytes(), + Protocol: ProtoKernel, + Priority: 1, + Table: 254, + Type: 1, + }, + expectedPfx: bnet.NewPfx(bnet.IPv4FromOctets(10, 0, 0, 0), 8), + expectedPaths: []*route.Path{ + { + Type: route.FIBPathType, + FIBPath: &route.FIBPath{ + Src: bnet.IPv4(456), + NextHop: bnet.IPv4(789), + Protocol: ProtoKernel, + Priority: 1, + Table: 254, + Type: 1, + Kernel: true, + }, + }, + }, + expectError: false, + }, + { + name: "Multiple nexthop", + source: netlink.Route{ + Dst: bnet.NewPfx(bnet.IPv4FromOctets(10, 0, 0, 0), 8).GetIPNet(), + Src: bnet.IPv4(456).Bytes(), + MultiPath: []*netlink.NexthopInfo{ + { + LinkIndex: 1, + Hops: 1, + Gw: bnet.IPv4(123).Bytes(), + Flags: 0, + NewDst: nil, + Encap: nil, + }, { + LinkIndex: 2, + Hops: 1, + Gw: bnet.IPv4(345).Bytes(), + Flags: 0, + NewDst: nil, + Encap: nil, + }, + }, + Protocol: ProtoKernel, + Priority: 1, + Table: 254, + Type: 1, + }, + expectedPfx: bnet.NewPfx(bnet.IPv4FromOctets(10, 0, 0, 0), 8), + expectedPaths: []*route.Path{ + { + Type: route.FIBPathType, + FIBPath: &route.FIBPath{ + Src: bnet.IPv4(456), + NextHop: bnet.IPv4(123), + Protocol: ProtoKernel, + Priority: 1, + Table: 254, + Type: 1, + Kernel: true, + }, + }, { + Type: route.FIBPathType, + FIBPath: &route.FIBPath{ + Src: bnet.IPv4(456), + NextHop: bnet.IPv4(345), + Protocol: ProtoKernel, + Priority: 1, + Table: 254, + Type: 1, + Kernel: true, + }, + }, + }, + expectError: false, + }, + { + name: "No source but destination", + source: netlink.Route{ + Dst: bnet.NewPfx(bnet.IPv4FromOctets(10, 0, 0, 0), 8).GetIPNet(), + Gw: bnet.IPv4(789).Bytes(), + Protocol: ProtoKernel, + Priority: 1, + Table: 254, + Type: 1, + }, + expectedPfx: bnet.NewPfx(bnet.IPv4FromOctets(10, 0, 0, 0), 8), + expectedPaths: []*route.Path{ + { + Type: route.FIBPathType, + FIBPath: &route.FIBPath{ + Src: bnet.IPv4(0), + NextHop: bnet.IPv4(789), + Protocol: ProtoKernel, + Priority: 1, + Table: 254, + Type: 1, + Kernel: true, + }, + }, + }, + expectError: false, + }, + { + name: "Source but no destination", + source: netlink.Route{ + Src: bnet.IPv4(456).Bytes(), + Gw: bnet.IPv4(789).Bytes(), + Protocol: ProtoKernel, + Priority: 1, + Table: 254, + Type: 1, + }, + expectedPfx: bnet.NewPfx(bnet.IPv4FromOctets(0, 0, 0, 0), 0), + expectedPaths: []*route.Path{ + { + Type: route.FIBPathType, + FIBPath: &route.FIBPath{ + Src: bnet.IPv4(456), + NextHop: bnet.IPv4(789), + Protocol: ProtoKernel, + Priority: 1, + Table: 254, + Type: 1, + Kernel: true, + }, + }, + }, + expectError: false, + }, + { + name: "No source but no destination", + source: netlink.Route{ + Gw: bnet.IPv4(789).Bytes(), + Protocol: ProtoKernel, + Priority: 1, + Table: 254, + Type: 1, + }, + expectedPfx: bnet.Prefix{}, + expectedPaths: []*route.Path{}, + expectError: true, + }, + { + name: "No source but destination IPv6", + source: netlink.Route{ + Dst: bnet.NewPfx(bnet.IPv6(2001, 0), 48).GetIPNet(), + Gw: bnet.IPv6(2001, 123).Bytes(), + Protocol: ProtoKernel, + Priority: 1, + Table: 254, + Type: 1, + }, + expectedPfx: bnet.NewPfx(bnet.IPv6(2001, 0), 48), + expectedPaths: []*route.Path{ + { + Type: route.FIBPathType, + FIBPath: &route.FIBPath{ + Src: bnet.IPv6(0, 0), + NextHop: bnet.IPv6(2001, 123), + Protocol: ProtoKernel, + Priority: 1, + Table: 254, + Type: 1, + Kernel: true, + }, + }, + }, + expectError: false, + }, + { + name: "Source but no destination IPv6", + source: netlink.Route{ + Src: bnet.IPv6(2001, 456).Bytes(), + Gw: bnet.IPv6(2001, 789).Bytes(), + Protocol: ProtoKernel, + Priority: 1, + Table: 254, + Type: 1, + }, + expectedPfx: bnet.NewPfx(bnet.IPv6(0, 0), 0), + expectedPaths: []*route.Path{ + { + Type: route.FIBPathType, + FIBPath: &route.FIBPath{ + Src: bnet.IPv6(2001, 456), + NextHop: bnet.IPv6(2001, 789), + Protocol: ProtoKernel, + Priority: 1, + Table: 254, + Type: 1, + Kernel: true, + }, + }, + }, + expectError: false, + }, + { + name: "no source no destination", + source: netlink.Route{ + Gw: bnet.IPv4(123).Bytes(), + Protocol: ProtoKernel, + Priority: 1, + Table: 254, + Type: 1, + }, + expectedPfx: bnet.NewPfx(bnet.IPv4(0), 0), + expectedPaths: []*route.Path{{}}, + expectError: true, + }, + } + + for _, test := range tests { + pfx, paths, err := NewPathsFromNlRoute(test.source, true) + if test.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.Equalf(t, test.expectedPaths, paths, test.name) + assert.Equalf(t, test.expectedPfx, pfx, test.name) + } + } +} diff --git a/protocols/netlink/netlink_reader.go b/protocols/fib/reader_linux.go similarity index 94% rename from protocols/netlink/netlink_reader.go rename to protocols/fib/reader_linux.go index 20e4b12bdcf66739b8738c5b0fade165d92c7b0b..23df0d9882439fb6cb2c5f1fcc095a48f26973cd 100644 --- a/protocols/netlink/netlink_reader.go +++ b/protocols/fib/reader_linux.go @@ -1,4 +1,4 @@ -package protocolnetlink +package fib import ( "fmt" @@ -59,7 +59,7 @@ func (nr *NetlinkReader) Read() { nr.mu.Lock() nr.routes = routes - log.Debugf("NetlinkRouteDiff: %d", len(route.NetlinkRouteDiff(nr.routes, routes))) + log.Debugf("NetlinkRouteDiff: %d", len(NetlinkRouteDiff(nr.routes, routes))) nr.mu.Unlock() time.Sleep(nr.options.UpdateInterval) @@ -81,7 +81,7 @@ func (nr *NetlinkReader) addPathsToClients(routes []netlink.Route) { // only advertise changed routes nr.mu.RLock() - advertise := route.NetlinkRouteDiff(routes, nr.routes) + advertise := NetlinkRouteDiff(routes, nr.routes) nr.mu.RUnlock() for _, client := range nr.clientManager.Clients() { @@ -92,7 +92,7 @@ func (nr *NetlinkReader) addPathsToClients(routes []netlink.Route) { } // create pfx and path from route - pfx, paths, err := route.NewPathsFromNlRoute(r, true) + pfx, paths, err := NewPathsFromNlRoute(r, true) if err != nil { log.WithError(err).WithFields(log.Fields{ "prefix": pfx.String(), @@ -135,7 +135,7 @@ func (nr *NetlinkReader) removePathsFromClients(routes []netlink.Route) { } // only withdraw changed routes - withdraw := route.NetlinkRouteDiff(nr.routes, routes) + withdraw := NetlinkRouteDiff(nr.routes, routes) nr.mu.RUnlock() for _, client := range nr.clientManager.Clients() { @@ -146,7 +146,7 @@ func (nr *NetlinkReader) removePathsFromClients(routes []netlink.Route) { } // create pfx and path from route - pfx, paths, err := route.NewPathsFromNlRoute(r, true) + pfx, paths, err := NewPathsFromNlRoute(r, true) if err != nil { log.WithError(err).WithFields(log.Fields{ "prefix": pfx.String(), diff --git a/protocols/netlink/netlink_writer.go b/protocols/fib/writer_linux.go similarity index 99% rename from protocols/netlink/netlink_writer.go rename to protocols/fib/writer_linux.go index fae9a1fdd78a6b7285213fb3984fd7bb2c7532d0..c5fac76b3ca8a3761da2f0f0a5cf4d9ed104ae44 100644 --- a/protocols/netlink/netlink_writer.go +++ b/protocols/fib/writer_linux.go @@ -1,4 +1,4 @@ -package protocolnetlink +package fib import ( "fmt" diff --git a/protocols/netlink/netlink.go b/protocols/netlink/netlink.go deleted file mode 100644 index 62ce9449a526fa67deba3647c3a33532f637ef69..0000000000000000000000000000000000000000 --- a/protocols/netlink/netlink.go +++ /dev/null @@ -1,45 +0,0 @@ -package protocolnetlink - -import ( - "github.com/bio-routing/bio-rd/config" - "github.com/bio-routing/bio-rd/routingtable" - "github.com/bio-routing/bio-rd/routingtable/locRIB" -) - -// Netlink is the netlink module which handles the entire NetlinkCommunication -type Netlink struct { - locRib *locRIB.LocRIB - - writer *NetlinkWriter - reader *NetlinkReader -} - -// NewNetlink creates a new Netlink object and returns the pointer to it -func NewNetlink(options *config.Netlink, locRib *locRIB.LocRIB) *Netlink { - - n := &Netlink{ - locRib: locRib, - writer: NewNetlinkWriter(options), - reader: NewNetlinkReader(options), - } - return n -} - -// Start the Netlink module -func (n *Netlink) Start() { - // connect all RIBs - options := routingtable.ClientOptions{ - BestOnly: false, - EcmpOnly: false, - MaxPaths: ^uint(0), // max int - } - - // 1. from locRib to Kernel - n.locRib.RegisterWithOptions(n.writer, options) - - // 2. from Kernel to locRib - n.reader.clientManager.RegisterWithOptions(n.locRib, options) - - // Listen for new routes from kernel - go n.reader.Read() -} diff --git a/route/fib_path.go b/route/fib_path.go new file mode 100644 index 0000000000000000000000000000000000000000..a43d91cd370214940cbfa2d89be43b9e40597a20 --- /dev/null +++ b/route/fib_path.go @@ -0,0 +1,114 @@ +package route + +import ( + "fmt" + + bnet "github.com/bio-routing/bio-rd/net" +) + +const ( + ProtoBio = 45 // bio +) + +// FIBPath represents a path learned via Netlink of a route +type FIBPath struct { + Src bnet.IP + NextHop bnet.IP // GW + Priority int + Protocol int + Type int + Table int + Kernel bool // True if the route is already installed in the kernel +} + +// NewNlPathFromBgpPath creates a new FIBPath object from a BGPPath object +func NewNlPathFromBgpPath(p *BGPPath) *FIBPath { + return &FIBPath{ + Src: p.Source, + NextHop: p.NextHop, + Protocol: ProtoBio, + Kernel: false, + } +} + +// Select compares s with t and returns negative if s < t, 0 if paths are equal, positive if s > t +func (s *FIBPath) Select(t *FIBPath) int8 { + if s.NextHop.Compare(t.NextHop) < 0 { + return -1 + } + + if s.NextHop.Compare(t.NextHop) > 0 { + return 1 + } + + if s.Src.Compare(t.Src) < 0 { + return -1 + } + + if s.Src.Compare(t.Src) > 0 { + return 1 + } + + if s.Priority < t.Priority { + return -1 + } + + if s.Priority > t.Priority { + return 1 + } + + if s.Protocol < t.Protocol { + return -1 + } + + if s.Protocol > t.Protocol { + return 1 + } + + if s.Table < t.Table { + return -1 + } + + if s.Table > t.Table { + return 1 + } + + return 0 +} + +// ECMP determines if path s and t are equal in terms of ECMP +func (s *FIBPath) ECMP(t *FIBPath) bool { + return s.Src == t.Src && s.Priority == t.Priority && s.Protocol == t.Protocol && s.Type == t.Type && s.Table == t.Table +} + +// Copy duplicates the current object +func (s *FIBPath) Copy() *FIBPath { + if s == nil { + return nil + } + + cp := *s + return &cp +} + +// Print all known information about a route in logfile friendly format +func (s *FIBPath) String() string { + ret := fmt.Sprintf("Source: %s, ", s.Src.String()) + ret += fmt.Sprintf("NextHop: %s, ", s.NextHop.String()) + ret += fmt.Sprintf("Priority: %d, ", s.Priority) + ret += fmt.Sprintf("Type: %d, ", s.Type) + ret += fmt.Sprintf("Table: %d", s.Table) + + return ret +} + +// Print all known information about a route in human readable form +func (s *FIBPath) Print() string { + ret := fmt.Sprintf("\t\tSource: %s\n", s.Src.String()) + ret += fmt.Sprintf("\t\tNextHop: %s\n", s.NextHop.String()) + ret += fmt.Sprintf("\t\tPriority: %d\n", s.Priority) + ret += fmt.Sprintf("\t\tType: %d\n", s.Type) + ret += fmt.Sprintf("\t\tTable: %d\n", s.Table) + + return ret +} diff --git a/route/netlink_path.go b/route/netlink_path.go deleted file mode 100644 index cb374fe8c7672d417641b07c22187620feabea58..0000000000000000000000000000000000000000 --- a/route/netlink_path.go +++ /dev/null @@ -1,192 +0,0 @@ -package route - -import ( - "fmt" - - bnet "github.com/bio-routing/bio-rd/net" - "github.com/vishvananda/netlink" -) - -const ( - ProtoUnspec = 0 // unspec (from /etc/iproute2/rt_protos) - ProtoRedirect = 1 // redirect (from /etc/iproute2/rt_protos) - ProtoKernel = 2 // kernel (from /etc/iproute2/rt_protos) - ProtoBoot = 3 // boot (from /etc/iproute2/rt_protos) - ProtoStatic = 4 // static (from /etc/iproute2/rt_protos) - ProtoZebra = 11 // zebra (from /etc/iproute2/rt_protos) - ProtoBird = 12 // bird (from /etc/iproute2/rt_protos) - ProtoDHCP = 16 // dhcp (from /etc/iproute2/rt_protos) - ProtoBio = 45 // bio -) - -// NetlinkPath represents a path learned via Netlink of a route -type NetlinkPath struct { - Src bnet.IP - NextHop bnet.IP // GW - Priority int - Protocol int - Type int - Table int - Kernel bool // True if the route is already installed in the kernel -} - -// NewNlPathFromBgpPath creates a new NetlinkPath object from a BGPPath object -func NewNlPathFromBgpPath(p *BGPPath) *NetlinkPath { - return &NetlinkPath{ - Src: p.Source, - NextHop: p.NextHop, - Protocol: ProtoBio, - Kernel: false, - } -} - -// NewNlPathFromRoute creates a new NetlinkPath object from a netlink.Route object -func NewPathsFromNlRoute(r netlink.Route, kernel bool) (bnet.Prefix, []*Path, error) { - var src bnet.IP - var dst bnet.Prefix - - if r.Src == nil && r.Dst == nil { - return bnet.Prefix{}, nil, fmt.Errorf("Cannot create NlPath, since source and destination are both nil") - } - - if r.Src == nil && r.Dst != nil { - dst = bnet.NewPfxFromIPNet(r.Dst) - if dst.Addr().IsIPv4() { - src = bnet.IPv4(0) - } else { - src = bnet.IPv6(0, 0) - } - } - - if r.Src != nil && r.Dst == nil { - src, _ = bnet.IPFromBytes(r.Src) - if src.IsIPv4() { - dst = bnet.NewPfx(bnet.IPv4(0), 0) - } else { - dst = bnet.NewPfx(bnet.IPv6(0, 0), 0) - } - } - - if r.Src != nil && r.Dst != nil { - src, _ = bnet.IPFromBytes(r.Src) - dst = bnet.NewPfxFromIPNet(r.Dst) - } - - paths := make([]*Path, 0) - - if len(r.MultiPath) > 0 { - for _, multiPath := range r.MultiPath { - nextHop, _ := bnet.IPFromBytes(multiPath.Gw) - paths = append(paths, &Path{ - Type: NetlinkPathType, - NetlinkPath: &NetlinkPath{ - Src: src, - NextHop: nextHop, - Priority: r.Priority, - Protocol: r.Protocol, - Type: r.Type, - Table: r.Table, - Kernel: kernel, - }, - }) - } - } else { - nextHop, _ := bnet.IPFromBytes(r.Gw) - paths = append(paths, &Path{ - Type: NetlinkPathType, - NetlinkPath: &NetlinkPath{ - Src: src, - NextHop: nextHop, - Priority: r.Priority, - Protocol: r.Protocol, - Type: r.Type, - Table: r.Table, - Kernel: kernel, - }, - }) - } - - return dst, paths, nil -} - -// Select compares s with t and returns negative if s < t, 0 if paths are equal, positive if s > t -func (s *NetlinkPath) Select(t *NetlinkPath) int8 { - if s.NextHop.Compare(t.NextHop) < 0 { - return -1 - } - - if s.NextHop.Compare(t.NextHop) > 0 { - return 1 - } - - if s.Src.Compare(t.Src) < 0 { - return -1 - } - - if s.Src.Compare(t.Src) > 0 { - return 1 - } - - if s.Priority < t.Priority { - return -1 - } - - if s.Priority > t.Priority { - return 1 - } - - if s.Protocol < t.Protocol { - return -1 - } - - if s.Protocol > t.Protocol { - return 1 - } - - if s.Table < t.Table { - return -1 - } - - if s.Table > t.Table { - return 1 - } - - return 0 -} - -// ECMP determines if path s and t are equal in terms of ECMP -func (s *NetlinkPath) ECMP(t *NetlinkPath) bool { - return s.Src == t.Src && s.Priority == t.Priority && s.Protocol == t.Protocol && s.Type == t.Type && s.Table == t.Table -} - -// Copy duplicates the current object -func (s *NetlinkPath) Copy() *NetlinkPath { - if s == nil { - return nil - } - - cp := *s - return &cp -} - -// Print all known information about a route in logfile friendly format -func (s *NetlinkPath) String() string { - ret := fmt.Sprintf("Source: %s, ", s.Src.String()) - ret += fmt.Sprintf("NextHop: %s, ", s.NextHop.String()) - ret += fmt.Sprintf("Priority: %d, ", s.Priority) - ret += fmt.Sprintf("Type: %d, ", s.Type) - ret += fmt.Sprintf("Table: %d", s.Table) - - return ret -} - -// Print all known information about a route in human readable form -func (s *NetlinkPath) Print() string { - ret := fmt.Sprintf("\t\tSource: %s\n", s.Src.String()) - ret += fmt.Sprintf("\t\tNextHop: %s\n", s.NextHop.String()) - ret += fmt.Sprintf("\t\tPriority: %d\n", s.Priority) - ret += fmt.Sprintf("\t\tType: %d\n", s.Type) - ret += fmt.Sprintf("\t\tTable: %d\n", s.Table) - - return ret -} diff --git a/route/path.go b/route/path.go index 0d1a64f47a894a8e70fbcd2172877e5dbee19c26..3fa6155f9b6af1b076e44debe1309f79eedd0184 100644 --- a/route/path.go +++ b/route/path.go @@ -8,10 +8,10 @@ import ( // Path represents a network path type Path struct { - Type uint8 - StaticPath *StaticPath - BGPPath *BGPPath - NetlinkPath *NetlinkPath + Type uint8 + StaticPath *StaticPath + BGPPath *BGPPath + FIBPath *FIBPath } // Select returns negative if p < q, 0 if paths are equal, positive if p > q @@ -39,8 +39,8 @@ func (p *Path) Select(q *Path) int8 { return p.BGPPath.Select(q.BGPPath) case StaticPathType: return p.StaticPath.Select(q.StaticPath) - case NetlinkPathType: - return p.NetlinkPath.Select(q.NetlinkPath) + case FIBPathType: + return p.FIBPath.Select(q.FIBPath) } panic("Unknown path type") @@ -53,8 +53,8 @@ func (p *Path) ECMP(q *Path) bool { return p.BGPPath.ECMP(q.BGPPath) case StaticPathType: return p.StaticPath.ECMP(q.StaticPath) - case NetlinkPathType: - return p.NetlinkPath.ECMP(q.NetlinkPath) + case FIBPathType: + return p.FIBPath.ECMP(q.FIBPath) } panic("Unknown path type") @@ -110,8 +110,8 @@ func (p *Path) String() string { return "not implemented yet" case BGPPathType: return p.BGPPath.String() - case NetlinkPathType: - return p.NetlinkPath.String() + case FIBPathType: + return p.FIBPath.String() default: return "Unknown paty type. Probably not implemented yet" } @@ -125,7 +125,7 @@ func (p *Path) Print() string { protocol = "static" case BGPPathType: protocol = "BGP" - case NetlinkPathType: + case FIBPathType: protocol = "Netlink" } @@ -135,8 +135,8 @@ func (p *Path) Print() string { ret += "Not implemented yet" case BGPPathType: ret += p.BGPPath.Print() - case NetlinkPathType: - ret += p.NetlinkPath.Print() + case FIBPathType: + ret += p.FIBPath.Print() } return ret @@ -162,8 +162,8 @@ func (p *Path) NextHop() bnet.IP { return p.BGPPath.NextHop case StaticPathType: return p.StaticPath.NextHop - case NetlinkPathType: - return p.NetlinkPath.NextHop + case FIBPathType: + return p.FIBPath.NextHop } panic("Unknown path type") diff --git a/route/path_test.go b/route/path_test.go index 84b3cde044750bcc75eb44ac89ff894c619d5cf3..42961958d75f4ed34cd6a56023fb9652d9b9ebcb 100644 --- a/route/path_test.go +++ b/route/path_test.go @@ -6,7 +6,6 @@ import ( bnet "github.com/bio-routing/bio-rd/net" "github.com/stretchr/testify/assert" - "github.com/vishvananda/netlink" ) func TestPathNextHop(t *testing.T) { @@ -38,8 +37,8 @@ func TestPathNextHop(t *testing.T) { { name: "Netlink Path", p: &Path{ - Type: NetlinkPathType, - NetlinkPath: &NetlinkPath{ + Type: FIBPathType, + FIBPath: &FIBPath{ NextHop: bnet.IPv4(1000), }, }, @@ -151,12 +150,12 @@ func TestSelect(t *testing.T) { { name: "Netlink", p: &Path{ - Type: NetlinkPathType, - NetlinkPath: &NetlinkPath{}, + Type: FIBPathType, + FIBPath: &FIBPath{}, }, q: &Path{ - Type: NetlinkPathType, - NetlinkPath: &NetlinkPath{}, + Type: FIBPathType, + FIBPath: &FIBPath{}, }, expected: 0, }, @@ -328,7 +327,7 @@ func TestNewNlPath(t *testing.T) { tests := []struct { name string source *Path - expected *NetlinkPath + expected *FIBPath }{ { name: "BGPPath", @@ -338,7 +337,7 @@ func TestNewNlPath(t *testing.T) { NextHop: bnet.IPv4(123), }, }, - expected: &NetlinkPath{ + expected: &FIBPath{ NextHop: bnet.IPv4(123), Protocol: ProtoBio, }, @@ -346,7 +345,7 @@ func TestNewNlPath(t *testing.T) { } for _, test := range tests { - var converted *NetlinkPath + var converted *FIBPath switch test.source.Type { case BGPPathType: @@ -360,245 +359,6 @@ func TestNewNlPath(t *testing.T) { } } -func TestNewPathsFromNetlinkRoute(t *testing.T) { - tests := []struct { - name string - source netlink.Route - expectedPfx bnet.Prefix - expectedPaths []*Path - expectError bool - }{ - { - name: "Simple", - source: netlink.Route{ - Dst: bnet.NewPfx(bnet.IPv4FromOctets(10, 0, 0, 0), 8).GetIPNet(), - Src: bnet.IPv4(456).Bytes(), - Gw: bnet.IPv4(789).Bytes(), - Protocol: ProtoKernel, - Priority: 1, - Table: 254, - Type: 1, - }, - expectedPfx: bnet.NewPfx(bnet.IPv4FromOctets(10, 0, 0, 0), 8), - expectedPaths: []*Path{ - { - Type: NetlinkPathType, - NetlinkPath: &NetlinkPath{ - Src: bnet.IPv4(456), - NextHop: bnet.IPv4(789), - Protocol: ProtoKernel, - Priority: 1, - Table: 254, - Type: 1, - Kernel: true, - }, - }, - }, - expectError: false, - }, - { - name: "Multiple nexthop", - source: netlink.Route{ - Dst: bnet.NewPfx(bnet.IPv4FromOctets(10, 0, 0, 0), 8).GetIPNet(), - Src: bnet.IPv4(456).Bytes(), - MultiPath: []*netlink.NexthopInfo{ - { - LinkIndex: 1, - Hops: 1, - Gw: bnet.IPv4(123).Bytes(), - Flags: 0, - NewDst: nil, - Encap: nil, - }, { - LinkIndex: 2, - Hops: 1, - Gw: bnet.IPv4(345).Bytes(), - Flags: 0, - NewDst: nil, - Encap: nil, - }, - }, - Protocol: ProtoKernel, - Priority: 1, - Table: 254, - Type: 1, - }, - expectedPfx: bnet.NewPfx(bnet.IPv4FromOctets(10, 0, 0, 0), 8), - expectedPaths: []*Path{ - { - Type: NetlinkPathType, - NetlinkPath: &NetlinkPath{ - Src: bnet.IPv4(456), - NextHop: bnet.IPv4(123), - Protocol: ProtoKernel, - Priority: 1, - Table: 254, - Type: 1, - Kernel: true, - }, - }, { - Type: NetlinkPathType, - NetlinkPath: &NetlinkPath{ - Src: bnet.IPv4(456), - NextHop: bnet.IPv4(345), - Protocol: ProtoKernel, - Priority: 1, - Table: 254, - Type: 1, - Kernel: true, - }, - }, - }, - expectError: false, - }, - { - name: "No source but destination", - source: netlink.Route{ - Dst: bnet.NewPfx(bnet.IPv4FromOctets(10, 0, 0, 0), 8).GetIPNet(), - Gw: bnet.IPv4(789).Bytes(), - Protocol: ProtoKernel, - Priority: 1, - Table: 254, - Type: 1, - }, - expectedPfx: bnet.NewPfx(bnet.IPv4FromOctets(10, 0, 0, 0), 8), - expectedPaths: []*Path{ - { - Type: NetlinkPathType, - NetlinkPath: &NetlinkPath{ - Src: bnet.IPv4(0), - NextHop: bnet.IPv4(789), - Protocol: ProtoKernel, - Priority: 1, - Table: 254, - Type: 1, - Kernel: true, - }, - }, - }, - expectError: false, - }, - { - name: "Source but no destination", - source: netlink.Route{ - Src: bnet.IPv4(456).Bytes(), - Gw: bnet.IPv4(789).Bytes(), - Protocol: ProtoKernel, - Priority: 1, - Table: 254, - Type: 1, - }, - expectedPfx: bnet.NewPfx(bnet.IPv4FromOctets(0, 0, 0, 0), 0), - expectedPaths: []*Path{ - { - Type: NetlinkPathType, - NetlinkPath: &NetlinkPath{ - Src: bnet.IPv4(456), - NextHop: bnet.IPv4(789), - Protocol: ProtoKernel, - Priority: 1, - Table: 254, - Type: 1, - Kernel: true, - }, - }, - }, - expectError: false, - }, - { - name: "No source but no destination", - source: netlink.Route{ - Gw: bnet.IPv4(789).Bytes(), - Protocol: ProtoKernel, - Priority: 1, - Table: 254, - Type: 1, - }, - expectedPfx: bnet.Prefix{}, - expectedPaths: []*Path{}, - expectError: true, - }, - { - name: "No source but destination IPv6", - source: netlink.Route{ - Dst: bnet.NewPfx(bnet.IPv6(2001, 0), 48).GetIPNet(), - Gw: bnet.IPv6(2001, 123).Bytes(), - Protocol: ProtoKernel, - Priority: 1, - Table: 254, - Type: 1, - }, - expectedPfx: bnet.NewPfx(bnet.IPv6(2001, 0), 48), - expectedPaths: []*Path{ - { - Type: NetlinkPathType, - NetlinkPath: &NetlinkPath{ - Src: bnet.IPv6(0, 0), - NextHop: bnet.IPv6(2001, 123), - Protocol: ProtoKernel, - Priority: 1, - Table: 254, - Type: 1, - Kernel: true, - }, - }, - }, - expectError: false, - }, - { - name: "Source but no destination IPv6", - source: netlink.Route{ - Src: bnet.IPv6(2001, 456).Bytes(), - Gw: bnet.IPv6(2001, 789).Bytes(), - Protocol: ProtoKernel, - Priority: 1, - Table: 254, - Type: 1, - }, - expectedPfx: bnet.NewPfx(bnet.IPv6(0, 0), 0), - expectedPaths: []*Path{ - { - Type: NetlinkPathType, - NetlinkPath: &NetlinkPath{ - Src: bnet.IPv6(2001, 456), - NextHop: bnet.IPv6(2001, 789), - Protocol: ProtoKernel, - Priority: 1, - Table: 254, - Type: 1, - Kernel: true, - }, - }, - }, - expectError: false, - }, - { - name: "no source no destination", - source: netlink.Route{ - Gw: bnet.IPv4(123).Bytes(), - Protocol: ProtoKernel, - Priority: 1, - Table: 254, - Type: 1, - }, - expectedPfx: bnet.NewPfx(bnet.IPv4(0), 0), - expectedPaths: []*Path{{}}, - expectError: true, - }, - } - - for _, test := range tests { - pfx, paths, err := NewPathsFromNlRoute(test.source, true) - if test.expectError { - assert.Error(t, err) - } else { - assert.NoError(t, err) - assert.Equalf(t, test.expectedPaths, paths, test.name) - assert.Equalf(t, test.expectedPfx, pfx, test.name) - } - } -} - func TestECMP(t *testing.T) { tests := []struct { name string @@ -648,11 +408,12 @@ func TestECMP(t *testing.T) { }, }, ecmp: false, - }, { + }, + { name: "Netlink Path ecmp", left: &Path{ - Type: NetlinkPathType, - NetlinkPath: &NetlinkPath{ + Type: FIBPathType, + FIBPath: &FIBPath{ Src: bnet.IPv4(123), Priority: 1, Protocol: 1, @@ -661,8 +422,8 @@ func TestECMP(t *testing.T) { }, }, right: &Path{ - Type: NetlinkPathType, - NetlinkPath: &NetlinkPath{ + Type: FIBPathType, + FIBPath: &FIBPath{ Src: bnet.IPv4(123), Priority: 1, Protocol: 1, @@ -674,8 +435,8 @@ func TestECMP(t *testing.T) { }, { name: "Netlink Path not ecmp", left: &Path{ - Type: NetlinkPathType, - NetlinkPath: &NetlinkPath{ + Type: FIBPathType, + FIBPath: &FIBPath{ Src: bnet.IPv4(123), Priority: 1, Protocol: 1, @@ -684,8 +445,8 @@ func TestECMP(t *testing.T) { }, }, right: &Path{ - Type: NetlinkPathType, - NetlinkPath: &NetlinkPath{ + Type: FIBPathType, + FIBPath: &FIBPath{ Src: bnet.IPv4(123), Priority: 2, Protocol: 1, @@ -734,23 +495,23 @@ func TestECMP(t *testing.T) { } } -func TestNetlinkPathSelect(t *testing.T) { +func TestFIBPathSelect(t *testing.T) { tests := []struct { name string - left *NetlinkPath - right *NetlinkPath + left *FIBPath + right *FIBPath expected int8 }{ { name: "equal", - left: &NetlinkPath{ + left: &FIBPath{ NextHop: bnet.IPv4(123), Src: bnet.IPv4(234), Priority: 1, Protocol: 1, Table: 1, }, - right: &NetlinkPath{ + right: &FIBPath{ NextHop: bnet.IPv4(123), Src: bnet.IPv4(234), Priority: 1, @@ -761,100 +522,100 @@ func TestNetlinkPathSelect(t *testing.T) { }, { name: "nextHop smaller", - left: &NetlinkPath{ + left: &FIBPath{ NextHop: bnet.IPv4(1), }, - right: &NetlinkPath{ + right: &FIBPath{ NextHop: bnet.IPv4(2), }, expected: -1, }, { name: "nextHop bigger", - left: &NetlinkPath{ + left: &FIBPath{ NextHop: bnet.IPv4(2), }, - right: &NetlinkPath{ + right: &FIBPath{ NextHop: bnet.IPv4(1), }, expected: 1, }, { name: "src smaller", - left: &NetlinkPath{ + left: &FIBPath{ Src: bnet.IPv4(1), }, - right: &NetlinkPath{ + right: &FIBPath{ Src: bnet.IPv4(2), }, expected: -1, }, { name: "src bigger", - left: &NetlinkPath{ + left: &FIBPath{ Src: bnet.IPv4(2), }, - right: &NetlinkPath{ + right: &FIBPath{ Src: bnet.IPv4(1), }, expected: 1, }, { name: "priority smaller", - left: &NetlinkPath{ + left: &FIBPath{ Priority: 1, }, - right: &NetlinkPath{ + right: &FIBPath{ Priority: 2, }, expected: -1, }, { name: "priority bigger", - left: &NetlinkPath{ + left: &FIBPath{ Priority: 2, }, - right: &NetlinkPath{ + right: &FIBPath{ Priority: 1, }, expected: 1, }, { name: "protocol smaller", - left: &NetlinkPath{ + left: &FIBPath{ Protocol: 1, }, - right: &NetlinkPath{ + right: &FIBPath{ Protocol: 2, }, expected: -1, }, { name: "protocol bigger", - left: &NetlinkPath{ + left: &FIBPath{ Protocol: 2, }, - right: &NetlinkPath{ + right: &FIBPath{ Protocol: 1, }, expected: 1, }, { name: "table smaller", - left: &NetlinkPath{ + left: &FIBPath{ Table: 1, }, - right: &NetlinkPath{ + right: &FIBPath{ Table: 2, }, expected: -1, }, { name: "table bigger", - left: &NetlinkPath{ + left: &FIBPath{ Table: 2, }, - right: &NetlinkPath{ + right: &FIBPath{ Table: 1, }, expected: 1, diff --git a/route/route.go b/route/route.go index fccb5955303ab04661b80802ce29e896fd2bf9de..1395b157f843559f9e82b51e247cc063faa17e23 100644 --- a/route/route.go +++ b/route/route.go @@ -6,7 +6,6 @@ import ( "sync" "github.com/bio-routing/bio-rd/net" - "github.com/vishvananda/netlink" ) const ( @@ -24,8 +23,8 @@ const ( // ISISPathType indicates a path is an ISIS path ISISPathType - // NetlinkPathType indicates a path is an Netlink/Kernel path - NetlinkPathType + // FIBPathType indicates a path is a FIB path + FIBPathType ) // Route links a prefix to paths @@ -278,51 +277,3 @@ func (r *Route) Print() string { return ret } - -// NetlinkRouteDiff gets the list of elements contained by a but not b -func NetlinkRouteDiff(a, b []netlink.Route) []netlink.Route { - ret := make([]netlink.Route, 0) - - for _, pa := range a { - if !netlinkRoutesContains(pa, b) { - ret = append(ret, pa) - } - } - - return ret -} - -func netlinkRoutesContains(needle netlink.Route, haystack []netlink.Route) bool { - for i := range haystack { - if netlinkRouteEquals(&needle, &haystack[i]) { - return true - } - } - - return false -} - -func netlinkRouteEquals(a, b *netlink.Route) bool { - aMaskSize, aMaskBits := a.Dst.Mask.Size() - bMaskSize, bMaskBits := b.Dst.Mask.Size() - - return a.LinkIndex == b.LinkIndex && - a.ILinkIndex == b.ILinkIndex && - a.Scope == b.Scope && - - a.Dst.IP.Equal(b.Dst.IP) && - aMaskSize == bMaskSize && - aMaskBits == bMaskBits && - - a.Src.Equal(b.Src) && - a.Gw.Equal(b.Gw) && - - a.Protocol == b.Protocol && - a.Priority == b.Priority && - a.Table == b.Table && - a.Type == b.Type && - a.Tos == b.Tos && - a.Flags == b.Flags && - a.MTU == b.MTU && - a.AdvMSS == b.AdvMSS -} diff --git a/route/route_test.go b/route/route_test.go index b23a39e1a7ef14b127993ec7b64583f31110c118..bb3162ca1ff2935dbace2a7392fa629904e3cab8 100644 --- a/route/route_test.go +++ b/route/route_test.go @@ -1,158 +1,13 @@ package route import ( - "net" "testing" "github.com/stretchr/testify/assert" - "github.com/vishvananda/netlink" bnet "github.com/bio-routing/bio-rd/net" ) -func TestNetlinkRouteDiff(t *testing.T) { - tests := []struct { - name string - left []netlink.Route - right []netlink.Route - expected []netlink.Route - }{ - { - name: "Equal", - left: []netlink.Route{ - { - Dst: &net.IPNet{ - IP: net.IPv4(10, 0, 0, 1), - Mask: net.IPv4Mask(255, 0, 0, 0), - }, - Table: 1, - }, - { - Dst: &net.IPNet{ - IP: net.IPv4(20, 0, 0, 1), - Mask: net.IPv4Mask(255, 0, 0, 0), - }, - Table: 2, - }, - }, - right: []netlink.Route{ - { - Dst: &net.IPNet{ - IP: net.IPv4(10, 0, 0, 1), - Mask: net.IPv4Mask(255, 0, 0, 0), - }, - Table: 1, - }, - { - Dst: &net.IPNet{ - IP: net.IPv4(20, 0, 0, 1), - Mask: net.IPv4Mask(255, 0, 0, 0), - }, - Table: 2, - }, - }, - expected: []netlink.Route{}, - }, { - name: "Left empty", - left: []netlink.Route{}, - right: []netlink.Route{ - { - Dst: &net.IPNet{ - IP: net.IPv4(10, 0, 0, 1), - Mask: net.IPv4Mask(255, 0, 0, 0), - }, - Table: 1, - }, - { - Dst: &net.IPNet{ - IP: net.IPv4(20, 0, 0, 1), - Mask: net.IPv4Mask(255, 0, 0, 0), - }, - Table: 2, - }, - }, - expected: []netlink.Route{}, - }, { - name: "Right empty", - left: []netlink.Route{ - { - Dst: &net.IPNet{ - IP: net.IPv4(10, 0, 0, 1), - Mask: net.IPv4Mask(255, 0, 0, 0), - }, - Table: 1, - }, - { - Dst: &net.IPNet{ - IP: net.IPv4(20, 0, 0, 1), - Mask: net.IPv4Mask(255, 0, 0, 0), - }, - Table: 2, - }, - }, - right: []netlink.Route{}, - expected: []netlink.Route{ - { - Dst: &net.IPNet{ - IP: net.IPv4(10, 0, 0, 1), - Mask: net.IPv4Mask(255, 0, 0, 0), - }, - Table: 1, - }, - { - Dst: &net.IPNet{ - IP: net.IPv4(20, 0, 0, 1), - Mask: net.IPv4Mask(255, 0, 0, 0), - }, - Table: 2, - }, - }, - }, { - name: "Diff", - left: []netlink.Route{ - { - Dst: &net.IPNet{ - IP: net.IPv4(10, 0, 0, 1), - Mask: net.IPv4Mask(255, 0, 0, 0), - }, - Table: 1, - }, - { - Dst: &net.IPNet{ - IP: net.IPv4(20, 0, 0, 1), - Mask: net.IPv4Mask(255, 0, 0, 0), - }, - Table: 2, - }, - }, - right: []netlink.Route{ - { - Dst: &net.IPNet{ - IP: net.IPv4(10, 0, 0, 1), - Mask: net.IPv4Mask(255, 0, 0, 0), - }, - Table: 1, - }, - }, - expected: []netlink.Route{ - { - Dst: &net.IPNet{ - IP: net.IPv4(20, 0, 0, 1), - Mask: net.IPv4Mask(255, 0, 0, 0), - }, - Table: 2, - }, - }, - }, - } - - for _, test := range tests { - res := NetlinkRouteDiff(test.left, test.right) - assert.Equal(t, test.expected, res) - } - -} - func TestNewRoute(t *testing.T) { tests := []struct { name string