]> git.puffer.fish Git - mirror/frr.git/commitdiff
zebra: static label binding
authorDon Slice <dslice@cumulusnetworks.com>
Tue, 27 Dec 2016 15:09:28 +0000 (07:09 -0800)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Thu, 6 Apr 2017 14:28:16 +0000 (10:28 -0400)
Implement static label binding of a label to a prefix (FEC).

Note: Currently, only binding to a prefix is supported, the nexthop and/or
other parameters are not considered.  This was cherry-picked by hand from
an earlier mpls branch.

Signed-off-by: Don Slice <dslice@cumulusnetworks.com>
zebra/zebra_mpls.c
zebra/zebra_mpls.h
zebra/zebra_mpls_vty.c
zebra/zebra_vrf.h

index 5a3ed7545d294f5f4f29747428f3458d540f58ca..814d171d9f50deab34f9aa95c7c428ab5850df37 100644 (file)
@@ -47,6 +47,7 @@
 #include "zebra/zebra_mpls.h"
 
 DEFINE_MTYPE_STATIC(ZEBRA, LSP,                        "MPLS LSP object")
+DEFINE_MTYPE_STATIC(ZEBRA, FEC,                        "MPLS FEC object")
 DEFINE_MTYPE_STATIC(ZEBRA, SLSP,               "MPLS static LSP config")
 DEFINE_MTYPE_STATIC(ZEBRA, NHLFE,              "MPLS nexthop object")
 DEFINE_MTYPE_STATIC(ZEBRA, SNHLFE,             "MPLS static nexthop object")
@@ -58,6 +59,17 @@ int mpls_enabled;
 extern struct zebra_t zebrad;
 
 /* static function declarations */
+
+static void
+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,
+         u_int32_t flags);
+static int
+fec_del (zebra_fec_t *fec);
+
 static unsigned int
 label_hash (void *p);
 static int
@@ -68,6 +80,7 @@ static int
 nhlfe_nexthop_active_ipv6 (zebra_nhlfe_t *nhlfe, struct nexthop *nexthop);
 static int
 nhlfe_nexthop_active (zebra_nhlfe_t *nhlfe);
+
 static void
 lsp_select_best_nhlfe (zebra_lsp_t *lsp);
 static void
@@ -84,6 +97,7 @@ static int
 lsp_processq_add (zebra_lsp_t *lsp);
 static void *
 lsp_alloc (void *p);
+
 static char *
 nhlfe2str (zebra_nhlfe_t *nhlfe, char *buf, int size);
 static int
@@ -134,6 +148,88 @@ mpls_processq_init (struct zebra_t *zebra);
 
 /* Static functions */
 
+/*
+ * Print a FEC-label binding entry.
+ */
+static void
+fec_print (zebra_fec_t *fec, struct vty *vty)
+{
+  struct route_node *rn;
+  char buf[BUFSIZ];
+
+  rn = fec->rn;
+  prefix2str(&rn->p, buf, BUFSIZ);
+  vty_out(vty, "%s%s", buf, VTY_NEWLINE);
+  vty_out(vty, "  Label: %s", label2str(fec->label, buf, BUFSIZ));
+  vty_out(vty, "%s", VTY_NEWLINE);
+}
+
+/*
+ * Locate FEC-label binding that matches with passed info.
+ */
+static zebra_fec_t *
+fec_find (struct route_table *table, struct prefix *p)
+{
+  struct route_node *rn;
+
+  apply_mask (p);
+  rn = route_node_lookup(table, p);
+  if (!rn)
+    return NULL;
+
+  route_unlock_node(rn);
+  return (rn->info);
+}
+
+/*
+ * Add a FEC.
+ */
+static zebra_fec_t *
+fec_add (struct route_table *table, struct prefix *p,
+         mpls_label_t label, u_int32_t flags)
+{
+  struct route_node *rn;
+  zebra_fec_t *fec;
+
+  apply_mask (p);
+
+  /* Lookup (or add) route node.*/
+  rn = route_node_get (table, p);
+  if (!rn)
+    return NULL;
+
+  fec = rn->info;
+
+  if (!fec)
+    {
+      fec = XCALLOC (MTYPE_FEC, sizeof(zebra_fec_t));
+      if (!fec)
+        return NULL;
+
+      rn->info = fec;
+      fec->rn = rn;
+      fec->label = label;
+    }
+  else
+    route_unlock_node (rn); /* for the route_node_get */
+
+  fec->flags = flags;
+
+  return fec;
+}
+
+/*
+ * Delete a FEC.
+ */
+static int
+fec_del (zebra_fec_t *fec)
+{
+  fec->rn->info = NULL;
+  route_unlock_node (fec->rn);
+  XFREE (MTYPE_FEC, fec);
+  return 0;
+}
+
 /*
  * Hash function for label.
  */
@@ -1274,6 +1370,215 @@ mpls_label2str (u_int8_t num_labels, mpls_label_t *labels,
   return buf;
 }
 
+/*
+ * Return FEC (if any) to which this label is bound.
+ * Note: Only works for per-prefix binding and when the label is not
+ * implicit-null.
+ * TODO: Currently walks entire table, can optimize later with another
+ * hash..
+ */
+zebra_fec_t *
+zebra_mpls_fec_for_label (struct zebra_vrf *zvrf, mpls_label_t label)
+{
+  struct route_node *rn;
+  zebra_fec_t *fec;
+  int af;
+
+  for (af = AFI_IP; af < AFI_MAX; af++)
+    {
+      if (zvrf->fec_table[af] == NULL)
+        continue;
+
+      for (rn = route_top(zvrf->fec_table[af]); rn; rn = route_next(rn))
+        {
+          if (!rn->info)
+            continue;
+          fec = rn->info;
+          if (fec->label == label)
+            return fec;
+        }
+    }
+
+  return NULL;
+}
+
+/*
+ * Inform if specified label is currently bound to a FEC or not.
+ */
+int
+zebra_mpls_label_already_bound (struct zebra_vrf *zvrf, mpls_label_t label)
+{
+  return (zebra_mpls_fec_for_label (zvrf, label) ? 1 : 0);
+}
+
+/*
+ * Add static FEC to label binding.
+ */
+int
+zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p,
+                           mpls_label_t in_label)
+{
+  struct route_table *table;
+  zebra_fec_t *fec;
+  char buf[BUFSIZ];
+  int ret = 0;
+
+  table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
+  if (!table)
+    return -1;
+
+  if (IS_ZEBRA_DEBUG_MPLS)
+    prefix2str(p, buf, BUFSIZ);
+
+  /* Update existing FEC or create a new one. */
+  fec = fec_find (table, p);
+  if (!fec)
+    {
+      fec = fec_add (table, p, in_label, FEC_FLAG_CONFIGURED);
+      if (!fec)
+        {
+          prefix2str(p, buf, BUFSIZ);
+          zlog_err ("Failed to add FEC %s upon config", buf);
+          return -1;
+        }
+
+      if (IS_ZEBRA_DEBUG_MPLS)
+        zlog_debug ("Add fec %s label %u", buf, in_label);
+    }
+  else
+    {
+      fec->flags |= FEC_FLAG_CONFIGURED;
+      if (fec->label == in_label)
+        /* Duplicate config */
+        return 0;
+
+      if (IS_ZEBRA_DEBUG_MPLS)
+        zlog_debug ("Update fec %s new label %u", buf, in_label);
+
+      fec->label = in_label;
+    }
+
+  return ret;
+}
+
+/*
+ * Remove static FEC to label binding.
+ */
+int
+zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p)
+{
+  struct route_table *table;
+  zebra_fec_t *fec;
+  char buf[BUFSIZ];
+
+  table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
+  if (!table)
+    return -1;
+
+  fec = fec_find (table, p);
+  if (!fec)
+    {
+      prefix2str(p, buf, BUFSIZ);
+      zlog_err("Failed to find FEC %s upon delete", buf);
+      return -1;
+    }
+
+  if (IS_ZEBRA_DEBUG_MPLS)
+    {
+      prefix2str(p, buf, BUFSIZ);
+      zlog_debug ("Delete fec %s", buf);
+    }
+
+  fec_del (fec);
+  return 0;
+}
+
+/*
+ * Display MPLS FEC to label binding configuration (VTY command handler).
+ */
+int
+zebra_mpls_write_fec_config (struct vty *vty, struct zebra_vrf *zvrf)
+{
+  struct route_node *rn;
+  int af;
+  zebra_fec_t *fec;
+  char buf[BUFSIZ];
+  int write = 0;
+
+  for (af = AFI_IP; af < AFI_MAX; af++)
+    {
+      if (zvrf->fec_table[af] == NULL)
+        continue;
+
+      for (rn = route_top(zvrf->fec_table[af]); rn; rn = route_next(rn))
+        {
+          if (!rn->info)
+            continue;
+
+          char lstr[BUFSIZ];
+          fec = rn->info;
+
+          if (!(fec->flags & FEC_FLAG_CONFIGURED))
+            continue;
+
+          write = 1;
+          prefix2str(&rn->p, buf, BUFSIZ);
+          vty_out(vty, "mpls label bind %s %s%s", buf,
+                  label2str(fec->label, lstr, BUFSIZ), VTY_NEWLINE);
+        }
+    }
+
+  return write;
+}
+
+/*
+ * Display MPLS FEC to label binding (VTY command handler).
+ */
+void
+zebra_mpls_print_fec_table (struct vty *vty, struct zebra_vrf *zvrf)
+{
+  struct route_node *rn;
+  int af;
+
+  for (af = AFI_IP; af < AFI_MAX; af++)
+    {
+      if (zvrf->fec_table[af] == NULL)
+        continue;
+
+      for (rn = route_top(zvrf->fec_table[af]); rn; rn = route_next(rn))
+        {
+          if (!rn->info)
+            continue;
+          fec_print (rn->info, vty);
+        }
+    }
+}
+
+/*
+ * Display MPLS FEC to label binding for a specific FEC (VTY command handler).
+ */
+void
+zebra_mpls_print_fec (struct vty *vty, struct zebra_vrf *zvrf, struct prefix *p)
+{
+  struct route_table *table;
+  struct route_node *rn;
+
+  table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
+  if (!table)
+    return;
+
+  apply_mask (p);
+  rn = route_node_lookup(table, p);
+  if (!rn)
+    return;
+
+  route_unlock_node(rn);
+  if (!rn->info)
+    return;
+
+  fec_print (rn->info, vty);
+}
+
 /*
  * Install/uninstall a FEC-To-NHLFE (FTN) binding.
  */
@@ -1927,6 +2232,8 @@ zebra_mpls_init_tables (struct zebra_vrf *zvrf)
     return;
   zvrf->slsp_table = hash_create(label_hash, label_cmp);
   zvrf->lsp_table = hash_create(label_hash, label_cmp);
+  zvrf->fec_table[AFI_IP] = route_table_init();
+  zvrf->fec_table[AFI_IP6] = route_table_init();
   zvrf->mpls_flags = 0;
 }
 
index a871fac6519b08bb6ca28ba1c194d3fc97c250f2..9ff230e5eee41b42eb231ff9225cd84808c8f57d 100644 (file)
@@ -52,6 +52,7 @@ typedef struct zebra_snhlfe_t_ zebra_snhlfe_t;
 typedef struct zebra_slsp_t_ zebra_slsp_t;
 typedef struct zebra_nhlfe_t_ zebra_nhlfe_t;
 typedef struct zebra_lsp_t_ zebra_lsp_t;
+typedef struct zebra_fec_t_ zebra_fec_t;
 
 /*
  * (Outgoing) nexthop label forwarding entry configuration
@@ -147,6 +148,21 @@ struct zebra_lsp_t_
   u_char addr_family;
 };
 
+/*
+ * FEC to label binding.
+ */
+struct zebra_fec_t_
+{
+  /* FEC (prefix) */
+  struct route_node *rn;
+
+  /* In-label - either statically bound or derived from label block. */
+  mpls_label_t label;
+
+  /* Flags. */
+  u_int32_t flags;
+#define FEC_FLAG_CONFIGURED       (1 << 0)
+};
 
 /* Function declarations. */
 
@@ -164,6 +180,53 @@ char *
 mpls_label2str (u_int8_t num_labels, mpls_label_t *labels,
                 char *buf, int len);
 
+/*
+ * Return FEC (if any) to which this label is bound.
+ * Note: Only works for per-prefix binding and when the label is not
+ * implicit-null.
+ * TODO: Currently walks entire table, can optimize later with another
+ * hash..
+ */
+zebra_fec_t *
+zebra_mpls_fec_for_label (struct zebra_vrf *zvrf, mpls_label_t label);
+
+/*
+ * Inform if specified label is currently bound to a FEC or not.
+ */
+int
+zebra_mpls_label_already_bound (struct zebra_vrf *zvrf, mpls_label_t label);
+
+/*
+ * Add static FEC to label binding.
+ */
+int
+zebra_mpls_static_fec_add (struct zebra_vrf *zvrf, struct prefix *p,
+                           mpls_label_t in_label);
+
+/*
+ * Remove static FEC to label binding.
+ */
+int
+zebra_mpls_static_fec_del (struct zebra_vrf *zvrf, struct prefix *p);
+
+/*
+ * Display MPLS FEC to label binding configuration (VTY command handler).
+ */
+int
+zebra_mpls_write_fec_config (struct vty *vty, struct zebra_vrf *zvrf);
+
+/*
+ * Display MPLS FEC to label binding (VTY command handler).
+ */
+void
+zebra_mpls_print_fec_table (struct vty *vty, struct zebra_vrf *zvrf);
+
+/*
+ * Display MPLS FEC to label binding for a specific FEC (VTY command handler).
+ */
+void
+zebra_mpls_print_fec (struct vty *vty, struct zebra_vrf *zvrf, struct prefix *p);
+
 /*
  * Install/uninstall a FEC-To-NHLFE (FTN) binding.
  */
index dd381723c53c3ee433aae3639e6acc7eb15a8ca8..90624c12a4585a3999967be9aef5b846ae4d5ebf 100644 (file)
@@ -209,6 +209,101 @@ DEFUN (no_mpls_transit_lsp_all,
   return zebra_mpls_transit_lsp (vty, 0, argv[3]->arg, NULL, NULL, NULL);
 }
 
+static int
+zebra_mpls_bind (struct vty *vty, int add_cmd, const char *prefix,
+                const char *label_str)
+{
+  struct zebra_vrf *zvrf;
+  struct prefix p;
+  u_int32_t label;
+  int ret;
+
+  zvrf = vrf_info_lookup(VRF_DEFAULT);
+  if (!zvrf)
+    {
+      vty_out (vty, "%% Default VRF does not exist%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  memset(&p, 0, sizeof(struct prefix));
+  ret = str2prefix(prefix, &p);
+  if (ret <= 0)
+    {
+      vty_out (vty, "%% Malformed address%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (add_cmd)
+    {
+      if (!label_str)
+        {
+          vty_out (vty, "%% No label binding specified%s", VTY_NEWLINE);
+          return CMD_WARNING;
+        }
+
+      if (!strcmp(label_str, "implicit-null"))
+        label = MPLS_IMP_NULL_LABEL;
+      else
+        {
+          label = atoi(label_str);
+          if (!IS_MPLS_UNRESERVED_LABEL(label))
+            {
+              vty_out (vty, "%% Invalid label%s", VTY_NEWLINE);
+              return CMD_WARNING;
+            }
+          if (zebra_mpls_label_already_bound (zvrf, label))
+            {
+              vty_out (vty, "%% Label already bound to a FEC%s",
+                       VTY_NEWLINE);
+              return CMD_WARNING;
+            }
+        }
+
+      ret = zebra_mpls_static_fec_add (zvrf, &p, label);
+    }
+  else
+    ret = zebra_mpls_static_fec_del (zvrf, &p);
+
+  if (ret)
+    {
+      vty_out (vty, "%% FEC to label binding cannot be %s%s",
+               add_cmd ? "added" : "deleted", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (mpls_label_bind,
+       mpls_label_bind_cmd,
+       "mpls label bind <A.B.C.D/M|X:X::X:X/M> <(16-1048575)|implicit-null>",
+       MPLS_STR
+       "Label configuration\n"
+       "Establish FEC to label binding\n"
+       "IPv4 prefix\n"
+       "IPv6 prefix\n"
+       "MPLS Label to bind\n"
+       "Use Implicit-Null Label\n")
+{
+  return zebra_mpls_bind (vty, 1, argv[3]->arg, argv[4]->arg);
+}
+
+DEFUN (no_mpls_label_bind,
+       no_mpls_label_bind_cmd,
+       "no mpls label bind <A.B.C.D/M|X:X::X:X/M> [<(16-1048575)|implicit-null>]",
+       NO_STR
+       MPLS_STR
+       "Label configuration\n"
+       "Establish FEC to label binding\n"
+       "IPv4 prefix\n"
+       "IPv6 prefix\n"
+       "MPLS Label to bind\n"
+       "Use Implicit-Null Label\n")
+
+{
+  return zebra_mpls_bind (vty, 0, argv[4]->arg, NULL);
+}
+
 /* Static route configuration.  */
 DEFUN (ip_route_label,
        ip_route_label_cmd,
@@ -777,9 +872,44 @@ zebra_mpls_config (struct vty *vty)
     return 0;
 
   write += zebra_mpls_write_lsp_config(vty, zvrf);
+  write += zebra_mpls_write_fec_config(vty, zvrf);
   return write;
 }
 
+DEFUN (show_mpls_fec,
+       show_mpls_fec_cmd,
+       "show mpls fec [<A.B.C.D/M|X:X::X:X/M>]",
+       SHOW_STR
+       MPLS_STR
+       "MPLS FEC table\n"
+       "FEC to display information about\n"
+       "FEC to display information about\n")
+{
+  struct zebra_vrf *zvrf;
+  struct prefix p;
+  int ret;
+
+  zvrf = vrf_info_lookup(VRF_DEFAULT);
+    if (!zvrf)
+      return 0;
+
+  if (argc == 3)
+    zebra_mpls_print_fec_table(vty, zvrf);
+  else
+    {
+      memset(&p, 0, sizeof(struct prefix));
+      ret = str2prefix(argv[3]->arg, &p);
+      if (ret <= 0)
+        {
+          vty_out (vty, "%% Malformed address%s", VTY_NEWLINE);
+          return CMD_WARNING;
+        }
+      zebra_mpls_print_fec (vty, zvrf, &p);
+    }
+
+  return CMD_SUCCESS;
+}
+
 DEFUN (show_mpls_table,
        show_mpls_table_cmd,
        "show mpls table [json]",
@@ -876,7 +1006,10 @@ zebra_mpls_vty_init (void)
   install_element (CONFIG_NODE, &no_mpls_transit_lsp_cmd);
   install_element (CONFIG_NODE, &no_mpls_transit_lsp_out_label_cmd);
   install_element (CONFIG_NODE, &no_mpls_transit_lsp_all_cmd);
+  install_element (CONFIG_NODE, &mpls_label_bind_cmd);
+  install_element (CONFIG_NODE, &no_mpls_label_bind_cmd);
 
   install_element (VIEW_NODE, &show_mpls_table_cmd);
   install_element (VIEW_NODE, &show_mpls_table_lsp_cmd);
+  install_element (VIEW_NODE, &show_mpls_fec_cmd);
 }
index 96d631d646e7d91ace47903c59fc660fc13f8754..8333ca27d7d356e45d8d419682302d8260d9aa66 100644 (file)
@@ -79,6 +79,9 @@ struct zebra_vrf
   /* MPLS label forwarding table */
   struct hash *lsp_table;
 
+  /* MPLS FEC binding table */
+  struct route_table *fec_table[AFI_MAX];
+
   /* MPLS processing flags */
   u_int16_t mpls_flags;
 #define MPLS_FLAG_SCHEDULE_LSPS    (1 << 0)