zebra: Add link parameters support to Zebra

* zebra/interface.c:
   - Add new link-params CLI commands
   - Add new functions to set/get link parameters for interface
* zebra/redistribute.[c,h]: Add new function to propagate link parameters
  to routing daemon (essentially OSPFD and ISISD) for Traffic Engineering.
* zebra/redistribute_null.c: Add new function
  zebra_interface_parameters_update()
* zebra/zserv.[c,h]: Add new functions to send link parameters

Signed-off-by: Olivier Dugeon <olivier.dugeon@orange.com>
diff --git a/zebra/interface.c b/zebra/interface.c
index 14dc589..6fa097f 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -192,7 +192,7 @@
       /* If deleted address is primary, mark subsequent one as such and distribute. */
       if (! CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
 	{
-	  ifc = listgetdata (listhead (addr_list));
+	  ifc = listgetdata ((struct listnode *)listhead (addr_list));
 	  zebra_interface_address_delete_update (ifp, ifc);
 	  UNSET_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY);
 	  /* XXX: Linux kernel removes all the secondary addresses when the primary
@@ -831,7 +831,7 @@
     {
       if (! rn->info)
 	continue;
-      
+
       for (ALL_LIST_ELEMENTS_RO ((struct list *)rn->info, node, connected))
         connected_dump_vty (vty, connected);
     }
@@ -843,6 +843,53 @@
 	connected_dump_vty (vty, connected);
     }
 
+  if (HAS_LINK_PARAMS(ifp))
+    {
+      int i;
+      struct if_link_params *iflp = ifp->link_params;
+      vty_out(vty, "  Traffic Engineering Link Parameters:%s", VTY_NEWLINE);
+      if (IS_PARAM_SET(iflp, LP_TE))
+        vty_out(vty, "    TE metric %u%s",iflp->te_metric, VTY_NEWLINE);
+      if (IS_PARAM_SET(iflp, LP_MAX_BW))
+        vty_out(vty, "    Maximum Bandwidth %g (Byte/s)%s", iflp->max_bw, VTY_NEWLINE);
+      if (IS_PARAM_SET(iflp, LP_MAX_RSV_BW))
+        vty_out(vty, "    Maximum Reservable Bandwidth %g (Byte/s)%s", iflp->max_rsv_bw, VTY_NEWLINE);
+      if (IS_PARAM_SET(iflp, LP_UNRSV_BW)) {
+        vty_out(vty, "    Unreserved Bandwidth per Class Type in Byte/s:%s", VTY_NEWLINE);
+        for (i = 0; i < MAX_CLASS_TYPE; i+=2)
+          vty_out(vty, "      [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)%s",
+                  i, iflp->unrsv_bw[i], i+1, iflp->unrsv_bw[i+1], VTY_NEWLINE);
+      }
+
+      if (IS_PARAM_SET(iflp, LP_ADM_GRP))
+        vty_out(vty, "    Administrative Group:%u%s", iflp->admin_grp, VTY_NEWLINE);
+      if (IS_PARAM_SET(iflp, LP_DELAY))
+        {
+          vty_out(vty, "    Link Delay Average: %u (micro-sec.)", iflp->av_delay);
+          if (IS_PARAM_SET(iflp, LP_MM_DELAY))
+            {
+              vty_out(vty, " Min:  %u (micro-sec.)", iflp->min_delay);
+              vty_out(vty, " Max:  %u (micro-sec.)", iflp->max_delay);
+            }
+          vty_out(vty, "%s", VTY_NEWLINE);
+        }
+      if (IS_PARAM_SET(iflp, LP_DELAY_VAR))
+        vty_out(vty, "    Link Delay Variation %u (micro-sec.)%s", iflp->delay_var, VTY_NEWLINE);
+      if (IS_PARAM_SET(iflp, LP_PKT_LOSS))
+        vty_out(vty, "    Link Packet Loss %g (in %%)%s", iflp->pkt_loss, VTY_NEWLINE);
+      if (IS_PARAM_SET(iflp, LP_AVA_BW))
+        vty_out(vty, "    Available Bandwidth %g (Byte/s)%s", iflp->ava_bw, VTY_NEWLINE);
+      if (IS_PARAM_SET(iflp, LP_RES_BW))
+        vty_out(vty, "    Residual Bandwidth %g (Byte/s)%s", iflp->res_bw, VTY_NEWLINE);
+      if (IS_PARAM_SET(iflp, LP_USE_BW))
+        vty_out(vty, "    Utilized Bandwidth %g (Byte/s)%s", iflp->use_bw, VTY_NEWLINE);
+      if (IS_PARAM_SET(iflp, LP_RMT_AS))
+        vty_out(vty, "    Neighbor ASBR IP: %s AS: %u %s", inet_ntoa(iflp->rmt_ip), iflp->rmt_as, VTY_NEWLINE);
+    }
+
+ #ifdef RTADV
+   nd_dump_vty (vty, ifp);
+ #endif /* RTADV */
 #if defined (HAVE_RTADV)
   nd_dump_vty (vty, ifp);
 #endif /* HAVE_RTADV */
@@ -938,13 +985,13 @@
 	    "Interface's name\n")
 {
   int ret;
-  struct interface * ifp;
+  struct interface *ifp;
   
   /* Call lib interface() */
   if ((ret = interface_cmd.func (self, vty, argc, argv)) != CMD_SUCCESS)
     return ret;
 
-  ifp = vty->index;  
+  ifp = vty->index;
 
   if (ifp->ifindex == IFINDEX_INTERNAL)
     /* Is this really necessary?  Shouldn't status be initialized to 0
@@ -1414,6 +1461,692 @@
        "Set bandwidth informational parameter\n"
        "Bandwidth in kilobits\n")
 
+struct cmd_node link_params_node =
+{
+  LINK_PARAMS_NODE,
+  "%s(config-link-params)# ",
+  1,
+};
+
+static void
+link_param_cmd_set_uint32 (struct interface *ifp, uint32_t *field, 
+                           uint32_t type, uint32_t value)
+{
+  /* Update field as needed */
+  if (IS_PARAM_UNSET(ifp->link_params, type) || *field != value)
+    {
+      *field = value;
+      SET_PARAM(ifp->link_params, type);
+
+      /* force protocols to update LINK STATE due to parameters change */
+      if (if_is_operative (ifp))
+        zebra_interface_parameters_update (ifp);
+    }
+}
+static void
+link_param_cmd_set_float (struct interface *ifp, float *field,
+                          uint32_t type, float value)
+{
+
+  /* Update field as needed */
+  if (IS_PARAM_UNSET(ifp->link_params, type) || *field != value)
+    {
+      *field = value;
+      SET_PARAM(ifp->link_params, type);
+
+      /* force protocols to update LINK STATE due to parameters change */
+      if (if_is_operative (ifp))
+        zebra_interface_parameters_update (ifp);
+    }
+}
+
+static void
+link_param_cmd_unset (struct interface *ifp, uint32_t type)
+{
+
+  /* Unset field */
+  UNSET_PARAM(ifp->link_params, type);
+
+  /* force protocols to update LINK STATE due to parameters change */
+  if (if_is_operative (ifp))
+    zebra_interface_parameters_update (ifp);
+}
+
+DEFUN (link_params,
+       link_params_cmd,
+       "link-params",
+       LINK_PARAMS_STR)
+{
+  vty->node = LINK_PARAMS_NODE;
+  
+  return CMD_SUCCESS;
+}
+
+/* Specific Traffic Engineering parameters commands */
+DEFUN (link_params_enable,
+       link_params_enable_cmd,
+       "enable",
+       "Activate link parameters on this interface\n")
+{
+  struct interface *ifp = (struct interface *) vty->index;
+    
+  /* This command could be issue at startup, when activate MPLS TE */
+  /* on a new interface or after a ON / OFF / ON toggle */
+  /* In all case, TE parameters are reset to their default factory */
+  if (IS_ZEBRA_DEBUG_EVENT)
+    zlog_debug ("Link-params: enable TE link parameters on interface %s", ifp->name);
+  
+  if (!if_link_params_get (ifp)) 
+    {
+      if (IS_ZEBRA_DEBUG_EVENT)
+        zlog_debug ("Link-params: failed to init TE link parameters  %s", ifp->name);
+      
+      return CMD_WARNING;
+    }
+  
+  /* force protocols to update LINK STATE due to parameters change */
+  if (if_is_operative (ifp))
+    zebra_interface_parameters_update (ifp);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_link_params_enable,
+       no_link_params_enable_cmd,
+       "no enable",
+       NO_STR
+       "Disable link parameters on this interface\n")
+{
+  struct interface *ifp = (struct interface *) vty->index;
+
+  zlog_debug ("MPLS-TE: disable TE link parameters on interface %s", ifp->name);
+  
+  if_link_params_free (ifp);
+  
+  /* force protocols to update LINK STATE due to parameters change */
+  if (if_is_operative (ifp))
+    zebra_interface_parameters_update (ifp);
+
+  return CMD_SUCCESS;
+}
+
+/* STANDARD TE metrics */
+DEFUN (link_params_metric,
+       link_params_metric_cmd,
+       "metric <0-4294967295>",
+       "Link metric for MPLS-TE purpose\n"
+       "Metric value in decimal\n")
+{
+  struct interface *ifp = (struct interface *) vty->index;
+  struct if_link_params *iflp = if_link_params_get (ifp);
+  u_int32_t metric;
+
+  VTY_GET_ULONG("metric", metric, argv[0]);
+
+  /* Update TE metric if needed */
+  link_param_cmd_set_uint32 (ifp, &iflp->te_metric, LP_TE, metric);
+  
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_link_params_metric,
+       no_link_params_metric_cmd,
+       "no metric",
+       NO_STR
+       "Disbale Link Metric on this interface\n")
+{
+  struct interface *ifp = (struct interface *) vty->index;
+  
+  /* Unset TE Metric */
+  link_param_cmd_unset(ifp, LP_TE);
+  
+  return CMD_SUCCESS;
+}
+
+DEFUN (link_params_maxbw,
+       link_params_maxbw_cmd,
+       "max-bw BANDWIDTH",
+       "Maximum bandwidth that can be used\n"
+       "Bytes/second (IEEE floating point format)\n")
+{
+  struct interface *ifp = (struct interface *) vty->index;
+  struct if_link_params *iflp = if_link_params_get (ifp);
+  
+  float bw;
+
+  if (sscanf (argv[0], "%g", &bw) != 1)
+    {
+      vty_out (vty, "link_params_maxbw: fscanf: %s%s", safe_strerror (errno),
+               VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Check that Maximum bandwidth is not lower than other bandwidth parameters */
+  if ((bw <= iflp->max_rsv_bw)
+      || (bw <= iflp->unrsv_bw[0])
+      || (bw <= iflp->unrsv_bw[1])
+      || (bw <= iflp->unrsv_bw[2])
+      || (bw <= iflp->unrsv_bw[3])
+      || (bw <= iflp->unrsv_bw[4])
+      || (bw <= iflp->unrsv_bw[5])
+      || (bw <= iflp->unrsv_bw[6])
+      || (bw <= iflp->unrsv_bw[7])
+      || (bw <= iflp->ava_bw)
+      || (bw <= iflp->res_bw)
+      || (bw <= iflp->use_bw))
+    {
+      vty_out (vty,
+               "Maximum Bandwidth could not be lower than others bandwidth%s",
+               VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Update Maximum Bandwidth if needed */
+  link_param_cmd_set_float (ifp, &iflp->max_bw, LP_MAX_BW, bw);
+    
+  return CMD_SUCCESS;
+}
+
+DEFUN (link_params_max_rsv_bw,
+       link_params_max_rsv_bw_cmd,
+       "max-rsv-bw BANDWIDTH",
+       "Maximum bandwidth that may be reserved\n"
+       "Bytes/second (IEEE floating point format)\n")
+{
+  struct interface *ifp = (struct interface *) vty->index;
+  struct if_link_params *iflp = if_link_params_get (ifp);
+  float bw;
+
+  if (sscanf (argv[0], "%g", &bw) != 1)
+    {
+      vty_out (vty, "link_params_max_rsv_bw: fscanf: %s%s", safe_strerror (errno),
+               VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Check that bandwidth is not greater than maximum bandwidth parameter */
+  if (bw > iflp->max_bw)
+    {
+      vty_out (vty,
+               "Maximum Reservable Bandwidth could not be greater than Maximum Bandwidth (%g)%s",
+               iflp->max_bw, VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Update Maximum Reservable Bandwidth if needed */
+  link_param_cmd_set_float (ifp, &iflp->max_rsv_bw, LP_MAX_RSV_BW, bw);
+  
+  return CMD_SUCCESS;
+}
+
+DEFUN (link_params_unrsv_bw,
+       link_params_unrsv_bw_cmd,
+       "unrsv-bw <0-7> BANDWIDTH",
+       "Unreserved bandwidth at each priority level\n"
+       "Priority\n"
+       "Bytes/second (IEEE floating point format)\n")
+{
+  struct interface *ifp = (struct interface *) vty->index;
+  struct if_link_params *iflp = if_link_params_get (ifp);
+  int priority;
+  float bw;
+
+  /* We don't have to consider about range check here. */
+  if (sscanf (argv[0], "%d", &priority) != 1)
+    {
+      vty_out (vty, "link_params_unrsv_bw: fscanf: %s%s", safe_strerror (errno),
+               VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (sscanf (argv[1], "%g", &bw) != 1)
+    {
+      vty_out (vty, "link_params_unrsv_bw: fscanf: %s%s", safe_strerror (errno),
+               VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Check that bandwidth is not greater than maximum bandwidth parameter */
+  if (bw > iflp->max_bw)
+    {
+      vty_out (vty,
+               "UnReserved Bandwidth could not be greater than Maximum Bandwidth (%g)%s",
+               iflp->max_bw, VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Update Unreserved Bandwidth if needed */
+  link_param_cmd_set_float (ifp, &iflp->unrsv_bw[priority], LP_UNRSV_BW, bw);
+  
+  return CMD_SUCCESS;
+}
+
+DEFUN (link_params_admin_grp,
+       link_params_admin_grp_cmd,
+       "admin-grp BITPATTERN",
+       "Administrative group membership\n"
+       "32-bit Hexadecimal value (e.g. 0xa1)\n")
+{
+  struct interface *ifp = (struct interface *) vty->index;
+  struct if_link_params *iflp = if_link_params_get (ifp);
+  unsigned long value;
+
+  if (sscanf (argv[0], "0x%lx", &value) != 1)
+    {
+      vty_out (vty, "link_params_admin_grp: fscanf: %s%s",
+               safe_strerror (errno), VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Update Administrative Group if needed */
+  link_param_cmd_set_uint32 (ifp, &iflp->admin_grp, LP_ADM_GRP, value);
+  
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_link_params_admin_grp,
+       no_link_params_admin_grp_cmd,
+       "no admin-grp",
+       NO_STR
+       "Disbale Administrative group membership on this interface\n")
+{
+  struct interface *ifp = (struct interface *) vty->index;
+  
+  /* Unset Admin Group */
+  link_param_cmd_unset(ifp, LP_ADM_GRP);
+  
+  return CMD_SUCCESS;
+}
+
+/* RFC5392 & RFC5316: INTER-AS */
+DEFUN (link_params_inter_as,
+       link_params_inter_as_cmd,
+       "neighbor A.B.C.D as <1-4294967295>",
+       "Configure remote ASBR information (Neighbor IP address and AS number)\n"
+       "Remote IP address in dot decimal A.B.C.D\n"
+       "Remote AS number\n"
+       "AS number in the range <1-4294967295>\n")
+{
+
+  struct interface *ifp = (struct interface *) vty->index;
+  struct if_link_params *iflp = if_link_params_get (ifp);
+  struct in_addr addr;
+  u_int32_t as;
+
+  if (!inet_aton (argv[0], &addr))
+    {
+      vty_out (vty, "Please specify Router-Addr by A.B.C.D%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+    
+  VTY_GET_ULONG("AS number", as, argv[1]);
+  
+  /* Update Remote IP and Remote AS fields if needed */
+  if (IS_PARAM_UNSET(iflp, LP_RMT_AS)
+      || iflp->rmt_as != as
+      || iflp->rmt_ip.s_addr != addr.s_addr)
+    {
+
+      iflp->rmt_as = as;
+      iflp->rmt_ip.s_addr = addr.s_addr;
+      SET_PARAM(iflp, LP_RMT_AS);
+
+      /* force protocols to update LINK STATE due to parameters change */
+      if (if_is_operative (ifp))
+        zebra_interface_parameters_update (ifp);
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_link_params_inter_as,
+       no_link_params_inter_as_cmd,
+       "no neighbor",
+       NO_STR
+       "Remove Neighbor IP address and AS number for Inter-AS TE\n")
+{
+
+  struct interface *ifp = (struct interface *) vty->index;
+  struct if_link_params *iflp = if_link_params_get (ifp);
+
+  /* Reset Remote IP and AS neighbor */
+  iflp->rmt_as = 0;
+  iflp->rmt_ip.s_addr = 0;
+  UNSET_PARAM(iflp, LP_RMT_AS);
+
+  /* force protocols to update LINK STATE due to parameters change */
+  if (if_is_operative (ifp))
+    zebra_interface_parameters_update (ifp);
+
+  return CMD_SUCCESS;
+}
+
+/* RFC7471: OSPF Traffic Engineering (TE) Metric extensions & draft-ietf-isis-metric-extensions-07.txt */
+DEFUN (link_params_delay,
+       link_params_delay_cmd,
+       "delay <0-16777215>",
+       "Unidirectional Average Link Delay\n"
+       "Average delay in micro-second as decimal (0...16777215)\n")
+{
+
+  struct interface *ifp = (struct interface *) vty->index;
+  struct if_link_params *iflp = if_link_params_get (ifp);
+  u_int32_t delay = 0, low = 0, high = 0;
+  u_int8_t update = 0;
+
+  /* Get and Check new delay values */
+  VTY_GET_ULONG("delay", delay, argv[0]);
+  switch (argc)
+    {
+    case 1:
+      /* Check new delay value against old Min and Max delays if set */
+      if (IS_PARAM_SET(iflp, LP_MM_DELAY)
+          && (delay <= iflp->min_delay || delay >= iflp->max_delay))
+        {
+          vty_out (vty, "Average delay should be comprise between Min (%d) and Max (%d) delay%s",
+                   iflp->min_delay, iflp->max_delay, VTY_NEWLINE);
+          return CMD_WARNING;
+        }
+      /* Update delay if value is not set or change */
+      if (IS_PARAM_UNSET(iflp, LP_DELAY)|| iflp->av_delay != delay)
+        {
+          iflp->av_delay = delay;
+          SET_PARAM(iflp, LP_DELAY);
+          update = 1;
+        }
+      /* Unset Min and Max delays if already set */
+      if (IS_PARAM_SET(iflp, LP_MM_DELAY))
+        {
+          iflp->min_delay = 0;
+          iflp->max_delay = 0;
+          UNSET_PARAM(iflp, LP_MM_DELAY);
+          update = 1;
+        }
+      break;
+    case 2:
+      vty_out (vty, "You should specify both Minimum and Maximum delay with Average delay%s",
+               VTY_NEWLINE);
+      return CMD_WARNING;
+    break;
+    case 3:
+      VTY_GET_ULONG("minimum delay", low, argv[1]);
+      VTY_GET_ULONG("maximum delay", high, argv[2]);
+      /* Check new delays value coherency */
+      if (delay <= low || delay >= high)
+        {
+          vty_out (vty, "Average delay should be comprise between Min (%d) and Max (%d) delay%s",
+                   low, high, VTY_NEWLINE);
+          return CMD_WARNING;
+        }
+      /* Update Delays if needed */
+      if (IS_PARAM_UNSET(iflp, LP_DELAY)
+          || IS_PARAM_UNSET(iflp, LP_MM_DELAY)
+          || iflp->av_delay != delay
+          || iflp->min_delay != low
+          || iflp->max_delay != high)
+        {
+          iflp->av_delay = delay;
+          SET_PARAM(iflp, LP_DELAY);
+          iflp->min_delay = low;
+          iflp->max_delay = high;
+          SET_PARAM(iflp, LP_MM_DELAY);
+          update = 1;
+        }
+      break;
+    default:
+      return CMD_WARNING;
+      break;
+    }
+
+  /* force protocols to update LINK STATE due to parameters change */
+  if (update == 1 && if_is_operative (ifp))
+    zebra_interface_parameters_update (ifp);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (link_params_delay,
+       link_params_delay_mm_cmd,
+       "delay <0-16777215> min <0-16777215> max <0-16777215>",
+       "Unidirectional Average Link Delay (optionally Minimum and Maximum delays)\n"
+       "Average delay in micro-second as decimal (0...16777215)\n"
+       "Minimum delay\n"
+       "Minimum delay in micro-second as decimal (0...16777215)\n"
+       "Maximum delay\n"
+       "Maximum delay in micro-second as decimal (0...16777215)\n")
+
+DEFUN (no_link_params_delay,
+       no_link_params_delay_cmd,
+       "no delay",
+       NO_STR
+       "Disbale Unidirectional Average, Min & Max Link Delay on this interface\n")
+{
+  struct interface *ifp = (struct interface *) vty->index;
+  struct if_link_params *iflp = if_link_params_get (ifp);
+  
+  /* Unset Delays */
+  iflp->av_delay = 0;
+  UNSET_PARAM(iflp, LP_DELAY);
+  iflp->min_delay = 0;
+  iflp->max_delay = 0;
+  UNSET_PARAM(iflp, LP_MM_DELAY);
+  
+  /* force protocols to update LINK STATE due to parameters change */
+  if (if_is_operative (ifp))
+    zebra_interface_parameters_update (ifp);
+  
+  return CMD_SUCCESS;
+}
+
+DEFUN (link_params_delay_var,
+       link_params_delay_var_cmd,
+       "delay-variation <0-16777215>",
+       "Unidirectional Link Delay Variation\n"
+       "delay variation in micro-second as decimal (0...16777215)\n")
+{
+  struct interface *ifp = (struct interface *) vty->index;
+  struct if_link_params *iflp = if_link_params_get (ifp);
+  u_int32_t value;
+  
+  VTY_GET_ULONG("delay variation", value, argv[0]);
+  
+  /* Update Delay Variation if needed */
+  link_param_cmd_set_uint32 (ifp, &iflp->delay_var, LP_DELAY_VAR, value);
+  
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_link_params_delay_var,
+       no_link_params_delay_var_cmd,
+       "no delay-variation",
+       NO_STR
+       "Disbale Unidirectional Delay Variation on this interface\n")
+{
+  struct interface *ifp = (struct interface *) vty->index;
+  
+  /* Unset Delay Variation */
+  link_param_cmd_unset(ifp, LP_DELAY_VAR);
+  
+  return CMD_SUCCESS;
+}
+
+DEFUN (link_params_pkt_loss,
+       link_params_pkt_loss_cmd,
+       "packet-loss PERCENTAGE",
+       "Unidirectional Link Packet Loss\n"
+       "percentage of total traffic by 0.000003% step and less than 50.331642%\n")
+{
+  struct interface *ifp = (struct interface *) vty->index;
+  struct if_link_params *iflp = if_link_params_get (ifp);
+  float fval;
+
+  if (sscanf (argv[0], "%g", &fval) != 1)
+    {
+      vty_out (vty, "link_params_pkt_loss: fscanf: %s%s", safe_strerror (errno),
+               VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (fval > MAX_PKT_LOSS)
+    fval = MAX_PKT_LOSS;
+
+  /* Update Packet Loss if needed */
+  link_param_cmd_set_float (ifp, &iflp->pkt_loss, LP_PKT_LOSS, fval);
+  
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_link_params_pkt_loss,
+       no_link_params_pkt_loss_cmd,
+       "no packet-loss",
+       NO_STR
+       "Disbale Unidirectional Link Packet Loss on this interface\n")
+{
+  struct interface *ifp = (struct interface *) vty->index;
+  
+  /* Unset Packet Loss */
+  link_param_cmd_unset(ifp, LP_PKT_LOSS);
+  
+  return CMD_SUCCESS;
+}
+
+DEFUN (link_params_res_bw,
+       link_params_res_bw_cmd,
+       "res-bw BANDWIDTH",
+       "Unidirectional Residual Bandwidth\n"
+       "Bytes/second (IEEE floating point format)\n")
+{
+  struct interface *ifp = (struct interface *) vty->index;
+  struct if_link_params *iflp = if_link_params_get (ifp);
+  float bw;
+
+  if (sscanf (argv[0], "%g", &bw) != 1)
+    {
+      vty_out (vty, "link_params_res_bw: fscanf: %s%s", safe_strerror (errno),
+               VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Check that bandwidth is not greater than maximum bandwidth parameter */
+  if (bw > iflp->max_bw)
+    {
+      vty_out (vty,
+               "Residual Bandwidth could not be greater than Maximum Bandwidth (%g)%s",
+               iflp->max_bw, VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Update Residual Bandwidth if needed */
+  link_param_cmd_set_float (ifp, &iflp->res_bw, LP_RES_BW, bw);
+  
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_link_params_res_bw,
+       no_link_params_res_bw_cmd,
+       "no res-bw",
+       NO_STR
+       "Disbale Unidirectional Residual Bandwidth on this interface\n")
+{
+  struct interface *ifp = (struct interface *) vty->index;
+  
+  /* Unset Residual Bandwidth */
+  link_param_cmd_unset(ifp, LP_RES_BW);
+  
+  return CMD_SUCCESS;
+}
+
+DEFUN (link_params_ava_bw,
+       link_params_ava_bw_cmd,
+       "ava-bw BANDWIDTH",
+       "Unidirectional Available Bandwidth\n"
+       "Bytes/second (IEEE floating point format)\n")
+{
+  struct interface *ifp = (struct interface *) vty->index;
+  struct if_link_params *iflp = if_link_params_get (ifp);
+  float bw;
+
+  if (sscanf (argv[0], "%g", &bw) != 1)
+    {
+      vty_out (vty, "link_params_ava_bw: fscanf: %s%s", safe_strerror (errno),
+               VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Check that bandwidth is not greater than maximum bandwidth parameter */
+  if (bw > iflp->max_bw)
+    {
+      vty_out (vty,
+               "Available Bandwidth could not be greater than Maximum Bandwidth (%g)%s",
+               iflp->max_bw, VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Update Residual Bandwidth if needed */
+  link_param_cmd_set_float (ifp, &iflp->ava_bw, LP_AVA_BW, bw);
+  
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_link_params_ava_bw,
+       no_link_params_ava_bw_cmd,
+       "no ava-bw",
+       NO_STR
+       "Disbale Unidirectional Available Bandwidth on this interface\n")
+{
+  struct interface *ifp = (struct interface *) vty->index;
+  
+  /* Unset Available Bandwidth */
+  link_param_cmd_unset(ifp, LP_AVA_BW);
+  
+  return CMD_SUCCESS;
+}
+
+DEFUN (link_params_use_bw,
+       link_params_use_bw_cmd,
+       "use-bw BANDWIDTH",
+       "Unidirectional Utilised Bandwidth\n"
+       "Bytes/second (IEEE floating point format)\n")
+{
+  struct interface *ifp = (struct interface *) vty->index;
+  struct if_link_params *iflp = if_link_params_get (ifp);
+  float bw;
+
+  if (sscanf (argv[0], "%g", &bw) != 1)
+    {
+      vty_out (vty, "link_params_use_bw: fscanf: %s%s", safe_strerror (errno),
+               VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Check that bandwidth is not greater than maximum bandwidth parameter */
+  if (bw > iflp->max_bw)
+    {
+      vty_out (vty,
+               "Utilised Bandwidth could not be greater than Maximum Bandwidth (%g)%s",
+               iflp->max_bw, VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Update Utilized Bandwidth if needed */
+  link_param_cmd_set_float (ifp, &iflp->use_bw, LP_USE_BW, bw);
+  
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_link_params_use_bw,
+       no_link_params_use_bw_cmd,
+       "no use-bw",
+       NO_STR
+       "Disbale Unidirectional Utilised Bandwidth on this interface\n")
+{
+  struct interface *ifp = (struct interface *) vty->index;
+  
+  /* Unset Utilised Bandwidth */
+  link_param_cmd_unset(ifp, LP_USE_BW);
+  
+  return CMD_SUCCESS;
+}
+
 static int
 ip_address_install (struct vty *vty, struct interface *ifp,
 		    const char *addr_str, const char *peer_str,
@@ -1752,6 +2485,56 @@
 #endif /* HAVE_IPV6 */
 
 static int
+link_params_config_write (struct vty *vty, struct interface *ifp)
+{
+  if ((ifp == NULL) || !HAS_LINK_PARAMS(ifp))
+    return -1;
+  
+  struct if_link_params *iflp = ifp->link_params;
+
+  vty_out (vty, " link-params%s", VTY_NEWLINE);
+  vty_out(vty, "  enable%s", VTY_NEWLINE);
+  if (IS_PARAM_SET(iflp, LP_TE))
+    vty_out(vty, "  metric %u%s",iflp->te_metric, VTY_NEWLINE);
+  if (IS_PARAM_SET(iflp, LP_MAX_BW))
+    vty_out(vty, "  max-bw %g%s", iflp->max_bw, VTY_NEWLINE);
+  if (IS_PARAM_SET(iflp, LP_MAX_RSV_BW))
+    vty_out(vty, "  max-rsv-bw %g%s", iflp->max_rsv_bw, VTY_NEWLINE);
+  if (IS_PARAM_SET(iflp, LP_UNRSV_BW))
+    {
+      for (int i = 0; i < 8; i++)
+        vty_out(vty, "  unrsv-bw %d %g%s",
+            i, iflp->unrsv_bw[i], VTY_NEWLINE);
+    }
+  if (IS_PARAM_SET(iflp, LP_ADM_GRP))
+    vty_out(vty, "  admin-grp %u%s", iflp->admin_grp, VTY_NEWLINE);
+  if (IS_PARAM_SET(iflp, LP_DELAY))
+    {
+      vty_out(vty, "  delay %u", iflp->av_delay);
+      if (IS_PARAM_SET(iflp, LP_MM_DELAY))
+        {
+          vty_out(vty, " min %u", iflp->min_delay);
+          vty_out(vty, " max %u", iflp->max_delay);
+        }
+      vty_out(vty, "%s", VTY_NEWLINE);
+    }
+  if (IS_PARAM_SET(iflp, LP_DELAY_VAR))
+    vty_out(vty, "  delay-variation %u%s", iflp->delay_var, VTY_NEWLINE);
+  if (IS_PARAM_SET(iflp, LP_PKT_LOSS))
+    vty_out(vty, "  packet-loss %g%s", iflp->pkt_loss, VTY_NEWLINE);
+  if (IS_PARAM_SET(iflp, LP_AVA_BW))
+    vty_out(vty, "  ava-bw %g%s", iflp->ava_bw, VTY_NEWLINE);
+  if (IS_PARAM_SET(iflp, LP_RES_BW))
+    vty_out(vty, "  res-bw %g%s", iflp->res_bw, VTY_NEWLINE);
+  if (IS_PARAM_SET(iflp, LP_USE_BW))
+    vty_out(vty, "  use-bw %g%s", iflp->use_bw, VTY_NEWLINE);
+  if (IS_PARAM_SET(iflp, LP_RMT_AS))
+    vty_out(vty, "  neighbor %s as %u%s", inet_ntoa(iflp->rmt_ip),
+        iflp->rmt_as, VTY_NEWLINE);
+  return 0;
+}
+
+static int
 if_config_write (struct vty *vty)
 {
   struct listnode *node;
@@ -1788,7 +2571,6 @@
 	 while processing config script */
       if (ifp->bandwidth != 0)
 	vty_out(vty, " bandwidth %u%s", ifp->bandwidth, VTY_NEWLINE); 
-
       if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION))
 	vty_out(vty, " link-detect%s", VTY_NEWLINE);
       else
@@ -1827,11 +2609,14 @@
       irdp_config_write (vty, ifp);
 #endif /* IRDP */
 
+      link_params_config_write (vty, ifp);
+
       vty_out (vty, "!%s", VTY_NEWLINE);
     }
   return 0;
 }
 
+
 /* Allocate and initialize interface vector. */
 void
 zebra_if_init (void)
@@ -1843,6 +2628,8 @@
   /* Install configuration write function. */
   install_node (&interface_node, if_config_write);
 
+  install_node (&link_params_node, NULL);
+  
   install_element (VIEW_NODE, &show_interface_cmd);
   install_element (VIEW_NODE, &show_interface_vrf_cmd);
   install_element (VIEW_NODE, &show_interface_vrf_all_cmd);
@@ -1875,4 +2662,22 @@
   install_element (INTERFACE_NODE, &ip_address_label_cmd);
   install_element (INTERFACE_NODE, &no_ip_address_label_cmd);
 #endif /* HAVE_NETLINK */
+  install_element(INTERFACE_NODE, &link_params_cmd);
+  install_default(LINK_PARAMS_NODE);
+  install_element(LINK_PARAMS_NODE, &link_params_enable_cmd);
+  install_element(LINK_PARAMS_NODE, &no_link_params_enable_cmd);
+  install_element(LINK_PARAMS_NODE, &link_params_metric_cmd);
+  install_element(LINK_PARAMS_NODE, &link_params_maxbw_cmd);
+  install_element(LINK_PARAMS_NODE, &link_params_max_rsv_bw_cmd);
+  install_element(LINK_PARAMS_NODE, &link_params_unrsv_bw_cmd);
+  install_element(LINK_PARAMS_NODE, &link_params_admin_grp_cmd);
+  install_element(LINK_PARAMS_NODE, &link_params_inter_as_cmd);
+  install_element(LINK_PARAMS_NODE, &no_link_params_inter_as_cmd);
+  install_element(LINK_PARAMS_NODE, &link_params_delay_cmd);
+  install_element(LINK_PARAMS_NODE, &link_params_delay_mm_cmd);
+  install_element(LINK_PARAMS_NODE, &link_params_delay_var_cmd);
+  install_element(LINK_PARAMS_NODE, &link_params_pkt_loss_cmd);
+  install_element(LINK_PARAMS_NODE, &link_params_ava_bw_cmd);
+  install_element(LINK_PARAMS_NODE, &link_params_res_bw_cmd);
+  install_element(LINK_PARAMS_NODE, &link_params_use_bw_cmd);
 }