]> git.puffer.fish Git - matthieu/frr.git/commitdiff
bgpd: This patch implements the exchange of the BGP-Prefix-SID label index attr
authorVivek Venkatraman <vivek@cumulusnetworks.com>
Thu, 9 Mar 2017 17:22:04 +0000 (12:22 -0500)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Thu, 6 Apr 2017 14:32:07 +0000 (10:32 -0400)
Implement BGP Prefix-SID IETF draft to be able to signal a labeled-unicast
prefix with a label index (segment ID). This makes it easier to deploy
global MPLS labels with BGP, even without other aspects of Segment Routing
implemented.

Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
bgpd/bgp_attr.c
bgpd/bgp_attr.h
bgpd/bgp_debug.c
bgpd/bgp_label.c
bgpd/bgp_route.c
bgpd/bgp_table.h
bgpd/bgpd.h

index 2c6bb5de0e9d5f3cee35398b0311e0fe7c4a7c57..acc08184b9541982ce4d0c2d9afa917b55803616 100644 (file)
@@ -676,6 +676,7 @@ attrhash_key_make (void *p)
       MIX(extra->mp_nexthop_global_in.s_addr);
       MIX(extra->originator_id.s_addr);
       MIX(extra->tag);
+      MIX(extra->label_index);
     }
   
   if (attr->aspath)
@@ -730,6 +731,7 @@ attrhash_cmp (const void *p1, const void *p2)
           && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
           && ae1->weight == ae2->weight
           && ae1->tag == ae2->tag
+          && ae1->label_index == ae2->label_index
           && ae1->mp_nexthop_len == ae2->mp_nexthop_len
           && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
           && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
@@ -1287,6 +1289,7 @@ const u_int8_t attr_flags_values [] = {
   [BGP_ATTR_AS4_PATH] =         BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
   [BGP_ATTR_AS4_AGGREGATOR] =   BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
   [BGP_ATTR_LARGE_COMMUNITIES]= BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
+  [BGP_ATTR_LABEL_INDEX] =      BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
 };
 static const size_t attr_flags_values_max = array_size(attr_flags_values) - 1;
 
@@ -2274,6 +2277,52 @@ bgp_attr_encap(
   return 0;
 }
 
+/* Label index attribute */
+static bgp_attr_parse_ret_t
+bgp_attr_label_index (struct bgp_attr_parser_args *args, struct bgp_nlri *mp_update)
+{
+  struct peer *const peer = args->peer;
+  struct attr *const attr = args->attr;
+  const bgp_size_t length = args->length;
+  u_int32_t label_index;
+
+  /* Length check. */
+  if (length != 8)
+    {
+      zlog_err ("Bad label index length %d", length);
+
+      return bgp_attr_malformed (args,
+                                 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+                                 args->total);
+    }
+
+  /* First u32 is currently unused - reserved and flags (undefined) */
+  stream_getl (peer->ibuf);
+
+  /* Fetch the label index and see if it is valid. */
+  label_index = stream_getl (peer->ibuf);
+  if (label_index == BGP_INVALID_LABEL_INDEX)
+    return bgp_attr_malformed (args,
+                               BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
+                               args->total);
+
+  /* Store label index; subsequently, we'll check on address-family */
+  (bgp_attr_extra_get (attr))->label_index = label_index;
+
+  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX);
+
+  /*
+   * Ignore the Label index attribute unless received for labeled-unicast
+   * SAFI. We reset the flag, though it is probably unnecesary.
+   */
+  if (!mp_update->length || mp_update->afi != SAFI_LABELED_UNICAST)
+    {
+      attr->extra->label_index = BGP_INVALID_LABEL_INDEX;
+      attr->flag &= ~ATTR_FLAG_BIT(BGP_ATTR_LABEL_INDEX);
+    }
+  return BGP_ATTR_PARSE_PROCEED;
+}
+
 /* BGP unknown attribute treatment. */
 static bgp_attr_parse_ret_t
 bgp_attr_unknown (struct bgp_attr_parser_args *args)
@@ -2572,6 +2621,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
         case BGP_ATTR_ENCAP:
           ret = bgp_attr_encap (type, peer, length, attr, flag, startp);
           break;
+        case BGP_ATTR_LABEL_INDEX:
+          ret = bgp_attr_label_index (&attr_args, mp_update);
+          break;
        default:
          ret = bgp_attr_unknown (&attr_args);
          break;
@@ -3355,6 +3407,23 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
        }
     }
 
+  /* Label index attribute. */
+  if (safi == SAFI_LABELED_UNICAST)
+    {
+      if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))
+        {
+          u_int32_t label_index;
+
+          assert (attr->extra);
+          label_index = attr->extra->label_index;
+          stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
+          stream_putc (s, BGP_ATTR_LABEL_INDEX);
+          stream_putc (s, 8);
+          stream_putl (s, 0);
+          stream_putl (s, label_index);
+        }
+    }
+
   if ( send_as4_path )
     {
       /* If the peer is NOT As4 capable, AND */
@@ -3638,6 +3707,17 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr,
       stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
     }
 
+  /* Label index */
+  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))
+    {
+      assert (attr->extra);
+      stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
+      stream_putc (s, BGP_ATTR_LABEL_INDEX);
+      stream_putc (s, 8);
+      stream_putl (s, 0);
+      stream_putl (s, attr->extra->label_index);
+    }
+
   /* Return total size of attribute. */
   len = stream_get_endp (s) - cp - 2;
   stream_putw_at (s, cp, len);
index 015039c6cd671e4ce8ef0a345d36f7dbbaa88f58..310fc0215dc3551e5b43322b55bde5774b618c02 100644 (file)
@@ -134,6 +134,9 @@ struct attr_extra
   /* route tag */
   route_tag_t tag;
 
+  /* Label index */
+  u_int32_t label_index;
+
   uint16_t                     encap_tunneltype;       /* grr */
   struct bgp_attr_encap_subtlv *encap_subtlvs;         /* rfc5512 */
 
index 232f53c778a7487f59f9f9d9745e9e5e2e2344e4..8e4d8bf4f292b9d3d6e5ac9d19384725e8207050 100644 (file)
@@ -450,6 +450,10 @@ bgp_dump_attr (struct peer *peer, struct attr *attr, char *buf, size_t size)
     snprintf (buf + strlen (buf), size - strlen (buf), ", path %s",
              aspath_print (attr->aspath));
 
+  if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX)))
+    snprintf (buf + strlen (buf), size - strlen (buf), ", label-index %u",
+              attr->extra->label_index);
+
   if (strlen (buf) > 1)
     return 1;
   else
index 283afbc9222db16390efe1ff7feaf19cf44676d5..e2c4a54044eab23a2835ffa1ca423da8afe2a0c2 100644 (file)
@@ -143,6 +143,11 @@ bgp_reg_dereg_for_label (struct bgp_node *rn, int reg)
   stream_putw(s, PREFIX_FAMILY(p));
   stream_put_prefix(s, p);
   stream_putw_at (s, 0, stream_get_endp (s));
+
+  if (reg)
+    SET_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL);
+  else
+    UNSET_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL);
   zclient_send_message(zclient);
 
   return;
index 0c29254f3f630b848314acfbc3b6c7c1048e167b..451b54edab1d6253603d880a891857fb238da832 100644 (file)
@@ -1942,9 +1942,21 @@ bgp_process_main (struct work_queue *wq, void *data)
     {
       label_valid = bgp_is_valid_label (rn->local_label);
       if (!old_select && new_select && !label_valid)
-        bgp_register_for_label (rn);
+        {
+          if (new_select->sub_type == BGP_ROUTE_STATIC &&
+              new_select->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))
+            {
+              label_ntop (MPLS_IMP_NULL_LABEL, 1, rn->local_label);
+              bgp_set_valid_label(rn->local_label);
+            }
+          else
+            bgp_register_for_label (rn);
+        }
       else if (old_select && !new_select)
-        bgp_unregister_for_label (rn);
+        {
+          if (CHECK_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL))
+            bgp_unregister_for_label (rn);
+        }
     }
 
   /* If best route remains the same and this is not due to user-initiated
@@ -3792,6 +3804,13 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
   if (bgp_static->atomic)
     attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
 
+  /* Store label index, if required. */
+  if (bgp_static->label_index != BGP_INVALID_LABEL_INDEX)
+    {
+      (bgp_attr_extra_get (&attr))->label_index = bgp_static->label_index;
+      attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX);
+    }
+
   /* Apply route-map. */
   if (bgp_static->rmap.name)
     {
@@ -7631,9 +7650,20 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
           if (json_paths)
             json_object_int_add(json_path, "remote-label", label);
           else
-            vty_out(vty, "      Remote label: %d%s", label, VTY_NEWLINE);
+            vty_out(vty, "      Remote label: %d", label);
         }
 
+      if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX)))
+        {
+          if (json_paths)
+            json_object_int_add(json_path, "label-index", attr->extra->label_index);
+          else
+            vty_out(vty, ", Label Index: %d", attr->extra->label_index);
+        }
+
+      if (!json_paths)
+        vty_out (vty, "%s", VTY_NEWLINE);
+
       /* Line 8 display Addpath IDs */
       if (binfo->addpath_rx_id || binfo->addpath_tx_id)
         {
index 2b874f66a667b7bc6e39175dad35813950b4729a..a6b99a53d6ecfb0b9c1c6376a5db0b289c065421 100644 (file)
@@ -63,6 +63,7 @@ struct bgp_node
 #define BGP_NODE_PROCESS_SCHEDULED     (1 << 0)
 #define BGP_NODE_USER_CLEAR             (1 << 1)
 #define BGP_NODE_LABEL_CHANGED          (1 << 2)
+#define BGP_NODE_REGISTERED_FOR_LABEL   (1 << 3)
 };
 
 /*
index e95d059227f8544938513e3974b6be49c1c471be..83c5d90ddf1aea3d6b7c8af43420113a1754b6bd 100644 (file)
@@ -972,6 +972,7 @@ struct bgp_nlri
 #define BGP_ATTR_AS4_AGGREGATOR                 18
 #define BGP_ATTR_AS_PATHLIMIT                   21
 #define BGP_ATTR_ENCAP                          23
+#define BGP_ATTR_LABEL_INDEX                    30
 #define BGP_ATTR_LARGE_COMMUNITIES              32
 #if ENABLE_BGP_VNC
 #define BGP_ATTR_VNC                           255