---
 lib/plist.c  |   5 +++
 lib/prefix.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 lib/prefix.h |  43 +++++++++++++++++++++++
 lib/zebra.h  |   3 +-
 4 files changed, 160 insertions(+), 3 deletions(-)

diff --git a/lib/plist.c b/lib/plist.c
index 699c9b1..9c6707c 100644
--- a/lib/plist.c
+++ b/lib/plist.c
@@ -734,6 +734,11 @@ vty_prefix_list_install (struct vty *vty, afi_t afi, const 
char *name,
          return CMD_WARNING;
        }
       break;
+    case AFI_ETHER:
+    default:
+      vty_out (vty, "%% Unrecognized AFI (%d)%s", afi, VTY_NEWLINE);
+      return CMD_WARNING;
+      break;
     }
 
   /* ge and le check. */
diff --git a/lib/prefix.c b/lib/prefix.c
index 3e4ca16..c760807 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -194,8 +194,9 @@ str2family(const char *string)
     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 @@ afi2family (afi_t afi)
   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 @@ family2afi (int family)
   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 @@ prefix_copy (struct prefix *dest, const struct prefix *src)
       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 @@ prefix_same (const struct prefix *p1, const struct prefix 
*p2)
        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 @@ prefix_family_str (const struct prefix *p)
   if (p->family == AF_INET6)
     return "inet6";
 #endif /* HAVE_IPV6 */
+  if (p->family == AF_ETHERNET)
+    return "ether";
   return "unspec";
 }
 
@@ -476,6 +505,60 @@ str2prefix_ipv4 (const char *str, struct prefix_ipv4 *p)
   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 @@ prefix_blen (const struct prefix *p)
       return IPV6_MAX_BYTELEN;
       break;
 #endif /* HAVE_IPV6 */
+    case AF_ETHERNET:
+      return ETHER_ADDR_LEN;
     }
   return 0;
 }
@@ -784,6 +869,11 @@ str2prefix (const char *str, struct prefix *p)
     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 @@ prefix2str (union prefix46constptr pu, char *str, int size)
   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;
diff --git a/lib/prefix.h b/lib/prefix.h
index 4a31750..2cf0b20 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -23,8 +23,30 @@
 #ifndef _ZEBRA_PREFIX_H
 #define _ZEBRA_PREFIX_H
 
+#ifdef SUNOS_5
+# include <sys/ethernet.h>
+#else
+# ifdef GNU_LINUX
+#  include <net/ethernet.h>
+# else
+#  include <netinet/if_ether.h>
+# endif
+#endif
 #include "sockunion.h"
 
+#ifndef ETHER_ADDR_LEN
+#define ETHER_ADDR_LEN  ETHERADDRL
+#endif
+
+/*
+ * there isn't a portable ethernet address type. We define our
+ * own to simplify internal handling
+ */
+struct ethaddr {
+    u_char octet[ETHER_ADDR_LEN];
+} __packed;
+
+
 /*
  * A struct prefix contains an address family, a prefix length, and an
  * address.  This can represent either a 'network prefix' as defined
@@ -34,6 +56,15 @@
  * interface.
  */
 
+/* different OSes use different names */
+#if defined(AF_PACKET)
+#define AF_ETHERNET AF_PACKET
+#else
+#if defined(AF_LINK)
+#define AF_ETHERNET AF_LINK
+#endif
+#endif
+
 /* IPv4 and IPv6 unified prefix structure. */
 struct prefix
 {
@@ -51,6 +82,7 @@ struct prefix
       struct in_addr id;
       struct in_addr adv_router;
     } lp;
+    struct ethaddr prefix_eth; /* AF_ETHERNET */
     u_char val[8];
     uintptr_t ptr;
   } u __attribute__ ((aligned (8)));
@@ -90,6 +122,14 @@ struct prefix_rd
   u_char val[8] __attribute__ ((aligned (8)));
 };
 
+/* Prefix for ethernet. */
+struct prefix_eth
+{
+  u_char family;
+  u_char prefixlen;
+  struct ethaddr eth_addr __attribute__ ((aligned (8))); /* AF_ETHERNET */
+};
+
 /* Prefix for a generic pointer */
 struct prefix_ptr
 {
@@ -174,6 +214,7 @@ extern int str2family(const char *);
 extern int afi2family (afi_t);
 extern afi_t family2afi (int);
 extern const char *safi2str(safi_t safi);
+extern const char *afi2str(afi_t afi);
 
 /* Check bit of the prefix. */
 extern unsigned int prefix_bit (const u_char *prefix, const u_char prefixlen);
@@ -197,6 +238,8 @@ extern struct prefix *sockunion2prefix (const union 
sockunion *dest,
 extern struct prefix *sockunion2hostprefix (const union sockunion *, struct 
prefix *p);
 extern void prefix2sockunion (const struct prefix *, union sockunion *);
 
+extern int str2prefix_eth (const char *, struct prefix_eth *);
+
 extern struct prefix_ipv4 *prefix_ipv4_new (void);
 extern void prefix_ipv4_free (struct prefix_ipv4 *);
 extern int str2prefix_ipv4 (const char *, struct prefix_ipv4 *);
diff --git a/lib/zebra.h b/lib/zebra.h
index d980283..428917a 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -482,7 +482,8 @@ extern const char *zserv_command_string (unsigned int 
command);
 typedef enum {
   AFI_IP  = 1,
   AFI_IP6 = 2,
-#define AFI_MAX 3
+  AFI_ETHER = 3,                /* RFC 1700 has "6" for 802.* */
+#define AFI_MAX 4
 } afi_t;
 
 /* Subsequent Address Family Identifier. */
-- 
2.1.3


_______________________________________________
Quagga-dev mailing list
[email protected]
https://lists.quagga.net/mailman/listinfo/quagga-dev

Reply via email to