src/node/ipv6-address.cc
author vincent@clarinet.u-strasbg.fr
Fri Nov 07 11:36:15 2008 -0800 (2008-11-07)
changeset 3852 9cf7ad0cac85
child 4311 abf229efd655
permissions -rw-r--r--
Initial IPv6 capability
     1 /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
     2 /*
     3  * Copyright (c) 2007-2008 Louis Pasteur University
     4  *
     5  * This program is free software; you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License version 2 as
     7  * published by the Free Software Foundation;
     8  *
     9  * This program is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    13  *
    14  * You should have received a copy of the GNU General Public License
    15  * along with this program; if not, write to the Free Software
    16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    17  *
    18  * Author: Sebastien Vincent <vincent@clarinet.u-strasbg.fr>
    19  */
    20 
    21 #include <string.h>
    22 
    23 #include "ns3/log.h"
    24 #include "ipv6-address.h"
    25 #include "ns3/assert.h"
    26 #include "mac48-address.h"
    27 
    28 #include <iomanip>
    29 
    30 NS_LOG_COMPONENT_DEFINE ("Ipv6Address");
    31 
    32 namespace ns3 {
    33 
    34 #ifdef __cplusplus
    35 extern "C"
    36 {
    37 #endif
    38 
    39   /**
    40    * \brief Get a hash key.
    41    * \param k the key
    42    * \param length the length of the key
    43    * \param level the previous hash, or an arbitrary value
    44    * \return hash
    45    * \note Adpated from Jens Jakobsen implementation (chillispot).
    46    */
    47   static uint32_t lookuphash (unsigned char* k, uint32_t length, uint32_t level)
    48   {
    49 #define mix(a,b,c) \
    50     { \
    51       a -= b; a -= c; a ^= (c>>13); \
    52       b -= c; b -= a; b ^= (a<<8); \
    53       c -= a; c -= b; c ^= (b>>13); \
    54       a -= b; a -= c; a ^= (c>>12);  \
    55       b -= c; b -= a; b ^= (a<<16); \
    56       c -= a; c -= b; c ^= (b>>5); \
    57       a -= b; a -= c; a ^= (c>>3);  \
    58       b -= c; b -= a; b ^= (a<<10); \
    59       c -= a; c -= b; c ^= (b>>15); \
    60     }
    61 
    62     typedef uint32_t  ub4;   /* unsigned 4-byte quantities */
    63     typedef unsigned  char ub1;   /* unsigned 1-byte quantities */
    64     uint32_t a,b,c,len;
    65 
    66     /* Set up the internal state */
    67     len = length;
    68     a = b = 0x9e3779b9;  /* the golden ratio; an arbitrary value */
    69     c = level;           /* the previous hash value */
    70 
    71     /*---------------------------------------- handle most of the key */
    72     while (len >= 12)
    73     {
    74       a += (k[0] +((ub4)k[1]<<8) +((ub4)k[2]<<16) +((ub4)k[3]<<24));
    75       b += (k[4] +((ub4)k[5]<<8) +((ub4)k[6]<<16) +((ub4)k[7]<<24));
    76       c += (k[8] +((ub4)k[9]<<8) +((ub4)k[10]<<16)+((ub4)k[11]<<24));
    77       mix(a,b,c);
    78       k += 12; len -= 12;
    79     }
    80 
    81     /*------------------------------------- handle the last 11 bytes */
    82     c += length;
    83     switch(len)              /* all the case statements fall through */
    84     {
    85       case 11: c+=((ub4)k[10]<<24);
    86       case 10: c+=((ub4)k[9]<<16);
    87       case 9 : c+=((ub4)k[8]<<8);
    88                /* the first byte of c is reserved for the length */
    89       case 8 : b+=((ub4)k[7]<<24);
    90       case 7 : b+=((ub4)k[6]<<16);
    91       case 6 : b+=((ub4)k[5]<<8);
    92       case 5 : b+=k[4];
    93       case 4 : a+=((ub4)k[3]<<24);
    94       case 3 : a+=((ub4)k[2]<<16);
    95       case 2 : a+=((ub4)k[1]<<8);
    96       case 1 : a+=k[0];
    97                /* case 0: nothing left to add */
    98     }
    99     mix(a,b,c);
   100     /*-------------------------------------------- report the result */
   101     return c;
   102   }
   103 #ifdef __cplusplus
   104 }
   105 #endif
   106 
   107 /**
   108  * \brief Convert an IPv6 C-string into a 128-bit representation.
   109  * \return 1 if OK, 0 if failure (bad format, ...)
   110  * \note This function is strongly inspired by inet_pton6() from Paul Vixie.
   111  * \todo Handle IPv6 address with decimal value for last four bytes.
   112  */
   113 static int AsciiToIpv6Host (char const *address, uint8_t addr[16])
   114 {
   115   static const char xdigits_l[] = "0123456789abcdef",
   116                xdigits_u[] = "0123456789ABCDEF";
   117   unsigned char tmp[16 /*NS_IN6ADDRSZ*/], *tp, *endp, *colonp;
   118   const char *xdigits, *curtok;
   119   int ch, seen_xdigits;
   120   unsigned int val;
   121 
   122   memset((tp = tmp), '\0', 16 /* NS_IN6ADDRSZ*/);
   123   endp = tp + 16 /*NS_IN6ADDRSZ*/;
   124   colonp = NULL;
   125   /* Leading :: requires some special handling. */
   126   if (*address == ':')
   127     if (*++address != ':')
   128       return (0);
   129   curtok = address;
   130   seen_xdigits = 0;
   131   val = 0;
   132   while ((ch = *address++) != '\0')
   133   {
   134     const char *pch;
   135 
   136     if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
   137       pch = strchr((xdigits = xdigits_u), ch);
   138     if (pch != NULL)
   139     {
   140       val <<= 4;
   141       val |= (pch - xdigits);
   142       if (++seen_xdigits > 4)
   143         return (0);
   144       continue;
   145     }
   146     if (ch == ':')
   147     {
   148       curtok = address;
   149       if (!seen_xdigits)
   150       {
   151         if (colonp)
   152           return (0);
   153         colonp = tp;
   154         continue;
   155       }
   156       if (tp + 2 /*NS_INT16SZ*/ > endp)
   157         return (0);
   158       *tp++ = (unsigned char) (val >> 8) & 0xff;
   159       *tp++ = (unsigned char) val & 0xff;
   160       seen_xdigits = 0;
   161       val = 0;
   162       continue;
   163     }
   164 
   165     /* TODO Handle address like 2001::xxx.xxx.xxx.xxxx */
   166 #if 0
   167     if (ch == '.' && ((tp + 4 /*NS_INADDRSZ*/) <= endp) &&
   168         inet_pton4(curtok, tp) > 0)
   169     {
   170       tp += 4 /*NS_INADDRSZ*/;
   171       seen_xdigits = 0;
   172       break;/* '\0' was seen by inet_pton4(). */
   173     }
   174 #endif
   175     return (0);
   176   }
   177   if (seen_xdigits)
   178   {
   179     if (tp + 2/* NS_INT16SZ*/ > endp)
   180       return (0);
   181     *tp++ = (unsigned char) (val >> 8) & 0xff;
   182     *tp++ = (unsigned char) val & 0xff;
   183   }
   184   if (colonp != NULL)
   185   {
   186     /*
   187      * Since some memmove()'s erroneously fail to handle
   188      * overlapping regions, we'll do the shift by hand.
   189      */
   190     const int n = tp - colonp;
   191     int i;
   192 
   193     if (tp == endp)
   194       return (0);
   195     for (i = 1; i <= n; i++)
   196     {
   197       endp[- i] = colonp[n - i];
   198       colonp[n - i] = 0;
   199     }
   200     tp = endp;
   201   }
   202   if (tp != endp)
   203     return (0);
   204 
   205   /* memcpy(dst, tmp, NS_IN6ADDRSZ);  */
   206   memcpy(addr, tmp, 16);
   207   return (1);
   208 }
   209 
   210 Ipv6Address::Ipv6Address ()
   211 {
   212   memset(m_address, 0x00, 16);
   213 }
   214 
   215 Ipv6Address::Ipv6Address (Ipv6Address const& addr)
   216 {
   217   memcpy(m_address, addr.m_address, 16);
   218 }
   219 
   220 Ipv6Address::Ipv6Address (Ipv6Address const* addr)
   221 {
   222   memcpy(m_address, addr->m_address, 16);
   223 }
   224 
   225 Ipv6Address::Ipv6Address (char const* address)
   226 {
   227   AsciiToIpv6Host (address, m_address);
   228 }
   229 
   230 Ipv6Address::Ipv6Address (uint8_t address[16])
   231 {
   232   /* 128 bit => 16 bytes */
   233   memcpy(m_address, address, 16);
   234 }
   235 
   236 Ipv6Address::~Ipv6Address ()
   237 {
   238   /* do nothing */
   239 }
   240 
   241 void Ipv6Address::Set (char const* address)
   242 {
   243   AsciiToIpv6Host (address, m_address);
   244 }
   245 
   246 void Ipv6Address::Set (uint8_t address[16])
   247 {
   248   /* 128 bit => 16 bytes */
   249   memcpy(m_address, address, 16);
   250 }
   251 
   252 void Ipv6Address::Serialize (uint8_t buf[16]) const
   253 {
   254   memcpy(buf, m_address, 16);
   255 }
   256 
   257 Ipv6Address Ipv6Address::Deserialize (const uint8_t buf[16])
   258 {
   259   Ipv6Address ipv6((uint8_t*)buf);
   260   return ipv6;
   261 }
   262 
   263 Ipv6Address Ipv6Address::MakeAutoconfiguredAddress (Mac48Address addr, Ipv6Address prefix)
   264 {
   265   Ipv6Address ret;
   266   uint8_t buf[16];
   267   uint8_t buf2[16];
   268 
   269   addr.CopyTo(buf);
   270   prefix.GetBytes(buf2);
   271 
   272   memcpy(buf2 + 8, buf, 3);
   273   buf2[11] = 0xff;
   274   buf2[12] = 0xfe;
   275   memcpy(buf2 + 13, buf + 3, 3);
   276   buf2[8] |= 0x02;
   277 
   278   ret.Set(buf2);
   279   return ret;
   280 }
   281 
   282 Ipv6Address Ipv6Address::MakeAutoconfiguredLinkLocalAddress (Mac48Address addr)
   283 {
   284   Ipv6Address ret;
   285   uint8_t buf[16];
   286   uint8_t buf2[16];
   287 
   288   addr.CopyTo(buf);
   289 
   290   memset(buf2, 0x00, sizeof(buf2));
   291   buf2[0] = 0xfe;
   292   buf2[1] = 0x80;
   293   memcpy(buf2 + 8, buf, 3);
   294   buf2[11] = 0xff;
   295   buf2[12] = 0xfe;
   296   memcpy(buf2 + 13, buf + 3, 3);
   297   buf2[8] |= 0x02;
   298 
   299   ret.Set(buf2);
   300   return ret;
   301 }
   302 
   303 Ipv6Address Ipv6Address::MakeSolicitedAddress (Ipv6Address addr)
   304 {
   305   uint8_t buf[16];
   306   uint8_t buf2[16];
   307   Ipv6Address ret;
   308 
   309   addr.Serialize(buf2);
   310 
   311   memset(buf, 0x00, sizeof(buf));
   312   buf[0] = 0xff;
   313   buf[1] = 0x02;
   314   buf[11] = 0x01;
   315   buf[12] = 0xff;
   316   buf[13] = buf2[13];
   317   buf[14] = buf2[14];
   318   buf[15] = buf2[15];
   319 
   320   ret.Set(buf);
   321   return ret;
   322 }
   323 
   324 void Ipv6Address::Print (std::ostream& os) const
   325 {
   326   os << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_address[0]
   327     << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_address[1] << ":"
   328     << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_address[2] 
   329     << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_address[3] << ":"
   330     << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_address[4]
   331     << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_address[5] << ":"
   332     << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_address[6]
   333     << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_address[7] << ":"
   334     << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_address[8]
   335     << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_address[9] << ":"
   336     << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_address[10]
   337     << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_address[11] << ":"
   338     << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_address[12]
   339     << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_address[13] << ":"
   340     << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_address[14]
   341     << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_address[15];
   342 }
   343 
   344 bool Ipv6Address::IsLocalhost () const
   345 {
   346   static Ipv6Address localhost("::1");
   347   return (*this == localhost);
   348 }
   349 
   350 bool Ipv6Address::IsMulticast () const
   351 {
   352   if(m_address[0] == 0xff)
   353   {
   354     return true;
   355   }
   356   return false;
   357 }
   358 
   359 Ipv6Address Ipv6Address::CombinePrefix (Ipv6Prefix const & prefix)
   360 {
   361   Ipv6Address ipv6;
   362   uint8_t addr[16];
   363   uint8_t pref[16];
   364   unsigned int i = 0;
   365 
   366   memcpy(addr, m_address, 16);
   367   ((Ipv6Prefix)prefix).GetBytes(pref);
   368 
   369   /* a little bit ugly... */
   370   for(i = 0 ; i < 16 ; i++)
   371   {
   372     addr[i] = addr[i] & pref[i];
   373   }
   374   ipv6.Set(addr);
   375   return ipv6;
   376 }
   377 
   378 bool Ipv6Address::IsSolicitedMulticast () const
   379 {
   380   uint8_t buf[16];
   381 
   382   Serialize(buf);
   383 
   384   if(buf[0] == 0xff && 
   385       buf[1] == 0x02 &&
   386       buf[11] == 0x01 &&
   387       buf[12] == 0xff)
   388   {
   389     return true;
   390   }
   391   return false;
   392 }
   393 
   394 bool Ipv6Address::IsAllNodesMulticast () const
   395 {
   396   static Ipv6Address allnodes("ff02::1");
   397   return (*this == allnodes);
   398 }
   399 
   400 bool Ipv6Address::IsAllRoutersMulticast () const
   401 {
   402   static Ipv6Address allrouters("ff02::2");
   403   return (*this == allrouters);
   404 }
   405 
   406 bool Ipv6Address::IsAllHostsMulticast () const
   407 {
   408   static Ipv6Address allhosts("ff02::3");
   409   return (*this == allhosts);
   410 }
   411 
   412 bool Ipv6Address::IsAny () const
   413 {
   414   static Ipv6Address any("::");
   415   return (*this == any);
   416 }
   417 
   418 bool Ipv6Address::IsMatchingType (const Address& address)
   419 {
   420   return address.CheckCompatible(GetType(), 16);
   421 }
   422 
   423 Ipv6Address::operator Address () const
   424 {
   425   return ConvertTo ();
   426 }
   427 
   428 Address Ipv6Address::ConvertTo (void) const
   429 {
   430   uint8_t buf[16];
   431   Serialize (buf);
   432   return Address(GetType(), buf, 16);
   433 }
   434 
   435 Ipv6Address Ipv6Address::ConvertFrom (const Address &address)
   436 {
   437   NS_ASSERT (address.CheckCompatible (GetType (), 16));
   438   uint8_t buf[16];
   439   address.CopyTo (buf);
   440   return Deserialize (buf);
   441 }
   442 
   443 uint8_t Ipv6Address::GetType (void)
   444 {
   445   static uint8_t type = Address::Register();
   446   return type;
   447 }
   448 
   449 Ipv6Address Ipv6Address::GetZero ()
   450 {
   451   Ipv6Address zero("::");
   452   return zero;
   453 }
   454 
   455 Ipv6Address Ipv6Address::GetAny ()
   456 {
   457   Ipv6Address any("::");
   458   return any;
   459 }
   460 
   461 Ipv6Address Ipv6Address::GetAllNodesMulticast ()
   462 {
   463   Ipv6Address nmc("ff02::1");
   464   return nmc;
   465 }
   466 
   467 Ipv6Address Ipv6Address::GetAllRoutersMulticast ()
   468 {
   469   Ipv6Address rmc("ff02::2");
   470   return rmc;
   471 }
   472 
   473 Ipv6Address Ipv6Address::GetAllHostsMulticast ()
   474 {
   475   Ipv6Address hmc("ff02::3");
   476   return hmc;
   477 }
   478 
   479 Ipv6Address Ipv6Address::GetLoopback ()
   480 {
   481   static Ipv6Address loopback("::1");
   482   return loopback;
   483 }
   484 
   485 void Ipv6Address::GetBytes (uint8_t buf[16]) const
   486 {
   487   memcpy(buf, m_address, 16);
   488 }
   489 
   490 bool Ipv6Address::IsLinkLocal () const
   491 {
   492   Ipv6Address linkLocal("fe80::0");
   493   if(!IsMulticast() && ((Ipv6Address*)this)->CombinePrefix(Ipv6Prefix(64))==linkLocal)
   494   {
   495     return true;
   496   }
   497   return false;
   498 }
   499 
   500 bool Ipv6Address::IsEqual (const Ipv6Address& other) const
   501 {
   502   if(!memcmp(m_address, other.m_address, 16))
   503   {
   504     return true;
   505   }
   506   return false;
   507 }
   508 
   509 std::ostream& operator << (std::ostream& os, Ipv6Address const& address)
   510 {
   511   address.Print(os);
   512   return os;
   513 }
   514 
   515 std::istream& operator >> (std::istream& is, Ipv6Address& address)
   516 {
   517   std::string str;
   518   is >> str;
   519   address = Ipv6Address (str.c_str ());
   520   return is;
   521 }
   522 
   523 Ipv6Prefix::Ipv6Prefix ()
   524 {
   525   memset(m_prefix, 0x00, 16);
   526 }
   527 
   528 Ipv6Prefix::Ipv6Prefix (char const* prefix)
   529 {
   530   AsciiToIpv6Host(prefix, m_prefix);
   531 }
   532 
   533 Ipv6Prefix::Ipv6Prefix (uint8_t prefix[16])
   534 {
   535   memcpy(m_prefix, prefix, 16);
   536 }
   537 
   538 Ipv6Prefix::Ipv6Prefix (uint8_t prefix)
   539 {
   540   unsigned int nb=0;
   541   unsigned int mod=0;
   542   unsigned int i=0;
   543 
   544   memset(m_prefix, 0x00, 16);
   545 
   546   NS_ASSERT(prefix <= 128);
   547 
   548   nb = prefix / 8;
   549   mod = prefix % 8;
   550 
   551   memset(m_prefix, 0xff, nb);
   552 
   553   if(mod)
   554   {
   555     m_prefix[nb] = 0xff << (8-mod);
   556   }
   557 
   558   if(nb < 16)
   559   {
   560     nb++;
   561     for(i = nb; i < 16 ; i++)
   562     {
   563       m_prefix[i] = 0x00;
   564     }
   565   }
   566 }
   567 
   568 Ipv6Prefix::Ipv6Prefix (Ipv6Prefix const& prefix)
   569 {
   570   memcpy(m_prefix, prefix.m_prefix, 16);
   571 }
   572 
   573 Ipv6Prefix::Ipv6Prefix (Ipv6Prefix const* prefix)
   574 {
   575   memcpy(m_prefix, prefix->m_prefix, 16);
   576 }
   577 
   578 Ipv6Prefix::~Ipv6Prefix ()
   579 {
   580   /* do nothing */
   581 }
   582 
   583 bool Ipv6Prefix::IsMatch (Ipv6Address a, Ipv6Address b) const
   584 {
   585   uint8_t addrA[16];
   586   uint8_t addrB[16];
   587   unsigned int i = 0;
   588 
   589   a.GetBytes(addrA);
   590   b.GetBytes(addrB);
   591 
   592   /* a little bit ugly... */
   593   for(i = 0 ; i < 16 ; i++)
   594   {
   595     if((addrA[i] & m_prefix[i]) !=	(addrB[i] & m_prefix[i]))
   596     {
   597       return false;
   598     }
   599   }
   600   return true;
   601 }
   602 
   603 void Ipv6Prefix::Print (std::ostream &os) const
   604 {
   605   os << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_prefix[0]
   606     << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_prefix[1] << ":"
   607     << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_prefix[2]
   608     << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_prefix[3] << ":"
   609     << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_prefix[4]
   610     << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_prefix[5] << ":"
   611     << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_prefix[6]
   612     << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_prefix[7] << ":"
   613     << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_prefix[8]
   614     << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_prefix[9] << ":"
   615     << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_prefix[10]
   616     << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_prefix[11] << ":"
   617     << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_prefix[12]
   618     << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_prefix[13] << ":"
   619     << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_prefix[14]
   620     << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_prefix[15];
   621 }
   622 
   623 Ipv6Prefix Ipv6Prefix::GetLoopback ()
   624 {
   625   Ipv6Prefix prefix((uint8_t)128);
   626   return prefix;
   627 }
   628 
   629 Ipv6Prefix Ipv6Prefix::GetZero ()
   630 {
   631   Ipv6Prefix prefix((uint8_t)0);
   632   return prefix;
   633 }
   634 
   635 void Ipv6Prefix::GetBytes (uint8_t buf[16]) const
   636 {
   637   memcpy(buf, m_prefix, 16);
   638 }
   639 
   640 bool Ipv6Prefix::IsEqual (const Ipv6Prefix& other) const
   641 {
   642   if(!memcmp(m_prefix, other.m_prefix, 16))
   643   {
   644     return true;
   645   }
   646   return false;
   647 }
   648 
   649 std::ostream& operator<< (std::ostream& os, Ipv6Prefix const& prefix)
   650 {
   651   prefix.Print (os);
   652   return os;
   653 }
   654 
   655 std::istream& operator >> (std::istream& is, Ipv6Prefix& prefix)
   656 {
   657   std::string str;
   658   is >> str;
   659   prefix = Ipv6Prefix (str.c_str ());
   660   return is;
   661 }
   662 
   663 bool operator == (Ipv6Prefix const &a, Ipv6Prefix const &b)
   664 {
   665   return a.IsEqual (b);
   666 }
   667 
   668 bool operator != (Ipv6Prefix const &a, Ipv6Prefix const &b)
   669 {
   670   return !a.IsEqual (b);
   671 }
   672 
   673 size_t Ipv6AddressHash::operator() (Ipv6Address const &x) const
   674 {
   675   uint8_t buf[16];
   676 
   677   x.GetBytes(buf);
   678 
   679   return lookuphash(buf, sizeof(buf), 0);
   680 }
   681 
   682 ATTRIBUTE_HELPER_CPP (Ipv6Address);
   683 ATTRIBUTE_HELPER_CPP (Ipv6Prefix);
   684 
   685 } /* namespace ns3 */
   686