diff options
author | Olivier Dugeon <olivier.dugeon@orange.com> | 2016-04-19 19:03:05 +0200 |
---|---|---|
committer | Donald Sharp <sharpd@cumulusnetwroks.com> | 2016-09-03 17:05:50 +0200 |
commit | f8c06e2c5270144ea6d1a3fbc70b42979db836db (patch) | |
tree | c8bc0f78a5c07792111bfc76da4f6814c7a51f37 /isisd | |
parent | Update Traffic Engineering Support for OSPFD (diff) | |
download | frr-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/AUTHORS | 1 | ||||
-rw-r--r-- | isisd/Makefile.am | 4 | ||||
-rw-r--r-- | isisd/isis_circuit.c | 9 | ||||
-rw-r--r-- | isisd/isis_circuit.h | 3 | ||||
-rw-r--r-- | isisd/isis_lsp.c | 81 | ||||
-rw-r--r-- | isisd/isis_lsp.h | 2 | ||||
-rw-r--r-- | isisd/isis_main.c | 3 | ||||
-rw-r--r-- | isisd/isis_pdu.c | 10 | ||||
-rw-r--r-- | isisd/isis_te.c | 1372 | ||||
-rw-r--r-- | isisd/isis_te.h | 331 | ||||
-rw-r--r-- | isisd/isis_tlv.c | 35 | ||||
-rw-r--r-- | isisd/isis_tlv.h | 20 | ||||
-rw-r--r-- | isisd/isis_zebra.c | 26 | ||||
-rw-r--r-- | isisd/isisd.c | 13 | ||||
-rw-r--r-- | isisd/isisd.h | 4 |
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 */ |