Skip to content

Commit

Permalink
Merge "Make BgpProtoPrefix parsing more robust"
Browse files Browse the repository at this point in the history
  • Loading branch information
Zuul authored and Gerrit Code Review committed Sep 24, 2014
2 parents 2086fd9 + 3d2daca commit 2972c61
Show file tree
Hide file tree
Showing 18 changed files with 374 additions and 224 deletions.
158 changes: 111 additions & 47 deletions src/bgp/bgp_peer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -951,21 +951,37 @@ void BgpPeer::ProcessUpdate(const BgpProto::Update *msg) {
for (vector<BgpProtoPrefix *>::const_iterator it =
msg->withdrawn_routes.begin(); it != msg->withdrawn_routes.end();
++it) {
Ip4Prefix prefix;
int result = Ip4Prefix::FromProtoPrefix((**it), &prefix);
if (result) {
BGP_LOG_PEER(Message, this, SandeshLevel::SYS_WARN,
BGP_LOG_FLAG_ALL, BGP_PEER_DIR_IN,
"Withdrawn route parse error");
continue;
}

DBRequest req;
req.oper = DBRequest::DB_ENTRY_DELETE;
req.data.reset(NULL);
Ip4Prefix prefix = Ip4Prefix(**it);
req.key.reset(new InetTable::RequestKey(prefix, this));
table->Enqueue(&req);
inc_rx_route_unreach();
}

for (vector<BgpProtoPrefix *>::const_iterator it = msg->nlri.begin();
it != msg->nlri.end(); ++it) {
Ip4Prefix prefix;
int result = Ip4Prefix::FromProtoPrefix((**it), &prefix);
if (result) {
BGP_LOG_PEER(Message, this, SandeshLevel::SYS_WARN,
BGP_LOG_FLAG_ALL, BGP_PEER_DIR_IN,
"NLRI parse error");
continue;
}

DBRequest req;
req.oper = DBRequest::DB_ENTRY_ADD_CHANGE;
req.data.reset(new InetTable::RequestData(attr, flags, 0));
Ip4Prefix prefix = Ip4Prefix(**it);
req.key.reset(new InetTable::RequestKey(prefix, this));
table->Enqueue(&req);
inc_rx_route_reach();
Expand Down Expand Up @@ -1008,12 +1024,20 @@ void BgpPeer::ProcessUpdate(const BgpProto::Update *msg) {
assert(table);

vector<BgpProtoPrefix *>::const_iterator it;
for (it = nlri->nlri.begin(); it < nlri->nlri.end(); it++) {
for (it = nlri->nlri.begin(); it < nlri->nlri.end(); ++it) {
Ip4Prefix prefix;
int result = Ip4Prefix::FromProtoPrefix((**it), &prefix);
if (result) {
BGP_LOG_PEER(Message, this, SandeshLevel::SYS_WARN,
BGP_LOG_FLAG_ALL, BGP_PEER_DIR_IN,
"NLRI parse error for inet route");
continue;
}

DBRequest req;
req.oper = oper;
if (oper == DBRequest::DB_ENTRY_ADD_CHANGE)
req.data.reset(new InetTable::RequestData(attr, flags, 0));
Ip4Prefix prefix = Ip4Prefix(**it);
req.key.reset(new InetTable::RequestKey(prefix, this));
table->Enqueue(&req);
}
Expand All @@ -1026,16 +1050,25 @@ void BgpPeer::ProcessUpdate(const BgpProto::Update *msg) {
assert(table);

vector<BgpProtoPrefix *>::const_iterator it;
for (it = nlri->nlri.begin(); it < nlri->nlri.end(); it++) {
uint32_t label = ((*it)->prefix[0] << 16 |
(*it)->prefix[1] << 8 |
(*it)->prefix[2]) >> 4;
for (it = nlri->nlri.begin(); it < nlri->nlri.end(); ++it) {
InetVpnPrefix prefix;
uint32_t label = 0;
int result =
InetVpnPrefix::FromProtoPrefix((**it), &prefix, &label);
if (result) {
BGP_LOG_PEER(Message, this, SandeshLevel::SYS_WARN,
BGP_LOG_FLAG_ALL, BGP_PEER_DIR_IN,
"NLRI parse error for inet-vpn route");
continue;
}

DBRequest req;
req.oper = oper;
if (oper == DBRequest::DB_ENTRY_ADD_CHANGE)
req.data.reset(new InetVpnTable::RequestData(attr, flags, label));
req.key.reset(new InetVpnTable::RequestKey(InetVpnPrefix(**it),
this));
if (oper == DBRequest::DB_ENTRY_ADD_CHANGE) {
req.data.reset(
new InetVpnTable::RequestData(attr, flags, label));
}
req.key.reset(new InetVpnTable::RequestKey(prefix, this));
table->Enqueue(&req);
}
break;
Expand All @@ -1048,17 +1081,24 @@ void BgpPeer::ProcessUpdate(const BgpProto::Update *msg) {

vector<BgpProtoPrefix *>::const_iterator it;
for (it = nlri->nlri.begin(); it < nlri->nlri.end(); ++it) {
uint32_t label = ((*it)->prefix[0] << 16 |
(*it)->prefix[1] << 8 |
(*it)->prefix[2]) >> 4;
Inet6VpnPrefix prefix;
uint32_t label = 0;
int result =
Inet6VpnPrefix::FromProtoPrefix((**it), &prefix, &label);
if (result) {
BGP_LOG_PEER(Message, this, SandeshLevel::SYS_WARN,
BGP_LOG_FLAG_ALL, BGP_PEER_DIR_IN,
"NLRI parse error for inet6-vpn route");
continue;
}

DBRequest req;
req.oper = oper;
if (oper == DBRequest::DB_ENTRY_ADD_CHANGE) {
req.data.reset(
new Inet6VpnTable::RequestData(attr, flags, label));
new Inet6VpnTable::RequestData(attr, flags, label));
}
req.key.reset(
new Inet6VpnTable::RequestKey(Inet6VpnPrefix(**it), this));
req.key.reset(new Inet6VpnTable::RequestKey(prefix, this));
table->Enqueue(&req);
}
break;
Expand All @@ -1071,7 +1111,7 @@ void BgpPeer::ProcessUpdate(const BgpProto::Update *msg) {
assert(table);

vector<BgpProtoPrefix *>::const_iterator it;
for (it = nlri->nlri.begin(); it < nlri->nlri.end(); it++) {
for (it = nlri->nlri.begin(); it < nlri->nlri.end(); ++it) {
EvpnPrefix prefix;
BgpAttrPtr new_attr;
uint32_t label = 0;
Expand All @@ -1081,63 +1121,87 @@ void BgpPeer::ProcessUpdate(const BgpProto::Update *msg) {
if (result) {
BGP_LOG_PEER(Message, this, SandeshLevel::SYS_WARN,
BGP_LOG_FLAG_ALL, BGP_PEER_DIR_IN,
"NLRI parse error for EVPN route type " << (*it)->type);
"NLRI parse error for e-vpn route type " << (*it)->type);
continue;
}

DBRequest req;
req.oper = oper;
if (oper == DBRequest::DB_ENTRY_ADD_CHANGE)
req.data.reset(new EvpnTable::RequestData(new_attr, flags, label));
if (oper == DBRequest::DB_ENTRY_ADD_CHANGE) {
req.data.reset(
new EvpnTable::RequestData(new_attr, flags, label));
}
req.key.reset(new EvpnTable::RequestKey(prefix, this));
table->Enqueue(&req);
}
break;
}

case Address::RTARGET: {
RTargetTable *table =
static_cast<RTargetTable *>(instance->GetTable(family));
case Address::ERMVPN: {
ErmVpnTable *table;
table = static_cast<ErmVpnTable *>(instance->GetTable(family));
assert(table);
if (oper == DBRequest::DB_ENTRY_DELETE && nlri->nlri.empty()) {
// End-Of-RIB message
end_of_rib_timer_->Cancel();
RegisterToVpnTables(true);
return;
}

vector<BgpProtoPrefix *>::const_iterator it;
for (it = nlri->nlri.begin(); it < nlri->nlri.end(); it++) {
for (it = nlri->nlri.begin(); it < nlri->nlri.end(); ++it) {
if (!ErmVpnPrefix::IsValidForBgp((*it)->type)) {
BGP_LOG_PEER(Message, this, SandeshLevel::SYS_WARN,
BGP_LOG_FLAG_ALL, BGP_PEER_DIR_IN,
"ERMVPN: Unsupported route type " << (*it)->type);
continue;
}

ErmVpnPrefix prefix;
int result = ErmVpnPrefix::FromProtoPrefix((**it), &prefix);
if (result) {
BGP_LOG_PEER(Message, this, SandeshLevel::SYS_WARN,
BGP_LOG_FLAG_ALL, BGP_PEER_DIR_IN,
"NLRI parse error for erm-vpn route type " << (*it)->type);
continue;
}

DBRequest req;
req.oper = oper;
if (oper == DBRequest::DB_ENTRY_ADD_CHANGE)
req.data.reset(new RTargetTable::RequestData(attr, flags, 0));
RTargetPrefix prefix = RTargetPrefix(**it);
req.key.reset(new RTargetTable::RequestKey(prefix, this));
if (oper == DBRequest::DB_ENTRY_ADD_CHANGE) {
req.data.reset(
new ErmVpnTable::RequestData(attr, flags, 0));
}
req.key.reset(new ErmVpnTable::RequestKey(prefix, this));
table->Enqueue(&req);
}
break;
}

case Address::ERMVPN: {
ErmVpnTable *table;
table = static_cast<ErmVpnTable *>(instance->GetTable(family));
case Address::RTARGET: {
RTargetTable *table =
static_cast<RTargetTable *>(instance->GetTable(family));
assert(table);

// Check for End-Of-RIB message.
if (oper == DBRequest::DB_ENTRY_DELETE && nlri->nlri.empty()) {
end_of_rib_timer_->Cancel();
RegisterToVpnTables(true);
return;
}

vector<BgpProtoPrefix *>::const_iterator it;
for (it = nlri->nlri.begin(); it < nlri->nlri.end(); it++) {
if (!ErmVpnPrefix::IsValidForBgp((*it)->type)) {
for (it = nlri->nlri.begin(); it < nlri->nlri.end(); ++it) {
RTargetPrefix prefix;
int result = RTargetPrefix::FromProtoPrefix((**it), &prefix);
if (result) {
BGP_LOG_PEER(Message, this, SandeshLevel::SYS_WARN,
BGP_LOG_FLAG_ALL, BGP_PEER_DIR_IN,
"ERMVPN: Unsupported route type " << (*it)->type);
"NLRI parse error for rtarget route");
continue;
}

DBRequest req;
req.oper = oper;
if (oper == DBRequest::DB_ENTRY_ADD_CHANGE)
req.data.reset(new ErmVpnTable::RequestData(attr, flags,
0));
req.key.reset(new ErmVpnTable::RequestKey(
ErmVpnPrefix(**it), this));
if (oper == DBRequest::DB_ENTRY_ADD_CHANGE) {
req.data.reset(
new RTargetTable::RequestData(attr, flags, 0));
}
req.key.reset(new RTargetTable::RequestKey(prefix, this));
table->Enqueue(&req);
}
break;
Expand Down
78 changes: 45 additions & 33 deletions src/bgp/ermvpn/ermvpn_route.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@
* Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
*/

#include "base/parse_object.h"
#include "bgp/ermvpn/ermvpn_route.h"

#include "base/parse_object.h"
#include "bgp/ermvpn/ermvpn_table.h"

using namespace std;
using std::copy;
using std::string;
using std::vector;

// BgpProtoPrefix format for erm-vpn prefix.
//
Expand Down Expand Up @@ -39,58 +42,67 @@ ErmVpnPrefix::ErmVpnPrefix(uint8_t type, const RouteDistinguisher &rd,
group_(group), source_(source) {
}

ErmVpnPrefix::ErmVpnPrefix(const BgpProtoPrefix &prefix) {
assert(IsValidForBgp(prefix.type));

int ErmVpnPrefix::FromProtoPrefix(const BgpProtoPrefix &proto_prefix,
ErmVpnPrefix *prefix) {
size_t rd_size = RouteDistinguisher::kSize;
size_t rtid_size = 4;
size_t rtid_size = Address::kMaxV4Bytes;
size_t nlri_size = proto_prefix.prefix.size();
size_t expected_nlri_size =
rd_size + rtid_size + 2 * (Address::kMaxV4Bytes + 1);

type_ = prefix.type;
if (!IsValidForBgp(proto_prefix.type))
return -1;
if (nlri_size != expected_nlri_size)
return -1;

prefix->type_ = proto_prefix.type;
size_t rd_offset = 0;
rd_ = RouteDistinguisher(&prefix.prefix[rd_offset]);

prefix->rd_ = RouteDistinguisher(&proto_prefix.prefix[rd_offset]);
size_t rtid_offset = rd_offset + rd_size;
router_id_ = Ip4Address(get_value(&prefix.prefix[rtid_offset], rtid_size));

prefix->router_id_ =
Ip4Address(get_value(&proto_prefix.prefix[rtid_offset], rtid_size));
size_t source_offset = rtid_offset + rtid_size + 1;
source_ = Ip4Address(get_value(&prefix.prefix[source_offset], 4));
prefix->source_ = Ip4Address(
get_value(&proto_prefix.prefix[source_offset], Address::kMaxV4Bytes));
size_t group_offset = source_offset + Address::kMaxV4Bytes + 1;
prefix->group_ = Ip4Address(
get_value(&proto_prefix.prefix[group_offset], Address::kMaxV4Bytes));

size_t group_offset = source_offset + 4 + 1;
group_ = Ip4Address(get_value(&prefix.prefix[group_offset], 4));
return 0;
}

void ErmVpnPrefix::BuildProtoPrefix(BgpProtoPrefix *prefix) const {
void ErmVpnPrefix::BuildProtoPrefix(BgpProtoPrefix *proto_prefix) const {
assert(IsValidForBgp(type_));

size_t rd_size = RouteDistinguisher::kSize;
size_t rtid_size = 4;
size_t rtid_size = Address::kMaxV4Bytes;

prefix->prefixlen = (rd_size + rtid_size + 1 + 4 + 1 + 4) * 8;
prefix->prefix.clear();
prefix->type = type_;
prefix->prefix.resize(prefix->prefixlen/8, 0);
proto_prefix->type = type_;
proto_prefix->prefix.clear();
proto_prefix->prefixlen =
(rd_size + rtid_size + 2 * (1 + Address::kMaxV4Bytes)) * 8;
proto_prefix->prefix.resize(proto_prefix->prefixlen / 8, 0);

size_t rd_offset = 0;
std::copy(rd_.GetData(), rd_.GetData() + rd_size,
prefix->prefix.begin() + rd_offset);
copy(rd_.GetData(), rd_.GetData() + rd_size,
proto_prefix->prefix.begin() + rd_offset);

size_t rtid_offset = rd_offset + rd_size;
const Ip4Address::bytes_type &rtid_bytes = router_id_.to_bytes();
std::copy(rtid_bytes.begin(), rtid_bytes.begin() + 4,
prefix->prefix.begin() + rtid_offset);
copy(rtid_bytes.begin(), rtid_bytes.begin() + Address::kMaxV4Bytes,
proto_prefix->prefix.begin() + rtid_offset);

size_t source_offset = rtid_offset + rtid_size + 1;
prefix->prefix[source_offset - 1] = 32;
proto_prefix->prefix[source_offset - 1] = Address::kMaxV4PrefixLen;
const Ip4Address::bytes_type &source_bytes = source_.to_bytes();
std::copy(source_bytes.begin(), source_bytes.begin() + 4,
prefix->prefix.begin() + source_offset);
copy(source_bytes.begin(), source_bytes.begin() + Address::kMaxV4Bytes,
proto_prefix->prefix.begin() + source_offset);

size_t group_offset = source_offset + 4 + 1;
prefix->prefix[group_offset - 1] = 32;
size_t group_offset = source_offset + Address::kMaxV4Bytes + 1;
proto_prefix->prefix[group_offset - 1] = Address::kMaxV4PrefixLen;
const Ip4Address::bytes_type &group_bytes = group_.to_bytes();
std::copy(group_bytes.begin(), group_bytes.begin() + 4,
prefix->prefix.begin() + group_offset);
copy(group_bytes.begin(), group_bytes.begin() + Address::kMaxV4Bytes,
proto_prefix->prefix.begin() + group_offset);
}

ErmVpnPrefix ErmVpnPrefix::FromString(const string &str,
Expand Down Expand Up @@ -273,10 +285,10 @@ void ErmVpnRoute::BuildProtoPrefix(BgpProtoPrefix *prefix,
}

void ErmVpnRoute::BuildBgpProtoNextHop(
std::vector<uint8_t> &nh, IpAddress nexthop) const {
vector<uint8_t> &nh, IpAddress nexthop) const {
nh.resize(4);
const Ip4Address::bytes_type &addr_bytes = nexthop.to_v4().to_bytes();
std::copy(addr_bytes.begin(), addr_bytes.end(), nh.begin());
copy(addr_bytes.begin(), addr_bytes.end(), nh.begin());
}

DBEntryBase::KeyPtr ErmVpnRoute::GetDBRequestKey() const {
Expand Down
5 changes: 4 additions & 1 deletion src/bgp/ermvpn/ermvpn_route.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,17 @@ class ErmVpnPrefix {
};

ErmVpnPrefix();
explicit ErmVpnPrefix(const BgpProtoPrefix &prefix);
ErmVpnPrefix(uint8_t type, const RouteDistinguisher &rd,
const Ip4Address &group, const Ip4Address &source);
ErmVpnPrefix(uint8_t type, const RouteDistinguisher &rd,
const Ip4Address &router_id,
const Ip4Address &group, const Ip4Address &source);

static int FromProtoPrefix(const BgpProtoPrefix &proto_prefix,
ErmVpnPrefix *prefix);
static ErmVpnPrefix FromString(const std::string &str,
boost::system::error_code *errorp = NULL);

std::string ToString() const;
std::string ToXmppIdString() const;
static bool IsValidForBgp(uint8_t type);
Expand Down

0 comments on commit 2972c61

Please sign in to comment.