mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-11-04 13:43:22 +00:00 
			
		
		
		
	This is a rather large mechanical commit that splits up the memory types defined in lib/memtypes.c and distributes them into *_memory.[ch] files in the individual daemons. The zebra change is slightly annoying because there is no nice place to put the #include "zebra_memory.h" statement. bgpd, ospf6d, isisd and some tests were reusing MTYPEs defined in the library for its own use. This is bad practice and would break when the memtype are made static. Acked-by: Vincent JARDIN <vincent.jardin@6wind.com> Acked-by: Donald Sharp <sharpd@cumulusnetworks.com> [CF: rebased for cmaster-next] Signed-off-by: David Lamparter <equinox@opensourcerouting.org> Signed-off-by: Christian Franke <chris@opensourcerouting.org>
		
			
				
	
	
		
			474 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			474 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * Interface looking up by ioctl ().
 | 
						|
 * Copyright (C) 1997, 98 Kunihiro Ishiguro
 | 
						|
 *
 | 
						|
 * 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 "if.h"
 | 
						|
#include "sockunion.h"
 | 
						|
#include "prefix.h"
 | 
						|
#include "ioctl.h"
 | 
						|
#include "connected.h"
 | 
						|
#include "memory.h"
 | 
						|
#include "zebra_memory.h"
 | 
						|
#include "log.h"
 | 
						|
#include "vrf.h"
 | 
						|
 | 
						|
#include "zebra/interface.h"
 | 
						|
#include "zebra/rib.h"
 | 
						|
 | 
						|
/* Interface looking up using infamous SIOCGIFCONF. */
 | 
						|
static int
 | 
						|
interface_list_ioctl (void)
 | 
						|
{
 | 
						|
  int ret;
 | 
						|
  int sock;
 | 
						|
#define IFNUM_BASE 32
 | 
						|
  int ifnum;
 | 
						|
  struct ifreq *ifreq;
 | 
						|
  struct ifconf ifconf;
 | 
						|
  struct interface *ifp;
 | 
						|
  int n;
 | 
						|
  int lastlen;
 | 
						|
 | 
						|
  /* Normally SIOCGIFCONF works with AF_INET socket. */
 | 
						|
  sock = socket (AF_INET, SOCK_DGRAM, 0);
 | 
						|
  if (sock < 0) 
 | 
						|
    {
 | 
						|
      zlog_warn ("Can't make AF_INET socket stream: %s", safe_strerror (errno));
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Set initial ifreq count.  This will be double when SIOCGIFCONF
 | 
						|
     fail.  Solaris has SIOCGIFNUM. */
 | 
						|
#ifdef SIOCGIFNUM
 | 
						|
  ret = ioctl (sock, SIOCGIFNUM, &ifnum);
 | 
						|
  if (ret < 0)
 | 
						|
    ifnum = IFNUM_BASE;
 | 
						|
  else
 | 
						|
    ifnum++;
 | 
						|
#else
 | 
						|
  ifnum = IFNUM_BASE;
 | 
						|
#endif /* SIOCGIFNUM */
 | 
						|
 | 
						|
  ifconf.ifc_buf = NULL;
 | 
						|
 | 
						|
  lastlen = 0;
 | 
						|
  /* Loop until SIOCGIFCONF success. */
 | 
						|
  for (;;) 
 | 
						|
    {
 | 
						|
      ifconf.ifc_len = sizeof (struct ifreq) * ifnum;
 | 
						|
      ifconf.ifc_buf = XREALLOC(MTYPE_TMP, ifconf.ifc_buf, ifconf.ifc_len);
 | 
						|
 | 
						|
      ret = ioctl(sock, SIOCGIFCONF, &ifconf);
 | 
						|
 | 
						|
      if (ret < 0) 
 | 
						|
	{
 | 
						|
	  zlog_warn ("SIOCGIFCONF: %s", safe_strerror(errno));
 | 
						|
	  goto end;
 | 
						|
	}
 | 
						|
      /* Repeatedly get info til buffer fails to grow. */
 | 
						|
      if (ifconf.ifc_len > lastlen)
 | 
						|
	{
 | 
						|
          lastlen = ifconf.ifc_len;
 | 
						|
	  ifnum += 10;
 | 
						|
	  continue;
 | 
						|
	}
 | 
						|
      /* Success. */
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Allocate interface. */
 | 
						|
  ifreq = ifconf.ifc_req;
 | 
						|
 | 
						|
#ifdef OPEN_BSD
 | 
						|
  for (n = 0; n < ifconf.ifc_len; )
 | 
						|
    {
 | 
						|
      int size;
 | 
						|
 | 
						|
      ifreq = (struct ifreq *)((caddr_t) ifconf.ifc_req + n);
 | 
						|
      ifp = if_get_by_name_len(ifreq->ifr_name,
 | 
						|
			       strnlen(ifreq->ifr_name,
 | 
						|
				       sizeof(ifreq->ifr_name)));
 | 
						|
      if_add_update (ifp);
 | 
						|
      size = ifreq->ifr_addr.sa_len;
 | 
						|
      if (size < sizeof (ifreq->ifr_addr))
 | 
						|
	size = sizeof (ifreq->ifr_addr);
 | 
						|
      size += sizeof (ifreq->ifr_name);
 | 
						|
      n += size;
 | 
						|
    }
 | 
						|
#else
 | 
						|
  for (n = 0; n < ifconf.ifc_len; n += sizeof(struct ifreq))
 | 
						|
    {
 | 
						|
      ifp = if_get_by_name_len(ifreq->ifr_name,
 | 
						|
			       strnlen(ifreq->ifr_name,
 | 
						|
				       sizeof(ifreq->ifr_name)));
 | 
						|
      if_add_update (ifp);
 | 
						|
      ifreq++;
 | 
						|
    }
 | 
						|
#endif /* OPEN_BSD */
 | 
						|
 | 
						|
 end:
 | 
						|
  close (sock);
 | 
						|
  XFREE (MTYPE_TMP, ifconf.ifc_buf);
 | 
						|
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
/* Get interface's index by ioctl. */
 | 
						|
static int
 | 
						|
if_get_index (struct interface *ifp)
 | 
						|
{
 | 
						|
#if defined(HAVE_IF_NAMETOINDEX)
 | 
						|
  /* Modern systems should have if_nametoindex(3). */
 | 
						|
  ifp->ifindex = if_nametoindex(ifp->name);
 | 
						|
#elif defined(SIOCGIFINDEX) && !defined(HAVE_BROKEN_ALIASES)
 | 
						|
  /* Fall-back for older linuxes. */
 | 
						|
  int ret;
 | 
						|
  struct ifreq ifreq;
 | 
						|
  static int if_fake_index;
 | 
						|
 | 
						|
  ifreq_set_name (&ifreq, ifp);
 | 
						|
 | 
						|
  ret = if_ioctl (SIOCGIFINDEX, (caddr_t) &ifreq);
 | 
						|
  if (ret < 0)
 | 
						|
    {
 | 
						|
      /* Linux 2.0.X does not have interface index. */
 | 
						|
      ifp->ifindex = if_fake_index++;
 | 
						|
      return ifp->ifindex;
 | 
						|
    }
 | 
						|
 | 
						|
  /* OK we got interface index. */
 | 
						|
#ifdef ifr_ifindex
 | 
						|
  ifp->ifindex = ifreq.ifr_ifindex;
 | 
						|
#else
 | 
						|
  ifp->ifindex = ifreq.ifr_index;
 | 
						|
#endif
 | 
						|
 | 
						|
#else
 | 
						|
/* Linux 2.2.X does not provide individual interface index 
 | 
						|
   for aliases and we know it. For others issue a warning. */
 | 
						|
#if !defined(HAVE_BROKEN_ALIASES)
 | 
						|
#warning "Using if_fake_index. You may want to add appropriate"
 | 
						|
#warning "mapping from ifname to ifindex for your system..."
 | 
						|
#endif
 | 
						|
  /* This branch probably won't provide usable results, but anyway... */
 | 
						|
  static int if_fake_index = 1;
 | 
						|
  ifp->ifindex = if_fake_index++;
 | 
						|
#endif
 | 
						|
 | 
						|
  return ifp->ifindex;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef SIOCGIFHWADDR
 | 
						|
static int
 | 
						|
if_get_hwaddr (struct interface *ifp)
 | 
						|
{
 | 
						|
  int ret;
 | 
						|
  struct ifreq ifreq;
 | 
						|
  int i;
 | 
						|
 | 
						|
  strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ);
 | 
						|
  ifreq.ifr_addr.sa_family = AF_INET;
 | 
						|
 | 
						|
  /* Fetch Hardware address if available. */
 | 
						|
  ret = if_ioctl (SIOCGIFHWADDR, (caddr_t) &ifreq);
 | 
						|
  if (ret < 0)
 | 
						|
    ifp->hw_addr_len = 0;
 | 
						|
  else
 | 
						|
    {
 | 
						|
      memcpy (ifp->hw_addr, ifreq.ifr_hwaddr.sa_data, 6);
 | 
						|
 | 
						|
      for (i = 0; i < 6; i++)
 | 
						|
	if (ifp->hw_addr[i] != 0)
 | 
						|
	  break;
 | 
						|
 | 
						|
      if (i == 6)
 | 
						|
	ifp->hw_addr_len = 0;
 | 
						|
      else
 | 
						|
	ifp->hw_addr_len = 6;
 | 
						|
    }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
#endif /* SIOCGIFHWADDR */
 | 
						|
 | 
						|
#ifdef HAVE_GETIFADDRS
 | 
						|
#include <ifaddrs.h>
 | 
						|
 | 
						|
static int
 | 
						|
if_getaddrs (void)
 | 
						|
{
 | 
						|
  int ret;
 | 
						|
  struct ifaddrs *ifap;
 | 
						|
  struct ifaddrs *ifapfree;
 | 
						|
  struct interface *ifp;
 | 
						|
  int prefixlen;
 | 
						|
 | 
						|
  ret = getifaddrs (&ifap); 
 | 
						|
  if (ret != 0)
 | 
						|
    {
 | 
						|
      zlog_err ("getifaddrs(): %s", safe_strerror (errno));
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
 | 
						|
  for (ifapfree = ifap; ifap; ifap = ifap->ifa_next)
 | 
						|
    {
 | 
						|
      if (ifap->ifa_addr == NULL)
 | 
						|
        {
 | 
						|
          zlog_err ("%s: nonsensical ifaddr with NULL ifa_addr, ifname %s",
 | 
						|
                    __func__, (ifap->ifa_name ? ifap->ifa_name : "(null)"));
 | 
						|
          continue;
 | 
						|
        }
 | 
						|
       
 | 
						|
      ifp = if_lookup_by_name (ifap->ifa_name);
 | 
						|
      if (ifp == NULL)
 | 
						|
	{
 | 
						|
	  zlog_err ("if_getaddrs(): Can't lookup interface %s\n",
 | 
						|
		    ifap->ifa_name);
 | 
						|
	  continue;
 | 
						|
	}
 | 
						|
 | 
						|
      if (ifap->ifa_addr->sa_family == AF_INET)
 | 
						|
	{
 | 
						|
	  struct sockaddr_in *addr;
 | 
						|
	  struct sockaddr_in *mask;
 | 
						|
	  struct sockaddr_in *dest;
 | 
						|
	  struct in_addr *dest_pnt;
 | 
						|
	  int flags = 0;
 | 
						|
 | 
						|
	  addr = (struct sockaddr_in *) ifap->ifa_addr;
 | 
						|
	  mask = (struct sockaddr_in *) ifap->ifa_netmask;
 | 
						|
	  prefixlen = ip_masklen (mask->sin_addr);
 | 
						|
 | 
						|
	  dest_pnt = NULL;
 | 
						|
 | 
						|
	  if (ifap->ifa_dstaddr &&
 | 
						|
	      !IPV4_ADDR_SAME(&addr->sin_addr,
 | 
						|
			      &((struct sockaddr_in *)
 | 
						|
			      	ifap->ifa_dstaddr)->sin_addr))
 | 
						|
	    {
 | 
						|
	      dest = (struct sockaddr_in *) ifap->ifa_dstaddr;
 | 
						|
	      dest_pnt = &dest->sin_addr;
 | 
						|
	      flags = ZEBRA_IFA_PEER;
 | 
						|
	    }
 | 
						|
	  else if (ifap->ifa_broadaddr &&
 | 
						|
		   !IPV4_ADDR_SAME(&addr->sin_addr,
 | 
						|
				   &((struct sockaddr_in *)
 | 
						|
				     ifap->ifa_broadaddr)->sin_addr))
 | 
						|
	    {
 | 
						|
	      dest = (struct sockaddr_in *) ifap->ifa_broadaddr;
 | 
						|
	      dest_pnt = &dest->sin_addr;
 | 
						|
	    }
 | 
						|
 | 
						|
	  connected_add_ipv4 (ifp, flags, &addr->sin_addr,
 | 
						|
			      prefixlen, dest_pnt, NULL);
 | 
						|
	}
 | 
						|
#ifdef HAVE_IPV6
 | 
						|
      if (ifap->ifa_addr->sa_family == AF_INET6)
 | 
						|
	{
 | 
						|
	  struct sockaddr_in6 *addr;
 | 
						|
	  struct sockaddr_in6 *mask;
 | 
						|
	  struct sockaddr_in6 *dest;
 | 
						|
	  struct in6_addr *dest_pnt;
 | 
						|
	  int flags = 0;
 | 
						|
 | 
						|
	  addr = (struct sockaddr_in6 *) ifap->ifa_addr;
 | 
						|
	  mask = (struct sockaddr_in6 *) ifap->ifa_netmask;
 | 
						|
	  prefixlen = ip6_masklen (mask->sin6_addr);
 | 
						|
 | 
						|
	  dest_pnt = NULL;
 | 
						|
 | 
						|
	  if (ifap->ifa_dstaddr &&
 | 
						|
	      !IPV6_ADDR_SAME(&addr->sin6_addr,
 | 
						|
			      &((struct sockaddr_in6 *)
 | 
						|
			      	ifap->ifa_dstaddr)->sin6_addr))
 | 
						|
	    {
 | 
						|
	      dest = (struct sockaddr_in6 *) ifap->ifa_dstaddr;
 | 
						|
	      dest_pnt = &dest->sin6_addr;
 | 
						|
	      flags = ZEBRA_IFA_PEER;
 | 
						|
	    }
 | 
						|
	  else if (ifap->ifa_broadaddr &&
 | 
						|
		   !IPV6_ADDR_SAME(&addr->sin6_addr,
 | 
						|
				   &((struct sockaddr_in6 *)
 | 
						|
				     ifap->ifa_broadaddr)->sin6_addr))
 | 
						|
	    {
 | 
						|
	      dest = (struct sockaddr_in6 *) ifap->ifa_broadaddr;
 | 
						|
	      dest_pnt = &dest->sin6_addr;
 | 
						|
	    }
 | 
						|
 | 
						|
#if defined(KAME)
 | 
						|
	  if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) 
 | 
						|
	    {
 | 
						|
	      addr->sin6_scope_id =
 | 
						|
			ntohs(*(u_int16_t *)&addr->sin6_addr.s6_addr[2]);
 | 
						|
	      addr->sin6_addr.s6_addr[2] = addr->sin6_addr.s6_addr[3] = 0;
 | 
						|
	    }	
 | 
						|
#endif          
 | 
						|
 | 
						|
	  connected_add_ipv6 (ifp, flags, &addr->sin6_addr, prefixlen, 
 | 
						|
	                      dest_pnt, NULL);
 | 
						|
	}
 | 
						|
#endif /* HAVE_IPV6 */
 | 
						|
    }
 | 
						|
 | 
						|
  freeifaddrs (ifapfree);
 | 
						|
 | 
						|
  return 0; 
 | 
						|
}
 | 
						|
#else /* HAVE_GETIFADDRS */
 | 
						|
/* Interface address lookup by ioctl.  This function only looks up
 | 
						|
   IPv4 address. */
 | 
						|
int
 | 
						|
if_get_addr (struct interface *ifp)
 | 
						|
{
 | 
						|
  int ret;
 | 
						|
  struct ifreq ifreq;
 | 
						|
  struct sockaddr_in addr;
 | 
						|
  struct sockaddr_in mask;
 | 
						|
  struct sockaddr_in dest;
 | 
						|
  struct in_addr *dest_pnt;
 | 
						|
  u_char prefixlen;
 | 
						|
  int flags = 0;
 | 
						|
 | 
						|
  /* Interface's name and address family. */
 | 
						|
  strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ);
 | 
						|
  ifreq.ifr_addr.sa_family = AF_INET;
 | 
						|
 | 
						|
  /* Interface's address. */
 | 
						|
  ret = if_ioctl (SIOCGIFADDR, (caddr_t) &ifreq);
 | 
						|
  if (ret < 0) 
 | 
						|
    {
 | 
						|
      if (errno != EADDRNOTAVAIL)
 | 
						|
	{
 | 
						|
	  zlog_warn ("SIOCGIFADDR fail: %s", safe_strerror (errno));
 | 
						|
	  return ret;
 | 
						|
	}
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
  memcpy (&addr, &ifreq.ifr_addr, sizeof (struct sockaddr_in));
 | 
						|
 | 
						|
  /* Interface's network mask. */
 | 
						|
  ret = if_ioctl (SIOCGIFNETMASK, (caddr_t) &ifreq);
 | 
						|
  if (ret < 0) 
 | 
						|
    {
 | 
						|
      if (errno != EADDRNOTAVAIL) 
 | 
						|
	{
 | 
						|
	  zlog_warn ("SIOCGIFNETMASK fail: %s", safe_strerror (errno));
 | 
						|
	  return ret;
 | 
						|
	}
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
#ifdef ifr_netmask
 | 
						|
  memcpy (&mask, &ifreq.ifr_netmask, sizeof (struct sockaddr_in));
 | 
						|
#else
 | 
						|
  memcpy (&mask, &ifreq.ifr_addr, sizeof (struct sockaddr_in));
 | 
						|
#endif /* ifr_netmask */
 | 
						|
  prefixlen = ip_masklen (mask.sin_addr);
 | 
						|
 | 
						|
  /* Point to point or borad cast address pointer init. */
 | 
						|
  dest_pnt = NULL;
 | 
						|
 | 
						|
  ret = if_ioctl (SIOCGIFDSTADDR, (caddr_t) &ifreq);
 | 
						|
  if (ret < 0) 
 | 
						|
    {
 | 
						|
      if (errno != EADDRNOTAVAIL) 
 | 
						|
	zlog_warn ("SIOCGIFDSTADDR fail: %s", safe_strerror (errno));
 | 
						|
    }
 | 
						|
  else if (!IPV4_ADDR_SAME(&addr.sin_addr, &ifreq.ifr_dstaddr.sin_addr))
 | 
						|
    {
 | 
						|
      memcpy (&dest, &ifreq.ifr_dstaddr, sizeof (struct sockaddr_in));
 | 
						|
      dest_pnt = &dest.sin_addr;
 | 
						|
      flags = ZEBRA_IFA_PEER;
 | 
						|
    }
 | 
						|
  if (!dest_pnt)
 | 
						|
    {
 | 
						|
      ret = if_ioctl (SIOCGIFBRDADDR, (caddr_t) &ifreq);
 | 
						|
      if (ret < 0) 
 | 
						|
	{
 | 
						|
	  if (errno != EADDRNOTAVAIL) 
 | 
						|
	    zlog_warn ("SIOCGIFBRDADDR fail: %s", safe_strerror (errno));
 | 
						|
	}
 | 
						|
      else if (!IPV4_ADDR_SAME(&addr.sin_addr, &ifreq.ifr_broadaddr.sin_addr))
 | 
						|
        {
 | 
						|
	  memcpy (&dest, &ifreq.ifr_broadaddr, sizeof (struct sockaddr_in));
 | 
						|
	  dest_pnt = &dest.sin_addr;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
  /* Set address to the interface. */
 | 
						|
  connected_add_ipv4 (ifp, flags, &addr.sin_addr, prefixlen, dest_pnt, NULL);
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
#endif /* HAVE_GETIFADDRS */
 | 
						|
 | 
						|
/* Fetch interface information via ioctl(). */
 | 
						|
static void
 | 
						|
interface_info_ioctl ()
 | 
						|
{
 | 
						|
  struct listnode *node, *nnode;
 | 
						|
  struct interface *ifp;
 | 
						|
  
 | 
						|
  for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), node, nnode, ifp))
 | 
						|
    {
 | 
						|
      if_get_index (ifp);
 | 
						|
#ifdef SIOCGIFHWADDR
 | 
						|
      if_get_hwaddr (ifp);
 | 
						|
#endif /* SIOCGIFHWADDR */
 | 
						|
      if_get_flags (ifp);
 | 
						|
#ifndef HAVE_GETIFADDRS
 | 
						|
      if_get_addr (ifp);
 | 
						|
#endif /* ! HAVE_GETIFADDRS */
 | 
						|
      if_get_mtu (ifp);
 | 
						|
      if_get_metric (ifp);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/* Lookup all interface information. */
 | 
						|
void
 | 
						|
interface_list (struct zebra_ns *zns)
 | 
						|
{
 | 
						|
 | 
						|
  zlog_info ("interface_list: NS %u", zns->ns_id);
 | 
						|
 | 
						|
  /* Linux can do both proc & ioctl, ioctl is the only way to get
 | 
						|
     interface aliases in 2.2 series kernels. */
 | 
						|
#ifdef HAVE_PROC_NET_DEV
 | 
						|
  interface_list_proc ();
 | 
						|
#endif /* HAVE_PROC_NET_DEV */
 | 
						|
  interface_list_ioctl ();
 | 
						|
 | 
						|
  /* After listing is done, get index, address, flags and other
 | 
						|
     interface's information. */
 | 
						|
  interface_info_ioctl ();
 | 
						|
 | 
						|
#ifdef HAVE_GETIFADDRS
 | 
						|
  if_getaddrs ();
 | 
						|
#endif /* HAVE_GETIFADDRS */
 | 
						|
 | 
						|
#if defined(HAVE_IPV6) && defined(HAVE_PROC_NET_IF_INET6)
 | 
						|
  /* Linux provides interface's IPv6 address via
 | 
						|
     /proc/net/if_inet6. */
 | 
						|
  ifaddr_proc_ipv6 ();
 | 
						|
#endif /* HAVE_IPV6 && HAVE_PROC_NET_IF_INET6 */
 | 
						|
}
 |