Browse Source

isisd: Add support of Traffic Engineering

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>
Olivier Dugeon 3 years ago
parent
commit
4f593574c4
14 changed files with 1898 additions and 21 deletions
  1. 1 0
      isisd/AUTHORS
  2. 2 2
      isisd/Makefile.am
  3. 10 2
      isisd/isis_circuit.c
  4. 3 1
      isisd/isis_circuit.h
  5. 81 0
      isisd/isis_lsp.c
  6. 3 0
      isisd/isis_main.c
  7. 10 0
      isisd/isis_pdu.c
  8. 1372 0
      isisd/isis_te.c
  9. 331 0
      isisd/isis_te.h
  10. 28 8
      isisd/isis_tlv.c
  11. 16 4
      isisd/isis_tlv.h
  12. 26 0
      isisd/isis_zebra.c
  13. 11 4
      isisd/isisd.c
  14. 4 0
      isisd/isisd.h

+ 1 - 0
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>

+ 2 - 2
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
 
 
 noinst_HEADERS = \
@@ -24,7 +24,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 = \

+ 10 - 2
isisd/isis_circuit.c

@@ -36,6 +36,7 @@
 #include "linklist.h"
 #include "command.h"
 #include "thread.h"
+#include "vty.h"
 #include "hash.h"
 #include "prefix.h"
 #include "stream.h"
@@ -57,6 +58,7 @@
 #include "isisd/isisd.h"
 #include "isisd/isis_csm.h"
 #include "isisd/isis_events.h"
+#include "isisd/isis_te.h"
 
 /*
  * Prototypes.
@@ -98,6 +100,8 @@ isis_circuit_new ()
       circuit->te_metric[i] = DEFAULT_CIRCUIT_METRIC;
     }
 
+  circuit->mtc = mpls_te_circuit_new();
+
   return circuit;
 }
 
@@ -195,8 +199,7 @@ circuit_scan_by_ifp (struct interface *ifp)
   return circuit_lookup_by_ifp (ifp, isis->init_circ_list);
 }
 
-static struct isis_circuit *
-isis_circuit_lookup (struct vty *vty)
+struct isis_circuit * isis_circuit_lookup (struct vty *vty)
 {
   struct interface *ifp;
   struct isis_circuit *circuit;
@@ -249,6 +252,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);
 
@@ -548,6 +555,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

+ 3 - 1
isisd/isis_circuit.h

@@ -108,13 +108,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 */
   struct metric metrics[2];	/* l1XxxMetric */
   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 */
@@ -143,6 +144,7 @@ void isis_circuit_del (struct isis_circuit *circuit);
 struct isis_circuit *circuit_lookup_by_ifp (struct interface *ifp,
 					    struct list *list);
 struct isis_circuit *circuit_scan_by_ifp (struct interface *ifp);
+struct isis_circuit * isis_circuit_lookup (struct vty *vty);
 void isis_circuit_configure (struct isis_circuit *circuit,
 			     struct isis_area *area);
 void isis_circuit_deconfigure (struct isis_circuit *circuit,

+ 81 - 0
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"
@@ -983,6 +984,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 */
@@ -1093,6 +1096,64 @@ lsp_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to,
   return;
 }
 
+/* Process IS_NEIGHBOURS TLV with TE subTLVs */
+static 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)
 {
@@ -1627,6 +1688,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),
@@ -1672,6 +1741,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));

+ 3 - 0
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"
@@ -340,6 +342,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);

+ 10 - 0
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);

File diff suppressed because it is too large
+ 1372 - 0
isisd/isis_te.c


+ 331 - 0
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 */

+ 28 - 8
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)
@@ -178,7 +179,6 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
 	       * |                        Virtual Flag                           | 
 	       * +-------+-------+-------+-------+-------+-------+-------+-------+
 	       */
-	      /* virtual = *pnt; FIXME: what is the use for this? */
 	      pnt++;
 	      value_len++;
 	      /* +-------+-------+-------+-------+-------+-------+-------+-------+
@@ -230,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;
 
@@ -846,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)
@@ -859,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);

+ 16 - 4
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 */

+ 26 - 0
isisd/isis_zebra.c

@@ -48,6 +48,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;
 
@@ -60,6 +61,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;
@@ -227,6 +235,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)
@@ -678,6 +703,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;
 #ifdef HAVE_IPV6

+ 11 - 4
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,13 +783,15 @@ print_debug (struct vty *vty, int flags, int onoff)
 }
 
 DEFUN (show_debugging,
-       show_debugging_cmd,
-       "show debugging",
+       show_debugging_isis_cmd,
+       "show debugging isis",
        SHOW_STR
        "State of each debugging option\n")
 {
-  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;
 }
 
@@ -3250,6 +3254,7 @@ isis_config_write (struct vty *vty)
 #endif /* TOPOLOGY_GENERATE */
 
       }
+    isis_mpls_te_config_write_router(vty);
     }
 
   return write;
@@ -3286,6 +3291,8 @@ isis_init ()
   install_element (VIEW_NODE, &show_database_detail_cmd);
   install_element (VIEW_NODE, &show_database_detail_arg_cmd);
 
+  install_element (ENABLE_NODE, &show_debugging_isis_cmd);
+
   install_node (&debug_node, config_write_debug);
 
   install_element (ENABLE_NODE, &debug_isis_adj_cmd);

+ 4 - 0
isisd/isisd.h

@@ -172,4 +172,8 @@ extern struct thread_master *master;
     } \
   while (0)
 
+#define DEBUG_TE                         (1<<13)
+
+#define IS_DEBUG_ISIS(x)                 (isis->debugs & x)
+
 #endif /* ISISD_H */