-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpath_attribute.go
108 lines (95 loc) · 2.37 KB
/
path_attribute.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package main
import (
"encoding/binary"
"fmt"
)
type AttributeTypeCode uint8
const (
AttributeTypeOrigin AttributeTypeCode = iota + 1
AttributeTypeASPath
AttributeTypeNextHop
// TODO: Other attributes
)
type Origin uint8
const (
OriginAttributeIGP Origin = iota
OriginAttributeEGP
OriginAttributeIncomplete
)
func OriginFromPathAttribute(a PathAttribute) (Origin, error) {
if a.TypeCode != AttributeTypeOrigin {
return 0, fmt.Errorf("invalid type code: %d", a.TypeCode)
}
if len(a.Value) != 1 {
return 0, fmt.Errorf("invalid attribute value length: %d", len(a.Value))
}
origin := Origin(a.Value[0])
if origin > 3 {
return 0, fmt.Errorf("invalid origin value: %v", origin)
}
return origin, nil
}
func (a Origin) ToPathAttribute() PathAttribute {
return PathAttribute{
Flags: 0b01000000, // well-known transitive
TypeCode: AttributeTypeOrigin,
Value: []byte{byte(a)},
}
}
type ASPath struct {
Sequence bool
Segments []uint16
}
func ASPathFromPathAttribute(a PathAttribute) (ASPath, error) {
if a.TypeCode != AttributeTypeASPath {
return ASPath{}, fmt.Errorf("invalid type code: %d", a.TypeCode)
}
if len(a.Value) < 2 {
return ASPath{}, fmt.Errorf("too short AS_PATH attribute: %d", len(a.Value))
}
length := int(a.Value[1])
segments := make([]uint16, length)
for i := 0; i < length; i++ {
offset := 2 + i*2
segments[i] = binary.BigEndian.Uint16(a.Value[offset : offset+2])
}
return ASPath{
Sequence: a.Value[0] == 2,
Segments: segments,
}, nil
}
func (a ASPath) ToPathAttribute() PathAttribute {
b := make([]byte, 2+len(a.Segments)*2)
if a.Sequence {
b[0] = 2
} else {
b[0] = 1
}
b[1] = uint8(len(a.Segments))
for i, s := range a.Segments {
offset := 2 + i*2
binary.BigEndian.PutUint16(b[offset:offset+2], s)
}
return PathAttribute{
Flags: 0b01000000, // well-known transitive
TypeCode: AttributeTypeASPath,
Value: b,
}
}
type NextHop []byte
func NextHopFromPathAttribute(a PathAttribute) (NextHop, error) {
if a.TypeCode != AttributeTypeNextHop {
return nil, fmt.Errorf("invalid type code: %d", a.TypeCode)
}
if len(a.Value) != 4 {
return nil, fmt.Errorf("invalid next hop length: %d", len(a.Value))
}
return NextHop(a.Value), nil
}
func (a NextHop) ToPathAttribute() PathAttribute {
return PathAttribute{
Flags: 0b01000000, // well-known transitive
TypeCode: AttributeTypeNextHop,
Value: []byte(a),
}
}