Skip to content
Snippets Groups Projects
Commit d55bc402 authored by cedi's avatar cedi
Browse files

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
parent 6c0bab61
No related branches found
No related tags found
No related merge requests found
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
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 {}
}
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,
},
})
}
// +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,
},
},
})
}
...@@ -37,9 +37,9 @@ func (n *Netlink) Start() { ...@@ -37,9 +37,9 @@ func (n *Netlink) Start() {
// 1. from locRib to Kernel // 1. from locRib to Kernel
n.locRib.ClientManager.RegisterWithOptions(n.writer, options) n.locRib.ClientManager.RegisterWithOptions(n.writer, options)
// 2. vom Kernel to locRib // 2. from Kernel to locRib
n.reader.ClientManager.RegisterWithOptions(n.locRib, options) n.reader.ClientManager.RegisterWithOptions(n.locRib, options)
// Listn for new routes from kernel // Listen for new routes from kernel
go n.reader.Read() go n.reader.Read()
} }
...@@ -14,6 +14,12 @@ import ( ...@@ -14,6 +14,12 @@ import (
"github.com/vishvananda/netlink" "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 // NetlinkReader read routes from the Linux Kernel and propagates it to the locRIB
type NetlinkReader struct { type NetlinkReader struct {
options *config.Netlink options *config.Netlink
...@@ -45,7 +51,7 @@ func (nr *NetlinkReader) Read() { ...@@ -45,7 +51,7 @@ func (nr *NetlinkReader) Read() {
for { for {
// Family doesn't matter. I only filter by the rt_table here // 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 { if err != nil {
log.WithError(err).Panic("Failed to read routes from kernel") log.WithError(err).Panic("Failed to read routes from kernel")
} }
...@@ -84,39 +90,45 @@ func (nr *NetlinkReader) propagateChanges(routes []netlink.Route) { ...@@ -84,39 +90,45 @@ func (nr *NetlinkReader) propagateChanges(routes []netlink.Route) {
// Add given paths to clients // Add given paths to clients
func (nr *NetlinkReader) addPathsToClients(routes []netlink.Route) { 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() // create pfx and path from route
advertise := route.NetlinkRouteDiff(routes, nr.routes) pfx := bnet.NewPfxFromIPNet(r.Dst)
nr.mu.RUnlock() 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 { // Apply filter (if existing)
// Is it a BIO-Written route? if so, skip it, dont advertise it if nr.filter != nil {
if r.Protocol == route.ProtoBio { var reject bool
log.WithFields(routeLogFields(r)).Debug("Skipping bio route") // TODO: Implement filter that cann handle netlinkRoute objects
continue 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 continue
} }
}
// Apply filter (if existing) for _, client := range nr.ClientManager.Clients() {
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
}
}
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"pfx": pfx, "pfx": pfx,
"path": path, "path": path,
...@@ -128,42 +140,46 @@ func (nr *NetlinkReader) addPathsToClients(routes []netlink.Route) { ...@@ -128,42 +140,46 @@ func (nr *NetlinkReader) addPathsToClients(routes []netlink.Route) {
// Remove given paths from clients // Remove given paths from clients
func (nr *NetlinkReader) removePathsFromClients(routes []netlink.Route) { func (nr *NetlinkReader) removePathsFromClients(routes []netlink.Route) {
for _, client := range nr.ClientManager.Clients() { nr.mu.RLock()
// If there where no routes yet, just skip this funktion. There's nothing to delete
nr.mu.RLock() // get the number of routes
if len(nr.routes) == 0 { routeLength := len(nr.routes)
nr.mu.RUnlock()
break
}
// only withdraw changed routes // If there where no routes yet, just skip this funktion. There's nothing to delete
withdraw := route.NetlinkRouteDiff(nr.routes, routes) if routeLength == 0 {
nr.mu.RUnlock() nr.mu.RUnlock()
return
}
for _, r := range withdraw { // only withdraw changed routes
// Is it a BIO-Written route? if so, skip it, dont advertise it withdraw := route.NetlinkRouteDiff(nr.routes, routes)
if r.Protocol == route.ProtoBio { nr.mu.RUnlock()
continue
}
// create pfx and path from route for _, r := range withdraw {
pfx := bnet.NewPfxFromIPNet(r.Dst) // Is it a BIO-Written route? if so, skip it, dont advertise it
path, err := createPathFromRoute(&r) if r.Protocol == route.ProtoBio {
if err != nil { continue
log.WithError(err).Error("Unable to create path") }
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) // Apply filter (if existing)
if nr.filter != nil { if nr.filter != nil {
var reject bool var reject bool
// TODO: Implement filter that cann handle netlinkRoute objects // TODO: Implement filter that cann handle netlinkRoute objects
path, reject = nr.filter.ProcessTerms(pfx, path) path, reject = nr.filter.ProcessTerms(pfx, path)
if reject { if reject {
continue continue
}
} }
}
for _, client := range nr.ClientManager.Clients() {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"pfx": pfx, "pfx": pfx,
"path": path, "path": path,
......
...@@ -133,7 +133,7 @@ func (s *NetlinkPath) Select(t *NetlinkPath) int8 { ...@@ -133,7 +133,7 @@ func (s *NetlinkPath) Select(t *NetlinkPath) int8 {
// ECMP determines if path s and t are equal in terms of ECMP // ECMP determines if path s and t are equal in terms of ECMP
func (s *NetlinkPath) ECMP(t *NetlinkPath) bool { func (s *NetlinkPath) ECMP(t *NetlinkPath) bool {
return true return false
} }
// Copy duplicates the current object // Copy duplicates the current object
......
...@@ -199,36 +199,38 @@ func (r *Route) PathSelection() { ...@@ -199,36 +199,38 @@ func (r *Route) PathSelection() {
r.updateEqualPathCount() 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 { func (r *Route) Equal(other *Route) bool {
r.mu.Lock() r.mu.Lock()
defer r.mu.Unlock() defer r.mu.Unlock()
a := r.pfx.Equal(other.pfx) pfxEqual := r.pfx.Equal(other.pfx)
b := r.ecmpPaths == other.ecmpPaths ecmpPathsEqual := r.ecmpPaths == other.ecmpPaths
c := true pathsEqual := comparePathSlice(r.paths, other.paths)
if r.paths == nil && other.paths == nil { return pfxEqual && ecmpPathsEqual && pathsEqual
c = true }
return a && b && c
// 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) { if len(left) != len(right) {
c = false return false
return a && b && c
} }
for _, myP := range r.paths { for _, leftPath := range left {
if !r.compareItemExists(myP, other.paths) { if !compareItemExists(leftPath, right) {
c = false return false
return a && b && c
} }
} }
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 { for _, compare := range haystack {
if needle.Equal(compare) { if needle.Equal(compare) {
return true return true
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment