lib: Add new if_link_params structure

This new structure is the basis to get new link parameters for
Traffic Engineering from Zebra/interface layer to OSPFD and ISISD
for the support of Traffic Engineering

* lib/if.[c,h]: link parameters struture and get/set functions
* lib/command.[c,h]: creation of a new link-node
* lib/zclient.[c,h]: modification to the ZBUS message to convey the
  link parameters structure
* lib/zebra.h: New ZBUS message
* lib/memtypes.c: Add new memory type for Traffic Engineering support

Signed-off-by: Olivier Dugeon <olivier.dugeon@orange.com>
diff --git a/lib/command.c b/lib/command.c
index fa2ef11..ab46fc4 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -2632,8 +2632,12 @@
     case KEYCHAIN_KEY_NODE:
       ret = KEYCHAIN_NODE;
       break;
+    case LINK_PARAMS_NODE:
+      ret = INTERFACE_NODE;
+      break;
     default:
       ret = CONFIG_NODE;
+      break;
     }
 
   return ret;
@@ -3003,6 +3007,9 @@
     case KEYCHAIN_KEY_NODE:
       vty->node = KEYCHAIN_NODE;
       break;
+    case LINK_PARAMS_NODE:
+      vty->node = INTERFACE_NODE;
+      break;
     default:
       break;
     }
@@ -3052,6 +3059,7 @@
     case MASC_NODE:
     case PIM_NODE:
     case VTY_NODE:
+    case LINK_PARAMS_NODE:
       vty_config_unlock (vty);
       vty->node = ENABLE_NODE;
       break;
diff --git a/lib/command.h b/lib/command.h
index 214b1d5..d8029fb 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -109,6 +109,7 @@
   FORWARDING_NODE,		/* IP forwarding node. */
   PROTOCOL_NODE,                /* protocol filtering node */
   VTY_NODE,			/* Vty node. */
+  LINK_PARAMS_NODE,		/* Link-parameters node */
 };
 
 /* Node which has some commands and prompt string and configuration
@@ -509,6 +510,10 @@
 "(neighbor|interface|area|lsa|zebra|config|dbex|spf|route|lsdb|redistribute|hook|asbr|prefix|abr)"
 #define ISIS_STR "IS-IS information\n"
 #define AREA_TAG_STR "[area tag]\n"
+#define MPLS_TE_STR "MPLS-TE specific commands\n"
+#define LINK_PARAMS_STR "Configure interface link parameters\n"
+#define OSPF_RI_STR "OSPF Router Information specific commands\n"
+#define PCE_STR "PCE Router Information specific commands\n"
 
 #define CONF_BACKUP_EXT ".sav"
 
diff --git a/lib/if.c b/lib/if.c
index 44b8586..45c1acc 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -168,6 +168,8 @@
 
   list_free (ifp->connected);
 
+  if_link_params_free (ifp);
+  
   XFREE (MTYPE_IF, ifp);
 }
 
@@ -1125,3 +1127,43 @@
     }
   return NULL;
 }
+
+struct if_link_params *
+if_link_params_get (struct interface *ifp)
+{
+  if (ifp->link_params != NULL)
+    return ifp->link_params;
+  
+  struct if_link_params *iflp = XCALLOC(MTYPE_IF_LINK_PARAMS,
+                                      sizeof (struct if_link_params));
+  if (iflp == NULL) return NULL;
+  
+  /* Set TE metric == standard metric */
+  iflp->te_metric = ifp->metric;
+
+  /* Compute default bandwidth based on interface */
+  int bw = (float)((ifp->bandwidth ? ifp->bandwidth : DEFAULT_BANDWIDTH) 
+                   * TE_KILO_BIT / TE_BYTE);
+  
+  /* Set Max, Reservable and Unreserved Bandwidth */
+  iflp->max_bw = bw;
+  iflp->max_rsv_bw = bw;
+  for (int i = 0; i < MAX_CLASS_TYPE; i++)
+    iflp->unrsv_bw[i] = bw;
+  
+  /* Update Link parameters status */
+  iflp->lp_status = LP_TE | LP_MAX_BW | LP_MAX_RSV_BW | LP_UNRSV_BW;
+
+  /* Finally attach newly created Link Parameters */
+  ifp->link_params = iflp;
+
+  return iflp;
+}
+
+void
+if_link_params_free (struct interface *ifp)
+{
+  if (ifp->link_params == NULL) return;
+  XFREE(MTYPE_IF_LINK_PARAMS, ifp->link_params);
+  ifp->link_params = NULL;
+}
diff --git a/lib/if.h b/lib/if.h
index b3d14ba..9796a4d 100644
--- a/lib/if.h
+++ b/lib/if.h
@@ -131,6 +131,63 @@
 };
 #endif /* HAVE_PROC_NET_DEV */
 
+/* Here are "non-official" architectural constants. */
+#define TE_EXT_MASK             0x0FFFFFFF
+#define TE_EXT_ANORMAL          0x80000000
+#define LOSS_PRECISION          0.000003
+#define TE_KILO_BIT             1000
+#define TE_BYTE                 8
+#define DEFAULT_BANDWIDTH       10000
+#define MAX_CLASS_TYPE          8
+#define MAX_PKT_LOSS            50.331642
+
+/* Link Parameters Status: 0: unset, 1: set, */
+#define LP_UNSET                0x0000
+#define LP_TE                   0x0001
+#define LP_MAX_BW               0x0002
+#define LP_MAX_RSV_BW           0x0004
+#define LP_UNRSV_BW             0x0008
+#define LP_ADM_GRP              0x0010
+#define LP_RMT_AS               0x0020
+#define LP_DELAY                0x0040
+#define LP_MM_DELAY             0x0080
+#define LP_DELAY_VAR            0x0100
+#define LP_PKT_LOSS             0x0200
+#define LP_RES_BW               0x0400
+#define LP_AVA_BW               0x0800
+#define LP_USE_BW               0x1000
+
+#define IS_PARAM_UNSET(lp, st) !(lp->lp_status & st)
+#define IS_PARAM_SET(lp, st) (lp->lp_status & st)
+#define IS_LINK_PARAMS_SET(lp) (lp->lp_status != LP_UNSET)
+
+#define SET_PARAM(lp, st) (lp->lp_status) |= (st)
+#define UNSET_PARAM(lp, st) (lp->lp_status) &= ~(st)
+#define RESET_LINK_PARAM(lp) (lp->lp_status = LP_UNSET)
+
+/* Link Parameters for Traffic Engineering */
+struct if_link_params {
+  u_int32_t lp_status;   /* Status of Link Parameters: */
+  u_int32_t te_metric;   /* Traffic Engineering metric */
+  float max_bw;          /* Maximum Bandwidth */
+  float max_rsv_bw;      /* Maximum Reservable Bandwidth */
+  float unrsv_bw[MAX_CLASS_TYPE];     /* Unreserved Bandwidth per Class Type (8) */
+  u_int32_t admin_grp;   /* Administrative group */
+  u_int32_t rmt_as;      /* Remote AS number */
+  struct in_addr rmt_ip; /* Remote IP address */
+  u_int32_t av_delay;    /* Link Average Delay */
+  u_int32_t min_delay;   /* Link Min Delay */
+  u_int32_t max_delay;   /* Link Max Delay */
+  u_int32_t delay_var;   /* Link Delay Variation */
+  float pkt_loss;        /* Link Packet Loss */
+  float res_bw;          /* Residual Bandwidth */
+  float ava_bw;          /* Available Bandwidth */
+  float use_bw;          /* Utilized Bandwidth */
+};
+
+#define INTERFACE_LINK_PARAMS_SIZE   sizeof(struct if_link_params)
+#define HAS_LINK_PARAMS(ifp)  ((ifp)->link_params != NULL)
+
 /* Interface structure */
 struct interface 
 {
@@ -172,6 +229,9 @@
   /* interface bandwidth, kbits */
   unsigned int bandwidth;
   
+  /* Link parameters for Traffic Engineering */
+  struct if_link_params *link_params;
+
   /* description of the interface. */
   char *desc;			
 
@@ -389,6 +449,10 @@
 extern char *if_indextoname (ifindex_t, char *);
 #endif
 
+/* link parameters */
+struct if_link_params *if_link_params_get (struct interface *);
+void if_link_params_free (struct interface *);
+
 /* Exported variables. */
 extern struct list *iflist;
 extern struct cmd_element interface_desc_cmd;
diff --git a/lib/memtypes.c b/lib/memtypes.c
index 3b9345d..f464c4b 100644
--- a/lib/memtypes.c
+++ b/lib/memtypes.c
@@ -72,6 +72,7 @@
   { MTYPE_VRF,			"VRF"				},
   { MTYPE_VRF_NAME,		"VRF name"			},
   { MTYPE_VRF_BITMAP,		"VRF bit-map"			},
+  { MTYPE_IF_LINK_PARAMS,       "Informational Link Parameters" },
   { -1, NULL },
 };
 
@@ -214,6 +215,8 @@
   { MTYPE_OSPF_IF_INFO,       "OSPF if info"			},
   { MTYPE_OSPF_IF_PARAMS,     "OSPF if params"			},
   { MTYPE_OSPF_MESSAGE,		"OSPF message"			},
+  { MTYPE_OSPF_MPLS_TE,       "OSPF MPLS parameters"            },
+  { MTYPE_OSPF_PCE_PARAMS,    "OSPF PCE parameters"             },
   { -1, NULL },
 };
 
@@ -256,6 +259,7 @@
   { MTYPE_ISIS_NEXTHOP6,      "ISIS nexthop6"			},
   { MTYPE_ISIS_DICT,          "ISIS dictionary"			},
   { MTYPE_ISIS_DICT_NODE,     "ISIS dictionary node"		},
+  { MTYPE_ISIS_MPLS_TE,       "ISIS MPLS_TE parameters"         },
   { -1, NULL },
 };
 
diff --git a/lib/zclient.c b/lib/zclient.c
index 208ea5c..c2e1333 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -707,8 +707,6 @@
  * ZEBRA_INTERFACE_DELETE from zebra to the client is:
  *     0                   1                   2                   3
  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- * +-+-+-+-+-+-+-+-+
- * |   type        |
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  * |  ifname                                                       |
  * |                                                               |
@@ -716,20 +714,32 @@
  * |                                                               |
  * |                                                               |
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |         ifindex                                               |
+ * |  ifindex                                                      |
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |         if_flags                                              |
+ * |  status       |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |  if_flags                                                     |
  * |                                                               |
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |         metric                                                |
+ * |  metric                                                       |
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |         ifmtu                                                 |
+ * |  ifmtu                                                        |
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |         ifmtu6                                                |
+ * |  ifmtu6                                                       |
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |         bandwidth                                             |
+ * |  bandwidth                                                    |
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |         sockaddr_dl                                           |
+ * |  Link Layer Type                                              |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |  Harware Address Length                                       |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |  Hardware Address      if HW lenght different from 0          |
+ * |   ...                  max INTERFACE_HWADDR_MAX               |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |  Link_params? |  Whether a link-params follows: 1 or 0.       
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |  Link_params    0 or 1 INTERFACE_LINK_PARAMS_SIZE sized       |
+ * |   ....          (struct if_link_params).                      |
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  */
 
@@ -782,7 +792,135 @@
   return ifp;
 }
 
-/* 
+static void
+link_params_set_value(struct stream *s, struct if_link_params *iflp)
+{
+  
+  if (iflp == NULL)
+    return;
+  
+  iflp->lp_status = stream_getl (s);
+  iflp->te_metric = stream_getl (s);
+  iflp->max_bw = stream_getf (s);
+  iflp->max_rsv_bw = stream_getf (s);
+  uint32_t bwclassnum = stream_getl (s);
+  {
+    unsigned int i;
+    for (i = 0; i < bwclassnum && i < MAX_CLASS_TYPE; i++)
+      iflp->unrsv_bw[i] = stream_getf (s);
+    if (i < bwclassnum)
+      zlog_err ("%s: received %d > %d (MAX_CLASS_TYPE) bw entries"
+                " - outdated library?",
+                __func__, bwclassnum, MAX_CLASS_TYPE);
+  }
+  iflp->admin_grp = stream_getl (s);
+  iflp->rmt_as = stream_getl (s);
+  iflp->rmt_ip.s_addr = stream_get_ipv4 (s);
+  
+  iflp->av_delay = stream_getl (s);
+  iflp->min_delay = stream_getl (s);
+  iflp->max_delay = stream_getl (s);
+  iflp->delay_var = stream_getl (s);
+  
+  iflp->pkt_loss = stream_getf (s);
+  iflp->res_bw = stream_getf (s);
+  iflp->ava_bw = stream_getf (s);
+  iflp->use_bw = stream_getf (s);
+}
+
+struct interface *
+zebra_interface_link_params_read (struct stream *s)
+{
+  struct if_link_params *iflp;
+  uint32_t ifindex = stream_getl (s);
+
+  struct interface *ifp = if_lookup_by_index (ifindex);
+
+  if (ifp == NULL || s == NULL)
+    {
+      zlog_err ("%s: unknown ifindex %u, shouldn't happen",
+                __func__, ifindex);
+      return NULL;
+    }
+
+  if ((iflp = if_link_params_get (ifp)) == NULL)
+    return NULL;
+
+  link_params_set_value(s, iflp);
+  
+  return ifp;
+}
+
+void
+zebra_interface_if_set_value (struct stream *s, struct interface *ifp)
+{
+  u_char link_params_status = 0;
+
+  /* Read interface's index. */
+  ifp->ifindex = stream_getl (s);
+  ifp->status = stream_getc (s);
+
+  /* Read interface's value. */
+  ifp->flags = stream_getq (s);
+  ifp->metric = stream_getl (s);
+  ifp->mtu = stream_getl (s);
+  ifp->mtu6 = stream_getl (s);
+  ifp->bandwidth = stream_getl (s);
+  ifp->ll_type = stream_getl (s);
+  ifp->hw_addr_len = stream_getl (s);
+  if (ifp->hw_addr_len)
+    stream_get (ifp->hw_addr, s, MIN(ifp->hw_addr_len, INTERFACE_HWADDR_MAX));
+
+  /* Read Traffic Engineering status */
+  link_params_status = stream_getc (s);
+  /* Then, Traffic Engineering parameters if any */
+  if (link_params_status)
+    {
+      struct if_link_params *iflp = if_link_params_get (ifp);
+      link_params_set_value(s, iflp);
+    }
+}
+
+size_t
+zebra_interface_link_params_write (struct stream *s, struct interface *ifp)
+{
+  size_t w;
+  struct if_link_params *iflp;
+  
+  if (s == NULL || ifp == NULL || ifp->link_params == NULL)
+    return 0;
+  
+  iflp = ifp->link_params;
+  w = 0;
+    
+  w += stream_putl (s, iflp->lp_status);
+
+  w += stream_putl (s, iflp->te_metric);
+  w += stream_putf (s, iflp->max_bw);
+  w += stream_putf (s, iflp->max_rsv_bw);
+  
+  w += stream_putl (s, MAX_CLASS_TYPE);
+  for (int i = 0; i < MAX_CLASS_TYPE; i++)
+    w += stream_putf (s, iflp->unrsv_bw[i]);
+  
+  w += stream_putl (s, iflp->admin_grp);
+  w += stream_putl (s, iflp->rmt_as);
+  w += stream_put_in_addr (s, &iflp->rmt_ip);
+  
+  w += stream_putl (s, iflp->av_delay);
+  w += stream_putl (s, iflp->min_delay);
+  w += stream_putl (s, iflp->max_delay);
+  w += stream_putl (s, iflp->delay_var);
+  
+  w += stream_putf (s, iflp->pkt_loss);
+  w += stream_putf (s, iflp->res_bw);
+  w += stream_putf (s, iflp->ava_bw);
+  w += stream_putf (s, iflp->use_bw);
+  
+  return w;
+}
+
+/*
  * format of message for address additon is:
  *    0
  *  0 1 2 3 4 5 6 7
@@ -811,28 +949,8 @@
  * :               :
  * |               |
  * +-+-+-+-+-+-+-+-+
- *
  */
 
-void
-zebra_interface_if_set_value (struct stream *s, struct interface *ifp)
-{
-  /* Read interface's index. */
-  ifp->ifindex = stream_getl (s);
-  ifp->status = stream_getc (s);
-
-  /* Read interface's value. */
-  ifp->flags = stream_getq (s);
-  ifp->metric = stream_getl (s);
-  ifp->mtu = stream_getl (s);
-  ifp->mtu6 = stream_getl (s);
-  ifp->bandwidth = stream_getl (s);
-  ifp->ll_type = stream_getl (s);
-  ifp->hw_addr_len = stream_getl (s);
-  if (ifp->hw_addr_len)
-    stream_get (ifp->hw_addr, s, MIN(ifp->hw_addr_len, INTERFACE_HWADDR_MAX));
-}
-
 static int
 memconstant(const void *s, int c, size_t n)
 {
@@ -1059,6 +1177,10 @@
       if (zclient->ipv6_route_delete)
 	(*zclient->ipv6_route_delete) (command, zclient, length, vrf_id);
       break;
+    case ZEBRA_INTERFACE_LINK_PARAMS:
+      if (zclient->interface_link_params)
+        (*zclient->interface_link_params) (command, zclient, length);
+      break;
     default:
       break;
     }
diff --git a/lib/zclient.h b/lib/zclient.h
index d069eb2..1513492 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -85,6 +85,7 @@
   int (*interface_down) (int, struct zclient *, uint16_t, vrf_id_t);
   int (*interface_address_add) (int, struct zclient *, uint16_t, vrf_id_t);
   int (*interface_address_delete) (int, struct zclient *, uint16_t, vrf_id_t);
+  int (*interface_link_params) (int, struct zclient *, uint16_t);
   int (*ipv4_route_add) (int, struct zclient *, uint16_t, vrf_id_t);
   int (*ipv4_route_delete) (int, struct zclient *, uint16_t, vrf_id_t);
   int (*ipv6_route_add) (int, struct zclient *, uint16_t, vrf_id_t);
@@ -184,6 +185,9 @@
 extern int zapi_ipv4_route (u_char, struct zclient *, struct prefix_ipv4 *, 
                             struct zapi_ipv4 *);
 
+extern struct interface *zebra_interface_link_params_read (struct stream *);
+extern size_t zebra_interface_link_params_write (struct stream *,
+                                                 struct interface *);
 #ifdef HAVE_IPV6
 /* IPv6 prefix add and delete function prototype. */
 
diff --git a/lib/zebra.h b/lib/zebra.h
index 7c4adf1..cb83a11 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -425,7 +425,8 @@
 #define ZEBRA_HELLO                       23
 #define ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB    24
 #define ZEBRA_VRF_UNREGISTER              25
-#define ZEBRA_MESSAGE_MAX                 26
+#define ZEBRA_INTERFACE_LINK_PARAMS       26
+#define ZEBRA_MESSAGE_MAX                 27
 
 /* Marker value used in new Zserv, in the byte location corresponding
  * the command value in the old zserv header. To allow old and new