From d55bc402ba103756b82afedf5d15ef46d8740fbf Mon Sep 17 00:00:00 2001
From: cedi <cedi@users.noreply.github.com>
Date: Mon, 22 Oct 2018 22:35:16 +0200
Subject: [PATCH] Cleanup code and address @BarbarossaTM pull request remarks

- Remove Makefile for adding it later in a seperate PR
- Remove main files which where added by accident
- Add constants for IPv4 and IPv6
- Improve log messages
- Simplify netlink_reader addPathsToClients and removePathsFromClients
- Refactor Route's Equal function
- Return false for ECMP in netlink_path since ecmp is currently not
implemented in netlink
---
 Makefile                            |  26 ------
 main.go                             |  63 --------------
 main_ipv4.go                        |  49 -----------
 main_ipv6.go                        |  72 ---------------
 protocols/netlink/netlink.go        |   4 +-
 protocols/netlink/netlink_reader.go | 130 ++++++++++++++++------------
 route/netlink_path.go               |   2 +-
 route/route.go                      |  34 ++++----
 8 files changed, 94 insertions(+), 286 deletions(-)
 delete mode 100644 Makefile
 delete mode 100644 main.go
 delete mode 100644 main_ipv4.go
 delete mode 100644 main_ipv6.go

diff --git a/Makefile b/Makefile
deleted file mode 100644
index 22eb8c21..00000000
--- a/Makefile
+++ /dev/null
@@ -1,26 +0,0 @@
-NAME=bio-rd
-
-all: test
-
-$(NAME): gazelle
-	bazel build //:bio-rd
-
-gazelle:
-	bazel run //:gazelle -- update
-
-test: $(NAME)
-	bazel test //...
-
-dep:
-	bazel build //vendor/github.com/golang/dep/cmd/dep
-
-dep-clean:
-	# hack: dep of dep gives us these, and it breaks gazelle
-	rm -rf vendor/github.com/golang/dep/cmd/dep/testdata
-	rm -rf vendor/github.com/golang/dep/internal/fs/testdata/symlinks/dir-symlink
-
-clean: dep-clean
-	bazel clean
-	rm $(NAME)
-
-.PHONY: $(NAME) gazelle clean dep dep-clean
diff --git a/main.go b/main.go
deleted file mode 100644
index 659857da..00000000
--- a/main.go
+++ /dev/null
@@ -1,63 +0,0 @@
-package main
-
-import (
-	"net"
-	"os"
-	"time"
-
-	"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/routingtable/locRIB"
-	log "github.com/sirupsen/logrus"
-
-	bnet "github.com/bio-routing/bio-rd/net"
-)
-
-func strAddr(s string) uint32 {
-	ret, _ := bnet.StrToAddr(s)
-	return ret
-}
-
-func main() {
-	log.SetLevel(log.DebugLevel)
-
-	f, err := os.OpenFile("/var/log/bio-rd.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
-	if err != nil {
-		log.Fatalf("error opening file: %v", err)
-	}
-	defer f.Close()
-
-	log.SetOutput(f)
-
-	log.Info("bio-routing started...\n")
-
-	cfg := &config.Global{
-		Listen: true,
-		LocalAddressList: []net.IP{
-			net.IPv4(169, 254, 0, 2),
-		},
-	}
-
-	rib := locRIB.New()
-	b := server.NewBgpServer()
-	startBGPServer(b, rib, cfg)
-
-	// Netlink communication
-	n := protocolnetlink.NewNetlink(&config.Netlink{
-		HoldTime:       time.Second * 15,
-		UpdateInterval: time.Second * 15,
-		RoutingTable:   config.RtMain,
-	}, rib)
-	n.Start()
-
-	go func() {
-		for {
-			log.Debugf("LocRIB count: %d", rib.Count())
-			log.Debugf(rib.Print())
-			time.Sleep(time.Second * 10)
-		}
-	}()
-
-	select {}
-}
diff --git a/main_ipv4.go b/main_ipv4.go
deleted file mode 100644
index 12bb67ae..00000000
--- a/main_ipv4.go
+++ /dev/null
@@ -1,49 +0,0 @@
-package main
-
-import (
-	"time"
-
-	"github.com/bio-routing/bio-rd/routingtable"
-	"github.com/bio-routing/bio-rd/routingtable/locRIB"
-
-	"github.com/bio-routing/bio-rd/config"
-	"github.com/bio-routing/bio-rd/protocols/bgp/server"
-	"github.com/bio-routing/bio-rd/routingtable/filter"
-	log "github.com/sirupsen/logrus"
-
-	bnet "github.com/bio-routing/bio-rd/net"
-)
-
-func startBGPServer(b server.BGPServer, rib *locRIB.LocRIB, cfg *config.Global) {
-	err := b.Start(cfg)
-	if err != nil {
-		log.Fatalf("Unable to start BGP server: %v", err)
-	}
-
-	b.AddPeer(config.Peer{
-		AdminEnabled:      true,
-		LocalAS:           65200,
-		PeerAS:            65100,
-		PeerAddress:       bnet.IPv4FromOctets(169, 254, 0, 1),
-		LocalAddress:      bnet.IPv4FromOctets(169, 254, 0, 2),
-		ReconnectInterval: time.Second * 20,
-		HoldTime:          time.Second * 20,
-		KeepAlive:         time.Second * 20,
-		Passive:           false,
-		RouterID:          b.RouterID(),
-
-		//AddPathSend: routingtable.ClientOptions{
-		//	MaxPaths: 10,
-		//},
-		//RouteServerClient: true,
-		IPv4: &config.AddressFamilyConfig{
-			RIB:          rib,
-			ImportFilter: filter.NewAcceptAllFilter(),
-			ExportFilter: filter.NewAcceptAllFilter(),
-			AddPathSend: routingtable.ClientOptions{
-				MaxPaths: 10,
-			},
-			AddPathRecv: true,
-		},
-	})
-}
diff --git a/main_ipv6.go b/main_ipv6.go
deleted file mode 100644
index cc26484b..00000000
--- a/main_ipv6.go
+++ /dev/null
@@ -1,72 +0,0 @@
-// +build ipv6
-
-package main
-
-import (
-	"net"
-	"time"
-
-	"github.com/bio-routing/bio-rd/config"
-	"github.com/bio-routing/bio-rd/protocols/bgp/server"
-	"github.com/bio-routing/bio-rd/routingtable"
-	"github.com/bio-routing/bio-rd/routingtable/filter"
-	"github.com/bio-routing/bio-rd/routingtable/locRIB"
-	"github.com/sirupsen/logrus"
-
-	bnet "github.com/bio-routing/bio-rd/net"
-)
-
-func startServer(b server.BGPServer, rib *locRIB.LocRIB) {
-
-	err := b.Start(&config.Global{
-		Listen: true,
-		LocalAddressList: []net.IP{
-			net.IP{0x20, 0x01, 0x6, 0x78, 0x1, 0xe0, 0, 0, 0, 0, 0, 0, 0, 0, 0xca, 0xfe},
-		},
-	})
-	if err != nil {
-		logrus.Fatalf("Unable to start BGP server: %v", err)
-	}
-
-	b.AddPeer(config.Peer{
-		AdminEnabled:      true,
-		LocalAS:           65200,
-		PeerAS:            202739,
-		PeerAddress:       bnet.IPv6FromBlocks(0x2001, 0x678, 0x1e0, 0, 0, 0, 0, 1),
-		LocalAddress:      bnet.IPv6FromBlocks(0x2001, 0x678, 0x1e0, 0, 0, 0, 0, 0xcafe),
-		ReconnectInterval: time.Second * 15,
-		HoldTime:          time.Second * 90,
-		KeepAlive:         time.Second * 30,
-		Passive:           true,
-		RouterID:          b.RouterID(),
-		IPv6: &config.AddressFamilyConfig{
-			RIB:          rib,
-			ImportFilter: filter.NewAcceptAllFilter(),
-			ExportFilter: filter.NewDrainFilter(),
-			AddPathSend: routingtable.ClientOptions{
-				BestOnly: true,
-			},
-		},
-	})
-
-	b.AddPeer(config.Peer{
-		AdminEnabled:      true,
-		LocalAS:           65200,
-		PeerAS:            65400,
-		PeerAddress:       bnet.IPv6FromBlocks(0x2001, 0x678, 0x1e0, 0xcafe, 0, 0, 0, 5),
-		LocalAddress:      bnet.IPv6FromBlocks(0x2001, 0x678, 0x1e0, 0, 0, 0, 0, 0xcafe),
-		ReconnectInterval: time.Second * 15,
-		HoldTime:          time.Second * 90,
-		KeepAlive:         time.Second * 30,
-		Passive:           true,
-		RouterID:          b.RouterID(),
-		IPv6: &config.AddressFamilyConfig{
-			RIB:          rib,
-			ImportFilter: filter.NewDrainFilter(),
-			ExportFilter: filter.NewAcceptAllFilter(),
-			AddPathSend: routingtable.ClientOptions{
-				BestOnly: true,
-			},
-		},
-	})
-}
diff --git a/protocols/netlink/netlink.go b/protocols/netlink/netlink.go
index f5fdedce..fa39d601 100644
--- a/protocols/netlink/netlink.go
+++ b/protocols/netlink/netlink.go
@@ -37,9 +37,9 @@ func (n *Netlink) Start() {
 	// 1. from locRib to Kernel
 	n.locRib.ClientManager.RegisterWithOptions(n.writer, options)
 
-	// 2. vom Kernel to locRib
+	// 2. from Kernel to locRib
 	n.reader.ClientManager.RegisterWithOptions(n.locRib, options)
 
-	// Listn for new routes from kernel
+	// Listen for new routes from kernel
 	go n.reader.Read()
 }
diff --git a/protocols/netlink/netlink_reader.go b/protocols/netlink/netlink_reader.go
index 75a97637..b4d16ea5 100644
--- a/protocols/netlink/netlink_reader.go
+++ b/protocols/netlink/netlink_reader.go
@@ -14,6 +14,12 @@ import (
 	"github.com/vishvananda/netlink"
 )
 
+// Constants for IP family
+const (
+	IPFamily4 = 4 // IPv4
+	IPFamily6 = 6 // IPv6
+)
+
 // NetlinkReader read routes from the Linux Kernel and propagates it to the locRIB
 type NetlinkReader struct {
 	options *config.Netlink
@@ -45,7 +51,7 @@ func (nr *NetlinkReader) Read() {
 
 	for {
 		// Family doesn't matter. I only filter by the rt_table here
-		routes, err := netlink.RouteListFiltered(4, &netlink.Route{Table: nr.options.RoutingTable}, netlink.RT_FILTER_TABLE)
+		routes, err := netlink.RouteListFiltered(IPFamily4, &netlink.Route{Table: nr.options.RoutingTable}, netlink.RT_FILTER_TABLE)
 		if err != nil {
 			log.WithError(err).Panic("Failed to read routes from kernel")
 		}
@@ -84,39 +90,45 @@ func (nr *NetlinkReader) propagateChanges(routes []netlink.Route) {
 
 // Add given paths to clients
 func (nr *NetlinkReader) addPathsToClients(routes []netlink.Route) {
-	for _, client := range nr.ClientManager.Clients() {
-		// only advertise changed routes
+	// only advertise changed routes
+	nr.mu.RLock()
+	advertise := route.NetlinkRouteDiff(routes, nr.routes)
+	nr.mu.RUnlock()
+
+	for _, r := range advertise {
+		// Is it a BIO-Written route? if so, skip it, dont advertise it
+		if r.Protocol == route.ProtoBio {
+			log.WithFields(routeLogFields(r)).Debug("Skipping bio route")
+			continue
+		}
 
-		nr.mu.RLock()
-		advertise := route.NetlinkRouteDiff(routes, nr.routes)
-		nr.mu.RUnlock()
+		// create pfx and path from route
+		pfx := bnet.NewPfxFromIPNet(r.Dst)
+		path, err := createPathFromRoute(&r)
+		if err != nil {
+			log.WithError(err).WithFields(log.Fields{
+				"prefix": pfx.String(),
+				"path":   path.String(),
+			}).Error("Unable to create path")
+			continue
+		}
 
-		for _, r := range advertise {
-			// Is it a BIO-Written route? if so, skip it, dont advertise it
-			if r.Protocol == route.ProtoBio {
-				log.WithFields(routeLogFields(r)).Debug("Skipping bio route")
-				continue
-			}
+		// Apply filter (if existing)
+		if nr.filter != nil {
+			var reject bool
+			// TODO: Implement filter that cann handle netlinkRoute objects
+			path, reject = nr.filter.ProcessTerms(pfx, path)
+			if reject {
+				log.WithError(err).WithFields(log.Fields{
+					"prefix": pfx.String(),
+					"path":   path.String(),
+				}).Debug("Skipping route due to filter")
 
-			// create pfx and path from route
-			pfx := bnet.NewPfxFromIPNet(r.Dst)
-			path, err := createPathFromRoute(&r)
-			if err != nil {
-				log.WithError(err).Error("Unable to create path")
 				continue
 			}
+		}
 
-			// Apply filter (if existing)
-			if nr.filter != nil {
-				var reject bool
-				// TODO: Implement filter that cann handle netlinkRoute objects
-				path, reject = nr.filter.ProcessTerms(pfx, path)
-				if reject {
-					log.Debug("Skipping route due to filter")
-					continue
-				}
-			}
-
+		for _, client := range nr.ClientManager.Clients() {
 			log.WithFields(log.Fields{
 				"pfx":  pfx,
 				"path": path,
@@ -128,42 +140,46 @@ func (nr *NetlinkReader) addPathsToClients(routes []netlink.Route) {
 
 // Remove given paths from clients
 func (nr *NetlinkReader) removePathsFromClients(routes []netlink.Route) {
-	for _, client := range nr.ClientManager.Clients() {
-		// If there where no routes yet, just skip this funktion. There's nothing to delete
-		nr.mu.RLock()
-		if len(nr.routes) == 0 {
-			nr.mu.RUnlock()
-			break
-		}
+	nr.mu.RLock()
+
+	// get the number of routes
+	routeLength := len(nr.routes)
 
-		// only withdraw changed routes
-		withdraw := route.NetlinkRouteDiff(nr.routes, routes)
+	// If there where no routes yet, just skip this funktion. There's nothing to delete
+	if routeLength == 0 {
 		nr.mu.RUnlock()
+		return
+	}
 
-		for _, r := range withdraw {
-			// Is it a BIO-Written route? if so, skip it, dont advertise it
-			if r.Protocol == route.ProtoBio {
-				continue
-			}
+	// only withdraw changed routes
+	withdraw := route.NetlinkRouteDiff(nr.routes, routes)
+	nr.mu.RUnlock()
 
-			// create pfx and path from route
-			pfx := bnet.NewPfxFromIPNet(r.Dst)
-			path, err := createPathFromRoute(&r)
-			if err != nil {
-				log.WithError(err).Error("Unable to create path")
-				continue
-			}
+	for _, r := range withdraw {
+		// Is it a BIO-Written route? if so, skip it, dont advertise it
+		if r.Protocol == route.ProtoBio {
+			continue
+		}
+
+		// create pfx and path from route
+		pfx := bnet.NewPfxFromIPNet(r.Dst)
+		path, err := createPathFromRoute(&r)
+		if err != nil {
+			log.WithError(err).Error("Unable to create path")
+			continue
+		}
 
-			// Apply filter (if existing)
-			if nr.filter != nil {
-				var reject bool
-				// TODO: Implement filter that cann handle netlinkRoute objects
-				path, reject = nr.filter.ProcessTerms(pfx, path)
-				if reject {
-					continue
-				}
+		// Apply filter (if existing)
+		if nr.filter != nil {
+			var reject bool
+			// TODO: Implement filter that cann handle netlinkRoute objects
+			path, reject = nr.filter.ProcessTerms(pfx, path)
+			if reject {
+				continue
 			}
+		}
 
+		for _, client := range nr.ClientManager.Clients() {
 			log.WithFields(log.Fields{
 				"pfx":  pfx,
 				"path": path,
diff --git a/route/netlink_path.go b/route/netlink_path.go
index a0f5e2f4..1f01495a 100644
--- a/route/netlink_path.go
+++ b/route/netlink_path.go
@@ -133,7 +133,7 @@ func (s *NetlinkPath) Select(t *NetlinkPath) int8 {
 
 // ECMP determines if path s and t are equal in terms of ECMP
 func (s *NetlinkPath) ECMP(t *NetlinkPath) bool {
-	return true
+	return false
 }
 
 // Copy duplicates the current object
diff --git a/route/route.go b/route/route.go
index 59b25f71..e7f6730b 100644
--- a/route/route.go
+++ b/route/route.go
@@ -199,36 +199,38 @@ func (r *Route) PathSelection() {
 	r.updateEqualPathCount()
 }
 
-// Euql compares Are two routes and return true if they are equal
+// Equal compares if two routes are the same
 func (r *Route) Equal(other *Route) bool {
 	r.mu.Lock()
 	defer r.mu.Unlock()
 
-	a := r.pfx.Equal(other.pfx)
-	b := r.ecmpPaths == other.ecmpPaths
-	c := true
+	pfxEqual := r.pfx.Equal(other.pfx)
+	ecmpPathsEqual := r.ecmpPaths == other.ecmpPaths
+	pathsEqual := comparePathSlice(r.paths, other.paths)
 
-	if r.paths == nil && other.paths == nil {
-		c = true
-		return a && b && c
+	return pfxEqual && ecmpPathsEqual && pathsEqual
+}
+
+// Compare two path pointer slices if they are equal
+func comparePathSlice(left, right []*Path) bool {
+	if left == nil && right == nil {
+		return true
 	}
 
-	if len(r.paths) != len(other.paths) {
-		c = false
-		return a && b && c
+	if len(left) != len(right) {
+		return false
 	}
 
-	for _, myP := range r.paths {
-		if !r.compareItemExists(myP, other.paths) {
-			c = false
-			return a && b && c
+	for _, leftPath := range left {
+		if !compareItemExists(leftPath, right) {
+			return false
 		}
 	}
 
-	return a && b && c
+	return true
 }
 
-func (r *Route) compareItemExists(needle *Path, haystack []*Path) bool {
+func compareItemExists(needle *Path, haystack []*Path) bool {
 	for _, compare := range haystack {
 		if needle.Equal(compare) {
 			return true
-- 
GitLab