]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Bugfixes in MULIT_EXIT_DISC attribute handling.
authorOndrej Zajicek <santiago@crfreenet.org>
Sun, 26 Oct 2008 21:59:21 +0000 (22:59 +0100)
committerOndrej Zajicek <santiago@crfreenet.org>
Sun, 26 Oct 2008 21:59:21 +0000 (22:59 +0100)
 - 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.

doc/bird.sgml
nest/a-path.c
nest/attrs.h
proto/bgp/attrs.c
proto/bgp/config.Y

index 5ee9562f4382840ed72c9c604f47ecd80c5f5400..8fa55f858a84b2442e466e0e4ecd2b161c1556cc 100644 (file)
@@ -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
index f4666911f73e58a0e186dee48b720c46fb8563f1..5e3ecfd47651d7f4addc0630564073a5dafc9ec2 100644 (file)
@@ -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)
 {
index aaa5f4a23088aef667f23225b0f56dcaedc91d9d..fee2c2c8ec106e7b50e96a57db95032606fdcee1 100644 (file)
@@ -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);
 
 
index b5d8fba788f19294e821d01516350ab6f8c0c1ce..2210cbe74d8a37a8da5574dc2f8032a139b53b53 100644 (file)
@@ -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)
index d7bba57533c6d918636d8d4410f507fc5bf6b33f..8524b2dde0bef1fdef8ec839ad1243f192f5c5e8 100644 (file)
@@ -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;