Skip to content

Commit 4240755

Browse files
committed
wip: ospv3 area 0
1 parent ec8b2a3 commit 4240755

File tree

12 files changed

+972
-17
lines changed

12 files changed

+972
-17
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ require (
1616
github.com/stretchr/testify v1.3.0
1717
github.com/vishvananda/netlink v1.0.0
1818
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc // indirect
19+
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980
1920
google.golang.org/genproto v0.0.0-20181221175505-bd9b4fb69e2f // indirect
2021
google.golang.org/grpc v1.17.0
2122
gopkg.in/yaml.v2 v2.2.2

protocols/ospfv3/packet/common.go

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,27 @@ func (i ID) Serialize(buf *bytes.Buffer) {
3030
buf.Write(convert.Uint32Byte(uint32(i)))
3131
}
3232

33+
// bitmasks for flags in RouterOptions
34+
const (
35+
RouterOptV6 uint16 = 1 << iota
36+
RouterOptE
37+
_
38+
RouterOptN
39+
RouterOptR
40+
RouterOptDC
41+
_
42+
_
43+
RouterOptAF
44+
)
45+
3346
type RouterOptions struct {
34-
_ uint16
35-
RawFlags uint8
47+
_ uint8
48+
Flags uint16
3649
}
3750

3851
func (r *RouterOptions) Serialize(buf *bytes.Buffer) {
39-
buf.Write([]byte{0, 0})
40-
buf.WriteByte(r.RawFlags)
52+
buf.WriteByte(0)
53+
buf.Write(convert.Uint16Byte(uint16(r.Flags)))
4154
}
4255

4356
type LSType uint16

protocols/ospfv3/packet/lsa.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -332,9 +332,9 @@ func DeserializeInterAreaRouterLSA(buf *bytes.Buffer) (*InterAreaRouterLSA, int,
332332

333333
// Bitmasks for flags used in ASExternalLSA
334334
const (
335-
ASExtLSAFlagE = 4
336-
ASExtLSAFlagF = 2
337-
ASExtLSAFlagT = 1
335+
ASExtLSAFlagT uint8 = 1 << iota
336+
ASExtLSAFlagF
337+
ASExtLSAFlagE
338338
)
339339

340340
type ASExternalLSA struct {

protocols/ospfv3/packet/packet.go

Lines changed: 62 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,29 @@ import (
55
"encoding/binary"
66
"fmt"
77

8+
"github.com/bio-routing/bio-rd/util/checksum"
89
"github.com/bio-routing/bio-rd/util/decode"
910
"github.com/bio-routing/tflow2/convert"
1011
"github.com/pkg/errors"
1112
)
1213

14+
const expectedVersion = 3
15+
16+
type OSPFMessageType uint8
17+
18+
// OSPF message types
19+
const (
20+
MsgTypeUnknown OSPFMessageType = iota
21+
MsgTypeHello
22+
MsgTypeDatabaseDescription
23+
MsgTypeLinkStateRequest
24+
MsgTypeLinkStateUpdate
25+
MsgTypeLinkStateAcknowledgment
26+
)
27+
1328
type OSPFv3Message struct {
1429
Version uint8
15-
Type uint8
30+
Type OSPFMessageType
1631
PacketLength uint16
1732
RouterID ID
1833
AreaID ID
@@ -22,21 +37,40 @@ type OSPFv3Message struct {
2237
}
2338

2439
const OSPFv3MessageHeaderLength = 16
40+
const OSPFv3MessagePacketLengthAtByte = 2
41+
const OSPFv3MessageChecksumAtByte = 12
42+
43+
func (x *OSPFv3Message) Serialize(out *bytes.Buffer) {
44+
buf := bytes.NewBuffer(nil)
2545

26-
func (x *OSPFv3Message) Serialize(buf *bytes.Buffer) {
2746
buf.WriteByte(x.Version)
28-
buf.WriteByte(x.Type)
47+
buf.WriteByte(uint8(x.Type))
2948
buf.Write(convert.Uint16Byte(x.PacketLength))
3049
x.RouterID.Serialize(buf)
3150
x.AreaID.Serialize(buf)
3251
buf.Write(convert.Uint16Byte(x.Checksum))
3352
buf.WriteByte(x.InstanceID)
3453
buf.WriteByte(0) // 1 byte reserved
3554
x.Body.Serialize(buf)
55+
56+
data := buf.Bytes()
57+
58+
length := uint16(len(data))
59+
putUint16(data, OSPFv3MessagePacketLengthAtByte, length)
60+
61+
checksum := checksum.IPChecksum(data, OSPFv3MessageChecksumAtByte)
62+
putUint16(data, OSPFv3MessageChecksumAtByte, checksum)
63+
64+
out.Write(data)
65+
}
66+
67+
func putUint16(b []byte, p int, v uint16) {
68+
binary.BigEndian.PutUint16(b[p:p+2], v)
3669
}
3770

3871
func DeserializeOSPFv3Message(buf *bytes.Buffer) (*OSPFv3Message, int, error) {
3972
pdu := &OSPFv3Message{}
73+
data := buf.Bytes()
4074

4175
var readBytes int
4276
var err error
@@ -59,6 +93,15 @@ func DeserializeOSPFv3Message(buf *bytes.Buffer) (*OSPFv3Message, int, error) {
5993
}
6094
readBytes += 16
6195

96+
if pdu.Version != expectedVersion {
97+
return nil, readBytes, fmt.Errorf("Invalid OSPF version: %d", pdu.Version)
98+
}
99+
100+
expectedChecksum := checksum.IPChecksum(data, OSPFv3MessageChecksumAtByte)
101+
if pdu.Checksum != expectedChecksum {
102+
return nil, readBytes, fmt.Errorf("Checksum mismatch. Expected %#04x, got %#04x", expectedChecksum, pdu.Checksum)
103+
}
104+
62105
n, err := pdu.ReadBody(buf)
63106
if err != nil {
64107
return nil, readBytes, errors.Wrap(err, "unable to decode message body")
@@ -75,15 +118,15 @@ func (m *OSPFv3Message) ReadBody(buf *bytes.Buffer) (int, error) {
75118
var err error
76119

77120
switch m.Type {
78-
case 1:
121+
case MsgTypeHello:
79122
body, readBytes, err = DeserializeHello(buf, bodyLength)
80-
case 2:
123+
case MsgTypeDatabaseDescription:
81124
body, readBytes, err = DeserializeDatabaseDescription(buf, bodyLength)
82-
case 3:
125+
case MsgTypeLinkStateRequest:
83126
body, readBytes, err = DeserializeLinkStateRequestMsg(buf, bodyLength)
84-
case 4:
127+
case MsgTypeLinkStateUpdate:
85128
body, readBytes, err = DeserializeLinkStateUpdate(buf)
86-
case 5:
129+
case MsgTypeLinkStateAcknowledgment:
87130
body, readBytes, err = DeserializeLinkStateAcknowledgement(buf, bodyLength)
88131
default:
89132
return 0, fmt.Errorf("unknown message type: %d", m.Type)
@@ -157,10 +200,19 @@ func DeserializeHello(buf *bytes.Buffer, bodyLength uint16) (*Hello, int, error)
157200
return pdu, readBytes, nil
158201
}
159202

203+
type DBFlags uint8
204+
205+
// database description flags
206+
const (
207+
DBFlagInit DBFlags = 1 << iota
208+
DBFlagMore
209+
DBFlagMS
210+
)
211+
160212
type DatabaseDescription struct {
161213
Options RouterOptions
162214
InterfaceMTU uint16
163-
DBFlags uint8
215+
DBFlags DBFlags
164216
DDSequenceNumber uint32
165217
LSAHeaders []*LSA
166218
}
@@ -170,7 +222,7 @@ func (x *DatabaseDescription) Serialize(buf *bytes.Buffer) {
170222
x.Options.Serialize(buf)
171223
buf.Write(convert.Uint16Byte(x.InterfaceMTU))
172224
buf.WriteByte(0) // 1 byte reserved
173-
buf.WriteByte(x.DBFlags)
225+
buf.WriteByte(uint8(x.DBFlags))
174226
buf.Write(convert.Uint32Byte(x.DDSequenceNumber))
175227
for i := range x.LSAHeaders {
176228
x.LSAHeaders[i].Serialize(buf, true)

protocols/ospfv3/server/area.go

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
package server
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"net"
7+
"sync"
8+
"sync/atomic"
9+
10+
"github.com/bio-routing/bio-rd/protocols/ospfv3/packet"
11+
"github.com/pkg/errors"
12+
"github.com/sirupsen/logrus"
13+
"github.com/vishvananda/netlink"
14+
)
15+
16+
type AreaConfig struct {
17+
ID packet.ID
18+
routerID packet.ID
19+
Stub bool // in spec ExternalRoutingCapability (changed so default is false)
20+
StubDefaultCost packet.InterfaceMetric
21+
}
22+
23+
type areaManager struct {
24+
interfaces map[string]*interfaceManager
25+
interfacesMutex sync.Mutex
26+
27+
config AreaConfig
28+
started *uint64
29+
30+
routerLSAs []packet.RouterLSA
31+
networkLSAs []packet.NetworkLSA
32+
lsaMutex sync.Mutex
33+
34+
tree spfTree
35+
treeMutex sync.Mutex
36+
37+
rib RoutingTable
38+
log logrus.FieldLogger
39+
}
40+
41+
func newAreaManager(log logrus.FieldLogger, config AreaConfig, rib RoutingTable) (*areaManager, error) {
42+
mgmt := &areaManager{
43+
interfaces: make(map[string]*interfaceManager),
44+
45+
config: config,
46+
rib: rib,
47+
log: log.WithField("area", fmt.Sprintf("%d", config.ID)),
48+
}
49+
50+
return mgmt, nil
51+
}
52+
53+
func (am *areaManager) AddInterface(ctx context.Context, name string, config InterfaceConfig) error {
54+
am.interfacesMutex.Lock()
55+
defer am.interfacesMutex.Unlock()
56+
57+
if _, ok := am.interfaces[name]; ok {
58+
return errors.New("interface is already configured. cannot reconfigure")
59+
}
60+
61+
ifm, err := newInterfaceManager(am.log.WithField("component", "interfaceManager"), am, name, config)
62+
if err != nil {
63+
return errors.Wrap(err, "unable to construct interface manager")
64+
}
65+
66+
am.interfaces[name] = ifm
67+
if am.Started() {
68+
if err := ifm.Start(ctx); err != nil {
69+
return errors.Wrap(err, "unable to start interface manager")
70+
}
71+
}
72+
73+
return nil
74+
}
75+
76+
func (am *areaManager) Started() bool {
77+
return atomic.LoadUint64(am.started) == 1
78+
}
79+
80+
func (am *areaManager) Start(ctx context.Context) error {
81+
if atomic.SwapUint64(am.started, 1) == 1 {
82+
return errors.New("already started")
83+
}
84+
85+
for name, ifm := range am.interfaces {
86+
if err := ifm.Start(ctx); err != nil {
87+
return errors.Wrap(err, fmt.Sprintf("unable to start interface: %s", name))
88+
}
89+
intf := ifm.GetInterface()
90+
if intf != nil && (intf.Flags&net.FlagUp) != 0 {
91+
ifm.SetLinkUp()
92+
}
93+
}
94+
95+
if err := am.startMonitorLinks(ctx); err != nil {
96+
return errors.Wrap(err, "unable to listen for interface link changes")
97+
}
98+
99+
return nil
100+
}
101+
102+
func (am *areaManager) GetConfig() AreaConfig {
103+
return am.config
104+
}
105+
106+
func (am *areaManager) startMonitorLinks(ctx context.Context) error {
107+
updateCh := make(chan netlink.LinkUpdate)
108+
done := make(chan struct{})
109+
if err := netlink.LinkSubscribe(updateCh, done); err != nil {
110+
return err
111+
}
112+
113+
go func() {
114+
for {
115+
var update netlink.LinkUpdate
116+
select {
117+
case <-ctx.Done():
118+
close(done)
119+
return
120+
case update = <-updateCh:
121+
}
122+
123+
name := update.Link.Attrs().Name
124+
am.interfacesMutex.Lock()
125+
ifm, found := am.interfaces[name]
126+
am.interfacesMutex.Unlock()
127+
if !found {
128+
continue
129+
}
130+
131+
if (net.Flags(update.IfInfomsg.Flags) & net.FlagUp) != 0 {
132+
ifm.SetLinkUp()
133+
} else {
134+
ifm.SetLinkDown()
135+
}
136+
}
137+
}()
138+
139+
return nil
140+
}

protocols/ospfv3/server/common.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package server
2+
3+
type Router interface {
4+
IsDR() bool
5+
IsBDR() bool
6+
}
7+
8+
// RFC: https://tools.ietf.org/html/rfc2328#page-95 (Section 10.4)
9+
func shouldFormAdjacency(ifType InterfaceType, self Router, neighbor Router) bool {
10+
return ifType == IfTypePointToPoint ||
11+
ifType == IfTypePointToMultipoint ||
12+
ifType == IfTypeVirtualLink ||
13+
self.IsDR() || self.IsBDR() ||
14+
neighbor.IsDR() || neighbor.IsBDR()
15+
}

0 commit comments

Comments
 (0)