]> git.puffer.fish Git - matthieu/frr.git/commitdiff
bgpd, lib, zebra: Implement handling of BGP-Prefix-SID label Index
authorVivek Venkatraman <vivek@cumulusnetworks.com>
Thu, 9 Mar 2017 17:55:54 +0000 (12:55 -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.

This patch implements the handling of the BGP-Prefix-SID Label Index
attribute. When received from a peer and the index is acceptable, the local
label is picked up from the SRGB and is programmed as the incoming label as
well as advertised to peers. If the index is not acceptable, no local label
is assigned. The outgoing label will always be the one advertised by the
downstream neighbor.

Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
bgpd/bgp_label.c
bgpd/bgp_label.h
bgpd/bgp_route.c
lib/mpls.h
lib/zebra.h
zebra/zebra_mpls.c
zebra/zebra_mpls.h
zebra/zebra_mpls_null.c
zebra/zserv.c

index e2c4a54044eab23a2835ffa1ca423da8afe2a0c2..0c331c5d5916ce9f40a761220a1badfc97d99ddb 100644 (file)
@@ -125,11 +125,14 @@ bgp_adv_label (struct bgp_node *rn, struct bgp_info *ri, struct peer *to,
 }
 
 void
-bgp_reg_dereg_for_label (struct bgp_node *rn, int reg)
+bgp_reg_dereg_for_label (struct bgp_node *rn, struct bgp_info *ri,
+                         int reg)
 {
   struct stream *s;
   struct prefix *p;
   int command;
+  u_int16_t flags = 0;
+  size_t flags_pos = 0;
 
   /* Check socket. */
   if (!zclient || zclient->sock < 0)
@@ -140,17 +143,29 @@ bgp_reg_dereg_for_label (struct bgp_node *rn, int reg)
   stream_reset (s);
   command = (reg) ? ZEBRA_FEC_REGISTER : ZEBRA_FEC_UNREGISTER;
   zclient_create_header (s, command, VRF_DEFAULT);
+  flags_pos = stream_get_endp (s); /* save position of 'flags' */
+  stream_putw(s, flags); /* initial flags */
   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);
+    {
+      assert (ri);
+      if (ri->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))
+        {
+          assert (ri->attr->extra);
+          flags |= ZEBRA_FEC_REGISTER_LABEL_INDEX;
+          stream_putl (s, ri->attr->extra->label_index);
+        }
+      SET_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL);
+    }
   else
     UNSET_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL);
-  zclient_send_message(zclient);
 
-  return;
+  /* Set length and flags */
+  stream_putw_at (s, 0, stream_get_endp (s));
+  stream_putw_at (s, flags_pos, flags);
+
+  zclient_send_message(zclient);
 }
 
 static int
index a7e7d5c47bbfe79b45848eacf36bbed6b75830fa..49a7b945abd310c6bc1ff405589254c49e65e64f 100644 (file)
@@ -30,7 +30,8 @@ struct bgp_node;
 struct bgp_info;
 struct peer;
 
-extern void bgp_reg_dereg_for_label (struct bgp_node *rn, int reg);
+extern void bgp_reg_dereg_for_label (struct bgp_node *rn, struct bgp_info *ri,
+                                     int reg);
 extern int bgp_parse_fec_update(void);
 extern u_char * bgp_adv_label(struct bgp_node *rn, struct bgp_info *ri,
                              struct peer *to, afi_t afi, safi_t safi);
@@ -84,15 +85,15 @@ bgp_unset_valid_label (u_char *t)
 }
 
 static inline void
-bgp_register_for_label (struct bgp_node *rn)
+bgp_register_for_label (struct bgp_node *rn, struct bgp_info *ri)
 {
-  bgp_reg_dereg_for_label (rn, 1);
+  bgp_reg_dereg_for_label (rn, ri, 1);
 }
 
 static inline void
 bgp_unregister_for_label (struct bgp_node *rn)
 {
-  bgp_reg_dereg_for_label (rn, 0);
+  bgp_reg_dereg_for_label (rn, NULL, 0);
 }
 
 /* Label stream to value */
index 451b54edab1d6253603d880a891857fb238da832..b016122a7f243c2b7eb0b87827d2e94ef7daf71d 100644 (file)
@@ -298,6 +298,20 @@ bgp_pcount_adjust (struct bgp_node *rn, struct bgp_info *ri)
     }
 }
 
+static int
+bgp_label_index_differs (struct bgp_info *ri1, struct bgp_info *ri2)
+{
+  u_int32_t ri1_label_index = BGP_INVALID_LABEL_INDEX;
+  u_int32_t ri2_label_index = BGP_INVALID_LABEL_INDEX;
+
+  if (ri1->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))
+    ri1_label_index = ri1->attr->extra->label_index;
+
+  if (ri2->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))
+    ri2_label_index = ri2->attr->extra->label_index;
+
+  return (!(ri1_label_index == ri2_label_index));
+}
 
 /* Set/unset bgp_info flags, adjusting any other state as needed.
  * This is here primarily to keep prefix-count in check.
@@ -1908,7 +1922,6 @@ bgp_process_main (struct work_queue *wq, void *data)
   struct bgp_info *new_select;
   struct bgp_info *old_select;
   struct bgp_info_pair old_and_new;
-  int label_valid;
 
   /* Is it end of initial update? (after startup) */
   if (!rn)
@@ -1935,28 +1948,31 @@ bgp_process_main (struct work_queue *wq, void *data)
 
   /* Do we need to allocate or free labels?
    * Right now, since we only deal with per-prefix labels, it is not necessary
-   * to do this upon changes to best path.
+   * to do this upon changes to best path except of the label index changes.
    */
   bgp_table_lock (bgp_node_table (rn));
   if (bgp_labeled_safi (safi))
     {
-      label_valid = bgp_is_valid_label (rn->local_label);
-      if (!old_select && new_select && !label_valid)
+      if (new_select)
         {
-          if (new_select->sub_type == BGP_ROUTE_STATIC &&
-              new_select->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))
+          if (!old_select ||
+              bgp_label_index_differs (new_select, old_select) ||
+              new_select->sub_type != old_select->sub_type)
             {
-              label_ntop (MPLS_IMP_NULL_LABEL, 1, rn->local_label);
-              bgp_set_valid_label(rn->local_label);
+              if (new_select->sub_type == BGP_ROUTE_STATIC &&
+                  new_select->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))
+                {
+                  if (CHECK_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL))
+                    bgp_unregister_for_label (rn);
+                  label_ntop (MPLS_IMP_NULL_LABEL, 1, rn->local_label);
+                  bgp_set_valid_label(rn->local_label);
+                }
+              else
+                bgp_register_for_label (rn, new_select);
             }
-          else
-            bgp_register_for_label (rn);
-        }
-      else if (old_select && !new_select)
-        {
-          if (CHECK_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL))
-            bgp_unregister_for_label (rn);
         }
+      else 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
index 5a9188375347fc73ac9b780310f8effde4dd72bb..f4f360c957f5d7d800ec89757d169bed04f60eaf 100644 (file)
@@ -123,6 +123,11 @@ mpls_lse_decode (mpls_lse_t lse, mpls_label_t *label,
   *ttl = MPLS_LABEL_TTL(local_lse);
 }
 
+/* Invalid label index value (when used with BGP Prefix-SID). Should
+ * match the BGP definition.
+ */
+#define MPLS_INVALID_LABEL_INDEX   0xFFFFFFFF
+
 
 /* Printable string for labels (with consideration for reserved values). */
 static inline char *
index ef261eedc190e72fe67680c63a5db74008a4ad3d..cd72dc67f82feba622212ef9ef8aed4d9068aa79 100644 (file)
@@ -393,6 +393,9 @@ extern const char *zserv_command_string (unsigned int command);
 #define ZEBRA_FLAG_SCOPE_LINK         0x100
 #define ZEBRA_FLAG_FIB_OVERRIDE       0x200
 
+/* Zebra FEC flags. */
+#define ZEBRA_FEC_REGISTER_LABEL_INDEX        0x1
+
 #ifndef INADDR_LOOPBACK
 #define        INADDR_LOOPBACK 0x7f000001      /* Internet address 127.0.0.1.  */
 #endif
index 85ce147d25c696d5d21734350e41e50fae4f5b8a..42738f8fb9c1f8670b8bbe8145c116c164bac528 100644 (file)
@@ -60,6 +60,10 @@ extern struct zebra_t zebrad;
 
 /* static function declarations */
 
+static void
+fec_evaluate (struct zebra_vrf *zvrf, int add);
+static u_int32_t
+fec_derive_label_from_index (struct zebra_vrf *vrf, zebra_fec_t *fec);
 static int
 lsp_install (struct zebra_vrf *zvrf, mpls_label_t label,
              struct route_node *rn, struct rib *rib);
@@ -77,7 +81,7 @@ static zebra_fec_t *
 fec_find (struct route_table *table, struct prefix *p);
 static zebra_fec_t *
 fec_add (struct route_table *table, struct prefix *p, mpls_label_t label,
-         u_int32_t flags);
+         u_int32_t flags, u_int32_t label_index);
 static int
 fec_del (zebra_fec_t *fec);
 
@@ -352,6 +356,84 @@ lsp_uninstall (struct zebra_vrf *zvrf, mpls_label_t label)
   return 0;
 }
 
+/*
+ * This function is invoked upon change to label block configuration; it
+ * will walk all registered FECs with label-index and appropriately update
+ * their local labels and trigger client updates.
+ */
+static void
+fec_evaluate (struct zebra_vrf *zvrf, int add)
+{
+  struct route_node *rn;
+  zebra_fec_t *fec;
+  u_int32_t old_label, new_label;
+  int af;
+  char buf[BUFSIZ];
+
+  for (af = AFI_IP; af < AFI_MAX; af++)
+    {
+      for (rn = route_top(zvrf->fec_table[af]); rn; rn = route_next(rn))
+        {
+          if ((fec = rn->info) == NULL)
+            continue;
+
+          /* Skip configured FECs and those without a label index. */
+          if (fec->flags & FEC_FLAG_CONFIGURED ||
+              fec->label_index == MPLS_INVALID_LABEL_INDEX)
+            continue;
+
+          if (IS_ZEBRA_DEBUG_MPLS)
+            prefix2str(&rn->p, buf, BUFSIZ);
+
+          /* Save old label, determine new label. */
+          old_label = fec->label;
+          if (add)
+            {
+              new_label = zvrf->mpls_srgb.start_label + fec->label_index;
+              if (new_label >= zvrf->mpls_srgb.end_label)
+                new_label = MPLS_INVALID_LABEL;
+            }
+          else
+            new_label = MPLS_INVALID_LABEL;
+
+          /* If label has changed, update FEC and clients. */
+          if (new_label == old_label)
+            continue;
+
+          if (IS_ZEBRA_DEBUG_MPLS)
+            zlog_debug ("Update fec %s new label %u upon label block %s",
+                         buf, new_label, add ? "ADD" : "DEL");
+
+          fec->label = new_label;
+          fec_update_clients (fec);
+
+          /* Update label forwarding entries appropriately */
+          fec_change_update_lsp (zvrf, fec, old_label);
+        }
+    }
+}
+
+/*
+ * Derive (if possible) and update the local label for the FEC based on
+ * its label index. The index is "acceptable" if it falls within the
+ * globally configured label block (SRGB).
+ */
+static u_int32_t
+fec_derive_label_from_index (struct zebra_vrf *zvrf, zebra_fec_t *fec)
+{
+  u_int32_t label;
+
+  if (fec->label_index != MPLS_INVALID_LABEL_INDEX &&
+      zvrf->mpls_srgb.start_label &&
+      ((label = zvrf->mpls_srgb.start_label + fec->label_index) <
+       zvrf->mpls_srgb.end_label))
+    fec->label = label;
+  else
+    fec->label = MPLS_INVALID_LABEL;
+
+  return fec->label;
+}
+
 /*
  * There is a change for this FEC. Install or uninstall label forwarding
  * entries, as appropriate.
@@ -457,6 +539,8 @@ fec_print (zebra_fec_t *fec, struct vty *vty)
   prefix2str(&rn->p, buf, BUFSIZ);
   vty_out(vty, "%s%s", buf, VTY_NEWLINE);
   vty_out(vty, "  Label: %s", label2str(fec->label, buf, BUFSIZ));
+  if (fec->label_index != MPLS_INVALID_LABEL_INDEX)
+    vty_out(vty, ", Label Index: %u", fec->label_index);
   vty_out(vty, "%s", VTY_NEWLINE);
   if (!list_isempty(fec->client_list))
     {
@@ -491,7 +575,7 @@ fec_find (struct route_table *table, struct prefix *p)
  */
 static zebra_fec_t *
 fec_add (struct route_table *table, struct prefix *p,
-         mpls_label_t label, u_int32_t flags)
+         mpls_label_t label, u_int32_t flags, u_int32_t label_index)
 {
   struct route_node *rn;
   zebra_fec_t *fec;
@@ -519,6 +603,7 @@ fec_add (struct route_table *table, struct prefix *p,
   else
     route_unlock_node (rn); /* for the route_node_get */
 
+  fec->label_index = label_index;
   fec->flags = flags;
 
   return fec;
@@ -1743,14 +1828,21 @@ zebra_mpls_lsp_uninstall (struct zebra_vrf *zvrf, struct route_node *rn, struct
 /*
  * Registration from a client for the label binding for a FEC. If a binding
  * already exists, it is informed to the client.
+ * NOTE: If there is a manually configured label binding, that is used.
+ * Otherwise, if aa label index is specified, it means we have to allocate the
+ * label from a locally configured label block (SRGB), if one exists and index
+ * is acceptable.
  */
 int
 zebra_mpls_fec_register (struct zebra_vrf *zvrf, struct prefix *p,
-                         struct zserv *client)
+                         u_int32_t label_index, struct zserv *client)
 {
   struct route_table *table;
   zebra_fec_t *fec;
   char buf[BUFSIZ];
+  int new_client;
+  int label_change = 0;
+  u_int32_t old_label;
 
   table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
   if (!table)
@@ -1763,7 +1855,7 @@ zebra_mpls_fec_register (struct zebra_vrf *zvrf, struct prefix *p,
   fec = fec_find (table, p);
   if (!fec)
     {
-      fec = fec_add (table, p, MPLS_INVALID_LABEL, 0);
+      fec = fec_add (table, p, MPLS_INVALID_LABEL, 0, label_index);
       if (!fec)
         {
           prefix2str(p, buf, BUFSIZ);
@@ -1771,27 +1863,60 @@ zebra_mpls_fec_register (struct zebra_vrf *zvrf, struct prefix *p,
                    buf, zebra_route_string(client->proto));
           return -1;
         }
+
+      old_label = MPLS_INVALID_LABEL;
+      new_client = 1;
     }
   else
     {
-      if (listnode_lookup(fec->client_list, client))
+      /* Client may register same FEC with different label index. */
+      new_client = (listnode_lookup(fec->client_list, client) == NULL);
+      if (!new_client && fec->label_index == label_index)
         /* Duplicate register */
         return 0;
+
+      /* Save current label, update label index */
+      old_label = fec->label;
+      fec->label_index = label_index;
     }
 
-  listnode_add (fec->client_list, client);
+  if (new_client)
+    listnode_add (fec->client_list, client);
 
   if (IS_ZEBRA_DEBUG_MPLS)
-    zlog_debug("FEC %s registered by client %s",
-                buf, zebra_route_string(client->proto));
+    zlog_debug("FEC %s Label Index %u %s by client %s",
+                buf, label_index, new_client ? "registered" : "updated",
+                zebra_route_string(client->proto));
+
+  /* If not a configured FEC, derive the local label (from label index)
+   * or reset it.
+   */
+  if (!(fec->flags & FEC_FLAG_CONFIGURED))
+    {
+      fec_derive_label_from_index (zvrf, fec);
+
+      /* If no label change, exit. */
+      if (fec->label == old_label)
+        return 0;
 
-  if (fec->label != MPLS_INVALID_LABEL)
+      label_change = 1;
+    }
+
+  /* If new client or label change, update client and install or uninstall
+   * label forwarding entry as needed.
+   */
+  /* Inform client of label, if needed. */
+  if ((new_client && fec->label != MPLS_INVALID_LABEL) ||
+      label_change)
     {
       if (IS_ZEBRA_DEBUG_MPLS)
         zlog_debug ("Update client label %u", fec->label);
       fec_send (fec, client);
     }
 
+  if (new_client || label_change)
+    return fec_change_update_lsp (zvrf, fec, old_label);
+
   return 0;
 }
 
@@ -1830,8 +1955,17 @@ zebra_mpls_fec_unregister (struct zebra_vrf *zvrf, struct prefix *p,
     zlog_debug("FEC %s unregistered by client %s",
                 buf, zebra_route_string(client->proto));
 
-  if (list_isempty(fec->client_list) && (fec->label == MPLS_INVALID_LABEL))
-    fec_del (fec);
+  /* If not a configured entry, delete the FEC if no other clients. Before
+   * deleting, see if any LSP needs to be uninstalled.
+   */
+  if (!(fec->flags & FEC_FLAG_CONFIGURED) &&
+      list_isempty(fec->client_list))
+    {
+      mpls_label_t old_label = fec->label;
+      fec->label = MPLS_INVALID_LABEL; /* reset */
+      fec_change_update_lsp (zvrf, fec, old_label);
+      fec_del (fec);
+    }
 
   return 0;
 }
@@ -1943,7 +2077,8 @@ zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p,
   fec = fec_find (table, p);
   if (!fec)
     {
-      fec = fec_add (table, p, in_label, FEC_FLAG_CONFIGURED);
+      fec = fec_add (table, p, in_label, FEC_FLAG_CONFIGURED,
+                     MPLS_INVALID_LABEL_INDEX);
       if (!fec)
         {
           prefix2str(p, buf, BUFSIZ);
@@ -1979,6 +2114,8 @@ zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p,
 /*
  * Remove static FEC to label binding. If there are no clients registered
  * for this FEC, delete the FEC; else notify clients
+ * Note: Upon delete of static binding, if label index exists for this FEC,
+ * client may need to be updated with derived label.
  */
 int
 zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p)
@@ -2003,7 +2140,8 @@ zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p)
   if (IS_ZEBRA_DEBUG_MPLS)
     {
       prefix2str(p, buf, BUFSIZ);
-      zlog_debug ("Delete fec %s", buf);
+      zlog_debug ("Delete fec %s label index %u",
+                  buf, fec->label_index);
     }
 
   old_label = fec->label;
@@ -2017,6 +2155,12 @@ zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p)
       return 0;
     }
 
+  /* Derive the local label (from label index) or reset it. */
+  fec_derive_label_from_index (zvrf, fec);
+  /* If there is a label change, update clients. */
+  if (fec->label == old_label)
+    return 0;
   fec_update_clients (fec);
 
   /* Update label forwarding entries appropriately */
@@ -2744,6 +2888,9 @@ zebra_mpls_label_block_add (struct zebra_vrf *zvrf, u_int32_t start_label,
 {
   zvrf->mpls_srgb.start_label = start_label;
   zvrf->mpls_srgb.end_label = end_label;
+
+  /* Evaluate registered FECs to see if any get a label or not. */
+  fec_evaluate (zvrf, 1);
   return 0;
 }
 
@@ -2755,6 +2902,9 @@ zebra_mpls_label_block_del (struct zebra_vrf *zvrf)
 {
   zvrf->mpls_srgb.start_label = 0;
   zvrf->mpls_srgb.end_label = 0;
+
+  /* Process registered FECs to clear their local label, if needed. */
+  fec_evaluate (zvrf, 0);
   return 0;
 }
 
index f8e95fa10025fc37b2361c94ad0584fa3adfb0f3..e271edd2eb4c78f5a89febb47740b73b7b30bba9 100644 (file)
@@ -159,6 +159,9 @@ struct zebra_fec_t_
   /* In-label - either statically bound or derived from label block. */
   mpls_label_t label;
 
+  /* Label index (into global label block), if valid */
+  u_int32_t label_index;
+
   /* Flags. */
   u_int32_t flags;
 #define FEC_FLAG_CONFIGURED       (1 << 0)
@@ -217,10 +220,14 @@ zebra_mpls_lsp_uninstall (struct zebra_vrf *zvrf, struct route_node *rn, struct
 /*
  * Registration from a client for the label binding for a FEC. If a binding
  * already exists, it is informed to the client.
+ * NOTE: If there is a manually configured label binding, that is used.
+ * Otherwise, if aa label index is specified, it means we have to allocate the
+ * label from a locally configured label block (SRGB), if one exists and index
+ * is acceptable.
  */
 int
 zebra_mpls_fec_register (struct zebra_vrf *zvrf, struct prefix *p,
-                         struct zserv *client);
+                         u_int32_t label_index, struct zserv *client);
 
 /*
  * Deregistration from a client for the label binding for a FEC. The FEC
@@ -265,6 +272,8 @@ zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p,
 /*
  * Remove static FEC to label binding. If there are no clients registered
  * for this FEC, delete the FEC; else notify clients.
+ * Note: Upon delete of static binding, if label index exists for this FEC,
+ * client may need to be updated with derived label.
  */
 int
 zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p);
index 12176c024ef803f702e9deec20cb012b1b0f6749..6b0a91de029ae50e7e25641a1a6722a63687f846 100644 (file)
@@ -175,7 +175,7 @@ zebra_mpls_print_fec (struct vty *vty, struct zebra_vrf *zvrf, struct prefix *p)
 
 int
 zebra_mpls_fec_register (struct zebra_vrf *zvrf, struct prefix *p,
-                         struct zserv *client)
+                         u_int32_t label_index, struct zserv *client)
 {
   return 0;
 }
index c11f1bf3fd822929c478ef898c9e71280ef6be20..7c8e6de765e43d4eb3695d96cf7f82ad505e8464 100644 (file)
@@ -942,6 +942,8 @@ zserv_fec_register (struct zserv *client, int sock, u_short length)
   struct zebra_vrf *zvrf;
   u_short l = 0;
   struct prefix p;
+  u_int16_t flags;
+  u_int32_t label_index = MPLS_INVALID_LABEL_INDEX;
 
   s = client->ibuf;
   zvrf = vrf_info_lookup(VRF_DEFAULT);
@@ -950,12 +952,18 @@ zserv_fec_register (struct zserv *client, int sock, u_short length)
 
   while (l < length)
     {
+      flags = stream_getw(s);
       p.family = stream_getw(s);
       p.prefixlen = stream_getc(s);
       l += 5;
       stream_get(&p.u.prefix, s, PSIZE(p.prefixlen));
       l += PSIZE(p.prefixlen);
-      zebra_mpls_fec_register (zvrf, &p, client);
+      if (flags & ZEBRA_FEC_REGISTER_LABEL_INDEX)
+        {
+          label_index = stream_getl(s);
+          l += 4;
+        }
+      zebra_mpls_fec_register (zvrf, &p, label_index, client);
     }
 
   return 0;
@@ -969,6 +977,7 @@ zserv_fec_unregister (struct zserv *client, int sock, u_short length)
   struct zebra_vrf *zvrf;
   u_short l = 0;
   struct prefix p;
+  u_int16_t flags;
 
   s = client->ibuf;
   zvrf = vrf_info_lookup(VRF_DEFAULT);
@@ -977,6 +986,7 @@ zserv_fec_unregister (struct zserv *client, int sock, u_short length)
 
   while (l < length)
     {
+      flags = stream_getw(s);
       p.family = stream_getw(s);
       p.prefixlen = stream_getc(s);
       l += 5;