| /* |
| * 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 "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 (iflist, 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 (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; |
| } |
| |