Commit b6bf284a authored by Ondřej Zajíček's avatar Ondřej Zajíček

Bugfixes in MULIT_EXIT_DISC attribute handling.

 - Old MED handling was completely different from behavior
   specified in RFCs - for example they havn't been propagated
   to neighboring areas.

 - Update tie-breaking according to RFC 4271.

 - Change default value for 'default bgp_med' configuration
   option according to RFC 4271.
parent 4819c3e1
......@@ -784,7 +784,7 @@ for each neighbor using the following configuration parameters:
<tag>default bgp_med <m/number/</tag> Value of the Multiple Exit
Discriminator to be used during route selection when the MED attribute
is missing. Default: infinite.
is missing. Default: 0.
<tag>default bgp_local_pref <m/number/</tag> Value of the Local Preference
to be used during route selection when the Local Preference attribute
......@@ -806,10 +806,16 @@ with `<tt/O/') are optional.
selection among multiple BGP routes (see the selection rules above). It's
used as an additional metric which is propagated through the whole local AS.
<tag>int <cf/bgp_med/ [IO]</tag> The Multiple Exit Discriminator of the route
is an optional attribute which is often used within the local AS to
reflect interior distances to various boundary routers. See the route selection
rules above for exact semantics.
<tag>int <cf/bgp_med/ [O]</tag> The Multiple Exit Discriminator of the route
is an optional attribute which is used on on external (inter-AS) links to
convey to an adjacent AS the optimal entry point into the local AS.
The received attribute may be also propagated over internal BGP links
(and this is default behavior). The attribute value is zeroed when a route
is exported from a routing table to a BGP instance to ensure that the attribute
received from a neighboring AS is not propagated to other neighboring ASes.
A new value might be set in the export filter of a BGP instance.
See RFC 4451<htmlurl url="ftp://ftp.rfc-editor.org/in-notes/rfc4451.txt">
for further discussion of BGP MED attribute.
<tag>enum <cf/bgp_origin/</tag> Origin of the route: either <cf/ORIGIN_IGP/
if the route has originated in an interior routing protocol or
......
......@@ -243,6 +243,20 @@ as_path_get_first(struct adata *path, u32 *orig_as)
return found;
}
int
as_path_get_last(struct adata *path, u32 *last_as)
{
u8 *p = path->data;
if ((path->length == 0) || (p[0] != AS_PATH_SEQUENCE) || (p[1] == 0))
return 0;
else
{
*last_as = get_as(p+2);
return 1;
}
}
int
as_path_is_member(struct adata *path, u32 as)
{
......
......@@ -27,6 +27,7 @@ int as_path_convert_to_new(struct adata *path, byte *dst, int req_as);
void as_path_format(struct adata *path, byte *buf, unsigned int size);
int as_path_getlen(struct adata *path);
int as_path_get_first(struct adata *path, u32 *orig_as);
int as_path_get_last(struct adata *path, u32 *last_as);
int as_path_is_member(struct adata *path, u32 as);
......
......@@ -146,7 +146,7 @@ static struct attr_desc bgp_attr_table[] = {
bgp_check_as_path, NULL },
{ "next_hop", 4, BAF_TRANSITIVE, EAF_TYPE_IP_ADDRESS, 1, /* BA_NEXT_HOP */
bgp_check_next_hop, NULL },
{ "med", 4, BAF_OPTIONAL, EAF_TYPE_INT, 0, /* BA_MULTI_EXIT_DISC */
{ "med", 4, BAF_OPTIONAL, EAF_TYPE_INT, 1, /* BA_MULTI_EXIT_DISC */
NULL, NULL },
{ "local_pref", 4, BAF_TRANSITIVE, EAF_TYPE_INT, 0, /* BA_LOCAL_PREF */
NULL, NULL },
......@@ -829,7 +829,17 @@ bgp_update_attrs(struct bgp_proto *p, rte *e, ea_list **attrs, struct linpool *p
eattr *a;
if (!p->is_internal)
bgp_path_prepend(e, attrs, pool, p->local_as);
{
bgp_path_prepend(e, attrs, pool, p->local_as);
/* The MULTI_EXIT_DISC attribute received from a neighboring AS MUST NOT be
* propagated to other neighboring ASes.
* Perhaps it would be better to undefine it.
*/
a = ea_find(e->attrs->eattrs, EA_CODE(EAP_BGP, BA_MULTI_EXIT_DISC));
if (a)
bgp_attach_attr(attrs, pool, BA_MULTI_EXIT_DISC, 0);
}
a = ea_find(e->attrs->eattrs, EA_CODE(EAP_BGP, BA_NEXT_HOP));
if (a && (p->is_internal || (!p->is_internal && e->attrs->iface == p->neigh->iface)))
......@@ -894,6 +904,18 @@ bgp_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool *
return bgp_create_attrs(p, e, attrs, pool);
}
static inline u32
bgp_get_neighbor(rte *r)
{
eattr *e = ea_find(r->attrs->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH));
u32 as;
if (e && as_path_get_last(e->u.ptr, &as))
return as;
else
return ((struct bgp_proto *) r->attrs->proto)->remote_as;
}
int
bgp_rte_better(rte *new, rte *old)
{
......@@ -936,14 +958,18 @@ bgp_rte_better(rte *new, rte *old)
return 0;
/* RFC 4271 9.1.2.2. c) Compare MED's */
x = ea_find(new->attrs->eattrs, EA_CODE(EAP_BGP, BA_MULTI_EXIT_DISC));
y = ea_find(old->attrs->eattrs, EA_CODE(EAP_BGP, BA_MULTI_EXIT_DISC));
n = x ? x->u.data : new_bgp->cf->default_med;
o = y ? y->u.data : old_bgp->cf->default_med;
if (n < o)
return 1;
if (n > o)
return 0;
if (bgp_get_neighbor(new) == bgp_get_neighbor(old))
{
x = ea_find(new->attrs->eattrs, EA_CODE(EAP_BGP, BA_MULTI_EXIT_DISC));
y = ea_find(old->attrs->eattrs, EA_CODE(EAP_BGP, BA_MULTI_EXIT_DISC));
n = x ? x->u.data : new_bgp->cf->default_med;
o = y ? y->u.data : old_bgp->cf->default_med;
if (n < o)
return 1;
if (n > o)
return 0;
}
/* RFC 4271 9.1.2.2. d) Prefer external peers */
if (new_bgp->is_internal > old_bgp->is_internal)
......
......@@ -33,7 +33,7 @@ bgp_proto_start: proto_start BGP {
BGP_CFG->hold_time = 240;
BGP_CFG->connect_retry_time = 120;
BGP_CFG->initial_hold_time = 240;
BGP_CFG->default_med = ~0; /* RFC 1771 doesn't specify this, draft-09 says ~0 */
BGP_CFG->default_med = 0;
BGP_CFG->compare_path_lengths = 1;
BGP_CFG->start_delay_time = 5;
BGP_CFG->error_amnesia_time = 300;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment