Split network address types and parsing/formatting functions out of
the monolithic packets.[ch] into a new netaddr.[ch] module:

 - netaddr.h: Ethernet address constants, inline helpers, IPv4/IPv6
   address parsing/formatting declarations, format macros (IP_FMT,
   ETH_ADDR_FMT, etc.), and the ovs_16aligned_in6_addr type.
 - netaddr.c: ~35 address functions moved from packets.c, including
   ip_parse(), ipv6_parse(), ipv6_string_mapped(), eth_addr_from_string(),
   eth_addr_is_reserved(), ip_format_masked(), ipv6_format_addr(),
   and all IPv6 address math (bitand, create_mask, count_cidr_bits, etc.).

packets.h now includes netaddr.h, so all existing consumers see no
change.  packets.[ch] retains packet header structs, protocol
constants, dp_packet manipulation, and tunnel-related functions.

This is a preparatory refactoring for the upcoming library split:
netaddr.[ch] will move into the utilities library while packets.[ch]
stays in the main libopenvswitch, cleanly resolving the logical
isolation concern without inlining address functions into headers.

Signed-off-by: Timothy Redaelli <[email protected]>
---
 lib/automake.mk |   2 +
 lib/netaddr.c   | 667 ++++++++++++++++++++++++++++++++++++++++++++++++
 lib/netaddr.h   | 418 ++++++++++++++++++++++++++++++
 lib/packets.c   | 641 ----------------------------------------------
 lib/packets.h   | 390 +---------------------------
 5 files changed, 1088 insertions(+), 1030 deletions(-)
 create mode 100644 lib/netaddr.c
 create mode 100644 lib/netaddr.h

diff --git a/lib/automake.mk b/lib/automake.mk
index 2dfca79da..7107780f7 100644
--- a/lib/automake.mk
+++ b/lib/automake.mk
@@ -251,6 +251,8 @@ lib_libopenvswitch_la_SOURCES = \
        lib/ovsdb-types.h \
        lib/ox-stat.c \
        lib/ox-stat.h \
+       lib/netaddr.c \
+       lib/netaddr.h \
        lib/packets.c \
        lib/packets.h \
        lib/pcap-file.c \
diff --git a/lib/netaddr.c b/lib/netaddr.c
new file mode 100644
index 000000000..3a554b849
--- /dev/null
+++ b/lib/netaddr.c
@@ -0,0 +1,667 @@
+/*
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include "netaddr.h"
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include "byte-order.h"
+#include "openvswitch/hmap.h"
+#include "openvswitch/dynamic-string.h"
+#include "ovs-thread.h"
+#include "hash.h"
+
+const struct in6_addr in6addr_exact = IN6ADDR_EXACT_INIT;
+const struct in6_addr in6addr_all_hosts = IN6ADDR_ALL_HOSTS_INIT;
+const struct in6_addr in6addr_all_routers = IN6ADDR_ALL_ROUTERS_INIT;
+const struct in6_addr in6addr_v4mapped_any = IN6ADDR_V4MAPPED_ANY_INIT;
+
+uint64_t
+eth_addr_to_uint64(const struct eth_addr ea)
+{
+    return (((uint64_t) ntohs(ea.be16[0]) << 32)
+            | ((uint64_t) ntohs(ea.be16[1]) << 16)
+            | ntohs(ea.be16[2]));
+}
+
+void
+eth_addr_from_uint64(uint64_t x, struct eth_addr *ea)
+{
+    ea->be16[0] = htons(x >> 32);
+    ea->be16[1] = htons((x & 0xFFFF0000) >> 16);
+    ea->be16[2] = htons(x & 0xFFFF);
+}
+
+void
+eth_addr_mark_random(struct eth_addr *ea)
+{
+    ea->ea[0] &= ~1;                /* Unicast. */
+    ea->ea[0] |= 2;                 /* Private. */
+}
+
+/* Returns true if 'ea' is a reserved address, that a bridge must never
+ * forward, false otherwise.
+ *
+ * If you change this function's behavior, please update corresponding
+ * documentation in vswitch.xml at the same time. */
+bool
+eth_addr_is_reserved(const struct eth_addr ea)
+{
+    struct eth_addr_node {
+        struct hmap_node hmap_node;
+        const uint64_t ea64;
+    };
+
+    static struct eth_addr_node nodes[] = {
+        /* STP, IEEE pause frames, and other reserved protocols. */
+        { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000000ULL },
+        { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000001ULL },
+        { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000002ULL },
+        { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000003ULL },
+        { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000004ULL },
+        { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000005ULL },
+        { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000006ULL },
+        { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000007ULL },
+        { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000008ULL },
+        { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000009ULL },
+        { HMAP_NODE_NULL_INITIALIZER, 0x0180c200000aULL },
+        { HMAP_NODE_NULL_INITIALIZER, 0x0180c200000bULL },
+        { HMAP_NODE_NULL_INITIALIZER, 0x0180c200000cULL },
+        { HMAP_NODE_NULL_INITIALIZER, 0x0180c200000dULL },
+        { HMAP_NODE_NULL_INITIALIZER, 0x0180c200000eULL },
+        { HMAP_NODE_NULL_INITIALIZER, 0x0180c200000fULL },
+
+        /* Extreme protocols. */
+        { HMAP_NODE_NULL_INITIALIZER, 0x00e02b000000ULL }, /* EDP. */
+        { HMAP_NODE_NULL_INITIALIZER, 0x00e02b000004ULL }, /* EAPS. */
+        { HMAP_NODE_NULL_INITIALIZER, 0x00e02b000006ULL }, /* EAPS. */
+
+        /* Cisco protocols. */
+        { HMAP_NODE_NULL_INITIALIZER, 0x01000c000000ULL }, /* ISL. */
+        { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccccULL }, /* PAgP, UDLD, CDP,
+                                                            * DTP, VTP. */
+        { HMAP_NODE_NULL_INITIALIZER, 0x01000ccccccdULL }, /* PVST+. */
+        { HMAP_NODE_NULL_INITIALIZER, 0x01000ccdcdcdULL }, /* STP Uplink Fast,
+                                                            * FlexLink. */
+
+        /* Cisco CFM. */
+        { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc0ULL },
+        { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc1ULL },
+        { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc2ULL },
+        { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc3ULL },
+        { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc4ULL },
+        { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc5ULL },
+        { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc6ULL },
+        { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc7ULL },
+    };
+
+    static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
+    struct eth_addr_node *node;
+    static struct hmap addrs;
+    uint64_t ea64;
+
+    if (ovsthread_once_start(&once)) {
+        hmap_init(&addrs);
+        for (node = nodes; node < &nodes[ARRAY_SIZE(nodes)]; node++) {
+            hmap_insert(&addrs, &node->hmap_node, hash_uint64(node->ea64));
+        }
+        ovsthread_once_done(&once);
+    }
+
+    ea64 = eth_addr_to_uint64(ea);
+    HMAP_FOR_EACH_IN_BUCKET (node, hmap_node, hash_uint64(ea64), &addrs) {
+        if (node->ea64 == ea64) {
+            return true;
+        }
+    }
+    return false;
+}
+
+/* Attempts to parse 's' as an Ethernet address.  If successful, stores the
+ * address in 'ea' and returns true, otherwise zeros 'ea' and returns
+ * false.  This function checks trailing characters. */
+bool
+eth_addr_from_string(const char *s, struct eth_addr *ea)
+{
+    int n = 0;
+    if (ovs_scan(s, ETH_ADDR_SCAN_FMT"%n", ETH_ADDR_SCAN_ARGS(*ea), &n)
+        && !s[n]) {
+        return true;
+    } else {
+        *ea = eth_addr_zero;
+        return false;
+    }
+}
+
+void
+eth_format_masked(const struct eth_addr eth,
+                  const struct eth_addr *mask, struct ds *s)
+{
+    ds_put_format(s, ETH_ADDR_FMT, ETH_ADDR_ARGS(eth));
+    if (mask && !eth_mask_is_exact(*mask)) {
+        ds_put_format(s, "/"ETH_ADDR_FMT, ETH_ADDR_ARGS(*mask));
+    }
+}
+
+void
+in6_addr_solicited_node(struct in6_addr *addr, const struct in6_addr *ip6)
+{
+    union ovs_16aligned_in6_addr *taddr =
+        (union ovs_16aligned_in6_addr *) addr;
+    memset(taddr->be16, 0, sizeof(taddr->be16));
+    taddr->be16[0] = htons(0xff02);
+    taddr->be16[5] = htons(0x1);
+    taddr->be16[6] = htons(0xff00);
+    memcpy(&addr->s6_addr[13], &ip6->s6_addr[13], 3);
+}
+
+/*
+ * Generates ipv6 EUI64 address from the given eth addr
+ * and prefix and stores it in 'lla'
+ */
+void
+in6_generate_eui64(struct eth_addr ea, const struct in6_addr *prefix,
+                   struct in6_addr *lla)
+{
+    union ovs_16aligned_in6_addr *taddr =
+        (union ovs_16aligned_in6_addr *) lla;
+    union ovs_16aligned_in6_addr *prefix_taddr =
+        (union ovs_16aligned_in6_addr *) prefix;
+    taddr->be16[0] = prefix_taddr->be16[0];
+    taddr->be16[1] = prefix_taddr->be16[1];
+    taddr->be16[2] = prefix_taddr->be16[2];
+    taddr->be16[3] = prefix_taddr->be16[3];
+    taddr->be16[4] = htons(((ea.ea[0] ^ 0x02) << 8) | ea.ea[1]);
+    taddr->be16[5] = htons(ea.ea[2] << 8 | 0x00ff);
+    taddr->be16[6] = htons(0xfe << 8 | ea.ea[3]);
+    taddr->be16[7] = ea.be16[2];
+}
+
+/* Generates ipv6 link local address from the given eth addr
+ * with prefix 'fe80::/64' and stores it in 'lla'. */
+void
+in6_generate_lla(struct eth_addr ea, struct in6_addr *lla)
+{
+    union ovs_16aligned_in6_addr *taddr =
+        (union ovs_16aligned_in6_addr *) lla;
+    memset(taddr->be16, 0, sizeof(taddr->be16));
+    taddr->be16[0] = htons(0xfe80);
+    taddr->be16[4] = htons(((ea.ea[0] ^ 0x02) << 8) | ea.ea[1]);
+    taddr->be16[5] = htons(ea.ea[2] << 8 | 0x00ff);
+    taddr->be16[6] = htons(0xfe << 8 | ea.ea[3]);
+    taddr->be16[7] = ea.be16[2];
+}
+
+/* Returns true if 'addr' is a link local address.  Otherwise, false. */
+bool
+in6_is_lla(struct in6_addr *addr)
+{
+#ifdef s6_addr32
+    return addr->s6_addr32[0] == htonl(0xfe800000) && !(addr->s6_addr32[1]);
+#else
+    return addr->s6_addr[0] == 0xfe && addr->s6_addr[1] == 0x80 &&
+         !(addr->s6_addr[2] | addr->s6_addr[3] | addr->s6_addr[4] |
+           addr->s6_addr[5] | addr->s6_addr[6] | addr->s6_addr[7]);
+#endif
+}
+
+void
+ipv6_multicast_to_ethernet(struct eth_addr *eth, const struct in6_addr *ip6)
+{
+    eth->ea[0] = 0x33;
+    eth->ea[1] = 0x33;
+    eth->ea[2] = ip6->s6_addr[12];
+    eth->ea[3] = ip6->s6_addr[13];
+    eth->ea[4] = ip6->s6_addr[14];
+    eth->ea[5] = ip6->s6_addr[15];
+}
+
+/* Given the IP netmask 'netmask', returns the number of bits of the IP address
+ * that it specifies, that is, the number of 1-bits in 'netmask'.
+ *
+ * If 'netmask' is not a CIDR netmask (see ip_is_cidr()), the return value will
+ * still be in the valid range but isn't otherwise meaningful. */
+int
+ip_count_cidr_bits(ovs_be32 netmask)
+{
+    return 32 - ctz32(ntohl(netmask));
+}
+
+void
+ip_format_masked(ovs_be32 ip, ovs_be32 mask, struct ds *s)
+{
+    ds_put_format(s, IP_FMT, IP_ARGS(ip));
+    if (mask != OVS_BE32_MAX) {
+        if (ip_is_cidr(mask)) {
+            ds_put_format(s, "/%d", ip_count_cidr_bits(mask));
+        } else {
+            ds_put_format(s, "/"IP_FMT, IP_ARGS(mask));
+        }
+    }
+}
+
+/* Parses string 's', which must be an IP address.  Stores the IP address into
+ * '*ip'.  Returns true if successful, otherwise false. */
+bool
+ip_parse(const char *s, ovs_be32 *ip)
+{
+    return inet_pton(AF_INET, s, ip) == 1;
+}
+
+/* Parses string 's', which must be an IP address with a port number
+ * with ":" as a separator (e.g.: 192.168.1.2:80).
+ * Stores the IP address into '*ip' and port number to '*port'.
+ *
+ * Returns NULL if successful, otherwise an error message that the caller must
+ * free(). */
+char * OVS_WARN_UNUSED_RESULT
+ip_parse_port(const char *s, ovs_be32 *ip, ovs_be16 *port)
+{
+    int n = 0;
+    if (ovs_scan(s, IP_PORT_SCAN_FMT"%n", IP_PORT_SCAN_ARGS(ip, port), &n)
+        && !s[n]) {
+        return NULL;
+    }
+
+    return xasprintf("%s: invalid IP address or port number", s);
+}
+
+/* Parses string 's', which must be an IP address with an optional netmask or
+ * CIDR prefix length.  Stores the IP address into '*ip', netmask into '*mask',
+ * (255.255.255.255, if 's' lacks a netmask), and number of scanned characters
+ * into '*n'.
+ *
+ * Returns NULL if successful, otherwise an error message that the caller must
+ * free(). */
+char * OVS_WARN_UNUSED_RESULT
+ip_parse_masked_len(const char *s, int *n, ovs_be32 *ip,
+                    ovs_be32 *mask)
+{
+    int prefix;
+
+    if (ovs_scan_len(s, n, IP_SCAN_FMT "/" IP_SCAN_FMT,
+                 IP_SCAN_ARGS(ip), IP_SCAN_ARGS(mask))) {
+        /* OK. */
+    } else if (ovs_scan_len(s, n, IP_SCAN_FMT "/%d",
+                            IP_SCAN_ARGS(ip), &prefix)) {
+        if (prefix < 0 || prefix > 32) {
+            return xasprintf("%s: IPv4 network prefix bits not between 0 and "
+                              "32, inclusive", s);
+        }
+        *mask = be32_prefix_mask(prefix);
+    } else if (ovs_scan_len(s, n, IP_SCAN_FMT, IP_SCAN_ARGS(ip))) {
+        *mask = OVS_BE32_MAX;
+    } else {
+        return xasprintf("%s: invalid IP address", s);
+    }
+    return NULL;
+}
+
+/* This function is similar to ip_parse_masked_len(), but doesn't return the
+ * number of scanned characters and expects 's' to end after the ip/(optional)
+ * mask.
+ *
+ * Returns NULL if successful, otherwise an error message that the caller must
+ * free(). */
+char * OVS_WARN_UNUSED_RESULT
+ip_parse_masked(const char *s, ovs_be32 *ip, ovs_be32 *mask)
+{
+    int n = 0;
+
+    char *error = ip_parse_masked_len(s, &n, ip, mask);
+    if (!error && s[n]) {
+        return xasprintf("%s: invalid IP address", s);
+    }
+    return error;
+}
+
+/* Similar to ip_parse_masked_len(), but the mask, if present, must be a CIDR
+ * mask and is returned as a prefix len in '*plen'. */
+char * OVS_WARN_UNUSED_RESULT
+ip_parse_cidr_len(const char *s, int *n, ovs_be32 *ip, unsigned int *plen)
+{
+    ovs_be32 mask;
+    char *error;
+
+    error = ip_parse_masked_len(s, n, ip, &mask);
+    if (error) {
+        return error;
+    }
+
+    if (!ip_is_cidr(mask)) {
+        return xasprintf("%s: CIDR network required", s);
+    }
+    *plen = ip_count_cidr_bits(mask);
+    return NULL;
+}
+
+/* Similar to ip_parse_cidr_len(), but doesn't return the number of scanned
+ * characters and expects 's' to be NULL terminated at the end of the
+ * ip/(optional) cidr. */
+char * OVS_WARN_UNUSED_RESULT
+ip_parse_cidr(const char *s, ovs_be32 *ip, unsigned int *plen)
+{
+    int n = 0;
+
+    char *error = ip_parse_cidr_len(s, &n, ip, plen);
+    if (!error && s[n]) {
+        return xasprintf("%s: invalid IP address", s);
+    }
+    return error;
+}
+
+/* Parses string 's', which must be an IPv6 address.  Stores the IPv6 address
+ * into '*ip'.  Returns true if successful, otherwise false. */
+bool
+ipv6_parse(const char *s, struct in6_addr *ip)
+{
+    return inet_pton(AF_INET6, s, ip) == 1;
+}
+
+/* Parses string 's', which must be an IPv6 address with an optional netmask or
+ * CIDR prefix length.  Stores the IPv6 address into '*ip' and the netmask into
+ * '*mask' (if 's' does not contain a netmask, all-one-bits is assumed), and
+ * number of scanned characters into '*n'.
+ *
+ * Returns NULL if successful, otherwise an error message that the caller must
+ * free(). */
+char * OVS_WARN_UNUSED_RESULT
+ipv6_parse_masked_len(const char *s, int *n, struct in6_addr *ip,
+                      struct in6_addr *mask)
+{
+    char ipv6_s[IPV6_SCAN_LEN + 1];
+    int prefix;
+
+    if (ovs_scan_len(s, n, " "IPV6_SCAN_FMT, ipv6_s)
+        && ipv6_parse(ipv6_s, ip)) {
+        if (ovs_scan_len(s, n, "/%d", &prefix)) {
+            if (prefix < 0 || prefix > 128) {
+                return xasprintf("%s: IPv6 network prefix bits not between 0 "
+                                 "and 128, inclusive", s);
+            }
+            *mask = ipv6_create_mask(prefix);
+        } else if (ovs_scan_len(s, n, "/"IPV6_SCAN_FMT, ipv6_s)) {
+             if (!ipv6_parse(ipv6_s, mask)) {
+                 return xasprintf("%s: Invalid IPv6 mask", s);
+             }
+            /* OK. */
+        } else {
+            /* OK. No mask. */
+            *mask = in6addr_exact;
+        }
+        return NULL;
+    }
+    return xasprintf("%s: invalid IPv6 address", s);
+}
+
+/* This function is similar to ipv6_parse_masked_len(), but doesn't return the
+ * number of scanned characters and expects 's' to end following the
+ * ipv6/(optional) mask. */
+char * OVS_WARN_UNUSED_RESULT
+ipv6_parse_masked(const char *s, struct in6_addr *ip, struct in6_addr *mask)
+{
+    int n = 0;
+
+    char *error = ipv6_parse_masked_len(s, &n, ip, mask);
+    if (!error && s[n]) {
+        return xasprintf("%s: invalid IPv6 address", s);
+    }
+    return error;
+}
+
+/* Similar to ipv6_parse_masked_len(), but the mask, if present, must be a CIDR
+ * mask and is returned as a prefix length in '*plen'. */
+char * OVS_WARN_UNUSED_RESULT
+ipv6_parse_cidr_len(const char *s, int *n, struct in6_addr *ip,
+                    unsigned int *plen)
+{
+    struct in6_addr mask;
+    char *error;
+
+    error = ipv6_parse_masked_len(s, n, ip, &mask);
+    if (error) {
+        return error;
+    }
+
+    if (!ipv6_is_cidr(&mask)) {
+        return xasprintf("%s: IPv6 CIDR network required", s);
+    }
+    *plen = ipv6_count_cidr_bits(&mask);
+    return NULL;
+}
+
+/* Similar to ipv6_parse_cidr_len(), but doesn't return the number of scanned
+ * characters and expects 's' to end after the ipv6/(optional) cidr. */
+char * OVS_WARN_UNUSED_RESULT
+ipv6_parse_cidr(const char *s, struct in6_addr *ip, unsigned int *plen)
+{
+    int n = 0;
+
+    char *error = ipv6_parse_cidr_len(s, &n, ip, plen);
+    if (!error && s[n]) {
+        return xasprintf("%s: invalid IPv6 address", s);
+    }
+    return error;
+}
+
+/* Stores the string representation of the IPv6 address 'addr' into the
+ * character array 'addr_str', which must be at least INET6_ADDRSTRLEN
+ * bytes long. */
+void
+ipv6_format_addr(const struct in6_addr *addr, struct ds *s)
+{
+    char *dst;
+
+    ds_reserve(s, s->length + INET6_ADDRSTRLEN);
+
+    dst = s->string + s->length;
+    inet_ntop(AF_INET6, addr, dst, INET6_ADDRSTRLEN);
+    s->length += strlen(dst);
+}
+
+/* Same as print_ipv6_addr, but optionally encloses the address in square
+ * brackets. */
+void
+ipv6_format_addr_bracket(const struct in6_addr *addr, struct ds *s,
+                         bool bracket)
+{
+    if (bracket) {
+        ds_put_char(s, '[');
+    }
+    ipv6_format_addr(addr, s);
+    if (bracket) {
+        ds_put_char(s, ']');
+    }
+}
+
+void
+ipv6_format_mapped(const struct in6_addr *addr, struct ds *s)
+{
+    if (IN6_IS_ADDR_V4MAPPED(addr)) {
+        ds_put_format(s, IP_FMT, addr->s6_addr[12], addr->s6_addr[13],
+                                 addr->s6_addr[14], addr->s6_addr[15]);
+    } else {
+        ipv6_format_addr(addr, s);
+    }
+}
+
+void
+ipv6_format_masked(const struct in6_addr *addr, const struct in6_addr *mask,
+                   struct ds *s)
+{
+    ipv6_format_addr(addr, s);
+    if (mask && !ipv6_mask_is_exact(mask)) {
+        if (ipv6_is_cidr(mask)) {
+            int cidr_bits = ipv6_count_cidr_bits(mask);
+            ds_put_format(s, "/%d", cidr_bits);
+        } else {
+            ds_put_char(s, '/');
+            ipv6_format_addr(mask, s);
+        }
+    }
+}
+
+/* Stores the string representation of the IPv6 address 'addr' into the
+ * character array 'addr_str', which must be at least INET6_ADDRSTRLEN
+ * bytes long. If addr is IPv4-mapped, store an IPv4 dotted-decimal string. */
+const char *
+ipv6_string_mapped(char *addr_str, const struct in6_addr *addr)
+{
+    ovs_be32 ip;
+    ip = in6_addr_get_mapped_ipv4(addr);
+    if (ip) {
+        return inet_ntop(AF_INET, &ip, addr_str, INET6_ADDRSTRLEN);
+    } else {
+        return inet_ntop(AF_INET6, addr, addr_str, INET6_ADDRSTRLEN);
+    }
+}
+
+#ifdef s6_addr32
+#define s6_addrX s6_addr32
+#define IPV6_FOR_EACH(VAR) for (int VAR = 0; VAR < 4; VAR++)
+#else
+#define s6_addrX s6_addr
+#define IPV6_FOR_EACH(VAR) for (int VAR = 0; VAR < 16; VAR++)
+#endif
+
+struct in6_addr
+ipv6_addr_bitand(const struct in6_addr *a, const struct in6_addr *b)
+{
+   struct in6_addr dst;
+   IPV6_FOR_EACH (i) {
+       dst.s6_addrX[i] = a->s6_addrX[i] & b->s6_addrX[i];
+   }
+   return dst;
+}
+
+struct in6_addr
+ipv6_addr_bitxor(const struct in6_addr *a, const struct in6_addr *b)
+{
+   struct in6_addr dst;
+   IPV6_FOR_EACH (i) {
+       dst.s6_addrX[i] = a->s6_addrX[i] ^ b->s6_addrX[i];
+   }
+   return dst;
+}
+
+bool
+ipv6_is_zero(const struct in6_addr *a)
+{
+   IPV6_FOR_EACH (i) {
+       if (a->s6_addrX[i]) {
+           return false;
+       }
+   }
+   return true;
+}
+
+/* Returns an in6_addr consisting of 'mask' high-order 1-bits and 128-N
+ * low-order 0-bits. */
+struct in6_addr
+ipv6_create_mask(int mask)
+{
+    struct in6_addr netmask;
+    uint8_t *netmaskp = &netmask.s6_addr[0];
+
+    memset(&netmask, 0, sizeof netmask);
+    while (mask > 8) {
+        *netmaskp = 0xff;
+        netmaskp++;
+        mask -= 8;
+    }
+
+    if (mask) {
+        *netmaskp = 0xff << (8 - mask);
+    }
+
+    return netmask;
+}
+
+/* Given the IPv6 netmask 'netmask', returns the number of bits of the IPv6
+ * address that it specifies, that is, the number of 1-bits in 'netmask'.
+ * 'netmask' must be a CIDR netmask (see ipv6_is_cidr()).
+ *
+ * If 'netmask' is not a CIDR netmask (see ipv6_is_cidr()), the return value
+ * will still be in the valid range but isn't otherwise meaningful. */
+int
+ipv6_count_cidr_bits(const struct in6_addr *netmask)
+{
+    int i;
+    int count = 0;
+    const uint8_t *netmaskp = &netmask->s6_addr[0];
+
+    for (i = 0; i < 16; i++) {
+        if (netmaskp[i] == 0xff) {
+            count += 8;
+        } else {
+            uint8_t nm;
+
+            for (nm = netmaskp[i]; nm; nm <<= 1) {
+                count++;
+            }
+            break;
+        }
+
+    }
+
+    return count;
+}
+
+/* Returns true if 'netmask' is a CIDR netmask, that is, if it consists of N
+ * high-order 1-bits and 128-N low-order 0-bits. */
+bool
+ipv6_is_cidr(const struct in6_addr *netmask)
+{
+    const uint8_t *netmaskp = &netmask->s6_addr[0];
+    int i;
+
+    for (i = 0; i < 16; i++) {
+        if (netmaskp[i] != 0xff) {
+            uint8_t x = ~netmaskp[i];
+            if (x & (x + 1)) {
+                return false;
+            }
+            while (++i < 16) {
+                if (netmaskp[i]) {
+                    return false;
+                }
+            }
+        }
+    }
+
+    return true;
+}
+
+bool
+ipv6_addr_equals_masked(const struct in6_addr *a, const struct in6_addr *b,
+                        int plen)
+{
+    struct in6_addr mask;
+    struct in6_addr ma;
+    struct in6_addr mb;
+
+    if (plen == 128) {
+        return ipv6_addr_equals(a, b);
+    }
+
+    mask = ipv6_create_mask(plen);
+    ma = ipv6_addr_bitand(a, &mask);
+    mb = ipv6_addr_bitand(b, &mask);
+
+    return ipv6_addr_equals(&ma, &mb);
+}
diff --git a/lib/netaddr.h b/lib/netaddr.h
new file mode 100644
index 000000000..b2634611e
--- /dev/null
+++ b/lib/netaddr.h
@@ -0,0 +1,418 @@
+/*
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016,
+ * 2017 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef NETADDR_H
+#define NETADDR_H 1
+
+#include <inttypes.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdint.h>
+#include <string.h>
+#include "compiler.h"
+#include "openvswitch/types.h"
+#include "random.h"
+#include "unaligned.h"
+#include "util.h"
+
+struct ds;
+
+/* Ethernet address. */
+
+#define ETH_ADDR_LEN           6
+
+static const struct eth_addr eth_addr_broadcast OVS_UNUSED
+    = ETH_ADDR_C(ff,ff,ff,ff,ff,ff);
+
+static const struct eth_addr eth_addr_exact OVS_UNUSED
+    = ETH_ADDR_C(ff,ff,ff,ff,ff,ff);
+
+static const struct eth_addr eth_addr_zero OVS_UNUSED
+    = ETH_ADDR_C(00,00,00,00,00,00);
+static const struct eth_addr64 eth_addr64_zero OVS_UNUSED
+    = ETH_ADDR64_C(00,00,00,00,00,00,00,00);
+
+static const struct eth_addr eth_addr_stp OVS_UNUSED
+    = ETH_ADDR_C(01,80,c2,00,00,00);
+
+static const struct eth_addr eth_addr_lacp OVS_UNUSED
+    = ETH_ADDR_C(01,80,c2,00,00,02);
+
+static const struct eth_addr eth_addr_bfd OVS_UNUSED
+    = ETH_ADDR_C(00,23,20,00,00,01);
+
+static inline bool eth_addr_is_broadcast(const struct eth_addr a)
+{
+    return (a.be16[0] & a.be16[1] & a.be16[2]) == htons(0xffff);
+}
+
+static inline bool eth_addr_is_multicast(const struct eth_addr a)
+{
+    return a.ea[0] & 1;
+}
+
+static inline bool eth_addr_is_local(const struct eth_addr a)
+{
+    /* Local if it is either a locally administered address or a Nicira random
+     * address. */
+    return a.ea[0] & 2
+        || (a.be16[0] == htons(0x0023)
+            && (a.be16[1] & htons(0xff80)) == htons(0x2080));
+}
+static inline bool eth_addr_is_zero(const struct eth_addr a)
+{
+    return !(a.be16[0] | a.be16[1] | a.be16[2]);
+}
+static inline bool eth_addr64_is_zero(const struct eth_addr64 a)
+{
+    return !(a.be16[0] | a.be16[1] | a.be16[2] | a.be16[3]);
+}
+
+static inline int eth_mask_is_exact(const struct eth_addr a)
+{
+    return (a.be16[0] & a.be16[1] & a.be16[2]) == htons(0xffff);
+}
+
+static inline int eth_addr_compare_3way(const struct eth_addr a,
+                                        const struct eth_addr b)
+{
+    return memcmp(&a, &b, sizeof a);
+}
+static inline int eth_addr64_compare_3way(const struct eth_addr64 a,
+                                          const struct eth_addr64 b)
+{
+    return memcmp(&a, &b, sizeof a);
+}
+
+static inline bool eth_addr_equals(const struct eth_addr a,
+                                   const struct eth_addr b)
+{
+    return !eth_addr_compare_3way(a, b);
+}
+static inline bool eth_addr64_equals(const struct eth_addr64 a,
+                                     const struct eth_addr64 b)
+{
+    return !eth_addr64_compare_3way(a, b);
+}
+
+static inline bool eth_addr_equal_except(const struct eth_addr a,
+                                         const struct eth_addr b,
+                                         const struct eth_addr mask)
+{
+    return !(((a.be16[0] ^ b.be16[0]) & mask.be16[0])
+             || ((a.be16[1] ^ b.be16[1]) & mask.be16[1])
+             || ((a.be16[2] ^ b.be16[2]) & mask.be16[2]));
+}
+
+uint64_t eth_addr_to_uint64(const struct eth_addr ea);
+
+static inline uint64_t eth_addr_vlan_to_uint64(const struct eth_addr ea,
+                                               uint16_t vlan)
+{
+    return (((uint64_t) vlan << 48) | eth_addr_to_uint64(ea));
+}
+
+void eth_addr_from_uint64(uint64_t x, struct eth_addr *ea);
+
+static inline struct eth_addr eth_addr_invert(const struct eth_addr src)
+{
+    struct eth_addr dst;
+
+    for (int i = 0; i < ARRAY_SIZE(src.be16); i++) {
+        dst.be16[i] = ~src.be16[i];
+    }
+
+    return dst;
+}
+
+void eth_addr_mark_random(struct eth_addr *ea);
+
+static inline void eth_addr_random(struct eth_addr *ea)
+{
+    random_bytes((uint8_t *) ea, sizeof *ea);
+    eth_addr_mark_random(ea);
+}
+
+static inline void eth_addr_nicira_random(struct eth_addr *ea)
+{
+    eth_addr_random(ea);
+
+    /* Set the OUI to the Nicira one. */
+    ea->ea[0] = 0x00;
+    ea->ea[1] = 0x23;
+    ea->ea[2] = 0x20;
+
+    /* Set the top bit to indicate random Nicira address. */
+    ea->ea[3] |= 0x80;
+}
+
+bool eth_addr_is_reserved(const struct eth_addr);
+bool eth_addr_from_string(const char *, struct eth_addr *);
+
+void eth_format_masked(const struct eth_addr ea,
+                       const struct eth_addr *mask, struct ds *s);
+
+/* Example:
+ *
+ * struct eth_addr mac;
+ *    [...]
+ * printf("The Ethernet address is "ETH_ADDR_FMT"\n", ETH_ADDR_ARGS(mac));
+ *
+ */
+#define ETH_ADDR_FMT                                                    \
+    "%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8
+#define ETH_ADDR_ARGS(EA) ETH_ADDR_BYTES_ARGS((EA).ea)
+#define ETH_ADDR_BYTES_ARGS(EAB) \
+         (EAB)[0], (EAB)[1], (EAB)[2], (EAB)[3], (EAB)[4], (EAB)[5]
+#define ETH_ADDR_STRLEN 17
+
+/* Example:
+ *
+ * struct eth_addr64 eui64;
+ *    [...]
+ * printf("The EUI-64 address is "ETH_ADDR64_FMT"\n", ETH_ADDR64_ARGS(mac));
+ *
+ */
+#define ETH_ADDR64_FMT \
+    "%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":" \
+    "%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8
+#define ETH_ADDR64_ARGS(EA) ETH_ADDR64_BYTES_ARGS((EA).ea64)
+#define ETH_ADDR64_BYTES_ARGS(EAB) \
+         (EAB)[0], (EAB)[1], (EAB)[2], (EAB)[3], \
+         (EAB)[4], (EAB)[5], (EAB)[6], (EAB)[7]
+#define ETH_ADDR64_STRLEN 23
+
+/* Example:
+ *
+ * char *string = "1 00:11:22:33:44:55 2";
+ * struct eth_addr mac;
+ * int a, b;
+ *
+ * if (ovs_scan(string, "%d"ETH_ADDR_SCAN_FMT"%d",
+ *              &a, ETH_ADDR_SCAN_ARGS(mac), &b)) {
+ *     ...
+ * }
+ */
+#define ETH_ADDR_SCAN_FMT "%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8
+#define ETH_ADDR_SCAN_ARGS(EA) \
+    &(EA).ea[0], &(EA).ea[1], &(EA).ea[2], \
+    &(EA).ea[3], &(EA).ea[4], &(EA).ea[5]
+
+/* IPv4 address. */
+
+#define IP_FMT "%"PRIu32".%"PRIu32".%"PRIu32".%"PRIu32
+#define IP_ARGS(ip)                             \
+    ntohl(ip) >> 24,                            \
+    (ntohl(ip) >> 16) & 0xff,                   \
+    (ntohl(ip) >> 8) & 0xff,                    \
+    ntohl(ip) & 0xff
+
+/* Example:
+ *
+ * char *string = "1 33.44.55.66 2";
+ * ovs_be32 ip;
+ * int a, b;
+ *
+ * if (ovs_scan(string, "%d"IP_SCAN_FMT"%d", &a, IP_SCAN_ARGS(&ip), &b)) {
+ *     ...
+ * }
+ */
+#define IP_SCAN_FMT "%"SCNu8".%"SCNu8".%"SCNu8".%"SCNu8
+#define IP_SCAN_ARGS(ip)                                    \
+        ((void) (ovs_be32) *(ip), &((uint8_t *) ip)[0]),    \
+        &((uint8_t *) ip)[1],                               \
+        &((uint8_t *) ip)[2],                               \
+        &((uint8_t *) ip)[3]
+
+#define IP_PORT_SCAN_FMT "%"SCNu8".%"SCNu8".%"SCNu8".%"SCNu8":%"SCNu16
+#define IP_PORT_SCAN_ARGS(ip, port)                                    \
+        ((void) (ovs_be32) *(ip), &((uint8_t *) ip)[0]),    \
+        &((uint8_t *) ip)[1],                               \
+        &((uint8_t *) ip)[2],                               \
+        &((uint8_t *) ip)[3],                               \
+        ((void) (ovs_be16) *(port), (uint16_t *) port)
+
+/* Returns true if 'netmask' is a CIDR netmask, that is, if it consists of N
+ * high-order 1-bits and 32-N low-order 0-bits. */
+static inline bool
+ip_is_cidr(ovs_be32 netmask)
+{
+    uint32_t x = ~ntohl(netmask);
+    return !(x & (x + 1));
+}
+static inline bool
+ip_is_multicast(ovs_be32 ip)
+{
+    return (ip & htonl(0xf0000000)) == htonl(0xe0000000);
+}
+static inline bool
+ip_is_local_multicast(ovs_be32 ip)
+{
+    return (ip & htonl(0xffffff00)) == htonl(0xe0000000);
+}
+int ip_count_cidr_bits(ovs_be32 netmask);
+void ip_format_masked(ovs_be32 ip, ovs_be32 mask, struct ds *);
+bool ip_parse(const char *s, ovs_be32 *ip);
+char *ip_parse_port(const char *s, ovs_be32 *ip, ovs_be16 *port)
+    OVS_WARN_UNUSED_RESULT;
+char *ip_parse_masked(const char *s, ovs_be32 *ip, ovs_be32 *mask)
+    OVS_WARN_UNUSED_RESULT;
+char *ip_parse_cidr(const char *s, ovs_be32 *ip, unsigned int *plen)
+    OVS_WARN_UNUSED_RESULT;
+char *ip_parse_masked_len(const char *s, int *n, ovs_be32 *ip, ovs_be32 *mask)
+    OVS_WARN_UNUSED_RESULT;
+char *ip_parse_cidr_len(const char *s, int *n, ovs_be32 *ip,
+                        unsigned int *plen)
+    OVS_WARN_UNUSED_RESULT;
+
+/* IPv6 address. */
+
+/* Like struct in6_addr, but whereas that struct requires 32-bit alignment on
+ * most implementations, this one only requires 16-bit alignment. */
+union ovs_16aligned_in6_addr {
+    ovs_be16 be16[8];
+    ovs_16aligned_be32 be32[4];
+};
+BUILD_ASSERT_DECL(sizeof(union ovs_16aligned_in6_addr)
+                  == sizeof(struct in6_addr));
+
+#define IPV6_SCAN_FMT "%46[0123456789abcdefABCDEF:.]"
+#define IPV6_SCAN_LEN 46
+
+extern const struct in6_addr in6addr_exact;
+#define IN6ADDR_EXACT_INIT { { { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, \
+                                 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff } } }
+
+extern const struct in6_addr in6addr_all_hosts;
+#define IN6ADDR_ALL_HOSTS_INIT \
+    { { { 0xff,0x02,0x00,0x00,0x00,0x00,0x00,0x00,                     \
+          0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01 } } }
+
+extern const struct in6_addr in6addr_all_routers;
+#define IN6ADDR_ALL_ROUTERS_INIT \
+    { { { 0xff,0x02,0x00,0x00,0x00,0x00,0x00,0x00,                     \
+          0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02 } } }
+
+extern const struct in6_addr in6addr_v4mapped_any;
+#define IN6ADDR_V4MAPPED_ANY_INIT \
+    { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+          0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } } }
+
+static inline bool ipv6_addr_equals(const struct in6_addr *a,
+                                    const struct in6_addr *b)
+{
+#ifdef IN6_ARE_ADDR_EQUAL
+    return IN6_ARE_ADDR_EQUAL(a, b);
+#else
+    return !memcmp(a, b, sizeof(*a));
+#endif
+}
+
+/* Checks the IPv6 address in 'mask' for all zeroes. */
+static inline bool ipv6_mask_is_any(const struct in6_addr *mask) {
+    return ipv6_addr_equals(mask, &in6addr_any);
+}
+
+static inline bool ipv6_mask_is_exact(const struct in6_addr *mask) {
+    return ipv6_addr_equals(mask, &in6addr_exact);
+}
+
+static inline bool ipv6_is_all_hosts(const struct in6_addr *addr) {
+    return ipv6_addr_equals(addr, &in6addr_all_hosts);
+}
+
+static inline bool ipv6_addr_is_set(const struct in6_addr *addr) {
+    return !ipv6_addr_equals(addr, &in6addr_any);
+}
+
+static inline bool ipv6_addr_is_multicast(const struct in6_addr *ip) {
+    return ip->s6_addr[0] == 0xff;
+}
+
+static inline struct in6_addr
+in6_addr_mapped_ipv4(ovs_be32 ip4)
+{
+    struct in6_addr ip6;
+    memset(&ip6, 0, sizeof(ip6));
+    ip6.s6_addr[10] = 0xff, ip6.s6_addr[11] = 0xff;
+    memcpy(&ip6.s6_addr[12], &ip4, 4);
+    return ip6;
+}
+
+static inline void
+in6_addr_set_mapped_ipv4(struct in6_addr *ip6, ovs_be32 ip4)
+{
+    *ip6 = in6_addr_mapped_ipv4(ip4);
+}
+
+static inline ovs_be32
+in6_addr_get_mapped_ipv4(const struct in6_addr *addr)
+{
+    union ovs_16aligned_in6_addr *taddr =
+        (union ovs_16aligned_in6_addr *) addr;
+    if (IN6_IS_ADDR_V4MAPPED(addr)) {
+        return get_16aligned_be32(&taddr->be32[3]);
+    } else {
+        return INADDR_ANY;
+    }
+}
+
+void in6_addr_solicited_node(struct in6_addr *addr,
+                             const struct in6_addr *ip6);
+
+void in6_generate_eui64(struct eth_addr ea, const struct in6_addr *prefix,
+                        struct in6_addr *lla);
+
+void in6_generate_lla(struct eth_addr ea, struct in6_addr *lla);
+
+/* Returns true if 'addr' is a link local address.  Otherwise, false. */
+bool in6_is_lla(struct in6_addr *addr);
+
+void ipv6_multicast_to_ethernet(struct eth_addr *eth,
+                                const struct in6_addr *ip6);
+
+void ipv6_format_addr(const struct in6_addr *addr, struct ds *);
+void ipv6_format_addr_bracket(const struct in6_addr *addr, struct ds *,
+                              bool bracket);
+void ipv6_format_mapped(const struct in6_addr *addr, struct ds *);
+void ipv6_format_masked(const struct in6_addr *addr,
+                        const struct in6_addr *mask, struct ds *);
+const char * ipv6_string_mapped(char *addr_str, const struct in6_addr *addr);
+struct in6_addr ipv6_addr_bitand(const struct in6_addr *src,
+                                 const struct in6_addr *mask);
+struct in6_addr ipv6_addr_bitxor(const struct in6_addr *a,
+                                 const struct in6_addr *b);
+bool ipv6_is_zero(const struct in6_addr *a);
+struct in6_addr ipv6_create_mask(int mask);
+int ipv6_count_cidr_bits(const struct in6_addr *netmask);
+bool ipv6_is_cidr(const struct in6_addr *netmask);
+bool ipv6_addr_equals_masked(const struct in6_addr *a,
+                             const struct in6_addr *b, int plen);
+
+bool ipv6_parse(const char *s, struct in6_addr *ip);
+char *ipv6_parse_masked(const char *s, struct in6_addr *ipv6,
+                        struct in6_addr *mask);
+char *ipv6_parse_cidr(const char *s, struct in6_addr *ip, unsigned int *plen)
+    OVS_WARN_UNUSED_RESULT;
+char *ipv6_parse_masked_len(const char *s, int *n, struct in6_addr *ipv6,
+                            struct in6_addr *mask);
+char *ipv6_parse_cidr_len(const char *s, int *n, struct in6_addr *ip,
+                          unsigned int *plen)
+    OVS_WARN_UNUSED_RESULT;
+
+#endif /* netaddr.h */
diff --git a/lib/packets.c b/lib/packets.c
index 80c41e4b6..b239afb0c 100644
--- a/lib/packets.c
+++ b/lib/packets.c
@@ -36,11 +36,6 @@
 #include "dp-packet-gso.h"
 #include "unaligned.h"
 
-const struct in6_addr in6addr_exact = IN6ADDR_EXACT_INIT;
-const struct in6_addr in6addr_all_hosts = IN6ADDR_ALL_HOSTS_INIT;
-const struct in6_addr in6addr_all_routers = IN6ADDR_ALL_ROUTERS_INIT;
-const struct in6_addr in6addr_v4mapped_any = IN6ADDR_V4MAPPED_ANY_INIT;
-
 struct in6_addr
 flow_tnl_dst(const struct flow_tnl *tnl)
 {
@@ -77,123 +72,6 @@ dpid_from_string(const char *s, uint64_t *dpidp)
     return *dpidp != 0;
 }
 
-uint64_t
-eth_addr_to_uint64(const struct eth_addr ea)
-{
-    return (((uint64_t) ntohs(ea.be16[0]) << 32)
-            | ((uint64_t) ntohs(ea.be16[1]) << 16)
-            | ntohs(ea.be16[2]));
-}
-
-void
-eth_addr_from_uint64(uint64_t x, struct eth_addr *ea)
-{
-    ea->be16[0] = htons(x >> 32);
-    ea->be16[1] = htons((x & 0xFFFF0000) >> 16);
-    ea->be16[2] = htons(x & 0xFFFF);
-}
-
-void
-eth_addr_mark_random(struct eth_addr *ea)
-{
-    ea->ea[0] &= ~1;                /* Unicast. */
-    ea->ea[0] |= 2;                 /* Private. */
-}
-
-/* Returns true if 'ea' is a reserved address, that a bridge must never
- * forward, false otherwise.
- *
- * If you change this function's behavior, please update corresponding
- * documentation in vswitch.xml at the same time. */
-bool
-eth_addr_is_reserved(const struct eth_addr ea)
-{
-    struct eth_addr_node {
-        struct hmap_node hmap_node;
-        const uint64_t ea64;
-    };
-
-    static struct eth_addr_node nodes[] = {
-        /* STP, IEEE pause frames, and other reserved protocols. */
-        { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000000ULL },
-        { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000001ULL },
-        { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000002ULL },
-        { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000003ULL },
-        { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000004ULL },
-        { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000005ULL },
-        { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000006ULL },
-        { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000007ULL },
-        { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000008ULL },
-        { HMAP_NODE_NULL_INITIALIZER, 0x0180c2000009ULL },
-        { HMAP_NODE_NULL_INITIALIZER, 0x0180c200000aULL },
-        { HMAP_NODE_NULL_INITIALIZER, 0x0180c200000bULL },
-        { HMAP_NODE_NULL_INITIALIZER, 0x0180c200000cULL },
-        { HMAP_NODE_NULL_INITIALIZER, 0x0180c200000dULL },
-        { HMAP_NODE_NULL_INITIALIZER, 0x0180c200000eULL },
-        { HMAP_NODE_NULL_INITIALIZER, 0x0180c200000fULL },
-
-        /* Extreme protocols. */
-        { HMAP_NODE_NULL_INITIALIZER, 0x00e02b000000ULL }, /* EDP. */
-        { HMAP_NODE_NULL_INITIALIZER, 0x00e02b000004ULL }, /* EAPS. */
-        { HMAP_NODE_NULL_INITIALIZER, 0x00e02b000006ULL }, /* EAPS. */
-
-        /* Cisco protocols. */
-        { HMAP_NODE_NULL_INITIALIZER, 0x01000c000000ULL }, /* ISL. */
-        { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccccULL }, /* PAgP, UDLD, CDP,
-                                                            * DTP, VTP. */
-        { HMAP_NODE_NULL_INITIALIZER, 0x01000ccccccdULL }, /* PVST+. */
-        { HMAP_NODE_NULL_INITIALIZER, 0x01000ccdcdcdULL }, /* STP Uplink Fast,
-                                                            * FlexLink. */
-
-        /* Cisco CFM. */
-        { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc0ULL },
-        { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc1ULL },
-        { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc2ULL },
-        { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc3ULL },
-        { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc4ULL },
-        { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc5ULL },
-        { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc6ULL },
-        { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc7ULL },
-    };
-
-    static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
-    struct eth_addr_node *node;
-    static struct hmap addrs;
-    uint64_t ea64;
-
-    if (ovsthread_once_start(&once)) {
-        hmap_init(&addrs);
-        for (node = nodes; node < &nodes[ARRAY_SIZE(nodes)]; node++) {
-            hmap_insert(&addrs, &node->hmap_node, hash_uint64(node->ea64));
-        }
-        ovsthread_once_done(&once);
-    }
-
-    ea64 = eth_addr_to_uint64(ea);
-    HMAP_FOR_EACH_IN_BUCKET (node, hmap_node, hash_uint64(ea64), &addrs) {
-        if (node->ea64 == ea64) {
-            return true;
-        }
-    }
-    return false;
-}
-
-/* Attempts to parse 's' as an Ethernet address.  If successful, stores the
- * address in 'ea' and returns true, otherwise zeros 'ea' and returns
- * false.  This function checks trailing characters. */
-bool
-eth_addr_from_string(const char *s, struct eth_addr *ea)
-{
-    int n = 0;
-    if (ovs_scan(s, ETH_ADDR_SCAN_FMT"%n", ETH_ADDR_SCAN_ARGS(*ea), &n)
-        && !s[n]) {
-        return true;
-    } else {
-        *ea = eth_addr_zero;
-        return false;
-    }
-}
-
 /* Fills 'b' with a Reverse ARP packet with Ethernet source address 'eth_src'.
  * This function is used by Open vSwitch to compose packets in cases where
  * context is important but content doesn't (or shouldn't) matter.
@@ -583,525 +461,6 @@ eth_from_hex(const char *hex, struct dp_packet **packetp)
 
     return NULL;
 }
-
-void
-eth_format_masked(const struct eth_addr eth,
-                  const struct eth_addr *mask, struct ds *s)
-{
-    ds_put_format(s, ETH_ADDR_FMT, ETH_ADDR_ARGS(eth));
-    if (mask && !eth_mask_is_exact(*mask)) {
-        ds_put_format(s, "/"ETH_ADDR_FMT, ETH_ADDR_ARGS(*mask));
-    }
-}
-
-void
-in6_addr_solicited_node(struct in6_addr *addr, const struct in6_addr *ip6)
-{
-    union ovs_16aligned_in6_addr *taddr =
-        (union ovs_16aligned_in6_addr *) addr;
-    memset(taddr->be16, 0, sizeof(taddr->be16));
-    taddr->be16[0] = htons(0xff02);
-    taddr->be16[5] = htons(0x1);
-    taddr->be16[6] = htons(0xff00);
-    memcpy(&addr->s6_addr[13], &ip6->s6_addr[13], 3);
-}
-
-/*
- * Generates ipv6 EUI64 address from the given eth addr
- * and prefix and stores it in 'lla'
- */
-void
-in6_generate_eui64(struct eth_addr ea, const struct in6_addr *prefix,
-                   struct in6_addr *lla)
-{
-    union ovs_16aligned_in6_addr *taddr =
-        (union ovs_16aligned_in6_addr *) lla;
-    union ovs_16aligned_in6_addr *prefix_taddr =
-        (union ovs_16aligned_in6_addr *) prefix;
-    taddr->be16[0] = prefix_taddr->be16[0];
-    taddr->be16[1] = prefix_taddr->be16[1];
-    taddr->be16[2] = prefix_taddr->be16[2];
-    taddr->be16[3] = prefix_taddr->be16[3];
-    taddr->be16[4] = htons(((ea.ea[0] ^ 0x02) << 8) | ea.ea[1]);
-    taddr->be16[5] = htons(ea.ea[2] << 8 | 0x00ff);
-    taddr->be16[6] = htons(0xfe << 8 | ea.ea[3]);
-    taddr->be16[7] = ea.be16[2];
-}
-
-/* Generates ipv6 link local address from the given eth addr
- * with prefix 'fe80::/64' and stores it in 'lla'. */
-void
-in6_generate_lla(struct eth_addr ea, struct in6_addr *lla)
-{
-    union ovs_16aligned_in6_addr *taddr =
-        (union ovs_16aligned_in6_addr *) lla;
-    memset(taddr->be16, 0, sizeof(taddr->be16));
-    taddr->be16[0] = htons(0xfe80);
-    taddr->be16[4] = htons(((ea.ea[0] ^ 0x02) << 8) | ea.ea[1]);
-    taddr->be16[5] = htons(ea.ea[2] << 8 | 0x00ff);
-    taddr->be16[6] = htons(0xfe << 8 | ea.ea[3]);
-    taddr->be16[7] = ea.be16[2];
-}
-
-/* Returns true if 'addr' is a link local address.  Otherwise, false. */
-bool
-in6_is_lla(struct in6_addr *addr)
-{
-#ifdef s6_addr32
-    return addr->s6_addr32[0] == htonl(0xfe800000) && !(addr->s6_addr32[1]);
-#else
-    return addr->s6_addr[0] == 0xfe && addr->s6_addr[1] == 0x80 &&
-         !(addr->s6_addr[2] | addr->s6_addr[3] | addr->s6_addr[4] |
-           addr->s6_addr[5] | addr->s6_addr[6] | addr->s6_addr[7]);
-#endif
-}
-
-void
-ipv6_multicast_to_ethernet(struct eth_addr *eth, const struct in6_addr *ip6)
-{
-    eth->ea[0] = 0x33;
-    eth->ea[1] = 0x33;
-    eth->ea[2] = ip6->s6_addr[12];
-    eth->ea[3] = ip6->s6_addr[13];
-    eth->ea[4] = ip6->s6_addr[14];
-    eth->ea[5] = ip6->s6_addr[15];
-}
-
-/* Given the IP netmask 'netmask', returns the number of bits of the IP address
- * that it specifies, that is, the number of 1-bits in 'netmask'.
- *
- * If 'netmask' is not a CIDR netmask (see ip_is_cidr()), the return value will
- * still be in the valid range but isn't otherwise meaningful. */
-int
-ip_count_cidr_bits(ovs_be32 netmask)
-{
-    return 32 - ctz32(ntohl(netmask));
-}
-
-void
-ip_format_masked(ovs_be32 ip, ovs_be32 mask, struct ds *s)
-{
-    ds_put_format(s, IP_FMT, IP_ARGS(ip));
-    if (mask != OVS_BE32_MAX) {
-        if (ip_is_cidr(mask)) {
-            ds_put_format(s, "/%d", ip_count_cidr_bits(mask));
-        } else {
-            ds_put_format(s, "/"IP_FMT, IP_ARGS(mask));
-        }
-    }
-}
-
-/* Parses string 's', which must be an IP address.  Stores the IP address into
- * '*ip'.  Returns true if successful, otherwise false. */
-bool
-ip_parse(const char *s, ovs_be32 *ip)
-{
-    return inet_pton(AF_INET, s, ip) == 1;
-}
-
-/* Parses string 's', which must be an IP address with a port number
- * with ":" as a separator (e.g.: 192.168.1.2:80).
- * Stores the IP address into '*ip' and port number to '*port'.
- *
- * Returns NULL if successful, otherwise an error message that the caller must
- * free(). */
-char * OVS_WARN_UNUSED_RESULT
-ip_parse_port(const char *s, ovs_be32 *ip, ovs_be16 *port)
-{
-    int n = 0;
-    if (ovs_scan(s, IP_PORT_SCAN_FMT"%n", IP_PORT_SCAN_ARGS(ip, port), &n)
-        && !s[n]) {
-        return NULL;
-    }
-
-    return xasprintf("%s: invalid IP address or port number", s);
-}
-
-/* Parses string 's', which must be an IP address with an optional netmask or
- * CIDR prefix length.  Stores the IP address into '*ip', netmask into '*mask',
- * (255.255.255.255, if 's' lacks a netmask), and number of scanned characters
- * into '*n'.
- *
- * Returns NULL if successful, otherwise an error message that the caller must
- * free(). */
-char * OVS_WARN_UNUSED_RESULT
-ip_parse_masked_len(const char *s, int *n, ovs_be32 *ip,
-                    ovs_be32 *mask)
-{
-    int prefix;
-
-    if (ovs_scan_len(s, n, IP_SCAN_FMT"/"IP_SCAN_FMT,
-                 IP_SCAN_ARGS(ip), IP_SCAN_ARGS(mask))) {
-        /* OK. */
-    } else if (ovs_scan_len(s, n, IP_SCAN_FMT"/%d",
-                            IP_SCAN_ARGS(ip), &prefix)) {
-        if (prefix < 0 || prefix > 32) {
-            return xasprintf("%s: IPv4 network prefix bits not between 0 and "
-                              "32, inclusive", s);
-        }
-        *mask = be32_prefix_mask(prefix);
-    } else if (ovs_scan_len(s, n, IP_SCAN_FMT, IP_SCAN_ARGS(ip))) {
-        *mask = OVS_BE32_MAX;
-    } else {
-        return xasprintf("%s: invalid IP address", s);
-    }
-    return NULL;
-}
-
-/* This function is similar to ip_parse_masked_len(), but doesn't return the
- * number of scanned characters and expects 's' to end after the ip/(optional)
- * mask.
- *
- * Returns NULL if successful, otherwise an error message that the caller must
- * free(). */
-char * OVS_WARN_UNUSED_RESULT
-ip_parse_masked(const char *s, ovs_be32 *ip, ovs_be32 *mask)
-{
-    int n = 0;
-
-    char *error = ip_parse_masked_len(s, &n, ip, mask);
-    if (!error && s[n]) {
-        return xasprintf("%s: invalid IP address", s);
-    }
-    return error;
-}
-
-/* Similar to ip_parse_masked_len(), but the mask, if present, must be a CIDR
- * mask and is returned as a prefix len in '*plen'. */
-char * OVS_WARN_UNUSED_RESULT
-ip_parse_cidr_len(const char *s, int *n, ovs_be32 *ip, unsigned int *plen)
-{
-    ovs_be32 mask;
-    char *error;
-
-    error = ip_parse_masked_len(s, n, ip, &mask);
-    if (error) {
-        return error;
-    }
-
-    if (!ip_is_cidr(mask)) {
-        return xasprintf("%s: CIDR network required", s);
-    }
-    *plen = ip_count_cidr_bits(mask);
-    return NULL;
-}
-
-/* Similar to ip_parse_cidr_len(), but doesn't return the number of scanned
- * characters and expects 's' to be NULL terminated at the end of the
- * ip/(optional) cidr. */
-char * OVS_WARN_UNUSED_RESULT
-ip_parse_cidr(const char *s, ovs_be32 *ip, unsigned int *plen)
-{
-    int n = 0;
-
-    char *error = ip_parse_cidr_len(s, &n, ip, plen);
-    if (!error && s[n]) {
-        return xasprintf("%s: invalid IP address", s);
-    }
-    return error;
-}
-
-/* Parses string 's', which must be an IPv6 address.  Stores the IPv6 address
- * into '*ip'.  Returns true if successful, otherwise false. */
-bool
-ipv6_parse(const char *s, struct in6_addr *ip)
-{
-    return inet_pton(AF_INET6, s, ip) == 1;
-}
-
-/* Parses string 's', which must be an IPv6 address with an optional netmask or
- * CIDR prefix length.  Stores the IPv6 address into '*ip' and the netmask into
- * '*mask' (if 's' does not contain a netmask, all-one-bits is assumed), and
- * number of scanned characters into '*n'.
- *
- * Returns NULL if successful, otherwise an error message that the caller must
- * free(). */
-char * OVS_WARN_UNUSED_RESULT
-ipv6_parse_masked_len(const char *s, int *n, struct in6_addr *ip,
-                      struct in6_addr *mask)
-{
-    char ipv6_s[IPV6_SCAN_LEN + 1];
-    int prefix;
-
-    if (ovs_scan_len(s, n, " "IPV6_SCAN_FMT, ipv6_s)
-        && ipv6_parse(ipv6_s, ip)) {
-        if (ovs_scan_len(s, n, "/%d", &prefix)) {
-            if (prefix < 0 || prefix > 128) {
-                return xasprintf("%s: IPv6 network prefix bits not between 0 "
-                                 "and 128, inclusive", s);
-            }
-            *mask = ipv6_create_mask(prefix);
-        } else if (ovs_scan_len(s, n, "/"IPV6_SCAN_FMT, ipv6_s)) {
-             if (!ipv6_parse(ipv6_s, mask)) {
-                 return xasprintf("%s: Invalid IPv6 mask", s);
-             }
-            /* OK. */
-        } else {
-            /* OK. No mask. */
-            *mask = in6addr_exact;
-        }
-        return NULL;
-    }
-    return xasprintf("%s: invalid IPv6 address", s);
-}
-
-/* This function is similar to ipv6_parse_masked_len(), but doesn't return the
- * number of scanned characters and expects 's' to end following the
- * ipv6/(optional) mask. */
-char * OVS_WARN_UNUSED_RESULT
-ipv6_parse_masked(const char *s, struct in6_addr *ip, struct in6_addr *mask)
-{
-    int n = 0;
-
-    char *error = ipv6_parse_masked_len(s, &n, ip, mask);
-    if (!error && s[n]) {
-        return xasprintf("%s: invalid IPv6 address", s);
-    }
-    return error;
-}
-
-/* Similar to ipv6_parse_masked_len(), but the mask, if present, must be a CIDR
- * mask and is returned as a prefix length in '*plen'. */
-char * OVS_WARN_UNUSED_RESULT
-ipv6_parse_cidr_len(const char *s, int *n, struct in6_addr *ip,
-                    unsigned int *plen)
-{
-    struct in6_addr mask;
-    char *error;
-
-    error = ipv6_parse_masked_len(s, n, ip, &mask);
-    if (error) {
-        return error;
-    }
-
-    if (!ipv6_is_cidr(&mask)) {
-        return xasprintf("%s: IPv6 CIDR network required", s);
-    }
-    *plen = ipv6_count_cidr_bits(&mask);
-    return NULL;
-}
-
-/* Similar to ipv6_parse_cidr_len(), but doesn't return the number of scanned
- * characters and expects 's' to end after the ipv6/(optional) cidr. */
-char * OVS_WARN_UNUSED_RESULT
-ipv6_parse_cidr(const char *s, struct in6_addr *ip, unsigned int *plen)
-{
-    int n = 0;
-
-    char *error = ipv6_parse_cidr_len(s, &n, ip, plen);
-    if (!error && s[n]) {
-        return xasprintf("%s: invalid IPv6 address", s);
-    }
-    return error;
-}
-
-/* Stores the string representation of the IPv6 address 'addr' into the
- * character array 'addr_str', which must be at least INET6_ADDRSTRLEN
- * bytes long. */
-void
-ipv6_format_addr(const struct in6_addr *addr, struct ds *s)
-{
-    char *dst;
-
-    ds_reserve(s, s->length + INET6_ADDRSTRLEN);
-
-    dst = s->string + s->length;
-    inet_ntop(AF_INET6, addr, dst, INET6_ADDRSTRLEN);
-    s->length += strlen(dst);
-}
-
-/* Same as print_ipv6_addr, but optionally encloses the address in square
- * brackets. */
-void
-ipv6_format_addr_bracket(const struct in6_addr *addr, struct ds *s,
-                         bool bracket)
-{
-    if (bracket) {
-        ds_put_char(s, '[');
-    }
-    ipv6_format_addr(addr, s);
-    if (bracket) {
-        ds_put_char(s, ']');
-    }
-}
-
-void
-ipv6_format_mapped(const struct in6_addr *addr, struct ds *s)
-{
-    if (IN6_IS_ADDR_V4MAPPED(addr)) {
-        ds_put_format(s, IP_FMT, addr->s6_addr[12], addr->s6_addr[13],
-                                 addr->s6_addr[14], addr->s6_addr[15]);
-    } else {
-        ipv6_format_addr(addr, s);
-    }
-}
-
-void
-ipv6_format_masked(const struct in6_addr *addr, const struct in6_addr *mask,
-                   struct ds *s)
-{
-    ipv6_format_addr(addr, s);
-    if (mask && !ipv6_mask_is_exact(mask)) {
-        if (ipv6_is_cidr(mask)) {
-            int cidr_bits = ipv6_count_cidr_bits(mask);
-            ds_put_format(s, "/%d", cidr_bits);
-        } else {
-            ds_put_char(s, '/');
-            ipv6_format_addr(mask, s);
-        }
-    }
-}
-
-/* Stores the string representation of the IPv6 address 'addr' into the
- * character array 'addr_str', which must be at least INET6_ADDRSTRLEN
- * bytes long. If addr is IPv4-mapped, store an IPv4 dotted-decimal string. */
-const char *
-ipv6_string_mapped(char *addr_str, const struct in6_addr *addr)
-{
-    ovs_be32 ip;
-    ip = in6_addr_get_mapped_ipv4(addr);
-    if (ip) {
-        return inet_ntop(AF_INET, &ip, addr_str, INET6_ADDRSTRLEN);
-    } else {
-        return inet_ntop(AF_INET6, addr, addr_str, INET6_ADDRSTRLEN);
-    }
-}
-
-#ifdef s6_addr32
-#define s6_addrX s6_addr32
-#define IPV6_FOR_EACH(VAR) for (int VAR = 0; VAR < 4; VAR++)
-#else
-#define s6_addrX s6_addr
-#define IPV6_FOR_EACH(VAR) for (int VAR = 0; VAR < 16; VAR++)
-#endif
-
-struct in6_addr
-ipv6_addr_bitand(const struct in6_addr *a, const struct in6_addr *b)
-{
-   struct in6_addr dst;
-   IPV6_FOR_EACH (i) {
-       dst.s6_addrX[i] = a->s6_addrX[i] & b->s6_addrX[i];
-   }
-   return dst;
-}
-
-struct in6_addr
-ipv6_addr_bitxor(const struct in6_addr *a, const struct in6_addr *b)
-{
-   struct in6_addr dst;
-   IPV6_FOR_EACH (i) {
-       dst.s6_addrX[i] = a->s6_addrX[i] ^ b->s6_addrX[i];
-   }
-   return dst;
-}
-
-bool
-ipv6_is_zero(const struct in6_addr *a)
-{
-   IPV6_FOR_EACH (i) {
-       if (a->s6_addrX[i]) {
-           return false;
-       }
-   }
-   return true;
-}
-
-/* Returns an in6_addr consisting of 'mask' high-order 1-bits and 128-N
- * low-order 0-bits. */
-struct in6_addr
-ipv6_create_mask(int mask)
-{
-    struct in6_addr netmask;
-    uint8_t *netmaskp = &netmask.s6_addr[0];
-
-    memset(&netmask, 0, sizeof netmask);
-    while (mask > 8) {
-        *netmaskp = 0xff;
-        netmaskp++;
-        mask -= 8;
-    }
-
-    if (mask) {
-        *netmaskp = 0xff << (8 - mask);
-    }
-
-    return netmask;
-}
-
-/* Given the IPv6 netmask 'netmask', returns the number of bits of the IPv6
- * address that it specifies, that is, the number of 1-bits in 'netmask'.
- * 'netmask' must be a CIDR netmask (see ipv6_is_cidr()).
- *
- * If 'netmask' is not a CIDR netmask (see ipv6_is_cidr()), the return value
- * will still be in the valid range but isn't otherwise meaningful. */
-int
-ipv6_count_cidr_bits(const struct in6_addr *netmask)
-{
-    int i;
-    int count = 0;
-    const uint8_t *netmaskp = &netmask->s6_addr[0];
-
-    for (i=0; i<16; i++) {
-        if (netmaskp[i] == 0xff) {
-            count += 8;
-        } else {
-            uint8_t nm;
-
-            for(nm = netmaskp[i]; nm; nm <<= 1) {
-                count++;
-            }
-            break;
-        }
-
-    }
-
-    return count;
-}
-
-/* Returns true if 'netmask' is a CIDR netmask, that is, if it consists of N
- * high-order 1-bits and 128-N low-order 0-bits. */
-bool
-ipv6_is_cidr(const struct in6_addr *netmask)
-{
-    const uint8_t *netmaskp = &netmask->s6_addr[0];
-    int i;
-
-    for (i=0; i<16; i++) {
-        if (netmaskp[i] != 0xff) {
-            uint8_t x = ~netmaskp[i];
-            if (x & (x + 1)) {
-                return false;
-            }
-            while (++i < 16) {
-                if (netmaskp[i]) {
-                    return false;
-                }
-            }
-        }
-    }
-
-    return true;
-}
-
-bool
-ipv6_addr_equals_masked(const struct in6_addr *a, const struct in6_addr *b,
-                        int plen)
-{
-    struct in6_addr mask;
-    struct in6_addr ma;
-    struct in6_addr mb;
-
-    if (plen == 128) {
-        return ipv6_addr_equals(a, b);
-    }
-
-    mask = ipv6_create_mask(plen);
-    ma = ipv6_addr_bitand(a, &mask);
-    mb = ipv6_addr_bitand(b, &mask);
-
-    return ipv6_addr_equals(&ma, &mb);
-}
-
 /* Populates 'b' with an Ethernet II packet headed with the given 'eth_dst',
  * 'eth_src' and 'eth_type' parameters.  A payload of 'size' bytes is allocated
  * in 'b' and returned.  This payload may be populated with appropriate
diff --git a/lib/packets.h b/lib/packets.h
index ea0bda840..7d91ae90e 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -22,16 +22,13 @@
 #include <stdint.h>
 #include <string.h>
 #include "compiler.h"
+#include "netaddr.h"
 #include "openvswitch/geneve.h"
 #include "openvswitch/packets.h"
-#include "openvswitch/types.h"
 #include "openvswitch/nsh.h"
 #include "odp-netlink.h"
-#include "random.h"
 #include "hash.h"
 #include "tun-metadata.h"
-#include "unaligned.h"
-#include "util.h"
 #include "timeval.h"
 
 struct dp_packet;
@@ -44,8 +41,6 @@ struct ds;
 /* Tunnel information is in userspace datapath format. */
 #define FLOW_TNL_F_UDPIF (1 << 4)
 
-static inline bool ipv6_addr_is_set(const struct in6_addr *addr);
-
 static inline bool
 flow_tnl_dst_is_set(const struct flow_tnl *tnl)
 {
@@ -202,149 +197,18 @@ pkt_metadata_prefetch_init(struct pkt_metadata *md)
 
 bool dpid_from_string(const char *s, uint64_t *dpidp);
 
-#define ETH_ADDR_LEN           6
-
-static const struct eth_addr eth_addr_broadcast OVS_UNUSED
-    = ETH_ADDR_C(ff,ff,ff,ff,ff,ff);
-
-static const struct eth_addr eth_addr_exact OVS_UNUSED
-    = ETH_ADDR_C(ff,ff,ff,ff,ff,ff);
-
-static const struct eth_addr eth_addr_zero OVS_UNUSED
-    = ETH_ADDR_C(00,00,00,00,00,00);
-static const struct eth_addr64 eth_addr64_zero OVS_UNUSED
-    = ETH_ADDR64_C(00,00,00,00,00,00,00,00);
-
-static const struct eth_addr eth_addr_stp OVS_UNUSED
-    = ETH_ADDR_C(01,80,c2,00,00,00);
-
-static const struct eth_addr eth_addr_lacp OVS_UNUSED
-    = ETH_ADDR_C(01,80,c2,00,00,02);
-
-static const struct eth_addr eth_addr_bfd OVS_UNUSED
-    = ETH_ADDR_C(00,23,20,00,00,01);
-
-static inline bool eth_addr_is_broadcast(const struct eth_addr a)
-{
-    return (a.be16[0] & a.be16[1] & a.be16[2]) == htons(0xffff);
-}
-
-static inline bool eth_addr_is_multicast(const struct eth_addr a)
-{
-    return a.ea[0] & 1;
-}
-
-static inline bool eth_addr_is_local(const struct eth_addr a)
-{
-    /* Local if it is either a locally administered address or a Nicira random
-     * address. */
-    return a.ea[0] & 2
-        || (a.be16[0] == htons(0x0023)
-            && (a.be16[1] & htons(0xff80)) == htons(0x2080));
-}
-static inline bool eth_addr_is_zero(const struct eth_addr a)
-{
-    return !(a.be16[0] | a.be16[1] | a.be16[2]);
-}
-static inline bool eth_addr64_is_zero(const struct eth_addr64 a)
-{
-    return !(a.be16[0] | a.be16[1] | a.be16[2] | a.be16[3]);
-}
-
-static inline int eth_mask_is_exact(const struct eth_addr a)
-{
-    return (a.be16[0] & a.be16[1] & a.be16[2]) == htons(0xffff);
-}
-
-static inline int eth_addr_compare_3way(const struct eth_addr a,
-                                        const struct eth_addr b)
-{
-    return memcmp(&a, &b, sizeof a);
-}
-static inline int eth_addr64_compare_3way(const struct eth_addr64 a,
-                                          const struct eth_addr64 b)
-{
-    return memcmp(&a, &b, sizeof a);
-}
-
-static inline bool eth_addr_equals(const struct eth_addr a,
-                                   const struct eth_addr b)
-{
-    return !eth_addr_compare_3way(a, b);
-}
-static inline bool eth_addr64_equals(const struct eth_addr64 a,
-                                     const struct eth_addr64 b)
-{
-    return !eth_addr64_compare_3way(a, b);
-}
-
-static inline bool eth_addr_equal_except(const struct eth_addr a,
-                                         const struct eth_addr b,
-                                         const struct eth_addr mask)
-{
-    return !(((a.be16[0] ^ b.be16[0]) & mask.be16[0])
-             || ((a.be16[1] ^ b.be16[1]) & mask.be16[1])
-             || ((a.be16[2] ^ b.be16[2]) & mask.be16[2]));
-}
-
-uint64_t eth_addr_to_uint64(const struct eth_addr ea);
-
-static inline uint64_t eth_addr_vlan_to_uint64(const struct eth_addr ea,
-                                               uint16_t vlan)
-{
-    return (((uint64_t)vlan << 48) | eth_addr_to_uint64(ea));
-}
-
-void eth_addr_from_uint64(uint64_t x, struct eth_addr *ea);
-
-static inline struct eth_addr eth_addr_invert(const struct eth_addr src)
-{
-    struct eth_addr dst;
-
-    for (int i = 0; i < ARRAY_SIZE(src.be16); i++) {
-        dst.be16[i] = ~src.be16[i];
-    }
-
-    return dst;
-}
-
-void eth_addr_mark_random(struct eth_addr *ea);
-
-static inline void eth_addr_random(struct eth_addr *ea)
-{
-    random_bytes((uint8_t *)ea, sizeof *ea);
-    eth_addr_mark_random(ea);
-}
-
-static inline void eth_addr_nicira_random(struct eth_addr *ea)
-{
-    eth_addr_random(ea);
-
-    /* Set the OUI to the Nicira one. */
-    ea->ea[0] = 0x00;
-    ea->ea[1] = 0x23;
-    ea->ea[2] = 0x20;
-
-    /* Set the top bit to indicate random Nicira address. */
-    ea->ea[3] |= 0x80;
-}
 static inline uint32_t hash_mac(const struct eth_addr ea,
                                 const uint16_t vlan, const uint32_t basis)
 {
     return hash_uint64_basis(eth_addr_vlan_to_uint64(ea, vlan), basis);
 }
 
-bool eth_addr_is_reserved(const struct eth_addr);
-bool eth_addr_from_string(const char *, struct eth_addr *);
-
 void compose_rarp(struct dp_packet *, const struct eth_addr);
 
 void eth_push_vlan(struct dp_packet *, ovs_be16 tpid, ovs_be16 tci);
 void eth_pop_vlan(struct dp_packet *);
 
 const char *eth_from_hex(const char *hex, struct dp_packet **packetp);
-void eth_format_masked(const struct eth_addr ea,
-                       const struct eth_addr *mask, struct ds *s);
 
 void set_mpls_lse(struct dp_packet *, ovs_be32 label);
 void push_mpls(struct dp_packet *packet, ovs_be16 ethtype, ovs_be32 lse);
@@ -359,51 +223,6 @@ ovs_be32 set_mpls_lse_values(uint8_t ttl, uint8_t tc, 
uint8_t bos,
 void add_mpls(struct dp_packet *packet, ovs_be16 ethtype, ovs_be32 lse,
               bool l3_encap);
 
-/* Example:
- *
- * struct eth_addr mac;
- *    [...]
- * printf("The Ethernet address is "ETH_ADDR_FMT"\n", ETH_ADDR_ARGS(mac));
- *
- */
-#define ETH_ADDR_FMT                                                    \
-    "%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8
-#define ETH_ADDR_ARGS(EA) ETH_ADDR_BYTES_ARGS((EA).ea)
-#define ETH_ADDR_BYTES_ARGS(EAB) \
-         (EAB)[0], (EAB)[1], (EAB)[2], (EAB)[3], (EAB)[4], (EAB)[5]
-#define ETH_ADDR_STRLEN 17
-
-/* Example:
- *
- * struct eth_addr64 eui64;
- *    [...]
- * printf("The EUI-64 address is "ETH_ADDR64_FMT"\n", ETH_ADDR64_ARGS(mac));
- *
- */
-#define ETH_ADDR64_FMT \
-    "%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":" \
-    "%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8
-#define ETH_ADDR64_ARGS(EA) ETH_ADDR64_BYTES_ARGS((EA).ea64)
-#define ETH_ADDR64_BYTES_ARGS(EAB) \
-         (EAB)[0], (EAB)[1], (EAB)[2], (EAB)[3], \
-         (EAB)[4], (EAB)[5], (EAB)[6], (EAB)[7]
-#define ETH_ADDR64_STRLEN 23
-
-/* Example:
- *
- * char *string = "1 00:11:22:33:44:55 2";
- * struct eth_addr mac;
- * int a, b;
- *
- * if (ovs_scan(string, "%d"ETH_ADDR_SCAN_FMT"%d",
- *              &a, ETH_ADDR_SCAN_ARGS(mac), &b)) {
- *     ...
- * }
- */
-#define ETH_ADDR_SCAN_FMT "%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8
-#define ETH_ADDR_SCAN_ARGS(EA) \
-    &(EA).ea[0], &(EA).ea[1], &(EA).ea[2], &(EA).ea[3], &(EA).ea[4], 
&(EA).ea[5]
-
 #define ETH_TYPE_IP            0x0800
 #define ETH_TYPE_ARP           0x0806
 #define ETH_TYPE_TEB           0x6558
@@ -625,71 +444,6 @@ mpls_lse_to_bos(ovs_be32 mpls_lse)
     return (mpls_lse & htonl(MPLS_BOS_MASK)) != 0;
 }
 
-#define IP_FMT "%"PRIu32".%"PRIu32".%"PRIu32".%"PRIu32
-#define IP_ARGS(ip)                             \
-    ntohl(ip) >> 24,                            \
-    (ntohl(ip) >> 16) & 0xff,                   \
-    (ntohl(ip) >> 8) & 0xff,                    \
-    ntohl(ip) & 0xff
-
-/* Example:
- *
- * char *string = "1 33.44.55.66 2";
- * ovs_be32 ip;
- * int a, b;
- *
- * if (ovs_scan(string, "%d"IP_SCAN_FMT"%d", &a, IP_SCAN_ARGS(&ip), &b)) {
- *     ...
- * }
- */
-#define IP_SCAN_FMT "%"SCNu8".%"SCNu8".%"SCNu8".%"SCNu8
-#define IP_SCAN_ARGS(ip)                                    \
-        ((void) (ovs_be32) *(ip), &((uint8_t *) ip)[0]),    \
-        &((uint8_t *) ip)[1],                               \
-        &((uint8_t *) ip)[2],                               \
-        &((uint8_t *) ip)[3]
-
-#define IP_PORT_SCAN_FMT "%"SCNu8".%"SCNu8".%"SCNu8".%"SCNu8":%"SCNu16
-#define IP_PORT_SCAN_ARGS(ip, port)                                    \
-        ((void) (ovs_be32) *(ip), &((uint8_t *) ip)[0]),    \
-        &((uint8_t *) ip)[1],                               \
-        &((uint8_t *) ip)[2],                               \
-        &((uint8_t *) ip)[3],                               \
-        ((void) (ovs_be16) *(port), (uint16_t *) port)
-
-/* Returns true if 'netmask' is a CIDR netmask, that is, if it consists of N
- * high-order 1-bits and 32-N low-order 0-bits. */
-static inline bool
-ip_is_cidr(ovs_be32 netmask)
-{
-    uint32_t x = ~ntohl(netmask);
-    return !(x & (x + 1));
-}
-static inline bool
-ip_is_multicast(ovs_be32 ip)
-{
-    return (ip & htonl(0xf0000000)) == htonl(0xe0000000);
-}
-static inline bool
-ip_is_local_multicast(ovs_be32 ip)
-{
-    return (ip & htonl(0xffffff00)) == htonl(0xe0000000);
-}
-int ip_count_cidr_bits(ovs_be32 netmask);
-void ip_format_masked(ovs_be32 ip, ovs_be32 mask, struct ds *);
-bool ip_parse(const char *s, ovs_be32 *ip);
-char *ip_parse_port(const char *s, ovs_be32 *ip, ovs_be16 *port)
-    OVS_WARN_UNUSED_RESULT;
-char *ip_parse_masked(const char *s, ovs_be32 *ip, ovs_be32 *mask)
-    OVS_WARN_UNUSED_RESULT;
-char *ip_parse_cidr(const char *s, ovs_be32 *ip, unsigned int *plen)
-    OVS_WARN_UNUSED_RESULT;
-char *ip_parse_masked_len(const char *s, int *n, ovs_be32 *ip, ovs_be32 *mask)
-    OVS_WARN_UNUSED_RESULT;
-char *ip_parse_cidr_len(const char *s, int *n, ovs_be32 *ip,
-                        unsigned int *plen)
-    OVS_WARN_UNUSED_RESULT;
-
 #define IP_VER(ip_ihl_ver) ((ip_ihl_ver) >> 4)
 #define IP_IHL(ip_ihl_ver) ((ip_ihl_ver) & 15)
 #define IP_IHL_VER(ihl, ver) (((ver) << 4) | (ihl))
@@ -973,15 +727,6 @@ BUILD_ASSERT_DECL(ARP_ETH_HEADER_LEN == sizeof(struct 
arp_eth_header));
 
 #define IPV6_HEADER_LEN 40
 
-/* Like struct in6_addr, but whereas that struct requires 32-bit alignment on
- * most implementations, this one only requires 16-bit alignment. */
-union ovs_16aligned_in6_addr {
-    ovs_be16 be16[8];
-    ovs_16aligned_be32 be32[4];
-};
-BUILD_ASSERT_DECL(sizeof(union ovs_16aligned_in6_addr)
-                  == sizeof(struct in6_addr));
-
 /* Like struct ip6_hdr, but whereas that struct requires 32-bit alignment, this
  * one only requires 16-bit alignment. */
 struct ovs_16aligned_ip6_hdr {
@@ -1148,110 +893,6 @@ BUILD_ASSERT_DECL(MLD2_RECORD_LEN == sizeof(struct 
mld2_record));
 /* The IPv6 flow label is in the lower 20 bits of the first 32-bit word. */
 #define IPV6_LABEL_MASK 0x000fffff
 
-/* Example:
- *
- * char *string = "1 ::1 2";
- * char ipv6_s[IPV6_SCAN_LEN + 1];
- * struct in6_addr ipv6;
- *
- * if (ovs_scan(string, "%d"IPV6_SCAN_FMT"%d", &a, ipv6_s, &b)
- *     && inet_pton(AF_INET6, ipv6_s, &ipv6) == 1) {
- *     ...
- * }
- */
-#define IPV6_SCAN_FMT "%46[0123456789abcdefABCDEF:.]"
-#define IPV6_SCAN_LEN 46
-
-extern const struct in6_addr in6addr_exact;
-#define IN6ADDR_EXACT_INIT { { { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, \
-                                 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff } } }
-
-extern const struct in6_addr in6addr_all_hosts;
-#define IN6ADDR_ALL_HOSTS_INIT { { { 0xff,0x02,0x00,0x00,0x00,0x00,0x00,0x00, \
-                                     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01 } 
} }
-
-extern const struct in6_addr in6addr_all_routers;
-#define IN6ADDR_ALL_ROUTERS_INIT { { { 
0xff,0x02,0x00,0x00,0x00,0x00,0x00,0x00, \
-                                       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02 
} } }
-
-extern const struct in6_addr in6addr_v4mapped_any;
-#define IN6ADDR_V4MAPPED_ANY_INIT \
-    { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
-          0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } } }
-
-static inline bool ipv6_addr_equals(const struct in6_addr *a,
-                                    const struct in6_addr *b)
-{
-#ifdef IN6_ARE_ADDR_EQUAL
-    return IN6_ARE_ADDR_EQUAL(a, b);
-#else
-    return !memcmp(a, b, sizeof(*a));
-#endif
-}
-
-/* Checks the IPv6 address in 'mask' for all zeroes. */
-static inline bool ipv6_mask_is_any(const struct in6_addr *mask) {
-    return ipv6_addr_equals(mask, &in6addr_any);
-}
-
-static inline bool ipv6_mask_is_exact(const struct in6_addr *mask) {
-    return ipv6_addr_equals(mask, &in6addr_exact);
-}
-
-static inline bool ipv6_is_all_hosts(const struct in6_addr *addr) {
-    return ipv6_addr_equals(addr, &in6addr_all_hosts);
-}
-
-static inline bool ipv6_addr_is_set(const struct in6_addr *addr) {
-    return !ipv6_addr_equals(addr, &in6addr_any);
-}
-
-static inline bool ipv6_addr_is_multicast(const struct in6_addr *ip) {
-    return ip->s6_addr[0] == 0xff;
-}
-
-static inline struct in6_addr
-in6_addr_mapped_ipv4(ovs_be32 ip4)
-{
-    struct in6_addr ip6;
-    memset(&ip6, 0, sizeof(ip6));
-    ip6.s6_addr[10] = 0xff, ip6.s6_addr[11] = 0xff;
-    memcpy(&ip6.s6_addr[12], &ip4, 4);
-    return ip6;
-}
-
-static inline void
-in6_addr_set_mapped_ipv4(struct in6_addr *ip6, ovs_be32 ip4)
-{
-    *ip6 = in6_addr_mapped_ipv4(ip4);
-}
-
-static inline ovs_be32
-in6_addr_get_mapped_ipv4(const struct in6_addr *addr)
-{
-    union ovs_16aligned_in6_addr *taddr =
-        (union ovs_16aligned_in6_addr *) addr;
-    if (IN6_IS_ADDR_V4MAPPED(addr)) {
-        return get_16aligned_be32(&taddr->be32[3]);
-    } else {
-        return INADDR_ANY;
-    }
-}
-
-void in6_addr_solicited_node(struct in6_addr *addr,
-                             const struct in6_addr *ip6);
-
-void in6_generate_eui64(struct eth_addr ea, const struct in6_addr *prefix,
-                        struct in6_addr *lla);
-
-void in6_generate_lla(struct eth_addr ea, struct in6_addr *lla);
-
-/* Returns true if 'addr' is a link local address.  Otherwise, false. */
-bool in6_is_lla(struct in6_addr *addr);
-
-void ipv6_multicast_to_ethernet(struct eth_addr *eth,
-                                const struct in6_addr *ip6);
-
 static inline bool dl_type_is_ip_any(ovs_be16 dl_type)
 {
     return dl_type == htons(ETH_TYPE_IP)
@@ -1598,35 +1239,6 @@ enum packet_type {
 };
 
 
-void ipv6_format_addr(const struct in6_addr *addr, struct ds *);
-void ipv6_format_addr_bracket(const struct in6_addr *addr, struct ds *,
-                              bool bracket);
-void ipv6_format_mapped(const struct in6_addr *addr, struct ds *);
-void ipv6_format_masked(const struct in6_addr *addr,
-                        const struct in6_addr *mask, struct ds *);
-const char * ipv6_string_mapped(char *addr_str, const struct in6_addr *addr);
-struct in6_addr ipv6_addr_bitand(const struct in6_addr *src,
-                                 const struct in6_addr *mask);
-struct in6_addr ipv6_addr_bitxor(const struct in6_addr *a,
-                                 const struct in6_addr *b);
-bool ipv6_is_zero(const struct in6_addr *a);
-struct in6_addr ipv6_create_mask(int mask);
-int ipv6_count_cidr_bits(const struct in6_addr *netmask);
-bool ipv6_is_cidr(const struct in6_addr *netmask);
-bool ipv6_addr_equals_masked(const struct in6_addr *a,
-                             const struct in6_addr *b, int plen);
-
-bool ipv6_parse(const char *s, struct in6_addr *ip);
-char *ipv6_parse_masked(const char *s, struct in6_addr *ipv6,
-                        struct in6_addr *mask);
-char *ipv6_parse_cidr(const char *s, struct in6_addr *ip, unsigned int *plen)
-    OVS_WARN_UNUSED_RESULT;
-char *ipv6_parse_masked_len(const char *s, int *n, struct in6_addr *ipv6,
-                            struct in6_addr *mask);
-char *ipv6_parse_cidr_len(const char *s, int *n, struct in6_addr *ip,
-                          unsigned int *plen)
-    OVS_WARN_UNUSED_RESULT;
-
 void *eth_compose(struct dp_packet *, const struct eth_addr eth_dst,
                   const struct eth_addr eth_src, uint16_t eth_type,
                   size_t size);
-- 
2.55.0

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to