summaryrefslogtreecommitdiffstats
path: root/zebra
diff options
context:
space:
mode:
authorvivek <vivek@cumulusnetworks.com>2016-04-15 19:51:56 +0200
committerDonald Sharp <sharpd@cumulusnetworks.com>2016-09-23 15:30:54 +0200
commit7758e3f31396019344d495946ba2bdd22e2544e9 (patch)
treed920ba8b03f3652b54cd280054bdecb125806836 /zebra
parentQuagga: Definitions for static LSPs (diff)
downloadfrr-7758e3f31396019344d495946ba2bdd22e2544e9.tar.xz
frr-7758e3f31396019344d495946ba2bdd22e2544e9.zip
Quagga: Static LSP configuration
Add support for statically configuring MPLS transit LSPs. This allows the configuration of ILM to one or more NHLFE, as defined in RFC 3031. The currently supported nexthop types are IPv4 or IPv6. The two label operations supported are swap and PHP; the latter is configured by specifying the out-label as "implicit-null". Note that the operation is against the label, so it should be the same for all NHLFEs. Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com> Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com> Ticket: CM-4804, ... Reviewed By: CCR-3085 Testing Done: In combination with other patches
Diffstat (limited to 'zebra')
-rw-r--r--zebra/Makefile.am4
-rw-r--r--zebra/debug.c36
-rw-r--r--zebra/debug.h4
-rw-r--r--zebra/main.c3
-rw-r--r--zebra/zebra_mpls.c540
-rw-r--r--zebra/zebra_mpls.h56
-rw-r--r--zebra/zebra_mpls_null.c45
-rw-r--r--zebra/zebra_vrf.c3
-rw-r--r--zebra/zebra_vty.c180
9 files changed, 869 insertions, 2 deletions
diff --git a/zebra/Makefile.am b/zebra/Makefile.am
index 4b6f9188b..10f7850c9 100644
--- a/zebra/Makefile.am
+++ b/zebra/Makefile.am
@@ -32,13 +32,13 @@ zebra_SOURCES = \
redistribute.c debug.c rtadv.c zebra_snmp.c zebra_vty.c \
irdp_main.c irdp_interface.c irdp_packet.c router-id.c zebra_fpm.c \
$(othersrc) zebra_ptm.c zebra_rnh.c zebra_ptm_redistribute.c \
- zebra_ns.c zebra_vrf.c zebra_static.c
+ zebra_ns.c zebra_vrf.c zebra_static.c zebra_mpls.c
testzebra_SOURCES = test_main.c zebra_rib.c interface.c connected.c debug.c \
zebra_vty.c zebra_ptm.c zebra_routemap.c zebra_ns.c zebra_vrf.c \
kernel_null.c redistribute_null.c ioctl_null.c misc_null.c zebra_rnh_null.c \
zebra_ptm_null.c rtadv_null.c if_null.c zserv_null.c zebra_static.c \
- zebra_memory.c
+ zebra_memory.c zebra_mpls_null.c
noinst_HEADERS = \
zebra_memory.h \
diff --git a/zebra/debug.c b/zebra/debug.c
index cdf233879..92354070e 100644
--- a/zebra/debug.c
+++ b/zebra/debug.c
@@ -31,6 +31,7 @@ unsigned long zebra_debug_kernel;
unsigned long zebra_debug_rib;
unsigned long zebra_debug_fpm;
unsigned long zebra_debug_nht;
+unsigned long zebra_debug_mpls;
DEFUN (show_debugging_zebra,
show_debugging_zebra_cmd,
@@ -82,6 +83,8 @@ DEFUN (show_debugging_zebra,
vty_out (vty, " Zebra FPM debugging is on%s", VTY_NEWLINE);
if (IS_ZEBRA_DEBUG_NHT)
vty_out (vty, " Zebra next-hop tracking debugging is on%s", VTY_NEWLINE);
+ if (IS_ZEBRA_DEBUG_MPLS)
+ vty_out (vty, " Zebra MPLS debugging is on%s", VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -108,6 +111,17 @@ DEFUN (debug_zebra_nht,
return CMD_WARNING;
}
+DEFUN (debug_zebra_mpls,
+ debug_zebra_mpls_cmd,
+ "debug zebra mpls",
+ DEBUG_STR
+ "Zebra configuration\n"
+ "Debug option set for zebra MPLS LSPs\n")
+{
+ zebra_debug_mpls = ZEBRA_DEBUG_MPLS;
+ return CMD_WARNING;
+}
+
DEFUN (debug_zebra_packet,
debug_zebra_packet_cmd,
"debug zebra packet",
@@ -245,6 +259,18 @@ DEFUN (no_debug_zebra_nht,
return CMD_SUCCESS;
}
+DEFUN (no_debug_zebra_mpls,
+ no_debug_zebra_mpls_cmd,
+ "no debug zebra mpls",
+ NO_STR
+ DEBUG_STR
+ "Zebra configuration\n"
+ "Debug option set for zebra MPLS LSPs\n")
+{
+ zebra_debug_mpls = 0;
+ return CMD_SUCCESS;
+}
+
DEFUN (no_debug_zebra_packet,
no_debug_zebra_packet_cmd,
"no debug zebra packet",
@@ -401,6 +427,11 @@ config_write_debug (struct vty *vty)
vty_out (vty, "debug zebra fpm%s", VTY_NEWLINE);
write++;
}
+ if (IS_ZEBRA_DEBUG_MPLS)
+ {
+ vty_out (vty, "debug zebra mpls%s", VTY_NEWLINE);
+ write++;
+ }
return write;
}
@@ -412,6 +443,7 @@ zebra_debug_init (void)
zebra_debug_kernel = 0;
zebra_debug_rib = 0;
zebra_debug_fpm = 0;
+ zebra_debug_mpls = 0;
install_node (&debug_node, config_write_debug);
@@ -420,6 +452,7 @@ zebra_debug_init (void)
install_element (ENABLE_NODE, &show_debugging_zebra_cmd);
install_element (ENABLE_NODE, &debug_zebra_events_cmd);
install_element (ENABLE_NODE, &debug_zebra_nht_cmd);
+ install_element (ENABLE_NODE, &debug_zebra_mpls_cmd);
install_element (ENABLE_NODE, &debug_zebra_packet_cmd);
install_element (ENABLE_NODE, &debug_zebra_packet_direct_cmd);
install_element (ENABLE_NODE, &debug_zebra_packet_detail_cmd);
@@ -430,6 +463,7 @@ zebra_debug_init (void)
install_element (ENABLE_NODE, &debug_zebra_fpm_cmd);
install_element (ENABLE_NODE, &no_debug_zebra_events_cmd);
install_element (ENABLE_NODE, &no_debug_zebra_nht_cmd);
+ install_element (ENABLE_NODE, &no_debug_zebra_mpls_cmd);
install_element (ENABLE_NODE, &no_debug_zebra_packet_cmd);
install_element (ENABLE_NODE, &no_debug_zebra_kernel_cmd);
install_element (ENABLE_NODE, &no_debug_zebra_kernel_msgdump_cmd);
@@ -439,6 +473,7 @@ zebra_debug_init (void)
install_element (CONFIG_NODE, &debug_zebra_events_cmd);
install_element (CONFIG_NODE, &debug_zebra_nht_cmd);
+ install_element (CONFIG_NODE, &debug_zebra_mpls_cmd);
install_element (CONFIG_NODE, &debug_zebra_packet_cmd);
install_element (CONFIG_NODE, &debug_zebra_packet_direct_cmd);
install_element (CONFIG_NODE, &debug_zebra_packet_detail_cmd);
@@ -449,6 +484,7 @@ zebra_debug_init (void)
install_element (CONFIG_NODE, &debug_zebra_fpm_cmd);
install_element (CONFIG_NODE, &no_debug_zebra_events_cmd);
install_element (CONFIG_NODE, &no_debug_zebra_nht_cmd);
+ install_element (CONFIG_NODE, &no_debug_zebra_mpls_cmd);
install_element (CONFIG_NODE, &no_debug_zebra_packet_cmd);
install_element (CONFIG_NODE, &no_debug_zebra_kernel_cmd);
install_element (CONFIG_NODE, &no_debug_zebra_kernel_msgdump_cmd);
diff --git a/zebra/debug.h b/zebra/debug.h
index 4416068bf..f8ebf3d61 100644
--- a/zebra/debug.h
+++ b/zebra/debug.h
@@ -41,6 +41,8 @@
#define ZEBRA_DEBUG_FPM 0x01
#define ZEBRA_DEBUG_NHT 0x01
+#define ZEBRA_DEBUG_MPLS 0x01
+
/* Debug related macro. */
#define IS_ZEBRA_DEBUG_EVENT (zebra_debug_event & ZEBRA_DEBUG_EVENT)
@@ -61,6 +63,7 @@
#define IS_ZEBRA_DEBUG_FPM (zebra_debug_fpm & ZEBRA_DEBUG_FPM)
#define IS_ZEBRA_DEBUG_NHT (zebra_debug_nht & ZEBRA_DEBUG_NHT)
+#define IS_ZEBRA_DEBUG_MPLS (zebra_debug_mpls & ZEBRA_DEBUG_MPLS)
extern unsigned long zebra_debug_event;
extern unsigned long zebra_debug_packet;
@@ -68,6 +71,7 @@ extern unsigned long zebra_debug_kernel;
extern unsigned long zebra_debug_rib;
extern unsigned long zebra_debug_fpm;
extern unsigned long zebra_debug_nht;
+extern unsigned long zebra_debug_mpls;
extern void zebra_debug_init (void);
diff --git a/zebra/main.c b/zebra/main.c
index e67568140..e06a17ca4 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -46,6 +46,7 @@
#include "zebra/zebra_ptm.h"
#include "zebra/zebra_ns.h"
#include "zebra/redistribute.h"
+#include "zebra/zebra_mpls.h"
#define ZEBRA_PTM_SUPPORT
@@ -362,6 +363,8 @@ main (int argc, char **argv)
zebra_ptm_init();
#endif
+ zebra_mpls_init ();
+
/* For debug purpose. */
/* SET_FLAG (zebra_debug_event, ZEBRA_DEBUG_EVENT); */
diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c
new file mode 100644
index 000000000..db1f31859
--- /dev/null
+++ b/zebra/zebra_mpls.c
@@ -0,0 +1,540 @@
+/* Zebra MPLS code
+ * Copyright (C) 2013 Cumulus Networks, Inc.
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "prefix.h"
+#include "table.h"
+#include "memory.h"
+#include "str.h"
+#include "command.h"
+#include "if.h"
+#include "log.h"
+#include "sockunion.h"
+#include "linklist.h"
+#include "thread.h"
+#include "workqueue.h"
+#include "prefix.h"
+#include "routemap.h"
+#include "stream.h"
+#include "nexthop.h"
+
+#include "zebra/rib.h"
+#include "zebra/rt.h"
+#include "zebra/zserv.h"
+#include "zebra/redistribute.h"
+#include "zebra/debug.h"
+#include "zebra/zebra_memory.h"
+#include "zebra/zebra_vrf.h"
+#include "zebra/zebra_mpls.h"
+
+DEFINE_MTYPE_STATIC(ZEBRA, LSP, "MPLS LSP object")
+DEFINE_MTYPE_STATIC(ZEBRA, SLSP, "MPLS static LSP config")
+DEFINE_MTYPE_STATIC(ZEBRA, SNHLFE, "MPLS static nexthop object")
+DEFINE_MTYPE_STATIC(ZEBRA, SNHLFE_IFNAME, "MPLS static nexthop ifname")
+
+/* Default rtm_table for all clients */
+extern struct zebra_t zebrad;
+
+/* static function declarations */
+static unsigned int
+label_hash (void *p);
+static int
+label_cmp (const void *p1, const void *p2);
+static void
+lsp_config_write (struct hash_backet *backet, void *ctxt);
+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);
+static zebra_snhlfe_t *
+snhlfe_find (zebra_slsp_t *slsp, enum nexthop_types_t gtype,
+ union g_addr *gate, char *ifname, 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);
+static int
+snhlfe_del (zebra_snhlfe_t *snhlfe);
+static int
+snhlfe_del_all (zebra_slsp_t *slsp);
+static char *
+snhlfe2str (zebra_snhlfe_t *snhlfe, char *buf, int size);
+
+
+
+
+/* Static functions */
+
+/*
+ * Hash function for label.
+ */
+static unsigned int
+label_hash (void *p)
+{
+ const zebra_ile_t *ile = p;
+
+ return (jhash_1word(ile->in_label, 0));
+}
+
+/*
+ * Compare 2 LSP hash entries based on in-label.
+ */
+static int
+label_cmp (const void *p1, const void *p2)
+{
+ const zebra_ile_t *ile1 = p1;
+ const zebra_ile_t *ile2 = p2;
+
+ return (ile1->in_label == ile2->in_label);
+}
+
+/*
+ * Write out static LSP configuration.
+ */
+static void
+lsp_config_write (struct hash_backet *backet, void *ctxt)
+{
+ zebra_slsp_t *slsp;
+ zebra_snhlfe_t *snhlfe;
+ struct vty *vty = (struct vty *) ctxt;
+ char buf[INET6_ADDRSTRLEN];
+
+ slsp = (zebra_slsp_t *) backet->data;
+ if (!slsp)
+ return;
+
+ for (snhlfe = slsp->snhlfe_list; snhlfe; snhlfe = snhlfe->next)
+ {
+ char lstr[30];
+ snhlfe2str (snhlfe, buf, BUFSIZ);
+ vty_out (vty, "mpls lsp %u %s %s%s",
+ slsp->ile.in_label, buf,
+ label2str(snhlfe->out_label, lstr, 30), VTY_NEWLINE);
+ }
+}
+
+/*
+ * Callback to allocate static LSP.
+ */
+static void *
+slsp_alloc (void *p)
+{
+ const zebra_ile_t *ile = p;
+ zebra_slsp_t *slsp;
+
+ slsp = XCALLOC (MTYPE_SLSP, sizeof(zebra_slsp_t));
+ slsp->ile = *ile;
+ return ((void *)slsp);
+}
+
+/*
+ * Check if static NHLFE matches with search info passed.
+ */
+static int
+snhlfe_match (zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype,
+ union g_addr *gate, char *ifname, ifindex_t ifindex)
+{
+ u_char cmp = -1;
+
+ if (snhlfe->gtype != gtype)
+ return -1;
+
+ switch (snhlfe->gtype)
+ {
+ case NEXTHOP_TYPE_IPV4:
+ cmp = memcmp(&(snhlfe->gate.ipv4), &(gate->ipv4),
+ sizeof(struct in_addr));
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ cmp = memcmp(&(snhlfe->gate.ipv6), &(gate->ipv6),
+ sizeof(struct in6_addr));
+ if (!cmp && snhlfe->gtype == NEXTHOP_TYPE_IPV6_IFINDEX)
+ cmp = !(snhlfe->ifindex == ifindex);
+ break;
+ default:
+ break;
+ }
+
+ return cmp;
+}
+
+/*
+ * Locate static NHLFE that matches with passed info.
+ */
+static zebra_snhlfe_t *
+snhlfe_find (zebra_slsp_t *slsp, enum nexthop_types_t gtype,
+ union g_addr *gate, char *ifname, ifindex_t ifindex)
+{
+ zebra_snhlfe_t *snhlfe;
+
+ if (!slsp)
+ return NULL;
+
+ for (snhlfe = slsp->snhlfe_list; snhlfe; snhlfe = snhlfe->next)
+ {
+ if (!snhlfe_match (snhlfe, gtype, gate, ifname, ifindex))
+ break;
+ }
+
+ return snhlfe;
+}
+
+
+/*
+ * Add static NHLFE. Base LSP config entry must have been created
+ * and duplicate check done.
+ */
+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)
+{
+ zebra_snhlfe_t *snhlfe;
+
+ if (!slsp)
+ return NULL;
+
+ snhlfe = XCALLOC(MTYPE_SNHLFE, sizeof(zebra_snhlfe_t));
+ snhlfe->slsp = slsp;
+ snhlfe->out_label = out_label;
+ snhlfe->gtype = gtype;
+ switch (gtype)
+ {
+ case NEXTHOP_TYPE_IPV4:
+ snhlfe->gate.ipv4 = gate->ipv4;
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ snhlfe->gate.ipv6 = gate->ipv6;
+ if (ifindex)
+ snhlfe->ifindex = ifindex;
+ break;
+ default:
+ XFREE (MTYPE_SNHLFE, snhlfe);
+ return NULL;
+ }
+
+ if (slsp->snhlfe_list)
+ slsp->snhlfe_list->prev = snhlfe;
+ snhlfe->next = slsp->snhlfe_list;
+ slsp->snhlfe_list = snhlfe;
+
+ return snhlfe;
+}
+
+/*
+ * Delete static NHLFE. Entry must be present on list.
+ */
+static int
+snhlfe_del (zebra_snhlfe_t *snhlfe)
+{
+ zebra_slsp_t *slsp;
+
+ if (!snhlfe)
+ return -1;
+
+ slsp = snhlfe->slsp;
+ if (!slsp)
+ return -1;
+
+ if (snhlfe->next)
+ snhlfe->next->prev = snhlfe->prev;
+ if (snhlfe->prev)
+ snhlfe->prev->next = snhlfe->next;
+ else
+ slsp->snhlfe_list = snhlfe->next;
+
+ snhlfe->prev = snhlfe->next = NULL;
+ if (snhlfe->ifname)
+ XFREE (MTYPE_SNHLFE_IFNAME, snhlfe->ifname);
+ XFREE (MTYPE_SNHLFE, snhlfe);
+
+ return 0;
+}
+
+/*
+ * Delete all static NHLFE entries for this LSP (in label).
+ */
+static int
+snhlfe_del_all (zebra_slsp_t *slsp)
+{
+ zebra_snhlfe_t *snhlfe, *snhlfe_next;
+
+ if (!slsp)
+ return -1;
+
+ for (snhlfe = slsp->snhlfe_list; snhlfe; snhlfe = snhlfe_next)
+ {
+ snhlfe_next = snhlfe->next;
+ snhlfe_del (snhlfe);
+ }
+
+ return 0;
+}
+
+/*
+ * Create printable string for NHLFE configuration.
+ */
+static char *
+snhlfe2str (zebra_snhlfe_t *snhlfe, char *buf, int size)
+{
+ buf[0] = '\0';
+ switch (snhlfe->gtype)
+ {
+ case NEXTHOP_TYPE_IPV4:
+ inet_ntop (AF_INET, &snhlfe->gate.ipv4, buf, size);
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ inet_ntop (AF_INET6, &snhlfe->gate.ipv6, buf, size);
+ if (snhlfe->ifindex)
+ strcat (buf, ifindex2ifname (snhlfe->ifindex));
+ break;
+ default:
+ break;
+ }
+
+ return buf;
+}
+
+
+
+/* Public functions */
+
+/*
+ * 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
+ * be consistent - i.e., all paths either do a swap or do PHP. This is due
+ * to current HW restrictions.
+ */
+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)
+{
+ struct hash *slsp_table;
+ zebra_ile_t tmp_ile;
+ zebra_slsp_t *slsp;
+ zebra_snhlfe_t *snhlfe;
+
+ /* Lookup table. */
+ slsp_table = zvrf->slsp_table;
+ if (!slsp_table)
+ return 0;
+
+ /* If entry is not present, exit. */
+ tmp_ile.in_label = in_label;
+ slsp = hash_lookup (slsp_table, &tmp_ile);
+ if (!slsp)
+ return 1;
+
+ snhlfe = snhlfe_find (slsp, gtype, gate, ifname, ifindex);
+ if (snhlfe)
+ {
+ if (snhlfe->out_label == out_label)
+ return 1;
+
+ /* If not only NHLFE, cannot allow label change. */
+ if (snhlfe != slsp->snhlfe_list ||
+ snhlfe->next)
+ return 0;
+ }
+ else
+ {
+ /* If other NHLFEs exist, label operation must match. */
+ if (slsp->snhlfe_list)
+ {
+ int cur_op, new_op;
+
+ cur_op = (slsp->snhlfe_list->out_label == MPLS_IMP_NULL_LABEL);
+ new_op = (out_label == MPLS_IMP_NULL_LABEL);
+ if (cur_op != new_op)
+ return 0;
+ }
+ }
+
+ /* Label values are good. */
+ return 1;
+}
+
+
+/*
+ * Add static LSP entry. This may be the first entry for this incoming label
+ * or an additional nexthop; an existing entry may also have outgoing label
+ * changed.
+ * Note: The label operation (swap or PHP) is common for the LSP entry (all
+ * NHLFEs).
+ */
+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)
+{
+ struct hash *slsp_table;
+ zebra_ile_t tmp_ile;
+ zebra_slsp_t *slsp;
+ zebra_snhlfe_t *snhlfe;
+ char buf[BUFSIZ];
+
+ /* Lookup table. */
+ slsp_table = zvrf->slsp_table;
+ if (!slsp_table)
+ return -1;
+
+ /* If entry is present, exit. */
+ tmp_ile.in_label = in_label;
+ slsp = hash_get (slsp_table, &tmp_ile, slsp_alloc);
+ if (!slsp)
+ return -1;
+ snhlfe = snhlfe_find (slsp, gtype, gate, ifname, ifindex);
+ if (snhlfe)
+ {
+ if (snhlfe->out_label == out_label)
+ /* No change */
+ return 0;
+
+ if (IS_ZEBRA_DEBUG_MPLS)
+ {
+ snhlfe2str (snhlfe, buf, BUFSIZ);
+ zlog_debug ("Upd static LSP in-label %u nexthop %s "
+ "out-label %u (old %u)",
+ in_label, buf, out_label, snhlfe->out_label);
+ }
+ snhlfe->out_label = out_label;
+ }
+ else
+ {
+ /* Add static LSP entry to this nexthop */
+ snhlfe = snhlfe_add (slsp, gtype, gate, ifname, ifindex, out_label);
+ if (!snhlfe)
+ return -1;
+
+ if (IS_ZEBRA_DEBUG_MPLS)
+ {
+ snhlfe2str (snhlfe, buf, BUFSIZ);
+ zlog_debug ("Add static LSP in-label %u nexthop %s out-label %u",
+ in_label, buf, out_label);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Delete static LSP entry. This may be the delete of one particular
+ * NHLFE for this incoming label or the delete of the entire entry (i.e.,
+ * all NHLFEs).
+ * NOTE: Delete of the only NHLFE will also end up deleting the entire
+ * LSP configuration.
+ */
+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)
+{
+ struct hash *slsp_table;
+ zebra_ile_t tmp_ile;
+ zebra_slsp_t *slsp;
+ zebra_snhlfe_t *snhlfe;
+
+ /* Lookup table. */
+ slsp_table = zvrf->slsp_table;
+ if (!slsp_table)
+ return -1;
+
+ /* If entry is not present, exit. */
+ tmp_ile.in_label = in_label;
+ slsp = hash_lookup (slsp_table, &tmp_ile);
+ if (!slsp)
+ return 0;
+
+ /* Is it delete of entire LSP or a specific NHLFE? */
+ if (gtype == NEXTHOP_TYPE_BLACKHOLE)
+ {
+ if (IS_ZEBRA_DEBUG_MPLS)
+ zlog_debug ("Del static LSP in-label %u", in_label);
+
+ /* Delete all static NHLFEs */
+ snhlfe_del_all (slsp);
+ }
+ else
+ {
+ /* Find specific NHLFE, exit if not found. */
+ snhlfe = snhlfe_find (slsp, gtype, gate, ifname, ifindex);
+ if (!snhlfe)
+ return 0;
+
+ if (IS_ZEBRA_DEBUG_MPLS)
+ {
+ char buf[BUFSIZ];
+ snhlfe2str (snhlfe, buf, BUFSIZ);
+ zlog_debug ("Del static LSP in-label %u nexthop %s",
+ in_label, buf);
+ }
+
+ /* Delete static LSP NHLFE */
+ snhlfe_del (snhlfe);
+ }
+
+ /* Remove entire static LSP entry if no NHLFE - valid in either case above. */
+ if (!slsp->snhlfe_list)
+ {
+ slsp = hash_release(slsp_table, &tmp_ile);
+ if (slsp)
+ XFREE(MTYPE_SLSP, slsp);
+ }
+
+ return 0;
+}
+
+/*
+ * Display MPLS LSP configuration of all static LSPs (VTY command handler).
+ */
+int
+zebra_mpls_write_lsp_config (struct vty *vty, struct zebra_vrf *zvrf)
+{
+ hash_iterate(zvrf->slsp_table, lsp_config_write, vty);
+ return (zvrf->slsp_table->count ? 1 : 0);
+}
+
+/*
+ * Allocate MPLS tables for this VRF and do other initialization.
+ * NOTE: Currently supported only for default VRF.
+ */
+void
+zebra_mpls_init_tables (struct zebra_vrf *zvrf)
+{
+ if (!zvrf)
+ return;
+ zvrf->slsp_table = hash_create(label_hash, label_cmp);
+}
+
+/*
+ * Global MPLS initialization.
+ */
+void
+zebra_mpls_init (void)
+{
+ /* Filler for subsequent use. */
+}
diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h
index b24a58e16..b62230ead 100644
--- a/zebra/zebra_mpls.h
+++ b/zebra/zebra_mpls.h
@@ -152,4 +152,60 @@ struct zebra_lsp_t_
};
+/* Function declarations. */
+
+/*
+ * 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
+ * be consistent - i.e., all paths either do a swap or do PHP. This is due
+ * to current HW restrictions.
+ */
+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);
+
+/*
+ * Add static LSP entry. This may be the first entry for this incoming label
+ * or an additional nexthop; an existing entry may also have outgoing label
+ * changed.
+ * Note: The label operation (swap or PHP) is common for the LSP entry (all
+ * NHLFEs).
+ */
+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);
+
+/*
+ * Delete static LSP entry. This may be the delete of one particular
+ * NHLFE for this incoming label or the delete of the entire entry (i.e.,
+ * all NHLFEs).
+ * NOTE: Delete of the only NHLFE will also end up deleting the entire
+ * LSP configuration.
+ */
+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);
+
+/*
+ * Display MPLS LSP configuration of all static LSPs (VTY command handler).
+ */
+int
+zebra_mpls_write_lsp_config (struct vty *vty, struct zebra_vrf *zvrf);
+
+/*
+ * Allocate MPLS tables for this VRF.
+ * NOTE: Currently supported only for default VRF.
+ */
+void
+zebra_mpls_init_tables (struct zebra_vrf *zvrf);
+
+/*
+ * Global MPLS initialization.
+ */
+void
+zebra_mpls_init (void);
+
#endif /*_ZEBRA_MPLS_H */
diff --git a/zebra/zebra_mpls_null.c b/zebra/zebra_mpls_null.c
new file mode 100644
index 000000000..a8c9aa332
--- /dev/null
+++ b/zebra/zebra_mpls_null.c
@@ -0,0 +1,45 @@
+#include <zebra.h>
+#include "nexthop.h"
+#include "zebra/rib.h"
+#include "zebra/zserv.h"
+#include "zebra/zebra_mpls.h"
+
+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)
+{
+ return 1;
+}
+
+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)
+{
+ return 0;
+}
+
+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)
+{
+ return 0;
+}
+
+int
+zebra_mpls_write_lsp_config (struct vty *vty, struct zebra_vrf *zvrf)
+{
+ return 0;
+}
+
+void
+zebra_mpls_init_tables (struct zebra_vrf *zvrf)
+{
+}
+
+void
+zebra_mpls_init (void)
+{
+}
diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c
index 890d749ca..ab825281e 100644
--- a/zebra/zebra_vrf.c
+++ b/zebra/zebra_vrf.c
@@ -32,6 +32,7 @@
#include "zebra/router-id.h"
#include "zebra/zebra_memory.h"
#include "zebra/zebra_static.h"
+#include "zebra/zebra_mpls.h"
extern struct zebra_t zebrad;
struct list *zvrf_list;
@@ -332,6 +333,8 @@ zebra_vrf_alloc (vrf_id_t vrf_id, const char *name)
zvrf->name[strlen(name)] = '\0';
}
+ zebra_mpls_init_tables (zvrf);
+
return zvrf;
}
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index a7ee63d87..4e0df372b 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -30,11 +30,13 @@
#include "rib.h"
#include "nexthop.h"
#include "vrf.h"
+#include "mpls.h"
#include "lib/json.h"
#include "routemap.h"
#include "zebra/zserv.h"
#include "zebra/zebra_vrf.h"
+#include "zebra/zebra_mpls.h"
#include "zebra/zebra_rnh.h"
#include "zebra/redistribute.h"
#include "zebra/zebra_routemap.h"
@@ -1910,6 +1912,160 @@ DEFUN (no_ip_route_mask_flags_tag_distance2_vrf,
return zebra_static_ipv4 (vty, SAFI_UNICAST, 0, argv[0], argv[1], NULL, argv[2], argv[3], argv[4], argv[5]);
}
+static int
+zebra_mpls_transit_lsp (struct vty *vty, int add_cmd, const char *inlabel_str,
+ const char *gate_str, const char *outlabel_str,
+ const char *flag_str)
+{
+ struct zebra_vrf *zvrf;
+ int ret;
+ enum nexthop_types_t gtype;
+ union g_addr gate;
+ mpls_label_t label;
+ mpls_label_t in_label, out_label;
+
+ zvrf = vrf_info_lookup(VRF_DEFAULT);
+ if (!zvrf)
+ {
+ vty_out (vty, "%% Default VRF does not exist%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (!inlabel_str)
+ {
+ vty_out (vty, "%% No Label Information%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ out_label = MPLS_IMP_NULL_LABEL; /* as initialization */
+ label = atoi(inlabel_str);
+ if (!IS_MPLS_UNRESERVED_LABEL(label))
+ {
+ vty_out (vty, "%% Invalid label%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (add_cmd)
+ {
+ if (!gate_str)
+ {
+ vty_out (vty, "%% No Nexthop Information%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (!outlabel_str)
+ {
+ vty_out (vty, "%% No Outgoing label Information%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+
+ in_label = label;
+ gtype = NEXTHOP_TYPE_BLACKHOLE; /* as initialization */
+
+ if (gate_str)
+ {
+ /* Gateway is a IPv4 or IPv6 nexthop. */
+ ret = inet_pton (AF_INET6, gate_str, &gate.ipv6);
+ if (ret)
+ gtype = NEXTHOP_TYPE_IPV6;
+ else
+ {
+ ret = inet_pton (AF_INET, gate_str, &gate.ipv4);
+ if (ret)
+ gtype = NEXTHOP_TYPE_IPV4;
+ else
+ {
+ vty_out (vty, "%% Invalid nexthop%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+ }
+
+ if (outlabel_str)
+ {
+ if (outlabel_str[0] == 'i')
+ out_label = MPLS_IMP_NULL_LABEL;
+ else
+ out_label = atoi(outlabel_str);
+ }
+
+ if (add_cmd)
+ {
+ /* Check that label value is consistent. */
+ if (!zebra_mpls_lsp_label_consistent (zvrf, in_label, out_label, gtype,
+ &gate, NULL, 0))
+ {
+ vty_out (vty, "%% Label value not consistent%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ ret = zebra_mpls_static_lsp_add (zvrf, in_label, out_label, gtype,
+ &gate, NULL, 0);
+ }
+ else
+ ret = zebra_mpls_static_lsp_del (zvrf, in_label, gtype, &gate, NULL, 0);
+
+ if (ret)
+ {
+ vty_out (vty, "%% LSP cannot be %s%s",
+ add_cmd ? "added" : "deleted", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (mpls_transit_lsp,
+ mpls_transit_lsp_cmd,
+ "mpls lsp <16-1048575> (A.B.C.D|X:X::X:X) (<16-1048575>|implicit-null)",
+ MPLS_STR
+ "Establish label switched path\n"
+ "Incoming MPLS label\n"
+ "IPv4 gateway address\n"
+ "IPv6 gateway address\n"
+ "Outgoing MPLS label\n"
+ "Use Implicit-Null label\n")
+{
+ return zebra_mpls_transit_lsp (vty, 1, argv[0], argv[1], argv[2], NULL);
+}
+
+DEFUN (no_mpls_transit_lsp,
+ no_mpls_transit_lsp_cmd,
+ "no mpls lsp <16-1048575> (A.B.C.D|X:X::X:X)",
+ NO_STR
+ MPLS_STR
+ "Establish label switched path\n"
+ "Incoming MPLS label\n"
+ "IPv4 gateway address\n"
+ "IPv6 gateway address\n")
+{
+ return zebra_mpls_transit_lsp (vty, 0, argv[0], argv[1], NULL, NULL);
+}
+
+ALIAS (no_mpls_transit_lsp,
+ no_mpls_transit_lsp_out_label_cmd,
+ "no mpls lsp <16-1048575> (A.B.C.D|X:X::X:X) (<16-1048575>|implicit-null)",
+ NO_STR
+ MPLS_STR
+ "Establish label switched path\n"
+ "Incoming MPLS label\n"
+ "IPv4 gateway address\n"
+ "IPv6 gateway address\n"
+ "Outgoing MPLS label\n"
+ "Use Implicit-Null label\n")
+
+DEFUN (no_mpls_transit_lsp_all,
+ no_mpls_transit_lsp_all_cmd,
+ "no mpls lsp <16-1048575>",
+ NO_STR
+ MPLS_STR
+ "Establish label switched path\n"
+ "Incoming MPLS label\n")
+{
+ return zebra_mpls_transit_lsp (vty, 0, argv[0], NULL, NULL, NULL);
+}
+
/* New RIB. Detailed information for IPv4 route. */
static void
vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast)
@@ -5738,6 +5894,21 @@ zebra_ip_config (struct vty *vty)
return write;
}
+/* MPLS LSP configuration write function. */
+static int
+zebra_mpls_config (struct vty *vty)
+{
+ int write = 0;
+ struct zebra_vrf *zvrf;
+
+ zvrf = vrf_info_lookup(VRF_DEFAULT);
+ if (!zvrf)
+ return 0;
+
+ write += zebra_mpls_write_lsp_config(vty, zvrf);
+ return write;
+}
+
DEFUN (ip_zebra_import_table_distance,
ip_zebra_import_table_distance_cmd,
"ip import-table <1-252> distance <1-255>",
@@ -5905,12 +6076,16 @@ config_write_protocol (struct vty *vty)
static struct cmd_node ip_node = { IP_NODE, "", 1 };
static struct cmd_node protocol_node = { PROTOCOL_NODE, "", 1 };
+/* MPLS node for MPLS LSP. */
+static struct cmd_node mpls_node = { MPLS_NODE, "", 1 };
+
/* Route VTY. */
void
zebra_vty_init (void)
{
install_node (&ip_node, zebra_ip_config);
install_node (&protocol_node, config_write_protocol);
+ install_node (&mpls_node, zebra_mpls_config);
install_element (CONFIG_NODE, &allow_external_route_update_cmd);
install_element (CONFIG_NODE, &no_allow_external_route_update_cmd);
@@ -6238,4 +6413,9 @@ zebra_vty_init (void)
install_element (VIEW_NODE, &show_ipv6_mroute_vrf_all_cmd);
install_element (ENABLE_NODE, &show_ipv6_mroute_vrf_all_cmd);
#endif /* HAVE_IPV6 */
+
+ install_element (CONFIG_NODE, &mpls_transit_lsp_cmd);
+ 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);
}