Skip to content

Commit 16908dd

Browse files
author
Maxime Peim
committed
fix: MRT extended timestamp
1 parent 2d2f0b0 commit 16908dd

File tree

3 files changed

+89
-48
lines changed

3 files changed

+89
-48
lines changed

pkg/packet/mrt/mrt.go

Lines changed: 46 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,15 @@ const (
5656
OSPFv3_ET MRTType = 49
5757
)
5858

59+
func (t MRTType) HasExtendedTimestamp() bool {
60+
switch t {
61+
case BGP4MP_ET, ISIS_ET, OSPFv3_ET:
62+
return true
63+
default:
64+
return false
65+
}
66+
}
67+
5968
type MRTSubTyper interface {
6069
ToUint16() uint16
6170
}
@@ -111,7 +120,7 @@ const (
111120
ESTABLISHED BGPState = 6
112121
)
113122

114-
func packValues(values []interface{}) ([]byte, error) {
123+
func packValues(values ...any) ([]byte, error) {
115124
b := new(bytes.Buffer)
116125
for _, v := range values {
117126
err := binary.Write(b, binary.BigEndian, v)
@@ -123,10 +132,11 @@ func packValues(values []interface{}) ([]byte, error) {
123132
}
124133

125134
type MRTHeader struct {
126-
Timestamp uint32
127-
Type MRTType
128-
SubType uint16
129-
Len uint32
135+
Timestamp uint32
136+
Type MRTType
137+
SubType uint16
138+
Len uint32
139+
ExtendedTimestampMicroseconds uint32
130140
}
131141

132142
func (h *MRTHeader) DecodeFromBytes(data []byte) error {
@@ -137,25 +147,38 @@ func (h *MRTHeader) DecodeFromBytes(data []byte) error {
137147
h.Type = MRTType(binary.BigEndian.Uint16(data[4:6]))
138148
h.SubType = binary.BigEndian.Uint16(data[6:8])
139149
h.Len = binary.BigEndian.Uint32(data[8:12])
150+
if h.Type.HasExtendedTimestamp() {
151+
h.ExtendedTimestampMicroseconds = binary.BigEndian.Uint32(data[12:16])
152+
}
140153
return nil
141154
}
142155

143156
func (h *MRTHeader) Serialize() ([]byte, error) {
144-
return packValues([]interface{}{h.Timestamp, h.Type, h.SubType, h.Len})
157+
fields := []any{h.Timestamp, h.Type, h.SubType, h.Len}
158+
if h.Type.HasExtendedTimestamp() {
159+
fields = append(fields, h.ExtendedTimestampMicroseconds)
160+
}
161+
return packValues(fields...)
145162
}
146163

147-
func NewMRTHeader(timestamp uint32, t MRTType, subtype MRTSubTyper, l uint32) (*MRTHeader, error) {
164+
func NewMRTHeader(timestamp time.Time, t MRTType, subtype MRTSubTyper, l uint32) (*MRTHeader, error) {
165+
ms := uint32(0)
166+
if t.HasExtendedTimestamp() {
167+
ms = uint32(timestamp.UnixMicro() - timestamp.Unix()*1000000)
168+
}
148169
return &MRTHeader{
149-
Timestamp: timestamp,
150-
Type: t,
151-
SubType: subtype.ToUint16(),
152-
Len: l,
170+
Timestamp: uint32(timestamp.Unix()),
171+
Type: t,
172+
SubType: subtype.ToUint16(),
173+
Len: l,
174+
ExtendedTimestampMicroseconds: ms,
153175
}, nil
154176
}
155177

156178
func (h *MRTHeader) GetTime() time.Time {
157179
t := int64(h.Timestamp)
158-
return time.Unix(t, 0)
180+
ms := int64(h.ExtendedTimestampMicroseconds)
181+
return time.Unix(t, ms*1000)
159182
}
160183

161184
type MRTMessage struct {
@@ -176,7 +199,7 @@ func (m *MRTMessage) Serialize() ([]byte, error) {
176199
return append(bbuf, buf...), nil
177200
}
178201

179-
func NewMRTMessage(timestamp uint32, t MRTType, subtype MRTSubTyper, body Body) (*MRTMessage, error) {
202+
func NewMRTMessage(timestamp time.Time, t MRTType, subtype MRTSubTyper, body Body) (*MRTMessage, error) {
180203
header, err := NewMRTHeader(timestamp, t, subtype, 0)
181204
if err != nil {
182205
return nil, err
@@ -252,12 +275,12 @@ func (p *Peer) Serialize() ([]byte, error) {
252275
buf = append(buf, p.IpAddress.To4()...)
253276
}
254277
if p.Type&(1<<1) > 0 {
255-
bbuf, err = packValues([]interface{}{p.AS})
278+
bbuf, err = packValues(p.AS)
256279
} else {
257280
if p.AS > uint32(math.MaxUint16) {
258281
return nil, fmt.Errorf("AS number is beyond 2 octet. %d > %d", p.AS, math.MaxUint16)
259282
}
260-
bbuf, err = packValues([]interface{}{uint16(p.AS)})
283+
bbuf, err = packValues(uint16(p.AS))
261284
}
262285
if err != nil {
263286
return nil, err
@@ -461,7 +484,6 @@ func (e *RibEntry) String() string {
461484
} else {
462485
return fmt.Sprintf("RIB_ENTRY: PeerIndex [%d] OriginatedTime [%d] PathAttributes [%v]", e.PeerIndex, e.OriginatedTime, e.PathAttributes)
463486
}
464-
465487
}
466488

467489
type Rib struct {
@@ -527,7 +549,7 @@ func (u *Rib) Serialize() ([]byte, error) {
527549
return nil, err
528550
}
529551
buf = append(buf, bbuf...)
530-
bbuf, err = packValues([]interface{}{uint16(len(u.Entries))})
552+
bbuf, err = packValues(uint16(len(u.Entries)))
531553
if err != nil {
532554
return nil, err
533555
}
@@ -716,13 +738,13 @@ func (m *BGP4MPHeader) decodeFromBytes(data []byte) ([]byte, error) {
716738
}
717739

718740
func (m *BGP4MPHeader) serialize() ([]byte, error) {
719-
var values []interface{}
741+
var values []any
720742
if m.isAS4 {
721-
values = []interface{}{m.PeerAS, m.LocalAS, m.InterfaceIndex, m.AddressFamily}
743+
values = []any{m.PeerAS, m.LocalAS, m.InterfaceIndex, m.AddressFamily}
722744
} else {
723-
values = []interface{}{uint16(m.PeerAS), uint16(m.LocalAS), m.InterfaceIndex, m.AddressFamily}
745+
values = []any{uint16(m.PeerAS), uint16(m.LocalAS), m.InterfaceIndex, m.AddressFamily}
724746
}
725-
buf, err := packValues(values)
747+
buf, err := packValues(values...)
726748
if err != nil {
727749
return nil, err
728750
}
@@ -792,7 +814,7 @@ func (m *BGP4MPStateChange) Serialize() ([]byte, error) {
792814
if err != nil {
793815
return nil, err
794816
}
795-
bbuf, err := packValues([]interface{}{m.OldState, m.NewState})
817+
bbuf, err := packValues(m.OldState, m.NewState)
796818
if err != nil {
797819
return nil, err
798820
}
@@ -907,14 +929,14 @@ func SplitMrt(data []byte, atEOF bool) (advance int, token []byte, err error) {
907929
if cap(data) < MRT_COMMON_HEADER_LEN { // read more
908930
return 0, nil, nil
909931
}
910-
//this reads the data
932+
// this reads the data
911933
hdr := &MRTHeader{}
912934
errh := hdr.DecodeFromBytes(data[:MRT_COMMON_HEADER_LEN])
913935
if errh != nil {
914936
return 0, nil, errh
915937
}
916938
totlen := int(hdr.Len + MRT_COMMON_HEADER_LEN)
917-
if len(data) < totlen { //need to read more
939+
if len(data) < totlen { // need to read more
918940
return 0, nil, nil
919941
}
920942
return totlen, data[0:totlen], nil

pkg/packet/mrt/mrt_test.go

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import (
2727
)
2828

2929
func TestMrtHdr(t *testing.T) {
30-
h1, err := NewMRTHeader(10, TABLE_DUMPv2, RIB_IPV4_MULTICAST, 20)
30+
h1, err := NewMRTHeader(time.Unix(10, 0), TABLE_DUMPv2, RIB_IPV4_MULTICAST, 20)
3131
if err != nil {
3232
t.Fatal(err)
3333
}
@@ -44,14 +44,23 @@ func TestMrtHdr(t *testing.T) {
4444
}
4545

4646
func TestMrtHdrTime(t *testing.T) {
47-
h1, err := NewMRTHeader(10, TABLE_DUMPv2, RIB_IPV4_MULTICAST, 20)
47+
ttime1 := time.Unix(10, 0)
48+
h1, err := NewMRTHeader(ttime1, TABLE_DUMPv2, RIB_IPV4_MULTICAST, 20)
4849
if err != nil {
4950
t.Fatal(err)
5051
}
51-
ttime := time.Unix(10, 0)
52-
htime := h1.GetTime()
53-
t.Logf("this timestamp should be 10s after epoch:%v", htime)
54-
assert.Equal(t, h1.GetTime(), ttime)
52+
h1time := h1.GetTime()
53+
t.Logf("this timestamp should be 10s after epoch:%v", h1time)
54+
assert.Equal(t, h1time, ttime1)
55+
56+
ttime2 := time.Unix(20, 123000)
57+
h2, err := NewMRTHeader(ttime2, BGP4MP_ET, STATE_CHANGE, 20)
58+
if err != nil {
59+
t.Fatal(err)
60+
}
61+
h2time := h2.GetTime()
62+
t.Logf("this timestamp should be 20s and 123ms after epoch:%v", h2time)
63+
assert.Equal(t, h2time, ttime2)
5564
}
5665

5766
func testPeer(t *testing.T, p1 *Peer) {
@@ -283,7 +292,7 @@ func TestMrtSplit(t *testing.T) {
283292
for i := 0; i < numwrite; i++ {
284293
msg := bgp.NewBGPKeepAliveMessage()
285294
m1 := NewBGP4MPMessage(65000, 65001, 1, "192.168.0.1", "192.168.0.2", false, msg)
286-
mm, _ := NewMRTMessage(1234, BGP4MP, MESSAGE, m1)
295+
mm, _ := NewMRTMessage(time.Unix(1234, 0), BGP4MP, MESSAGE, m1)
287296
b1, err := mm.Serialize()
288297
if err != nil {
289298
t.Fatal(err)
@@ -302,15 +311,13 @@ func TestMrtSplit(t *testing.T) {
302311
}
303312

304313
func FuzzMRT(f *testing.F) {
305-
306314
f.Fuzz(func(t *testing.T, data []byte) {
307315
if len(data) < 16 {
308316
return
309317
}
310318

311319
hdr := &MRTHeader{}
312320
err := hdr.DecodeFromBytes(data[:MRT_COMMON_HEADER_LEN])
313-
314321
if err != nil {
315322
return
316323
}

pkg/server/mrt.go

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -103,18 +103,19 @@ func (m *mrtWriter) loop() error {
103103
case e.FourBytesAs:
104104
subtype = mrt.MESSAGE_AS4
105105
}
106-
if bm, err := mrt.NewMRTMessage(uint32(e.Timestamp.Unix()), mrt.BGP4MP, subtype, mp); err != nil {
106+
if bm, err := mrt.NewMRTMessage(e.Timestamp, mrt.BGP4MP, subtype, mp); err != nil {
107107
m.s.logger.Warn("Failed to create MRT BGP4MP message",
108108
log.Fields{
109109
"Topic": "mrt",
110110
"Data": e,
111111
"Error": err,
112-
"Subtype": subtype})
112+
"Subtype": subtype,
113+
})
113114
} else {
114115
msg = append(msg, bm)
115116
}
116117
case *watchEventTable:
117-
t := uint32(time.Now().Unix())
118+
t := time.Now()
118119

119120
peers := make([]*mrt.Peer, 1, len(e.Neighbor)+1)
120121
// Adding dummy Peer record for locally generated routes
@@ -131,7 +132,8 @@ func (m *mrtWriter) loop() error {
131132
"Topic": "mrt",
132133
"Data": e,
133134
"Error": err,
134-
"Subtype": mrt.PEER_INDEX_TABLE})
135+
"Subtype": mrt.PEER_INDEX_TABLE,
136+
})
135137
break
136138
} else {
137139
msg = append(msg, bm)
@@ -174,7 +176,8 @@ func (m *mrtWriter) loop() error {
174176
"Topic": "mrt",
175177
"Data": e,
176178
"Error": err,
177-
"Subtype": st})
179+
"Subtype": st,
180+
})
178181
} else {
179182
msg = append(msg, bm)
180183
seq++
@@ -224,7 +227,8 @@ func (m *mrtWriter) loop() error {
224227
m.s.logger.Warn("Can't write to destination MRT file",
225228
log.Fields{
226229
"Topic": "mrt",
227-
"Error": err})
230+
"Error": err,
231+
})
228232
}
229233
}
230234

@@ -236,7 +240,8 @@ func (m *mrtWriter) loop() error {
236240
log.Fields{
237241
"Topic": "mrt",
238242
"Data": e,
239-
"Error": err})
243+
"Error": err,
244+
})
240245
} else {
241246
b.Write(buf)
242247
if b.Len() > 1*1000*1000 {
@@ -259,7 +264,8 @@ func (m *mrtWriter) loop() error {
259264
m.s.logger.Warn("can't rotate MRT file",
260265
log.Fields{
261266
"Topic": "mrt",
262-
"Error": err})
267+
"Error": err,
268+
})
263269
}
264270
}
265271

@@ -293,7 +299,8 @@ func mrtFileOpen(logger log.Logger, filename string, rInterval uint64) (*os.File
293299
log.Fields{
294300
"Topic": "mrt",
295301
"Filename": realname,
296-
"RotationInterval": rInterval})
302+
"RotationInterval": rInterval,
303+
})
297304

298305
i := len(realname)
299306
for i > 0 && os.IsPathSeparator(realname[i-1]) {
@@ -311,7 +318,8 @@ func mrtFileOpen(logger log.Logger, filename string, rInterval uint64) (*os.File
311318
logger.Warn("can't create MRT destination directory",
312319
log.Fields{
313320
"Topic": "mrt",
314-
"Error": err})
321+
"Error": err,
322+
})
315323
return nil, err
316324
}
317325
}
@@ -321,7 +329,8 @@ func mrtFileOpen(logger log.Logger, filename string, rInterval uint64) (*os.File
321329
logger.Warn("can't create MRT destination file",
322330
log.Fields{
323331
"Topic": "mrt",
324-
"Error": err})
332+
"Error": err,
333+
})
325334
}
326335
return file, err
327336
}
@@ -360,26 +369,29 @@ func (m *mrtManager) enable(c *oc.MrtConfig) error {
360369
m.bgpServer.logger.Info("use minimum mrt rotation interval",
361370
log.Fields{
362371
"Topic": "mrt",
363-
"Interval": minRotationInterval})
372+
"Interval": minRotationInterval,
373+
})
364374
rInterval = minRotationInterval
365375
}
366376
}
367377

368-
if c.DumpType == oc.MRT_TYPE_TABLE {
378+
switch c.DumpType {
379+
case oc.MRT_TYPE_TABLE:
369380
if rInterval == 0 {
370381
if dInterval < minDumpInterval {
371382
m.bgpServer.logger.Info("use minimum mrt dump interval",
372383
log.Fields{
373384
"Topic": "mrt",
374-
"Interval": minDumpInterval})
385+
"Interval": minDumpInterval,
386+
})
375387
dInterval = minDumpInterval
376388
}
377389
} else if dInterval == 0 {
378390
setRotationMin()
379391
} else {
380392
return fmt.Errorf("can't specify both intervals in the table dump type")
381393
}
382-
} else if c.DumpType == oc.MRT_TYPE_UPDATES {
394+
case oc.MRT_TYPE_UPDATES:
383395
// ignore the dump interval
384396
dInterval = 0
385397
if len(c.TableName) > 0 {

0 commit comments

Comments
 (0)