lib: add AF_ETHERNET/AFI_ETHER
diff --git a/lib/prefix.c b/lib/prefix.c
index aeb627b..43fc317 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -194,8 +194,9 @@
     return AF_INET;
   else if (!strcmp("ipv6", string))
     return AF_INET6;
-  else
-    return -1;
+  else if (!strcmp("ethernet", string))
+    return AF_ETHERNET;
+  return -1;
 }
 
 /* Address Famiy Identifier to Address Family converter. */
@@ -208,6 +209,8 @@
   else if (afi == AFI_IP6)
     return AF_INET6;
 #endif /* HAVE_IPV6 */
+  else if (afi == AFI_ETHER)
+    return AF_ETHERNET;
   return 0;
 }
 
@@ -220,10 +223,26 @@
   else if (family == AF_INET6)
     return AFI_IP6;
 #endif /* HAVE_IPV6 */
+  else if (family == AF_ETHERNET)
+    return AFI_ETHER;
   return 0;
 }
 
 const char *
+afi2str(afi_t afi)
+{
+  switch (afi) {
+    case AFI_IP:
+	return "IPv4";
+    case AFI_IP6:
+	return "IPv6";
+    case AFI_ETHER:
+	return "ethernet";
+  }
+  return NULL;
+}
+
+const char *
 safi2str(safi_t safi)
 {
   switch (safi) {
@@ -286,6 +305,10 @@
       dest->u.lp.id = src->u.lp.id;
       dest->u.lp.adv_router = src->u.lp.adv_router;
     }
+  else if (src->family == AF_ETHERNET)
+    {
+      dest->u.prefix_eth = src->u.prefix_eth;
+    }
   else
     {
       zlog (NULL, LOG_ERR, "prefix_copy(): Unknown address family %d",
@@ -315,6 +338,10 @@
 	if (IPV6_ADDR_SAME (&p1->u.prefix6.s6_addr, &p2->u.prefix6.s6_addr))
 	  return 1;
 #endif /* HAVE_IPV6 */
+      if (p1->family == AF_ETHERNET) {
+	if (!memcmp(p1->u.prefix_eth.octet, p2->u.prefix_eth.octet, ETHER_ADDR_LEN))
+	    return 1;
+      }
     }
   return 0;
 }
@@ -406,6 +433,8 @@
   if (p->family == AF_INET6)
     return "inet6";
 #endif /* HAVE_IPV6 */
+  if (p->family == AF_ETHERNET)
+    return "ether";
   return "unspec";
 }
 
@@ -476,6 +505,60 @@
   return ret;
 }
 
+/* When string format is invalid return 0. */
+int
+str2prefix_eth (const char *str, struct prefix_eth *p)
+{
+  int		ret = 0;
+  int		plen = 48;
+  char		*pnt;
+  char		*cp = NULL;
+  const char	*str_addr = str;
+  unsigned int	a[6];
+  int		i;
+
+  /* Find slash inside string. */
+  pnt = strchr (str, '/');
+
+  if (pnt)
+    {
+      /* Get prefix length. */
+      plen = (u_char) atoi (++pnt);
+      if (plen > 48)
+	{
+	  ret = 0;
+	  goto done;
+	}
+
+      cp = XMALLOC (MTYPE_TMP, (pnt - str) + 1);
+      strncpy (cp, str, pnt - str);
+      *(cp + (pnt - str)) = '\0';
+
+      str_addr = cp;
+    }
+
+  /* Convert string to prefix. */
+  if (sscanf(str_addr, "%2x:%2x:%2x:%2x:%2x:%2x",
+    a+0, a+1, a+2, a+3, a+4, a+5) != 6)
+    {
+      ret = 0;
+      goto done;
+    }
+  for (i = 0; i < 6; ++i)
+    {
+      p->eth_addr.octet[i] = a[i] & 0xff;
+    }
+  p->prefixlen = plen;
+  p->family = AF_ETHERNET;
+  ret = 1;
+
+done:
+  if (cp)
+    XFREE (MTYPE_TMP, cp);
+
+  return ret;
+}
+
 /* Convert masklen into IP address's netmask (network byte order). */
 void
 masklen2ip (const int masklen, struct in_addr *netmask)
@@ -762,6 +845,8 @@
       return IPV6_MAX_BYTELEN;
       break;
 #endif /* HAVE_IPV6 */
+    case AF_ETHERNET:
+      return ETHER_ADDR_LEN;
     }
   return 0;
 }
@@ -784,6 +869,11 @@
     return ret;
 #endif /* HAVE_IPV6 */
 
+  /* Next we try to convert string to struct prefix_eth. */
+  ret = str2prefix_eth (str, (struct prefix_eth *) p);
+  if (ret)
+    return ret;
+
   return 0;
 }
 
@@ -793,6 +883,24 @@
   const struct prefix *p = pu.p;
   char buf[BUFSIZ];
 
+  if (p->family == AF_ETHERNET) {
+    int		i;
+    char	*s = str;
+
+    assert(size > (3*ETHER_ADDR_LEN) + 1 /* slash */ + 3 /* plen */ );
+    for (i = 0; i < ETHER_ADDR_LEN; ++i) {
+	sprintf(s, "%02x", p->u.prefix_eth.octet[i]);
+	if (i < (ETHER_ADDR_LEN - 1)) {
+	    *(s+2) = ':';
+	    s += 3;
+	} else {
+	    s += 2;
+	}
+    }
+    sprintf(s, "/%d", p->prefixlen);
+    return 0;
+  }
+
   inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ);
   snprintf (str, size, "%s/%d", buf, p->prefixlen);
   return str;