]> git.proxmox.com Git - mirror_frr.git/commitdiff
mpls: add support for LDP LSPs
authorRenato Westphal <renato@opensourcerouting.org>
Wed, 1 Jun 2016 17:19:30 +0000 (14:19 -0300)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Fri, 23 Sep 2016 13:31:12 +0000 (09:31 -0400)
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
ldpd/ldp_zebra.c
lib/log.c
lib/mpls.h
lib/nexthop.c
lib/nexthop.h
lib/zebra.h
zebra/zebra_mpls.c
zebra/zebra_mpls.h
zebra/zebra_rib.c
zebra/zebra_static.c
zebra/zserv.c

index 41ff47fba36c140646f363e1cdfaa9534a83cc77..6e19e4f6070e84b4f238658100a85f5f8c0c5818 100644 (file)
@@ -28,6 +28,7 @@
 #include "command.h"
 #include "network.h"
 #include "linklist.h"
+#include "mpls.h"
 
 #include "ldpd.h"
 #include "ldpe.h"
@@ -38,6 +39,7 @@
 static void     ifp2kif(struct interface *, struct kif *);
 static void     ifc2kaddr(struct interface *, struct connected *,
                    struct kaddr *);
+static int      zebra_send_mpls_labels(int, struct kroute *);
 static int      ldp_router_id_update(int, struct zclient *, zebra_size_t,
                    vrf_id_t);
 static int      ldp_interface_add(int, struct zclient *, zebra_size_t,
@@ -89,18 +91,62 @@ ifc2kaddr(struct interface *ifp, struct connected *ifc, struct kaddr *ka)
        }
 }
 
+static int
+zebra_send_mpls_labels(int cmd, struct kroute *kr)
+{
+       struct stream           *s;
+
+       if (kr->local_label < MPLS_LABEL_RESERVED_MAX ||
+           kr->remote_label == NO_LABEL)
+               return (0);
+
+       debug_zebra_out("prefix %s/%u nexthop %s labels %s/%s (%s)",
+           log_addr(kr->af, &kr->prefix), kr->prefixlen,
+           log_addr(kr->af, &kr->nexthop), log_label(kr->local_label),
+           log_label(kr->remote_label),
+           (cmd == ZEBRA_MPLS_LABELS_ADD) ? "add" : "delete");
+
+       /* Reset stream. */
+       s = zclient->obuf;
+       stream_reset(s);
+
+       zclient_create_header(s, cmd, VRF_DEFAULT);
+       stream_putc(s, ZEBRA_LSP_LDP);
+       stream_putl(s, kr->af);
+       switch (kr->af) {
+       case AF_INET:
+               stream_put_in_addr(s, &kr->prefix.v4);
+               stream_putc(s, kr->prefixlen);
+               stream_put_in_addr(s, &kr->nexthop.v4);
+               break;
+       case AF_INET6:
+               stream_write(s, (u_char *)&kr->prefix.v6, 16);
+               stream_putc(s, kr->prefixlen);
+               stream_write(s, (u_char *)&kr->nexthop.v6, 16);
+               break;
+       default:
+               fatalx("kr_change: unknown af");
+       }
+       stream_putc(s, kr->priority);
+       stream_putl(s, kr->local_label);
+       stream_putl(s, kr->remote_label);
+
+       /* Put length at the first point of the stream. */
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       return (zclient_send_message(zclient));
+}
+
 int
 kr_change(struct kroute *kr)
 {
-       /* TODO */
-       return (0);
+       return (zebra_send_mpls_labels(ZEBRA_MPLS_LABELS_ADD, kr));
 }
 
 int
 kr_delete(struct kroute *kr)
 {
-       /* TODO */
-       return (0);
+       return (zebra_send_mpls_labels(ZEBRA_MPLS_LABELS_DELETE, kr));
 }
 
 int
index 14fa81a9d75a221f0ada53c90cc7f92e9b798177..fb7b33dcf9dc1c3e88d876c65ebc48869b2057b8 100644 (file)
--- a/lib/log.c
+++ b/lib/log.c
@@ -939,6 +939,8 @@ static const struct zebra_desc_table command_types[] = {
   DESC_ENTRY    (ZEBRA_INTERFACE_ENABLE_RADV),
   DESC_ENTRY    (ZEBRA_INTERFACE_DISABLE_RADV),
   DESC_ENTRY    (ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB),
+  DESC_ENTRY   (ZEBRA_MPLS_LABELS_ADD),
+  DESC_ENTRY   (ZEBRA_MPLS_LABELS_DELETE),
 };
 #undef DESC_ENTRY
 
index 5a67b915d1988aa9a9f7ce0ed326c83556d47ec6..1f77aaa536f96dd038879ce4f999bab0c9251d25 100644 (file)
@@ -75,8 +75,17 @@ typedef unsigned int mpls_lse_t;
 /* MPLS label value as a 32-bit (mostly we only care about the label value). */
 typedef unsigned int mpls_label_t;
 
+#define MPLS_NO_LABEL                      0xFFFFFFFF
 #define MPLS_INVALID_LABEL                 0xFFFFFFFF
 
+/* LSP types. */
+enum lsp_types_t
+{
+  ZEBRA_LSP_NONE = 0,        /* No LSP. */
+  ZEBRA_LSP_STATIC = 1,      /* Static LSP. */
+  ZEBRA_LSP_LDP = 2          /* LDP LSP. */
+};
+
 /* Functions for basic label operations. */
 
 /* Encode a label stack entry from fields; convert to network byte-order as
index 8e775b68be341198e556733dffd0c3844d7abd42..01771e253c02bac8c3319a71e3aa0f82c5c99fca 100644 (file)
@@ -130,8 +130,8 @@ copy_nexthops (struct nexthop **tnh, struct nexthop *nh)
       memcpy(&(nexthop->gate), &(nh->gate), sizeof(union g_addr));
       memcpy(&(nexthop->src), &(nh->src), sizeof(union g_addr));
       if (nh->nh_label)
-        nexthop_add_labels (nexthop, nh->nh_label->num_labels,
-                            &nh->nh_label->label[0]);
+        nexthop_add_labels (nexthop, nh->nh_label_type,
+                           nh->nh_label->num_labels, &nh->nh_label->label[0]);
       nexthop_add(tnh, nexthop);
 
       if (CHECK_FLAG(nh1->flags, NEXTHOP_FLAG_RECURSIVE))
@@ -164,12 +164,13 @@ nexthops_free (struct nexthop *nexthop)
 
 /* Update nexthop with label information. */
 void
-nexthop_add_labels (struct nexthop *nexthop, u_int8_t num_labels,
-                    mpls_label_t *label)
+nexthop_add_labels (struct nexthop *nexthop, enum lsp_types_t type,
+                   u_int8_t num_labels, mpls_label_t *label)
 {
   struct nexthop_label *nh_label;
   int i;
 
+  nexthop->nh_label_type = type;
   nh_label = XCALLOC (MTYPE_NH_LABEL, sizeof (struct nexthop_label));
   nh_label->num_labels = num_labels;
   for (i = 0; i < num_labels; i++)
@@ -182,7 +183,10 @@ void
 nexthop_del_labels (struct nexthop *nexthop)
 {
   if (nexthop->nh_label)
-    XFREE (MTYPE_NH_LABEL, nexthop->nh_label);
+    {
+      XFREE (MTYPE_NH_LABEL, nexthop->nh_label);
+      nexthop->nh_label_type = ZEBRA_LSP_NONE;
+    }
 }
 
 const char *
index c06dfe0e25ac30997316d57bb9ceacb810ddf0bb..e66e0eee20ef08eb0221c60238c6bc3340a616ac 100644 (file)
@@ -85,6 +85,9 @@ struct nexthop
    * Only one level of recursive resolution is currently supported. */
   struct nexthop *resolved;
 
+  /* Type of label(s), if any */
+  enum lsp_types_t nh_label_type;
+
   /* Label(s) associated with this nexthop. */
   struct nexthop_label *nh_label;
 };
@@ -109,7 +112,7 @@ void copy_nexthops (struct nexthop **tnh, struct nexthop *nh);
 void nexthop_free (struct nexthop *nexthop);
 void nexthops_free (struct nexthop *nexthop);
 
-void nexthop_add_labels (struct nexthop *, u_int8_t, mpls_label_t *);
+void nexthop_add_labels (struct nexthop *, enum lsp_types_t, u_int8_t, mpls_label_t *);
 void nexthop_del_labels (struct nexthop *);
 
 extern const char *nexthop_type_to_str (enum nexthop_types_t nh_type);
index d7a441c2e95d904b3319a3be9ad50e873edeb5e2..da069d1dfa311200d0b98f2649644e1451865e65 100644 (file)
@@ -422,6 +422,8 @@ typedef enum {
   ZEBRA_INTERFACE_DISABLE_RADV,
   ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB,
   ZEBRA_INTERFACE_LINK_PARAMS,
+  ZEBRA_MPLS_LABELS_ADD,
+  ZEBRA_MPLS_LABELS_DELETE,
 } zebra_message_types_t;
 
 /* Marker value used in new Zserv, in the byte location corresponding
index 3e841147721771f2a02b547b2e4c21ababb1554f..8f18f326d1282b0aeda04b695f473b506fc182dd 100644 (file)
@@ -99,15 +99,10 @@ nhlfe_add (zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
 static int
 nhlfe_del (zebra_nhlfe_t *snhlfe);
 static int
-static_lsp_install (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);
+mpls_lsp_uninstall_all (struct hash *lsp_table, zebra_lsp_t *lsp,
+                       enum lsp_types_t type);
 static int
-static_lsp_uninstall (struct zebra_vrf *zvrf, mpls_label_t in_label,
-                      enum nexthop_types_t gtype, union g_addr *gate,
-                      char *ifname, ifindex_t ifindex);
-static int
-static_lsp_uninstall_all (struct zebra_vrf *zvrf, mpls_label_t in_label);
+mpls_static_lsp_uninstall_all (struct zebra_vrf *zvrf, mpls_label_t in_label);
 static void
 nhlfe_print (zebra_nhlfe_t *nhlfe, struct vty *vty);
 static void
@@ -684,7 +679,7 @@ nhlfe_add (zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
       XFREE (MTYPE_NHLFE, nhlfe);
       return NULL;
     }
-  nexthop_add_labels (nexthop, 1, &out_label);
+  nexthop_add_labels (nexthop, lsp_type, 1, &out_label);
 
   nexthop->type = gtype;
   switch (nexthop->type)
@@ -746,190 +741,28 @@ nhlfe_del (zebra_nhlfe_t *nhlfe)
   return 0;
 }
 
-
-/*
- * Install/update a static NHLFE for an LSP in the forwarding table. This may
- * be a new LSP entry or a new NHLFE for an existing in-label or an update of
- * the out-label for an existing NHLFE (update case).
- */
 static int
-static_lsp_install (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)
+mpls_lsp_uninstall_all (struct hash *lsp_table, zebra_lsp_t *lsp,
+                       enum lsp_types_t type)
 {
-  struct hash *lsp_table;
-  zebra_ile_t tmp_ile;
-  zebra_lsp_t *lsp;
-  zebra_nhlfe_t *nhlfe;
-  char buf[BUFSIZ];
-
-  /* Lookup table. */
-  lsp_table = zvrf->lsp_table;
-  if (!lsp_table)
-    return -1;
-
-  /* If entry is present, exit. */
-  tmp_ile.in_label = in_label;
-  lsp = hash_get (lsp_table, &tmp_ile, lsp_alloc);
-  if (!lsp)
-    return -1;
-  nhlfe = nhlfe_find (lsp, ZEBRA_LSP_STATIC, gtype, gate, ifname, ifindex);
-  if (nhlfe)
-    {
-      struct nexthop *nh = nhlfe->nexthop;
-
-      assert (nh);
-      assert (nh->nh_label);
-
-      /* Clear deleted flag (in case it was set) */
-      UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_DELETED);
-      if (nh->nh_label->label[0] == out_label)
-        /* No change */
-        return 0;
-
-      if (IS_ZEBRA_DEBUG_MPLS)
-        {
-          nhlfe2str (nhlfe, buf, BUFSIZ);
-          zlog_debug ("LSP in-label %u type %d nexthop %s "
-                      "out-label changed to %u (old %u)",
-                      in_label, ZEBRA_LSP_STATIC, buf,
-                      out_label, nh->nh_label->label[0]);
-        }
-
-      /* Update out label, trigger processing. */
-      nh->nh_label->label[0] = out_label;
-    }
-  else
-    {
-      /* Add LSP entry to this nexthop */
-      nhlfe = nhlfe_add (lsp, ZEBRA_LSP_STATIC, gtype, gate,
-                         ifname, ifindex, out_label);
-      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",
-                      in_label, ZEBRA_LSP_STATIC, buf,
-                      out_label);
-        }
-
-      lsp->addr_family = NHLFE_FAMILY (nhlfe);
-    }
-
-  /* Mark NHLFE, queue LSP for processing. */
-  SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
-  if (lsp_processq_add (lsp))
-    return -1;
-
-  return 0;
-}
-
-/*
- * Uninstall a particular static NHLFE in the forwarding table. If this is
- * the only NHLFE, the entire LSP forwarding entry has to be deleted.
- */
-static int
-static_lsp_uninstall (struct zebra_vrf *zvrf, mpls_label_t in_label,
-                      enum nexthop_types_t gtype, union g_addr *gate,
-                      char *ifname, ifindex_t ifindex)
-{
-  struct hash *lsp_table;
-  zebra_ile_t tmp_ile;
-  zebra_lsp_t *lsp;
-  zebra_nhlfe_t *nhlfe;
-  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 = in_label;
-  lsp = hash_lookup (lsp_table, &tmp_ile);
-  if (!lsp)
-    return 0;
-  nhlfe = nhlfe_find (lsp, ZEBRA_LSP_STATIC, gtype, gate, ifname, ifindex);
-  if (!nhlfe)
-    return 0;
-
-  if (IS_ZEBRA_DEBUG_MPLS)
-    {
-      nhlfe2str (nhlfe, buf, BUFSIZ);
-      zlog_debug ("Del LSP in-label %u type %d nexthop %s flags 0x%x",
-                  in_label, ZEBRA_LSP_STATIC, buf, nhlfe->flags);
-    }
-
-  /* Mark NHLFE for delete or directly delete, as appropriate. */
-  if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED))
-    {
-      UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_CHANGED);
-      SET_FLAG (nhlfe->flags, NHLFE_FLAG_DELETED);
-      if (lsp_processq_add (lsp))
-        return -1;
-    }
-  else
-    {
-      nhlfe_del (nhlfe);
-
-      /* Free LSP entry if no other NHLFEs and not scheduled. */
-      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 static NHLFEs for a particular LSP forwarding entry.
- * If no other NHLFEs exist, the entry would be deleted.
- */
-static int
-static_lsp_uninstall_all (struct zebra_vrf *zvrf, mpls_label_t in_label)
-{
-  struct hash *lsp_table;
-  zebra_ile_t tmp_ile;
-  zebra_lsp_t *lsp;
   zebra_nhlfe_t *nhlfe, *nhlfe_next;
   int schedule_lsp = 0;
   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 = in_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 non-static NHLFEs */
-      if (nhlfe->type != ZEBRA_LSP_STATIC)
+      if (nhlfe->type != type)
         continue;
 
       if (IS_ZEBRA_DEBUG_MPLS)
         {
           nhlfe2str (nhlfe, buf, BUFSIZ);
           zlog_debug ("Del LSP in-label %u type %d nexthop %s flags 0x%x",
-                      in_label, ZEBRA_LSP_STATIC, buf, nhlfe->flags);
+                      lsp->ile.in_label, type, buf, nhlfe->flags);
         }
 
       if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED))
@@ -965,6 +798,31 @@ static_lsp_uninstall_all (struct zebra_vrf *zvrf, mpls_label_t in_label)
   return 0;
 }
 
+/*
+ * Uninstall all static NHLFEs for a particular LSP forwarding entry.
+ * If no other NHLFEs exist, the entry would be deleted.
+ */
+static int
+mpls_static_lsp_uninstall_all (struct zebra_vrf *zvrf, mpls_label_t in_label)
+{
+  struct hash *lsp_table;
+  zebra_ile_t tmp_ile;
+  zebra_lsp_t *lsp;
+
+  /* Lookup table. */
+  lsp_table = zvrf->lsp_table;
+  if (!lsp_table)
+    return -1;
+
+  /* If entry is not present, exit. */
+  tmp_ile.in_label = in_label;
+  lsp = hash_lookup (lsp_table, &tmp_ile);
+  if (!lsp || !lsp->nhlfe_list)
+    return 0;
+
+  return mpls_lsp_uninstall_all (lsp_table, lsp, ZEBRA_LSP_STATIC);
+}
+
 static json_object *
 nhlfe_json (zebra_nhlfe_t *nhlfe)
 {
@@ -1394,6 +1252,274 @@ mpls_label2str (u_int8_t num_labels, mpls_label_t *labels,
   return buf;
 }
 
+/*
+ * Install/uninstall a FEC-To-NHLFE (FTN) binding.
+ */
+int
+mpls_ftn_update (int add, struct zebra_vrf *zvrf, enum lsp_types_t type,
+                struct prefix *prefix, union g_addr *gate, u_int8_t distance,
+                mpls_label_t out_label)
+{
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *rib;
+  struct nexthop *nexthop;
+
+  /* Lookup table.  */
+  table = zebra_vrf_table (family2afi(prefix->family), SAFI_UNICAST, zvrf->vrf_id);
+  if (! table)
+    return -1;
+
+  /* Lookup existing route */
+  rn = route_node_get (table, prefix);
+  RNODE_FOREACH_RIB (rn, rib)
+    {
+       if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
+         continue;
+       if (rib->distance == distance)
+         break;
+    }
+
+  if (rib == NULL)
+    return -1;
+
+  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+    switch (prefix->family)
+      {
+       case AF_INET:
+         if (nexthop->type != NEXTHOP_TYPE_IPV4 &&
+             nexthop->type != NEXTHOP_TYPE_IPV4_IFINDEX)
+           continue;
+         if (! IPV4_ADDR_SAME (&nexthop->gate.ipv4, &gate->ipv4))
+           continue;
+         goto found;
+         break;
+       case AF_INET6:
+         if (nexthop->type != NEXTHOP_TYPE_IPV6 &&
+             nexthop->type != NEXTHOP_TYPE_IPV6_IFINDEX)
+           continue;
+         if (! IPV6_ADDR_SAME (&nexthop->gate.ipv6, &gate->ipv6))
+           continue;
+         goto found;
+         break;
+       default:
+         break;
+      }
+  /* nexthop not found */
+  return -1;
+
+ found:
+  if (add)
+    nexthop_add_labels (nexthop, type, 1, &out_label);
+  else
+    nexthop_del_labels (nexthop);
+
+  SET_FLAG (rib->status, RIB_ENTRY_CHANGED);
+  SET_FLAG (rib->status, RIB_ENTRY_NEXTHOPS_CHANGED);
+  rib_queue_add (rn);
+
+  return 0;
+}
+
+/*
+ * Install/update a NHLFE for an LSP in the forwarding table. This may be
+ * a new LSP entry or a new NHLFE for an existing in-label or an update of
+ * the out-label for an existing NHLFE (update case).
+ */
+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)
+{
+  struct hash *lsp_table;
+  zebra_ile_t tmp_ile;
+  zebra_lsp_t *lsp;
+  zebra_nhlfe_t *nhlfe;
+  char buf[BUFSIZ];
+
+  /* Lookup table. */
+  lsp_table = zvrf->lsp_table;
+  if (!lsp_table)
+    return -1;
+
+  /* If entry is present, exit. */
+  tmp_ile.in_label = in_label;
+  lsp = hash_get (lsp_table, &tmp_ile, lsp_alloc);
+  if (!lsp)
+    return -1;
+  nhlfe = nhlfe_find (lsp, type, gtype, gate, ifname, ifindex);
+  if (nhlfe)
+    {
+      struct nexthop *nh = nhlfe->nexthop;
+
+      assert (nh);
+      assert (nh->nh_label);
+
+      /* Clear deleted flag (in case it was set) */
+      UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_DELETED);
+      if (nh->nh_label->label[0] == out_label)
+        /* No change */
+        return 0;
+
+      if (IS_ZEBRA_DEBUG_MPLS)
+        {
+          nhlfe2str (nhlfe, buf, BUFSIZ);
+          zlog_debug ("LSP in-label %u type %d nexthop %s "
+                      "out-label changed to %u (old %u)",
+                      in_label, type, buf,
+                      out_label, nh->nh_label->label[0]);
+        }
+
+      /* Update out label, trigger processing. */
+      nh->nh_label->label[0] = out_label;
+    }
+  else
+    {
+      /* Add LSP entry to this nexthop */
+      nhlfe = nhlfe_add (lsp, type, gtype, gate,
+                         ifname, ifindex, out_label);
+      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", in_label, type, buf, out_label);
+        }
+
+      lsp->addr_family = NHLFE_FAMILY (nhlfe);
+    }
+
+  /* Mark NHLFE, queue LSP for processing. */
+  SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
+  if (lsp_processq_add (lsp))
+    return -1;
+
+  return 0;
+}
+
+/*
+ * Uninstall a particular NHLFE in the forwarding table. If this is
+ * the only NHLFE, the entire LSP forwarding entry has to be deleted.
+ */
+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)
+{
+  struct hash *lsp_table;
+  zebra_ile_t tmp_ile;
+  zebra_lsp_t *lsp;
+  zebra_nhlfe_t *nhlfe;
+  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 = in_label;
+  lsp = hash_lookup (lsp_table, &tmp_ile);
+  if (!lsp)
+    return 0;
+  nhlfe = nhlfe_find (lsp, type, gtype, gate, ifname, ifindex);
+  if (!nhlfe)
+    return 0;
+
+  if (IS_ZEBRA_DEBUG_MPLS)
+    {
+      nhlfe2str (nhlfe, buf, BUFSIZ);
+      zlog_debug ("Del LSP in-label %u type %d nexthop %s flags 0x%x",
+                  in_label, type, buf, nhlfe->flags);
+    }
+
+  /* Mark NHLFE for delete or directly delete, as appropriate. */
+  if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED))
+    {
+      UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_CHANGED);
+      SET_FLAG (nhlfe->flags, NHLFE_FLAG_DELETED);
+      if (lsp_processq_add (lsp))
+        return -1;
+    }
+  else
+    {
+      nhlfe_del (nhlfe);
+
+      /* Free LSP entry if no other NHLFEs and not scheduled. */
+      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 LDP NHLFEs for a particular LSP forwarding entry.
+ * If no other NHLFEs exist, the entry would be deleted.
+ */
+void
+mpls_ldp_lsp_uninstall_all (struct hash_backet *backet, void *ctxt)
+{
+  zebra_lsp_t *lsp;
+  struct hash *lsp_table;
+
+  lsp = (zebra_lsp_t *) backet->data;
+  if (!lsp || !lsp->nhlfe_list)
+    return;
+
+  lsp_table = ctxt;
+  if (!lsp_table)
+    return;
+
+  mpls_lsp_uninstall_all (lsp_table, lsp, ZEBRA_LSP_LDP);
+}
+
+/*
+ * Uninstall all LDP FEC-To-NHLFE (FTN) bindings of the given address-family.
+ */
+void
+mpls_ldp_ftn_uninstall_all (struct zebra_vrf *zvrf, int afi)
+{
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *rib;
+  struct nexthop *nexthop;
+  int update;
+
+  /* Process routes of interested address-families. */
+  table = zebra_vrf_table (afi, SAFI_UNICAST, zvrf->vrf_id);
+  if (!table)
+    return;
+
+  for (rn = route_top (table); rn; rn = route_next (rn))
+    {
+      update = 0;
+      RNODE_FOREACH_RIB (rn, rib)
+       for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+         if (nexthop->nh_label_type == ZEBRA_LSP_LDP)
+           {
+             nexthop_del_labels (nexthop);
+             SET_FLAG (rib->status, RIB_ENTRY_CHANGED);
+             SET_FLAG (rib->status, RIB_ENTRY_NEXTHOPS_CHANGED);
+             update = 1;
+           }
+
+      if (update)
+       rib_queue_add (rn);
+    }
+}
+
 /*
  * Check that the label values used in LSP creation are consistent. The
  * main criteria is that if there is ECMP, the label operation must still
@@ -1511,8 +1637,8 @@ zebra_mpls_static_lsp_add (struct zebra_vrf *zvrf, mpls_label_t in_label,
     }
 
   /* (Re)Install LSP in the main table. */
-  if (static_lsp_install (zvrf, in_label, out_label, gtype,
-                          gate, ifname, ifindex))
+  if (mpls_lsp_install (zvrf, ZEBRA_LSP_STATIC, in_label, out_label, gtype,
+      gate, ifname, ifindex))
     return -1;
 
   return 0;
@@ -1553,7 +1679,7 @@ zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label,
         zlog_debug ("Del static LSP in-label %u", in_label);
 
       /* Uninstall entire LSP from the main table. */
-      static_lsp_uninstall_all (zvrf, in_label);
+      mpls_static_lsp_uninstall_all (zvrf, in_label);
 
       /* Delete all static NHLFEs */
       snhlfe_del_all (slsp);
@@ -1574,8 +1700,8 @@ zebra_mpls_static_lsp_del (struct zebra_vrf *zvrf, mpls_label_t in_label,
         }
 
       /* Uninstall LSP from the main table. */
-      static_lsp_uninstall (zvrf, in_label, gtype,
-                            gate, ifname, ifindex);
+      mpls_lsp_uninstall (zvrf, ZEBRA_LSP_STATIC, in_label, gtype, gate,
+                         ifname, ifindex);
 
       /* Delete static LSP NHLFE */
       snhlfe_del (snhlfe);
index 11949c931361e49ff341e77c7a9e485c213cd6b5..7c672fa43398a089ff0d8c424f29d7b288964eda 100644 (file)
@@ -53,13 +53,6 @@ typedef struct zebra_slsp_t_ zebra_slsp_t;
 typedef struct zebra_nhlfe_t_ zebra_nhlfe_t;
 typedef struct zebra_lsp_t_ zebra_lsp_t;
 
-/* LSP types. */
-enum lsp_types_t
-{
-  ZEBRA_LSP_INVALID = 0,     /* Invalid. */
-  ZEBRA_LSP_STATIC = 1,      /* Static LSP. */
-};
-
 /*
  * (Outgoing) nexthop label forwarding entry configuration
  */
@@ -171,6 +164,47 @@ char *
 mpls_label2str (u_int8_t num_labels, mpls_label_t *labels,
                 char *buf, int len);
 
+/*
+ * Install/uninstall a FEC-To-NHLFE (FTN) binding.
+ */
+int
+mpls_ftn_update (int add, struct zebra_vrf *zvrf, enum lsp_types_t type,
+                struct prefix *prefix, union g_addr *gate, u_int8_t distance,
+                mpls_label_t out_label);
+
+/*
+ * Install/update a NHLFE for an LSP in the forwarding table. This may be
+ * a new LSP entry or a new NHLFE for an existing in-label or an update of
+ * the out-label for an existing NHLFE (update case).
+ */
+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);
+
+/*
+ * Uninstall a particular NHLFE in the forwarding table. If this is
+ * the only NHLFE, the entire LSP forwarding entry has to be deleted.
+ */
+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);
+
+/*
+ * Uninstall all LDP NHLFEs for a particular LSP forwarding entry.
+ * If no other NHLFEs exist, the entry would be deleted.
+ */
+void
+mpls_ldp_lsp_uninstall_all (struct hash_backet *backet, void *ctxt);
+
+/*
+ * Uninstall all LDP FEC-To-NHLFE (FTN) bindings of the given address-family.
+ */
+void
+mpls_ldp_ftn_uninstall_all (struct zebra_vrf *zvrf, int afi);
+
 /*
  * Check that the label values used in LSP creation are consistent. The
  * main criteria is that if there is ECMP, the label operation must still
@@ -282,7 +316,7 @@ lsp_type_from_rib_type (int rib_type)
       case ZEBRA_ROUTE_STATIC:
         return ZEBRA_LSP_STATIC;
       default:
-        return ZEBRA_LSP_INVALID;
+        return ZEBRA_LSP_NONE;
     }
 }
 
@@ -294,6 +328,8 @@ nhlfe_type2str(enum lsp_types_t lsp_type)
     {
       case ZEBRA_LSP_STATIC:
         return "Static";
+      case ZEBRA_LSP_LDP:
+        return "LDP";
       default:
         return "Unknown";
     }
index f79dfafa5e7e0bad59de27edf97c0444e5e0bbdb..f57c0b5d678d95936f0e19fff3c0e69909efae92 100644 (file)
@@ -205,7 +205,7 @@ rib_copy_nexthops (struct rib *rib, struct nexthop *nh)
   memcpy(&(nexthop->gate), &(nh->gate), sizeof(union g_addr));
   memcpy(&(nexthop->src), &(nh->src), sizeof(union g_addr));
   if (nh->nh_label)
-    nexthop_add_labels (nexthop, nh->nh_label->num_labels,
+    nexthop_add_labels (nexthop, nh->nh_label_type, nh->nh_label->num_labels,
                         &nh->nh_label->label[0]);
   rib_nexthop_add(rib, nexthop);
   if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE))
index fddc9d54c8ce0bbd38e78acc9b0650f69d9d662e..f2362e68716167affe87c1525a2a6b023d0f101b 100644 (file)
@@ -98,7 +98,7 @@ static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ro
         }
       /* Update label(s), if present. */
       if (si->snh_label.num_labels)
-       nexthop_add_labels (nexthop, si->snh_label.num_labels,
+       nexthop_add_labels (nexthop, ZEBRA_LSP_STATIC, si->snh_label.num_labels,
                            &si->snh_label.label[0]);
 
       if (IS_ZEBRA_DEBUG_RIB)
@@ -162,7 +162,7 @@ static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ro
         }
       /* Update label(s), if present. */
       if (si->snh_label.num_labels)
-       nexthop_add_labels (nexthop, si->snh_label.num_labels,
+       nexthop_add_labels (nexthop, ZEBRA_LSP_STATIC, si->snh_label.num_labels,
                            &si->snh_label.label[0]);
 
       /* Save the flags of this static routes (reject, blackhole) */
index e617ae28a2d306a6ab9e9b140eee6b85d1afde80..4c68f6acb96186415274e8294c1a3e558e17559c 100644 (file)
@@ -52,6 +52,7 @@
 #include "zebra/interface.h"
 #include "zebra/zebra_ptm.h"
 #include "zebra/rtadv.h"
+#include "zebra/zebra_mpls.h"
 
 /* Event list of zebra. */
 enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE };
@@ -1630,6 +1631,65 @@ zread_vrf_unregister (struct zserv *client, u_short length, struct zebra_vrf *zv
   return 0;
 }
 
+static void
+zread_mpls_labels (int command, struct zserv *client, u_short length,
+                  vrf_id_t vrf_id)
+{
+  struct stream *s;
+  enum lsp_types_t type;
+  struct prefix prefix;
+  enum nexthop_types_t gtype;
+  union g_addr gate;
+  mpls_label_t in_label, out_label;
+  u_int8_t distance;
+  struct zebra_vrf *zvrf;
+
+  zvrf = vrf_info_lookup (vrf_id);
+  if (!zvrf)
+    return;
+
+  /* Get input stream.  */
+  s = client->ibuf;
+
+  /* Get data. */
+  type = stream_getc (s);
+  prefix.family = stream_getl (s);
+  switch (prefix.family)
+    {
+    case AF_INET:
+      prefix.u.prefix4.s_addr = stream_get_ipv4 (s);
+      prefix.prefixlen = stream_getc (s);
+      gtype = NEXTHOP_TYPE_IPV4;
+      gate.ipv4.s_addr = stream_get_ipv4 (s);
+      break;
+    case AF_INET6:
+      stream_get (&prefix.u.prefix6, s, 16);
+      prefix.prefixlen = stream_getc (s);
+      gtype = NEXTHOP_TYPE_IPV6;
+      stream_get (&gate.ipv6, s, 16);
+      break;
+    default:
+      return;
+    }
+  distance = stream_getc (s);
+  in_label = stream_getl (s);
+  out_label = stream_getl (s);
+
+  if (command == ZEBRA_MPLS_LABELS_ADD)
+    {
+      mpls_lsp_install (zvrf, type, in_label, out_label, gtype, &gate,
+                       NULL, 0);
+      if (out_label != MPLS_IMP_NULL_LABEL)
+       mpls_ftn_update (1, zvrf, type, &prefix, &gate, distance, out_label);
+    }
+  else if (command == ZEBRA_MPLS_LABELS_DELETE)
+    {
+      mpls_lsp_uninstall (zvrf, type, in_label, gtype, &gate, NULL, 0);
+      if (out_label != MPLS_IMP_NULL_LABEL)
+       mpls_ftn_update (0, zvrf, type, &prefix, &gate, distance, out_label);
+    }
+}
+
 /* Cleanup registered nexthops (across VRFs) upon client disconnect. */
 static void
 zebra_client_close_cleanup_rnh (struct zserv *client)
@@ -1645,6 +1705,13 @@ zebra_client_close_cleanup_rnh (struct zserv *client)
           zebra_cleanup_rnh_client(zvrf->vrf_id, AF_INET6, client, RNH_NEXTHOP_TYPE);
           zebra_cleanup_rnh_client(zvrf->vrf_id, AF_INET, client, RNH_IMPORT_CHECK_TYPE);
           zebra_cleanup_rnh_client(zvrf->vrf_id, AF_INET6, client, RNH_IMPORT_CHECK_TYPE);
+         if (client->proto == ZEBRA_ROUTE_LDP)
+           {
+             hash_iterate(zvrf->lsp_table, mpls_ldp_lsp_uninstall_all,
+                          zvrf->lsp_table);
+             mpls_ldp_ftn_uninstall_all (zvrf, AFI_IP);
+             mpls_ldp_ftn_uninstall_all (zvrf, AFI_IP6);
+           }
         }
     }
 }
@@ -1926,6 +1993,10 @@ zebra_client_read (struct thread *thread)
     case ZEBRA_INTERFACE_DISABLE_RADV:
       zebra_interface_radv_set (client, sock, length, zvrf, 0);
       break;
+    case ZEBRA_MPLS_LABELS_ADD:
+    case ZEBRA_MPLS_LABELS_DELETE:
+      zread_mpls_labels (command, client, length, vrf_id);
+      break;
     default:
       zlog_info ("Zebra received unknown command %d", command);
       break;