update RFC1966 (BGP route reflection) support.

From: Greg Hankins <gregh@twoguys.org>

svn path=/trunk/; revision=1759
This commit is contained in:
Jun-ichiro itojun Hagino 2000-03-29 06:27:54 +00:00
parent c317b042a8
commit 01d2363d0e
1 changed files with 174 additions and 110 deletions

View File

@ -6,11 +6,11 @@
*
* Supports:
* RFC1771 A Border Gateway Protocol 4 (BGP-4)
* RFC1966 BGP Route Reflection An alternative to full mesh IBGP
* RFC1997 BGP Communities Attribute
* RFC2283 Multiprotocol Extensions for BGP-4
*
* TODO:
* RFC1966 BGP Route Reflection An alternative to full mesh IBGP
* RFC1863 A BGP/IDRP Route Server alternative to a full mesh routing
* RFC1965 Autonomous System Confederations for BGP
* Destination Preference Attribute for BGP (work in progress)
@ -198,6 +198,7 @@ static gint ett_bgp_update = -1;
static gint ett_bgp_notification = -1;
static gint ett_bgp_as_paths = -1;
static gint ett_bgp_communities = -1;
static gint ett_bgp_cluster_list = -1;
/*
* Decode an IPv4 prefix.
@ -298,28 +299,30 @@ dissect_bgp_open(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
static void
dissect_bgp_update(const u_char *pd, int offset, frame_data *fd,
proto_tree *tree)
{
struct bgp bgp; /* BGP header */
struct bgp_attr bgpa; /* path attributes */
int hlen; /* message length */
const u_char *p; /* packet offset pointer */
const u_char *q; /* tmp */
const u_char *end; /* message end */
int len; /* tmp */
proto_item *ti; /* tree item */
proto_tree *subtree; /* subtree for attibutes */
proto_tree *subtree2; /* subtree for attibutes */
proto_tree *subtree3; /* subtree for attibutes */
proto_tree *as_paths_tree; /* subtree for AS_PATHs */
proto_tree *as_path_tree; /* subtree for AS_PATH */
proto_tree *communities_tree; /* subtree for COMMUNITIES */
proto_tree *community_tree; /* subtree for a community */
int i, j; /* tmp */
guint8 length; /* AS_PATH length */
guint8 type; /* AS_PATH type */
char *as_path_str = NULL; /* AS_PATH string */
char *communities_str = NULL; /* COMMUNITIES string */
char junk_buf[256]; /* tmp */
{
struct bgp bgp; /* BGP header */
struct bgp_attr bgpa; /* path attributes */
int hlen; /* message length */
const u_char *p; /* packet offset pointer */
const u_char *q; /* tmp */
const u_char *end; /* message end */
int len; /* tmp */
proto_item *ti; /* tree item */
proto_tree *subtree; /* subtree for attibutes */
proto_tree *subtree2; /* subtree for attibutes */
proto_tree *subtree3; /* subtree for attibutes */
proto_tree *as_paths_tree; /* subtree for AS_PATHs */
proto_tree *as_path_tree; /* subtree for AS_PATH */
proto_tree *communities_tree; /* subtree for COMMUNITIES */
proto_tree *community_tree; /* subtree for a community */
proto_tree *cluster_list_tree; /* subtree for CLUSTER_LIST */
int i, j; /* tmp */
guint8 length; /* AS_PATH length */
guint8 type; /* AS_PATH type */
char *as_path_str = NULL; /* AS_PATH string */
char *communities_str = NULL; /* COMMUNITIES string */
char *cluster_list_str = NULL; /* CLUSTER_LIST string */
char junk_buf[256]; /* tmp */
/* snarf UPDATE message */
@ -459,7 +462,7 @@ dissect_bgp_update(const u_char *pd, int offset, frame_data *fd,
ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
"%s: %u (%u %s)",
val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
pntohl(&p[i + aoff]), alen + aoff,
pntohl(&p[i + aoff]), alen + aoff,
(alen + aoff == 1) ? "byte" : "bytes");
break;
case BGPTYPE_LOCAL_PREF:
@ -493,45 +496,45 @@ dissect_bgp_update(const u_char *pd, int offset, frame_data *fd,
if (alen % 4 != 0)
goto default_attribute_top;
/* (p + i + 3) =
(p + current attribute + 3 bytes to first tuple) */
end = p + alen + i + 3;
q = p + i + 3;
/* must be freed by second switch! */
/* "alen * 12" (5 digits, a :, 5 digits + space ) should be
a good estimate of how long the communities string could
be */
communities_str = malloc((alen + 1) * 12);
if (communities_str == NULL) break;
communities_str[0] = '\0';
memset(junk_buf, 0, sizeof(junk_buf));
/* (p + i + 3) =
(p + current attribute + 3 bytes to first tuple) */
end = p + alen + i + 3;
q = p + i + 3;
/* must be freed by second switch! */
/* "alen * 12" (5 digits, a :, 5 digits + space ) should be
a good estimate of how long the communities string could
be */
communities_str = malloc((alen + 1) * 12);
if (communities_str == NULL) break;
communities_str[0] = '\0';
memset(junk_buf, 0, sizeof(junk_buf));
/* snarf each community */
while (q < end) {
/* check for well-known communities */
/* snarf each community */
while (q < end) {
/* check for well-known communities */
if (pntohl(q) == BGP_COMM_NO_EXPORT)
strncpy(junk_buf, "NO_EXPORT ", 10);
strncpy(junk_buf, "NO_EXPORT ", 10);
else if (pntohl(q) == BGP_COMM_NO_ADVERTISE)
strncpy(junk_buf, "NO_ADVERTISE ", 13);
strncpy(junk_buf, "NO_ADVERTISE ", 13);
else if (pntohl(q) == BGP_COMM_NO_EXPORT_SUBCONFED)
strncpy(junk_buf, "NO_EXPORT_SUBCONFED ", 20);
else {
snprintf(junk_buf, sizeof(junk_buf), "%u:%u ",
pntohs(q),
pntohs(q + 2));
}
q += 4;
strncat(communities_str, junk_buf, sizeof(junk_buf));
}
/* cleanup end of string */
communities_str[strlen(communities_str) - 1] = '\0';
strncpy(junk_buf, "NO_EXPORT_SUBCONFED ", 20);
else {
snprintf(junk_buf, sizeof(junk_buf), "%u:%u ",
pntohs(q),
pntohs(q + 2));
}
q += 4;
strncat(communities_str, junk_buf, sizeof(junk_buf));
}
/* cleanup end of string */
communities_str[strlen(communities_str) - 1] = '\0';
ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
"%s: %s (%u %s)",
val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
communities_str, alen + aoff,
(alen + aoff == 1) ? "byte" : "bytes");
communities_str, alen + aoff,
(alen + aoff == 1) ? "byte" : "bytes");
break;
case BGPTYPE_ORIGINATOR_ID:
if (alen != 4)
@ -540,16 +543,47 @@ dissect_bgp_update(const u_char *pd, int offset, frame_data *fd,
"%s: %s (%u %s)",
val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
ip_to_str(&p[i + aoff]), alen + aoff, (alen + aoff == 1)
? "byte" : "bytes");
? "byte" : "bytes");
break;
case BGPTYPE_CLUSTER_LIST:
if (alen % 4 != 0)
goto default_attribute_top;
/* (p + i + 3) =
(p + current attribute + 3 bytes to first tuple) */
end = p + alen + i + 3;
q = p + i + 3;
/* must be freed by second switch! */
/* "alen * 16" (12 digits, 3 dots + space ) should be
a good estimate of how long the cluster_list string could
be */
cluster_list_str = malloc((alen + 1) * 16);
if (cluster_list_str == NULL) break;
cluster_list_str[0] = '\0';
memset(junk_buf, 0, sizeof(junk_buf));
/* snarf each cluster list */
while (q < end) {
snprintf(junk_buf, sizeof(junk_buf), "%s ", ip_to_str(q));
strncat(cluster_list_str, junk_buf, sizeof(junk_buf));
q += 4;
}
/* cleanup end of string */
cluster_list_str[strlen(cluster_list_str) - 1] = '\0';
ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
"%s: %s (%u %s)",
val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
cluster_list_str, alen + aoff,
(alen + aoff == 1) ? "byte" : "bytes");
break;
default:
default_attribute_top:
ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
"%s (%u %s)",
val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
alen + aoff, (alen + aoff == 1) ? "byte" : "bytes");
}
} /* end of first switch */
subtree2 = proto_item_add_subtree(ti, ett_bgp_attr);
/* figure out flags */
@ -705,11 +739,11 @@ dissect_bgp_update(const u_char *pd, int offset, frame_data *fd,
case BGPTYPE_MULTI_EXIT_DISC:
if (alen != 4) {
proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
"Multi exit discriminator (invalid): %u %s",
"Multiple exit discriminator (invalid): %u %s",
alen, (alen == 1) ? "byte" : "bytes");
} else {
proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
"Multi exit discriminator: %u",
"Multiple exit discriminator: %u",
pntohl(&p[i + aoff]));
}
break;
@ -720,8 +754,7 @@ dissect_bgp_update(const u_char *pd, int offset, frame_data *fd,
(alen == 1) ? "byte" : "bytes");
} else {
proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
"Local preference: %u",
pntohl(&p[i + aoff]));
"Local preference: %u", pntohl(&p[i + aoff]));
}
break;
case BGPTYPE_ATOMIC_AGGREGATE:
@ -738,8 +771,7 @@ dissect_bgp_update(const u_char *pd, int offset, frame_data *fd,
(alen == 1) ? "byte" : "bytes");
} else {
proto_tree_add_text(subtree2, p - pd + i + aoff, 2,
"Aggregator AS: %u",
pntohs(&p[i + aoff]));
"Aggregator AS: %u", pntohs(&p[i + aoff]));
proto_tree_add_text(subtree2, p - pd + i + aoff + 2, 4,
"Aggregator origin: %s",
ip_to_str(&p[i + aoff + 2]));
@ -750,58 +782,60 @@ dissect_bgp_update(const u_char *pd, int offset, frame_data *fd,
proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
"Communities (invalid): %u %s", alen,
(alen == 1) ? "byte" : "bytes");
free(communities_str);
break;
}
ti = proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
"Communities: %s", communities_str);
communities_tree = proto_item_add_subtree(ti,
ett_bgp_communities);
ti = proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
"Communities: %s", communities_str);
communities_tree = proto_item_add_subtree(ti,
ett_bgp_communities);
/* (p + i + 3) =
(p + current attribute + 3 bytes to first tuple) */
end = p + alen + i + 3;
q = p + i + 3;
/* (p + i + 3) =
(p + current attribute + 3 bytes to first tuple) */
end = p + alen + i + 3;
q = p + i + 3;
/* snarf each community */
while (q < end) {
/* check for reserved values */
/* snarf each community */
while (q < end) {
/* check for reserved values */
if (pntohs(q) == FOURHEX0 || pntohs(q) == FOURHEXF) {
/* check for well-known communities */
if (pntohl(q) == BGP_COMM_NO_EXPORT)
proto_tree_add_text(communities_tree,
q - pd - 3 + aoff, 4,
"Community: NO_EXPORT (0x%x)", pntohl(q));
else if (pntohl(q) == BGP_COMM_NO_ADVERTISE)
proto_tree_add_text(communities_tree,
q - pd - 3 + aoff, 4,
"Community: NO_ADVERTISE (0x%x)", pntohl(q));
else if (pntohl(q) == BGP_COMM_NO_EXPORT_SUBCONFED)
proto_tree_add_text(communities_tree,
q - pd - 3 + aoff, 4,
"Community: NO_EXPORT_SUBCONFED (0x%x)",
pntohl(q));
else
proto_tree_add_text(communities_tree,
q - pd - 3 + aoff, 4,
"Community (reserved): 0x%x", pntohl(q));
}
else {
/* check for well-known communities */
if (pntohl(q) == BGP_COMM_NO_EXPORT)
proto_tree_add_text(communities_tree,
q - pd - 3 + aoff, 4,
"Community: NO_EXPORT (0x%x)", pntohl(q));
else if (pntohl(q) == BGP_COMM_NO_ADVERTISE)
proto_tree_add_text(communities_tree,
q - pd - 3 + aoff, 4,
"Community: NO_ADVERTISE (0x%x)", pntohl(q));
else if (pntohl(q) == BGP_COMM_NO_EXPORT_SUBCONFED)
proto_tree_add_text(communities_tree,
q - pd - 3 + aoff, 4,
"Community: NO_EXPORT_SUBCONFED (0x%x)",
pntohl(q));
else
proto_tree_add_text(communities_tree,
q - pd - 3 + aoff, 4,
"Community (reserved): 0x%x", pntohl(q));
}
else {
ti = proto_tree_add_text(communities_tree,
q - pd - 3 + aoff, 4, "Community: %u:%u",
pntohs(q), pntohs(q + 2));
community_tree = proto_item_add_subtree(ti,
ett_bgp_communities);
proto_tree_add_text(community_tree, q - pd - 3 + aoff,
2, "Community AS: %u", pntohs(q));
proto_tree_add_text(community_tree, q - pd - 1 + aoff,
2, "Community value: %u", pntohs(q + 2));
}
ti = proto_tree_add_text(communities_tree,
q - pd - 3 + aoff, 4, "Community: %u:%u",
pntohs(q), pntohs(q + 2));
community_tree = proto_item_add_subtree(ti,
ett_bgp_communities);
proto_tree_add_text(community_tree, q - pd - 3 + aoff,
2, "Community AS: %u", pntohs(q));
proto_tree_add_text(community_tree, q - pd - 1 + aoff,
2, "Community value: %u", pntohs(q + 2));
}
q += 4;
}
q += 4;
}
free(communities_str);
free(communities_str);
break;
case BGPTYPE_ORIGINATOR_ID:
if (alen != 4) {
@ -910,7 +944,7 @@ dissect_bgp_update(const u_char *pd, int offset, frame_data *fd,
break;
case BGPTYPE_MP_UNREACH_NLRI:
af = pntohs(&p[i + aoff]);
af = pntohs(&p[i + aoff]);
proto_tree_add_text(subtree2, p - pd + i + aoff, 2,
"Address family: %s (%u)",
val_to_str(af, afnumber, "Unknown"), af);
@ -952,12 +986,41 @@ dissect_bgp_update(const u_char *pd, int offset, frame_data *fd,
break;
case BGPTYPE_CLUSTER_LIST:
if (alen % 4 != 0) {
proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
"Cluster list (invalid): %u %s", alen,
(alen == 1) ? "byte" : "bytes");
free(cluster_list_str);
break;
}
ti = proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
"Cluster list: %s", cluster_list_str);
cluster_list_tree = proto_item_add_subtree(ti,
ett_bgp_cluster_list);
/* (p + i + 3) =
(p + current attribute + 3 bytes to first tuple) */
end = p + alen + i + 3;
q = p + i + 3;
/* snarf each cluster identifier */
while (q < end) {
ti = proto_tree_add_text(cluster_list_tree,
q - pd - 3 + aoff, 4, "Cluster identifier: %s",
ip_to_str(q));
q += 4;
}
free(cluster_list_str);
break;
default:
proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
"Unknown (%d %s)", alen, (alen == 1) ? "byte" :
"bytes");
break;
}
} /* end of second switch */
i += alen + aoff;
}
@ -1134,7 +1197,7 @@ dissect_bgp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
}
proto_tree_add_text(bgp1_tree, offset + i, BGP_MARKER_SIZE,
"Marker");
"Marker: 16 bytes");
if (hlen < BGP_HEADER_SIZE || hlen > BGP_MAX_PACKET_SIZE) {
proto_tree_add_text(bgp1_tree,
@ -1197,6 +1260,7 @@ proto_register_bgp(void)
&ett_bgp_notification,
&ett_bgp_as_paths,
&ett_bgp_communities,
&ett_bgp_cluster_list,
};
proto_bgp = proto_register_protocol("Border Gateway Protocol", "bgp");