Skip to content

Commit 3ff8c3b

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

File tree

2 files changed

+62
-33
lines changed

2 files changed

+62
-33
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
}

0 commit comments

Comments
 (0)