summaryrefslogtreecommitdiffstats
path: root/isisd
diff options
context:
space:
mode:
authorOlivier Dugeon <olivier.dugeon@orange.com>2016-04-19 19:03:05 +0200
committerDonald Sharp <sharpd@cumulusnetwroks.com>2016-09-03 17:05:50 +0200
commitf8c06e2c5270144ea6d1a3fbc70b42979db836db (patch)
treec8bc0f78a5c07792111bfc76da4f6814c7a51f37 /isisd
parentUpdate Traffic Engineering Support for OSPFD (diff)
downloadfrr-f8c06e2c5270144ea6d1a3fbc70b42979db836db.tar.xz
frr-f8c06e2c5270144ea6d1a3fbc70b42979db836db.zip
Add support of Traffic Engineering to IS-IS
These patches is an implementation of RFC5305 that enable the support of Traffic Engineering in IS-IS * isisd/Makefile.am: Add new files isis_te.c and isis_te.h * isisd/isis_circuit.[c,h]: Add new mpls_te_circuit structure to isis_circuit structure to handle new Traffic Engineering TLVs * isisd/isis_lsp.c: Update LSP handler to mux/demux Traffic Engineering TLVs * isisd/isis_main.c: Add initialisation of ISIS TE * isisd/isis_pdu.c: Update function process_p2p_hello() to retrieve remote IP address to populate Traffic Engineering TLV. * isisd/isis_te.[c,]: Implementation of RFC5305 * isisd/isis_tlv.[c,h]: Update TLV definition and function to handle Traffic Engineering ones * isisd/isis_zebra.c: Add new function isis_zebra_link_params() to retrieve the link parameters of interfaces from ZBus to populate the Traffic Engineering TLVs * isisd/isisd.[c,h]: Add Traffic Engineering support with new debug command Signed-off-by: Olivier Dugeon <olivier.dugeon@orange.com>
Diffstat (limited to 'isisd')
-rw-r--r--isisd/AUTHORS1
-rw-r--r--isisd/Makefile.am4
-rw-r--r--isisd/isis_circuit.c9
-rw-r--r--isisd/isis_circuit.h3
-rw-r--r--isisd/isis_lsp.c81
-rw-r--r--isisd/isis_lsp.h2
-rw-r--r--isisd/isis_main.c3
-rw-r--r--isisd/isis_pdu.c10
-rw-r--r--isisd/isis_te.c1372
-rw-r--r--isisd/isis_te.h331
-rw-r--r--isisd/isis_tlv.c35
-rw-r--r--isisd/isis_tlv.h20
-rw-r--r--isisd/isis_zebra.c26
-rw-r--r--isisd/isisd.c13
-rw-r--r--isisd/isisd.h4
15 files changed, 1896 insertions, 18 deletions
diff --git a/isisd/AUTHORS b/isisd/AUTHORS
index 05fc0a507..80b3a28e1 100644
--- a/isisd/AUTHORS
+++ b/isisd/AUTHORS
@@ -2,3 +2,4 @@ Sampo Saaristo <sambo@cs.tut.fi>
Ofer Wald <ofersf@islands.co.il>
Hannes Gredler <hannes@gredler.at>
Subbaiah Venkata <svenkata@google.com>
+Olivier Dugeon <olivier.dugeon@orange.com>
diff --git a/isisd/Makefile.am b/isisd/Makefile.am
index 6dd132d49..bfe2e9477 100644
--- a/isisd/Makefile.am
+++ b/isisd/Makefile.am
@@ -16,7 +16,7 @@ libisis_a_SOURCES = \
isis_adjacency.c isis_lsp.c dict.c isis_circuit.c isis_pdu.c \
isis_tlv.c isisd.c isis_misc.c isis_zebra.c isis_dr.c \
isis_flags.c isis_dynhn.c iso_checksum.c isis_csm.c isis_events.c \
- isis_spf.c isis_redist.c isis_route.c isis_routemap.c \
+ isis_spf.c isis_redist.c isis_route.c isis_routemap.c isis_te.c \
isis_vty.c
@@ -25,7 +25,7 @@ noinst_HEADERS = \
isis_lsp.h dict.h isis_circuit.h isis_misc.h isis_network.h \
isis_zebra.h isis_dr.h isis_flags.h isis_dynhn.h isis_common.h \
iso_checksum.h isis_csm.h isis_events.h isis_spf.h isis_redist.h \
- isis_route.h isis_routemap.h \
+ isis_route.h isis_routemap.h isis_te.h \
include-netbsd/clnp.h include-netbsd/esis.h include-netbsd/iso.h
isisd_SOURCES = \
diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c
index 7138b4231..4f22a5e55 100644
--- a/isisd/isis_circuit.c
+++ b/isisd/isis_circuit.c
@@ -37,6 +37,7 @@
#include "linklist.h"
#include "command.h"
#include "thread.h"
+#include "vty.h"
#include "hash.h"
#include "prefix.h"
#include "stream.h"
@@ -58,6 +59,7 @@
#include "isisd/isisd.h"
#include "isisd/isis_csm.h"
#include "isisd/isis_events.h"
+#include "isisd/isis_te.h"
/*
* Prototypes.
@@ -96,6 +98,8 @@ isis_circuit_new ()
circuit->te_metric[i] = DEFAULT_CIRCUIT_METRIC;
}
+ circuit->mtc = mpls_te_circuit_new();
+
return circuit;
}
@@ -222,6 +226,10 @@ isis_circuit_add_addr (struct isis_circuit *circuit,
ipv4->prefixlen = connected->address->prefixlen;
ipv4->prefix = connected->address->u.prefix4;
listnode_add (circuit->ip_addrs, ipv4);
+
+ /* Update MPLS TE Local IP address parameter */
+ set_circuitparams_local_ipaddr (circuit->mtc, ipv4->prefix);
+
if (circuit->area)
lsp_regenerate_schedule (circuit->area, circuit->is_type, 0);
@@ -518,6 +526,7 @@ isis_circuit_if_bind (struct isis_circuit *circuit, struct interface *ifp)
assert (ifp->info == circuit);
else
ifp->info = circuit;
+ isis_link_params_update (circuit, ifp);
}
void
diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h
index 9d6e426d4..9ada1e26a 100644
--- a/isisd/isis_circuit.h
+++ b/isisd/isis_circuit.h
@@ -112,13 +112,14 @@ struct isis_circuit
*/
struct isis_passwd passwd; /* Circuit rx/tx password */
int is_type; /* circuit is type == level of circuit
- * diffrenciated from circuit type (media) */
+ * differentiated from circuit type (media) */
u_int32_t hello_interval[2]; /* l1HelloInterval in msecs */
u_int16_t hello_multiplier[2]; /* l1HelloMultiplier */
u_int16_t csnp_interval[2]; /* level-1 csnp-interval in seconds */
u_int16_t psnp_interval[2]; /* level-1 psnp-interval in seconds */
u_int8_t metric[2];
u_int32_t te_metric[2];
+ struct mpls_te_circuit *mtc; /* Support for MPLS-TE parameters - see isis_te.[c,h] */
int ip_router; /* Route IP ? */
int is_passive; /* Is Passive ? */
struct list *ip_addrs; /* our IP addresses */
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
index 81f1958e6..0177a9423 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -52,6 +52,7 @@
#include "isisd/isis_csm.h"
#include "isisd/isis_adjacency.h"
#include "isisd/isis_spf.h"
+#include "isisd/isis_te.h"
#ifdef TOPOLOGY_GENERATE
#include "spgrid.h"
@@ -981,6 +982,8 @@ lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost)
lspid_print (te_is_neigh->neigh_id, LSPid, dynhost, 0);
vty_out (vty, " Metric : %-8d IS-Extended : %s%s",
GET_TE_METRIC(te_is_neigh), LSPid, VTY_NEWLINE);
+ if (IS_MPLS_TE(isisMplsTE))
+ mpls_te_print_detail(vty, te_is_neigh);
}
/* TE IPv4 tlv */
@@ -1091,6 +1094,64 @@ lsp_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to,
return;
}
+/* Process IS_NEIGHBOURS TLV with TE subTLVs */
+void
+lsp_te_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to, int frag_thold)
+{
+ int count, size = 0;
+ struct listnode *node, *nextnode;
+ struct te_is_neigh *elem;
+
+ /* Start computing real size of TLVs */
+ for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem))
+ size = size + elem->sub_tlvs_length + IS_NEIGHBOURS_LEN;
+
+ /* can we fit all ? */
+ if (!FRAG_NEEDED (lsp->pdu, frag_thold, size))
+ {
+ tlv_add_te_is_neighs (*from, lsp->pdu);
+ if (listcount (*to) != 0)
+ {
+ for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem))
+ {
+ listnode_add (*to, elem);
+ list_delete_node (*from, node);
+ }
+ }
+ else
+ {
+ list_free (*to);
+ *to = *from;
+ *from = NULL;
+ }
+ }
+ else
+ {
+ /* fit all we can */
+ /* Compute remaining place in LSP PDU */
+ count = FRAG_THOLD (lsp->pdu, frag_thold) - 2 -
+ (STREAM_SIZE (lsp->pdu) - STREAM_REMAIN (lsp->pdu));
+ /* Determine size of TE SubTLVs */
+ elem = (struct te_is_neigh *)listgetdata ((struct listnode *)listhead (*from));
+ count = count - elem->sub_tlvs_length - IS_NEIGHBOURS_LEN;
+ if (count > 0)
+ {
+ while (count > 0)
+ {
+ listnode_add (*to, listgetdata ((struct listnode *)listhead (*from)));
+ listnode_delete (*from, listgetdata ((struct listnode *)listhead (*from)));
+
+ elem = (struct te_is_neigh *)listgetdata ((struct listnode *)listhead (*from));
+ count = count - elem->sub_tlvs_length - IS_NEIGHBOURS_LEN;
+ }
+
+ tlv_add_te_is_neighs (*to, lsp->pdu);
+ }
+ }
+ lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
+ return;
+}
+
static u_int16_t
lsp_rem_lifetime (struct isis_area *area, int level)
{
@@ -1631,6 +1692,14 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
}
else
{
+ /* Check if MPLS_TE is activate */
+ if (IS_MPLS_TE(isisMplsTE) && HAS_LINK_PARAMS(circuit->interface))
+ /* Add SubTLVs & Adjust real size of SubTLVs */
+ te_is_neigh->sub_tlvs_length = add_te_subtlvs(te_is_neigh->sub_tlvs, circuit->mtc);
+ else
+ /* Or keep only TE metric with no SubTLVs if MPLS_TE is off */
+ te_is_neigh->sub_tlvs_length = 0;
+
listnode_add (tlv_data.te_is_neighs, te_is_neigh);
lsp_debug("ISIS (%s): Adding DIS %s.%02x as te-style neighbor",
area->area_tag, sysid_print(te_is_neigh->neigh_id),
@@ -1679,6 +1748,18 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area)
memcpy (te_is_neigh->neigh_id, nei->sysid, ISIS_SYS_ID_LEN);
metric = circuit->te_metric[level - 1];
SET_TE_METRIC(te_is_neigh, metric);
+ /* Check if MPLS_TE is activate */
+ if (IS_MPLS_TE(isisMplsTE) && HAS_LINK_PARAMS(circuit->interface))
+ /* Update Local and Remote IP address for MPLS TE circuit parameters */
+ /* NOTE sure that it is the pertinent place for that updates */
+ /* Local IP address could be updated in isis_circuit.c - isis_circuit_add_addr() */
+ /* But, where update remote IP address ? in isis_pdu.c - process_p2p_hello() ? */
+
+ /* Add SubTLVs & Adjust real size of SubTLVs */
+ te_is_neigh->sub_tlvs_length = add_te_subtlvs(te_is_neigh->sub_tlvs, circuit->mtc);
+ else
+ /* Or keep only TE metric with no SubTLVs if MPLS_TE is off */
+ te_is_neigh->sub_tlvs_length = 0;
listnode_add (tlv_data.te_is_neighs, te_is_neigh);
lsp_debug("ISIS (%s): Adding te-style is reach for %s", area->area_tag,
sysid_print(te_is_neigh->neigh_id));
diff --git a/isisd/isis_lsp.h b/isisd/isis_lsp.h
index a35bfa762..7b2286b18 100644
--- a/isisd/isis_lsp.h
+++ b/isisd/isis_lsp.h
@@ -112,6 +112,8 @@ void lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost);
int lsp_print_all (struct vty *vty, dict_t * lspdb, char detail,
char dynhost);
const char *lsp_bits2string (u_char *);
+void lsp_te_tlv_fit (struct isis_lsp *lsp, struct list **from,
+ struct list **to, int frag_thold);
/* sets SRMflags for all active circuits of an lsp */
void lsp_set_all_srmflags (struct isis_lsp *lsp);
diff --git a/isisd/isis_main.c b/isisd/isis_main.c
index 234e516db..81ca1e20c 100644
--- a/isisd/isis_main.c
+++ b/isisd/isis_main.c
@@ -50,6 +50,8 @@
#include "isisd/isis_route.h"
#include "isisd/isis_routemap.h"
#include "isisd/isis_zebra.h"
+#include "isisd/isis_tlv.h"
+#include "isisd/isis_te.h"
/* Default configuration file name */
#define ISISD_DEFAULT_CONFIG "isisd.conf"
@@ -348,6 +350,7 @@ main (int argc, char **argv, char **envp)
isis_spf_cmds_init ();
isis_redist_init ();
isis_route_map_init();
+ isis_mpls_te_init();
/* create the global 'isis' instance */
isis_new (1);
diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c
index 0401e44a9..1dfb4623f 100644
--- a/isisd/isis_pdu.c
+++ b/isisd/isis_pdu.c
@@ -53,6 +53,7 @@
#include "isisd/iso_checksum.h"
#include "isisd/isis_csm.h"
#include "isisd/isis_events.h"
+#include "isisd/isis_te.h"
#define ISIS_MINIMUM_FIXED_HDR_LEN 15
#define ISIS_MIN_PDU_LEN 13 /* partial seqnum pdu with id_len=2 */
@@ -630,6 +631,15 @@ process_p2p_hello (struct isis_circuit *circuit)
if (found & TLVFLAG_IPV4_ADDR)
tlvs_to_adj_ipv4_addrs (&tlvs, adj);
+ /* Update MPLS TE Remote IP address parameter if possible */
+ if (IS_MPLS_TE(isisMplsTE) && circuit->mtc && IS_CIRCUIT_TE(circuit->mtc))
+ if (adj->ipv4_addrs != NULL && listcount(adj->ipv4_addrs) != 0)
+ {
+ struct in_addr *ip_addr;
+ ip_addr = (struct in_addr *)listgetdata ((struct listnode *)listhead (adj->ipv4_addrs));
+ set_circuitparams_rmt_ipaddr (circuit->mtc, *ip_addr);
+ }
+
#ifdef HAVE_IPV6
if (found & TLVFLAG_IPV6_ADDR)
tlvs_to_adj_ipv6_addrs (&tlvs, adj);
diff --git a/isisd/isis_te.c b/isisd/isis_te.c
new file mode 100644
index 000000000..247d699b1
--- /dev/null
+++ b/isisd/isis_te.c
@@ -0,0 +1,1372 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_te.c
+ *
+ * This is an implementation of RFC5305
+ *
+ * Copyright (C) 2014 Orange Labs
+ * http://www.orange.com
+ *
+ * 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 <math.h>
+
+#include "linklist.h"
+#include "thread.h"
+#include "vty.h"
+#include "stream.h"
+#include "memory.h"
+#include "log.h"
+#include "prefix.h"
+#include "command.h"
+#include "hash.h"
+#include "if.h"
+#include "vrf.h"
+#include "checksum.h"
+#include "md5.h"
+#include "sockunion.h"
+#include "network.h"
+
+#include "isisd/dict.h"
+#include "isisd/isis_constants.h"
+#include "isisd/isis_common.h"
+#include "isisd/isis_flags.h"
+#include "isisd/isis_circuit.h"
+#include "isisd/isisd.h"
+#include "isisd/isis_tlv.h"
+#include "isisd/isis_lsp.h"
+#include "isisd/isis_pdu.h"
+#include "isisd/isis_dynhn.h"
+#include "isisd/isis_misc.h"
+#include "isisd/isis_csm.h"
+#include "isisd/isis_adjacency.h"
+#include "isisd/isis_spf.h"
+#include "isisd/isis_te.h"
+
+/* Global varial for MPLS TE management */
+struct isis_mpls_te isisMplsTE;
+
+const char *mode2text[] = { "Disable", "Area", "AS", "Emulate" };
+
+/*------------------------------------------------------------------------*
+ * Followings are control functions for MPLS-TE parameters management.
+ *------------------------------------------------------------------------*/
+
+/* Search MPLS TE Circuit context from Interface */
+static struct mpls_te_circuit *
+lookup_mpls_params_by_ifp (struct interface *ifp)
+{
+ struct isis_circuit *circuit;
+
+ if ((circuit = circuit_scan_by_ifp (ifp)) == NULL)
+ return NULL;
+
+ return circuit->mtc;
+}
+
+/* Create new MPLS TE Circuit context */
+struct mpls_te_circuit *
+mpls_te_circuit_new()
+{
+ struct mpls_te_circuit *mtc;
+
+ zlog_debug ("ISIS MPLS-TE: Create new MPLS TE Circuit context");
+
+ mtc = XCALLOC(MTYPE_ISIS_MPLS_TE, sizeof (struct mpls_te_circuit));
+
+ if (mtc == NULL)
+ return NULL;
+
+ mtc->status = disable;
+ mtc->type = STD_TE;
+ mtc->length = 0;
+
+ return mtc;
+
+}
+
+/* Copy SUB TLVs parameters into a buffer - No space verification are performed */
+/* Caller must verify before that there is enough free space in the buffer */
+u_char
+add_te_subtlvs(u_char *buf, struct mpls_te_circuit *mtc)
+{
+ u_char size, *tlvs = buf;
+
+ zlog_debug ("ISIS MPLS-TE: Add TE Sub TLVs to buffer");
+
+ if (mtc == NULL)
+ {
+ zlog_debug("ISIS MPLS-TE: Abort! No MPLS TE Circuit available has been specified");
+ return 0;
+ }
+
+ /* Create buffer if not provided */
+ if (buf == NULL)
+ {
+ zlog_debug("ISIS MPLS-TE: Abort! No Buffer has been specified");
+ return 0;
+ }
+
+ /* TE_SUBTLV_ADMIN_GRP */
+ if (SUBTLV_TYPE(mtc->admin_grp) != 0)
+ {
+ size = SUBTLV_SIZE (&(mtc->admin_grp.header));
+ memcpy(tlvs, &(mtc->admin_grp), size);
+ tlvs += size;
+ }
+
+ /* TE_SUBTLV_LLRI */
+ if (SUBTLV_TYPE(mtc->llri) != 0)
+ {
+ size = SUBTLV_SIZE (&(mtc->llri.header));
+ memcpy(tlvs, &(mtc->llri), size);
+ tlvs += size;
+ }
+
+ /* TE_SUBTLV_LCLIF_IPADDR */
+ if (SUBTLV_TYPE(mtc->local_ipaddr) != 0)
+ {
+ size = SUBTLV_SIZE (&(mtc->local_ipaddr.header));
+ memcpy(tlvs, &(mtc->local_ipaddr), size);
+ tlvs += size;
+ }
+
+ /* TE_SUBTLV_RMTIF_IPADDR */
+ if (SUBTLV_TYPE(mtc->rmt_ipaddr) != 0)
+ {
+ size = SUBTLV_SIZE (&(mtc->rmt_ipaddr.header));
+ memcpy(tlvs, &(mtc->rmt_ipaddr), size);
+ tlvs += size;
+ }
+
+ /* TE_SUBTLV_MAX_BW */
+ if (SUBTLV_TYPE(mtc->max_bw) != 0)
+ {
+ size = SUBTLV_SIZE (&(mtc->max_bw.header));
+ memcpy(tlvs, &(mtc->max_bw), size);
+ tlvs += size;
+ }
+
+ /* TE_SUBTLV_MAX_RSV_BW */
+ if (SUBTLV_TYPE(mtc->max_rsv_bw) != 0)
+ {
+ size = SUBTLV_SIZE (&(mtc->max_rsv_bw.header));
+ memcpy(tlvs, &(mtc->max_rsv_bw), size);
+ tlvs += size;
+ }
+
+ /* TE_SUBTLV_UNRSV_BW */
+ if (SUBTLV_TYPE(mtc->unrsv_bw) != 0)
+ {
+ size = SUBTLV_SIZE (&(mtc->unrsv_bw.header));
+ memcpy(tlvs, &(mtc->unrsv_bw), size);
+ tlvs += size;
+ }
+
+ /* TE_SUBTLV_TE_METRIC */
+ if (SUBTLV_TYPE(mtc->te_metric) != 0)
+ {
+ size = SUBTLV_SIZE (&(mtc->te_metric.header));
+ memcpy(tlvs, &(mtc->te_metric), size);
+ tlvs += size;
+ }
+
+ /* TE_SUBTLV_AV_DELAY */
+ if (SUBTLV_TYPE(mtc->av_delay) != 0)
+ {
+ size = SUBTLV_SIZE (&(mtc->av_delay.header));
+ memcpy(tlvs, &(mtc->av_delay), size);
+ tlvs += size;
+ }
+
+ /* TE_SUBTLV_MM_DELAY */
+ if (SUBTLV_TYPE(mtc->mm_delay) != 0)
+ {
+ size = SUBTLV_SIZE (&(mtc->mm_delay.header));
+ memcpy(tlvs, &(mtc->mm_delay), size);
+ tlvs += size;
+ }
+
+ /* TE_SUBTLV_DELAY_VAR */
+ if (SUBTLV_TYPE(mtc->delay_var) != 0)
+ {
+ size = SUBTLV_SIZE (&(mtc->delay_var.header));
+ memcpy(tlvs, &(mtc->delay_var), size);
+ tlvs += size;
+ }
+
+ /* TE_SUBTLV_PKT_LOSS */
+ if (SUBTLV_TYPE(mtc->pkt_loss) != 0)
+ {
+ size = SUBTLV_SIZE (&(mtc->pkt_loss.header));
+ memcpy(tlvs, &(mtc->pkt_loss), size);
+ tlvs += size;
+ }
+
+ /* TE_SUBTLV_RES_BW */
+ if (SUBTLV_TYPE(mtc->res_bw) != 0)
+ {
+ size = SUBTLV_SIZE (&(mtc->res_bw.header));
+ memcpy(tlvs, &(mtc->res_bw), size);
+ tlvs += size;
+ }
+
+ /* TE_SUBTLV_AVA_BW */
+ if (SUBTLV_TYPE(mtc->ava_bw) != 0)
+ {
+ size = SUBTLV_SIZE (&(mtc->ava_bw.header));
+ memcpy(tlvs, &(mtc->ava_bw), size);
+ tlvs += size;
+ }
+
+ /* TE_SUBTLV_USE_BW */
+ if (SUBTLV_TYPE(mtc->use_bw) != 0)
+ {
+ size = SUBTLV_SIZE (&(mtc->use_bw.header));
+ memcpy(tlvs, &(mtc->use_bw), size);
+ tlvs += size;
+ }
+
+ /* Update SubTLVs length */
+ mtc->length = subtlvs_len(mtc);
+
+ zlog_debug("ISIS MPLS-TE: Add %d bytes length SubTLVs", mtc->length);
+
+ return mtc->length;
+}
+
+/* Compute total Sub-TLVs size */
+u_char
+subtlvs_len (struct mpls_te_circuit *mtc)
+{
+ int length = 0;
+
+ /* Sanity Check */
+ if (mtc == NULL)
+ return 0;
+
+ /* TE_SUBTLV_ADMIN_GRP */
+ if (SUBTLV_TYPE(mtc->admin_grp) != 0)
+ length += SUBTLV_SIZE (&(mtc->admin_grp.header));
+
+ /* TE_SUBTLV_LLRI */
+ if (SUBTLV_TYPE(mtc->llri) != 0)
+ length += SUBTLV_SIZE (&mtc->llri.header);
+
+ /* TE_SUBTLV_LCLIF_IPADDR */
+ if (SUBTLV_TYPE(mtc->local_ipaddr) != 0)
+ length += SUBTLV_SIZE (&mtc->local_ipaddr.header);
+
+ /* TE_SUBTLV_RMTIF_IPADDR */
+ if (SUBTLV_TYPE(mtc->rmt_ipaddr) != 0)
+ length += SUBTLV_SIZE (&mtc->rmt_ipaddr.header);
+
+ /* TE_SUBTLV_MAX_BW */
+ if (SUBTLV_TYPE(mtc->max_bw) != 0)
+ length += SUBTLV_SIZE (&mtc->max_bw.header);
+
+ /* TE_SUBTLV_MAX_RSV_BW */
+ if (SUBTLV_TYPE(mtc->max_rsv_bw) != 0)
+ length += SUBTLV_SIZE (&mtc->max_rsv_bw.header);
+
+ /* TE_SUBTLV_UNRSV_BW */
+ if (SUBTLV_TYPE(mtc->unrsv_bw) != 0)
+ length += SUBTLV_SIZE (&mtc->unrsv_bw.header);
+
+ /* TE_SUBTLV_TE_METRIC */
+ if (SUBTLV_TYPE(mtc->te_metric) != 0)
+ length += SUBTLV_SIZE (&mtc->te_metric.header);
+
+ /* TE_SUBTLV_AV_DELAY */
+ if (SUBTLV_TYPE(mtc->av_delay) != 0)
+ length += SUBTLV_SIZE (&mtc->av_delay.header);
+
+ /* TE_SUBTLV_MM_DELAY */
+ if (SUBTLV_TYPE(mtc->mm_delay) != 0)
+ length += SUBTLV_SIZE (&mtc->mm_delay.header);
+
+ /* TE_SUBTLV_DELAY_VAR */
+ if (SUBTLV_TYPE(mtc->delay_var) != 0)
+ length += SUBTLV_SIZE (&mtc->delay_var.header);
+
+ /* TE_SUBTLV_PKT_LOSS */
+ if (SUBTLV_TYPE(mtc->pkt_loss) != 0)
+ length += SUBTLV_SIZE (&mtc->pkt_loss.header);
+
+ /* TE_SUBTLV_RES_BW */
+ if (SUBTLV_TYPE(mtc->res_bw) != 0)
+ length += SUBTLV_SIZE (&mtc->res_bw.header);
+
+ /* TE_SUBTLV_AVA_BW */
+ if (SUBTLV_TYPE(mtc->ava_bw) != 0)
+ length += SUBTLV_SIZE (&mtc->ava_bw.header);
+
+ /* TE_SUBTLV_USE_BW */
+ if (SUBTLV_TYPE(mtc->use_bw) != 0)
+ length += SUBTLV_SIZE (&mtc->use_bw.header);
+
+ /* Check that length is lower than the MAXIMUM SUBTLV size i.e. 256 */
+ if (length > MAX_SUBTLV_SIZE)
+ {
+ mtc->length = 0;
+ return 0;
+ }
+
+ mtc->length = (u_char)length;
+
+ return mtc->length;
+}
+
+/* Following are various functions to set MPLS TE parameters */
+static void
+set_circuitparams_admin_grp (struct mpls_te_circuit *mtc, u_int32_t admingrp)
+{
+ SUBTLV_TYPE(mtc->admin_grp) = TE_SUBTLV_ADMIN_GRP;
+ SUBTLV_LEN(mtc->admin_grp) = SUBTLV_DEF_SIZE;
+ mtc->admin_grp.value = htonl(admingrp);
+ return;
+}
+
+static void __attribute__ ((unused))
+set_circuitparams_llri (struct mpls_te_circuit *mtc, u_int32_t local, u_int32_t remote)
+{
+ SUBTLV_TYPE(mtc->llri) = TE_SUBTLV_LLRI;
+ SUBTLV_LEN(mtc->llri) = TE_SUBTLV_LLRI_SIZE;
+ mtc->llri.local = htonl(local);
+ mtc->llri.remote = htonl(remote);
+}
+
+void
+set_circuitparams_local_ipaddr (struct mpls_te_circuit *mtc, struct in_addr addr)
+{
+
+ SUBTLV_TYPE(mtc->local_ipaddr) = TE_SUBTLV_LOCAL_IPADDR;
+ SUBTLV_LEN(mtc->local_ipaddr) = SUBTLV_DEF_SIZE;
+ mtc->local_ipaddr.value.s_addr = addr.s_addr;
+ return;
+}
+
+void
+set_circuitparams_rmt_ipaddr (struct mpls_te_circuit *mtc, struct in_addr addr)
+{
+
+ SUBTLV_TYPE(mtc->rmt_ipaddr) = TE_SUBTLV_RMT_IPADDR;
+ SUBTLV_LEN(mtc->rmt_ipaddr) = SUBTLV_DEF_SIZE;
+ mtc->rmt_ipaddr.value.s_addr = addr.s_addr;
+ return;
+}
+
+static void
+set_circuitparams_max_bw (struct mpls_te_circuit *mtc, float fp)
+{
+ SUBTLV_TYPE(mtc->max_bw) = TE_SUBTLV_MAX_BW;
+ SUBTLV_LEN(mtc->max_bw) = SUBTLV_DEF_SIZE;
+ mtc->max_bw.value = htonf(fp);
+ return;
+}
+
+static void
+set_circuitparams_max_rsv_bw (struct mpls_te_circuit *mtc, float fp)
+{
+ SUBTLV_TYPE(mtc->max_rsv_bw) = TE_SUBTLV_MAX_RSV_BW;
+ SUBTLV_LEN(mtc->max_rsv_bw) = SUBTLV_DEF_SIZE;
+ mtc->max_rsv_bw.value = htonf(fp);
+ return;
+}
+
+static void
+set_circuitparams_unrsv_bw (struct mpls_te_circuit *mtc, int priority, float fp)
+{
+ /* Note that TLV-length field is the size of array. */
+ SUBTLV_TYPE(mtc->unrsv_bw) = TE_SUBTLV_UNRSV_BW;
+ SUBTLV_LEN(mtc->unrsv_bw) = TE_SUBTLV_UNRSV_SIZE;
+ mtc->unrsv_bw.value[priority] = htonf(fp);
+ return;
+}
+
+static void
+set_circuitparams_te_metric (struct mpls_te_circuit *mtc, u_int32_t te_metric)
+{
+ SUBTLV_TYPE(mtc->te_metric) = TE_SUBTLV_TE_METRIC;
+ SUBTLV_LEN(mtc->te_metric) = TE_SUBTLV_TE_METRIC_SIZE;
+ mtc->te_metric.value[0] = (te_metric >> 16) & 0xFF;
+ mtc->te_metric.value[1] = (te_metric >> 8) & 0xFF;
+ mtc->te_metric.value[2] = te_metric & 0xFF;
+ return;
+}
+
+static void
+set_circuitparams_inter_as (struct mpls_te_circuit *mtc, struct in_addr addr, u_int32_t as)
+{
+
+ /* Set the Remote ASBR IP address and then the associated AS number */
+ SUBTLV_TYPE(mtc->rip) = TE_SUBTLV_RIP;
+ SUBTLV_LEN(mtc->rip) = SUBTLV_DEF_SIZE;
+ mtc->rip.value.s_addr = addr.s_addr;
+
+ SUBTLV_TYPE(mtc->ras) = TE_SUBTLV_RAS;
+ SUBTLV_LEN(mtc->ras) = SUBTLV_DEF_SIZE;
+ mtc->ras.value = htonl(as);
+}
+
+static void
+unset_circuitparams_inter_as (struct mpls_te_circuit *mtc)
+{
+
+ /* Reset the Remote ASBR IP address and then the associated AS number */
+ SUBTLV_TYPE(mtc->rip) = 0;
+ SUBTLV_LEN(mtc->rip) = 0;
+ mtc->rip.value.s_addr = 0;
+
+ SUBTLV_TYPE(mtc->ras) = 0;
+ SUBTLV_LEN(mtc->ras) = 0;
+ mtc->ras.value = 0;
+}
+
+static void
+set_circuitparams_av_delay (struct mpls_te_circuit *mtc, u_int32_t delay, u_char anormal)
+{
+ u_int32_t tmp;
+ /* Note that TLV-length field is the size of array. */
+ SUBTLV_TYPE(mtc->av_delay) = TE_SUBTLV_AV_DELAY;
+ SUBTLV_LEN(mtc->av_delay) = SUBTLV_DEF_SIZE;
+ tmp = delay & TE_EXT_MASK;
+ if (anormal)
+ tmp |= TE_EXT_ANORMAL;
+ mtc->av_delay.value = htonl(tmp);
+ return;
+}
+
+static void
+set_circuitparams_mm_delay (struct mpls_te_circuit *mtc, u_int32_t low, u_int32_t high, u_char anormal)
+{
+ u_int32_t tmp;
+ /* Note that TLV-length field is the size of array. */
+ SUBTLV_TYPE(mtc->mm_delay) = TE_SUBTLV_MM_DELAY;
+ SUBTLV_LEN(mtc->mm_delay) = TE_SUBTLV_MM_DELAY_SIZE;
+ tmp = low & TE_EXT_MASK;
+ if (anormal)
+ tmp |= TE_EXT_ANORMAL;
+ mtc->mm_delay.low = htonl(tmp);
+ mtc->mm_delay.high = htonl(high);
+ return;
+}
+
+static void
+set_circuitparams_delay_var (struct mpls_te_circuit *mtc, u_int32_t jitter)
+{
+ /* Note that TLV-length field is the size of array. */
+ SUBTLV_TYPE(mtc->delay_var) = TE_SUBTLV_DELAY_VAR;
+ SUBTLV_LEN(mtc->delay_var) = SUBTLV_DEF_SIZE;
+ mtc->delay_var.value = htonl(jitter & TE_EXT_MASK);
+ return;
+}
+
+static void
+set_circuitparams_pkt_loss (struct mpls_te_circuit *mtc, u_int32_t loss, u_char anormal)
+{
+ u_int32_t tmp;
+ /* Note that TLV-length field is the size of array. */
+ SUBTLV_TYPE(mtc->pkt_loss) = TE_SUBTLV_PKT_LOSS;
+ SUBTLV_LEN(mtc->pkt_loss) = SUBTLV_DEF_SIZE;
+ tmp = loss & TE_EXT_MASK;
+ if (anormal)
+ tmp |= TE_EXT_ANORMAL;
+ mtc->pkt_loss.value = htonl(tmp);
+ return;
+}
+
+static void
+set_circuitparams_res_bw (struct mpls_te_circuit *mtc, float fp)
+{
+ /* Note that TLV-length field is the size of array. */
+ SUBTLV_TYPE(mtc->res_bw) = TE_SUBTLV_RES_BW;
+ SUBTLV_LEN(mtc->res_bw) = SUBTLV_DEF_SIZE;
+ mtc->res_bw.value = htonf(fp);
+ return;
+}
+
+static void
+set_circuitparams_ava_bw (struct mpls_te_circuit *mtc, float fp)
+{
+ /* Note that TLV-length field is the size of array. */
+ SUBTLV_TYPE(mtc->ava_bw) = TE_SUBTLV_AVA_BW;
+ SUBTLV_LEN(mtc->ava_bw) = SUBTLV_DEF_SIZE;
+ mtc->ava_bw.value = htonf(fp);
+ return;
+}
+
+static void
+set_circuitparams_use_bw (struct mpls_te_circuit *mtc, float fp)
+{
+ /* Note that TLV-length field is the size of array. */
+ SUBTLV_TYPE(mtc->use_bw) = TE_SUBTLV_USE_BW;
+ SUBTLV_LEN(mtc->use_bw) = SUBTLV_DEF_SIZE;
+ mtc->use_bw.value = htonf(fp);
+ return;
+}
+
+/* Main initialization / update function of the MPLS TE Circuit context */
+/* Call when interface TE Link parameters are modified */
+void
+isis_link_params_update (struct isis_circuit *circuit, struct interface *ifp)
+{
+ int i;
+ struct prefix_ipv4 *addr;
+ struct mpls_te_circuit *mtc;
+
+ /* Sanity Check */
+ if ((circuit == NULL) || (ifp == NULL))
+ return;
+
+ zlog_info ("MPLS-TE: Initialize circuit parameters for interface %s", ifp->name);
+
+ /* Check if MPLS TE Circuit context has not been already created */
+ if (circuit->mtc == NULL)
+ circuit->mtc = mpls_te_circuit_new();
+
+ mtc = circuit->mtc;
+
+ /* Fulfil MTC TLV from ifp TE Link parameters */
+ if (HAS_LINK_PARAMS(ifp))
+ {
+ mtc->status = enable;
+ /* STD_TE metrics */
+ if (IS_PARAM_SET(ifp->link_params, LP_ADM_GRP))
+ set_circuitparams_admin_grp (mtc, ifp->link_params->admin_grp);
+ else
+ SUBTLV_TYPE(mtc->admin_grp) = 0;
+
+ /* If not already set, register local IP addr from ip_addr list if it exists */
+ if (SUBTLV_TYPE(mtc->local_ipaddr) == 0)
+ {
+ if (circuit->ip_addrs != NULL && listcount(circuit->ip_addrs) != 0)
+ {
+ addr = (struct prefix_ipv4 *)listgetdata ((struct listnode *)listhead (circuit->ip_addrs));
+ set_circuitparams_local_ipaddr (mtc, addr->prefix);
+ }
+ }
+
+ /* If not already set, try to determine Remote IP addr if circuit is P2P */
+ if ((SUBTLV_TYPE(mtc->rmt_ipaddr) == 0) && (circuit->circ_type == CIRCUIT_T_P2P))
+ {
+ struct isis_adjacency *adj = circuit->u.p2p.neighbor;
+ if (adj->ipv4_addrs != NULL && listcount(adj->ipv4_addrs) != 0)
+ {
+ struct in_addr *ip_addr;
+ ip_addr = (struct in_addr *)listgetdata ((struct listnode *)listhead (adj->ipv4_addrs));
+ set_circuitparams_rmt_ipaddr (mtc, *ip_addr);
+ }
+ }
+
+ if (IS_PARAM_SET(ifp->link_params, LP_MAX_BW))
+ set_circuitparams_max_bw (mtc, ifp->link_params->max_bw);
+ else
+ SUBTLV_TYPE(mtc->max_bw) = 0;
+
+ if (IS_PARAM_SET(ifp->link_params, LP_MAX_RSV_BW))
+ set_circuitparams_max_rsv_bw (mtc, ifp->link_params->max_rsv_bw);
+ else
+ SUBTLV_TYPE(mtc->max_rsv_bw) = 0;
+
+ if (IS_PARAM_SET(ifp->link_params, LP_UNRSV_BW))
+ for (i = 0; i < MAX_CLASS_TYPE; i++)
+ set_circuitparams_unrsv_bw (mtc, i, ifp->link_params->unrsv_bw[i]);
+ else
+ SUBTLV_TYPE(mtc->unrsv_bw) = 0;
+
+ if (IS_PARAM_SET(ifp->link_params, LP_TE))
+ set_circuitparams_te_metric(mtc, ifp->link_params->te_metric);
+ else
+ SUBTLV_TYPE(mtc->te_metric) = 0;
+
+ /* TE metric Extensions */
+ if (IS_PARAM_SET(ifp->link_params, LP_DELAY))
+ set_circuitparams_av_delay(mtc, ifp->link_params->av_delay, 0);
+ else
+ SUBTLV_TYPE(mtc->av_delay) = 0;
+
+ if (IS_PARAM_SET(ifp->link_params, LP_MM_DELAY))
+ set_circuitparams_mm_delay(mtc, ifp->link_params->min_delay, ifp->link_params->max_delay, 0);
+ else
+ SUBTLV_TYPE(mtc->mm_delay) = 0;
+
+ if (IS_PARAM_SET(ifp->link_params, LP_DELAY_VAR))
+ set_circuitparams_delay_var(mtc, ifp->link_params->delay_var);
+ else
+ SUBTLV_TYPE(mtc->delay_var) = 0;
+
+ if (IS_PARAM_SET(ifp->link_params, LP_PKT_LOSS))
+ set_circuitparams_pkt_loss(mtc, ifp->link_params->pkt_loss, 0);
+ else
+ SUBTLV_TYPE(mtc->pkt_loss) = 0;
+
+ if (IS_PARAM_SET(ifp->link_params, LP_RES_BW))
+ set_circuitparams_res_bw(mtc, ifp->link_params->res_bw);
+ else
+ SUBTLV_TYPE(mtc->res_bw) = 0;
+
+ if (IS_PARAM_SET(ifp->link_params, LP_AVA_BW))
+ set_circuitparams_ava_bw(mtc, ifp->link_params->ava_bw);
+ else
+ SUBTLV_TYPE(mtc->ava_bw) = 0;
+
+ if (IS_PARAM_SET(ifp->link_params, LP_USE_BW))
+ set_circuitparams_use_bw(mtc, ifp->link_params->use_bw);
+ else
+ SUBTLV_TYPE(mtc->use_bw) = 0;
+
+ /* INTER_AS */
+ if (IS_PARAM_SET(ifp->link_params, LP_RMT_AS))
+ set_circuitparams_inter_as(mtc, ifp->link_params->rmt_ip, ifp->link_params->rmt_as);
+ else
+ /* reset inter-as TE params */
+ unset_circuitparams_inter_as (mtc);
+
+ /* Compute total length of SUB TLVs */
+ mtc->length = subtlvs_len(mtc);
+
+ }
+ else
+ mtc->status = disable;
+
+ /* Finally Update LSP */
+#if 0
+ if (IS_MPLS_TE(isisMplsTE) && circuit->area)
+ lsp_regenerate_schedule (circuit->area, circuit->is_type, 0);
+#endif
+ return;
+}
+
+void
+isis_mpls_te_update (struct interface *ifp)
+{
+ struct isis_circuit *circuit;
+
+ /* Sanity Check */
+ if (ifp == NULL)
+ return;
+
+ /* Get circuit context from interface */
+ if ((circuit = circuit_scan_by_ifp(ifp)) == NULL)
+ return;
+
+ /* Update TE TLVs ... */
+ isis_link_params_update(circuit, ifp);
+
+ /* ... and LSP */
+ if (IS_MPLS_TE(isisMplsTE) && circuit->area)
+ lsp_regenerate_schedule (circuit->area, circuit->is_type, 0);
+
+ return;
+}
+
+/*------------------------------------------------------------------------*
+ * Followings are vty session control functions.
+ *------------------------------------------------------------------------*/
+
+static u_char
+show_vty_subtlv_admin_grp (struct vty *vty, struct te_subtlv_admin_grp *tlv)
+{
+
+ if (vty != NULL)
+ vty_out (vty, " Administrative Group: 0x%x%s",
+ (u_int32_t) ntohl (tlv->value), VTY_NEWLINE);
+ else
+ zlog_debug (" Administrative Group: 0x%x",
+ (u_int32_t) ntohl (tlv->value));
+
+ return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
+}
+
+static u_char
+show_vty_subtlv_llri (struct vty *vty, struct te_subtlv_llri *tlv)
+{
+ if (vty != NULL)
+ {
+ vty_out (vty, " Link Local ID: %d%s", (u_int32_t) ntohl (tlv->local),
+ VTY_NEWLINE);
+ vty_out (vty, " Link Remote ID: %d%s", (u_int32_t) ntohl (tlv->remote),
+ VTY_NEWLINE);
+ }
+ else
+ {
+ zlog_debug (" Link Local ID: %d", (u_int32_t) ntohl (tlv->local));
+ zlog_debug (" Link Remote ID: %d", (u_int32_t) ntohl (tlv->remote));
+ }
+
+ return (SUBTLV_HDR_SIZE + TE_SUBTLV_LLRI_SIZE);
+}
+
+static u_char
+show_vty_subtlv_local_ipaddr (struct vty *vty, struct te_subtlv_local_ipaddr *tlv)
+{
+ if (vty != NULL)
+ vty_out (vty, " Local Interface IP Address(es): %s%s", inet_ntoa (tlv->value), VTY_NEWLINE);
+ else
+ zlog_debug (" Local Interface IP Address(es): %s", inet_ntoa (tlv->value));
+
+ return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
+}
+
+static u_char
+show_vty_subtlv_rmt_ipaddr (struct vty *vty, struct te_subtlv_rmt_ipaddr *tlv)
+{
+ if (vty != NULL)
+ vty_out (vty, " Remote Interface IP Address(es): %s%s", inet_ntoa (tlv->value), VTY_NEWLINE);
+ else
+ zlog_debug (" Remote Interface IP Address(es): %s", inet_ntoa (tlv->value));
+
+ return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
+}
+
+static u_char
+show_vty_subtlv_max_bw (struct vty *vty, struct te_subtlv_max_bw *tlv)
+{
+ float fval;
+
+ fval = ntohf (tlv->value);
+
+ if (vty != NULL)
+ vty_out (vty, " Maximum Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE);
+ else
+ zlog_debug (" Maximum Bandwidth: %g (Bytes/sec)", fval);
+
+ return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
+}
+
+static u_char
+show_vty_subtlv_max_rsv_bw (struct vty *vty, struct te_subtlv_max_rsv_bw *tlv)
+{
+ float fval;
+
+ fval = ntohf (tlv->value);
+
+ if (vty != NULL)
+ vty_out (vty, " Maximum Reservable Bandwidth: %g (Bytes/sec)%s", fval,
+ VTY_NEWLINE);
+ else
+ zlog_debug (" Maximum Reservable Bandwidth: %g (Bytes/sec)", fval);
+
+ return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
+}
+
+static u_char
+show_vty_subtlv_unrsv_bw (struct vty *vty, struct te_subtlv_unrsv_bw *tlv)
+{
+ float fval1, fval2;
+ int i;
+
+ if (vty != NULL)
+ vty_out (vty, " Unreserved Bandwidth:%s",VTY_NEWLINE);
+ else
+ zlog_debug (" Unreserved Bandwidth:");
+
+ for (i = 0; i < MAX_CLASS_TYPE; i+=2)
+ {
+ fval1 = ntohf (tlv->value[i]);
+ fval2 = ntohf (tlv->value[i+1]);
+ if (vty != NULL)
+ vty_out (vty, " [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)%s", i, fval1, i+1, fval2, VTY_NEWLINE);
+ else
+ zlog_debug (" [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)", i, fval1, i+1, fval2);
+ }
+
+ return (SUBTLV_HDR_SIZE + TE_SUBTLV_UNRSV_SIZE);
+}
+
+static u_char
+show_vty_subtlv_te_metric (struct vty *vty, struct te_subtlv_te_metric *tlv)
+{
+ u_int32_t te_metric;
+
+ te_metric = tlv->value[2] | tlv->value[1] << 8 | tlv->value[0] << 16;
+ if (vty != NULL)
+ vty_out (vty, " Traffic Engineering Metric: %u%s", te_metric, VTY_NEWLINE);
+ else
+ zlog_debug (" Traffic Engineering Metric: %u", te_metric);
+
+ return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
+}
+
+static u_char
+show_vty_subtlv_ras (struct vty *vty, struct te_subtlv_ras *tlv)
+{
+ if (vty != NULL)
+ vty_out (vty, " Inter-AS TE Remote AS number: %u%s", ntohl (tlv->value), VTY_NEWLINE);
+ else
+ zlog_debug (" Inter-AS TE Remote AS number: %u", ntohl (tlv->value));
+
+ return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
+}
+
+static u_char
+show_vty_subtlv_rip (struct vty *vty, struct te_subtlv_rip *tlv)
+{
+ if (vty != NULL)
+ vty_out (vty, " Inter-AS TE Remote ASBR IP address: %s%s", inet_ntoa (tlv->value), VTY_NEWLINE);
+ else
+ zlog_debug (" Inter-AS TE Remote ASBR IP address: %s", inet_ntoa (tlv->value));
+
+ return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
+}
+
+static u_char
+show_vty_subtlv_av_delay (struct vty *vty, struct te_subtlv_av_delay *tlv)
+{
+ u_int32_t delay;
+ u_int32_t A;
+
+ delay = (u_int32_t) ntohl (tlv->value) & TE_EXT_MASK;
+ A = (u_int32_t) ntohl (tlv->value) & TE_EXT_ANORMAL;
+
+ if (vty != NULL)
+ vty_out (vty, " %s Average Link Delay: %d (micro-sec)%s", A ? "Anomalous" : "Normal", delay, VTY_NEWLINE);
+ else
+ zlog_debug (" %s Average Link Delay: %d (micro-sec)", A ? "Anomalous" : "Normal", delay);
+
+ return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
+}
+
+static u_char
+show_vty_subtlv_mm_delay (struct vty *vty, struct te_subtlv_mm_delay *tlv)
+{
+ u_int32_t low, high;
+ u_int32_t A;
+
+ low = (u_int32_t) ntohl (tlv->low) & TE_EXT_MASK;
+ A = (u_int32_t) ntohl (tlv->low) & TE_EXT_ANORMAL;
+ high = (u_int32_t) ntohl (tlv->high) & TE_EXT_MASK;
+
+ if (vty != NULL)
+ vty_out (vty, " %s Min/Max Link Delay: %d / %d (micro-sec)%s", A ? "Anomalous" : "Normal", low, high, VTY_NEWLINE);
+ else
+ zlog_debug (" %s Min/Max Link Delay: %d / %d (micro-sec)", A ? "Anomalous" : "Normal", low, high);
+
+ return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
+}
+
+static u_char
+show_vty_subtlv_delay_var (struct vty *vty, struct te_subtlv_delay_var *tlv)
+{
+ u_int32_t jitter;
+
+ jitter = (u_int32_t) ntohl (tlv->value) & TE_EXT_MASK;
+
+ if (vty != NULL)
+ vty_out (vty, " Delay Variation: %d (micro-sec)%s", jitter, VTY_NEWLINE);
+ else
+ zlog_debug (" Delay Variation: %d (micro-sec)", jitter);
+
+ return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
+}
+
+static u_char
+show_vty_subtlv_pkt_loss (struct vty *vty, struct te_subtlv_pkt_loss *tlv)
+{
+ u_int32_t loss;
+ u_int32_t A;
+ float fval;
+
+ loss = (u_int32_t) ntohl (tlv->value) & TE_EXT_MASK;
+ fval = (float) (loss * LOSS_PRECISION);
+ A = (u_int32_t) ntohl (tlv->value) & TE_EXT_ANORMAL;
+
+ if (vty != NULL)
+ vty_out (vty, " %s Link Packet Loss: %g (%%)%s", A ? "Anomalous" : "Normal", fval, VTY_NEWLINE);
+ else
+ zlog_debug (" %s Link Packet Loss: %g (%%)", A ? "Anomalous" : "Normal", fval);
+
+ return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
+}
+
+static u_char
+show_vty_subtlv_res_bw (struct vty *vty, struct te_subtlv_res_bw *tlv)
+{
+ float fval;
+
+ fval = ntohf(tlv->value);
+
+ if (vty != NULL)
+ vty_out (vty, " Unidirectional Residual Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE);
+ else
+ zlog_debug (" Unidirectional Residual Bandwidth: %g (Bytes/sec)", fval);
+
+ return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
+}
+
+static u_char
+show_vty_subtlv_ava_bw (struct vty *vty, struct te_subtlv_ava_bw *tlv)
+{
+ float fval;
+
+ fval = ntohf (tlv->value);
+
+ if (vty != NULL)
+ vty_out (vty, " Unidirectional Available Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE);
+ else
+ zlog_debug (" Unidirectional Available Bandwidth: %g (Bytes/sec)", fval);
+
+ return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
+}
+
+static u_char
+show_vty_subtlv_use_bw (struct vty *vty, struct te_subtlv_use_bw *tlv)
+{
+ float fval;
+
+ fval = ntohf (tlv->value);
+
+ if (vty != NULL)
+ vty_out (vty, " Unidirectional Utilized Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE);
+ else
+ zlog_debug (" Unidirectional Utilized Bandwidth: %g (Bytes/sec)", fval);
+
+ return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
+}
+
+static u_char
+show_vty_unknown_tlv (struct vty *vty, struct subtlv_header *tlvh)
+{
+ int i, rtn = 1;
+ u_char *v = (u_char *)tlvh;
+
+ if (vty != NULL)
+ {
+ if (tlvh->length != 0)
+ {
+ vty_out (vty, " Unknown TLV: [type(%#.2x), length(%#.2x)]%s",
+ tlvh->type, tlvh->length, VTY_NEWLINE);
+ vty_out(vty, " Dump: [00]");
+ rtn = 1; /* initialize end of line counter */
+ for (i = 0; i < tlvh->length; i++)
+ {
+ vty_out (vty, " %#.2x", v[i]);
+ if (rtn == 8)
+ {
+ vty_out (vty, "%s [%.2x]", VTY_NEWLINE, i + 1);
+ rtn = 1;
+ }
+ else
+ rtn++;
+ }
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+ else
+ vty_out (vty, " Unknown TLV: [type(%#.2x), length(%#.2x)]%s",
+ tlvh->type, tlvh->length, VTY_NEWLINE);
+ }
+ else
+ {
+ zlog_debug (" Unknown TLV: [type(%#.2x), length(%#.2x)]",
+ tlvh->type, tlvh->length);
+ }
+
+ return SUBTLV_SIZE(tlvh);
+}
+
+/* Main Show function */
+void
+mpls_te_print_detail(struct vty *vty, struct te_is_neigh *te)
+{
+ struct subtlv_header *tlvh, *next;
+ u_int16_t sum = 0;
+
+ zlog_debug ("ISIS MPLS-TE: Show database TE detail");
+
+ if (te->sub_tlvs == NULL)
+ return;
+
+ tlvh = (struct subtlv_header *)te->sub_tlvs;
+
+ for (; sum < te->sub_tlvs_length; tlvh = (next ? next : SUBTLV_HDR_NEXT (tlvh)))
+ {
+ next = NULL;
+
+ switch (tlvh->type)
+ {
+ case TE_SUBTLV_ADMIN_GRP:
+ sum += show_vty_subtlv_admin_grp (vty, (struct te_subtlv_admin_grp *)tlvh);
+ break;
+ case TE_SUBTLV_LLRI:
+ sum += show_vty_subtlv_llri (vty, (struct te_subtlv_llri *)tlvh);
+ break;
+ case TE_SUBTLV_LOCAL_IPADDR:
+ sum += show_vty_subtlv_local_ipaddr (vty, (struct te_subtlv_local_ipaddr *)tlvh);
+ break;
+ case TE_SUBTLV_RMT_IPADDR:
+ sum += show_vty_subtlv_rmt_ipaddr (vty, (struct te_subtlv_rmt_ipaddr *)tlvh);
+ break;
+ case TE_SUBTLV_MAX_BW:
+ sum += show_vty_subtlv_max_bw (vty, (struct te_subtlv_max_bw *)tlvh);
+ break;
+ case TE_SUBTLV_MAX_RSV_BW:
+ sum += show_vty_subtlv_max_rsv_bw (vty, (struct te_subtlv_max_rsv_bw *)tlvh);
+ break;
+ case TE_SUBTLV_UNRSV_BW:
+ sum += show_vty_subtlv_unrsv_bw (vty, (struct te_subtlv_unrsv_bw *)tlvh);
+ break;
+ case TE_SUBTLV_TE_METRIC:
+ sum += show_vty_subtlv_te_metric (vty, (struct te_subtlv_te_metric *)tlvh);
+ break;
+ case TE_SUBTLV_RAS:
+ sum += show_vty_subtlv_ras (vty, (struct te_subtlv_ras *)tlvh);
+ break;
+ case TE_SUBTLV_RIP:
+ sum += show_vty_subtlv_rip (vty, (struct te_subtlv_rip *)tlvh);
+ break;
+ case TE_SUBTLV_AV_DELAY:
+ sum += show_vty_subtlv_av_delay (vty, (struct te_subtlv_av_delay *)tlvh);
+ break;
+ case TE_SUBTLV_MM_DELAY:
+ sum += show_vty_subtlv_mm_delay (vty, (struct te_subtlv_mm_delay *)tlvh);
+ break;
+ case TE_SUBTLV_DELAY_VAR:
+ sum += show_vty_subtlv_delay_var (vty, (struct te_subtlv_delay_var *)tlvh);
+ break;
+ case TE_SUBTLV_PKT_LOSS:
+ sum += show_vty_subtlv_pkt_loss (vty, (struct te_subtlv_pkt_loss *)tlvh);
+ break;
+ case TE_SUBTLV_RES_BW:
+ sum += show_vty_subtlv_res_bw (vty, (struct te_subtlv_res_bw *)tlvh);
+ break;
+ case TE_SUBTLV_AVA_BW:
+ sum += show_vty_subtlv_ava_bw (vty, (struct te_subtlv_ava_bw *)tlvh);
+ break;
+ case TE_SUBTLV_USE_BW:
+ sum += show_vty_subtlv_use_bw (vty, (struct te_subtlv_use_bw *)tlvh);
+ break;
+ default:
+ sum += show_vty_unknown_tlv (vty, tlvh);
+ break;
+ }
+ }
+ return;
+}
+
+/* Specific MPLS TE router parameters write function */
+void
+isis_mpls_te_config_write_router (struct vty *vty)
+{
+
+ zlog_debug ("ISIS MPLS-TE: Write ISIS router configuration");
+
+ if (IS_MPLS_TE(isisMplsTE))
+ {
+ vty_out (vty, " mpls-te on%s", VTY_NEWLINE);
+ vty_out (vty, " mpls-te router-address %s%s",
+ inet_ntoa (isisMplsTE.router_id), VTY_NEWLINE);
+ }
+
+ return;
+}
+
+
+/*------------------------------------------------------------------------*
+ * Followings are vty command functions.
+ *------------------------------------------------------------------------*/
+
+DEFUN (isis_mpls_te_on,
+ isis_mpls_te_on_cmd,
+ "mpls-te on",
+ MPLS_TE_STR
+ "Enable MPLS-TE functionality\n")
+{
+ struct listnode *node;
+ struct isis_circuit *circuit;
+
+ if (IS_MPLS_TE(isisMplsTE))
+ return CMD_SUCCESS;
+
+ if (IS_DEBUG_ISIS(DEBUG_TE))
+ zlog_debug ("ISIS MPLS-TE: OFF -> ON");
+
+ isisMplsTE.status = enable;
+
+ /*
+ * Following code is intended to handle two cases;
+ *
+ * 1) MPLS-TE was disabled at startup time, but now become enabled.
+ * In this case, we must enable MPLS-TE Circuit regarding interface MPLS_TE flag
+ * 2) MPLS-TE was once enabled then disabled, and now enabled again.
+ */
+ for (ALL_LIST_ELEMENTS_RO (isisMplsTE.cir_list, node, circuit))
+ {
+ if (circuit->mtc == NULL || IS_FLOOD_AS (circuit->mtc->type))
+ continue;
+
+ if ((circuit->mtc->status == disable)
+ && HAS_LINK_PARAMS(circuit->interface))
+ circuit->mtc->status = enable;
+ else
+ continue;
+
+ /* Reoriginate STD_TE & GMPLS circuits */
+ if (circuit->area)
+ lsp_regenerate_schedule (circuit->area, circuit->is_type, 0);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_isis_mpls_te_on,
+ no_isis_mpls_te_on_cmd,
+ "no mpls-te",
+ NO_STR
+ "Disable the MPLS-TE functionality\n")
+{
+ struct listnode *node;
+ struct isis_circuit *circuit;
+
+ if (isisMplsTE.status == disable)
+ return CMD_SUCCESS;
+
+ if (IS_DEBUG_ISIS(DEBUG_TE))
+ zlog_debug ("ISIS MPLS-TE: ON -> OFF");
+
+ isisMplsTE.status = disable;
+
+ /* Flush LSP if circuit engage */
+ for (ALL_LIST_ELEMENTS_RO (isisMplsTE.cir_list, node, circuit))
+ {
+ if (circuit->mtc == NULL || (circuit->mtc->status == disable))
+ continue;
+
+ /* disable MPLS_TE Circuit */
+ circuit->mtc->status = disable;
+
+ /* Re-originate circuit without STD_TE & GMPLS parameters */
+ if (circuit->area)
+ lsp_regenerate_schedule (circuit->area, circuit->is_type, 0);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (isis_mpls_te_router_addr,
+ isis_mpls_te_router_addr_cmd,
+ "mpls-te router-address A.B.C.D",
+ MPLS_TE_STR
+ "Stable IP address of the advertising router\n"
+ "MPLS-TE router address in IPv4 address format\n")
+{
+ struct in_addr value;
+ struct listnode *node;
+ struct isis_area *area;
+
+ if (! inet_aton (argv[0], &value))
+ {
+ vty_out (vty, "Please specify Router-Addr by A.B.C.D%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ isisMplsTE.router_id.s_addr = value.s_addr;
+
+ if (isisMplsTE.status == disable)
+ return CMD_SUCCESS;
+
+ /* Update main Router ID in isis global structure */
+ isis->router_id = value.s_addr;
+ /* And re-schedule LSP update */
+ for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
+ if (listcount (area->area_addrs) > 0)
+ lsp_regenerate_schedule (area, area->is_type, 0);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (isis_mpls_te_inter_as,
+ isis_mpls_te_inter_as_cmd,
+ "mpls-te inter-as (level-1|level-1-2|level-2-only)",
+ MPLS_TE_STR
+ "Configure MPLS-TE Inter-AS support\n"
+ "AREA native mode self originate INTER-AS LSP with L1 only flooding scope)\n"
+ "AREA native mode self originate INTER-AS LSP with L1 and L2 flooding scope)\n"
+ "AS native mode self originate INTER-AS LSP with L2 only flooding scope\n")
+{
+ vty_out (vty, "Not yet supported%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_isis_mpls_te_inter_as,
+ no_isis_mpls_te_inter_as_cmd,
+ "no mpls-te inter-as",
+ NO_STR
+ "Disable the MPLS-TE functionality\n"
+ "Disable MPLS-TE Inter-AS support\n")
+{
+
+ vty_out (vty, "Not yet supported%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_isis_mpls_te_router,
+ show_isis_mpls_te_router_cmd,
+ "show isis mpls-te router",
+ SHOW_STR
+ ISIS_STR
+ MPLS_TE_STR
+ "Router information\n")
+{
+ if (IS_MPLS_TE(isisMplsTE))
+ {
+ vty_out (vty, "--- MPLS-TE router parameters ---%s", VTY_NEWLINE);
+
+ if (vty != NULL)
+ {
+ if (ntohs (isisMplsTE.router_id.s_addr) != 0)
+ vty_out (vty, " Router-Address: %s%s", inet_ntoa (isisMplsTE.router_id), VTY_NEWLINE);
+ else
+ vty_out (vty, " N/A%s", VTY_NEWLINE);
+ }
+ }
+ else
+ vty_out (vty, " MPLS-TE is disable on this router%s", VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
+static void
+show_mpls_te_sub (struct vty *vty, struct interface *ifp)
+{
+ struct mpls_te_circuit *mtc;
+
+ if ((IS_MPLS_TE(isisMplsTE))
+ && ((mtc = lookup_mpls_params_by_ifp (ifp)) != NULL))
+ {
+ /* Continue only if interface is not passive or support Inter-AS TEv2 */
+ if (mtc->status != enable)
+ {
+ if (IS_INTER_AS(mtc->type))
+ {
+ vty_out (vty, "-- Inter-AS TEv2 link parameters for %s --%s",
+ ifp->name, VTY_NEWLINE);
+ }
+ else
+ {
+ /* MPLS-TE is not activate on this interface */
+ /* or this interface is passive and Inter-AS TEv2 is not activate */
+ vty_out (vty, " %s: MPLS-TE is disabled on this interface%s",
+ ifp->name, VTY_NEWLINE);
+ return;
+ }
+ }
+ else
+ {
+ vty_out (vty, "-- MPLS-TE link parameters for %s --%s",
+ ifp->name, VTY_NEWLINE);
+ }
+
+ show_vty_subtlv_admin_grp (vty, &mtc->admin_grp);
+
+ if (SUBTLV_TYPE(mtc->local_ipaddr) != 0)
+ show_vty_subtlv_local_ipaddr (vty, &mtc->local_ipaddr);
+ if (SUBTLV_TYPE(mtc->rmt_ipaddr) != 0)
+ show_vty_subtlv_rmt_ipaddr (vty, &mtc->rmt_ipaddr);
+
+ show_vty_subtlv_max_bw (vty, &mtc->max_bw);
+ show_vty_subtlv_max_rsv_bw (vty, &mtc->max_rsv_bw);
+ show_vty_subtlv_unrsv_bw (vty, &mtc->unrsv_bw);
+ show_vty_subtlv_te_metric (vty, &mtc->te_metric);
+
+ if (IS_INTER_AS(mtc->type))
+ {
+ if (SUBTLV_TYPE(mtc->ras) != 0)
+ show_vty_subtlv_ras (vty, &mtc->ras);
+ if (SUBTLV_TYPE(mtc->rip) != 0)
+ show_vty_subtlv_rip (vty, &mtc->rip);
+ }
+
+ show_vty_subtlv_av_delay (vty, &mtc->av_delay);
+ show_vty_subtlv_mm_delay (vty, &mtc->mm_delay);
+ show_vty_subtlv_delay_var (vty, &mtc->delay_var);
+ show_vty_subtlv_pkt_loss (vty, &mtc->pkt_loss);
+ show_vty_subtlv_res_bw (vty, &mtc->res_bw);
+ show_vty_subtlv_ava_bw (vty, &mtc->ava_bw);
+ show_vty_subtlv_use_bw (vty, &mtc->use_bw);
+ vty_out (vty, "---------------%s%s", VTY_NEWLINE, VTY_NEWLINE);
+ }
+ else
+ {
+ vty_out (vty, " %s: MPLS-TE is disabled on this interface%s",
+ ifp->name, VTY_NEWLINE);
+ }
+
+ return;
+}
+
+DEFUN (show_isis_mpls_te_interface,
+ show_isis_mpls_te_interface_cmd,
+ "show isis mpls-te interface [INTERFACE]",
+ SHOW_STR
+ ISIS_STR
+ MPLS_TE_STR
+ "Interface information\n"
+ "Interface name\n")
+{
+ struct interface *ifp;
+ struct listnode *node;
+
+ /* Show All Interfaces. */
+ if (argc == 0)
+ {
+ for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp))
+ show_mpls_te_sub (vty, ifp);
+ }
+ /* Interface name is specified. */
+ else
+ {
+ if ((ifp = if_lookup_by_name (argv[0])) == NULL)
+ vty_out (vty, "No such interface name%s", VTY_NEWLINE);
+ else
+ show_mpls_te_sub (vty, ifp);
+ }
+
+ return CMD_SUCCESS;
+}
+
+/* Initialize MPLS_TE */
+void
+isis_mpls_te_init (void)
+{
+
+ zlog_debug("ISIS MPLS-TE: Initialize");
+
+ /* Initialize MPLS_TE structure */
+ isisMplsTE.status = disable;
+ isisMplsTE.level = 0;
+ isisMplsTE.inter_as = off;
+ isisMplsTE.interas_areaid.s_addr = 0;
+ isisMplsTE.cir_list = list_new();
+ isisMplsTE.router_id.s_addr = 0;
+
+ /* Register new VTY commands */
+ install_element (VIEW_NODE, &show_isis_mpls_te_router_cmd);
+ install_element (VIEW_NODE, &show_isis_mpls_te_interface_cmd);
+ install_element (ENABLE_NODE, &show_isis_mpls_te_router_cmd);
+ install_element (ENABLE_NODE, &show_isis_mpls_te_interface_cmd);
+
+ install_element (ISIS_NODE, &isis_mpls_te_on_cmd);
+ install_element (ISIS_NODE, &no_isis_mpls_te_on_cmd);
+ install_element (ISIS_NODE, &isis_mpls_te_router_addr_cmd);
+ install_element (ISIS_NODE, &isis_mpls_te_inter_as_cmd);
+ install_element (ISIS_NODE, &no_isis_mpls_te_inter_as_cmd);
+
+ return;
+}
diff --git a/isisd/isis_te.h b/isisd/isis_te.h
new file mode 100644
index 000000000..4cec1735a
--- /dev/null
+++ b/isisd/isis_te.h
@@ -0,0 +1,331 @@
+/*
+ * IS-IS Rout(e)ing protocol - isis_te.c
+ *
+ * This is an implementation of RFC5305, RFC 5307 and draft-ietf-isis-te-metric-extensions-11
+ *
+ * Copyright (C) 2014 Orange Labs
+ * http://www.orange.com
+ *
+ * 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.
+ */
+
+#ifndef _ZEBRA_ISIS_MPLS_TE_H
+#define _ZEBRA_ISIS_MPLS_TE_H
+
+/*
+ * Traffic Engineering information are transport through LSP:
+ * - Extended IS Reachability TLV = 22
+ * - Traffic Engineering Router ID TLV = 134
+ * - Extended IP Reachability TLV = 135
+ * - Inter-AS Reachability Information TLV = 141
+ *
+ * and support following sub-TLV:
+ *
+ * Name Value Status
+ * _________________________________________________
+ * Administartive group (color) 3 RFC5305
+ * Link Local/Remote Identifiers 4 RFC5307
+ * IPv4 interface address 6 RFC5305
+ * IPv4 neighbor address 8 RFC5305
+ * Maximum link bandwidth 9 RFC5305
+ * Reservable link bandwidth 10 RFC5305
+ * Unreserved bandwidth 11 RFC5305
+ * TE Default metric 18 RFC5305
+ * Link Protection Type 20 RFC5307
+ * Interface Switching Capability 21 RFC5307
+ * Remote AS number 24 RFC5316
+ * IPv4 Remote ASBR identifier 25 RFC5316
+ *
+ */
+
+/* NOTE: RFC5316 is not yet supported in this version */
+
+/* Following define the type of TE link regarding the various RFC */
+#define STD_TE 0x01
+#define GMPLS 0x02
+#define INTER_AS 0x04
+#define FLOOD_L1 0x10
+#define FLOOD_L2 0x20
+#define FLOOD_AS 0x40
+#define EMULATED 0x80
+
+#define IS_STD_TE(x) (x & STD_TE)
+#define IS_INTER_AS(x) (x & INTER_AS)
+#define IS_EMULATED(x) (x & EMULATED)
+#define IS_FLOOD_L1(x) (x & FLOOD_L1)
+#define IS_FLOOD_L2(x) (x & FLOOD_L2)
+#define IS_FLOOD_AS(x) (x & FLOOD_AS)
+#define IS_INTER_AS_EMU(x) (x & INTER_AS & EMULATED)
+#define IS_INTER_AS_AS(x) (x & INTER_AS & FLOOD_AS)
+
+/*
+ * Following section defines subTLV (tag, length, value) structures,
+ * used for Traffic Engineering.
+ */
+struct subtlv_header
+{
+ u_char type; /* sub_TLV_XXX type (see above) */
+ u_char length; /* Value portion only, in byte */
+};
+
+#define SUBTLV_HDR_SIZE 2 /* (sizeof (struct sub_tlv_header)) */
+
+#define SUBTLV_SIZE(stlvh) (SUBTLV_HDR_SIZE + (stlvh)->length)
+
+#define SUBTLV_HDR_TOP(lsph) (struct subtlv_header *)((char *)(lsph) + ISIS_LSP_HEADER_SIZE)
+
+#define SUBTLV_HDR_NEXT(stlvh) (struct subtlv_header *)((char *)(stlvh) + SUBTLV_SIZE(stlvh))
+
+#define SUBTLV_TYPE(stlvh) stlvh.header.type
+#define SUBTLV_LEN(stlvh) stlvh.header.length
+#define SUBTLV_VAL(stlvh) stlvh.value
+#define SUBTLV_DATA(stlvh) stlvh + SUBTLV_HDR_SIZE
+
+#define SUBTLV_DEF_SIZE 4
+
+/* Link Sub-TLV: Resource Class/Color - RFC 5305 */
+#define TE_SUBTLV_ADMIN_GRP 3
+struct te_subtlv_admin_grp
+{
+ struct subtlv_header header; /* Value length is 4 octets. */
+ u_int32_t value; /* Admin. group membership. */
+} __attribute__((__packed__));
+
+/* Link Local/Remote Identifiers - RFC 5307 */
+#define TE_SUBTLV_LLRI 4
+#define TE_SUBTLV_LLRI_SIZE 8
+struct te_subtlv_llri
+{
+ struct subtlv_header header; /* Value length is 8 octets. */
+ u_int32_t local; /* Link Local Identifier */
+ u_int32_t remote; /* Link Remote Identifier */
+} __attribute__((__packed__));
+
+/* Link Sub-TLV: Local Interface IP Address - RFC 5305 */
+#define TE_SUBTLV_LOCAL_IPADDR 6
+struct te_subtlv_local_ipaddr
+{
+ struct subtlv_header header; /* Value length is 4 x N octets. */
+ struct in_addr value; /* Local IP address(es). */
+} __attribute__((__packed__));
+
+/* Link Sub-TLV: Neighbor Interface IP Address - RFC 5305 */
+#define TE_SUBTLV_RMT_IPADDR 8
+struct te_subtlv_rmt_ipaddr
+{
+ struct subtlv_header header; /* Value length is 4 x N octets. */
+ struct in_addr value; /* Neighbor's IP address(es). */
+} __attribute__((__packed__));
+
+/* Link Sub-TLV: Maximum Bandwidth - RFC 5305 */
+#define TE_SUBTLV_MAX_BW 9
+struct te_subtlv_max_bw
+{
+ struct subtlv_header header; /* Value length is 4 octets. */
+ float value; /* bytes/sec */
+} __attribute__((__packed__));
+
+/* Link Sub-TLV: Maximum Reservable Bandwidth - RFC 5305 */
+#define TE_SUBTLV_MAX_RSV_BW 10
+struct te_subtlv_max_rsv_bw
+{
+ struct subtlv_header header; /* Value length is 4 octets. */
+ float value; /* bytes/sec */
+} __attribute__((__packed__));
+
+/* Link Sub-TLV: Unreserved Bandwidth - RFC 5305 */
+#define TE_SUBTLV_UNRSV_BW 11
+#define TE_SUBTLV_UNRSV_SIZE 32
+struct te_subtlv_unrsv_bw
+{
+ struct subtlv_header header; /* Value length is 32 octets. */
+ float value[8]; /* One for each priority level. */
+} __attribute__((__packed__));
+
+/* Link Sub-TLV: Traffic Engineering Metric - RFC 5305 */
+#define TE_SUBTLV_TE_METRIC 18
+#define TE_SUBTLV_TE_METRIC_SIZE 3
+struct te_subtlv_te_metric
+{
+ struct subtlv_header header; /* Value length is 4 octets. */
+ u_char value[3]; /* Link metric for TE purpose. */
+} __attribute__((__packed__));
+
+/* Remote AS Number sub-TLV - RFC5316 */
+#define TE_SUBTLV_RAS 24
+struct te_subtlv_ras
+{
+ struct subtlv_header header; /* Value length is 4 octets. */
+ u_int32_t value; /* Remote AS number */
+} __attribute__((__packed__));
+
+/* IPv4 Remote ASBR ID Sub-TLV - RFC5316 */
+#define TE_SUBTLV_RIP 25
+struct te_subtlv_rip
+{
+ struct subtlv_header header; /* Value length is 4 octets. */
+ struct in_addr value; /* Remote ASBR IP address */
+} __attribute__((__packed__));
+
+
+/* draft-ietf-isis-te-metric-extensions-11.txt */
+/* Link Sub-TLV: Average Link Delay */
+#define TE_SUBTLV_AV_DELAY 33
+struct te_subtlv_av_delay
+{
+ struct subtlv_header header; /* Value length is 4 bytes. */
+ u_int32_t value; /* Average delay in micro-seconds only 24 bits => 0 ... 16777215
+ with Anomalous Bit (A) as Upper most bit */
+} __attribute__((__packed__));
+
+/* Link Sub-TLV: Low/High Link Delay */
+#define TE_SUBTLV_MM_DELAY 34
+#define TE_SUBTLV_MM_DELAY_SIZE 8
+struct te_subtlv_mm_delay
+{
+ struct subtlv_header header; /* Value length is 8 bytes. */
+ u_int32_t low; /* low delay in micro-seconds only 24 bits => 0 ... 16777215
+ with Anomalous Bit (A) as Upper most bit */
+ u_int32_t high; /* high delay in micro-seconds only 24 bits => 0 ... 16777215 */
+} __attribute__((__packed__));
+
+/* Link Sub-TLV: Link Delay Variation i.e. Jitter */
+#define TE_SUBTLV_DELAY_VAR 35
+struct te_subtlv_delay_var
+{
+ struct subtlv_header header; /* Value length is 4 bytes. */
+ u_int32_t value; /* interval in micro-seconds only 24 bits => 0 ... 16777215 */
+} __attribute__((__packed__));
+
+/* Link Sub-TLV: Routine Unidirectional Link Packet Loss */
+#define TE_SUBTLV_PKT_LOSS 36
+struct te_subtlv_pkt_loss
+{
+ struct subtlv_header header; /* Value length is 4 bytes. */
+ u_int32_t value; /* in percentage of total traffic only 24 bits (2^24 - 2)
+ with Anomalous Bit (A) as Upper most bit */
+} __attribute__((__packed__));
+
+/* Link Sub-TLV: Unidirectional Residual Bandwidth */ /* Optional */
+#define TE_SUBTLV_RES_BW 37
+struct te_subtlv_res_bw
+{
+ struct subtlv_header header; /* Value length is 4 bytes. */
+ float value; /* bandwidth in IEEE floating point format with units in bytes per second */
+} __attribute__((__packed__));
+
+/* Link Sub-TLV: Unidirectional Available Bandwidth */ /* Optional */
+#define TE_SUBTLV_AVA_BW 38
+struct te_subtlv_ava_bw
+{
+ struct subtlv_header header; /* Value length is 4 octets. */
+ float value; /* bandwidth in IEEE floating point format with units in bytes per second */
+} __attribute__((__packed__));
+
+/* Link Sub-TLV: Unidirectional Utilized Bandwidth */ /* Optional */
+#define TE_SUBTLV_USE_BW 39
+struct te_subtlv_use_bw
+{
+ struct subtlv_header header; /* Value length is 4 octets. */
+ float value; /* bandwidth in IEEE floating point format with units in bytes per second */
+} __attribute__((__packed__));
+
+#define TE_SUBTLV_MAX 40 /* Last SUBTLV + 1 */
+
+/* Following declaration concerns the MPLS-TE and LINk-TE management */
+typedef enum _status_t { disable, enable, learn } status_t;
+
+/* Mode for Inter-AS LSP */ /* TODO: Check how if LSP is flooded in RFC5316 */
+typedef enum _interas_mode_t { off, region, as, emulate } interas_mode_t;
+
+#define IS_MPLS_TE(m) (m.status == enable)
+#define IS_CIRCUIT_TE(c) (c->status == enable)
+
+/* Following structure are internal use only. */
+struct isis_mpls_te
+{
+ /* Status of MPLS-TE: enable or disable */
+ status_t status;
+
+ /* L1, L1-L2, L2-Only */
+ u_int8_t level;
+
+ /* RFC5316 */
+ interas_mode_t inter_as;
+ struct in_addr interas_areaid;
+
+ /* Circuit list on which TE are enable */
+ struct list *cir_list;
+
+ /* MPLS_TE router ID */
+ struct in_addr router_id;
+};
+
+extern struct isis_mpls_te isisMplsTE;
+
+struct mpls_te_circuit
+{
+
+ /* Status of MPLS-TE on this interface */
+ status_t status;
+
+ /* Type of MPLS-TE circuit: STD_TE(RFC5305), INTER_AS(RFC5316), INTER_AS_EMU(RFC5316 emulated) */
+ u_int8_t type;
+
+ /* Total size of sub_tlvs */
+ u_char length;
+
+ /* Store subTLV in network byte order. */
+ /* RFC5305 */
+ struct te_subtlv_admin_grp admin_grp;
+ /* RFC5307 */
+ struct te_subtlv_llri llri;
+ /* RFC5305 */
+ struct te_subtlv_local_ipaddr local_ipaddr;
+ struct te_subtlv_rmt_ipaddr rmt_ipaddr;
+ struct te_subtlv_max_bw max_bw;
+ struct te_subtlv_max_rsv_bw max_rsv_bw;
+ struct te_subtlv_unrsv_bw unrsv_bw;
+ struct te_subtlv_te_metric te_metric;
+ /* RFC5316 */
+ struct te_subtlv_ras ras;
+ struct te_subtlv_rip rip;
+ /* draft-ietf-isis-te-metric-extension */
+ struct te_subtlv_av_delay av_delay;
+ struct te_subtlv_mm_delay mm_delay;
+ struct te_subtlv_delay_var delay_var;
+ struct te_subtlv_pkt_loss pkt_loss;
+ struct te_subtlv_res_bw res_bw;
+ struct te_subtlv_ava_bw ava_bw;
+ struct te_subtlv_use_bw use_bw;
+};
+
+/* Prototypes. */
+void isis_mpls_te_init (void);
+struct mpls_te_circuit *mpls_te_circuit_new(void);
+void mpls_te_print_detail(struct vty *, struct te_is_neigh *);
+void set_circuitparams_local_ipaddr (struct mpls_te_circuit *, struct in_addr);
+void set_circuitparams_rmt_ipaddr (struct mpls_te_circuit *, struct in_addr);
+u_char subtlvs_len (struct mpls_te_circuit *);
+u_char add_te_subtlvs(u_char *, struct mpls_te_circuit *);
+u_char build_te_subtlvs(u_char *, struct isis_circuit *);
+void isis_link_params_update(struct isis_circuit *, struct interface *);
+void isis_mpls_te_update(struct interface *);
+void isis_mpls_te_config_write_router (struct vty *);
+
+#endif /* _ZEBRA_ISIS_MPLS_TE_H */
diff --git a/isisd/isis_tlv.c b/isisd/isis_tlv.c
index b4017b5f4..1d29d7828 100644
--- a/isisd/isis_tlv.c
+++ b/isisd/isis_tlv.c
@@ -42,6 +42,7 @@
#include "isisd/isis_misc.h"
#include "isisd/isis_pdu.h"
#include "isisd/isis_lsp.h"
+#include "isisd/isis_te.h"
void
free_tlv (void *val)
@@ -229,9 +230,23 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
while (length > value_len)
{
te_is_nei = (struct te_is_neigh *) pnt;
- value_len += 11;
- pnt += 11;
- /* FIXME - subtlvs are handled here, for now we skip */
+ value_len += IS_NEIGHBOURS_LEN;
+ pnt += IS_NEIGHBOURS_LEN;
+ /* FIXME - subtlvs are handled here, for now we skip */
+ /* FIXME: All TE SubTLVs are not necessary present in LSP PDU. */
+ /* So, it must be copied in a new te_is_neigh structure */
+ /* rather than just initialize pointer to the original LSP PDU */
+ /* to avoid consider the rest of lspdu as subTLVs or buffer overflow */
+ if (IS_MPLS_TE(isisMplsTE))
+ {
+ struct te_is_neigh *new = XCALLOC(MTYPE_ISIS_TLV, sizeof(struct te_is_neigh));
+ memcpy(new->neigh_id, te_is_nei->neigh_id, ISIS_SYS_ID_LEN + 1);
+ memcpy(new->te_metric, te_is_nei->te_metric, 3);
+ new->sub_tlvs_length = te_is_nei->sub_tlvs_length;
+ memcpy(new->sub_tlvs, pnt, te_is_nei->sub_tlvs_length);
+ te_is_nei = new;
+ }
+ /* Skip SUB TLVs payload */
value_len += te_is_nei->sub_tlvs_length;
pnt += te_is_nei->sub_tlvs_length;
@@ -845,8 +860,8 @@ tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream)
for (ALL_LIST_ELEMENTS_RO (te_is_neighs, node, te_is_neigh))
{
- /* FIXME: This will be wrong if we are going to add TE sub TLVs. */
- if (pos - value + IS_NEIGHBOURS_LEN > 255)
+ /* FIXME: Check if Total SubTLVs size doesn't exceed 255 */
+ if (pos - value + IS_NEIGHBOURS_LEN + te_is_neigh->sub_tlvs_length > 255)
{
retval = add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream);
if (retval != ISIS_OK)
@@ -858,9 +873,15 @@ tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream)
pos += ISIS_SYS_ID_LEN + 1;
memcpy (pos, te_is_neigh->te_metric, 3);
pos += 3;
- /* Sub TLVs length. */
- *pos = 0;
+ /* Set the total size of Sub TLVs */
+ *pos = te_is_neigh->sub_tlvs_length;
pos++;
+ /* Copy Sub TLVs if any */
+ if (te_is_neigh->sub_tlvs_length > 0)
+ {
+ memcpy (pos, te_is_neigh->sub_tlvs, te_is_neigh->sub_tlvs_length);
+ pos += te_is_neigh->sub_tlvs_length;
+ }
}
return add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream);
diff --git a/isisd/isis_tlv.h b/isisd/isis_tlv.h
index 619003a0e..5a39d564d 100644
--- a/isisd/isis_tlv.h
+++ b/isisd/isis_tlv.h
@@ -39,7 +39,7 @@
* LSP Entries 9 n n y ISO10589
* Authentication 10 y y y ISO10589, RFC3567
* Checksum 12 y n y RFC3358
- * TE IS Reachability 22 n y n RFC5305
+ * Extended IS Reachability 22 n y n RFC5305
* IS Alias 24 n y n RFC3786
* IP Int. Reachability 128 n y n RFC1195
* Protocols Supported 129 y y n RFC1195
@@ -50,6 +50,7 @@
* Extended IP Reachability 135 n y n RFC5305
* Dynamic Hostname 137 n y n RFC2763
* Shared Risk Link Group 138 n y y RFC5307
+ * Inter-AS Reachability 141 n y n RFC5316
* Restart TLV 211 y n n RFC3847
* MT IS Reachability 222 n y n RFC5120
* MT Supported 229 y y n RFC5120
@@ -59,10 +60,10 @@
* MT IPv6 IP Reachability 237 n y n RFC5120
* P2P Adjacency State 240 y n n RFC3373
* IIH Sequence Number 241 y n n draft-shen-isis-iih-sequence
- * Router Capability 242 - - - draft-ietf-isis-caps
+ * Router Capability 242 n y n RFC4971
*
*
- * IS Reachability sub-TLVs we (should) support.
+ * IS Reachability sub-TLVs we support (See isis_te.[c,h])
* ____________________________________________________________________________
* Name Value Status
* ____________________________________________________________________________
@@ -76,6 +77,8 @@
* TE Default metric 18 RFC5305
* Link Protection Type 20 RFC5307
* Interface Switching Capability 21 RFC5307
+ * Remote AS number 24 RFC5316
+ * IPv4 Remote ASBR identifier 25 RFC5316
*
*
* IP Reachability sub-TLVs we (should) support.
@@ -109,6 +112,7 @@
#define IPV6_ADDR 232
#define IPV6_REACHABILITY 236
#define WAY3_HELLO 240
+#define ROUTER_INFORMATION 242
#define AUTH_INFO_HDRLEN 3
@@ -121,6 +125,8 @@
#define IPV6_REACH_LEN 22
#define TE_IPV4_REACH_LEN 9
+#define MAX_SUBTLV_SIZE 256
+
/* struct for neighbor */
struct is_neigh
{
@@ -128,12 +134,18 @@ struct is_neigh
u_char neigh_id[ISIS_SYS_ID_LEN + 1];
};
-/* struct for te is neighbor */
+/* struct for te metric */
struct te_is_neigh
{
u_char neigh_id[ISIS_SYS_ID_LEN + 1];
u_char te_metric[3];
u_char sub_tlvs_length;
+ /* Theorical Maximum SubTLVs is 256 because the sub_tlvs_length is 8 bits */
+ /* Practically, 118 bytes are necessary to store all supported TE parameters */
+ /* FIXME: A pointer will use less memory, but need to be free */
+ /* which is hard to fix, especially within free_tlvs() function */
+ /* and malloc() / free() as a CPU cost compared to the memory usage */
+ u_char sub_tlvs[MAX_SUBTLV_SIZE]; /* SUB TLVs storage */
};
/* Decode and encode three-octet metric into host byte order integer */
diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c
index 0e5a7ff3b..569ff70d8 100644
--- a/isisd/isis_zebra.c
+++ b/isisd/isis_zebra.c
@@ -49,6 +49,7 @@
#include "isisd/isis_lsp.h"
#include "isisd/isis_route.h"
#include "isisd/isis_zebra.h"
+#include "isisd/isis_te.h"
struct zclient *zclient = NULL;
@@ -61,6 +62,13 @@ isis_router_id_update_zebra (int command, struct zclient *zclient,
struct listnode *node;
struct prefix router_id;
+ /*
+ * If ISIS TE is enable, TE Router ID is set through specific command.
+ * See mpls_te_router_addr() command in isis_te.c
+ */
+ if (IS_MPLS_TE(isisMplsTE))
+ return 0;
+
zebra_router_id_update_read (zclient->ibuf, &router_id);
if (isis->router_id == router_id.u.prefix4.s_addr)
return 0;
@@ -228,6 +236,23 @@ isis_zebra_if_address_del (int command, struct zclient *client,
return 0;
}
+static int
+isis_zebra_link_params (int command, struct zclient *zclient,
+ zebra_size_t length)
+{
+ struct interface *ifp;
+
+ ifp = zebra_interface_link_params_read (zclient->ibuf);
+
+ if (ifp == NULL)
+ return 0;
+
+ /* Update TE TLV */
+ isis_mpls_te_update(ifp);
+
+ return 0;
+}
+
static void
isis_zebra_route_add_ipv4 (struct prefix *prefix,
struct isis_route_info *route_info)
@@ -680,6 +705,7 @@ isis_zebra_init (struct thread_master *master)
zclient->interface_down = isis_zebra_if_state_down;
zclient->interface_address_add = isis_zebra_if_address_add;
zclient->interface_address_delete = isis_zebra_if_address_del;
+ zclient->interface_link_params = isis_zebra_link_params;
zclient->ipv4_route_add = isis_zebra_read_ipv4;
zclient->ipv4_route_delete = isis_zebra_read_ipv4;
zclient->redistribute_route_ipv4_add = isis_zebra_read_ipv4;
diff --git a/isisd/isisd.c b/isisd/isisd.c
index 0d0b805a2..5a9011512 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -54,6 +54,7 @@
#include "isisd/isis_route.h"
#include "isisd/isis_zebra.h"
#include "isisd/isis_events.h"
+#include "isisd/isis_te.h"
#ifdef TOPOLOGY_GENERATE
#include "spgrid.h"
@@ -98,6 +99,7 @@ isis_new (unsigned long process_id)
* uncomment the next line for full debugs
*/
/* isis->debugs = 0xFFFF; */
+ isisMplsTE.status = disable; /* Only support TE metric */
}
struct isis_area *
@@ -781,14 +783,16 @@ print_debug (struct vty *vty, int flags, int onoff)
}
DEFUN (show_debugging,
- show_debugging_cmd,
+ show_debugging_isis_cmd,
"show debugging isis",
SHOW_STR
"State of each debugging option\n"
ISIS_STR)
{
- vty_out (vty, "IS-IS:%s", VTY_NEWLINE);
- print_debug (vty, isis->debugs, 1);
+ if (isis->debugs) {
+ vty_out (vty, "IS-IS:%s", VTY_NEWLINE);
+ print_debug (vty, isis->debugs, 1);
+ }
return CMD_SUCCESS;
}
@@ -2282,6 +2286,7 @@ isis_config_write (struct vty *vty)
#endif /* TOPOLOGY_GENERATE */
}
+ isis_mpls_te_config_write_router(vty);
}
return write;
@@ -2336,7 +2341,7 @@ isis_init ()
install_element (ENABLE_NODE, &show_database_arg_detail_cmd);
install_element (ENABLE_NODE, &show_database_detail_cmd);
install_element (ENABLE_NODE, &show_database_detail_arg_cmd);
- install_element (ENABLE_NODE, &show_debugging_cmd);
+ install_element (ENABLE_NODE, &show_debugging_isis_cmd);
install_node (&debug_node, config_write_debug);
diff --git a/isisd/isisd.h b/isisd/isisd.h
index 69a0100d5..9a4f360a2 100644
--- a/isisd/isisd.h
+++ b/isisd/isisd.h
@@ -197,4 +197,8 @@ extern struct thread_master *master;
} \
while (0)
+#define DEBUG_TE (1<<13)
+
+#define IS_DEBUG_ISIS(x) (isis->debugs & x)
+
#endif /* ISISD_H */