]> git.proxmox.com Git - mirror_frr.git/commitdiff
zebra: labeled unicast handling
authorDon Slice <dslice@cumulusnetworks.com>
Thu, 2 Feb 2017 17:58:33 +0000 (12:58 -0500)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Thu, 6 Apr 2017 14:29:19 +0000 (10:29 -0400)
Support install of labeled-unicast routes by a client. This would be
BGP, in order to install routes corresponding to AFI/SAFI 1/4 (IPv4)
or 2/4 (IPv6). Convert labeled-unicast routes into label forwarding
entries (i.e., transit LSPs) when there is a static label binding.

Signed-off-by: Don Slice <dslice@cumulusnetworks.com>
13 files changed:
lib/mpls.h
lib/nexthop.c
lib/nexthop.h
lib/zclient.c
lib/zclient.h
lib/zebra.h
zebra/rib.h
zebra/zebra_mpls.c
zebra/zebra_mpls.h
zebra/zebra_mpls_null.c
zebra/zebra_mpls_vty.c
zebra/zebra_rib.c
zebra/zserv.c

index 13a46e10127cacdd67002c07ec8309aede0a9ac6..5a9188375347fc73ac9b780310f8effde4dd72bb 100644 (file)
@@ -85,7 +85,8 @@ enum lsp_types_t
 {
   ZEBRA_LSP_NONE = 0,        /* No LSP. */
   ZEBRA_LSP_STATIC = 1,      /* Static LSP. */
-  ZEBRA_LSP_LDP = 2          /* LDP LSP. */
+  ZEBRA_LSP_LDP = 2,         /* LDP LSP. */
+  ZEBRA_LSP_BGP = 3          /* BGP LSP. */
 };
 
 /* Functions for basic label operations. */
index 7b8ac95e832bec6978b803e92230459df2044136..a6420fea339c1bd481cde379ccbd9e8213664dd0 100644 (file)
@@ -92,6 +92,28 @@ nexthop_type_to_str (enum nexthop_types_t nh_type)
   return desc[nh_type];
 }
 
+/*
+ * Check if the labels match for the 2 nexthops specified.
+ */
+int
+nexthop_labels_match (struct nexthop *nh1, struct nexthop *nh2)
+{
+  struct nexthop_label *nhl1, *nhl2;
+
+  nhl1 = nh1->nh_label;
+  nhl2 = nh2->nh_label;
+  if ((nhl1 && !nhl2) || (!nhl1 && nhl2))
+    return 0;
+
+  if (nhl1->num_labels != nhl2->num_labels)
+    return 0;
+
+  if (memcmp (nhl1->label, nhl2->label, nhl1->num_labels))
+    return 0;
+
+  return 1;
+}
+
 struct nexthop *
 nexthop_new (void)
 {
index e66e0eee20ef08eb0221c60238c6bc3340a616ac..83c5b850b8f90def607723447c286287aa71b302 100644 (file)
@@ -117,6 +117,7 @@ void nexthop_del_labels (struct nexthop *);
 
 extern const char *nexthop_type_to_str (enum nexthop_types_t nh_type);
 extern int nexthop_same_no_recurse (struct nexthop *next1, struct nexthop *next2);
+extern int nexthop_labels_match (struct nexthop *nh1, struct nexthop *nh2);
 
 extern const char * nexthop2str (struct nexthop *nexthop, char *str, int size);
 #endif /*_LIB_NEXTHOP_H */
index 9e53b66c77cb509c96f8ccb11d026a5d25a68af1..541a5444cf2a627a5b9e9946ab4e55bdf3cab06b 100644 (file)
@@ -733,6 +733,18 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p,
   s = zclient->obuf;
   stream_reset (s);
 
+  /* Some checks for labeled-unicast. The current expectation is that each
+   * nexthop is accompanied by a label in the case of labeled-unicast.
+   */
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL) &&
+      CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP))
+    {
+      /* We expect prefixes installed with labels and the number to match
+       * the number of nexthops.
+       */
+      assert (api->label_num == api->nexthop_num);
+    }
+
   zclient_create_header (s, cmd, api->vrf_id);
   
   /* Put type and nexthop. */
@@ -749,7 +761,7 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p,
 
   /* Nexthop, ifindex, distance and metric information. */
   if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP))
-     {
+    {
       /* traditional 32-bit data units */
       if (CHECK_FLAG (api->flags, ZEBRA_FLAG_BLACKHOLE))
         {
@@ -765,6 +777,9 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p,
         {
           stream_putc (s, NEXTHOP_TYPE_IPV4);
           stream_put_in_addr (s, api->nexthop[i]);
+          /* For labeled-unicast, each nexthop is followed by label. */
+          if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL))
+            stream_putl (s, api->label[i]);
         }
       for (i = 0; i < api->ifindex_num; i++)
         {
@@ -800,6 +815,18 @@ zapi_ipv4_route_ipv6_nexthop (u_char cmd, struct zclient *zclient,
   s = zclient->obuf;
   stream_reset (s);
 
+  /* Some checks for labeled-unicast. The current expectation is that each
+   * nexthop is accompanied by a label in the case of labeled-unicast.
+   */
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL) &&
+      CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP))
+    {
+      /* We expect prefixes installed with labels and the number to match
+       * the number of nexthops.
+       */
+      assert (api->label_num == api->nexthop_num);
+    }
+
   zclient_create_header (s, cmd, api->vrf_id);
 
   /* Put type and nexthop. */
@@ -831,6 +858,9 @@ zapi_ipv4_route_ipv6_nexthop (u_char cmd, struct zclient *zclient,
        {
          stream_putc (s, NEXTHOP_TYPE_IPV6);
          stream_write (s, (u_char *)api->nexthop[i], 16);
+          /* For labeled-unicast, each nexthop is followed by label. */
+          if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL))
+            stream_putl (s, api->label[i]);
        }
       for (i = 0; i < api->ifindex_num; i++)
        {
@@ -869,6 +899,18 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p,
   s = zclient->obuf;
   stream_reset (s);
 
+  /* Some checks for labeled-unicast. The current expectation is that each
+   * nexthop is accompanied by a label in the case of labeled-unicast.
+   */
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL) &&
+      CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP))
+    {
+      /* We expect prefixes installed with labels and the number to match
+       * the number of nexthops.
+       */
+      assert (api->label_num == api->nexthop_num);
+    }
+
   zclient_create_header (s, cmd, api->vrf_id);
 
   /* Put type and nexthop. */
@@ -907,6 +949,9 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p,
        {
          stream_putc (s, NEXTHOP_TYPE_IPV6);
          stream_write (s, (u_char *)api->nexthop[i], 16);
+          /* For labeled-unicast, each nexthop is followed by label. */
+          if (CHECK_FLAG (api->message, ZAPI_MESSAGE_LABEL))
+            stream_putl (s, api->label[i]);
        }
       for (i = 0; i < api->ifindex_num; i++)
        {
index a5a1b530c5e5df9e7659c3d03a4fa6e39a6c6eb6..a54bf420d37feb53d3fd15fab61e927be056e38a 100644 (file)
@@ -178,6 +178,7 @@ struct zclient
 #define ZAPI_MESSAGE_TAG      0x10
 #define ZAPI_MESSAGE_MTU      0x20
 #define ZAPI_MESSAGE_SRCPFX   0x40
+#define ZAPI_MESSAGE_LABEL    0x80
 
 /* Zserv protocol message header */
 struct zserv_header
@@ -210,6 +211,9 @@ struct zapi_ipv4
   u_char ifindex_num;
   ifindex_t *ifindex;
 
+  u_char label_num;
+  unsigned int *label;
+
   u_char distance;
 
   u_int32_t metric;
@@ -301,6 +305,9 @@ struct zapi_ipv6
   u_char ifindex_num;
   ifindex_t *ifindex;
 
+  u_char label_num;
+  unsigned int *label;
+
   u_char distance;
 
   u_int32_t metric;
index 760264d752fe72ad60616ad21df0416f67dcf43c..985382bff57eb17cdde23a22307d3526fdc09e43 100644 (file)
@@ -413,11 +413,13 @@ typedef enum {
 #define SAFI_ENCAP               5
 #define SAFI_RESERVED_5           5
 #define SAFI_EVPN                 6
-#define SAFI_MAX                  7
+#define SAFI_LABELED_UNICAST      7
+#define SAFI_MAX                  8
 
 #define IANA_SAFI_RESERVED            0
 #define IANA_SAFI_UNICAST             1
 #define IANA_SAFI_MULTICAST           2
+#define IANA_SAFI_LABELED_UNICAST     4
 #define IANA_SAFI_ENCAP               7
 #define IANA_SAFI_MPLS_VPN            128
 
index 5381d76b9874688cf88007093979a669d0b160c5..8f6cff0d8a101026be7d4ac9da100f62660ebd87 100644 (file)
@@ -372,7 +372,7 @@ extern void rib_init (void);
 extern unsigned long rib_score_proto (u_char proto, u_short instance);
 extern void rib_queue_add (struct route_node *rn);
 extern void meta_queue_free (struct meta_queue *mq);
-
+extern int zebra_rib_labeled_unicast (struct rib *rib);
 extern struct route_table *rib_table_ipv6;
 
 extern void rib_unlink (struct route_node *, struct rib *);
index 366853cc006a094487722d95ce235674aced1b1a..f13a3f4f0a686087367d2cff1b5c924c197442c1 100644 (file)
@@ -60,6 +60,13 @@ extern struct zebra_t zebrad;
 
 /* static function declarations */
 
+static int
+lsp_install (struct zebra_vrf *zvrf, mpls_label_t label,
+             struct route_node *rn, struct rib *rib);
+static int
+lsp_uninstall (struct zebra_vrf *zvrf, mpls_label_t label);
+static int
+fec_change_update_lsp (struct zebra_vrf *zvrf, zebra_fec_t *fec, mpls_label_t old_label);
 static int
 fec_send (zebra_fec_t *fec, struct zserv *client);
 static void
@@ -69,7 +76,7 @@ fec_print (zebra_fec_t *fec, struct vty *vty);
 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, u_int32_t label,
+fec_add (struct route_table *table, struct prefix *p, mpls_label_t label,
          u_int32_t flags);
 static int
 fec_del (zebra_fec_t *fec);
@@ -106,17 +113,19 @@ static char *
 nhlfe2str (zebra_nhlfe_t *nhlfe, char *buf, int size);
 static int
 nhlfe_nhop_match (zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype,
-                  union g_addr *gate, char *ifname, ifindex_t ifindex);
+                  union g_addr *gate, ifindex_t ifindex);
 static zebra_nhlfe_t *
 nhlfe_find (zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
             enum nexthop_types_t gtype, union g_addr *gate,
-            char *ifname, ifindex_t ifindex);
+            ifindex_t ifindex);
 static zebra_nhlfe_t *
 nhlfe_add (zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
            enum nexthop_types_t gtype, union g_addr *gate,
-           char *ifname, ifindex_t ifindex, mpls_label_t out_label);
+           ifindex_t ifindex, mpls_label_t out_label);
 static int
 nhlfe_del (zebra_nhlfe_t *snhlfe);
+static void
+nhlfe_out_label_update (zebra_nhlfe_t *nhlfe, struct nexthop_label *nh_label);
 static int
 mpls_lsp_uninstall_all (struct hash *lsp_table, zebra_lsp_t *lsp,
                        enum lsp_types_t type);
@@ -130,14 +139,13 @@ static void *
 slsp_alloc (void *p);
 static int
 snhlfe_match (zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype,
-              union g_addr *gate, char *ifname, ifindex_t ifindex);
+              union g_addr *gate, ifindex_t ifindex);
 static zebra_snhlfe_t *
 snhlfe_find (zebra_slsp_t *slsp, enum nexthop_types_t gtype,
-             union g_addr *gate, char *ifname, ifindex_t ifindex);
+             union g_addr *gate, ifindex_t ifindex);
 static zebra_snhlfe_t *
 snhlfe_add (zebra_slsp_t *slsp, enum nexthop_types_t gtype,
-            union g_addr *gate, char *ifname, ifindex_t ifindex,
-            mpls_label_t out_label);
+            union g_addr *gate, ifindex_t ifindex, mpls_label_t out_label);
 static int
 snhlfe_del (zebra_snhlfe_t *snhlfe);
 static int
@@ -152,6 +160,245 @@ mpls_processq_init (struct zebra_t *zebra);
 
 /* Static functions */
 
+/*
+ * Install label forwarding entry based on labeled-route entry.
+ */
+static int
+lsp_install (struct zebra_vrf *zvrf, mpls_label_t label,
+             struct route_node *rn, struct rib *rib)
+{
+  struct hash *lsp_table;
+  zebra_ile_t tmp_ile;
+  zebra_lsp_t *lsp;
+  zebra_nhlfe_t *nhlfe;
+  struct nexthop *nexthop;
+  enum lsp_types_t  lsp_type;
+  char buf[BUFSIZ];
+  int added, changed;
+
+  /* Lookup table. */
+  lsp_table = zvrf->lsp_table;
+  if (!lsp_table)
+    return -1;
+
+  /* See if route entry is selected; we really expect only 1 entry here. */
+  if (!CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+    return 0;
+
+  lsp_type = lsp_type_from_rib_type (rib->type);
+  added = changed = 0;
+
+  /* Locate or allocate LSP entry. */
+  tmp_ile.in_label = label;
+  lsp = hash_get (lsp_table, &tmp_ile, lsp_alloc);
+  if (!lsp)
+    return -1;
+
+  /* For each active nexthop, create NHLFE. Note that we deliberately skip
+   * recursive nexthops right now, because intermediate hops won't understand
+   * the label advertised by the recursive nexthop (plus we don't have the
+   * logic yet to push multiple labels).
+   */
+  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+    {
+      /* Skip inactive and recursive entries. */
+      if (!CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+        continue;
+      if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+        continue;
+
+      nhlfe = nhlfe_find (lsp, lsp_type, nexthop->type, &nexthop->gate,
+                          nexthop->ifindex);
+      if (nhlfe)
+        {
+          /* Clear deleted flag (in case it was set) */
+          UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_DELETED);
+          if (nexthop_labels_match (nhlfe->nexthop, nexthop))
+            /* No change */
+            continue;
+
+
+          if (IS_ZEBRA_DEBUG_MPLS)
+            {
+              nhlfe2str (nhlfe, buf, BUFSIZ);
+              zlog_debug ("LSP in-label %u type %d nexthop %s "
+                          "out-label changed",
+                          lsp->ile.in_label, lsp_type, buf);
+            }
+
+          /* Update out label, trigger processing. */
+          nhlfe_out_label_update (nhlfe, nexthop->nh_label);
+          SET_FLAG (nhlfe->flags, NHLFE_FLAG_CHANGED);
+          changed++;
+        }
+      else
+        {
+          /* Add LSP entry to this nexthop */
+          nhlfe = nhlfe_add (lsp, lsp_type, nexthop->type,
+                             &nexthop->gate, nexthop->ifindex,
+                             nexthop->nh_label->label[0]);
+          if (!nhlfe)
+            return -1;
+
+          if (IS_ZEBRA_DEBUG_MPLS)
+            {
+              nhlfe2str (nhlfe, buf, BUFSIZ);
+              zlog_debug ("Add LSP in-label %u type %d nexthop %s "
+                          "out-label %u",
+                          lsp->ile.in_label, lsp_type, buf,
+                          nexthop->nh_label->label[0]);
+            }
+
+          lsp->addr_family = NHLFE_FAMILY (nhlfe);
+
+          /* Mark NHLFE as changed. */
+          SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
+          added++;
+        }
+    }
+
+  /* Queue LSP for processing if necessary. If no NHLFE got added (special
+   * case), delete the LSP entry; this case results in somewhat ugly logging.
+   */
+  if (added || changed)
+    {
+      if (lsp_processq_add (lsp))
+        return -1;
+    }
+  else if (!lsp->nhlfe_list &&
+           !CHECK_FLAG (lsp->flags, LSP_FLAG_SCHEDULED))
+    {
+      if (IS_ZEBRA_DEBUG_MPLS)
+        zlog_debug ("Free LSP in-label %u flags 0x%x",
+                    lsp->ile.in_label, lsp->flags);
+
+      lsp = hash_release(lsp_table, &lsp->ile);
+      if (lsp)
+        XFREE(MTYPE_LSP, lsp);
+    }
+
+  return 0;
+}
+
+/*
+ * Uninstall all non-static NHLFEs of a label forwarding entry. If all
+ * NHLFEs are removed, the entire entry is deleted.
+ */
+static int
+lsp_uninstall (struct zebra_vrf *zvrf, mpls_label_t label)
+{
+  struct hash *lsp_table;
+  zebra_ile_t tmp_ile;
+  zebra_lsp_t *lsp;
+  zebra_nhlfe_t *nhlfe, *nhlfe_next;
+  char buf[BUFSIZ];
+
+  /* Lookup table. */
+  lsp_table = zvrf->lsp_table;
+  if (!lsp_table)
+    return -1;
+
+  /* If entry is not present, exit. */
+  tmp_ile.in_label = label;
+  lsp = hash_lookup (lsp_table, &tmp_ile);
+  if (!lsp || !lsp->nhlfe_list)
+    return 0;
+
+  /* Mark NHLFEs for delete or directly delete, as appropriate. */
+  for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe_next)
+    {
+      nhlfe_next = nhlfe->next;
+
+      /* Skip static NHLFEs */
+      if (nhlfe->type == ZEBRA_LSP_STATIC)
+        continue;
+
+      if (IS_ZEBRA_DEBUG_MPLS)
+        {
+          nhlfe2str (nhlfe, buf, BUFSIZ);
+          zlog_debug ("Del LSP in-label %u type %d nexthop %s flags 0x%x",
+                      label, nhlfe->type, buf, nhlfe->flags);
+        }
+
+      if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED))
+        {
+          UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_CHANGED);
+          SET_FLAG (nhlfe->flags, NHLFE_FLAG_DELETED);
+        }
+      else
+        {
+          nhlfe_del (nhlfe);
+        }
+    }
+
+  /* Queue LSP for processing, if needed, else delete. */
+  if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED))
+    {
+      if (lsp_processq_add (lsp))
+        return -1;
+    }
+  else if (!lsp->nhlfe_list &&
+           !CHECK_FLAG (lsp->flags, LSP_FLAG_SCHEDULED))
+    {
+      if (IS_ZEBRA_DEBUG_MPLS)
+        zlog_debug ("Del LSP in-label %u flags 0x%x",
+                    lsp->ile.in_label, lsp->flags);
+
+      lsp = hash_release(lsp_table, &lsp->ile);
+      if (lsp)
+        XFREE(MTYPE_LSP, lsp);
+    }
+
+  return 0;
+}
+
+/*
+ * There is a change for this FEC. Install or uninstall label forwarding
+ * entries, as appropriate.
+ */
+static int
+fec_change_update_lsp (struct zebra_vrf *zvrf, zebra_fec_t *fec, mpls_label_t old_label)
+{
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *rib;
+  afi_t afi;
+
+  /* Uninstall label forwarding entry, if previously installed. */
+  if (old_label != MPLS_INVALID_LABEL &&
+      old_label != MPLS_IMP_NULL_LABEL)
+    lsp_uninstall (zvrf, old_label);
+
+  /* Install label forwarding entry corr. to new label, if needed. */
+  if (fec->label == MPLS_INVALID_LABEL ||
+      fec->label == MPLS_IMP_NULL_LABEL)
+    return 0;
+
+  afi = family2afi(PREFIX_FAMILY(&fec->rn->p));
+  table = zebra_vrf_table (afi, SAFI_UNICAST, zvrf_id (zvrf));
+  if (!table)
+    return 0;
+
+  /* See if labeled route exists. */
+  rn = route_node_lookup (table, &fec->rn->p);
+  if (!rn)
+    return 0;
+
+  RNODE_FOREACH_RIB (rn, rib)
+    {
+      if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+        break;
+    }
+
+  if (!rib || !zebra_rib_labeled_unicast (rib))
+    return 0;
+
+  if (lsp_install (zvrf, fec->label, rn, rib))
+    return -1;
+
+  return 0;
+}
+
 /*
  * Inform about FEC to a registered client.
  */
@@ -760,7 +1007,7 @@ nhlfe2str (zebra_nhlfe_t *nhlfe, char *buf, int size)
  */
 static int
 nhlfe_nhop_match (zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype,
-                  union g_addr *gate, char *ifname, ifindex_t ifindex)
+                  union g_addr *gate, ifindex_t ifindex)
 {
   struct nexthop *nhop;
   int cmp = 1;
@@ -802,7 +1049,7 @@ nhlfe_nhop_match (zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype,
 static zebra_nhlfe_t *
 nhlfe_find (zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
             enum nexthop_types_t gtype, union g_addr *gate,
-            char *ifname, ifindex_t ifindex)
+            ifindex_t ifindex)
 {
   zebra_nhlfe_t *nhlfe;
 
@@ -813,7 +1060,7 @@ nhlfe_find (zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
     {
       if (nhlfe->type != lsp_type)
         continue;
-      if (!nhlfe_nhop_match (nhlfe, gtype, gate, ifname, ifindex))
+      if (!nhlfe_nhop_match (nhlfe, gtype, gate, ifindex))
         break;
     }
 
@@ -827,7 +1074,7 @@ nhlfe_find (zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
 static zebra_nhlfe_t *
 nhlfe_add (zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
            enum nexthop_types_t gtype, union g_addr *gate,
-           char *ifname, ifindex_t ifindex, mpls_label_t out_label)
+           ifindex_t ifindex, mpls_label_t out_label)
 {
   zebra_nhlfe_t *nhlfe;
   struct nexthop *nexthop;
@@ -917,6 +1164,15 @@ nhlfe_del (zebra_nhlfe_t *nhlfe)
   return 0;
 }
 
+/*
+ * Update label for NHLFE entry.
+ */
+static void
+nhlfe_out_label_update (zebra_nhlfe_t *nhlfe, struct nexthop_label *nh_label)
+{
+  nhlfe->nexthop->nh_label->label[0] = nh_label->label[0];
+}
+
 static int
 mpls_lsp_uninstall_all (struct hash *lsp_table, zebra_lsp_t *lsp,
                        enum lsp_types_t type)
@@ -1184,7 +1440,7 @@ slsp_cmp (zebra_slsp_t *slsp1, zebra_slsp_t *slsp2)
  */
 static int
 snhlfe_match (zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype,
-              union g_addr *gate, char *ifname, ifindex_t ifindex)
+              union g_addr *gate, ifindex_t ifindex)
 {
   int cmp = 1;
 
@@ -1216,7 +1472,7 @@ snhlfe_match (zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype,
  */
 static zebra_snhlfe_t *
 snhlfe_find (zebra_slsp_t *slsp, enum nexthop_types_t gtype,
-             union g_addr *gate, char *ifname, ifindex_t ifindex)
+             union g_addr *gate, ifindex_t ifindex)
 {
   zebra_snhlfe_t *snhlfe;
 
@@ -1225,7 +1481,7 @@ snhlfe_find (zebra_slsp_t *slsp, enum nexthop_types_t gtype,
 
   for (snhlfe = slsp->snhlfe_list; snhlfe; snhlfe = snhlfe->next)
     {
-      if (!snhlfe_match (snhlfe, gtype, gate, ifname, ifindex))
+      if (!snhlfe_match (snhlfe, gtype, gate, ifindex))
         break;
     }
 
@@ -1239,7 +1495,7 @@ snhlfe_find (zebra_slsp_t *slsp, enum nexthop_types_t gtype,
  */
 static zebra_snhlfe_t *
 snhlfe_add (zebra_slsp_t *slsp, enum nexthop_types_t gtype,
-            union g_addr *gate, char *ifname, ifindex_t ifindex,
+            union g_addr *gate, ifindex_t ifindex,
             mpls_label_t out_label)
 {
   zebra_snhlfe_t *snhlfe;
@@ -1388,7 +1644,7 @@ mpls_str2label (const char *label_str, u_int8_t *num_labels,
   *num_labels = 0;
   for (i = 0; i < MPLS_MAX_LABELS; i++)
     {
-      u_int32_t label;
+      mpls_label_t label;
 
       label = strtoul(label_str, &endp, 0);
 
@@ -1432,6 +1688,58 @@ mpls_label2str (u_int8_t num_labels, mpls_label_t *labels,
   return buf;
 }
 
+/*
+ * Install dynamic LSP entry.
+ */
+int
+zebra_mpls_lsp_install (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib)
+{
+  struct route_table *table;
+  zebra_fec_t *fec;
+
+  table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))];
+  if (!table)
+    return -1;
+
+  /* See if there is a configured label binding for this FEC. */
+  fec = fec_find (table, &rn->p);
+  if (!fec || fec->label == MPLS_INVALID_LABEL)
+    return 0;
+
+  /* We cannot install a label forwarding entry if local label is the
+   * implicit-null label.
+   */
+  if (fec->label == MPLS_IMP_NULL_LABEL)
+    return 0;
+
+  if (lsp_install (zvrf, fec->label, rn, rib))
+    return -1;
+
+  return 0;
+}
+
+/*
+ * Uninstall dynamic LSP entry, if any.
+ */
+int
+zebra_mpls_lsp_uninstall (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib)
+{
+  struct route_table *table;
+  zebra_fec_t *fec;
+
+  table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))];
+  if (!table)
+    return -1;
+
+  /* See if there is a configured label binding for this FEC. */
+  fec = fec_find (table, &rn->p);
+  if (!fec || fec->label == MPLS_INVALID_LABEL)
+    return 0;
+
+  /* Uninstall always removes all dynamic NHLFEs. */
+  return lsp_uninstall (zvrf, fec->label);
+}
+
 /*
  * Registration from a client for the label binding for a FEC. If a binding
  * already exists, it is informed to the client.
@@ -1611,7 +1919,8 @@ zebra_mpls_label_already_bound (struct zebra_vrf *zvrf, mpls_label_t label)
 
 /*
  * Add static FEC to label binding. If there are clients registered for this
- * FEC, notify them.
+ * FEC, notify them. If there are labeled routes for this FEC, install the
+ * label forwarding entry.
 */
 int
 zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p,
@@ -1620,6 +1929,7 @@ zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p,
   struct route_table *table;
   zebra_fec_t *fec;
   char buf[BUFSIZ];
+  mpls_label_t old_label;
   int ret = 0;
 
   table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
@@ -1652,11 +1962,15 @@ zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p,
         return 0;
 
       /* Label change, update clients. */
+      old_label = fec->label;
       if (IS_ZEBRA_DEBUG_MPLS)
         zlog_debug ("Update fec %s new label %u", buf, in_label);
 
       fec->label = in_label;
       fec_update_clients (fec);
+
+      /* Update label forwarding entries appropriately */
+      ret = fec_change_update_lsp (zvrf, fec, old_label);
     }
 
   return ret;
@@ -1671,6 +1985,7 @@ zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p)
 {
   struct route_table *table;
   zebra_fec_t *fec;
+  mpls_label_t old_label;
   char buf[BUFSIZ];
 
   table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
@@ -1691,6 +2006,7 @@ zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p)
       zlog_debug ("Delete fec %s", buf);
     }
 
+  old_label = fec->label;
   fec->flags &= ~FEC_FLAG_CONFIGURED;
   fec->label = MPLS_INVALID_LABEL;
 
@@ -1703,7 +2019,8 @@ zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p)
 
   fec_update_clients (fec);
 
-  return 0;
+  /* Update label forwarding entries appropriately */
+  return fec_change_update_lsp (zvrf, fec, old_label);
 }
 
 /*
@@ -1879,7 +2196,7 @@ int
 mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type,
                  mpls_label_t in_label, mpls_label_t out_label,
                  enum nexthop_types_t gtype, union g_addr *gate,
-                 char *ifname, ifindex_t ifindex)
+                 ifindex_t ifindex)
 {
   struct hash *lsp_table;
   zebra_ile_t tmp_ile;
@@ -1897,7 +2214,7 @@ mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type,
   lsp = hash_get (lsp_table, &tmp_ile, lsp_alloc);
   if (!lsp)
     return -1;
-  nhlfe = nhlfe_find (lsp, type, gtype, gate, ifname, ifindex);
+  nhlfe = nhlfe_find (lsp, type, gtype, gate, ifindex);
   if (nhlfe)
     {
       struct nexthop *nh = nhlfe->nexthop;
@@ -1926,8 +2243,7 @@ mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type,
   else
     {
       /* Add LSP entry to this nexthop */
-      nhlfe = nhlfe_add (lsp, type, gtype, gate,
-                         ifname, ifindex, out_label);
+      nhlfe = nhlfe_add (lsp, type, gtype, gate, ifindex, out_label);
       if (!nhlfe)
         return -1;
 
@@ -1956,7 +2272,7 @@ mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type,
 int
 mpls_lsp_uninstall (struct zebra_vrf *zvrf, enum lsp_types_t type,
                    mpls_label_t in_label, enum nexthop_types_t gtype,
-                   union g_addr *gate, char *ifname, ifindex_t ifindex)
+                   union g_addr *gate, ifindex_t ifindex)
 {
   struct hash *lsp_table;
   zebra_ile_t tmp_ile;
@@ -1974,7 +2290,7 @@ mpls_lsp_uninstall (struct zebra_vrf *zvrf, enum lsp_types_t type,
   lsp = hash_lookup (lsp_table, &tmp_ile);
   if (!lsp)
     return 0;
-  nhlfe = nhlfe_find (lsp, type, gtype, gate, ifname, ifindex);
+  nhlfe = nhlfe_find (lsp, type, gtype, gate, ifindex);
   if (!nhlfe)
     return 0;
 
@@ -2079,7 +2395,7 @@ mpls_ldp_ftn_uninstall_all (struct zebra_vrf *zvrf, int afi)
 int
 zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label,
                      mpls_label_t out_label, enum nexthop_types_t gtype,
-                     union g_addr *gate, char *ifname, ifindex_t ifindex)
+                     union g_addr *gate, ifindex_t ifindex)
 {
   struct hash *slsp_table;
   zebra_ile_t tmp_ile;
@@ -2097,7 +2413,7 @@ zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label,
   if (!slsp)
     return 1;
 
-  snhlfe = snhlfe_find (slsp, gtype, gate, ifname, ifindex);
+  snhlfe = snhlfe_find (slsp, gtype, gate, ifindex);
   if (snhlfe)
     {
       if (snhlfe->out_label == out_label)
@@ -2137,7 +2453,7 @@ zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label,
 int
 zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label,
                      mpls_label_t out_label, enum nexthop_types_t gtype,
-                     union g_addr *gate, char *ifname, ifindex_t ifindex)
+                     union g_addr *gate, ifindex_t ifindex)
 {
   struct hash *slsp_table;
   zebra_ile_t tmp_ile;
@@ -2155,7 +2471,7 @@ zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label,
   slsp = hash_get (slsp_table, &tmp_ile, slsp_alloc);
   if (!slsp)
     return -1;
-  snhlfe = snhlfe_find (slsp, gtype, gate, ifname, ifindex);
+  snhlfe = snhlfe_find (slsp, gtype, gate, ifindex);
   if (snhlfe)
     {
       if (snhlfe->out_label == out_label)
@@ -2174,7 +2490,7 @@ zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label,
   else
     {
       /* Add static LSP entry to this nexthop */
-      snhlfe = snhlfe_add (slsp, gtype, gate, ifname, ifindex, out_label);
+      snhlfe = snhlfe_add (slsp, gtype, gate, ifindex, out_label);
       if (!snhlfe)
         return -1;
 
@@ -2188,7 +2504,7 @@ zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label,
 
   /* (Re)Install LSP in the main table. */
   if (mpls_lsp_install (zvrf, ZEBRA_LSP_STATIC, in_label, out_label, gtype,
-      gate, ifname, ifindex))
+      gate, ifindex))
     return -1;
 
   return 0;
@@ -2204,7 +2520,7 @@ zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label,
 int
 zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label,
                            enum nexthop_types_t gtype, union g_addr *gate,
-                           char *ifname, ifindex_t ifindex)
+                           ifindex_t ifindex)
 {
   struct hash *slsp_table;
   zebra_ile_t tmp_ile;
@@ -2237,7 +2553,7 @@ zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label,
   else
     {
       /* Find specific NHLFE, exit if not found. */
-      snhlfe = snhlfe_find (slsp, gtype, gate, ifname, ifindex);
+      snhlfe = snhlfe_find (slsp, gtype, gate, ifindex);
       if (!snhlfe)
         return 0;
 
@@ -2251,7 +2567,7 @@ zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label,
 
       /* Uninstall LSP from the main table. */
       mpls_lsp_uninstall (zvrf, ZEBRA_LSP_STATIC, in_label, gtype, gate,
-                         ifname, ifindex);
+                         ifindex);
 
       /* Delete static LSP NHLFE */
       snhlfe_del (snhlfe);
index 4636a28c10c2c6965aa10ba125ec52576a7defc9..f9d58a46e80eab4a720b5d8d3499d05cc2c72c35 100644 (file)
@@ -183,6 +183,18 @@ char *
 mpls_label2str (u_int8_t num_labels, mpls_label_t *labels,
                 char *buf, int len);
 
+/*
+ * Install dynamic LSP entry.
+ */
+int
+zebra_mpls_lsp_install (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib);
+
+/*
+ * Uninstall dynamic LSP entry, if any. 
+ */
+int
+zebra_mpls_lsp_uninstall (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib);
+
 /*
  * Registration from a client for the label binding for a FEC. If a binding
  * already exists, it is informed to the client.
@@ -224,7 +236,8 @@ zebra_mpls_label_already_bound (struct zebra_vrf *zvrf, mpls_label_t label);
 
 /*
  * Add static FEC to label binding. If there are clients registered for this
- * FEC, notify them.
+ * FEC, notify them. If there are labeled routes for this FEC, install the
+ * label forwarding entry.
  */
 int
 zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p,
@@ -273,7 +286,7 @@ int
 mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type,
                  mpls_label_t in_label, mpls_label_t out_label,
                  enum nexthop_types_t gtype, union g_addr *gate,
-                 char *ifname, ifindex_t ifindex);
+                 ifindex_t ifindex);
 
 /*
  * Uninstall a particular NHLFE in the forwarding table. If this is
@@ -282,7 +295,7 @@ mpls_lsp_install (struct zebra_vrf *zvrf, enum lsp_types_t type,
 int
 mpls_lsp_uninstall (struct zebra_vrf *zvrf, enum lsp_types_t type,
                    mpls_label_t in_label, enum nexthop_types_t gtype,
-                   union g_addr *gate, char *ifname, ifindex_t ifindex);
+                   union g_addr *gate, ifindex_t ifindex);
 
 /*
  * Uninstall all LDP NHLFEs for a particular LSP forwarding entry.
@@ -307,7 +320,7 @@ mpls_ldp_ftn_uninstall_all (struct zebra_vrf *zvrf, int afi);
 int
 zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label,
                      mpls_label_t out_label, enum nexthop_types_t gtype,
-                     union g_addr *gate, char *ifname, ifindex_t ifindex);
+                     union g_addr *gate, ifindex_t ifindex);
 #endif /* HAVE_CUMULUS */
 
 /*
@@ -320,7 +333,7 @@ zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label,
 int
 zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label,
                      mpls_label_t out_label, enum nexthop_types_t gtype,
-                     union g_addr *gate, char *ifname, ifindex_t ifindex);
+                     union g_addr *gate, ifindex_t ifindex);
 
 /*
  * Delete static LSP entry. This may be the delete of one particular
@@ -332,7 +345,7 @@ zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label,
 int
 zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label,
                            enum nexthop_types_t gtype, union g_addr *gate,
-                           char *ifname, ifindex_t ifindex);
+                           ifindex_t ifindex);
 
 /*
  * Schedule all MPLS label forwarding entries for processing.
@@ -415,6 +428,8 @@ lsp_type_from_rib_type (int rib_type)
     {
       case ZEBRA_ROUTE_STATIC:
         return ZEBRA_LSP_STATIC;
+      case ZEBRA_ROUTE_BGP:
+        return ZEBRA_LSP_BGP;
       default:
         return ZEBRA_LSP_NONE;
     }
@@ -430,6 +445,8 @@ nhlfe_type2str(enum lsp_types_t lsp_type)
         return "Static";
       case ZEBRA_LSP_LDP:
         return "LDP";
+      case ZEBRA_LSP_BGP:
+        return "BGP";
       default:
         return "Unknown";
     }
index 29990928d3d0bbae7551f8c35e55d338fd4ee9cc..d6f99b517838f82a88eb8d92d86927cd9ceca848 100644 (file)
@@ -44,6 +44,18 @@ mpls_str2label (const char *label_str, u_int8_t *num_labels,
   return 0;
 }
 
+int
+zebra_mpls_lsp_install (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib)
+{
+  return 0;
+}
+
+int
+zebra_mpls_lsp_uninstall (struct zebra_vrf *zvrf, struct route_node *rn, struct rib *rib)
+{
+  return 0;
+}
+
 void
 zebra_mpls_init_tables (struct zebra_vrf *zvrf)
 {
@@ -70,7 +82,7 @@ zebra_mpls_write_lsp_config (struct vty *vty, struct zebra_vrf *zvrf)
 int
 zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label,
                                  mpls_label_t out_label, enum nexthop_types_t gtype,
-                                 union g_addr *gate, char *ifname, ifindex_t ifindex)
+                                 union g_addr *gate, ifindex_t ifindex)
 {
   return 0;
 }
@@ -78,7 +90,7 @@ zebra_mpls_lsp_label_consistent (struct zebra_vrf *zvrf, mpls_label_t in_label,
 int
 zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label,
                            mpls_label_t out_label, enum nexthop_types_t gtype,
-                           union g_addr *gate, char *ifname, ifindex_t ifindex)
+                           union g_addr *gate, ifindex_t ifindex)
 {
   return 0;
 }
@@ -86,7 +98,7 @@ zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label,
 int
 zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label,
                            enum nexthop_types_t gtype, union g_addr *gate,
-                           char *ifname, ifindex_t ifindex)
+                           ifindex_t ifindex)
 {
   return 0;
 }
index 90624c12a4585a3999967be9aef5b846ae4d5ebf..8d8025682a509a12d0dcdae7a32fb8a0671832be 100644 (file)
@@ -133,7 +133,7 @@ zebra_mpls_transit_lsp (struct vty *vty, int add_cmd, const char *inlabel_str,
 #if defined(HAVE_CUMULUS)
       /* Check that label value is consistent. */
       if (!zebra_mpls_lsp_label_consistent (zvrf, in_label, out_label, gtype,
-                                            &gate, NULL, 0))
+                                            &gate, 0))
         {
           vty_out (vty, "%% Label value not consistent%s",
                    VTY_NEWLINE);
@@ -142,10 +142,10 @@ zebra_mpls_transit_lsp (struct vty *vty, int add_cmd, const char *inlabel_str,
 #endif /* HAVE_CUMULUS */
 
       ret = zebra_mpls_static_lsp_add (zvrf, in_label, out_label, gtype,
-                                       &gate, NULL, 0);
+                                       &gate, 0);
     }
   else
-    ret = zebra_mpls_static_lsp_del (zvrf, in_label, gtype, &gate, NULL, 0);
+    ret = zebra_mpls_static_lsp_del (zvrf, in_label, gtype, &gate, 0);
 
   if (ret)
     {
index b3e70e46fa9eaa558a6d6e4d4c59d85e85a0835b..e4d583d5f2ae7f8eb017c0f531c37157ed439e49 100644 (file)
@@ -1084,7 +1084,25 @@ nexthop_active_update (struct route_node *rn, struct rib *rib, int set)
   return rib->nexthop_active_num;
 }
 
+/*
+ * Is this RIB labeled-unicast? It must be of type BGP and all paths
+ * (nexthops) must have a label.
+ */
+int
+zebra_rib_labeled_unicast (struct rib *rib)
+{
+  struct nexthop *nexthop = NULL, *tnexthop;
+  int recursing;
+
+  if (rib->type != ZEBRA_ROUTE_BGP)
+    return 0;
+
+  for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
+    if (!nexthop->nh_label || !nexthop->nh_label->num_labels)
+      return 0;
 
+  return 1;
+}
 
 /* Update flag indicates whether this is a "replace" or not. Currently, this
  * is only used for IPv4.
@@ -1177,7 +1195,12 @@ rib_uninstall (struct route_node *rn, struct rib *rib)
 
       if (! RIB_SYSTEM_ROUTE (rib))
        rib_uninstall_kernel (rn, rib);
-      UNSET_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB);
+
+      /* If labeled-unicast route, uninstall transit LSP. */
+      if (zebra_rib_labeled_unicast (rib))
+        zebra_mpls_lsp_uninstall (info->zvrf, rn, rib);
+
+       UNSET_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB);
     }
 
   if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
@@ -1272,6 +1295,10 @@ rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn,
                    zvrf_id (zvrf), buf, rn, new, new->type);
     }
 
+  /* If labeled-unicast route, install transit LSP. */
+  if (zebra_rib_labeled_unicast (new))
+    zebra_mpls_lsp_install (zvrf, rn, new);
+
   if (!RIB_SYSTEM_ROUTE (new))
     {
       if (rib_install_kernel (rn, new, NULL))
@@ -1301,6 +1328,10 @@ rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn,
                   zvrf_id (zvrf), buf, rn, old, old->type);
     }
 
+  /* If labeled-unicast route, uninstall transit LSP. */
+  if (zebra_rib_labeled_unicast (old))
+    zebra_mpls_lsp_uninstall (zvrf, rn, old);
+
   if (!RIB_SYSTEM_ROUTE (old))
     rib_uninstall_kernel (rn, old);
 
@@ -1354,6 +1385,10 @@ rib_process_update_fib (struct zebra_vrf *zvrf, struct route_node *rn,
           /* Non-system route should be installed. */
           if (!RIB_SYSTEM_ROUTE (new))
             {
+              /* If labeled-unicast route, install transit LSP. */
+              if (zebra_rib_labeled_unicast (new))
+                zebra_mpls_lsp_install (zvrf, rn, new);
+
               if (rib_install_kernel (rn, new, old))
                 {
                   char buf[SRCDEST2STR_BUFFER];
@@ -1368,6 +1403,10 @@ rib_process_update_fib (struct zebra_vrf *zvrf, struct route_node *rn,
             {
               if (RIB_SYSTEM_ROUTE(new))
                 {
+                  /* If labeled-unicast route, uninstall transit LSP. */
+                  if (zebra_rib_labeled_unicast (old))
+                    zebra_mpls_lsp_uninstall (zvrf, rn, old);
+
                   if (!RIB_SYSTEM_ROUTE (old))
                     rib_uninstall_kernel (rn, old);
                 }
@@ -1404,6 +1443,10 @@ rib_process_update_fib (struct zebra_vrf *zvrf, struct route_node *rn,
                             nh_active ? "install failed" : "nexthop inactive");
             }
 
+          /* If labeled-unicast route, uninstall transit LSP. */
+          if (zebra_rib_labeled_unicast (old))
+            zebra_mpls_lsp_uninstall (zvrf, rn, old);
+
           if (!RIB_SYSTEM_ROUTE (old))
             rib_uninstall_kernel (rn, old);
           UNSET_FLAG (new->status, RIB_ENTRY_SELECTED_FIB);
@@ -2934,8 +2977,10 @@ rib_tables_iter_next (rib_tables_iter_t *iter)
   } afi_safis[] = {
     { AFI_IP, SAFI_UNICAST },
     { AFI_IP, SAFI_MULTICAST },
+    { AFI_IP, SAFI_LABELED_UNICAST },
     { AFI_IP6, SAFI_UNICAST },
     { AFI_IP6, SAFI_MULTICAST },
+    { AFI_IP6, SAFI_LABELED_UNICAST },
   };
 
   table = NULL;
index 73ea58980565ebfe03d65d4885052e113ed760fb..c11f1bf3fd822929c478ef898c9e71280ef6be20 100644 (file)
@@ -1129,13 +1129,15 @@ zread_ipv4_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
   struct rib *rib;
   struct prefix p;
   u_char message;
-  struct in_addr nexthop;
+  struct in_addr nhop_addr;
   u_char nexthop_num;
   u_char nexthop_type;
   struct stream *s;
   ifindex_t ifindex;
   safi_t safi;
   int ret;
+  mpls_label_t label;
+  struct nexthop *nexthop;
 
   /* Get input stream.  */
   s = client->ibuf;
@@ -1177,13 +1179,19 @@ zread_ipv4_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
              rib_nexthop_ifindex_add (rib, ifindex);
              break;
            case NEXTHOP_TYPE_IPV4:
-             nexthop.s_addr = stream_get_ipv4 (s);
-             rib_nexthop_ipv4_add (rib, &nexthop, NULL);
+              nhop_addr.s_addr = stream_get_ipv4 (s);
+              nexthop = rib_nexthop_ipv4_add (rib, &nhop_addr, NULL);
+              /* For labeled-unicast, each nexthop is followed by label. */
+              if (CHECK_FLAG (message, ZAPI_MESSAGE_LABEL))
+                {
+                  label = (mpls_label_t)stream_getl (s);
+                  nexthop_add_labels (nexthop, nexthop->nh_label_type, 1, &label);
+                }
              break;
            case NEXTHOP_TYPE_IPV4_IFINDEX:
-             nexthop.s_addr = stream_get_ipv4 (s);
+             nhop_addr.s_addr = stream_get_ipv4 (s);
              ifindex = stream_getl (s);
-             rib_nexthop_ipv4_ifindex_add (rib, &nexthop, NULL, ifindex);
+             rib_nexthop_ipv4_ifindex_add (rib, &nhop_addr, NULL, ifindex);
              break;
            case NEXTHOP_TYPE_IPV6:
              stream_forward_getp (s, IPV6_MAX_BYTELEN);
@@ -1276,6 +1284,11 @@ zread_ipv4_delete (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
              break;
            case NEXTHOP_TYPE_IPV4:
              nexthop.s_addr = stream_get_ipv4 (s);
+              /* For labeled-unicast, each nexthop is followed by label, but
+               * we don't care for delete.
+               */
+              if (CHECK_FLAG (api.message, ZAPI_MESSAGE_LABEL))
+                stream_forward_getp (s, sizeof(u_int32_t));
              nexthop_p = (union g_addr *)&nexthop;
              break;
            case NEXTHOP_TYPE_IPV4_IFINDEX:
@@ -1461,7 +1474,7 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
 {
   unsigned int i;
   struct stream *s;
-  struct in6_addr nexthop;
+  struct in6_addr nhop_addr;
   struct rib *rib;
   u_char message;
   u_char nexthop_num;
@@ -1472,11 +1485,14 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
   static struct in6_addr nexthops[MULTIPATH_NUM];
   static unsigned int ifindices[MULTIPATH_NUM];
   int ret;
+  static mpls_label_t labels[MULTIPATH_NUM];
+  mpls_label_t label;
+  struct nexthop *nexthop;
 
   /* Get input stream.  */
   s = client->ibuf;
 
-  memset (&nexthop, 0, sizeof (struct in6_addr));
+  memset (&nhop_addr, 0, sizeof (struct in6_addr));
 
   /* Allocate new rib. */
   rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
@@ -1525,10 +1541,17 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
          switch (nexthop_type)
            {
            case NEXTHOP_TYPE_IPV6:
-             stream_get (&nexthop, s, 16);
-              if (nh_count < multipath_num) {
-               nexthops[nh_count++] = nexthop;
-              }
+              stream_get (&nhop_addr, s, 16);
+              if (nh_count < MULTIPATH_NUM)
+                {
+                  /* For labeled-unicast, each nexthop is followed by label. */
+                  if (CHECK_FLAG (message, ZAPI_MESSAGE_LABEL))
+                    {
+                      label = (mpls_label_t)stream_getl (s);
+                     labels[nh_count++] = label;
+                    }
+                 nexthops[nh_count++] = nhop_addr;
+                }
              break;
            case NEXTHOP_TYPE_IFINDEX:
               if (if_count < multipath_num) {
@@ -1546,9 +1569,11 @@ zread_ipv6_add (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
         {
          if ((i < nh_count) && !IN6_IS_ADDR_UNSPECIFIED (&nexthops[i])) {
             if ((i < if_count) && ifindices[i])
-              rib_nexthop_ipv6_ifindex_add (rib, &nexthops[i], ifindices[i]);
+              nexthop = rib_nexthop_ipv6_ifindex_add (rib, &nexthops[i], ifindices[i]);
             else
-             rib_nexthop_ipv6_add (rib, &nexthops[i]);
+             nexthop = rib_nexthop_ipv6_add (rib, &nexthops[i]);
+            if (CHECK_FLAG (message, ZAPI_MESSAGE_LABEL))
+              nexthop_add_labels (nexthop, nexthop->nh_label_type, 1, &labels[i]);
           }
           else {
             if ((i < if_count) && ifindices[i])
@@ -1645,6 +1670,11 @@ zread_ipv6_delete (struct zserv *client, u_short length, struct zebra_vrf *zvrf)
            {
            case NEXTHOP_TYPE_IPV6:
              stream_get (&nexthop, s, 16);
+              /* For labeled-unicast, each nexthop is followed by label, but
+               * we don't care for delete.
+               */
+              if (CHECK_FLAG (api.message, ZAPI_MESSAGE_LABEL))
+                stream_forward_getp (s, sizeof(u_int32_t));
              pnexthop = (union g_addr *)&nexthop;
              break;
            case NEXTHOP_TYPE_IFINDEX:
@@ -1815,14 +1845,14 @@ zread_mpls_labels (int command, struct zserv *client, u_short length,
   if (command == ZEBRA_MPLS_LABELS_ADD)
     {
       mpls_lsp_install (zvrf, type, in_label, out_label, gtype, &gate,
-                       NULL, ifindex);
+                       ifindex);
       if (out_label != MPLS_IMP_NULL_LABEL)
        mpls_ftn_update (1, zvrf, type, &prefix, gtype, &gate, ifindex,
                         distance, out_label);
     }
   else if (command == ZEBRA_MPLS_LABELS_DELETE)
     {
-      mpls_lsp_uninstall (zvrf, type, in_label, gtype, &gate, NULL, ifindex);
+      mpls_lsp_uninstall (zvrf, type, in_label, gtype, &gate, ifindex);
       if (out_label != MPLS_IMP_NULL_LABEL)
        mpls_ftn_update (0, zvrf, type, &prefix, gtype, &gate, ifindex,
                         distance, out_label);