diff options
-rw-r--r-- | packet/bgp.go | 162 | ||||
-rw-r--r-- | packet/bgp_test.go | 27 |
2 files changed, 132 insertions, 57 deletions
diff --git a/packet/bgp.go b/packet/bgp.go index 59d62915..fcbb3bd1 100644 --- a/packet/bgp.go +++ b/packet/bgp.go @@ -1151,9 +1151,81 @@ func NewPathAttributeOrigin(value uint8) *PathAttributeOrigin { type AsPathParam struct { Type uint8 Num uint8 + AS []uint16 +} + +func (a *AsPathParam) Serialize() ([]byte, error) { + buf := make([]byte, 2+len(a.AS)*2) + buf[0] = a.Type + buf[1] = a.Num + for j, as := range a.AS { + binary.BigEndian.PutUint16(buf[2+j*2:], as) + } + return buf, nil +} + +func (a *AsPathParam) DecodeFromBytes(data []byte) error { + a.Type = data[0] + a.Num = data[1] + data = data[2:] + for i := 0; i < int(a.Num); i++ { + a.AS = append(a.AS, binary.BigEndian.Uint16(data)) + data = data[2:] + } + return nil +} + +func (a *AsPathParam) Len() int { + return 2 + len(a.AS)*2 +} + +func NewAsPathParam(segType uint8, as []uint16) *AsPathParam { + return &AsPathParam{ + Type: segType, + Num: uint8(len(as)), + AS: as, + } +} + +type As4PathParam struct { + Type uint8 + Num uint8 AS []uint32 } +func (a *As4PathParam) Serialize() ([]byte, error) { + buf := make([]byte, 2+len(a.AS)*4) + buf[0] = a.Type + buf[1] = a.Num + for j, as := range a.AS { + binary.BigEndian.PutUint32(buf[2+j*4:], as) + } + return buf, nil +} + +func (a *As4PathParam) DecodeFromBytes(data []byte) error { + a.Type = data[0] + a.Num = data[1] + data = data[2:] + for i := 0; i < int(a.Num); i++ { + a.AS = append(a.AS, binary.BigEndian.Uint32(data)) + data = data[4:] + } + return nil +} + +func (a *As4PathParam) Len() int { + return 2 + len(a.AS)*4 +} + +func NewAs4PathParam(segType uint8, as []uint32) *As4PathParam { + return &As4PathParam{ + Type: segType, + Num: uint8(len(as)), + AS: as, + } +} + type DefaultAsPath struct { } @@ -1173,53 +1245,32 @@ func (p *DefaultAsPath) isValidAspath(data []byte) bool { return true } -// TODO: could marge two functions nicely with reflect? -func (p *DefaultAsPath) decodeAspath(data []byte) []AsPathParam { - var param []AsPathParam - - for len(data) > 0 { - a := AsPathParam{} - a.Type = data[0] - a.Num = data[1] - data = data[2:] - for i := 0; i < int(a.Num); i++ { - a.AS = append(a.AS, uint32(binary.BigEndian.Uint16(data))) - data = data[2:] - } - param = append(param, a) - } - return param -} - -func (p *DefaultAsPath) decodeAs4path(data []byte) []AsPathParam { - var param []AsPathParam - - for len(data) > 0 { - a := AsPathParam{} - a.Type = data[0] - a.Num = data[1] - data = data[2:] - for i := 0; i < int(a.Num); i++ { - a.AS = append(a.AS, binary.BigEndian.Uint32(data)) - data = data[4:] - } - param = append(param, a) - } - return param +type AsPathParamInterface interface { + Serialize() ([]byte, error) + DecodeFromBytes([]byte) error + Len() int } type PathAttributeAsPath struct { DefaultAsPath PathAttribute - Value []AsPathParam + Value []AsPathParamInterface } func (p *PathAttributeAsPath) DecodeFromBytes(data []byte) error { p.PathAttribute.DecodeFromBytes(data) - if p.DefaultAsPath.isValidAspath(p.PathAttribute.Value) { - p.Value = p.DefaultAsPath.decodeAspath(p.PathAttribute.Value) - } else { - p.Value = p.DefaultAsPath.decodeAs4path(p.PathAttribute.Value) + validAs := p.DefaultAsPath.isValidAspath(p.PathAttribute.Value) + v := p.PathAttribute.Value + for len(v) > 0 { + var tuple AsPathParamInterface + if validAs == true { + tuple = &AsPathParam{} + } else { + tuple = &As4PathParam{} + } + tuple.DecodeFromBytes(v) + p.Value = append(p.Value, tuple) + v = v[tuple.Len():] } return nil } @@ -1227,11 +1278,9 @@ func (p *PathAttributeAsPath) DecodeFromBytes(data []byte) error { func (p *PathAttributeAsPath) Serialize() ([]byte, error) { buf := make([]byte, 0) for _, v := range p.Value { - vbuf := make([]byte, 2+len(v.AS)*2) - vbuf[0] = v.Type - vbuf[1] = v.Num - for j, as := range v.AS { - binary.BigEndian.PutUint16(vbuf[2+j*2:], uint16(as)) + vbuf, err := v.Serialize() + if err != nil { + return nil, err } buf = append(buf, vbuf...) } @@ -1239,7 +1288,7 @@ func (p *PathAttributeAsPath) Serialize() ([]byte, error) { return p.PathAttribute.Serialize() } -func NewPathAttributeAsPath(value []AsPathParam) *PathAttributeAsPath { +func NewPathAttributeAsPath(value []AsPathParamInterface) *PathAttributeAsPath { return &PathAttributeAsPath{ PathAttribute: PathAttribute{ Flags: BGP_ATTR_FLAG_TRANSITIVE, @@ -1733,17 +1782,36 @@ func NewPathAttributeExtendedCommunities(value []ExtendedCommunityInterface) *Pa type PathAttributeAs4Path struct { PathAttribute - Value []AsPathParam + Value []*As4PathParam DefaultAsPath } func (p *PathAttributeAs4Path) DecodeFromBytes(data []byte) error { p.PathAttribute.DecodeFromBytes(data) - p.Value = p.DefaultAsPath.decodeAs4path(p.PathAttribute.Value) + v := p.PathAttribute.Value + for len(v) > 0 { + tuple := &As4PathParam{} + tuple.DecodeFromBytes(v) + p.Value = append(p.Value, tuple) + v = v[tuple.Len():] + } return nil } -func NewPathAttributeAs4Path(value []AsPathParam) *PathAttributeAs4Path { +func (p *PathAttributeAs4Path) Serialize() ([]byte, error) { + buf := make([]byte, 0) + for _, v := range p.Value { + vbuf, err := v.Serialize() + if err != nil { + return nil, err + } + buf = append(buf, vbuf...) + } + p.PathAttribute.Value = buf + return p.PathAttribute.Serialize() +} + +func NewPathAttributeAs4Path(value []*As4PathParam) *PathAttributeAs4Path { return &PathAttributeAs4Path{ PathAttribute: PathAttribute{ Flags: BGP_ATTR_FLAG_TRANSITIVE, diff --git a/packet/bgp_test.go b/packet/bgp_test.go index fc0c9eb7..59734ba4 100644 --- a/packet/bgp_test.go +++ b/packet/bgp_test.go @@ -38,16 +38,22 @@ func update() *BGPMessage { w2 := WithdrawnRoute{*NewIPAddrPrefix(17, "100.33.3.0")} w := []WithdrawnRoute{w1, w2} - aspath := []AsPathParam{ - AsPathParam{Type: 2, Num: 1, AS: []uint32{1000}}, - AsPathParam{Type: 1, Num: 2, AS: []uint32{1001, 1002}}, - AsPathParam{Type: 2, Num: 2, AS: []uint32{1003, 1004}}, + aspath1 := []AsPathParamInterface{ + NewAsPathParam(2, []uint16{1000}), + NewAsPathParam(1, []uint16{1001, 1002}), + NewAsPathParam(2, []uint16{1003, 1004}), } - aspath2 := []AsPathParam{ - AsPathParam{Type: 2, Num: 1, AS: []uint32{1000000}}, - AsPathParam{Type: 1, Num: 2, AS: []uint32{1000001, 1002}}, - AsPathParam{Type: 2, Num: 2, AS: []uint32{1003, 100004}}, + aspath2 := []AsPathParamInterface{ + NewAs4PathParam(2, []uint32{1000000}), + NewAs4PathParam(1, []uint32{1000001, 1002}), + NewAs4PathParam(2, []uint32{1003, 100004}), + } + + aspath3 := []*As4PathParam{ + NewAs4PathParam(2, []uint32{1000000}), + NewAs4PathParam(1, []uint32{1000001, 1002}), + NewAs4PathParam(2, []uint32{1003, 100004}), } ecommunities := []ExtendedCommunityInterface{ @@ -77,7 +83,8 @@ func update() *BGPMessage { p := []PathAttributeInterface{ NewPathAttributeOrigin(3), - NewPathAttributeAsPath(aspath), + NewPathAttributeAsPath(aspath1), + NewPathAttributeAsPath(aspath2), NewPathAttributeNextHop("129.1.1.2"), NewPathAttributeMultiExitDisc(1 << 20), NewPathAttributeLocalPref(1 << 22), @@ -87,7 +94,7 @@ func update() *BGPMessage { NewPathAttributeOriginatorId("10.10.0.1"), NewPathAttributeClusterList([]string{"10.10.0.2", "10.10.0.3"}), NewPathAttributeExtendedCommunities(ecommunities), - NewPathAttributeAs4Path(aspath2), + NewPathAttributeAs4Path(aspath3), NewPathAttributeAs4Aggregator(10000, "112.22.2.1"), NewPathAttributeMpReachNLRI("112.22.2.0", mp_nlri), NewPathAttributeMpReachNLRI("1023::", mp_nlri2), |