Skip to content
Snippets Groups Projects
Commit d68903f7 authored by Oliver Herms's avatar Oliver Herms
Browse files

Implemented neighbor address validation

parent c30ce8ae
No related branches found
No related tags found
No related merge requests found
...@@ -5,6 +5,7 @@ import ( ...@@ -5,6 +5,7 @@ import (
"sync" "sync"
"github.com/bio-routing/bio-rd/config" "github.com/bio-routing/bio-rd/config"
bnet "github.com/bio-routing/bio-rd/net"
"github.com/bio-routing/bio-rd/protocols/device" "github.com/bio-routing/bio-rd/protocols/device"
"github.com/bio-routing/bio-rd/protocols/isis/packet" "github.com/bio-routing/bio-rd/protocols/isis/packet"
"github.com/bio-routing/bio-rd/protocols/isis/types" "github.com/bio-routing/bio-rd/protocols/isis/types"
...@@ -42,7 +43,7 @@ type level struct { ...@@ -42,7 +43,7 @@ type level struct {
HelloInterval uint16 HelloInterval uint16
HoldTime uint16 HoldTime uint16
Metric uint32 Metric uint32
neighborManager *neighborManager neighborManager neighborManagerInterface
} }
func newDev(srv *Server, ifcfg *config.ISISInterfaceConfig) *dev { func newDev(srv *Server, ifcfg *config.ISISInterfaceConfig) *dev {
...@@ -64,7 +65,7 @@ func newDev(srv *Server, ifcfg *config.ISISInterfaceConfig) *dev { ...@@ -64,7 +65,7 @@ func newDev(srv *Server, ifcfg *config.ISISInterfaceConfig) *dev {
d.level2.HelloInterval = ifcfg.ISISLevel2Config.HelloInterval d.level2.HelloInterval = ifcfg.ISISLevel2Config.HelloInterval
d.level2.HoldTime = ifcfg.ISISLevel2Config.HoldTime d.level2.HoldTime = ifcfg.ISISLevel2Config.HoldTime
d.level2.Metric = ifcfg.ISISLevel2Config.Metric d.level2.Metric = ifcfg.ISISLevel2Config.Metric
d.level2.neighborManager = newNeighborManager() d.level2.neighborManager = newNeighborManager(d)
} }
return d return d
...@@ -124,3 +125,16 @@ func (d *dev) disable() error { ...@@ -124,3 +125,16 @@ func (d *dev) disable() error {
d.up = false d.up = false
return nil return nil
} }
func (d *dev) validateNeighborAddresses(addrs []uint32) []uint32 {
res := make([]uint32, 0, len(addrs))
for i := range addrs {
for j := range d.phy.Addrs {
if d.phy.Addrs[j].Contains(bnet.NewPfx(bnet.IPv4(addrs[i]), 32)) {
res = append(res, addrs[i])
}
}
}
return res
}
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"testing" "testing"
"github.com/bio-routing/bio-rd/config" "github.com/bio-routing/bio-rd/config"
"github.com/bio-routing/bio-rd/net"
"github.com/bio-routing/bio-rd/protocols/device" "github.com/bio-routing/bio-rd/protocols/device"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
...@@ -256,3 +257,57 @@ func TestDeviceAddDevice(t *testing.T) { ...@@ -256,3 +257,57 @@ func TestDeviceAddDevice(t *testing.T) {
assert.Equal(t, test.expected, test.dm, test.name) assert.Equal(t, test.expected, test.dm, test.name)
} }
} }
func TestValidateNeighborAddresses(t *testing.T) {
tests := []struct {
name string
d *dev
addrs []uint32
expected []uint32
}{
{
name: "Test #1",
d: &dev{
phy: &device.Device{
Addrs: []net.Prefix{
net.NewPfx(net.IPv4FromOctets(10, 0, 0, 0), 24),
},
},
},
addrs: []uint32{
net.IPv4FromOctets(10, 0, 0, 2).ToUint32(),
},
expected: []uint32{
net.IPv4FromOctets(10, 0, 0, 2).ToUint32(),
},
},
{
name: "Test #2",
d: &dev{
phy: &device.Device{
Addrs: []net.Prefix{
net.NewPfx(net.IPv4FromOctets(10, 0, 0, 0), 30),
net.NewPfx(net.IPv4FromOctets(10, 0, 0, 4), 30),
net.NewPfx(net.IPv4FromOctets(192, 168, 100, 0), 22),
},
},
},
addrs: []uint32{
net.IPv4FromOctets(100, 100, 100, 100).ToUint32(),
net.IPv4FromOctets(10, 0, 0, 5).ToUint32(),
net.IPv4FromOctets(10, 0, 0, 9).ToUint32(),
net.IPv4FromOctets(192, 168, 101, 22).ToUint32(),
net.IPv4FromOctets(10, 0, 0, 22).ToUint32(),
},
expected: []uint32{
net.IPv4FromOctets(10, 0, 0, 5).ToUint32(),
net.IPv4FromOctets(192, 168, 101, 22).ToUint32(),
},
},
}
for _, test := range tests {
res := test.d.validateNeighborAddresses(test.addrs)
assert.Equal(t, test.expected, res, test.name)
}
}
...@@ -13,20 +13,20 @@ func (d *dev) helloRoutine() { ...@@ -13,20 +13,20 @@ func (d *dev) helloRoutine() {
} }
func (d *dev) processP2PHello(h *packet.P2PHello, src types.MACAddress) error { func (d *dev) processP2PHello(h *packet.P2PHello, src types.MACAddress) error {
n, err := d.p2pHelloToNeighbor(h)
if err != nil {
return errors.Wrap(err, "Unable to create neighbor object from hello")
}
if h.CircuitType != 2 { if h.CircuitType != 2 {
return fmt.Errorf("Unsupported P2P Hello: Level 1") return fmt.Errorf("Unsupported P2P Hello: Level 1")
} }
d.level2.neighborManager.setNeighbor(src, n) n, err := d.p2pHelloToNeighbor(h, src)
if err != nil {
return errors.Wrap(err, "Unable to create neighbor object from hello")
}
d.level2.neighborManager.setNeighbor(n)
return nil return nil
} }
func (d *dev) p2pHelloToNeighbor(h *packet.P2PHello) (*neighbor, error) { func (d *dev) p2pHelloToNeighbor(h *packet.P2PHello, src types.MACAddress) (*neighbor, error) {
p2pAdjTLV := h.GetP2PAdjTLV() p2pAdjTLV := h.GetP2PAdjTLV()
if p2pAdjTLV == nil { if p2pAdjTLV == nil {
return nil, fmt.Errorf("Received a P2P hello PDU without P2P Adjacency TLV on %s", d.name) return nil, fmt.Errorf("Received a P2P hello PDU without P2P Adjacency TLV on %s", d.name)
...@@ -38,6 +38,7 @@ func (d *dev) p2pHelloToNeighbor(h *packet.P2PHello) (*neighbor, error) { ...@@ -38,6 +38,7 @@ func (d *dev) p2pHelloToNeighbor(h *packet.P2PHello) (*neighbor, error) {
} }
n := &neighbor{ n := &neighbor{
macAddress: src,
systemID: h.SystemID, systemID: h.SystemID,
dev: d, dev: d,
holdingTime: h.HoldingTimer, holdingTime: h.HoldingTimer,
......
...@@ -8,6 +8,115 @@ import ( ...@@ -8,6 +8,115 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
type mockNeighborManager struct {
wantFailGetNeighbor bool
callCounterSetNeighbor int
}
func (mnm *mockNeighborManager) setNeighbor(n *neighbor) {
mnm.callCounterSetNeighbor++
}
func (mnm *mockNeighborManager) getNeighbor(addr types.MACAddress) *neighbor {
if mnm.wantFailGetNeighbor {
return nil
}
return &neighbor{}
}
func TestProcessP2PHello(t *testing.T) {
tests := []struct {
name string
d *dev
h *packet.P2PHello
wantFail bool
wantErr string
expectedNeighborManager *mockNeighborManager
}{
{
name: "Invalid Circuit Type",
d: &dev{
level2: &level{
neighborManager: &mockNeighborManager{},
},
},
h: &packet.P2PHello{
CircuitType: 0x01,
SystemID: types.SystemID{10, 20, 30, 40, 50, 60},
HoldingTimer: 27,
LocalCircuitID: 123,
},
wantFail: true,
wantErr: "Unsupported P2P Hello: Level 1",
},
{
name: "p2pHelloToNeighbor fail",
d: &dev{
name: "eth0",
},
h: &packet.P2PHello{ // No TLVs
CircuitType: 0x02,
SystemID: types.SystemID{10, 20, 30, 40, 50, 60},
HoldingTimer: 27,
LocalCircuitID: 123,
},
wantFail: true,
wantErr: "Unable to create neighbor object from hello: Received a P2P hello PDU without P2P Adjacency TLV on eth0",
},
{
name: "Check neighbor manager called",
d: &dev{
level2: &level{
neighborManager: &mockNeighborManager{},
},
},
h: &packet.P2PHello{
CircuitType: 0x02,
SystemID: types.SystemID{10, 20, 30, 40, 50, 60},
HoldingTimer: 27,
LocalCircuitID: 123,
TLVs: []packet.TLV{
&packet.P2PAdjacencyStateTLV{
TLVType: packet.P2PAdjacencyStateTLVType,
TLVLength: 15,
ExtendedLocalCircuitID: 1024,
},
&packet.IPInterfaceAddressesTLV{
TLVType: packet.IPInterfaceAddressesTLVType,
TLVLength: 4,
IPv4Addresses: []uint32{100},
},
},
},
wantFail: false,
expectedNeighborManager: &mockNeighborManager{
callCounterSetNeighbor: 1,
},
},
}
for _, test := range tests {
err := test.d.processP2PHello(test.h, types.MACAddress{10, 20, 30, 40, 50, 60})
if err != nil && test.wantFail {
assert.Equal(t, test.wantErr, err.Error(), test.name)
continue
}
if err != nil && !test.wantFail {
t.Errorf("Unexpected failure for test %q: %v", test.name, err)
continue
}
if err == nil && test.wantFail {
t.Errorf("Unexpected success for test %q", test.name)
continue
}
assert.Equal(t, test.expectedNeighborManager, test.d.level2.neighborManager, test.name)
}
}
func TestP2pHelloToNeighbor(t *testing.T) { func TestP2pHelloToNeighbor(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
...@@ -91,7 +200,7 @@ func TestP2pHelloToNeighbor(t *testing.T) { ...@@ -91,7 +200,7 @@ func TestP2pHelloToNeighbor(t *testing.T) {
} }
for _, test := range tests { for _, test := range tests {
n, err := test.d.p2pHelloToNeighbor(test.h) n, err := test.d.p2pHelloToNeighbor(test.h, types.MACAddress{})
if err != nil { if err != nil {
if test.wantFail { if test.wantFail {
assert.Equal(t, test.log, err.Error(), test.name) assert.Equal(t, test.log, err.Error(), test.name)
......
...@@ -3,6 +3,7 @@ package server ...@@ -3,6 +3,7 @@ package server
import "github.com/bio-routing/bio-rd/protocols/isis/types" import "github.com/bio-routing/bio-rd/protocols/isis/types"
type neighbor struct { type neighbor struct {
macAddress types.MACAddress
systemID types.SystemID systemID types.SystemID
dev *dev dev *dev
holdingTime uint16 holdingTime uint16
......
...@@ -6,52 +6,54 @@ import ( ...@@ -6,52 +6,54 @@ import (
"github.com/bio-routing/bio-rd/protocols/isis/types" "github.com/bio-routing/bio-rd/protocols/isis/types"
) )
type neighborEntry struct { type neighborManagerInterface interface {
addr types.MACAddress setNeighbor(n *neighbor)
n *neighbor getNeighbor(addr types.MACAddress) *neighbor
} }
type neighborManager struct { type neighborManager struct {
db []neighborEntry dev *dev
db []*neighbor
dbMu sync.RWMutex dbMu sync.RWMutex
p2p bool
} }
func newNeighborManager() *neighborManager { func newNeighborManager(d *dev) *neighborManager {
return &neighborManager{ return &neighborManager{
db: make([]neighborEntry, 0, 1), dev: d,
db: make([]*neighbor, 0, 1),
} }
} }
func (nm *neighborManager) setNeighbor(addr types.MACAddress, n *neighbor) { func (nm *neighborManager) setNeighbor(n *neighbor) {
nm.dbMu.RLock() nm.dbMu.RLock()
defer nm.dbMu.RUnlock() defer nm.dbMu.RUnlock()
for i := range nm.db { for i := range nm.db {
if nm.db[i].addr != addr { if nm.db[i].macAddress != n.macAddress {
continue continue
} }
// FIXME: Update // TODO: Verfiy if hello is valid for us
nm.db[i] = n
return return
} }
// FIXME: Add // TODO: Verfiy if hello is valid for us
nm.db = append(nm.db, neighborEntry{ nm.db = append(nm.db, n)
addr: addr,
n: n,
})
} }
func (nm *neighborManager) getNeighbor(addr types.MACAddress) *neighbor { // IS THIS FUNCION NEEDED?
func (nm *neighborManager) getNeighbor(mac types.MACAddress) *neighbor {
nm.dbMu.RLock() nm.dbMu.RLock()
defer nm.dbMu.RUnlock() defer nm.dbMu.RUnlock()
for i := range nm.db { for i := range nm.db {
if nm.db[i].addr != addr { if nm.db[i].macAddress != mac {
continue continue
} }
return nm.db[i].n return nm.db[i]
} }
return nil return nil
......
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