Skip to content

Commit 0c88925

Browse files
committed
Bgp: multiprotocol capability negotiation in OPEN (RFC 4760 / RFC 5492)
For an IPv6 BGP session the speaker now advertises the Multiprotocol Extensions capability in the OPEN message, so the peer learns we use the IPv6 (AFI=2, SAFI=1) address family instead of relying on out-of-band agreement. IPv4 unicast is BGP's default address family (RFC 4271), so IPv4 sessions send no capabilities and their OPEN encoding (and all 8 IPv4 bgpv4 fingerprints) stay byte-identical. - BgpHeader.msg: add the RFC 5492 Capabilities optional parameter (BgpOptionalParameterCapabilities, parameter type 2) carrying a list of capabilities, and the RFC 4760 Multiprotocol Extensions capability (BgpCapabilityMultiprotocol, code 1: AFI + reserved + SAFI). - BgpSession::sendOpenMessage(): for IPv6 sessions attach one Multiprotocol capability (AFI=2, SAFI=1) and size the optional-parameters / total / chunk lengths accordingly; IPv4 sessions are unchanged. - BgpHeaderSerializer: serialize and deserialize the Capabilities parameter and Multiprotocol capability (unknown optional-parameter / capability types still round-trip as raw / header-only). Also fixes a latent infinite-loop guard in the raw optional-parameter serialize loop. - BgpRouter::printOpenMessage(): parse and log the peer's advertised capabilities (AFI/SAFI). Advertise + parse only; no enforcement / NOTIFICATION. Verified: new tests/unit/Bgp_open_capability_serializer.test (serialize-> deserialize round-trip for IPv6 and IPv4 advertisements) PASSES; IPv4 (Bgp2RoutersInAS: OPEN carries no capabilities, sessions ESTABLISHED, UPDATEs flow) stays byte-identical, IPv6 (BgpIpv6Basic: hostA->hostB 20/21 pings) advertises the capability and converges. Only the 2 IPv6 bgpv4 fingerprints (BgpIpv6Basic, BgpAndOspfv3) change; the 8 IPv4 ones are byte-identical.
1 parent ee91fcc commit 0c88925

5 files changed

Lines changed: 212 additions & 8 deletions

File tree

src/inet/routing/bgpv4/BgpRouter.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,6 +1034,16 @@ void BgpRouter::printOpenMessage(const BgpOpenMessage& openMsg)
10341034
EV_INFO << " Optional parameter " << i + 1 << ": \n";
10351035
EV_INFO << " Parameter type: " << optParam->getParameterType() << "\n";
10361036
EV_INFO << " Parameter length: " << optParam->getParameterValueLength() << "\n";
1037+
if (auto caps = dynamic_cast<const BgpOptionalParameterCapabilities *>(optParam)) {
1038+
for (size_t c = 0; c < caps->getCapabilityArraySize(); c++) {
1039+
auto cap = caps->getCapability(c);
1040+
if (auto mp = dynamic_cast<const BgpCapabilityMultiprotocol *>(cap))
1041+
EV_INFO << " Capability: Multiprotocol Extensions, AFI=" << mp->getAfi()
1042+
<< " SAFI=" << (int)mp->getSafi() << "\n";
1043+
else
1044+
EV_INFO << " Capability: code " << (int)cap->getCapabilityCode() << "\n";
1045+
}
1046+
}
10371047
}
10381048
}
10391049

src/inet/routing/bgpv4/BgpSession.cc

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,28 @@ void BgpSession::sendOpenMessage()
150150
// BGP Identifier is a 4-octet router id; for IPv6 it cannot be the (IPv6) local address
151151
openMsg->setBgpIdentifier(bgpRouter.isIpv6() ? bgpRouter.getRouterId() : _info.socket->getLocalAddress().toIpv4());
152152

153+
// For an IPv6 session, advertise the Multiprotocol Extensions capability (RFC 4760 /
154+
// RFC 5492) so the peer learns we use the IPv6 (AFI=2, SAFI=1) address family. IPv4
155+
// unicast is BGP's default address family (RFC 4271), so for IPv4 sessions the OPEN
156+
// carries no capabilities (and stays byte-identical to the pre-MP-BGP encoding).
157+
if (bgpRouter.isIpv6()) {
158+
auto *mpCap = new BgpCapabilityMultiprotocol();
159+
mpCap->setAfi(2); // IPv6
160+
mpCap->setSafi(1); // unicast
161+
auto *capsParam = new BgpOptionalParameterCapabilities();
162+
capsParam->setCapabilityArraySize(1);
163+
capsParam->setCapability(0, mpCap);
164+
// parameter value = the capability list: capCode(1) + capLen(1) + value(capabilityLength)
165+
capsParam->setParameterValueLength(2 + mpCap->getCapabilityLength());
166+
openMsg->setOptionalParameterArraySize(1);
167+
openMsg->setOptionalParameter(0, capsParam);
168+
// optional parameters total = paramType(1) + paramLen(1) + parameter value
169+
unsigned short optParamsLength = 2 + capsParam->getParameterValueLength();
170+
openMsg->setOptionalParametersLength(optParamsLength);
171+
openMsg->setTotalLength((BGP_HEADER_OCTETS + BGP_OPEN_OCTETS).get<B>() + optParamsLength);
172+
openMsg->setChunkLength(BGP_HEADER_OCTETS + BGP_OPEN_OCTETS + B(optParamsLength));
173+
}
174+
153175
EV_INFO << "Sending BGP Open message to " << _info.peerAddr.str()
154176
<< " on interface " << _info.linkIntf->getInterfaceName()
155177
<< "[" << _info.linkIntf->getInterfaceId() << "] with contents:\n";

src/inet/routing/bgpv4/bgpmessage/BgpHeader.msg

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,45 @@ class BgpOptionalParameterBase
7676
unsigned short parameterValueLength;
7777
}
7878

79-
//TODO add accepted BgpOptionalParameter variants
80-
8179
class BgpOptionalParameterRaw extends BgpOptionalParameterBase
8280
{
8381
char value[];
8482
}
8583

84+
//
85+
// Base for a BGP capability advertised inside a Capabilities optional parameter
86+
// (RFC 5492). On the wire: Capability Code (1 octet) + Capability Length (1 octet)
87+
// + Capability Value (Capability Length octets).
88+
//
89+
class BgpCapabilityBase
90+
{
91+
@packetData;
92+
uint8_t capabilityCode;
93+
uint8_t capabilityLength; // length (in octets) of the capability value
94+
}
95+
96+
//
97+
// Multiprotocol Extensions capability (RFC 4760, section 8); advertises one
98+
// (AFI, SAFI) pair the speaker supports. AFI=1 IPv4, AFI=2 IPv6; SAFI=1 unicast.
99+
//
100+
class BgpCapabilityMultiprotocol extends BgpCapabilityBase
101+
{
102+
capabilityCode = 1;
103+
capabilityLength = 4;
104+
uint16_t afi; // Address Family Identifier
105+
uint8_t reserved = 0; // 1 octet, sent as 0
106+
uint8_t safi; // Subsequent Address Family Identifier
107+
}
108+
109+
//
110+
// Capabilities Optional Parameter (RFC 5492); carries one or more capabilities.
111+
//
112+
class BgpOptionalParameterCapabilities extends BgpOptionalParameterBase
113+
{
114+
parameterType = 2; // Capabilities (RFC 5492)
115+
BgpCapabilityBase *capability[] @owned;
116+
}
117+
86118
//
87119
// Represents a BGPv4 OPEN message.
88120
//

src/inet/routing/bgpv4/bgpmessage/BgpHeaderSerializer.cc

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,31 @@ void BgpHeaderSerializer::serialize(MemoryOutputStream& stream, const Ptr<const
7979
stream.writeByte(optionalParametersLength);
8080
unsigned short numOptionalParametersBytes = 0;
8181
for (size_t i = 0; i < bgpOpenMessage->getOptionalParameterArraySize(); ++i) {
82-
const BgpOptionalParameterRaw *optionalParameter = static_cast<const BgpOptionalParameterRaw *>(bgpOpenMessage->getOptionalParameter(i));
82+
const BgpOptionalParameterBase *optionalParameter = bgpOpenMessage->getOptionalParameter(i);
8383
stream.writeByte(optionalParameter->getParameterType());
8484
unsigned short parameterValueLength = optionalParameter->getParameterValueLength();
8585
stream.writeByte(parameterValueLength);
86-
for (size_t e = 0; optionalParameter->getValueArraySize(); ++e) {
87-
stream.writeByte(optionalParameter->getValue(e));
86+
if (auto caps = dynamic_cast<const BgpOptionalParameterCapabilities *>(optionalParameter)) {
87+
// RFC 5492 Capabilities: a list of <code, length, value> capabilities
88+
for (size_t c = 0; c < caps->getCapabilityArraySize(); ++c) {
89+
const BgpCapabilityBase *cap = caps->getCapability(c);
90+
stream.writeByte(cap->getCapabilityCode());
91+
stream.writeByte(cap->getCapabilityLength());
92+
if (auto mp = dynamic_cast<const BgpCapabilityMultiprotocol *>(cap)) {
93+
stream.writeUint16Be(mp->getAfi());
94+
stream.writeByte(mp->getReserved());
95+
stream.writeByte(mp->getSafi());
96+
}
97+
else
98+
throw cRuntimeError("Cannot serialize BGP OPEN Message: unknown BGP capability code %d.", cap->getCapabilityCode());
99+
}
100+
}
101+
else if (auto raw = dynamic_cast<const BgpOptionalParameterRaw *>(optionalParameter)) {
102+
for (size_t e = 0; e < raw->getValueArraySize(); ++e)
103+
stream.writeByte(raw->getValue(e));
88104
}
105+
else
106+
throw cRuntimeError("Cannot serialize BGP OPEN Message: unknown optional parameter type %d.", optionalParameter->getParameterType());
89107
numOptionalParametersBytes += 2 + parameterValueLength;
90108
}
91109
if (numOptionalParametersBytes != optionalParametersLength)
@@ -262,11 +280,43 @@ const Ptr<Chunk> BgpHeaderSerializer::deserialize(MemoryInputStream& stream) con
262280
bgpOpenMessage->setOptionalParametersLength(optionalParametersLength);
263281
for (size_t i = 0; optionalParametersLength > 0; ++i) {
264282
bgpOpenMessage->setOptionalParameterArraySize(i + 1);
265-
BgpOptionalParameterRaw *optionalParameter = new BgpOptionalParameterRaw();
266-
optionalParameter->setParameterType(stream.readByte());
283+
uint8_t parameterType = stream.readByte();
267284
uint8_t parameterValueLength = stream.readByte();
268-
optionalParameter->setParameterValueLength(parameterValueLength);
269285
optionalParametersLength -= (2 + parameterValueLength);
286+
if (parameterType == 2) {
287+
// RFC 5492 Capabilities optional parameter: a list of capabilities
288+
BgpOptionalParameterCapabilities *caps = new BgpOptionalParameterCapabilities();
289+
caps->setParameterValueLength(parameterValueLength);
290+
uint8_t remaining = parameterValueLength;
291+
for (size_t c = 0; remaining > 0; ++c) {
292+
uint8_t capabilityCode = stream.readByte();
293+
uint8_t capabilityLength = stream.readByte();
294+
remaining -= (2 + capabilityLength);
295+
caps->setCapabilityArraySize(c + 1);
296+
if (capabilityCode == 1 && capabilityLength == 4) {
297+
// Multiprotocol Extensions (RFC 4760)
298+
BgpCapabilityMultiprotocol *mp = new BgpCapabilityMultiprotocol();
299+
mp->setAfi(stream.readUint16Be());
300+
mp->setReserved(stream.readByte());
301+
mp->setSafi(stream.readByte());
302+
caps->setCapability(c, mp);
303+
}
304+
else {
305+
// unknown capability: keep its header, skip the value bytes
306+
BgpCapabilityBase *cap = new BgpCapabilityBase();
307+
cap->setCapabilityCode(capabilityCode);
308+
cap->setCapabilityLength(capabilityLength);
309+
for (uint8_t k = 0; k < capabilityLength; ++k)
310+
stream.readByte();
311+
caps->setCapability(c, cap);
312+
}
313+
}
314+
bgpOpenMessage->setOptionalParameter(i, caps);
315+
continue;
316+
}
317+
BgpOptionalParameterRaw *optionalParameter = new BgpOptionalParameterRaw();
318+
optionalParameter->setParameterType(parameterType);
319+
optionalParameter->setParameterValueLength(parameterValueLength);
270320
for (size_t e = 0; parameterValueLength > 0; ++e) {
271321
optionalParameter->setValueArraySize(e + 1);
272322
optionalParameter->setValue(e, stream.readByte());
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
%description:
2+
Round-trip serialization of the BGP OPEN message carrying the RFC 5492 Capabilities
3+
optional parameter with an RFC 4760 Multiprotocol Extensions capability (AFI/SAFI).
4+
Verifies serialize->bytes->deserialize reproduces the capability and the expected
5+
on-wire length, for both the IPv6 (AFI=2) and IPv4 (AFI=1) advertisements.
6+
7+
%includes:
8+
#include "inet/common/packet/Packet.h"
9+
#include "inet/common/packet/chunk/BytesChunk.h"
10+
#include "inet/routing/bgpv4/bgpmessage/BgpHeader_m.h"
11+
12+
using namespace inet;
13+
using namespace inet::bgp;
14+
15+
%global:
16+
17+
// build an OPEN advertising one Multiprotocol capability for the given AFI/SAFI,
18+
// exactly as BgpSession::sendOpenMessage() does
19+
static Ptr<BgpOpenMessage> makeOpen(uint16_t afi, uint8_t safi)
20+
{
21+
auto open = makeShared<BgpOpenMessage>();
22+
open->setMyAS(64500);
23+
open->setHoldTime(SimTime(180, SIMTIME_S));
24+
open->setBgpIdentifier(Ipv4Address("1.2.3.4"));
25+
26+
auto *mp = new BgpCapabilityMultiprotocol();
27+
mp->setAfi(afi);
28+
mp->setSafi(safi);
29+
auto *caps = new BgpOptionalParameterCapabilities();
30+
caps->setCapabilityArraySize(1);
31+
caps->setCapability(0, mp);
32+
caps->setParameterValueLength(2 + mp->getCapabilityLength());
33+
open->setOptionalParameterArraySize(1);
34+
open->setOptionalParameter(0, caps);
35+
unsigned short optLen = 2 + caps->getParameterValueLength();
36+
open->setOptionalParametersLength(optLen);
37+
open->setTotalLength((BGP_HEADER_OCTETS + BGP_OPEN_OCTETS).get<B>() + optLen);
38+
open->setChunkLength(BGP_HEADER_OCTETS + BGP_OPEN_OCTETS + B(optLen));
39+
return open;
40+
}
41+
42+
static Ptr<const BgpOpenMessage> roundTrip(const Ptr<const BgpOpenMessage>& original)
43+
{
44+
Packet pkt("test");
45+
pkt.insertAtFront(original);
46+
auto bytes = pkt.peekAllAsBytes(); // forces serialize()
47+
Packet pkt2("test2");
48+
pkt2.insertAtFront(bytes);
49+
auto hdr = pkt2.popAtFront<BgpHeader>(); // forces deserialize()
50+
return dynamicPtrCast<const BgpOpenMessage>(hdr);
51+
}
52+
53+
static void checkAf(uint16_t afi, uint8_t safi)
54+
{
55+
auto open = makeOpen(afi, safi);
56+
57+
// OPEN base (29) + one capabilities param (2) + one MP capability (2 + 4) = 37 octets
58+
Packet sz("sz"); sz.insertAtFront(open);
59+
ASSERT(sz.getDataLength() == B(37));
60+
61+
auto o2 = roundTrip(staticPtrCast<const BgpOpenMessage>(open));
62+
ASSERT(o2 != nullptr);
63+
ASSERT(o2->getMyAS() == 64500);
64+
ASSERT(o2->getBgpIdentifier() == Ipv4Address("1.2.3.4"));
65+
ASSERT(o2->getOptionalParametersLength() == 8);
66+
ASSERT(o2->getOptionalParameterArraySize() == 1);
67+
68+
auto caps = dynamic_cast<const BgpOptionalParameterCapabilities *>(o2->getOptionalParameter(0));
69+
ASSERT(caps != nullptr);
70+
ASSERT(caps->getParameterType() == 2);
71+
ASSERT(caps->getCapabilityArraySize() == 1);
72+
73+
auto mp = dynamic_cast<const BgpCapabilityMultiprotocol *>(caps->getCapability(0));
74+
ASSERT(mp != nullptr);
75+
ASSERT(mp->getCapabilityCode() == 1);
76+
ASSERT(mp->getCapabilityLength() == 4);
77+
ASSERT(mp->getAfi() == afi);
78+
ASSERT(mp->getSafi() == safi);
79+
EV << " AFI=" << afi << " SAFI=" << (int)safi << " round-trip PASS" << endl;
80+
}
81+
82+
%activity:
83+
84+
EV << "=== BGP OPEN Multiprotocol capability round-trip ===" << endl;
85+
checkAf(2, 1); // IPv6 unicast
86+
checkAf(1, 1); // IPv4 unicast
87+
EV << "All BGP OPEN capability round-trips passed." << endl;
88+
89+
%contains: stdout
90+
All BGP OPEN capability round-trips passed.

0 commit comments

Comments
 (0)