diff --git a/protocols/bgp/packet/bgp.go b/protocols/bgp/packet/bgp.go index c6776ace6c41f6ccbfd8e2b126f38fc5c16d4798..3f25ddf60adea2bfdf13b6043e06ef05818a999c 100644 --- a/protocols/bgp/packet/bgp.go +++ b/protocols/bgp/packet/bgp.go @@ -85,15 +85,17 @@ const ( ConnectionCollisionResolution = 7 OutOfResoutces = 8 - IPv4AFI = 1 - UnicastSAFI = 1 - CapabilitiesParamType = 2 - AddPathCapabilityCode = 69 - ASN4CapabilityCode = 65 - AddPathReceive = 1 - AddPathSend = 2 - AddPathSendReceive = 3 - ASTransASN = 23456 + IPv4AFI = 1 + IPv6AFI = 2 + UnicastSAFI = 1 + CapabilitiesParamType = 2 + MultiProtocolCapabilityCode = 1 + AddPathCapabilityCode = 69 + ASN4CapabilityCode = 65 + AddPathReceive = 1 + AddPathSend = 2 + AddPathSendReceive = 3 + ASTransASN = 23456 ) type BGPError struct { diff --git a/protocols/bgp/packet/decoder.go b/protocols/bgp/packet/decoder.go index ca717c781194adf20d2d5c08f332c03f060be849..cd951463a15215bd6aaa43e8799e59c95cee549b 100644 --- a/protocols/bgp/packet/decoder.go +++ b/protocols/bgp/packet/decoder.go @@ -233,6 +233,12 @@ func decodeCapability(buf *bytes.Buffer) (Capability, error) { } switch cap.Code { + case MultiProtocolCapabilityCode: + mpCap, err := decodeMultiProtocolCapability(buf) + if err != nil { + return cap, fmt.Errorf("Unable to decode multi protocol capability") + } + cap.Value = mpCap case AddPathCapabilityCode: addPathCap, err := decodeAddPathCapability(buf) if err != nil { @@ -257,6 +263,21 @@ func decodeCapability(buf *bytes.Buffer) (Capability, error) { return cap, nil } +func decodeMultiProtocolCapability(buf *bytes.Buffer) (MultiProtocolCapability, error) { + mpCap := MultiProtocolCapability{} + reserved := uint8(0) + fields := []interface{}{ + &mpCap.AFI, &reserved, &mpCap.SAFI, + } + + err := decode(buf, fields) + if err != nil { + return mpCap, err + } + + return mpCap, nil +} + func decodeAddPathCapability(buf *bytes.Buffer) (AddPathCapability, error) { addPathCap := AddPathCapability{} fields := []interface{}{ diff --git a/protocols/bgp/packet/decoder_test.go b/protocols/bgp/packet/decoder_test.go index 5613bbcb6c46a385492f5c38f5a837ae5e287ee7..ac611ceff133e4375e70995a2b564900671ed8aa 100644 --- a/protocols/bgp/packet/decoder_test.go +++ b/protocols/bgp/packet/decoder_test.go @@ -1736,6 +1736,19 @@ func TestDecodeCapability(t *testing.T) { }, wantFail: false, }, + { + name: "MP Capability (IPv6)", + input: []byte{1, 4, 0, 2, 0, 1}, + expected: Capability{ + Code: MultiProtocolCapabilityCode, + Length: 4, + Value: MultiProtocolCapability{ + AFI: IPv6AFI, + SAFI: UnicastSAFI, + }, + }, + wantFail: false, + }, { name: "Fail", input: []byte{69, 4, 0, 1}, diff --git a/protocols/bgp/packet/encoder_test.go b/protocols/bgp/packet/encoder_test.go index fd7405d735a5d11a4117d144e7086828c86f5628..1b0b60d5c919227acc5418dfef3e5802aa92b8d7 100644 --- a/protocols/bgp/packet/encoder_test.go +++ b/protocols/bgp/packet/encoder_test.go @@ -106,30 +106,61 @@ func TestSerializeOptParams(t *testing.T) { expected: []byte{}, }, { - name: "1 Option", + name: "AddPath", optParams: []OptParam{ - { + OptParam{ Type: 2, Length: 6, - Value: Capability{ - Code: 69, - Length: 4, - Value: AddPathCapability{ - AFI: 1, - SAFI: 1, - SendReceive: 3, + Value: Capabilities{ + Capability{ + Code: 69, + Length: 4, + Value: AddPathCapability{ + AFI: 1, + SAFI: 1, + SendReceive: 3, + }, }, }, }, }, expected: []byte{2, 6, 69, 4, 0, 1, 1, 3}, }, + { + name: "Multi Protocol Support (IPv6), 32 bit ASNs", + optParams: []OptParam{ + OptParam{ + Length: 12, + Type: CapabilitiesParamType, + Value: Capabilities{ + Capability{ + Code: MultiProtocolCapabilityCode, + Length: 4, + Value: MultiProtocolCapability{ + AFI: 2, + SAFI: 1, + }, + }, + Capability{ + Code: ASN4CapabilityCode, + Length: 4, + Value: ASN4Capability{ + ASN4: 202739, + }, + }, + }, + }, + }, + expected: []byte{2, 12, 1, 4, 0, 2, 0, 1, 65, 4, 0x00, 0x03, 0x17, 0xf3}, + }, } for _, test := range tests { - buf := bytes.NewBuffer(make([]byte, 0)) - serializeOptParams(buf, test.optParams) - assert.Equal(t, test.expected, buf.Bytes()) + t.Run(test.name, func(t *testing.T) { + buf := bytes.NewBuffer(make([]byte, 0)) + serializeOptParams(buf, test.optParams) + assert.Equal(t, test.expected, buf.Bytes()) + }) } } diff --git a/protocols/bgp/packet/parameters.go b/protocols/bgp/packet/parameters.go index 0ed9af66fe01f96600c02eeb2c00b69b11edc76c..2f99f773af6e2659beb1c4585cb7c2b27ed5ff01 100644 --- a/protocols/bgp/packet/parameters.go +++ b/protocols/bgp/packet/parameters.go @@ -29,6 +29,8 @@ func (c Capabilities) serialize(buf *bytes.Buffer) { for _, cap := range c { cap.serialize(tmpBuf) } + + buf.Write(tmpBuf.Bytes()) } func (c Capability) serialize(buf *bytes.Buffer) { @@ -60,3 +62,14 @@ type ASN4Capability struct { func (a ASN4Capability) serialize(buf *bytes.Buffer) { buf.Write(convert.Uint32Byte(a.ASN4)) } + +type MultiProtocolCapability struct { + AFI uint16 + SAFI uint8 +} + +func (a MultiProtocolCapability) serialize(buf *bytes.Buffer) { + buf.Write(convert.Uint16Byte(a.AFI)) + buf.WriteByte(0) // RESERVED + buf.WriteByte(a.SAFI) +} diff --git a/protocols/bgp/server/peer.go b/protocols/bgp/server/peer.go index 2772903061d6180c6d49ff48c70e3f96af4dfc33..7a7587f83d060fdbad636897317e4225a527ed3a 100644 --- a/protocols/bgp/server/peer.go +++ b/protocols/bgp/server/peer.go @@ -124,7 +124,7 @@ func newPeer(c config.Peer, rib *locRIB.LocRIB, server *bgpServer) (*peer, error } p.fsms = append(p.fsms, NewActiveFSM2(p)) - caps := make([]packet.Capability, 0) + caps := make(packet.Capabilities, 0) addPathEnabled, addPathCap := handleAddPathCapability(c) if addPathEnabled { @@ -133,12 +133,10 @@ func newPeer(c config.Peer, rib *locRIB.LocRIB, server *bgpServer) (*peer, error caps = append(caps, asn4Capability(c)) - for _, cap := range caps { - p.optOpenParams = append(p.optOpenParams, packet.OptParam{ - Type: packet.CapabilitiesParamType, - Value: cap, - }) - } + p.optOpenParams = append(p.optOpenParams, packet.OptParam{ + Type: packet.CapabilitiesParamType, + Value: caps, + }) return p, nil }