Skip to content

Commit

Permalink
Merge "Add BGP ExtendedLength attribute encoding." into R2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
Zuul authored and opencontrail-ci-admin committed May 18, 2015
2 parents 3808ae6 + 3d6486b commit dad6d8d
Show file tree
Hide file tree
Showing 12 changed files with 473 additions and 38 deletions.
13 changes: 8 additions & 5 deletions src/base/proto.h
Expand Up @@ -439,7 +439,7 @@ class ProtoChoice : public ChoiceBase {
ChoiceEncoder(EncodeContext *context, const T *msg, uint8_t *data, int size,
int *resultp)
: context(context), msg(msg), data(data), size(size),
resultp(resultp) {
resultp(resultp), found(false) {
}
template <typename U, typename CtxType>
struct EncoderTrue {
Expand All @@ -465,8 +465,9 @@ class ProtoChoice : public ChoiceBase {
struct EncoderSetter {
int operator()(int opt, EncodeContext *context, const CtxType *msg,
uint8_t *data, int size) {
if (Derived::Setter::get(msg) == opt) {
return EncoderTrue<U, CtxType>()(opt, context, msg, data, size);
int value = Derived::Setter::get(msg);
if (value == opt || opt == -1) {
return EncoderTrue<U, CtxType>()(value, context, msg, data, size);
}
return 0;
}
Expand Down Expand Up @@ -508,7 +509,7 @@ class ProtoChoice : public ChoiceBase {
};
template <typename U>
void operator()(U x) {
if (*resultp < 0) {
if (*resultp < 0 || found) {
return;
}
// The choice element can be determined by:
Expand All @@ -534,7 +535,8 @@ class ProtoChoice : public ChoiceBase {
int result = choice(U::first::value, context, msg, data, size);
if (result < 0) {
*resultp = result;
} else {
} else if (result > 0) {
found = true;
*resultp += result;
}
}
Expand All @@ -544,6 +546,7 @@ class ProtoChoice : public ChoiceBase {
uint8_t *data;
int size;
int *resultp;
bool found;
};
};

Expand Down
9 changes: 9 additions & 0 deletions src/bgp/bgp_aspath.cc
Expand Up @@ -56,6 +56,15 @@ std::string AsPathSpec::ToString() const {
return oss.str();
}

size_t AsPathSpec::EncodeLength() const {
size_t sz = 0;
for (size_t i = 0; i < path_segments.size(); i++) {
sz += 2;
sz += path_segments[i]->path_segment.size() * 2;
}
return sz;
}

bool AsPathSpec::AsPathLoop(as_t as) const {
for (size_t i = 0; i < path_segments.size(); i++)
for (size_t j = 0; j < path_segments[i]->path_segment.size(); j++)
Expand Down
1 change: 1 addition & 0 deletions src/bgp/bgp_aspath.h
Expand Up @@ -63,6 +63,7 @@ struct AsPathSpec : public BgpAttribute {

virtual int CompareTo(const BgpAttribute &rhs_attr) const;
virtual void ToCanonical(BgpAttr *attr);
virtual size_t EncodeLength() const;
virtual std::string ToString() const;
AsPathSpec *Add(as_t asn) const;
std::vector<PathSegment *> path_segments;
Expand Down
110 changes: 101 additions & 9 deletions src/bgp/bgp_attr.cc
Expand Up @@ -5,6 +5,7 @@
#include "bgp/bgp_attr.h"
#include "base/util.h"
#include "bgp/bgp_proto.h"
#include "net/bgp_af.h"

int BgpAttrOrigin::CompareTo(const BgpAttribute &rhs_attr) const {
int ret = BgpAttribute::CompareTo(rhs_attr);
Expand Down Expand Up @@ -149,6 +150,25 @@ int BgpMpNlri::CompareTo(const BgpAttribute &rhs_attr) const {
void BgpMpNlri::ToCanonical(BgpAttr *attr) {
}

size_t BgpMpNlri::EncodeLength() const {
size_t sz = 2 /* safi */ + 1 /* afi */ +
1 /* NlriNextHopLength */ +
1 /* Reserved */;
sz += nexthop.size();
for (std::vector<BgpProtoPrefix*>::const_iterator iter = nlri.begin();
iter != nlri.end(); ++iter) {
size_t bytes = 0;
if (afi == BgpAf::L2Vpn &&
(safi == BgpAf::EVpn || safi == BgpAf::ErmVpn)) {
bytes = (*iter)->prefixlen;
} else {
bytes = ((*iter)->prefixlen + 7) / 8;
}
sz += 1 + bytes;
}
return sz;
}

PmsiTunnelSpec::PmsiTunnelSpec()
: BgpAttribute(PmsiTunnel, kFlags),
tunnel_flags(0), tunnel_type(0), label(0) {
Expand All @@ -161,9 +181,11 @@ PmsiTunnelSpec::PmsiTunnelSpec(const BgpAttribute &rhs)
int PmsiTunnelSpec::CompareTo(const BgpAttribute &rhs_attr) const {
int ret = BgpAttribute::CompareTo(rhs_attr);
if (ret != 0) return ret;
const PmsiTunnelSpec &rhs =
static_cast<const PmsiTunnelSpec &>(rhs_attr);
KEY_COMPARE(this, &rhs);
const PmsiTunnelSpec &rhs = static_cast<const PmsiTunnelSpec &>(rhs_attr);
KEY_COMPARE(tunnel_flags, rhs.tunnel_flags);
KEY_COMPARE(tunnel_type, rhs.tunnel_type);
KEY_COMPARE(label, rhs.label);
KEY_COMPARE(identifier, rhs.identifier);
return 0;
}

Expand Down Expand Up @@ -255,13 +277,47 @@ void EdgeDiscoverySpec::Edge::SetLabels(
labels.push_back(last_label);
}

template <class InputIterator, class CompareOp>
int STLSortedCompare(InputIterator first1, InputIterator last1,
InputIterator first2, InputIterator last2,
CompareOp op) {
InputIterator iter1 = first1;
InputIterator iter2 = first2;
while (iter1 != last1 && iter2 != last2) {
int result = op(*iter1, *iter2);
if (result != 0) {
return result;
}
++iter1;
++iter2;
}
if (iter1 != last1) {
return 1;
}
if (iter2 != last2) {
return -1;
}
return 0;
}

struct EdgeDiscoverySpecEdgeCompare {
int operator()(const EdgeDiscoverySpec::Edge *lhs,
const EdgeDiscoverySpec::Edge *rhs) const {
KEY_COMPARE(lhs->address, rhs->address);
KEY_COMPARE(lhs->labels, rhs->labels);
return 0;
}
};

int EdgeDiscoverySpec::CompareTo(const BgpAttribute &rhs_attr) const {
int ret = BgpAttribute::CompareTo(rhs_attr);
if (ret != 0) return ret;
const EdgeDiscoverySpec &rhs =
static_cast<const EdgeDiscoverySpec &>(rhs_attr);
KEY_COMPARE(this, &rhs);
return 0;
static_cast<const EdgeDiscoverySpec &>(rhs_attr);
ret = STLSortedCompare(edge_list.begin(), edge_list.end(),
rhs.edge_list.begin(), rhs.edge_list.end(),
EdgeDiscoverySpecEdgeCompare());
return ret;
}

void EdgeDiscoverySpec::ToCanonical(BgpAttr *attr) {
Expand All @@ -285,6 +341,17 @@ std::string EdgeDiscoverySpec::ToString() const {
return oss.str();
}

size_t EdgeDiscoverySpec::EncodeLength() const {
size_t sz = 0;
for (EdgeList::const_iterator iter = edge_list.begin();
iter != edge_list.end(); ++iter) {
sz += 2; /* AddressLen + LabelLen */
sz += (*iter)->address.size();
sz += (*iter)->labels.size() * sizeof(uint32_t);
}
return sz;
}

EdgeDiscovery::Edge::Edge(const EdgeDiscoverySpec::Edge *spec_edge) {
address = spec_edge->GetIp4Address();
uint32_t first_label, last_label;
Expand Down Expand Up @@ -349,13 +416,26 @@ void EdgeForwardingSpec::Edge::SetOutboundIp4Address(Ip4Address addr) {
outbound_address.begin());
}

struct EdgeForwardingSpecEdgeCompare {
int operator()(const EdgeForwardingSpec::Edge *lhs,
const EdgeForwardingSpec::Edge *rhs) const {
KEY_COMPARE(lhs->inbound_address, rhs->inbound_address);
KEY_COMPARE(lhs->outbound_address, rhs->outbound_address);
KEY_COMPARE(lhs->inbound_label, rhs->inbound_label);
KEY_COMPARE(lhs->outbound_label, rhs->outbound_label);
return 0;
}
};

int EdgeForwardingSpec::CompareTo(const BgpAttribute &rhs_attr) const {
int ret = BgpAttribute::CompareTo(rhs_attr);
if (ret != 0) return ret;
const EdgeForwardingSpec &rhs =
static_cast<const EdgeForwardingSpec &>(rhs_attr);
KEY_COMPARE(this, &rhs);
return 0;
static_cast<const EdgeForwardingSpec &>(rhs_attr);
ret = STLSortedCompare(edge_list.begin(), edge_list.end(),
rhs.edge_list.begin(), rhs.edge_list.end(),
EdgeForwardingSpecEdgeCompare());
return ret;
}

void EdgeForwardingSpec::ToCanonical(BgpAttr *attr) {
Expand All @@ -380,6 +460,18 @@ std::string EdgeForwardingSpec::ToString() const {
return oss.str();
}

size_t EdgeForwardingSpec::EncodeLength() const {
size_t sz = 0;
for (EdgeList::const_iterator iter = edge_list.begin();
iter != edge_list.end(); ++iter) {
sz += 1 /* address len */ + 8 /* 2 labels */;
sz += (*iter)->inbound_address.size();
sz += (*iter)->outbound_address.size();
}

return sz;
}

EdgeForwarding::Edge::Edge(const EdgeForwardingSpec::Edge *spec_edge) {
inbound_address = spec_edge->GetInboundIp4Address();
outbound_address = spec_edge->GetOutboundIp4Address();
Expand Down
3 changes: 3 additions & 0 deletions src/bgp/bgp_attr.h
Expand Up @@ -150,6 +150,7 @@ struct BgpMpNlri : public BgpAttribute {
}
virtual int CompareTo(const BgpAttribute &rhs_attr) const;
virtual void ToCanonical(BgpAttr *attr);
virtual size_t EncodeLength() const;

uint16_t afi;
uint8_t safi;
Expand Down Expand Up @@ -237,6 +238,7 @@ struct EdgeDiscoverySpec : public BgpAttribute {
virtual int CompareTo(const BgpAttribute &rhs_attr) const;
virtual void ToCanonical(BgpAttr *attr);
virtual std::string ToString() const;
virtual size_t EncodeLength() const;

struct Edge : public ParseObject {
Ip4Address GetIp4Address() const;
Expand Down Expand Up @@ -298,6 +300,7 @@ struct EdgeForwardingSpec : public BgpAttribute {
virtual int CompareTo(const BgpAttribute &rhs_attr) const;
virtual void ToCanonical(BgpAttr *attr);
virtual std::string ToString() const;
virtual size_t EncodeLength() const;

struct Edge : public ParseObject {
Ip4Address GetInboundIp4Address() const;
Expand Down
14 changes: 13 additions & 1 deletion src/bgp/bgp_attr_base.cc
Expand Up @@ -32,10 +32,22 @@ void BgpProtoPrefix::WriteLabel(size_t label_offset, uint32_t label) {
int BgpAttribute::CompareTo(const BgpAttribute &rhs) const {
KEY_COMPARE(code, rhs.code);
KEY_COMPARE(subcode, rhs.subcode);
KEY_COMPARE(flags, rhs.flags);
KEY_COMPARE(flags & ~ExtendedLength, rhs.flags & ~ExtendedLength);
return 0;
}

size_t BgpAttribute::EncodeLength() const {
return 0;
}

uint8_t BgpAttribute::GetEncodeFlags() const {
uint8_t value = flags;
if (EncodeLength() >= sizeof(uint8_t) << 8) {
value |= BgpAttribute::ExtendedLength;
}
return value;
}

std::string BgpAttribute::ToString() const {
char repr[80];
snprintf(repr, sizeof(repr), "<code: %d, flags: %02x>", code, flags);
Expand Down
13 changes: 12 additions & 1 deletion src/bgp/bgp_attr_base.h
Expand Up @@ -16,7 +16,8 @@

class BgpAttr;

struct BgpAttribute : public ParseObject {
class BgpAttribute : public ParseObject {
public:
enum Flag {
Optional = 1 << 7,
Transitive = 1 << 6,
Expand Down Expand Up @@ -59,6 +60,16 @@ struct BgpAttribute : public ParseObject {
uint8_t code;
uint8_t subcode;
uint8_t flags;
/*
* Variable length attributes should return the size of the attribute
* for encoding purposes in order to set the ExtendedLength flag.
*/
virtual size_t EncodeLength() const;
/*
* Helper method to compute flags used when encoding attributes.
*/
uint8_t GetEncodeFlags() const;

virtual std::string ToString() const;
virtual int CompareTo(const BgpAttribute &rhs) const;
virtual void ToCanonical(BgpAttr *attr) { }
Expand Down
18 changes: 13 additions & 5 deletions src/bgp/bgp_proto.cc
Expand Up @@ -575,7 +575,7 @@ class BgpPathAttrLength : public ProtoElement<BgpPathAttrLength> {
typedef AttrLen SequenceLength;
struct AttrSizeSet {
static int get(const BgpAttribute *obj) {
if (obj->flags & BgpAttribute::ExtendedLength) {
if (obj->GetEncodeFlags() & BgpAttribute::ExtendedLength) {
// Extended Length: use 2 bytes to read
return 2;
} else {
Expand Down Expand Up @@ -807,7 +807,15 @@ class BgpPathAttributeAsPath : public ProtoSequence<BgpPathAttributeAsPath> {
class BgpPathAttributeFlags : public ProtoElement<BgpPathAttributeFlags> {
public:
static const int kSize = 1;
typedef Accessor<BgpAttribute, uint8_t, &BgpAttribute::flags> Setter;
struct FlagsAccessor {
static void set(BgpAttribute *obj, uint8_t value) {
obj->flags = value;
}
static uint8_t get(const BgpAttribute *obj) {
return obj->GetEncodeFlags();
}
};
typedef FlagsAccessor Setter;
};

class BgpPathAttributeCommunityList :
Expand Down Expand Up @@ -1379,6 +1387,7 @@ class BgpPathAttribute : public ProtoChoice<BgpPathAttribute> {
mpl::pair<mpl::int_<BgpAttribute::Origin>,
BgpAttrTemplate<BgpAttrOrigin, 1, int,
&BgpAttrOrigin::origin> >,
mpl::pair<mpl::int_<BgpAttribute::AsPath>, BgpPathAttributeAsPath>,
mpl::pair<mpl::int_<BgpAttribute::NextHop>,
BgpAttrTemplate<BgpAttrNextHop, 4, uint32_t,
&BgpAttrNextHop::nexthop> >,
Expand All @@ -1392,12 +1401,11 @@ class BgpPathAttribute : public ProtoChoice<BgpPathAttribute> {
BgpPathAttributeAtomicAggregate>,
mpl::pair<mpl::int_<BgpAttribute::Aggregator>,
BgpPathAttributeAggregator>,
mpl::pair<mpl::int_<BgpAttribute::Communities>,
BgpPathAttributeCommunities>,
mpl::pair<mpl::int_<BgpAttribute::OriginatorId>,
BgpAttrTemplate<BgpAttrOriginatorId, 4, uint32_t,
&BgpAttrOriginatorId::originator_id> >,
mpl::pair<mpl::int_<BgpAttribute::AsPath>, BgpPathAttributeAsPath>,
mpl::pair<mpl::int_<BgpAttribute::Communities>,
BgpPathAttributeCommunities>,
mpl::pair<mpl::int_<BgpAttribute::MPReachNlri>,
BgpPathAttributeMpReachNlriSequence>,
mpl::pair<mpl::int_<BgpAttribute::MPUnreachNlri>,
Expand Down
10 changes: 6 additions & 4 deletions src/bgp/bgp_session.cc
Expand Up @@ -77,9 +77,8 @@ void BgpSession::SendNotification(int code, int subcode,
msg.error = code;
msg.subcode = subcode;
msg.data = data;
uint8_t buf[256];
int result = BgpProto::Encode(&msg, buf, sizeof(buf));
assert(result > BgpProto::kMinMessageSize);
uint8_t buf[BgpProto::kMaxMessageSize];
int msglen = BgpProto::Encode(&msg, buf, sizeof(buf));

// Use SYS_DEBUG for connection collision, SYS_NOTICE for the rest.
SandeshLevel::type log_level;
Expand All @@ -92,5 +91,8 @@ void BgpSession::SendNotification(int code, int subcode,
BGP_LOG(BgpPeerNotification, log_level, BGP_LOG_FLAG_ALL,
peer_ ? peer_->ToUVEKey() : ToString(),
BGP_PEER_DIR_OUT, code, subcode, msg.ToString());
Send(buf, result, NULL);

if (msglen > BgpProto::kMinMessageSize) {
Send(buf, msglen, NULL);
}
}

0 comments on commit dad6d8d

Please sign in to comment.