BGP add-path (Additional Paths) support for IPv4 unicast

From me:
Fix some whitespace/tab...

svn path=/trunk/; revision=38724
This commit is contained in:
Alexis La Goutte 2011-08-24 21:58:14 +00:00
parent 11f1f1a019
commit 154b424ed3
1 changed files with 189 additions and 15 deletions

View File

@ -37,6 +37,7 @@
* draft-ietf-idr-bgp-ext-communities-05
* draft-knoll-idr-qos-attribute-03
* draft-nalawade-kapoor-tunnel-safi-05
* draft-ietf-idr-add-paths-04 Additional-Path for BGP-4
*
* TODO:
* Destination Preference Attribute for BGP (work in progress)
@ -316,6 +317,7 @@ static const value_string capability_vals[] = {
{ BGP_CAPABILITY_GRACEFUL_RESTART, "Graceful Restart capability" },
{ BGP_CAPABILITY_4_OCTET_AS_NUMBER, "Support for 4-octet AS number capability" },
{ BGP_CAPABILITY_DYNAMIC_CAPABILITY, "Support for Dynamic capability" },
{ BGP_CAPABILITY_ADDITIONAL_PATHS, "Support for Additional Paths" },
{ BGP_CAPABILITY_ROUTE_REFRESH_CISCO, "Route refresh capability" },
{ BGP_CAPABILITY_ORF_CISCO, "Cooperative route filtering capability" },
{ 0, NULL }
@ -361,6 +363,7 @@ static int hf_bgp_mp_unreach_nlri_ipv4_prefix = -1;
static int hf_bgp_mp_nlri_tnl_id = -1;
static int hf_bgp_withdrawn_prefix = -1;
static int hf_bgp_nlri_prefix = -1;
static int hf_bgp_nlri_path_id = -1;
static gint ett_bgp = -1;
static gint ett_bgp_prefix = -1;
@ -396,6 +399,108 @@ static gboolean bgp_desegment = TRUE;
static gint bgp_asn_len = 0;
/*
* Detect IPv4 prefixes conform to BGP Additional Path but NOT conform to standard BGP
*
* A real BGP speaker would rely on the BGP Additional Path in the BGP Open messages.
* But it is not suitable for a packet analyse because the BGP sessions are not supposed to
* restart very often, and Open messages from both sides of the session would be needed
* to determine the result of the capability negociation.
* Code inspired from the decode_prefix4 function
*/
static int
detect_add_path_prefix4(tvbuff_t *tvb, gint offset, gint end) {
guint32 addr_len;
guint8 prefix_len;
gint o;
/* Must be compatible with BGP Additional Path */
for (o = offset + 4; o < end; o += 4) {
prefix_len = tvb_get_guint8(tvb, o);
if( prefix_len > 32) {
return 0; /* invalid prefix lenght - not BGP add-path */
}
addr_len = (prefix_len + 7) / 8;
o += 1 + addr_len;
if( o > end ) {
return 0; /* invalid offset - not BGP add-path */
}
if (prefix_len % 8) {
/* detect bits set after the end of the prefix */
if( tvb_get_guint8(tvb, o - 1 ) & (0xFF >> (prefix_len % 8)) ) {
return 0; /* invalid prefix content - not BGP add-path */
}
}
}
/* Must NOT be compatible with standard BGP */
for (o = offset; o < end; ) {
prefix_len = tvb_get_guint8(tvb, o);
if( prefix_len > 32) {
return 1; /* invalid prefix lenght - may be BGP add-path */
}
addr_len = (prefix_len + 7) / 8;
o += 1 + addr_len;
if( o > end ) {
return 1; /* invalid offset - may be BGP add-path */
}
if (prefix_len % 8) {
/* detect bits set after the end of the prefix */
if( tvb_get_guint8(tvb, o - 1 ) & (0xFF >> (prefix_len % 8)) ) {
return 1; /* invalid prefix content - may be BGP add-path (or a bug) */
}
}
}
return 0; /* valid - do not assume Additional Path */
}
/*
* Decode an IPv4 prefix with Path Identifier
* Code inspired from the decode_prefix4 function
*/
static int
decode_path_prefix4(proto_tree *tree, int hf_path_id, int hf_addr, tvbuff_t *tvb, gint offset,
const char *tag)
{
proto_item *ti;
proto_tree *prefix_tree;
union {
guint8 addr_bytes[4];
guint32 addr;
} ip_addr; /* IP address */
guint8 plen; /* prefix length */
int length; /* number of octets needed for prefix */
guint32 path_identifier;
/* snarf path identifier length and prefix */
path_identifier = tvb_get_ntohl(tvb, offset);
plen = tvb_get_guint8(tvb, offset + 4);
length = ipv4_addr_and_mask(tvb, offset + 4 + 1, ip_addr.addr_bytes, plen);
if (length < 0) {
proto_tree_add_text(tree, tvb, offset + 4 , 1, "%s length %u invalid (> 32)",
tag, plen);
return -1;
}
/* put prefix into protocol tree */
ti = proto_tree_add_text(tree, tvb, offset,
4 + 1 + length, "%s/%u PathId %u ",
ip_to_str(ip_addr.addr_bytes), plen, path_identifier);
prefix_tree = proto_item_add_subtree(ti, ett_bgp_prefix);
if (hf_path_id != -1) {
proto_tree_add_uint(prefix_tree, hf_path_id, tvb, offset, 4,
path_identifier);
} else {
proto_tree_add_text(prefix_tree, tvb, offset, 4,
"%s Path Id: %u", tag, path_identifier);
}
proto_tree_add_text(prefix_tree, tvb, offset + 4, 1, "%s prefix length: %u",
tag, plen);
if (hf_addr != -1) {
proto_tree_add_ipv4(prefix_tree, hf_addr, tvb, offset + 4 + 1, length,
ip_addr.addr);
} else {
proto_tree_add_text(prefix_tree, tvb, offset + 4 + 1, length,
"%s prefix: %s", tag, ip_to_str(ip_addr.addr_bytes));
}
return(4 + 1 + length);
}
/*
* Decode an IPv4 prefix.
*/
@ -1377,6 +1482,48 @@ dissect_bgp_capability_item(tvbuff_t *tvb, int *p, proto_tree *tree, int ctype,
}
}
break;
case BGP_CAPABILITY_ADDITIONAL_PATHS:
proto_tree_add_text(tree, tvb, *p - 2, 1,
"Capability code: %s (%d)", val_to_str(ctype,
capability_vals, "Unknown capability"), ctype);
if (clen != 4) {
proto_tree_add_text(tree, tvb, *p,
clen, "Capability value: Invalid");
proto_tree_add_text(tree, tvb, *p,
clen, "Capability value: Unknown");
}
else { /* AFI SAFI Send-receive*/
proto_tree_add_text(tree, tvb, *p - 1,
1, "Capability length: %u byte%s", clen,
plurality(clen, "", "s"));
ti = proto_tree_add_text(tree, tvb, *p, clen, "Capability value");
subtree = proto_item_add_subtree(ti, ett_bgp_option);
/* AFI */
i = tvb_get_ntohs(tvb, *p);
proto_tree_add_text(subtree, tvb, *p,
2, "Address family identifier: %s (%u)",
val_to_str(i, afn_vals, "Unknown"), i);
*p += 2;
/* SAFI */
i = tvb_get_guint8(tvb, *p);
proto_tree_add_text(subtree, tvb, *p,
1, "Subsequent address family identifier: %s (%u)",
val_to_str(i, bgpattr_nlri_safi,
i >= 128 ? "Vendor specific" : "Unknown"), i);
(*p)++;
/* Send-Receive */
i = tvb_get_guint8(tvb, *p);
proto_tree_add_text(subtree, tvb, *p, 1,
"Flags: 0x%02x (%sSend,%sReceive)", i,
((i&BGP_ADDPATH_SEND)? "":"Dont"),
((i&BGP_ADDPATH_RECEIVE)? "":"Dont"));
/* Note: flags may be provided as a bitfield subtree */
(*p)++;
}
*p += clen;
break;
case BGP_CAPABILITY_ROUTE_REFRESH_CISCO:
case BGP_CAPABILITY_ROUTE_REFRESH:
proto_tree_add_text(tree, tvb, *p - 2, 1,
@ -1630,17 +1777,28 @@ dissect_bgp_update(tvbuff_t *tvb, proto_tree *tree)
if (len > 0) {
ti = proto_tree_add_text(tree, tvb, o, len, "Withdrawn routes:");
subtree = proto_item_add_subtree(ti, ett_bgp_unfeas);
/* parse each prefix */
end = o + len;
while (o < end) {
i = decode_prefix4(subtree, hf_bgp_withdrawn_prefix, tvb, o, len,
"Withdrawn route");
if (i < 0)
return;
o += i;
end = o + len;
/* Heuristic to detect if IPv4 prefix are using Path Identifiers */
if( detect_add_path_prefix4(tvb, o, end) ) {
/* IPv4 prefixes with Path Id */
while (o < end) {
i = decode_path_prefix4(subtree, hf_bgp_nlri_path_id, hf_bgp_withdrawn_prefix, tvb, o,
"Withdrawn route");
if (i < 0)
return;
o += i;
}
} else {
while (o < end) {
i = decode_prefix4(subtree, hf_bgp_withdrawn_prefix, tvb, o, len,
"Withdrawn route");
if (i < 0)
return;
o += i;
}
}
}
}
/* check for advertisements */
len = tvb_get_ntohs(tvb, o);
@ -2655,12 +2813,25 @@ dissect_bgp_update(tvbuff_t *tvb, proto_tree *tree)
plurality(len, "", "s"));
subtree = proto_item_add_subtree(ti, ett_bgp_nlri);
end = o + len;
while (o < end) {
i = decode_prefix4(subtree, hf_bgp_nlri_prefix, tvb, o, 0,
"NLRI");
if (i < 0)
return;
o += i;
/* Heuristic to detect if IPv4 prefix are using Path Identifiers */
if( detect_add_path_prefix4(tvb, o, end) ) {
/* IPv4 prefixes with Path Id */
while (o < end) {
i = decode_path_prefix4(subtree, hf_bgp_nlri_path_id, hf_bgp_nlri_prefix, tvb, o,
"NLRI");
if (i < 0)
return;
o += i;
}
} else {
/* Standard prefixes */
while (o < end) {
i = decode_prefix4(subtree, hf_bgp_nlri_prefix, tvb, o, 0,
"NLRI");
if (i < 0)
return;
o += i;
}
}
}
}
@ -3212,6 +3383,9 @@ proto_register_bgp(void)
{ &hf_bgp_nlri_prefix,
{ "NLRI prefix", "bgp.nlri_prefix", FT_IPv4, BASE_NONE,
NULL, 0x0, NULL, HFILL}},
{ &hf_bgp_nlri_path_id,
{ "NLRI path id", "bgp.nlri_path_id", FT_UINT32, BASE_DEC,
NULL, 0x0, NULL, HFILL}},
{ &hf_bgp_origin,
{ "Origin", "bgp.origin", FT_UINT8, BASE_DEC,
VALS(bgpattr_origin), 0x0, NULL, HFILL}},