--- embedaddon/quagga/lib/if.c	2012/10/09 09:22:28	1.1.1.2
+++ embedaddon/quagga/lib/if.c	2016/11/02 10:09:11	1.1.1.3
@@ -27,6 +27,7 @@
 #include "vector.h"
 #include "vty.h"
 #include "command.h"
+#include "vrf.h"
 #include "if.h"
 #include "sockunion.h"
 #include "prefix.h"
@@ -35,8 +36,8 @@
 #include "buffer.h"
 #include "str.h"
 #include "log.h"
-
-/* Master list of interfaces. */
+
+/* List of interfaces in only the default VRF */
 struct list *iflist;
 
 /* One for each program.  This structure is needed to store hooks. */
@@ -44,8 +45,8 @@ struct if_master
 {
   int (*if_new_hook) (struct interface *);
   int (*if_delete_hook) (struct interface *);
-} if_master;
-
+} if_master = {0,};
+
 /* Compare interface names, returning an integer greater than, equal to, or
  * less than 0, (following the strcmp convention), according to the
  * relationship between ifp1 and ifp2.  Interface names consist of an
@@ -113,9 +114,10 @@ if_cmp_func (struct interface *ifp1, struct interface 
 
 /* Create new interface structure. */
 struct interface *
-if_create (const char *name, int namelen)
+if_create_vrf (const char *name, int namelen, vrf_id_t vrf_id)
 {
   struct interface *ifp;
+  struct list *intf_list = vrf_iflist_get (vrf_id);
 
   ifp = XCALLOC (MTYPE_IF, sizeof (struct interface));
   ifp->ifindex = IFINDEX_INTERNAL;
@@ -124,11 +126,12 @@ if_create (const char *name, int namelen)
   assert (namelen <= INTERFACE_NAMSIZ);	/* Need space for '\0' at end. */
   strncpy (ifp->name, name, namelen);
   ifp->name[namelen] = '\0';
-  if (if_lookup_by_name(ifp->name) == NULL)
-    listnode_add_sort (iflist, ifp);
+  ifp->vrf_id = vrf_id;
+  if (if_lookup_by_name_vrf (ifp->name, vrf_id) == NULL)
+    listnode_add_sort (intf_list, ifp);
   else
     zlog_err("if_create(%s): corruption detected -- interface with this "
-	     "name exists already!", ifp->name);
+             "name exists already in VRF %u!", ifp->name, vrf_id);
   ifp->connected = list_new ();
   ifp->connected->del = (void (*) (void *)) connected_free;
 
@@ -138,6 +141,12 @@ if_create (const char *name, int namelen)
   return ifp;
 }
 
+struct interface *
+if_create (const char *name, int namelen)
+{
+  return if_create_vrf (name, namelen, VRF_DEFAULT);
+}
+
 /* Delete interface structure. */
 void
 if_delete_retain (struct interface *ifp)
@@ -153,7 +162,7 @@ if_delete_retain (struct interface *ifp)
 void
 if_delete (struct interface *ifp)
 {
-  listnode_delete (iflist, ifp);
+  listnode_delete (vrf_iflist (ifp->vrf_id), ifp);
 
   if_delete_retain(ifp);
 
@@ -180,46 +189,64 @@ if_add_hook (int type, int (*func)(struct interface *i
 
 /* Interface existance check by index. */
 struct interface *
-if_lookup_by_index (unsigned int index)
+if_lookup_by_index_vrf (ifindex_t ifindex, vrf_id_t vrf_id)
 {
   struct listnode *node;
   struct interface *ifp;
 
-  for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp))
+  for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp))
     {
-      if (ifp->ifindex == index)
+      if (ifp->ifindex == ifindex)
 	return ifp;
     }
   return NULL;
 }
 
+struct interface *
+if_lookup_by_index (ifindex_t ifindex)
+{
+  return if_lookup_by_index_vrf (ifindex, VRF_DEFAULT);
+}
+
 const char *
-ifindex2ifname (unsigned int index)
+ifindex2ifname_vrf (ifindex_t ifindex, vrf_id_t vrf_id)
 {
   struct interface *ifp;
 
-  return ((ifp = if_lookup_by_index(index)) != NULL) ?
+  return ((ifp = if_lookup_by_index_vrf (ifindex, vrf_id)) != NULL) ?
   	 ifp->name : "unknown";
 }
 
-unsigned int
-ifname2ifindex (const char *name)
+const char *
+ifindex2ifname (ifindex_t ifindex)
 {
+  return ifindex2ifname_vrf (ifindex, VRF_DEFAULT);
+}
+
+ifindex_t
+ifname2ifindex_vrf (const char *name, vrf_id_t vrf_id)
+{
   struct interface *ifp;
 
-  return ((ifp = if_lookup_by_name(name)) != NULL) ? ifp->ifindex
+  return ((ifp = if_lookup_by_name_vrf (name, vrf_id)) != NULL) ? ifp->ifindex
                                                    : IFINDEX_INTERNAL;
 }
 
+ifindex_t
+ifname2ifindex (const char *name)
+{
+  return ifname2ifindex_vrf (name, VRF_DEFAULT);
+}
+
 /* Interface existance check by interface name. */
 struct interface *
-if_lookup_by_name (const char *name)
+if_lookup_by_name_vrf (const char *name, vrf_id_t vrf_id)
 {
   struct listnode *node;
   struct interface *ifp;
   
   if (name)
-    for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
+    for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp))
       {
         if (strcmp(name, ifp->name) == 0)
           return ifp;
@@ -228,15 +255,21 @@ if_lookup_by_name (const char *name)
 }
 
 struct interface *
-if_lookup_by_name_len(const char *name, size_t namelen)
+if_lookup_by_name (const char *name)
 {
+  return if_lookup_by_name_vrf (name, VRF_DEFAULT);
+}
+
+struct interface *
+if_lookup_by_name_len_vrf (const char *name, size_t namelen, vrf_id_t vrf_id)
+{
   struct listnode *node;
   struct interface *ifp;
 
   if (namelen > INTERFACE_NAMSIZ)
     return NULL;
 
-  for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
+  for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp))
     {
       if (!memcmp(name, ifp->name, namelen) && (ifp->name[namelen] == '\0'))
 	return ifp;
@@ -244,9 +277,15 @@ if_lookup_by_name_len(const char *name, size_t namelen
   return NULL;
 }
 
+struct interface *
+if_lookup_by_name_len(const char *name, size_t namelen)
+{
+  return if_lookup_by_name_len_vrf (name, namelen, VRF_DEFAULT);
+}
+
 /* Lookup interface by IPv4 address. */
 struct interface *
-if_lookup_exact_address (struct in_addr src)
+if_lookup_exact_address_vrf (struct in_addr src, vrf_id_t vrf_id)
 {
   struct listnode *node;
   struct listnode *cnode;
@@ -254,7 +293,7 @@ if_lookup_exact_address (struct in_addr src)
   struct prefix *p;
   struct connected *c;
 
-  for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
+  for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp))
     {
       for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c))
 	{
@@ -270,9 +309,15 @@ if_lookup_exact_address (struct in_addr src)
   return NULL;
 }
 
+struct interface *
+if_lookup_exact_address (struct in_addr src)
+{
+  return if_lookup_exact_address_vrf (src, VRF_DEFAULT);
+}
+
 /* Lookup interface by IPv4 address. */
 struct interface *
-if_lookup_address (struct in_addr src)
+if_lookup_address_vrf (struct in_addr src, vrf_id_t vrf_id)
 {
   struct listnode *node;
   struct prefix addr;
@@ -288,7 +333,7 @@ if_lookup_address (struct in_addr src)
 
   match = NULL;
 
-  for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
+  for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp))
     {
       for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c))
 	{
@@ -304,26 +349,72 @@ if_lookup_address (struct in_addr src)
   return match;
 }
 
+struct interface *
+if_lookup_address (struct in_addr src)
+{
+  return if_lookup_address_vrf (src, VRF_DEFAULT);
+}
+
+/* Lookup interface by prefix */
+struct interface *
+if_lookup_prefix_vrf (struct prefix *prefix, vrf_id_t vrf_id)
+{
+  struct listnode *node;
+  struct listnode *cnode;
+  struct interface *ifp;
+  struct connected *c;
+
+  for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp))
+    {
+      for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c))
+        {
+          if (prefix_cmp(c->address, prefix) == 0)
+            {
+              return ifp;
+            }
+        }
+    }
+  return NULL;
+}
+
+struct interface *
+if_lookup_prefix (struct prefix *prefix)
+{
+  return if_lookup_prefix_vrf (prefix, VRF_DEFAULT);
+}
+
 /* Get interface by name if given name interface doesn't exist create
    one. */
 struct interface *
-if_get_by_name (const char *name)
+if_get_by_name_vrf (const char *name, vrf_id_t vrf_id)
 {
   struct interface *ifp;
 
-  return ((ifp = if_lookup_by_name(name)) != NULL) ? ifp :
-	 if_create(name, strlen(name));
+  return ((ifp = if_lookup_by_name_vrf (name, vrf_id)) != NULL) ? ifp :
+         if_create_vrf (name, strlen(name), vrf_id);
 }
 
 struct interface *
-if_get_by_name_len(const char *name, size_t namelen)
+if_get_by_name (const char *name)
 {
+  return if_get_by_name_vrf (name, VRF_DEFAULT);
+}
+
+struct interface *
+if_get_by_name_len_vrf (const char *name, size_t namelen, vrf_id_t vrf_id)
+{
   struct interface *ifp;
 
-  return ((ifp = if_lookup_by_name_len(name, namelen)) != NULL) ? ifp :
-	 if_create(name, namelen);
+  return ((ifp = if_lookup_by_name_len_vrf (name, namelen, vrf_id)) != NULL) ? \
+         ifp : if_create_vrf (name, namelen, vrf_id);
 }
 
+struct interface *
+if_get_by_name_len (const char *name, size_t namelen)
+{
+  return if_get_by_name_len_vrf (name, namelen, VRF_DEFAULT);
+}
+
 /* Does interface up ? */
 int
 if_is_up (struct interface *ifp)
@@ -429,15 +520,15 @@ static void
 if_dump (const struct interface *ifp)
 {
   struct listnode *node;
-  struct connected *c;
+  struct connected *c __attribute__((unused));
 
   for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, c))
-    zlog_info ("Interface %s index %d metric %d mtu %d "
+    zlog_info ("Interface %s vrf %u index %d metric %d mtu %d "
 #ifdef HAVE_IPV6
                "mtu6 %d "
 #endif /* HAVE_IPV6 */
                "%s",
-               ifp->name, ifp->ifindex, ifp->metric, ifp->mtu, 
+               ifp->name, ifp->vrf_id, ifp->ifindex, ifp->metric, ifp->mtu,
 #ifdef HAVE_IPV6
                ifp->mtu6,
 #endif /* HAVE_IPV6 */
@@ -448,11 +539,15 @@ if_dump (const struct interface *ifp)
 void
 if_dump_all (void)
 {
+  struct list *intf_list;
   struct listnode *node;
   void *p;
+  vrf_iter_t iter;
 
-  for (ALL_LIST_ELEMENTS_RO (iflist, node, p))
-    if_dump (p);
+  for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter))
+    if ((intf_list = vrf_iter2iflist (iter)) != NULL)
+      for (ALL_LIST_ELEMENTS_RO (intf_list, node, p))
+        if_dump (p);
 }
 
 DEFUN (interface_desc, 
@@ -489,7 +584,7 @@ DEFUN (no_interface_desc, 
 
   return CMD_SUCCESS;
 }
-
+
 #ifdef SUNOS_5
 /* Need to handle upgrade from SUNWzebra to Quagga. SUNWzebra created
  * a seperate struct interface for each logical interface, so config
@@ -512,12 +607,12 @@ DEFUN (no_interface_desc, 
  *     - no idea, just get the name in its entirety.
  */
 static struct interface *
-if_sunwzebra_get (const char *name, size_t nlen)
+if_sunwzebra_get (const char *name, size_t nlen, vrf_id_t vrf_id)
 {
   struct interface *ifp;
   size_t seppos = 0;
 
-  if ( (ifp = if_lookup_by_name_len(name, nlen)) != NULL)
+  if ( (ifp = if_lookup_by_name_len_vrf (name, nlen, vrf_id)) != NULL)
     return ifp;
   
   /* hunt the primary interface name... */
@@ -526,12 +621,12 @@ if_sunwzebra_get (const char *name, size_t nlen)
   
   /* Wont catch seperator as last char, e.g. 'foo0:' but thats invalid */
   if (seppos < nlen)
-    return if_get_by_name_len (name, seppos);
+    return if_get_by_name_len_vrf (name, seppos, vrf_id);
   else
-    return if_get_by_name_len (name, nlen);
+    return if_get_by_name_len_vrf (name, nlen, vrf_id);
 }
 #endif /* SUNOS_5 */
-
+
 DEFUN (interface,
        interface_cmd,
        "interface IFNAME",
@@ -540,6 +635,7 @@ DEFUN (interface,
 {
   struct interface *ifp;
   size_t sl;
+  vrf_id_t vrf_id = VRF_DEFAULT;
 
   if ((sl = strlen(argv[0])) > INTERFACE_NAMSIZ)
     {
@@ -549,10 +645,13 @@ DEFUN (interface,
       return CMD_WARNING;
     }
 
+  if (argc > 1)
+    VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]);
+
 #ifdef SUNOS_5
-  ifp = if_sunwzebra_get (argv[0], sl);
+  ifp = if_sunwzebra_get (argv[0], sl, vrf_id);
 #else
-  ifp = if_get_by_name_len(argv[0], sl);
+  ifp = if_get_by_name_len_vrf (argv[0], sl, vrf_id);
 #endif /* SUNOS_5 */
 
   vty->index = ifp;
@@ -561,6 +660,13 @@ DEFUN (interface,
   return CMD_SUCCESS;
 }
 
+ALIAS (interface,
+       interface_vrf_cmd,
+       "interface IFNAME " VRF_CMD_STR,
+       "Select an interface to configure\n"
+       "Interface's name\n"
+       VRF_CMD_HELP_STR)
+
 DEFUN_NOSH (no_interface,
            no_interface_cmd,
            "no interface IFNAME",
@@ -570,9 +676,13 @@ DEFUN_NOSH (no_interface,
 {
   // deleting interface
   struct interface *ifp;
+  vrf_id_t vrf_id = VRF_DEFAULT;
 
-  ifp = if_lookup_by_name (argv[0]);
+  if (argc > 1)
+    VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]);
 
+  ifp = if_lookup_by_name_vrf (argv[0], vrf_id);
+
   if (ifp == NULL)
     {
       vty_out (vty, "%% Interface %s does not exist%s", argv[0], VTY_NEWLINE);
@@ -591,6 +701,14 @@ DEFUN_NOSH (no_interface,
   return CMD_SUCCESS;
 }
 
+ALIAS (no_interface,
+       no_interface_vrf_cmd,
+       "no interface IFNAME " VRF_CMD_STR,
+       NO_STR
+       "Delete a pseudo interface's configuration\n"
+       "Interface's name\n"
+       VRF_CMD_HELP_STR)
+
 /* For debug purpose. */
 DEFUN (show_address,
        show_address_cmd,
@@ -603,8 +721,12 @@ DEFUN (show_address,
   struct interface *ifp;
   struct connected *ifc;
   struct prefix *p;
+  vrf_id_t vrf_id = VRF_DEFAULT;
 
-  for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
+  if (argc > 0)
+    VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]);
+
+  for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp))
     {
       for (ALL_LIST_ELEMENTS_RO (ifp->connected, node2, ifc))
 	{
@@ -618,6 +740,52 @@ DEFUN (show_address,
   return CMD_SUCCESS;
 }
 
+ALIAS (show_address,
+       show_address_vrf_cmd,
+       "show address " VRF_CMD_STR,
+       SHOW_STR
+       "address\n"
+       VRF_CMD_HELP_STR)
+
+DEFUN (show_address_vrf_all,
+       show_address_vrf_all_cmd,
+       "show address " VRF_ALL_CMD_STR,
+       SHOW_STR
+       "address\n"
+       VRF_ALL_CMD_HELP_STR)
+{
+  struct list *intf_list;
+  struct listnode *node;
+  struct listnode *node2;
+  struct interface *ifp;
+  struct connected *ifc;
+  struct prefix *p;
+  vrf_iter_t iter;
+
+  for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter))
+    {
+      intf_list = vrf_iter2iflist (iter);
+      if (!intf_list || !listcount (intf_list))
+        continue;
+
+      vty_out (vty, "%sVRF %u%s%s", VTY_NEWLINE, vrf_iter2id (iter),
+               VTY_NEWLINE, VTY_NEWLINE);
+
+      for (ALL_LIST_ELEMENTS_RO (intf_list, node, ifp))
+        {
+          for (ALL_LIST_ELEMENTS_RO (ifp->connected, node2, ifc))
+            {
+              p = ifc->address;
+
+              if (p->family == AF_INET)
+                vty_out (vty, "%s/%d%s", inet_ntoa (p->u.prefix4), p->prefixlen,
+                         VTY_NEWLINE);
+            }
+        }
+    }
+  return CMD_SUCCESS;
+}
+
 /* Allocate connected structure. */
 struct connected *
 connected_new (void)
@@ -653,8 +821,8 @@ connected_log (struct connected *connected, char *str)
   ifp = connected->ifp;
   p = connected->address;
 
-  snprintf (logbuf, BUFSIZ, "%s interface %s %s %s/%d ", 
-	    str, ifp->name, prefix_family_str (p),
+  snprintf (logbuf, BUFSIZ, "%s interface %s vrf %u %s %s/%d ",
+	    str, ifp->name, ifp->vrf_id, prefix_family_str (p),
 	    inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
 	    p->prefixlen);
 
@@ -760,7 +928,7 @@ connected_add_by_prefix (struct interface *ifp, struct
 }
 
 #ifndef HAVE_IF_NAMETOINDEX
-unsigned int
+ifindex_t
 if_nametoindex (const char *name)
 {
   struct interface *ifp;
@@ -772,7 +940,7 @@ if_nametoindex (const char *name)
 
 #ifndef HAVE_IF_INDEXTONAME
 char *
-if_indextoname (unsigned int ifindex, char *name)
+if_indextoname (ifindex_t ifindex, char *name)
 {
   struct interface *ifp;
 
@@ -782,7 +950,7 @@ if_indextoname (unsigned int ifindex, char *name)
   return ifp->name;
 }
 #endif
-
+
 #if 0 /* this route_table of struct connected's is unused
        * however, it would be good to use a route_table rather than
        * a list..
@@ -837,7 +1005,7 @@ ifaddr_ipv4_delete (struct in_addr *ifaddr, struct int
 
 /* Lookup interface by interface's IP address or interface index. */
 static struct interface *
-ifaddr_ipv4_lookup (struct in_addr *addr, unsigned int ifindex)
+ifaddr_ipv4_lookup (struct in_addr *addr, ifindex_t ifindex)
 {
   struct prefix_ipv4 p;
   struct route_node *rn;
@@ -864,35 +1032,96 @@ ifaddr_ipv4_lookup (struct in_addr *addr, unsigned int
 
 /* Initialize interface list. */
 void
-if_init (void)
+if_init (vrf_id_t vrf_id, struct list **intf_list)
 {
-  iflist = list_new ();
+  *intf_list = list_new ();
 #if 0
   ifaddr_ipv4_table = route_table_init ();
 #endif /* ifaddr_ipv4_table */
 
-  if (iflist) {
-    iflist->cmp = (int (*)(void *, void *))if_cmp_func;
-    return;
-  }
+  (*intf_list)->cmp = (int (*)(void *, void *))if_cmp_func;
 
-  memset (&if_master, 0, sizeof if_master);
+  if (vrf_id == VRF_DEFAULT)
+    iflist = *intf_list;
 }
 
 void
-if_terminate (void)
+if_terminate (vrf_id_t vrf_id, struct list **intf_list)
 {
   for (;;)
     {
       struct interface *ifp;
 
-      ifp = listnode_head (iflist);
+      ifp = listnode_head (*intf_list);
       if (ifp == NULL)
 	break;
 
       if_delete (ifp);
     }
 
-  list_delete (iflist);
-  iflist = NULL;
+  list_delete (*intf_list);
+  *intf_list = NULL;
+
+  if (vrf_id == VRF_DEFAULT)
+    iflist = NULL;
+}
+
+const char *
+if_link_type_str (enum zebra_link_type llt)
+{
+  switch (llt)
+    {
+#define llts(T,S) case (T): return (S)
+      llts(ZEBRA_LLT_UNKNOWN,               "Unknown");
+      llts(ZEBRA_LLT_ETHER,                 "Ethernet");
+      llts(ZEBRA_LLT_EETHER,                "Experimental Ethernet");
+      llts(ZEBRA_LLT_AX25,                  "AX.25 Level 2");
+      llts(ZEBRA_LLT_PRONET,                "PROnet token ring");
+      llts(ZEBRA_LLT_IEEE802,               "IEEE 802.2 Ethernet/TR/TB");
+      llts(ZEBRA_LLT_ARCNET,                "ARCnet");
+      llts(ZEBRA_LLT_APPLETLK,              "AppleTalk");
+      llts(ZEBRA_LLT_DLCI,                  "Frame Relay DLCI");
+      llts(ZEBRA_LLT_ATM,                   "ATM");
+      llts(ZEBRA_LLT_METRICOM,              "Metricom STRIP");
+      llts(ZEBRA_LLT_IEEE1394,              "IEEE 1394 IPv4");
+      llts(ZEBRA_LLT_EUI64,                 "EUI-64");
+      llts(ZEBRA_LLT_INFINIBAND,            "InfiniBand");
+      llts(ZEBRA_LLT_SLIP,                  "SLIP");
+      llts(ZEBRA_LLT_CSLIP,                 "Compressed SLIP");
+      llts(ZEBRA_LLT_SLIP6,                 "SLIPv6");
+      llts(ZEBRA_LLT_CSLIP6,                "Compressed SLIPv6");
+      llts(ZEBRA_LLT_ROSE,                  "ROSE packet radio");
+      llts(ZEBRA_LLT_X25,                   "CCITT X.25");
+      llts(ZEBRA_LLT_PPP,                   "PPP");
+      llts(ZEBRA_LLT_CHDLC,                 "Cisco HDLC");
+      llts(ZEBRA_LLT_RAWHDLC,               "Raw HDLC");
+      llts(ZEBRA_LLT_LAPB,                  "LAPB");
+      llts(ZEBRA_LLT_IPIP,                  "IPIP Tunnel");
+      llts(ZEBRA_LLT_IPIP6,                 "IPIP6 Tunnel");
+      llts(ZEBRA_LLT_FRAD,                  "FRAD");
+      llts(ZEBRA_LLT_SKIP,                  "SKIP vif");
+      llts(ZEBRA_LLT_LOOPBACK,              "Loopback");
+      llts(ZEBRA_LLT_LOCALTLK,              "Localtalk");
+      llts(ZEBRA_LLT_FDDI,                  "FDDI");
+      llts(ZEBRA_LLT_SIT,                   "IPv6-in-IPv4 SIT");
+      llts(ZEBRA_LLT_IPDDP,                 "IP-in-DDP tunnel");
+      llts(ZEBRA_LLT_IPGRE,                 "GRE over IP");
+      llts(ZEBRA_LLT_PIMREG,                "PIMSM registration");
+      llts(ZEBRA_LLT_HIPPI,                 "HiPPI");
+      llts(ZEBRA_LLT_IRDA,                  "IrDA");
+      llts(ZEBRA_LLT_FCPP,                  "Fibre-Channel PtP");
+      llts(ZEBRA_LLT_FCAL,                  "Fibre-Channel Arbitrated Loop");
+      llts(ZEBRA_LLT_FCPL,                  "Fibre-Channel Public Loop");
+      llts(ZEBRA_LLT_FCFABRIC,              "Fibre-Channel Fabric");
+      llts(ZEBRA_LLT_IEEE802_TR,            "IEEE 802.2 Token Ring");
+      llts(ZEBRA_LLT_IEEE80211,             "IEEE 802.11");
+      llts(ZEBRA_LLT_IEEE80211_RADIOTAP,    "IEEE 802.11 Radiotap");
+      llts(ZEBRA_LLT_IEEE802154,            "IEEE 802.15.4");
+      llts(ZEBRA_LLT_IEEE802154_PHY,        "IEEE 802.15.4 Phy");
+      default:
+        zlog_warn ("Unknown value %d", llt);
+        return "Unknown type!";
+#undef llts
+    }
+  return NULL;
 }